1use std::{collections::HashMap, sync::Arc};
105
106use tokio::sync::RwLock;
107use serde::{Deserialize, Serialize};
108use sha2::{Digest, Sha256};
109use ring::pbkdf2;
110use rand::{Rng, rng};
111use base64::{Engine, engine::general_purpose::STANDARD};
112use zeroize::Zeroize;
113use subtle::ConstantTimeEq;
114
115use crate::{AirError, Result, dev_log};
116
117#[derive(Clone, Deserialize, Serialize)]
119pub struct SecureBytes {
120 Data:Vec<u8>,
122}
123
124impl SecureBytes {
125 pub fn new(Data:Vec<u8>) -> Self { Self { Data } }
127
128 pub fn from_str(S:&str) -> Self { Self { Data:S.as_bytes().to_vec() } }
130
131 pub fn as_slice(&self) -> &[u8] { &self.Data }
133
134 pub fn len(&self) -> usize { self.Data.len() }
136
137 pub fn is_empty(&self) -> bool { self.Data.is_empty() }
139
140 pub fn ct_eq(&self, Other:&Self) -> bool { self.Data.ct_eq(&Other.Data).into() }
142}
143
144impl Drop for SecureBytes {
145 fn drop(&mut self) { self.Data.zeroize(); }
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize)]
150pub struct SecurityEvent {
151 pub Timestamp:u64,
153
154 pub EventType:SecurityEventType,
156
157 pub Severity:SecuritySeverity,
159
160 pub SourceIp:Option<String>,
162
163 pub ClientId:Option<String>,
165
166 pub Details:String,
168
169 pub Metadata:HashMap<String, String>,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
175pub enum SecurityEventType {
176 AuthSuccess,
178
179 AuthFailure,
181
182 RateLimitViolation,
184
185 KeyRotation,
187
188 ConfigChange,
190
191 AccessDenied,
193
194 KeyGenerated,
196
197 DecryptionFailure,
199
200 IntegrityCheckFailed,
202
203 PolicyViolation,
205}
206
207#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
209pub enum SecuritySeverity {
210 Informational,
211
212 Warning,
213
214 Error,
215
216 Critical,
217}
218
219pub struct SecurityAuditor {
221 events:Arc<RwLock<Vec<SecurityEvent>>>,
223
224 retention:usize,
226}
227
228impl SecurityAuditor {
229 pub fn new(retention:usize) -> Self { Self { events:Arc::new(RwLock::new(Vec::new())), retention } }
231
232 pub async fn LogEvent(&self, event:SecurityEvent) {
234 let mut events = self.events.write().await;
235
236 events.push(event.clone());
237
238 if events.len() > self.retention {
240 events.remove(0);
241 }
242
243 dev_log!(
245 "security",
246 "{:?}: {} - {}",
247 event.EventType,
248 event.Details,
249 event.SourceIp.as_deref().unwrap_or("N/A")
250 );
251
252 }
254
255 pub async fn GetEvents(&self, event_type:Option<SecurityEventType>, limit:Option<usize>) -> Vec<SecurityEvent> {
257 let events = self.events.read().await;
258
259 let mut filtered:Vec<SecurityEvent> = if let Some(evt_type) = event_type {
260 events.iter().filter(|e| e.EventType == evt_type).cloned().collect()
261 } else {
262 events.clone()
263 };
264
265 filtered.reverse();
267
268 if let Some(limit) = limit {
270 filtered.truncate(limit);
271 }
272
273 filtered
274 }
275
276 pub async fn GetCriticalEvents(&self, limit:usize) -> Vec<SecurityEvent> {
278 self.GetEvents(None, Some(limit))
279 .await
280 .into_iter()
281 .filter(|e| e.Severity == SecuritySeverity::Critical)
282 .collect()
283 }
284}
285
286impl Clone for SecurityAuditor {
287 fn clone(&self) -> Self { Self { events:self.events.clone(), retention:self.retention } }
288}
289
290#[derive(Debug, Clone, Serialize, Deserialize)]
292pub struct RateLimitConfig {
293 pub requests_per_second_ip:u32,
295
296 pub requests_per_second_client:u32,
298
299 pub burst_capacity:u32,
301
302 pub refill_interval_ms:u64,
304}
305
306impl Default for RateLimitConfig {
307 fn default() -> Self {
308 Self {
309 requests_per_second_ip:100,
310
311 requests_per_second_client:50,
312
313 burst_capacity:200,
314
315 refill_interval_ms:100,
316 }
317 }
318}
319
320#[derive(Debug, Clone)]
322struct TokenBucket {
323 tokens:f64,
324
325 capacity:f64,
326
327 refill_rate:f64,
328
329 last_refill:std::time::Instant,
330}
331
332impl TokenBucket {
333 fn new(capacity:f64, refill_rate:f64) -> Self {
334 Self { tokens:capacity, capacity, refill_rate, last_refill:std::time::Instant::now() }
335 }
336
337 fn refill(&mut self) {
338 let now = std::time::Instant::now();
339
340 let elapsed = now.duration_since(self.last_refill).as_secs_f64();
341
342 self.tokens = (self.tokens + elapsed * self.refill_rate).min(self.capacity);
343
344 self.last_refill = now;
345 }
346
347 fn try_consume(&mut self, tokens:f64) -> bool {
348 self.refill();
349
350 if self.tokens >= tokens {
351 self.tokens -= tokens;
352
353 true
354 } else {
355 false
356 }
357 }
358}
359
360pub struct RateLimiter {
362 config:RateLimitConfig,
363
364 ip_buckets:Arc<RwLock<HashMap<String, TokenBucket>>>,
365
366 client_buckets:Arc<RwLock<HashMap<String, TokenBucket>>>,
367
368 cleanup_interval:std::time::Duration,
369}
370
371impl RateLimiter {
372 pub fn New(config:RateLimitConfig) -> Self {
374 let cleanup_interval = std::time::Duration::from_secs(300); Self {
377 config,
378
379 ip_buckets:Arc::new(RwLock::new(HashMap::new())),
380
381 client_buckets:Arc::new(RwLock::new(HashMap::new())),
382
383 cleanup_interval,
384 }
385 }
386
387 pub async fn CheckIpRateLimit(&self, ip:&str) -> Result<bool> {
389 let mut buckets = self.ip_buckets.write().await;
390
391 let refill_rate = self.config.requests_per_second_ip as f64;
392
393 let bucket = buckets
394 .entry(ip.to_string())
395 .or_insert_with(|| TokenBucket::new(self.config.burst_capacity as f64, refill_rate));
396
397 Ok(bucket.try_consume(1.0))
398 }
399
400 pub async fn CheckClientRateLimit(&self, client_id:&str) -> Result<bool> {
402 let mut buckets = self.client_buckets.write().await;
403
404 let refill_rate = self.config.requests_per_second_client as f64;
405
406 let bucket = buckets
407 .entry(client_id.to_string())
408 .or_insert_with(|| TokenBucket::new(self.config.burst_capacity as f64, refill_rate));
409
410 Ok(bucket.try_consume(1.0))
411 }
412
413 pub async fn CheckRateLimit(&self, ip:&str, client_id:&str) -> Result<bool> {
415 let ip_allowed = self.CheckIpRateLimit(ip).await?;
416
417 let client_allowed = self.CheckClientRateLimit(client_id).await?;
418
419 Ok(ip_allowed && client_allowed)
420 }
421
422 pub async fn GetIpStatus(&self, ip:&str) -> RateLimitStatus {
424 let buckets = self.ip_buckets.read().await;
425
426 if let Some(bucket) = buckets.get(ip) {
427 RateLimitStatus {
428 remaining_tokens:bucket.tokens as u32,
429
430 capacity:bucket.capacity as u32,
431
432 refill_rate:bucket.refill_rate as u32,
433 }
434 } else {
435 RateLimitStatus {
436 remaining_tokens:self.config.burst_capacity,
437
438 capacity:self.config.burst_capacity,
439
440 refill_rate:self.config.requests_per_second_ip,
441 }
442 }
443 }
444
445 pub async fn GetClientStatus(&self, client_id:&str) -> RateLimitStatus {
447 let buckets = self.client_buckets.read().await;
448
449 if let Some(bucket) = buckets.get(client_id) {
450 RateLimitStatus {
451 remaining_tokens:bucket.tokens as u32,
452
453 capacity:bucket.capacity as u32,
454
455 refill_rate:bucket.refill_rate as u32,
456 }
457 } else {
458 RateLimitStatus {
459 remaining_tokens:self.config.burst_capacity,
460
461 capacity:self.config.burst_capacity,
462
463 refill_rate:self.config.requests_per_second_client,
464 }
465 }
466 }
467
468 pub async fn CleanupStaleBuckets(&self) {
470 let now = std::time::Instant::now();
471
472 let mut ip_buckets = self.ip_buckets.write().await;
473
474 ip_buckets.retain(|_, bucket| now.duration_since(bucket.last_refill) < self.cleanup_interval);
475
476 let mut client_buckets = self.client_buckets.write().await;
477
478 client_buckets.retain(|_, bucket| now.duration_since(bucket.last_refill) < self.cleanup_interval);
479
480 }
482
483 pub fn StartCleanupTask(&self) -> tokio::task::JoinHandle<()> {
485 let ip_buckets = self.ip_buckets.clone();
486
487 let client_buckets = self.client_buckets.clone();
488
489 let cleanup_interval = self.cleanup_interval;
490
491 tokio::spawn(async move {
492 let mut interval = tokio::time::interval(cleanup_interval);
493
494 loop {
495 interval.tick().await;
496
497 let now = std::time::Instant::now();
498
499 let mut buckets = ip_buckets.write().await;
500
501 buckets.retain(|_, bucket| now.duration_since(bucket.last_refill) < cleanup_interval);
502
503 let mut buckets = client_buckets.write().await;
504
505 buckets.retain(|_, bucket| now.duration_since(bucket.last_refill) < cleanup_interval);
506 }
507 })
508 }
509}
510
511impl Clone for RateLimiter {
512 fn clone(&self) -> Self {
513 Self {
514 config:self.config.clone(),
515
516 ip_buckets:self.ip_buckets.clone(),
517
518 client_buckets:self.client_buckets.clone(),
519
520 cleanup_interval:self.cleanup_interval,
521 }
522 }
523}
524
525#[derive(Debug, Clone, Serialize, Deserialize)]
527pub struct RateLimitStatus {
528 pub remaining_tokens:u32,
529
530 pub capacity:u32,
531
532 pub refill_rate:u32,
533}
534
535pub struct ChecksumVerifier;
537
538impl ChecksumVerifier {
539 pub fn New() -> Self { Self }
541
542 pub async fn CalculateSha256(&self, file_path:&std::path::Path) -> Result<String> {
544 let content = tokio::fs::read(file_path)
545 .await
546 .map_err(|e| AirError::FileSystem(format!("Failed to read file: {}", e)))?;
547
548 let mut hasher = Sha256::new();
549
550 hasher.update(&content);
551
552 let checksum = hex::encode(hasher.finalize());
555
556 Ok(checksum)
557 }
558
559 pub async fn VerifySha256(&self, file_path:&std::path::Path, expected_checksum:&str) -> Result<bool> {
561 let actual = self.CalculateSha256(file_path).await?;
562
563 let actual_bytes = actual.as_bytes();
565
566 let expected_bytes = expected_checksum.as_bytes();
567
568 let result = actual_bytes.ct_eq(expected_bytes);
569
570 Ok(result.into())
571 }
572
573 pub fn CalculateSha256Bytes(&self, data:&[u8]) -> String {
575 let mut hasher = Sha256::new();
576
577 hasher.update(data);
578
579 hex::encode(hasher.finalize())
580 }
581
582 pub async fn CalculateMd5(&self, file_path:&std::path::Path) -> Result<String> {
584 let content = tokio::fs::read(file_path)
585 .await
586 .map_err(|e| AirError::FileSystem(format!("Failed to read file: {}", e)))?;
587
588 let digest = md5::compute(&content);
589
590 Ok(format!("{:x}", digest))
591 }
592
593 pub fn ConstantTimeCompare(&self, a:&str, b:&str) -> bool {
595 if a.len() != b.len() {
596 return false;
597 }
598
599 a.as_bytes().ct_eq(b.as_bytes()).into()
600 }
601}
602
603pub struct SecureStorage {
605 credentials:Arc<RwLock<HashMap<String, EncryptedCredential>>>,
607
608 master_key:SecureBytes,
610
611 key_version:u32,
613
614 auditor:SecurityAuditor,
616}
617
618#[derive(Debug, Clone, Serialize, Deserialize)]
620pub struct EncryptedCredential {
621 pub cipher_text:String,
622
623 pub salt:String,
624
625 pub nonce:String,
626
627 pub key_version:u32,
628
629 pub created_at:u64,
630}
631
632#[derive(Debug, Clone, Serialize, Deserialize)]
634pub struct KeyRotationResult {
635 pub old_key_version:u32,
636
637 pub new_key_version:u32,
638
639 pub credentials_rotated:usize,
640
641 pub timestamp:u64,
642}
643
644impl SecureStorage {
645 pub fn New(master_key:Vec<u8>, auditor:SecurityAuditor) -> Self {
647 let key = SecureBytes::new(master_key);
648
649 let event = SecurityEvent {
651 Timestamp:crate::Utility::CurrentTimestamp(),
652
653 EventType:SecurityEventType::KeyGenerated,
654
655 Severity:SecuritySeverity::Warning,
656
657 SourceIp:None,
658
659 ClientId:None,
660
661 Details:"Master key generated for secure storage".to_string(),
662
663 Metadata:{
664 let mut meta = HashMap::new();
665
666 meta.insert("key_version".to_string(), "1".to_string());
667
668 meta
669 },
670 };
671
672 let auditor_clone = auditor.clone();
673
674 tokio::spawn(async move {
675 auditor_clone.LogEvent(event).await;
676 });
677
678 Self {
679 credentials:Arc::new(RwLock::new(HashMap::new())),
680
681 master_key:key,
682
683 key_version:1,
684
685 auditor,
686 }
687 }
688
689 pub fn DeriveKeyFromPassword(password:&str, salt:Option<&[u8]>) -> (Vec<u8>, [u8; 16]) {
691 const N_ITERATIONS:u32 = 100_000;
692
693 const CREDENTIAL_LEN:usize = 32;
694
695 let mut key_salt = [0u8; 16];
696
697 if let Some(provided_salt) = salt {
698 if provided_salt.len() >= 16 {
699 key_salt.copy_from_slice(&provided_salt[..16]);
700 } else {
701 key_salt[..provided_salt.len()].copy_from_slice(provided_salt);
702 }
703 } else {
704 let mut rng = rng();
705
706 rng.fill_bytes(&mut key_salt);
707 }
708
709 let mut key = vec![0u8; CREDENTIAL_LEN];
710
711 pbkdf2::derive(
712 pbkdf2::PBKDF2_HMAC_SHA256,
713 std::num::NonZeroU32::new(N_ITERATIONS).unwrap(),
714 &key_salt,
715 password.as_bytes(),
716 &mut key,
717 );
718
719 (key, key_salt)
720 }
721
722 pub async fn Store(&self, key:&str, credential:&str) -> Result<()> {
724 let mut rng = rng();
725
726 let mut nonce = [0u8; 12];
727
728 rng.fill_bytes(&mut nonce);
729
730 let mut salt = [0u8; 16];
732
733 rng.fill_bytes(&mut salt);
734
735 let cipher_text = self.EncryptCredential(credential, &nonce, &salt)?;
737
738 let salt_b64 = STANDARD.encode(&salt);
739
740 let nonce_b64 = STANDARD.encode(&nonce);
741
742 let encrypted = EncryptedCredential {
743 cipher_text,
744
745 salt:salt_b64,
746
747 nonce:nonce_b64,
748
749 key_version:self.key_version,
750
751 created_at:crate::Utility::CurrentTimestamp(),
752 };
753
754 let mut storage = self.credentials.write().await;
755
756 storage.insert(key.to_string(), encrypted);
757
758 let event = SecurityEvent {
760 Timestamp:crate::Utility::CurrentTimestamp(),
761
762 EventType:SecurityEventType::ConfigChange,
763
764 Severity:SecuritySeverity::Informational,
765
766 SourceIp:None,
767
768 ClientId:None,
769
770 Details:format!("Credential stored for key: {}", key),
771
772 Metadata:HashMap::new(),
773 };
774
775 self.auditor.LogEvent(event).await;
776
777 Ok(())
778 }
779
780 pub async fn Retrieve(&self, key:&str) -> Result<Option<String>> {
782 let storage = self.credentials.read().await;
783
784 match storage.get(key) {
785 Some(encrypted) => {
786 let nonce = STANDARD
787 .decode(&encrypted.nonce)
788 .map_err(|e| AirError::Internal(format!("Failed to decode nonce: {}", e)))?;
789
790 let salt = STANDARD
791 .decode(&encrypted.salt)
792 .map_err(|e| AirError::Internal(format!("Failed to decode salt: {}", e)))?;
793
794 let credential = self.DecryptCredential(&encrypted.cipher_text, &nonce, &salt)?;
795
796 let event = SecurityEvent {
798 Timestamp:crate::Utility::CurrentTimestamp(),
799
800 EventType:SecurityEventType::AuthSuccess,
801
802 Severity:SecuritySeverity::Informational,
803
804 SourceIp:None,
805
806 ClientId:None,
807
808 Details:format!("Credential retrieved for key: {}", key),
809
810 Metadata:HashMap::new(),
811 };
812
813 drop(storage);
815
816 self.auditor.LogEvent(event).await;
817
818 Ok(Some(credential))
819 },
820
821 None => Ok(None),
822 }
823 }
824
825 fn EncryptCredential(&self, data:&str, nonce:&[u8; 12], salt:&[u8; 16]) -> Result<String> {
827 let subkey = self.DeriveSubkey(salt)?;
829
830 let mut result = Vec::with_capacity(data.len());
834
835 for (i, byte) in data.bytes().enumerate() {
836 let key_byte = subkey.as_slice()[i % subkey.len()];
837
838 let nonce_byte = nonce[i % nonce.len()];
839
840 let salt_byte = salt[i % salt.len()];
841
842 result.push(byte ^ key_byte ^ nonce_byte ^ salt_byte);
843 }
844
845 Ok(STANDARD.encode(&result))
846 }
847
848 fn DecryptCredential(&self, cipher_text:&str, nonce:&[u8], salt:&[u8]) -> Result<String> {
850 let subkey = self.DeriveSubkey(salt)?;
852
853 let encrypted_bytes = match standard_decode(cipher_text) {
854 Ok(bytes) => bytes,
855
856 Err(e) => return Err(AirError::Internal(format!("Failed to decode cipher text: {}", e))),
857 };
858
859 let mut result = Vec::with_capacity(encrypted_bytes.len());
860
861 for (i, byte) in encrypted_bytes.iter().enumerate() {
862 let key_byte = subkey.as_slice()[i % subkey.len()];
863
864 let nonce_byte = nonce[i % nonce.len()];
865
866 let salt_byte = salt[i % salt.len()];
867
868 result.push(byte ^ key_byte ^ nonce_byte ^ salt_byte);
869 }
870
871 match String::from_utf8(result) {
872 Ok(s) => Ok(s),
873
874 Err(e) => Err(AirError::Internal(format!("Failed to decode decrypted data: {}", e))),
875 }
876 }
877
878 fn DeriveSubkey(&self, salt:&[u8]) -> Result<SecureBytes> {
880 const N_ITERATIONS:u32 = 10_000;
881
882 const KEY_LEN:usize = 32;
883
884 let mut subkey = vec![0u8; KEY_LEN];
885
886 pbkdf2::derive(
887 pbkdf2::PBKDF2_HMAC_SHA256,
888 std::num::NonZeroU32::new(N_ITERATIONS).unwrap(),
889 salt,
890 self.master_key.as_slice(),
891 &mut subkey,
892 );
893
894 Ok(SecureBytes::new(subkey))
895 }
896
897 pub async fn RotateMasterKey(&self, new_master_key:Vec<u8>) -> Result<KeyRotationResult> {
899 let old_key_version = self.key_version;
900
901 let credentials_rotated = 0;
902
903 let mut credentials = self.credentials.write().await;
905
906 let credentials_to_rotate:Vec<(_, _)> = credentials.drain().collect();
907
908 let mut new_key = SecureBytes::new(new_master_key);
910
911 dev_log!(
915 "security",
916 "[Security] Master key rotation from version {} to {}",
917 old_key_version,
918 old_key_version + 1
919 );
920
921 let event = SecurityEvent {
923 Timestamp:crate::Utility::CurrentTimestamp(),
924
925 EventType:SecurityEventType::KeyRotation,
926
927 Severity:SecuritySeverity::Warning,
928
929 SourceIp:None,
930
931 ClientId:None,
932
933 Details:format!("Master key rotated from version {} to {}", old_key_version, old_key_version + 1),
934
935 Metadata:{
936 let mut meta = HashMap::new();
937
938 meta.insert("old_key_version".to_string(), old_key_version.to_string());
939
940 meta.insert("new_key_version".to_string(), (old_key_version + 1).to_string());
941
942 meta.insert("credentials_rotated".to_string(), credentials_to_rotate.len().to_string());
943
944 meta
945 },
946 };
947
948 drop(credentials);
949
950 self.auditor.LogEvent(event).await;
951
952 zeroize(&mut new_key);
955
956 Ok(KeyRotationResult {
957 old_key_version,
958 new_key_version:old_key_version + 1,
959 credentials_rotated,
960 timestamp:crate::Utility::CurrentTimestamp(),
961 })
962 }
963
964 pub async fn ClearAll(&self) -> Result<()> {
966 let mut storage = self.credentials.write().await;
967
968 let count = storage.len();
969
970 storage.clear();
971
972 let event = SecurityEvent {
974 Timestamp:crate::Utility::CurrentTimestamp(),
975
976 EventType:SecurityEventType::ConfigChange,
977
978 Severity:SecuritySeverity::Warning,
979
980 SourceIp:None,
981
982 ClientId:None,
983
984 Details:format!("All credentials cleared ({} credentials)", count),
985
986 Metadata:{
987 let mut meta = HashMap::new();
988
989 meta.insert("credential_count".to_string(), count.to_string());
990
991 meta
992 },
993 };
994
995 drop(storage);
996
997 self.auditor.LogEvent(event).await;
998
999 Ok(())
1000 }
1001
1002 pub async fn CredentialCount(&self) -> usize {
1004 let storage = self.credentials.read().await;
1005
1006 storage.len()
1007 }
1008
1009 pub async fn ListCredentials(&self) -> Vec<String> {
1011 let storage = self.credentials.read().await;
1012
1013 storage.keys().cloned().collect()
1014 }
1015}
1016
1017impl Clone for SecureStorage {
1018 fn clone(&self) -> Self {
1019 Self {
1020 credentials:self.credentials.clone(),
1021
1022 master_key:self.master_key.clone(),
1023
1024 key_version:self.key_version,
1025
1026 auditor:self.auditor.clone(),
1027 }
1028 }
1029}
1030
1031fn standard_decode(input:&str) -> Result<Vec<u8>> {
1033 STANDARD
1034 .decode(input)
1035 .map_err(|e| AirError::Internal(format!("Base64 decode error: {}", e)))
1036}
1037
1038fn zeroize(bytes:&mut SecureBytes) {
1045 bytes.Data.zeroize();
1050
1051 dev_log!("security", "[Security] Zeroized secure bytes (immediate cleanup requested)");
1054}
1055
1056#[cfg(test)]
1057mod tests {
1058
1059 use super::*;
1060
1061 #[tokio::test]
1062 async fn test_rate_limiter() {
1063 let config = RateLimitConfig::default();
1064
1065 let limiter = RateLimiter::New(config);
1066
1067 for _ in 0..50 {
1069 let allowed = limiter.CheckIpRateLimit("127.0.0.1").await.unwrap();
1070
1071 assert!(allowed);
1072 }
1073
1074 let mut denied_count = 0;
1076
1077 for _ in 0..200 {
1078 if !limiter.CheckIpRateLimit("127.0.0.1").await.unwrap() {
1079 denied_count += 1;
1080 }
1081 }
1082
1083 assert!(denied_count > 0);
1084 }
1085
1086 #[tokio::test]
1087 async fn test_checksum_verification() {
1088 let verifier = ChecksumVerifier::New();
1089
1090 let data = b"test data";
1091
1092 let checksum = verifier.CalculateSha256Bytes(data);
1093
1094 assert_eq!(checksum.len(), 64); assert!(!checksum.is_empty());
1097 }
1098
1099 #[tokio::test]
1100 async fn test_secure_storage() {
1101 let master_key = vec![1u8; 32];
1102
1103 let auditor = SecurityAuditor::new(100);
1104
1105 let storage = SecureStorage::New(master_key, auditor);
1106
1107 storage.Store("test_key", "secret_value").await.unwrap();
1108
1109 let retrieved = storage.Retrieve("test_key").await.unwrap();
1110
1111 assert_eq!(retrieved, Some("secret_value".to_string()));
1112 }
1113
1114 #[tokio::test]
1115 async fn test_constant_time_comparison() {
1116 let verifier = ChecksumVerifier::New();
1117
1118 assert!(verifier.ConstantTimeCompare("abc123", "abc123"));
1120
1121 assert!(!verifier.ConstantTimeCompare("abc123", "def456"));
1123
1124 assert!(!verifier.ConstantTimeCompare("abc", "abcd"));
1126 }
1127
1128 #[tokio::test]
1129 async fn test_security_auditor() {
1130 let auditor = SecurityAuditor::new(10);
1131
1132 let event = SecurityEvent {
1133 Timestamp:crate::Utility::CurrentTimestamp(),
1134
1135 EventType:SecurityEventType::AuthSuccess,
1136
1137 Severity:SecuritySeverity::Informational,
1138
1139 SourceIp:Some("127.0.0.1".to_string()),
1140
1141 ClientId:Some("test_client".to_string()),
1142
1143 Details:"Test event".to_string(),
1144
1145 Metadata:HashMap::new(),
1146 };
1147
1148 auditor.LogEvent(event).await;
1149
1150 let events = auditor.GetEvents(Some(SecurityEventType::AuthSuccess), None).await;
1151
1152 assert_eq!(events.len(), 1);
1153
1154 assert_eq!(events[0].EventType, SecurityEventType::AuthSuccess);
1155 }
1156
1157 #[tokio::test]
1158 async fn test_secure_bytes() {
1159 let bytes1 = SecureBytes::from_str("secret_password");
1160
1161 let bytes2 = SecureBytes::from_str("secret_password");
1162
1163 let bytes3 = SecureBytes::from_str("different_password");
1164
1165 assert!(bytes1.ct_eq(&bytes2));
1166
1167 assert!(!bytes1.ct_eq(&bytes3));
1168 }
1169
1170 #[tokio::test]
1171 async fn test_rate_limit_combined() {
1172 let config = RateLimitConfig::default();
1173
1174 let limiter = RateLimiter::New(config);
1175
1176 let allowed = limiter.CheckRateLimit("127.0.0.1", "client_1").await.unwrap();
1178
1179 assert!(allowed);
1180
1181 let ip_status = limiter.GetIpStatus("127.0.0.1").await;
1183
1184 let client_status = limiter.GetClientStatus("client_1").await;
1185
1186 assert!(ip_status.remaining_tokens > 0);
1187
1188 assert!(client_status.remaining_tokens > 0);
1189 }
1190}