use crate::types::{Cookie, Result};
use serde::{Deserialize, Serialize};
#[derive(Debug)]
pub struct PatternRecognizer {
patterns: Vec<CookiePattern>,
}
impl PatternRecognizer {
#[must_use]
pub fn new() -> Self {
Self {
patterns: Self::load_default_patterns(),
}
}
pub fn train(&mut self, _cookies: &[Cookie]) -> Result<()> {
tracing::info!(
"Pattern recognizer using {} predefined patterns",
self.patterns.len()
);
Ok(())
}
pub fn find_suspicious(&self, cookies: &[Cookie]) -> Result<Vec<Cookie>> {
let mut suspicious = Vec::new();
for cookie in cookies {
if self.matches_suspicious_pattern(cookie) {
suspicious.push(cookie.clone());
}
}
Ok(suspicious)
}
fn matches_suspicious_pattern(&self, cookie: &Cookie) -> bool {
self.patterns.iter().any(|pattern| pattern.matches(cookie))
}
fn load_default_patterns() -> Vec<CookiePattern> {
vec![
CookiePattern {
pattern_type: PatternType::XssIndicator,
name_regex: Some(r"<script|javascript:|onerror=".to_string()),
value_regex: Some(r"<script|javascript:|onerror=".to_string()),
description: "Potential XSS attack pattern".to_string(),
},
CookiePattern {
pattern_type: PatternType::SessionFixation,
name_regex: Some(r"(?i)session|sid|token".to_string()),
value_regex: Some(r"^[a-f0-9]{32,}$".to_string()),
description: "Potential session fixation".to_string(),
},
CookiePattern {
pattern_type: PatternType::Tracking,
name_regex: Some(r"(?i)_ga|_gid|_fbp|_gcl|doubleclick".to_string()),
value_regex: None,
description: "Third-party tracking cookie".to_string(),
},
]
}
}
impl Default for PatternRecognizer {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CookiePattern {
pub pattern_type: PatternType,
pub name_regex: Option<String>,
pub value_regex: Option<String>,
pub description: String,
}
impl CookiePattern {
fn matches(&self, cookie: &Cookie) -> bool {
let name_match = self
.name_regex
.as_ref()
.map_or(true, |regex| cookie.name.contains(regex));
let value_match = self
.value_regex
.as_ref()
.map_or(true, |regex| cookie.value.contains(regex));
name_match && value_match
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum PatternType {
XssIndicator,
CsrfIndicator,
SessionFixation,
Tracking,
Fingerprinting,
Malware,
Exfiltration,
SupplyChain,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pattern_recognizer_creation() {
let recognizer = PatternRecognizer::new();
assert!(!recognizer.patterns.is_empty());
}
}