quantrs2_device/performance_analytics_dashboard/
session.rs

1//! Session and User Management for Performance Dashboard
2//!
3//! This module handles user sessions, permissions, preferences, and access control
4//! for the performance analytics dashboard.
5
6use crate::DeviceResult;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::time::{Duration, SystemTime};
10
11/// User session management
12pub struct SessionManager {
13    active_sessions: HashMap<String, UserSession>,
14    session_config: SessionConfig,
15    auth_provider: Box<dyn AuthProvider + Send + Sync>,
16    permission_manager: PermissionManager,
17}
18
19/// User session information
20#[derive(Debug, Clone)]
21pub struct UserSession {
22    pub session_id: String,
23    pub user_id: String,
24    pub permissions: Vec<Permission>,
25    pub preferences: UserPreferences,
26    pub last_activity: SystemTime,
27    pub session_data: HashMap<String, String>,
28    pub auth_token: Option<String>,
29    pub expires_at: SystemTime,
30}
31
32/// Session configuration
33#[derive(Debug, Clone)]
34pub struct SessionConfig {
35    pub session_timeout: Duration,
36    pub max_concurrent_sessions: usize,
37    pub require_authentication: bool,
38    pub enable_session_persistence: bool,
39    pub cookie_settings: CookieSettings,
40    pub security_settings: SecuritySettings,
41}
42
43/// Cookie settings
44#[derive(Debug, Clone)]
45pub struct CookieSettings {
46    pub secure: bool,
47    pub http_only: bool,
48    pub same_site: SameSitePolicy,
49    pub domain: Option<String>,
50    pub path: String,
51    pub max_age: Duration,
52}
53
54/// Same-site policy
55#[derive(Debug, Clone, PartialEq, Eq)]
56pub enum SameSitePolicy {
57    Strict,
58    Lax,
59    None,
60}
61
62/// Security settings
63#[derive(Debug, Clone)]
64pub struct SecuritySettings {
65    pub csrf_protection: bool,
66    pub rate_limiting: bool,
67    pub ip_whitelist: Option<Vec<String>>,
68    pub require_https: bool,
69    pub enable_audit_logging: bool,
70}
71
72/// User permissions
73#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
74pub enum Permission {
75    ReadDashboard,
76    WriteDashboard,
77    ManageAlerts,
78    ExportData,
79    ViewReports,
80    ManageUsers,
81    SystemAdmin,
82    Custom(String),
83}
84
85/// User preferences
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct UserPreferences {
88    pub dashboard_layout: String,
89    pub default_time_range: String,
90    pub chart_preferences: ChartPreferences,
91    pub notification_preferences: NotificationPreferences,
92    pub display_preferences: DisplayPreferences,
93    pub custom_preferences: HashMap<String, String>,
94}
95
96/// Chart preferences
97#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct ChartPreferences {
99    pub preferred_chart_types: Vec<String>,
100    pub color_scheme: String,
101    pub animation_enabled: bool,
102    pub interactive_features: bool,
103    pub default_aggregation: String,
104    pub refresh_interval: u64,
105}
106
107/// Notification preferences
108#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct NotificationPreferences {
110    pub email_notifications: bool,
111    pub browser_notifications: bool,
112    pub slack_notifications: bool,
113    pub notification_frequency: NotificationFrequency,
114    pub alert_thresholds: HashMap<String, f64>,
115    pub quiet_hours: Option<QuietHours>,
116}
117
118/// Notification frequency
119#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
120pub enum NotificationFrequency {
121    Immediate,
122    Hourly,
123    Daily,
124    Weekly,
125    Custom(Duration),
126}
127
128/// Quiet hours configuration
129#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct QuietHours {
131    pub start_time: String, // HH:MM format
132    pub end_time: String,   // HH:MM format
133    pub timezone: String,
134    pub days_of_week: Vec<DayOfWeek>,
135}
136
137/// Days of the week
138#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
139pub enum DayOfWeek {
140    Monday,
141    Tuesday,
142    Wednesday,
143    Thursday,
144    Friday,
145    Saturday,
146    Sunday,
147}
148
149/// Display preferences
150#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct DisplayPreferences {
152    pub theme: String,
153    pub font_size: String,
154    pub density: DisplayDensity,
155    pub sidebar_collapsed: bool,
156    pub show_tooltips: bool,
157    pub language: String,
158    pub timezone: String,
159}
160
161/// Display density
162#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
163pub enum DisplayDensity {
164    Compact,
165    Normal,
166    Spacious,
167}
168
169/// Authentication provider trait
170pub trait AuthProvider {
171    fn authenticate(&self, credentials: &Credentials) -> DeviceResult<AuthResult>;
172    fn validate_token(&self, token: &str) -> DeviceResult<TokenValidation>;
173    fn refresh_token(&self, refresh_token: &str) -> DeviceResult<AuthResult>;
174    fn logout(&self, token: &str) -> DeviceResult<()>;
175}
176
177/// Authentication credentials
178#[derive(Debug, Clone)]
179pub struct Credentials {
180    pub username: Option<String>,
181    pub password: Option<String>,
182    pub token: Option<String>,
183    pub oauth_code: Option<String>,
184    pub provider: AuthProviderType,
185}
186
187/// Authentication provider types
188#[derive(Debug, Clone, PartialEq, Eq)]
189pub enum AuthProviderType {
190    Local,
191    LDAP,
192    OAuth2,
193    SAML,
194    JWT,
195    Custom(String),
196}
197
198/// Authentication result
199#[derive(Debug, Clone)]
200pub struct AuthResult {
201    pub success: bool,
202    pub user_info: Option<UserInfo>,
203    pub access_token: Option<String>,
204    pub refresh_token: Option<String>,
205    pub expires_at: Option<SystemTime>,
206    pub error_message: Option<String>,
207}
208
209/// User information
210#[derive(Debug, Clone)]
211pub struct UserInfo {
212    pub user_id: String,
213    pub username: String,
214    pub email: String,
215    pub full_name: String,
216    pub roles: Vec<Role>,
217    pub groups: Vec<String>,
218    pub metadata: HashMap<String, String>,
219}
220
221/// User role
222#[derive(Debug, Clone)]
223pub struct Role {
224    pub role_id: String,
225    pub role_name: String,
226    pub permissions: Vec<Permission>,
227    pub description: String,
228}
229
230/// Token validation result
231#[derive(Debug, Clone)]
232pub struct TokenValidation {
233    pub valid: bool,
234    pub user_id: Option<String>,
235    pub expires_at: Option<SystemTime>,
236    pub scopes: Vec<String>,
237}
238
239/// Permission manager for access control
240pub struct PermissionManager {
241    role_definitions: HashMap<String, Role>,
242    permission_cache: HashMap<String, Vec<Permission>>,
243    access_policies: Vec<AccessPolicy>,
244}
245
246/// Access policy
247#[derive(Debug, Clone)]
248pub struct AccessPolicy {
249    pub policy_id: String,
250    pub resource: String,
251    pub action: String,
252    pub conditions: Vec<AccessCondition>,
253    pub effect: PolicyEffect,
254}
255
256/// Policy effect
257#[derive(Debug, Clone, PartialEq, Eq)]
258pub enum PolicyEffect {
259    Allow,
260    Deny,
261}
262
263/// Access condition
264#[derive(Debug, Clone)]
265pub struct AccessCondition {
266    pub condition_type: ConditionType,
267    pub operator: ConditionOperator,
268    pub value: String,
269}
270
271/// Condition types
272#[derive(Debug, Clone, PartialEq, Eq)]
273pub enum ConditionType {
274    UserRole,
275    UserGroup,
276    TimeOfDay,
277    DayOfWeek,
278    IpAddress,
279    ResourceOwner,
280    Custom(String),
281}
282
283/// Condition operators
284#[derive(Debug, Clone, PartialEq, Eq)]
285pub enum ConditionOperator {
286    Equals,
287    NotEquals,
288    Contains,
289    StartsWith,
290    EndsWith,
291    GreaterThan,
292    LessThan,
293    InRange,
294    Custom(String),
295}
296
297/// Session activity tracking
298#[derive(Debug, Clone)]
299pub struct SessionActivity {
300    pub session_id: String,
301    pub user_id: String,
302    pub activity_type: ActivityType,
303    pub timestamp: SystemTime,
304    pub ip_address: String,
305    pub user_agent: String,
306    pub resource_accessed: Option<String>,
307    pub metadata: HashMap<String, String>,
308}
309
310/// Activity types
311#[derive(Debug, Clone, PartialEq, Eq)]
312pub enum ActivityType {
313    Login,
314    Logout,
315    DashboardView,
316    ChartInteraction,
317    DataExport,
318    ConfigurationChange,
319    AlertAcknowledgement,
320    Custom(String),
321}
322
323/// Audit logging
324pub struct AuditLogger {
325    log_config: AuditLogConfig,
326    log_storage: Box<dyn LogStorage + Send + Sync>,
327    log_buffer: Vec<AuditEvent>,
328}
329
330/// Audit log configuration
331#[derive(Debug, Clone)]
332pub struct AuditLogConfig {
333    pub enabled: bool,
334    pub log_level: AuditLogLevel,
335    pub retention_period: Duration,
336    pub include_sensitive_data: bool,
337    pub encryption_enabled: bool,
338}
339
340/// Audit log levels
341#[derive(Debug, Clone, PartialEq, Eq)]
342pub enum AuditLogLevel {
343    Debug,
344    Info,
345    Warning,
346    Error,
347    Critical,
348}
349
350/// Audit event
351#[derive(Debug, Clone)]
352pub struct AuditEvent {
353    pub event_id: String,
354    pub timestamp: SystemTime,
355    pub user_id: Option<String>,
356    pub session_id: Option<String>,
357    pub event_type: AuditEventType,
358    pub resource: String,
359    pub action: String,
360    pub result: AuditResult,
361    pub ip_address: String,
362    pub user_agent: String,
363    pub details: HashMap<String, String>,
364}
365
366/// Audit event types
367#[derive(Debug, Clone, PartialEq, Eq)]
368pub enum AuditEventType {
369    Authentication,
370    Authorization,
371    DataAccess,
372    DataModification,
373    SystemChange,
374    SecurityEvent,
375    Custom(String),
376}
377
378/// Audit result
379#[derive(Debug, Clone, PartialEq, Eq)]
380pub enum AuditResult {
381    Success,
382    Failure,
383    Unauthorized,
384    Forbidden,
385    Error,
386}
387
388/// Log storage trait
389pub trait LogStorage {
390    fn store(&self, event: &AuditEvent) -> DeviceResult<()>;
391    fn query(&self, criteria: &QueryCriteria) -> DeviceResult<Vec<AuditEvent>>;
392    fn purge_old_logs(&self, before: SystemTime) -> DeviceResult<usize>;
393}
394
395/// Query criteria for log retrieval
396#[derive(Debug, Clone)]
397pub struct QueryCriteria {
398    pub start_time: Option<SystemTime>,
399    pub end_time: Option<SystemTime>,
400    pub user_id: Option<String>,
401    pub event_type: Option<AuditEventType>,
402    pub resource: Option<String>,
403    pub result: Option<AuditResult>,
404    pub limit: Option<usize>,
405}
406
407impl SessionManager {
408    pub fn new(config: SessionConfig, auth_provider: Box<dyn AuthProvider + Send + Sync>) -> Self {
409        Self {
410            active_sessions: HashMap::new(),
411            session_config: config,
412            auth_provider,
413            permission_manager: PermissionManager::new(),
414        }
415    }
416
417    pub async fn create_session(&mut self, credentials: &Credentials) -> DeviceResult<UserSession> {
418        // Authenticate user
419        let auth_result = self.auth_provider.authenticate(credentials)?;
420
421        if !auth_result.success {
422            return Err(crate::DeviceError::APIError(
423                "Authentication failed".to_string(),
424            ));
425        }
426
427        let user_info = auth_result
428            .user_info
429            .ok_or_else(|| crate::DeviceError::APIError("Missing user information".to_string()))?;
430
431        // Create session
432        let session_id = self.generate_session_id();
433        let expires_at = SystemTime::now() + self.session_config.session_timeout;
434
435        let permissions = self.permission_manager.get_user_permissions(&user_info)?;
436        let preferences = self.load_user_preferences(&user_info.user_id).await?;
437
438        let session = UserSession {
439            session_id: session_id.clone(),
440            user_id: user_info.user_id.clone(),
441            permissions,
442            preferences,
443            last_activity: SystemTime::now(),
444            session_data: HashMap::new(),
445            auth_token: auth_result.access_token,
446            expires_at,
447        };
448
449        // Check concurrent session limit
450        self.enforce_session_limits(&user_info.user_id)?;
451
452        self.active_sessions
453            .insert(session_id.clone(), session.clone());
454
455        Ok(session)
456    }
457
458    pub fn validate_session(&mut self, session_id: &str) -> DeviceResult<&mut UserSession> {
459        // First check if session exists and is not expired
460        if let Some(session) = self.active_sessions.get(session_id) {
461            if SystemTime::now() > session.expires_at {
462                self.active_sessions.remove(session_id);
463                return Err(crate::DeviceError::APIError("Session expired".to_string()));
464            }
465        } else {
466            return Err(crate::DeviceError::APIError("Invalid session".to_string()));
467        }
468
469        // Now get mutable reference and update last activity
470        // SAFETY: We verified the session exists above, so this should never fail
471        let session = self
472            .active_sessions
473            .get_mut(session_id)
474            .expect("Session was verified to exist");
475        session.last_activity = SystemTime::now();
476
477        Ok(session)
478    }
479
480    pub fn terminate_session(&mut self, session_id: &str) -> DeviceResult<()> {
481        if let Some(session) = self.active_sessions.remove(session_id) {
482            // Logout from auth provider if token exists
483            if let Some(token) = &session.auth_token {
484                let _ = self.auth_provider.logout(token);
485            }
486        }
487
488        Ok(())
489    }
490
491    pub fn cleanup_expired_sessions(&mut self) -> DeviceResult<usize> {
492        let now = SystemTime::now();
493        let expired_sessions: Vec<String> = self
494            .active_sessions
495            .iter()
496            .filter(|(_, session)| now > session.expires_at)
497            .map(|(id, _)| id.clone())
498            .collect();
499
500        let count = expired_sessions.len();
501        for session_id in expired_sessions {
502            self.active_sessions.remove(&session_id);
503        }
504
505        Ok(count)
506    }
507
508    pub async fn update_user_preferences(
509        &mut self,
510        user_id: &str,
511        preferences: UserPreferences,
512    ) -> DeviceResult<()> {
513        // Update preferences for all active sessions of this user
514        for session in self.active_sessions.values_mut() {
515            if session.user_id == user_id {
516                session.preferences = preferences.clone();
517            }
518        }
519
520        // Persist preferences
521        self.save_user_preferences(user_id, &preferences).await?;
522
523        Ok(())
524    }
525
526    pub fn get_session_statistics(&self) -> SessionStatistics {
527        let total_sessions = self.active_sessions.len();
528        let mut sessions_by_user = HashMap::new();
529        let mut recent_activity_count = 0;
530        let recent_threshold = SystemTime::now() - Duration::from_secs(5 * 60);
531
532        for session in self.active_sessions.values() {
533            *sessions_by_user.entry(session.user_id.clone()).or_insert(0) += 1;
534
535            if session.last_activity > recent_threshold {
536                recent_activity_count += 1;
537            }
538        }
539
540        SessionStatistics {
541            total_active_sessions: total_sessions,
542            sessions_by_user,
543            recent_activity_count,
544            average_session_duration: self.calculate_average_session_duration(),
545        }
546    }
547
548    fn generate_session_id(&self) -> String {
549        // Generate secure session ID
550        // SAFETY: SystemTime::now() is always after UNIX_EPOCH
551        format!(
552            "session_{}",
553            SystemTime::now()
554                .duration_since(std::time::UNIX_EPOCH)
555                .unwrap_or(Duration::ZERO)
556                .as_nanos()
557        )
558    }
559
560    fn enforce_session_limits(&mut self, user_id: &str) -> DeviceResult<()> {
561        let user_session_count = self
562            .active_sessions
563            .values()
564            .filter(|s| s.user_id == user_id)
565            .count();
566
567        if user_session_count >= self.session_config.max_concurrent_sessions {
568            // Remove oldest session for this user
569            if let Some((oldest_session_id, _)) = self
570                .active_sessions
571                .iter()
572                .filter(|(_, s)| s.user_id == user_id)
573                .min_by_key(|(_, s)| s.last_activity)
574                .map(|(id, s)| (id.clone(), s.clone()))
575            {
576                self.active_sessions.remove(&oldest_session_id);
577            }
578        }
579
580        Ok(())
581    }
582
583    async fn load_user_preferences(&self, user_id: &str) -> DeviceResult<UserPreferences> {
584        // Simplified preference loading - in real implementation, load from database
585        Ok(UserPreferences::default())
586    }
587
588    async fn save_user_preferences(
589        &self,
590        user_id: &str,
591        preferences: &UserPreferences,
592    ) -> DeviceResult<()> {
593        // Simplified preference saving - in real implementation, save to database
594        Ok(())
595    }
596
597    fn calculate_average_session_duration(&self) -> Duration {
598        if self.active_sessions.is_empty() {
599            return Duration::from_secs(0);
600        }
601
602        let now = SystemTime::now();
603        let total_duration: Duration = self
604            .active_sessions
605            .values()
606            .map(|s| {
607                now.duration_since(s.last_activity)
608                    .unwrap_or(Duration::from_secs(0))
609            })
610            .sum();
611
612        total_duration / self.active_sessions.len() as u32
613    }
614}
615
616/// Session statistics
617#[derive(Debug, Clone)]
618pub struct SessionStatistics {
619    pub total_active_sessions: usize,
620    pub sessions_by_user: HashMap<String, usize>,
621    pub recent_activity_count: usize,
622    pub average_session_duration: Duration,
623}
624
625impl Default for PermissionManager {
626    fn default() -> Self {
627        Self::new()
628    }
629}
630
631impl PermissionManager {
632    pub fn new() -> Self {
633        Self {
634            role_definitions: Self::create_default_roles(),
635            permission_cache: HashMap::new(),
636            access_policies: Vec::new(),
637        }
638    }
639
640    pub fn get_user_permissions(&mut self, user_info: &UserInfo) -> DeviceResult<Vec<Permission>> {
641        // Check cache first
642        if let Some(cached_permissions) = self.permission_cache.get(&user_info.user_id) {
643            return Ok(cached_permissions.clone());
644        }
645
646        // Calculate permissions from roles
647        let mut permissions = Vec::new();
648        for role in &user_info.roles {
649            if let Some(role_def) = self.role_definitions.get(&role.role_id) {
650                permissions.extend(role_def.permissions.clone());
651            }
652        }
653
654        // Remove duplicates
655        permissions.sort();
656        permissions.dedup();
657
658        // Cache permissions
659        self.permission_cache
660            .insert(user_info.user_id.clone(), permissions.clone());
661
662        Ok(permissions)
663    }
664
665    pub fn check_permission(
666        &self,
667        user_permissions: &[Permission],
668        required_permission: &Permission,
669    ) -> bool {
670        user_permissions.contains(required_permission)
671            || user_permissions.contains(&Permission::SystemAdmin)
672    }
673
674    pub fn evaluate_access_policy(
675        &self,
676        user_info: &UserInfo,
677        resource: &str,
678        action: &str,
679    ) -> DeviceResult<bool> {
680        for policy in &self.access_policies {
681            if policy.resource == resource
682                && policy.action == action
683                && self.evaluate_conditions(&policy.conditions, user_info)?
684            {
685                return Ok(policy.effect == PolicyEffect::Allow);
686            }
687        }
688
689        // Default deny
690        Ok(false)
691    }
692
693    fn create_default_roles() -> HashMap<String, Role> {
694        let mut roles = HashMap::new();
695
696        roles.insert(
697            "admin".to_string(),
698            Role {
699                role_id: "admin".to_string(),
700                role_name: "Administrator".to_string(),
701                permissions: vec![Permission::SystemAdmin],
702                description: "Full system access".to_string(),
703            },
704        );
705
706        roles.insert(
707            "viewer".to_string(),
708            Role {
709                role_id: "viewer".to_string(),
710                role_name: "Viewer".to_string(),
711                permissions: vec![Permission::ReadDashboard, Permission::ViewReports],
712                description: "Read-only access".to_string(),
713            },
714        );
715
716        roles.insert(
717            "operator".to_string(),
718            Role {
719                role_id: "operator".to_string(),
720                role_name: "Operator".to_string(),
721                permissions: vec![
722                    Permission::ReadDashboard,
723                    Permission::WriteDashboard,
724                    Permission::ManageAlerts,
725                    Permission::ExportData,
726                    Permission::ViewReports,
727                ],
728                description: "Operational access".to_string(),
729            },
730        );
731
732        roles
733    }
734
735    fn evaluate_conditions(
736        &self,
737        conditions: &[AccessCondition],
738        user_info: &UserInfo,
739    ) -> DeviceResult<bool> {
740        for condition in conditions {
741            if !self.evaluate_single_condition(condition, user_info)? {
742                return Ok(false);
743            }
744        }
745        Ok(true)
746    }
747
748    fn evaluate_single_condition(
749        &self,
750        condition: &AccessCondition,
751        user_info: &UserInfo,
752    ) -> DeviceResult<bool> {
753        match &condition.condition_type {
754            ConditionType::UserRole => {
755                let has_role = user_info.roles.iter().any(|r| r.role_id == condition.value);
756                Ok(match condition.operator {
757                    ConditionOperator::Equals => has_role,
758                    ConditionOperator::NotEquals => !has_role,
759                    _ => false,
760                })
761            }
762            ConditionType::UserGroup => {
763                let in_group = user_info.groups.contains(&condition.value);
764                Ok(match condition.operator {
765                    ConditionOperator::Equals => in_group,
766                    ConditionOperator::NotEquals => !in_group,
767                    _ => false,
768                })
769            }
770            _ => Ok(true), // Simplified - other conditions not implemented
771        }
772    }
773}
774
775impl AuditLogger {
776    pub fn new(config: AuditLogConfig, storage: Box<dyn LogStorage + Send + Sync>) -> Self {
777        Self {
778            log_config: config,
779            log_storage: storage,
780            log_buffer: Vec::new(),
781        }
782    }
783
784    pub fn log_event(&mut self, event: AuditEvent) -> DeviceResult<()> {
785        if !self.log_config.enabled {
786            return Ok(());
787        }
788
789        // Add to buffer
790        self.log_buffer.push(event);
791
792        // Flush if buffer is full
793        if self.log_buffer.len() >= 100 {
794            self.flush_buffer()?;
795        }
796
797        Ok(())
798    }
799
800    pub fn flush_buffer(&mut self) -> DeviceResult<()> {
801        for event in &self.log_buffer {
802            self.log_storage.store(event)?;
803        }
804        self.log_buffer.clear();
805        Ok(())
806    }
807
808    pub fn query_logs(&self, criteria: &QueryCriteria) -> DeviceResult<Vec<AuditEvent>> {
809        self.log_storage.query(criteria)
810    }
811}
812
813// Default implementations
814impl Default for UserPreferences {
815    fn default() -> Self {
816        Self {
817            dashboard_layout: "grid".to_string(),
818            default_time_range: "last_hour".to_string(),
819            chart_preferences: ChartPreferences::default(),
820            notification_preferences: NotificationPreferences::default(),
821            display_preferences: DisplayPreferences::default(),
822            custom_preferences: HashMap::new(),
823        }
824    }
825}
826
827impl Default for ChartPreferences {
828    fn default() -> Self {
829        Self {
830            preferred_chart_types: vec!["line".to_string(), "bar".to_string()],
831            color_scheme: "scientific".to_string(),
832            animation_enabled: true,
833            interactive_features: true,
834            default_aggregation: "minute".to_string(),
835            refresh_interval: 30,
836        }
837    }
838}
839
840impl Default for NotificationPreferences {
841    fn default() -> Self {
842        Self {
843            email_notifications: true,
844            browser_notifications: false,
845            slack_notifications: false,
846            notification_frequency: NotificationFrequency::Immediate,
847            alert_thresholds: HashMap::new(),
848            quiet_hours: None,
849        }
850    }
851}
852
853impl Default for DisplayPreferences {
854    fn default() -> Self {
855        Self {
856            theme: "light".to_string(),
857            font_size: "medium".to_string(),
858            density: DisplayDensity::Normal,
859            sidebar_collapsed: false,
860            show_tooltips: true,
861            language: "en".to_string(),
862            timezone: "UTC".to_string(),
863        }
864    }
865}
866
867impl Default for SessionConfig {
868    fn default() -> Self {
869        Self {
870            session_timeout: Duration::from_secs(8 * 3600),
871            max_concurrent_sessions: 5,
872            require_authentication: true,
873            enable_session_persistence: false,
874            cookie_settings: CookieSettings {
875                secure: true,
876                http_only: true,
877                same_site: SameSitePolicy::Strict,
878                domain: None,
879                path: "/".to_string(),
880                max_age: Duration::from_secs(8 * 3600),
881            },
882            security_settings: SecuritySettings {
883                csrf_protection: true,
884                rate_limiting: true,
885                ip_whitelist: None,
886                require_https: true,
887                enable_audit_logging: true,
888            },
889        }
890    }
891}
892
893impl Default for AuditLogConfig {
894    fn default() -> Self {
895        Self {
896            enabled: true,
897            log_level: AuditLogLevel::Info,
898            retention_period: Duration::from_secs(90 * 24 * 3600),
899            include_sensitive_data: false,
900            encryption_enabled: true,
901        }
902    }
903}