libddwaf/
config.rs

1use std::ffi::{CStr, CString};
2use std::ptr::null_mut;
3
4/// The configuration for a new [`Builder`](crate::Builder).
5#[derive(Clone)]
6pub struct Config {
7    pub(crate) raw: libddwaf_sys::ddwaf_config,
8    _obfuscator: Obfuscator, // For keeping the memory alive
9}
10impl Config {
11    /// Creates a new [`Config`] with the provided [`Limits`] and [`Obfuscator`].
12    #[must_use]
13    pub fn new(limits: Limits, obfuscator: Obfuscator) -> Self {
14        Self {
15            raw: libddwaf_sys::ddwaf_config {
16                limits,
17                obfuscator: obfuscator.raw,
18                free_fn: None,
19            },
20            _obfuscator: obfuscator,
21        }
22    }
23}
24impl Default for Config {
25    fn default() -> Self {
26        Self::new(Limits::default(), Obfuscator::default())
27    }
28}
29
30/// The limits attached to a [`Config`].
31pub type Limits = libddwaf_sys::_ddwaf_config__ddwaf_config_limits;
32
33/// Obfuscation configuration for the WAF.
34///
35/// This is effectively a pair of regular expressions that are respectively used
36/// to determine which key and value data to obfuscate when producing WAF
37/// outputs.
38#[repr(transparent)]
39pub struct Obfuscator {
40    raw: libddwaf_sys::_ddwaf_config__ddwaf_config_obfuscator,
41}
42impl Obfuscator {
43    /// Creates a new [`Obfuscator`] with the provided key and value regular
44    /// expressions.
45    ///
46    /// # Panics
47    /// Panics if the provided key or value cannot be turned into a [`CString`].
48    pub fn new<T: Into<Vec<u8>>, U: Into<Vec<u8>>>(
49        key_regex: Option<T>,
50        value_regex: Option<U>,
51    ) -> Self {
52        let key_regex = key_regex.map_or(null_mut(), |s| {
53            CString::new(s).expect("Invalid key regex").into_raw()
54        });
55        let value_regex = value_regex.map_or(null_mut(), |s| {
56            CString::new(s).expect("Invalid value regex").into_raw()
57        });
58        Self {
59            #[allow(clippy::used_underscore_items)]
60            raw: libddwaf_sys::_ddwaf_config__ddwaf_config_obfuscator {
61                key_regex,
62                value_regex,
63            },
64        }
65    }
66
67    /// Returns the regular expression used to determine key data to be obfuscated, if one has been
68    /// set.
69    #[must_use]
70    pub const fn key_regex(&self) -> Option<&CStr> {
71        if self.raw.key_regex.is_null() {
72            None
73        } else {
74            Some(unsafe { CStr::from_ptr(self.raw.key_regex) })
75        }
76    }
77
78    /// Returns the regular expression used to determine value data to be obfuscated, if one has
79    /// been set.
80    #[must_use]
81    pub const fn value_regex(&self) -> Option<&CStr> {
82        if self.raw.value_regex.is_null() {
83            None
84        } else {
85            Some(unsafe { CStr::from_ptr(self.raw.value_regex) })
86        }
87    }
88}
89impl Clone for Obfuscator {
90    fn clone(&self) -> Self {
91        Self::new(
92            self.key_regex().map(CStr::to_bytes),
93            self.value_regex().map(CStr::to_bytes),
94        )
95    }
96}
97/// The regular expression used by [`Obfuscator::default`] to determine which key data to obfuscate.
98pub const OBFUSCATOR_DEFAULT_KEY_REGEX: &str = r"(?i)pass|pw(?:or)?d|secret|(?:api|private|public|access)[_-]?key|token|consumer[_-]?(?:id|key|secret)|sign(?:ed|ature)|bearer|authorization|jsessionid|phpsessid|asp\.net[_-]sessionid|sid|jwt";
99/// The regular expression used by [`Obfuscator::default`] to determine which value data to obfuscate.
100pub const OBFUSCATOR_DEFAULT_VAL_REGEX: &str = r#"(?i)(?:p(?:ass)?w(?:or)?d|pass(?:[_-]?phrase)?|secret(?:[_-]?key)?|(?:(?:api|private|public|access)[_-]?)key(?:[_-]?id)?|(?:(?:auth|access|id|refresh)[_-]?)?token|consumer[_-]?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?|jsessionid|phpsessid|asp\.net(?:[_-]|-)sessionid|sid|jwt)(?:\s*=([^;&]+)|"\s*:\s*("[^"]+"|\d+))|bearer\s+([a-z0-9\._\-]+)|token\s*:\s*([a-z0-9]{13})|gh[opsu]_([0-9a-zA-Z]{36})|ey[I-L][\w=-]+\.(ey[I-L][\w=-]+(?:\.[\w.+\/=-]+)?)|[\-]{5}BEGIN[a-z\s]+PRIVATE\sKEY[\-]{5}([^\-]+)[\-]{5}END[a-z\s]+PRIVATE\sKEY|ssh-rsa\s*([a-z0-9\/\.+]{100,})"#;
101impl Default for Obfuscator {
102    fn default() -> Self {
103        Obfuscator::new(
104            Some(OBFUSCATOR_DEFAULT_KEY_REGEX),
105            Some(OBFUSCATOR_DEFAULT_VAL_REGEX),
106        )
107    }
108}
109impl Drop for Obfuscator {
110    fn drop(&mut self) {
111        if !self.raw.key_regex.is_null() {
112            unsafe {
113                drop(CString::from_raw(self.raw.key_regex.cast_mut()));
114            }
115        }
116        if !self.raw.value_regex.is_null() {
117            unsafe {
118                drop(CString::from_raw(self.raw.value_regex.cast_mut()));
119            }
120        }
121    }
122}