leptos_sync_core/security/
gdpr.rs

1//! GDPR compliance system for data protection and privacy rights
2
3use crate::SyncError;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use tokio::sync::RwLock;
7use chrono::{DateTime, Utc, Duration};
8
9/// Data subject information for GDPR compliance
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct DataSubject {
12    pub id: String,
13    pub email: String,
14    pub name: String,
15    pub consent_given: bool,
16    pub consent_date: DateTime<Utc>,
17    pub consent_withdrawn_date: Option<DateTime<Utc>>,
18    pub data_retention_period: Option<Duration>,
19    pub created_at: DateTime<Utc>,
20    pub updated_at: DateTime<Utc>,
21}
22
23/// Data processing purpose for GDPR compliance
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
25pub enum DataProcessingPurpose {
26    ServiceProvision,
27    Analytics,
28    Marketing,
29    LegalCompliance,
30    Research,
31    Other(String),
32}
33
34/// Personal data record with metadata
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct PersonalDataRecord {
37    pub id: String,
38    pub subject_id: String,
39    pub data: Vec<u8>,
40    pub purpose: DataProcessingPurpose,
41    pub created_at: DateTime<Utc>,
42    pub expires_at: Option<DateTime<Utc>>,
43    pub is_encrypted: bool,
44    pub encryption_key_id: Option<String>,
45}
46
47/// Audit log entry for GDPR compliance
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct AuditLogEntry {
50    pub id: String,
51    pub user_id: String,
52    pub operation: String,
53    pub timestamp: String,
54    pub details: String,
55    pub ip_address: Option<String>,
56    pub user_agent: Option<String>,
57}
58
59/// GDPR compliance manager
60pub struct GDPRCompliance {
61    data_subjects: RwLock<HashMap<String, DataSubject>>,
62    personal_data: RwLock<HashMap<String, PersonalDataRecord>>,
63    audit_log: RwLock<Vec<AuditLogEntry>>,
64    consent_records: RwLock<HashMap<String, Vec<DataProcessingPurpose>>>,
65}
66
67impl GDPRCompliance {
68    /// Create a new GDPR compliance manager
69    pub fn new() -> Self {
70        Self {
71            data_subjects: RwLock::new(HashMap::new()),
72            personal_data: RwLock::new(HashMap::new()),
73            audit_log: RwLock::new(Vec::new()),
74            consent_records: RwLock::new(HashMap::new()),
75        }
76    }
77
78    /// Register a data subject
79    pub async fn register_data_subject(&self, subject: DataSubject) -> Result<(), SyncError> {
80        let subject_id = subject.id.clone();
81        
82        // Check if subject already exists
83        {
84            let subjects = self.data_subjects.read().await;
85            if subjects.contains_key(&subject_id) {
86                return Err(SyncError::GDPRError("Data subject already exists".to_string()));
87            }
88        }
89
90        // Store data subject
91        {
92            let mut subjects = self.data_subjects.write().await;
93            subjects.insert(subject_id.clone(), subject);
94        }
95
96        // Log the registration
97        self.log_audit_event(&subject_id, "DATA_SUBJECT_REGISTERED", "Data subject registered").await?;
98
99        Ok(())
100    }
101
102    /// Get data subject by ID
103    pub async fn get_data_subject(&self, subject_id: &str) -> Result<DataSubject, SyncError> {
104        let subjects = self.data_subjects.read().await;
105        subjects.get(subject_id)
106            .cloned()
107            .ok_or_else(|| SyncError::GDPRError("Data subject not found".to_string()))
108    }
109
110    /// Update data subject information
111    pub async fn update_data_subject(&self, subject_id: &str, updates: DataSubject) -> Result<(), SyncError> {
112        {
113            let mut subjects = self.data_subjects.write().await;
114            if let Some(subject) = subjects.get_mut(subject_id) {
115                *subject = updates;
116                subject.updated_at = Utc::now();
117            } else {
118                return Err(SyncError::GDPRError("Data subject not found".to_string()));
119            }
120        }
121
122        // Log the update
123        self.log_audit_event(subject_id, "DATA_SUBJECT_UPDATED", "Data subject information updated").await?;
124
125        Ok(())
126    }
127
128    /// Withdraw consent for data subject
129    pub async fn withdraw_consent(&self, subject_id: &str) -> Result<(), SyncError> {
130        {
131            let mut subjects = self.data_subjects.write().await;
132            if let Some(subject) = subjects.get_mut(subject_id) {
133                subject.consent_given = false;
134                subject.consent_withdrawn_date = Some(Utc::now());
135                subject.updated_at = Utc::now();
136            } else {
137                return Err(SyncError::GDPRError("Data subject not found".to_string()));
138            }
139        }
140
141        // Log the consent withdrawal
142        self.log_audit_event(subject_id, "CONSENT_WITHDRAWN", "Data subject withdrew consent").await?;
143
144        Ok(())
145    }
146
147    /// Withdraw consent for specific purpose
148    pub async fn withdraw_consent_for_purpose(&self, subject_id: &str, purpose: DataProcessingPurpose) -> Result<(), SyncError> {
149        // Remove data for the specific purpose
150        {
151            let mut personal_data = self.personal_data.write().await;
152            personal_data.retain(|_, record| {
153                !(record.subject_id == subject_id && record.purpose == purpose)
154            });
155        }
156
157        // Update consent records
158        {
159            let mut consent_records = self.consent_records.write().await;
160            if let Some(purposes) = consent_records.get_mut(subject_id) {
161                purposes.retain(|p| p != &purpose);
162            }
163        }
164
165        // Log the purpose-specific consent withdrawal
166        self.log_audit_event(subject_id, "CONSENT_WITHDRAWN_FOR_PURPOSE", 
167            &format!("Consent withdrawn for purpose: {:?}", purpose)).await?;
168
169        Ok(())
170    }
171
172    /// Store personal data
173    pub async fn store_personal_data(&self, subject_id: &str, data: &[u8], purpose: DataProcessingPurpose) -> Result<String, SyncError> {
174        // Check if data subject exists and has given consent
175        {
176            let subjects = self.data_subjects.read().await;
177            if let Some(subject) = subjects.get(subject_id) {
178                if !subject.consent_given {
179                    return Err(SyncError::GDPRError("No consent given for data processing".to_string()));
180                }
181            } else {
182                return Err(SyncError::GDPRError("Data subject not found".to_string()));
183            }
184        }
185
186        // Generate data record ID
187        let record_id = self.generate_record_id();
188
189        // Create personal data record
190        let record = PersonalDataRecord {
191            id: record_id.clone(),
192            subject_id: subject_id.to_string(),
193            data: data.to_vec(),
194            purpose: purpose.clone(),
195            created_at: Utc::now(),
196            expires_at: None,
197            is_encrypted: false,
198            encryption_key_id: None,
199        };
200
201        // Store the record
202        {
203            let mut personal_data = self.personal_data.write().await;
204            personal_data.insert(record_id.clone(), record);
205        }
206
207        // Update consent records
208        {
209            let mut consent_records = self.consent_records.write().await;
210            consent_records.entry(subject_id.to_string())
211                .or_insert_with(Vec::new)
212                .push(purpose.clone());
213        }
214
215        // Log the data storage
216        self.log_audit_event(subject_id, "PERSONAL_DATA_STORED", 
217            &format!("Personal data stored for purpose: {:?}", purpose)).await?;
218
219        Ok(record_id)
220    }
221
222    /// Store personal data with retention period
223    pub async fn store_personal_data_with_retention(&self, subject_id: &str, data: &[u8], purpose: DataProcessingPurpose, retention_period: Duration) -> Result<String, SyncError> {
224        // Check consent
225        {
226            let subjects = self.data_subjects.read().await;
227            if let Some(subject) = subjects.get(subject_id) {
228                if !subject.consent_given {
229                    return Err(SyncError::GDPRError("No consent given for data processing".to_string()));
230                }
231            } else {
232                return Err(SyncError::GDPRError("Data subject not found".to_string()));
233            }
234        }
235
236        let record_id = self.generate_record_id();
237        let expires_at = Utc::now() + retention_period;
238
239        let record = PersonalDataRecord {
240            id: record_id.clone(),
241            subject_id: subject_id.to_string(),
242            data: data.to_vec(),
243            purpose: purpose.clone(),
244            created_at: Utc::now(),
245            expires_at: Some(expires_at),
246            is_encrypted: false,
247            encryption_key_id: None,
248        };
249
250        {
251            let mut personal_data = self.personal_data.write().await;
252            personal_data.insert(record_id.clone(), record);
253        }
254
255        {
256            let mut consent_records = self.consent_records.write().await;
257            consent_records.entry(subject_id.to_string())
258                .or_insert_with(Vec::new)
259                .push(purpose.clone());
260        }
261
262        self.log_audit_event(subject_id, "PERSONAL_DATA_STORED_WITH_RETENTION", 
263            &format!("Personal data stored with retention period: {:?}", retention_period)).await?;
264
265        Ok(record_id)
266    }
267
268    /// Get personal data for a subject
269    pub async fn get_personal_data(&self, subject_id: &str) -> Result<Vec<u8>, SyncError> {
270        let personal_data = self.personal_data.read().await;
271        
272        // Find the first record for the subject (simplified implementation)
273        for record in personal_data.values() {
274            if record.subject_id == subject_id {
275                return Ok(record.data.clone());
276            }
277        }
278
279        Err(SyncError::GDPRError("No personal data found for subject".to_string()))
280    }
281
282    /// Export all personal data for a subject (Right to Data Portability)
283    pub async fn export_all_personal_data(&self, subject_id: &str) -> Result<Vec<Vec<u8>>, SyncError> {
284        let personal_data = self.personal_data.read().await;
285        
286        let mut exported_data = Vec::new();
287        for record in personal_data.values() {
288            if record.subject_id == subject_id {
289                exported_data.push(record.data.clone());
290            }
291        }
292
293        // Log the data export
294        self.log_audit_event(subject_id, "DATA_EXPORTED", "All personal data exported").await?;
295
296        Ok(exported_data)
297    }
298
299    /// Delete all personal data for a subject (Right to be Forgotten)
300    pub async fn delete_all_personal_data(&self, subject_id: &str) -> Result<(), SyncError> {
301        // Delete all personal data records
302        {
303            let mut personal_data = self.personal_data.write().await;
304            personal_data.retain(|_, record| record.subject_id != subject_id);
305        }
306
307        // Delete consent records
308        {
309            let mut consent_records = self.consent_records.write().await;
310            consent_records.remove(subject_id);
311        }
312
313        // Delete data subject record
314        {
315            let mut subjects = self.data_subjects.write().await;
316            subjects.remove(subject_id);
317        }
318
319        // Log the data deletion
320        self.log_audit_event(subject_id, "ALL_DATA_DELETED", "All personal data deleted (Right to be Forgotten)").await?;
321
322        Ok(())
323    }
324
325    /// Get audit log for a subject
326    pub async fn get_audit_log(&self, subject_id: &str) -> Result<Vec<AuditLogEntry>, SyncError> {
327        let audit_log = self.audit_log.read().await;
328        let subject_logs: Vec<AuditLogEntry> = audit_log
329            .iter()
330            .filter(|entry| entry.user_id == subject_id)
331            .cloned()
332            .collect();
333
334        Ok(subject_logs)
335    }
336
337    /// Clean up expired data
338    pub async fn cleanup_expired_data(&self) -> Result<usize, SyncError> {
339        let now = Utc::now();
340        let mut expired_count = 0;
341
342        {
343            let mut personal_data = self.personal_data.write().await;
344            personal_data.retain(|_, record| {
345                if let Some(expires_at) = record.expires_at {
346                    if now > expires_at {
347                        expired_count += 1;
348                        false
349                    } else {
350                        true
351                    }
352                } else {
353                    true
354                }
355            });
356        }
357
358        // Log the cleanup
359        self.log_audit_event("SYSTEM", "EXPIRED_DATA_CLEANUP", 
360            &format!("Cleaned up {} expired data records", expired_count)).await?;
361
362        Ok(expired_count)
363    }
364
365    /// Log audit event
366    async fn log_audit_event(&self, user_id: &str, operation: &str, details: &str) -> Result<(), SyncError> {
367        let entry = AuditLogEntry {
368            id: self.generate_audit_id(),
369            user_id: user_id.to_string(),
370            operation: operation.to_string(),
371            timestamp: Utc::now().to_rfc3339(),
372            details: details.to_string(),
373            ip_address: None,
374            user_agent: None,
375        };
376
377        {
378            let mut audit_log = self.audit_log.write().await;
379            audit_log.push(entry);
380        }
381
382        Ok(())
383    }
384
385    /// Generate unique record ID
386    fn generate_record_id(&self) -> String {
387        use rand::{Rng, rngs::OsRng};
388        use base64::{Engine as _, engine::general_purpose};
389        let mut rng = OsRng;
390        let random_bytes: [u8; 16] = rng.r#gen();
391        format!("record_{}", general_purpose::STANDARD.encode(random_bytes))
392    }
393
394    /// Generate unique audit ID
395    fn generate_audit_id(&self) -> String {
396        use rand::{Rng, rngs::OsRng};
397        use base64::{Engine as _, engine::general_purpose};
398        let mut rng = OsRng;
399        let random_bytes: [u8; 16] = rng.r#gen();
400        format!("audit_{}", general_purpose::STANDARD.encode(random_bytes))
401    }
402
403    /// Get all data subjects
404    pub async fn list_data_subjects(&self) -> Vec<DataSubject> {
405        let subjects = self.data_subjects.read().await;
406        subjects.values().cloned().collect()
407    }
408
409    /// Get data processing purposes for a subject
410    pub async fn get_processing_purposes(&self, subject_id: &str) -> Result<Vec<DataProcessingPurpose>, SyncError> {
411        let consent_records = self.consent_records.read().await;
412        Ok(consent_records.get(subject_id).cloned().unwrap_or_default())
413    }
414
415    /// Check if subject has given consent for a specific purpose
416    pub async fn has_consent_for_purpose(&self, subject_id: &str, purpose: &DataProcessingPurpose) -> Result<bool, SyncError> {
417        let consent_records = self.consent_records.read().await;
418        Ok(consent_records.get(subject_id)
419            .map(|purposes| purposes.contains(purpose))
420            .unwrap_or(false))
421    }
422}
423
424#[cfg(test)]
425mod tests {
426    use super::*;
427
428    #[tokio::test]
429    async fn test_data_subject_registration() {
430        let gdpr = GDPRCompliance::new();
431        let subject = DataSubject {
432            id: "user_123".to_string(),
433            email: "user@example.com".to_string(),
434            name: "John Doe".to_string(),
435            consent_given: true,
436            consent_date: Utc::now(),
437            consent_withdrawn_date: None,
438            data_retention_period: None,
439            created_at: Utc::now(),
440            updated_at: Utc::now(),
441        };
442        
443        let result = gdpr.register_data_subject(subject.clone()).await;
444        assert!(result.is_ok());
445        
446        // Verify subject is registered
447        let retrieved = gdpr.get_data_subject("user_123").await.unwrap();
448        assert_eq!(retrieved.email, subject.email);
449    }
450
451    #[tokio::test]
452    async fn test_consent_management() {
453        let gdpr = GDPRCompliance::new();
454        let subject = DataSubject {
455            id: "user_123".to_string(),
456            email: "user@example.com".to_string(),
457            name: "John Doe".to_string(),
458            consent_given: true,
459            consent_date: Utc::now(),
460            consent_withdrawn_date: None,
461            data_retention_period: None,
462            created_at: Utc::now(),
463            updated_at: Utc::now(),
464        };
465        
466        gdpr.register_data_subject(subject).await.unwrap();
467        
468        // Withdraw consent
469        gdpr.withdraw_consent("user_123").await.unwrap();
470        
471        // Verify consent is withdrawn
472        let subject = gdpr.get_data_subject("user_123").await.unwrap();
473        assert!(!subject.consent_given);
474        assert!(subject.consent_withdrawn_date.is_some());
475    }
476
477    #[tokio::test]
478    async fn test_right_to_be_forgotten() {
479        let gdpr = GDPRCompliance::new();
480        let subject = DataSubject {
481            id: "user_123".to_string(),
482            email: "user@example.com".to_string(),
483            name: "John Doe".to_string(),
484            consent_given: true,
485            consent_date: Utc::now(),
486            consent_withdrawn_date: None,
487            data_retention_period: None,
488            created_at: Utc::now(),
489            updated_at: Utc::now(),
490        };
491        
492        gdpr.register_data_subject(subject).await.unwrap();
493        
494        // Store some data
495        let data = "sensitive_user_data".as_bytes();
496        gdpr.store_personal_data("user_123", data, DataProcessingPurpose::ServiceProvision).await.unwrap();
497        
498        // Exercise right to be forgotten
499        gdpr.delete_all_personal_data("user_123").await.unwrap();
500        
501        // Verify data is deleted
502        let retrieved_data = gdpr.get_personal_data("user_123").await;
503        assert!(retrieved_data.is_err());
504        
505        // Verify subject is deleted
506        let retrieved_subject = gdpr.get_data_subject("user_123").await;
507        assert!(retrieved_subject.is_err());
508    }
509
510    #[tokio::test]
511    async fn test_data_portability() {
512        let gdpr = GDPRCompliance::new();
513        let subject = DataSubject {
514            id: "user_123".to_string(),
515            email: "user@example.com".to_string(),
516            name: "John Doe".to_string(),
517            consent_given: true,
518            consent_date: Utc::now(),
519            consent_withdrawn_date: None,
520            data_retention_period: None,
521            created_at: Utc::now(),
522            updated_at: Utc::now(),
523        };
524        
525        gdpr.register_data_subject(subject).await.unwrap();
526        
527        // Store some data
528        let data1 = "data1".as_bytes();
529        let data2 = "data2".as_bytes();
530        gdpr.store_personal_data("user_123", data1, DataProcessingPurpose::ServiceProvision).await.unwrap();
531        gdpr.store_personal_data("user_123", data2, DataProcessingPurpose::Analytics).await.unwrap();
532        
533        // Export all data
534        let exported_data = gdpr.export_all_personal_data("user_123").await.unwrap();
535        assert!(exported_data.contains(&data1.to_vec()));
536        assert!(exported_data.contains(&data2.to_vec()));
537    }
538
539    #[tokio::test]
540    async fn test_data_processing_purposes() {
541        let gdpr = GDPRCompliance::new();
542        let subject = DataSubject {
543            id: "user_123".to_string(),
544            email: "user@example.com".to_string(),
545            name: "John Doe".to_string(),
546            consent_given: true,
547            consent_date: Utc::now(),
548            consent_withdrawn_date: None,
549            data_retention_period: None,
550            created_at: Utc::now(),
551            updated_at: Utc::now(),
552        };
553        
554        gdpr.register_data_subject(subject).await.unwrap();
555        
556        // Store data for different purposes
557        let service_data = "service_data".as_bytes();
558        let analytics_data = "analytics_data".as_bytes();
559        
560        gdpr.store_personal_data("user_123", service_data, DataProcessingPurpose::ServiceProvision).await.unwrap();
561        gdpr.store_personal_data("user_123", analytics_data, DataProcessingPurpose::Analytics).await.unwrap();
562        
563        // Withdraw consent for analytics only
564        gdpr.withdraw_consent_for_purpose("user_123", DataProcessingPurpose::Analytics).await.unwrap();
565        
566        // Verify analytics data is deleted but service data remains
567        let all_data = gdpr.export_all_personal_data("user_123").await.unwrap();
568        assert!(all_data.contains(&service_data.to_vec()));
569        assert!(!all_data.contains(&analytics_data.to_vec()));
570    }
571
572    #[tokio::test]
573    async fn test_data_retention_policy() {
574        let gdpr = GDPRCompliance::new();
575        let subject = DataSubject {
576            id: "user_123".to_string(),
577            email: "user@example.com".to_string(),
578            name: "John Doe".to_string(),
579            consent_given: true,
580            consent_date: Utc::now(),
581            consent_withdrawn_date: None,
582            data_retention_period: None,
583            created_at: Utc::now(),
584            updated_at: Utc::now(),
585        };
586        
587        gdpr.register_data_subject(subject).await.unwrap();
588        
589        // Store data with retention period
590        let data = "temporary_data".as_bytes();
591        gdpr.store_personal_data_with_retention("user_123", data, DataProcessingPurpose::ServiceProvision, Duration::seconds(1)).await.unwrap();
592        
593        // Wait for retention period to expire
594        tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
595        
596        // Trigger retention cleanup
597        let cleaned_count = gdpr.cleanup_expired_data().await.unwrap();
598        assert_eq!(cleaned_count, 1);
599        
600        // Verify data is deleted
601        let retrieved_data = gdpr.get_personal_data("user_123").await;
602        assert!(retrieved_data.is_err());
603    }
604
605    #[tokio::test]
606    async fn test_audit_logging() {
607        let gdpr = GDPRCompliance::new();
608        let subject = DataSubject {
609            id: "user_123".to_string(),
610            email: "user@example.com".to_string(),
611            name: "John Doe".to_string(),
612            consent_given: true,
613            consent_date: Utc::now(),
614            consent_withdrawn_date: None,
615            data_retention_period: None,
616            created_at: Utc::now(),
617            updated_at: Utc::now(),
618        };
619        
620        gdpr.register_data_subject(subject).await.unwrap();
621        
622        // Perform various operations
623        gdpr.store_personal_data("user_123", b"test_data", DataProcessingPurpose::ServiceProvision).await.unwrap();
624        gdpr.withdraw_consent("user_123").await.unwrap();
625        gdpr.delete_all_personal_data("user_123").await.unwrap();
626        
627        // Get audit log
628        let audit_log = gdpr.get_audit_log("user_123").await.unwrap();
629        assert!(audit_log.len() >= 3); // At least 3 operations logged
630        
631        // Verify log entries contain required information
632        for entry in audit_log {
633            assert!(!entry.timestamp.is_empty());
634            assert!(!entry.operation.is_empty());
635            assert!(!entry.user_id.is_empty());
636        }
637    }
638
639    #[tokio::test]
640    async fn test_consent_validation() {
641        let gdpr = GDPRCompliance::new();
642        let subject = DataSubject {
643            id: "user_123".to_string(),
644            email: "user@example.com".to_string(),
645            name: "John Doe".to_string(),
646            consent_given: false, // No consent given
647            consent_date: Utc::now(),
648            consent_withdrawn_date: None,
649            data_retention_period: None,
650            created_at: Utc::now(),
651            updated_at: Utc::now(),
652        };
653        
654        gdpr.register_data_subject(subject).await.unwrap();
655        
656        // Try to store data without consent
657        let result = gdpr.store_personal_data("user_123", b"test_data", DataProcessingPurpose::ServiceProvision).await;
658        assert!(result.is_err());
659        assert!(result.unwrap_err().to_string().contains("No consent given"));
660    }
661
662    #[tokio::test]
663    async fn test_duplicate_subject_registration() {
664        let gdpr = GDPRCompliance::new();
665        let subject = DataSubject {
666            id: "user_123".to_string(),
667            email: "user@example.com".to_string(),
668            name: "John Doe".to_string(),
669            consent_given: true,
670            consent_date: Utc::now(),
671            consent_withdrawn_date: None,
672            data_retention_period: None,
673            created_at: Utc::now(),
674            updated_at: Utc::now(),
675        };
676        
677        // Register first time
678        let result1 = gdpr.register_data_subject(subject.clone()).await;
679        assert!(result1.is_ok());
680        
681        // Try to register same subject again
682        let result2 = gdpr.register_data_subject(subject).await;
683        assert!(result2.is_err());
684        assert!(result2.unwrap_err().to_string().contains("already exists"));
685    }
686}