use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::time::SystemTime;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum AuditError {
#[error("Audit log failed: {0}")]
LogFailed(String),
#[error("Audit search failed: {0}")]
SearchFailed(String),
#[error("Audit integrity check failed: {0}")]
IntegrityCheckFailed(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditLogEntry {
pub id: String,
pub user_id: String,
pub action: String,
pub resource: String,
pub timestamp: std::time::SystemTime,
pub ip_address: String,
pub result: String, pub metadata: HashMap<String, String>,
}
#[derive(Debug)]
pub struct AuditLogger {
logs: Vec<AuditLogEntry>,
}
impl AuditLogger {
pub fn new() -> Self {
Self { logs: Vec::new() }
}
pub fn log(&mut self, entry: AuditLogEntry) -> Result<(), AuditError> {
self.logs.push(entry);
Ok(())
}
pub fn get_logs(&self) -> &[AuditLogEntry] {
&self.logs
}
pub fn search(&self, query: &str) -> Result<Vec<&AuditLogEntry>, AuditError> {
let results: _ = self
.logs
.iter()
.filter(|entry| {
entry.action.contains(query)
|| entry.resource.contains(query)
|| entry.user_id.contains(query)
})
.collect();
Ok(results)
}
pub fn check_integrity(&self) -> Result<bool, AuditError> {
if self.logs.is_empty() {
return Ok(true);
}
for i in 1..self.logs.len() {
if self.logs[i - 1].timestamp > self.logs[i].timestamp {
return Ok(false);
}
}
Ok(true)
}
}
impl Default for AuditLogger {
fn default() -> Self {
Self::new()
}
}