use anyhow::Result;
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
#[cfg(feature = "enhanced")]
pub mod enhanced;
pub mod file;
pub mod memory;
pub mod neutralization;
pub use file::FileAuditLogger;
pub use memory::InMemoryAuditLogger;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AuditEventId(pub String);
impl Default for AuditEventId {
fn default() -> Self {
Self::new()
}
}
impl AuditEventId {
pub fn new() -> Self {
Self(uuid::Uuid::new_v4().to_string())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum AuditSeverity {
Info,
Warning,
Error,
Critical,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AuditEventType {
AuthSuccess { user_id: String },
AuthFailure {
user_id: Option<String>,
reason: String,
},
AccessGranted { user_id: String, resource: String },
AccessDenied {
user_id: String,
resource: String,
reason: String,
},
ThreatDetected {
client_id: String,
threat_count: u32,
},
ThreatBlocked {
client_id: String,
threat_type: String,
},
NeutralizationStarted {
client_id: String,
threat_id: String,
threat_type: String,
},
NeutralizationCompleted {
client_id: String,
threat_id: String,
action: String,
duration_ms: u64,
},
NeutralizationFailed {
client_id: String,
threat_id: String,
error: String,
},
NeutralizationSkipped {
client_id: String,
threat_id: String,
reason: String,
},
NeutralizationRolledBack {
client_id: String,
threat_id: String,
reason: String,
},
RateLimitTriggered {
client_id: String,
limit_type: String,
},
ConfigChanged {
changed_by: String,
changes: HashMap<String, String>,
},
ConfigReloaded {
success: bool,
error: Option<String>,
},
PluginLoaded {
plugin_id: String,
plugin_name: String,
},
PluginUnloaded { plugin_id: String, reason: String },
PluginError { plugin_id: String, error: String },
ServerStarted { version: String },
ServerStopped { reason: String },
SystemError { component: String, error: String },
Custom {
event_type: String,
data: serde_json::Value,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditEvent {
pub id: AuditEventId,
pub timestamp: DateTime<Utc>,
pub event_type: AuditEventType,
pub severity: AuditSeverity,
pub client_id: Option<String>,
pub ip_address: Option<String>,
pub user_agent: Option<String>,
pub context: HashMap<String, serde_json::Value>,
pub tags: Vec<String>,
}
impl AuditEvent {
pub fn new(event_type: AuditEventType, severity: AuditSeverity) -> Self {
Self {
id: AuditEventId::new(),
timestamp: Utc::now(),
event_type,
severity,
client_id: None,
ip_address: None,
user_agent: None,
context: HashMap::new(),
tags: Vec::new(),
}
}
pub fn with_client_id(mut self, client_id: String) -> Self {
self.client_id = Some(client_id);
self
}
pub fn with_ip_address(mut self, ip: String) -> Self {
self.ip_address = Some(ip);
self
}
pub fn with_context(mut self, key: String, value: serde_json::Value) -> Self {
self.context.insert(key, value);
self
}
pub fn with_tags(mut self, tags: Vec<String>) -> Self {
self.tags = tags;
self
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AuditFilter {
pub min_severity: Option<AuditSeverity>,
pub event_type_pattern: Option<String>,
pub client_id: Option<String>,
pub ip_address: Option<String>,
pub start_time: Option<DateTime<Utc>>,
pub end_time: Option<DateTime<Utc>>,
pub tags: Vec<String>,
pub limit: Option<usize>,
pub offset: Option<usize>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AuditStats {
pub total_events: u64,
pub events_by_severity: HashMap<String, u64>,
pub events_by_type: HashMap<String, u64>,
pub storage_size_bytes: u64,
pub oldest_event: Option<DateTime<Utc>>,
pub newest_event: Option<DateTime<Utc>>,
}
#[async_trait]
pub trait AuditLogger: Send + Sync {
async fn log(&self, event: AuditEvent) -> Result<AuditEventId>;
async fn log_batch(&self, events: Vec<AuditEvent>) -> Result<Vec<AuditEventId>>;
async fn query(&self, filter: AuditFilter) -> Result<Vec<AuditEvent>>;
async fn get_event(&self, id: &AuditEventId) -> Result<Option<AuditEvent>>;
async fn delete_before(&self, timestamp: DateTime<Utc>) -> Result<u64>;
async fn get_stats(&self) -> Result<AuditStats>;
async fn export(&self, filter: AuditFilter, format: ExportFormat) -> Result<Vec<u8>>;
async fn verify_integrity(&self) -> Result<IntegrityReport>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ExportFormat {
Json,
Csv,
Syslog,
Cef, }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntegrityReport {
pub intact: bool,
pub events_checked: u64,
pub issues: Vec<String>,
pub verified_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditConfig {
pub enabled: bool,
pub backend: AuditBackend,
pub retention_days: u32,
pub max_events: Option<u64>,
pub buffer_size: usize,
pub file_path: Option<String>,
pub rotation: Option<RotationConfig>,
pub compress: bool,
pub encrypt: bool,
pub custom_config: HashMap<String, serde_json::Value>,
}
impl Default for AuditConfig {
fn default() -> Self {
Self {
enabled: false,
backend: AuditBackend::Memory,
retention_days: 90,
max_events: Some(1_000_000),
buffer_size: 1000,
file_path: Some("./audit.log".to_string()),
rotation: Some(RotationConfig::default()),
compress: false,
encrypt: false,
custom_config: HashMap::new(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum AuditBackend {
Memory,
File,
#[cfg(feature = "enhanced")]
Enhanced,
Custom(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RotationConfig {
pub strategy: RotationStrategy,
pub max_size_mb: u64,
pub max_age_hours: u64,
pub max_backups: u32,
}
impl Default for RotationConfig {
fn default() -> Self {
Self {
strategy: RotationStrategy::Size,
max_size_mb: 100,
max_age_hours: 24,
max_backups: 10,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum RotationStrategy {
Size,
Time,
Both,
}
pub trait AuditLoggerFactory: Send + Sync {
fn create(&self, config: &AuditConfig) -> Result<Arc<dyn AuditLogger>>;
}
pub struct DefaultAuditLoggerFactory;
impl AuditLoggerFactory for DefaultAuditLoggerFactory {
fn create(&self, config: &AuditConfig) -> Result<Arc<dyn AuditLogger>> {
if !config.enabled {
return Ok(Arc::new(NoOpAuditLogger));
}
match &config.backend {
AuditBackend::Memory => Ok(Arc::new(InMemoryAuditLogger::new(config.clone())?)),
AuditBackend::File => Ok(Arc::new(FileAuditLogger::new(config.clone())?)),
#[cfg(feature = "enhanced")]
AuditBackend::Enhanced => Ok(Arc::new(enhanced::EnhancedAuditLogger::new(
config.clone(),
)?)),
AuditBackend::Custom(name) => Err(anyhow::anyhow!(
"Custom audit backend '{}' not implemented",
name
)),
}
}
}
struct NoOpAuditLogger;
#[async_trait]
impl AuditLogger for NoOpAuditLogger {
async fn log(&self, _event: AuditEvent) -> Result<AuditEventId> {
Ok(AuditEventId::new())
}
async fn log_batch(&self, events: Vec<AuditEvent>) -> Result<Vec<AuditEventId>> {
Ok(events.into_iter().map(|_| AuditEventId::new()).collect())
}
async fn query(&self, _filter: AuditFilter) -> Result<Vec<AuditEvent>> {
Ok(Vec::new())
}
async fn get_event(&self, _id: &AuditEventId) -> Result<Option<AuditEvent>> {
Ok(None)
}
async fn delete_before(&self, _timestamp: DateTime<Utc>) -> Result<u64> {
Ok(0)
}
async fn get_stats(&self) -> Result<AuditStats> {
Ok(AuditStats::default())
}
async fn export(&self, _filter: AuditFilter, _format: ExportFormat) -> Result<Vec<u8>> {
Ok(Vec::new())
}
async fn verify_integrity(&self) -> Result<IntegrityReport> {
Ok(IntegrityReport {
intact: true,
events_checked: 0,
issues: Vec::new(),
verified_at: Utc::now(),
})
}
}
pub struct AuditEventBuilder {
event: AuditEvent,
}
impl AuditEventBuilder {
pub fn new(event_type: AuditEventType, severity: AuditSeverity) -> Self {
Self {
event: AuditEvent::new(event_type, severity),
}
}
pub fn client_id(mut self, id: String) -> Self {
self.event.client_id = Some(id);
self
}
pub fn ip_address(mut self, ip: String) -> Self {
self.event.ip_address = Some(ip);
self
}
pub fn user_agent(mut self, ua: String) -> Self {
self.event.user_agent = Some(ua);
self
}
pub fn context(mut self, key: String, value: serde_json::Value) -> Self {
self.event.context.insert(key, value);
self
}
pub fn tag(mut self, tag: String) -> Self {
self.event.tags.push(tag);
self
}
pub fn build(self) -> AuditEvent {
self.event
}
}
pub mod compliance {
pub struct GDPR;
pub struct SOC2;
pub struct HIPAA;
pub struct PciDss;
pub struct ISO27001;
pub struct ComplianceMatrix;
pub struct RecommendedConfig;
}
pub fn create_audit_logger(_config: &crate::config::Config) -> Arc<dyn AuditLogger> {
let audit_config = AuditConfig::default();
let factory = DefaultAuditLoggerFactory;
factory
.create(&audit_config)
.unwrap_or_else(|_| Arc::new(NoOpAuditLogger))
}