losan 1.0.0

An high-performance multi-threaded log sanitizer built in Rust
use regex::{Regex, RegexBuilder};

pub const EMAIL_PATTERN: &str = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}";
pub const PHONE_PATTERN: &str =
    r"\b(?:\+[0-9]{1,3}[-. \t]?)?\(?[0-9]{2,4}\)?[-. \t]?[0-9]{3,4}[-. \t]?[0-9]{3,4}\b";

pub const IPV4_PATTERN: &str = r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b";
pub const IPV6_PATTERN: &str = r"\b(?:[a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}\b";

pub const UUID_PATTERN: &str =
    r"\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b";

pub const ID_PATTERN: &str =
    r#"(?i)\b(user_?id|account_?id|client_?id|id)["']?[ \t]*[:=][ \t]*["']?([a-zA-Z0-9_\-]+)["']?"#;
pub const APIKEY_PATTERN: &str = r#"(?i)\b(api[_-]?key|secret[_-]?key|access[_-]?key)["']?[ \t]*[:=][ \t]*["']?([a-zA-Z0-9_\-\.]{16,})["']?"#;

pub const JWT_PATTERN: &str = r"\beyJ[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]*\b";
pub const BEARER_PATTERN: &str = r"(?i)(Bearer)[ \t]+([a-zA-Z0-9_\-\.=]+)";

pub struct MaskRule {
    pub pattern: Regex,
    pub replacement: &'static str,
}

impl MaskRule {
    fn new(pattern_str: &str, replacement: &'static str) -> Self {
        let pattern = RegexBuilder::new(pattern_str)
            .size_limit(10 * 1024 * 1024)
            .unicode(false)
            .build()
            .unwrap_or_else(|e| panic!("Failed to compile regex '{}': {}", pattern_str, e));

        Self {
            pattern,
            replacement,
        }
    }

    pub fn rules() -> Vec<MaskRule> {
        vec![
            Self::new(UUID_PATTERN, "[REDACTED_UUID]"),
            Self::new(JWT_PATTERN, "[REDACTED_TOKEN]"),
            Self::new(EMAIL_PATTERN, "[REDACTED_EMAIL]"),
            Self::new(IPV6_PATTERN, "[REDACTED_IPV6]"),
            Self::new(IPV4_PATTERN, "[REDACTED_IPV4]"),
            Self::new(APIKEY_PATTERN, "$1=[REDACTED_KEY]"),
            Self::new(ID_PATTERN, "$1=[REDACTED_ID]"),
            Self::new(BEARER_PATTERN, "$1 [REDACTED_TOKEN]"),
            Self::new(PHONE_PATTERN, "[REDACTED_PHONE]"),
        ]
    }
}