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