use serde::{Deserialize, Serialize};
use std::time::Instant;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PayloadAnomalyType {
OversizedRequest,
OversizedResponse,
BandwidthSpike,
ExfiltrationPattern,
UploadPattern,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum PayloadAnomalySeverity {
Low,
Medium,
High,
Critical,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum PayloadAnomalyMetadata {
Oversize {
actual_bytes: u64,
expected_bytes: u64,
threshold: f64,
percentile: f64,
},
BandwidthSpike {
current_bytes_per_min: u64,
avg_bytes_per_min: u64,
threshold: f64,
},
DataPattern {
request_bytes: u64,
response_bytes: u64,
ratio: f64,
threshold: f64,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PayloadAnomaly {
pub id: String,
pub anomaly_type: PayloadAnomalyType,
pub severity: PayloadAnomalySeverity,
#[serde(skip)]
pub detected_at_instant: Option<Instant>,
pub detected_at: i64,
pub template: String,
pub entity_id: String,
pub description: String,
pub metadata: PayloadAnomalyMetadata,
pub risk_applied: Option<f64>,
}
impl PayloadAnomaly {
pub fn new(
anomaly_type: PayloadAnomalyType,
severity: PayloadAnomalySeverity,
template: String,
entity_id: String,
description: String,
metadata: PayloadAnomalyMetadata,
) -> Self {
let now = Instant::now();
Self {
id: uuid::Uuid::new_v4().to_string(),
anomaly_type,
severity,
detected_at_instant: Some(now),
detected_at: chrono::Utc::now().timestamp_millis(),
template,
entity_id,
description,
metadata,
risk_applied: None,
}
}
pub fn with_risk(mut self, risk: f64) -> Self {
self.risk_applied = Some(risk);
self
}
}
impl PayloadAnomalyType {
pub fn default_severity(&self) -> PayloadAnomalySeverity {
match self {
Self::OversizedRequest => PayloadAnomalySeverity::Medium,
Self::OversizedResponse => PayloadAnomalySeverity::Low,
Self::BandwidthSpike => PayloadAnomalySeverity::High,
Self::ExfiltrationPattern => PayloadAnomalySeverity::Critical,
Self::UploadPattern => PayloadAnomalySeverity::High,
}
}
}