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 pub EventType:SecurityEventType,
155 pub Severity:SecuritySeverity,
157 pub SourceIp:Option<String>,
159 pub ClientId:Option<String>,
161 pub Details:String,
163 pub Metadata:HashMap<String, String>,
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
169pub enum SecurityEventType {
170 AuthSuccess,
172 AuthFailure,
174 RateLimitViolation,
176 KeyRotation,
178 ConfigChange,
180 AccessDenied,
182 KeyGenerated,
184 DecryptionFailure,
186 IntegrityCheckFailed,
188 PolicyViolation,
190}
191
192#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
194pub enum SecuritySeverity {
195 Informational,
196 Warning,
197 Error,
198 Critical,
199}
200
201pub struct SecurityAuditor {
203 events:Arc<RwLock<Vec<SecurityEvent>>>,
205 retention:usize,
207}
208
209impl SecurityAuditor {
210 pub fn new(retention:usize) -> Self { Self { events:Arc::new(RwLock::new(Vec::new())), retention } }
212
213 pub async fn LogEvent(&self, event:SecurityEvent) {
215 let mut events = self.events.write().await;
216 events.push(event.clone());
217
218 if events.len() > self.retention {
220 events.remove(0);
221 }
222
223 dev_log!(
225 "security",
226 "{:?}: {} - {}",
227 event.EventType,
228 event.Details,
229 event.SourceIp.as_deref().unwrap_or("N/A")
230 );
231
232 }
234
235 pub async fn GetEvents(&self, event_type:Option<SecurityEventType>, limit:Option<usize>) -> Vec<SecurityEvent> {
237 let events = self.events.read().await;
238
239 let mut filtered:Vec<SecurityEvent> = if let Some(evt_type) = event_type {
240 events.iter().filter(|e| e.EventType == evt_type).cloned().collect()
241 } else {
242 events.clone()
243 };
244
245 filtered.reverse();
247
248 if let Some(limit) = limit {
250 filtered.truncate(limit);
251 }
252
253 filtered
254 }
255
256 pub async fn GetCriticalEvents(&self, limit:usize) -> Vec<SecurityEvent> {
258 self.GetEvents(None, Some(limit))
259 .await
260 .into_iter()
261 .filter(|e| e.Severity == SecuritySeverity::Critical)
262 .collect()
263 }
264}
265
266impl Clone for SecurityAuditor {
267 fn clone(&self) -> Self { Self { events:self.events.clone(), retention:self.retention } }
268}
269
270#[derive(Debug, Clone, Serialize, Deserialize)]
272pub struct RateLimitConfig {
273 pub requests_per_second_ip:u32,
275
276 pub requests_per_second_client:u32,
278
279 pub burst_capacity:u32,
281
282 pub refill_interval_ms:u64,
284}
285
286impl Default for RateLimitConfig {
287 fn default() -> Self {
288 Self {
289 requests_per_second_ip:100,
290 requests_per_second_client:50,
291 burst_capacity:200,
292 refill_interval_ms:100,
293 }
294 }
295}
296
297#[derive(Debug, Clone)]
299struct TokenBucket {
300 tokens:f64,
301 capacity:f64,
302 refill_rate:f64,
303 last_refill:std::time::Instant,
304}
305
306impl TokenBucket {
307 fn new(capacity:f64, refill_rate:f64) -> Self {
308 Self { tokens:capacity, capacity, refill_rate, last_refill:std::time::Instant::now() }
309 }
310
311 fn refill(&mut self) {
312 let now = std::time::Instant::now();
313 let elapsed = now.duration_since(self.last_refill).as_secs_f64();
314 self.tokens = (self.tokens + elapsed * self.refill_rate).min(self.capacity);
315 self.last_refill = now;
316 }
317
318 fn try_consume(&mut self, tokens:f64) -> bool {
319 self.refill();
320 if self.tokens >= tokens {
321 self.tokens -= tokens;
322 true
323 } else {
324 false
325 }
326 }
327}
328
329pub struct RateLimiter {
331 config:RateLimitConfig,
332 ip_buckets:Arc<RwLock<HashMap<String, TokenBucket>>>,
333 client_buckets:Arc<RwLock<HashMap<String, TokenBucket>>>,
334 cleanup_interval:std::time::Duration,
335}
336
337impl RateLimiter {
338 pub fn New(config:RateLimitConfig) -> Self {
340 let cleanup_interval = std::time::Duration::from_secs(300); Self {
343 config,
344 ip_buckets:Arc::new(RwLock::new(HashMap::new())),
345 client_buckets:Arc::new(RwLock::new(HashMap::new())),
346 cleanup_interval,
347 }
348 }
349
350 pub async fn CheckIpRateLimit(&self, ip:&str) -> Result<bool> {
352 let mut buckets = self.ip_buckets.write().await;
353
354 let refill_rate = self.config.requests_per_second_ip as f64;
355 let bucket = buckets
356 .entry(ip.to_string())
357 .or_insert_with(|| TokenBucket::new(self.config.burst_capacity as f64, refill_rate));
358
359 Ok(bucket.try_consume(1.0))
360 }
361
362 pub async fn CheckClientRateLimit(&self, client_id:&str) -> Result<bool> {
364 let mut buckets = self.client_buckets.write().await;
365
366 let refill_rate = self.config.requests_per_second_client as f64;
367 let bucket = buckets
368 .entry(client_id.to_string())
369 .or_insert_with(|| TokenBucket::new(self.config.burst_capacity as f64, refill_rate));
370
371 Ok(bucket.try_consume(1.0))
372 }
373
374 pub async fn CheckRateLimit(&self, ip:&str, client_id:&str) -> Result<bool> {
376 let ip_allowed = self.CheckIpRateLimit(ip).await?;
377 let client_allowed = self.CheckClientRateLimit(client_id).await?;
378
379 Ok(ip_allowed && client_allowed)
380 }
381
382 pub async fn GetIpStatus(&self, ip:&str) -> RateLimitStatus {
384 let buckets = self.ip_buckets.read().await;
385
386 if let Some(bucket) = buckets.get(ip) {
387 RateLimitStatus {
388 remaining_tokens:bucket.tokens as u32,
389 capacity:bucket.capacity as u32,
390 refill_rate:bucket.refill_rate as u32,
391 }
392 } else {
393 RateLimitStatus {
394 remaining_tokens:self.config.burst_capacity,
395 capacity:self.config.burst_capacity,
396 refill_rate:self.config.requests_per_second_ip,
397 }
398 }
399 }
400
401 pub async fn GetClientStatus(&self, client_id:&str) -> RateLimitStatus {
403 let buckets = self.client_buckets.read().await;
404
405 if let Some(bucket) = buckets.get(client_id) {
406 RateLimitStatus {
407 remaining_tokens:bucket.tokens as u32,
408 capacity:bucket.capacity as u32,
409 refill_rate:bucket.refill_rate as u32,
410 }
411 } else {
412 RateLimitStatus {
413 remaining_tokens:self.config.burst_capacity,
414 capacity:self.config.burst_capacity,
415 refill_rate:self.config.requests_per_second_client,
416 }
417 }
418 }
419
420 pub async fn CleanupStaleBuckets(&self) {
422 let now = std::time::Instant::now();
423
424 let mut ip_buckets = self.ip_buckets.write().await;
425 ip_buckets.retain(|_, bucket| now.duration_since(bucket.last_refill) < self.cleanup_interval);
426
427 let mut client_buckets = self.client_buckets.write().await;
428 client_buckets.retain(|_, bucket| now.duration_since(bucket.last_refill) < self.cleanup_interval);
429
430 }
432
433 pub fn StartCleanupTask(&self) -> tokio::task::JoinHandle<()> {
435 let ip_buckets = self.ip_buckets.clone();
436 let client_buckets = self.client_buckets.clone();
437 let cleanup_interval = self.cleanup_interval;
438
439 tokio::spawn(async move {
440 let mut interval = tokio::time::interval(cleanup_interval);
441
442 loop {
443 interval.tick().await;
444
445 let now = std::time::Instant::now();
446
447 let mut buckets = ip_buckets.write().await;
448 buckets.retain(|_, bucket| now.duration_since(bucket.last_refill) < cleanup_interval);
449
450 let mut buckets = client_buckets.write().await;
451 buckets.retain(|_, bucket| now.duration_since(bucket.last_refill) < cleanup_interval);
452 }
453 })
454 }
455}
456
457impl Clone for RateLimiter {
458 fn clone(&self) -> Self {
459 Self {
460 config:self.config.clone(),
461 ip_buckets:self.ip_buckets.clone(),
462 client_buckets:self.client_buckets.clone(),
463 cleanup_interval:self.cleanup_interval,
464 }
465 }
466}
467
468#[derive(Debug, Clone, Serialize, Deserialize)]
470pub struct RateLimitStatus {
471 pub remaining_tokens:u32,
472 pub capacity:u32,
473 pub refill_rate:u32,
474}
475
476pub struct ChecksumVerifier;
478
479impl ChecksumVerifier {
480 pub fn New() -> Self { Self }
482 pub async fn CalculateSha256(&self, file_path:&std::path::Path) -> Result<String> {
484 let content = tokio::fs::read(file_path)
485 .await
486 .map_err(|e| AirError::FileSystem(format!("Failed to read file: {}", e)))?;
487
488 let mut hasher = Sha256::new();
489 hasher.update(&content);
490 let checksum = format!("{:x}", hasher.finalize());
491
492 Ok(checksum)
493 }
494
495 pub async fn VerifySha256(&self, file_path:&std::path::Path, expected_checksum:&str) -> Result<bool> {
497 let actual = self.CalculateSha256(file_path).await?;
498
499 let actual_bytes = actual.as_bytes();
501 let expected_bytes = expected_checksum.as_bytes();
502
503 let result = actual_bytes.ct_eq(expected_bytes);
504
505 Ok(result.into())
506 }
507
508 pub fn CalculateSha256Bytes(&self, data:&[u8]) -> String {
510 let mut hasher = Sha256::new();
511 hasher.update(data);
512 format!("{:x}", hasher.finalize())
513 }
514
515 pub async fn CalculateMd5(&self, file_path:&std::path::Path) -> Result<String> {
517 let content = tokio::fs::read(file_path)
518 .await
519 .map_err(|e| AirError::FileSystem(format!("Failed to read file: {}", e)))?;
520
521 let digest = md5::compute(&content);
522 Ok(format!("{:x}", digest))
523 }
524
525 pub fn ConstantTimeCompare(&self, a:&str, b:&str) -> bool {
527 if a.len() != b.len() {
528 return false;
529 }
530 a.as_bytes().ct_eq(b.as_bytes()).into()
531 }
532}
533
534pub struct SecureStorage {
536 credentials:Arc<RwLock<HashMap<String, EncryptedCredential>>>,
538
539 master_key:SecureBytes,
541
542 key_version:u32,
544
545 auditor:SecurityAuditor,
547}
548
549#[derive(Debug, Clone, Serialize, Deserialize)]
551pub struct EncryptedCredential {
552 pub cipher_text:String,
553 pub salt:String,
554 pub nonce:String,
555 pub key_version:u32,
556 pub created_at:u64,
557}
558
559#[derive(Debug, Clone, Serialize, Deserialize)]
561pub struct KeyRotationResult {
562 pub old_key_version:u32,
563 pub new_key_version:u32,
564 pub credentials_rotated:usize,
565 pub timestamp:u64,
566}
567
568impl SecureStorage {
569 pub fn New(master_key:Vec<u8>, auditor:SecurityAuditor) -> Self {
571 let key = SecureBytes::new(master_key);
572
573 let event = SecurityEvent {
575 Timestamp:crate::Utility::CurrentTimestamp(),
576 EventType:SecurityEventType::KeyGenerated,
577 Severity:SecuritySeverity::Warning,
578 SourceIp:None,
579 ClientId:None,
580 Details:"Master key generated for secure storage".to_string(),
581 Metadata:{
582 let mut meta = HashMap::new();
583 meta.insert("key_version".to_string(), "1".to_string());
584 meta
585 },
586 };
587
588 let auditor_clone = auditor.clone();
589 tokio::spawn(async move {
590 auditor_clone.LogEvent(event).await;
591 });
592
593 Self {
594 credentials:Arc::new(RwLock::new(HashMap::new())),
595 master_key:key,
596 key_version:1,
597 auditor,
598 }
599 }
600
601 pub fn DeriveKeyFromPassword(password:&str, salt:Option<&[u8]>) -> (Vec<u8>, [u8; 16]) {
603 const N_ITERATIONS:u32 = 100_000;
604 const CREDENTIAL_LEN:usize = 32;
605
606 let mut key_salt = [0u8; 16];
607
608 if let Some(provided_salt) = salt {
609 if provided_salt.len() >= 16 {
610 key_salt.copy_from_slice(&provided_salt[..16]);
611 } else {
612 key_salt[..provided_salt.len()].copy_from_slice(provided_salt);
613 }
614 } else {
615 let mut rng = rng();
616 rng.fill_bytes(&mut key_salt);
617 }
618
619 let mut key = vec![0u8; CREDENTIAL_LEN];
620 pbkdf2::derive(
621 pbkdf2::PBKDF2_HMAC_SHA256,
622 std::num::NonZeroU32::new(N_ITERATIONS).unwrap(),
623 &key_salt,
624 password.as_bytes(),
625 &mut key,
626 );
627
628 (key, key_salt)
629 }
630
631 pub async fn Store(&self, key:&str, credential:&str) -> Result<()> {
633 let mut rng = rng();
634 let mut nonce = [0u8; 12];
635 rng.fill_bytes(&mut nonce);
636
637 let mut salt = [0u8; 16];
639 rng.fill_bytes(&mut salt);
640
641 let cipher_text = self.EncryptCredential(credential, &nonce, &salt)?;
643
644 let salt_b64 = STANDARD.encode(&salt);
645 let nonce_b64 = STANDARD.encode(&nonce);
646
647 let encrypted = EncryptedCredential {
648 cipher_text,
649 salt:salt_b64,
650 nonce:nonce_b64,
651 key_version:self.key_version,
652 created_at:crate::Utility::CurrentTimestamp(),
653 };
654
655 let mut storage = self.credentials.write().await;
656 storage.insert(key.to_string(), encrypted);
657
658 let event = SecurityEvent {
660 Timestamp:crate::Utility::CurrentTimestamp(),
661 EventType:SecurityEventType::ConfigChange,
662 Severity:SecuritySeverity::Informational,
663 SourceIp:None,
664 ClientId:None,
665 Details:format!("Credential stored for key: {}", key),
666 Metadata:HashMap::new(),
667 };
668
669 self.auditor.LogEvent(event).await;
670
671 Ok(())
672 }
673
674 pub async fn Retrieve(&self, key:&str) -> Result<Option<String>> {
676 let storage = self.credentials.read().await;
677
678 match storage.get(key) {
679 Some(encrypted) => {
680 let nonce = STANDARD
681 .decode(&encrypted.nonce)
682 .map_err(|e| AirError::Internal(format!("Failed to decode nonce: {}", e)))?;
683
684 let salt = STANDARD
685 .decode(&encrypted.salt)
686 .map_err(|e| AirError::Internal(format!("Failed to decode salt: {}", e)))?;
687
688 let credential = self.DecryptCredential(&encrypted.cipher_text, &nonce, &salt)?;
689
690 let event = SecurityEvent {
692 Timestamp:crate::Utility::CurrentTimestamp(),
693 EventType:SecurityEventType::AuthSuccess,
694 Severity:SecuritySeverity::Informational,
695 SourceIp:None,
696 ClientId:None,
697 Details:format!("Credential retrieved for key: {}", key),
698 Metadata:HashMap::new(),
699 };
700
701 drop(storage);
703 self.auditor.LogEvent(event).await;
704
705 Ok(Some(credential))
706 },
707 None => Ok(None),
708 }
709 }
710
711 fn EncryptCredential(&self, data:&str, nonce:&[u8; 12], salt:&[u8; 16]) -> Result<String> {
713 let subkey = self.DeriveSubkey(salt)?;
715
716 let mut result = Vec::with_capacity(data.len());
720
721 for (i, byte) in data.bytes().enumerate() {
722 let key_byte = subkey.as_slice()[i % subkey.len()];
723 let nonce_byte = nonce[i % nonce.len()];
724 let salt_byte = salt[i % salt.len()];
725 result.push(byte ^ key_byte ^ nonce_byte ^ salt_byte);
726 }
727
728 Ok(STANDARD.encode(&result))
729 }
730
731 fn DecryptCredential(&self, cipher_text:&str, nonce:&[u8], salt:&[u8]) -> Result<String> {
733 let subkey = self.DeriveSubkey(salt)?;
735
736 let encrypted_bytes = match standard_decode(cipher_text) {
737 Ok(bytes) => bytes,
738 Err(e) => return Err(AirError::Internal(format!("Failed to decode cipher text: {}", e))),
739 };
740
741 let mut result = Vec::with_capacity(encrypted_bytes.len());
742
743 for (i, byte) in encrypted_bytes.iter().enumerate() {
744 let key_byte = subkey.as_slice()[i % subkey.len()];
745 let nonce_byte = nonce[i % nonce.len()];
746 let salt_byte = salt[i % salt.len()];
747 result.push(byte ^ key_byte ^ nonce_byte ^ salt_byte);
748 }
749
750 match String::from_utf8(result) {
751 Ok(s) => Ok(s),
752 Err(e) => Err(AirError::Internal(format!("Failed to decode decrypted data: {}", e))),
753 }
754 }
755
756 fn DeriveSubkey(&self, salt:&[u8]) -> Result<SecureBytes> {
758 const N_ITERATIONS:u32 = 10_000;
759 const KEY_LEN:usize = 32;
760
761 let mut subkey = vec![0u8; KEY_LEN];
762
763 pbkdf2::derive(
764 pbkdf2::PBKDF2_HMAC_SHA256,
765 std::num::NonZeroU32::new(N_ITERATIONS).unwrap(),
766 salt,
767 self.master_key.as_slice(),
768 &mut subkey,
769 );
770
771 Ok(SecureBytes::new(subkey))
772 }
773
774 pub async fn RotateMasterKey(&self, new_master_key:Vec<u8>) -> Result<KeyRotationResult> {
776 let old_key_version = self.key_version;
777 let credentials_rotated = 0;
778
779 let mut credentials = self.credentials.write().await;
781 let credentials_to_rotate:Vec<(_, _)> = credentials.drain().collect();
782
783 let mut new_key = SecureBytes::new(new_master_key);
785
786 dev_log!(
790 "security",
791 "[Security] Master key rotation from version {} to {}",
792 old_key_version,
793 old_key_version + 1
794 );
795
796 let event = SecurityEvent {
798 Timestamp:crate::Utility::CurrentTimestamp(),
799 EventType:SecurityEventType::KeyRotation,
800 Severity:SecuritySeverity::Warning,
801 SourceIp:None,
802 ClientId:None,
803 Details:format!("Master key rotated from version {} to {}", old_key_version, old_key_version + 1),
804 Metadata:{
805 let mut meta = HashMap::new();
806 meta.insert("old_key_version".to_string(), old_key_version.to_string());
807 meta.insert("new_key_version".to_string(), (old_key_version + 1).to_string());
808 meta.insert("credentials_rotated".to_string(), credentials_to_rotate.len().to_string());
809 meta
810 },
811 };
812
813 drop(credentials);
814 self.auditor.LogEvent(event).await;
815
816 zeroize(&mut new_key);
819
820 Ok(KeyRotationResult {
821 old_key_version,
822 new_key_version:old_key_version + 1,
823 credentials_rotated,
824 timestamp:crate::Utility::CurrentTimestamp(),
825 })
826 }
827
828 pub async fn ClearAll(&self) -> Result<()> {
830 let mut storage = self.credentials.write().await;
831 let count = storage.len();
832 storage.clear();
833
834 let event = SecurityEvent {
836 Timestamp:crate::Utility::CurrentTimestamp(),
837 EventType:SecurityEventType::ConfigChange,
838 Severity:SecuritySeverity::Warning,
839 SourceIp:None,
840 ClientId:None,
841 Details:format!("All credentials cleared ({} credentials)", count),
842 Metadata:{
843 let mut meta = HashMap::new();
844 meta.insert("credential_count".to_string(), count.to_string());
845 meta
846 },
847 };
848
849 drop(storage);
850 self.auditor.LogEvent(event).await;
851
852 Ok(())
853 }
854
855 pub async fn CredentialCount(&self) -> usize {
857 let storage = self.credentials.read().await;
858 storage.len()
859 }
860
861 pub async fn ListCredentials(&self) -> Vec<String> {
863 let storage = self.credentials.read().await;
864 storage.keys().cloned().collect()
865 }
866}
867
868impl Clone for SecureStorage {
869 fn clone(&self) -> Self {
870 Self {
871 credentials:self.credentials.clone(),
872 master_key:self.master_key.clone(),
873 key_version:self.key_version,
874 auditor:self.auditor.clone(),
875 }
876 }
877}
878
879fn standard_decode(input:&str) -> Result<Vec<u8>> {
881 STANDARD
882 .decode(input)
883 .map_err(|e| AirError::Internal(format!("Base64 decode error: {}", e)))
884}
885
886fn zeroize(bytes:&mut SecureBytes) {
893 bytes.Data.zeroize();
898 dev_log!("security", "[Security] Zeroized secure bytes (immediate cleanup requested)");
901}
902
903#[cfg(test)]
904mod tests {
905 use super::*;
906
907 #[tokio::test]
908 async fn test_rate_limiter() {
909 let config = RateLimitConfig::default();
910 let limiter = RateLimiter::New(config);
911
912 for _ in 0..50 {
914 let allowed = limiter.CheckIpRateLimit("127.0.0.1").await.unwrap();
915 assert!(allowed);
916 }
917
918 let mut denied_count = 0;
920 for _ in 0..200 {
921 if !limiter.CheckIpRateLimit("127.0.0.1").await.unwrap() {
922 denied_count += 1;
923 }
924 }
925 assert!(denied_count > 0);
926 }
927
928 #[tokio::test]
929 async fn test_checksum_verification() {
930 let verifier = ChecksumVerifier::New();
931 let data = b"test data";
932 let checksum = verifier.CalculateSha256Bytes(data);
933
934 assert_eq!(checksum.len(), 64); assert!(!checksum.is_empty());
936 }
937
938 #[tokio::test]
939 async fn test_secure_storage() {
940 let master_key = vec![1u8; 32];
941 let auditor = SecurityAuditor::new(100);
942 let storage = SecureStorage::New(master_key, auditor);
943
944 storage.Store("test_key", "secret_value").await.unwrap();
945 let retrieved = storage.Retrieve("test_key").await.unwrap();
946
947 assert_eq!(retrieved, Some("secret_value".to_string()));
948 }
949
950 #[tokio::test]
951 async fn test_constant_time_comparison() {
952 let verifier = ChecksumVerifier::New();
953
954 assert!(verifier.ConstantTimeCompare("abc123", "abc123"));
956
957 assert!(!verifier.ConstantTimeCompare("abc123", "def456"));
959
960 assert!(!verifier.ConstantTimeCompare("abc", "abcd"));
962 }
963
964 #[tokio::test]
965 async fn test_security_auditor() {
966 let auditor = SecurityAuditor::new(10);
967
968 let event = SecurityEvent {
969 Timestamp:crate::Utility::CurrentTimestamp(),
970 EventType:SecurityEventType::AuthSuccess,
971 Severity:SecuritySeverity::Informational,
972 SourceIp:Some("127.0.0.1".to_string()),
973 ClientId:Some("test_client".to_string()),
974 Details:"Test event".to_string(),
975 Metadata:HashMap::new(),
976 };
977
978 auditor.LogEvent(event).await;
979
980 let events = auditor.GetEvents(Some(SecurityEventType::AuthSuccess), None).await;
981 assert_eq!(events.len(), 1);
982 assert_eq!(events[0].EventType, SecurityEventType::AuthSuccess);
983 }
984
985 #[tokio::test]
986 async fn test_secure_bytes() {
987 let bytes1 = SecureBytes::from_str("secret_password");
988 let bytes2 = SecureBytes::from_str("secret_password");
989 let bytes3 = SecureBytes::from_str("different_password");
990
991 assert!(bytes1.ct_eq(&bytes2));
992 assert!(!bytes1.ct_eq(&bytes3));
993 }
994
995 #[tokio::test]
996 async fn test_rate_limit_combined() {
997 let config = RateLimitConfig::default();
998 let limiter = RateLimiter::New(config);
999
1000 let allowed = limiter.CheckRateLimit("127.0.0.1", "client_1").await.unwrap();
1002 assert!(allowed);
1003
1004 let ip_status = limiter.GetIpStatus("127.0.0.1").await;
1006 let client_status = limiter.GetClientStatus("client_1").await;
1007
1008 assert!(ip_status.remaining_tokens > 0);
1009 assert!(client_status.remaining_tokens > 0);
1010 }
1011}