use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ActorType {
User,
ServiceAccount,
System,
Anonymous,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct AuditActor {
pub actor_id: String,
pub actor_type: ActorType,
pub ip_address: Option<String>,
pub session_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct AuditResource {
pub resource_type: String,
pub resource_id: String,
pub tenant_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "status", rename_all = "snake_case")]
pub enum AuditOutcome {
Success,
Failure {
reason: String,
},
PartialSuccess {
details: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub enum AuditEventKind {
Authentication,
Authorization,
DataAccess,
DataModification,
Admin,
Security,
System,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditEvent {
pub event_id: String,
pub timestamp: DateTime<Utc>,
pub kind: AuditEventKind,
pub action: String,
pub actor: AuditActor,
pub resource: AuditResource,
pub outcome: AuditOutcome,
pub duration_ms: Option<u64>,
pub metadata: HashMap<String, String>,
pub data_subject_id: Option<String>,
}
impl AuditEvent {
pub fn new(
kind: AuditEventKind,
action: impl Into<String>,
actor: AuditActor,
resource: AuditResource,
outcome: AuditOutcome,
) -> Self {
Self {
event_id: Uuid::new_v4().to_string(),
timestamp: Utc::now(),
kind,
action: action.into(),
actor,
resource,
outcome,
duration_ms: None,
metadata: HashMap::new(),
data_subject_id: None,
}
}
#[must_use]
pub fn with_duration(mut self, duration_ms: u64) -> Self {
self.duration_ms = Some(duration_ms);
self
}
#[must_use]
pub fn with_metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.metadata.insert(key.into(), value.into());
self
}
#[must_use]
pub fn with_data_subject(mut self, subject_id: impl Into<String>) -> Self {
self.data_subject_id = Some(subject_id.into());
self
}
}