mod capture;
mod layer;
mod module;
mod ring;
mod shipper;
pub use capture::{CapturedRequest, REDACTED};
pub use layer::{CaptureHandle, CaptureLayer};
pub use module::CaptureModule;
pub use ring::CaptureRing;
pub use shipper::{CaptureShipper, CaptureSink};
use std::time::Duration;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct RedactionConfig {
pub headers: Vec<String>,
pub body_fields: Vec<String>,
}
impl RedactionConfig {
pub fn header_redacted(&self, name: &str) -> bool {
self.headers.iter().any(|h| h.eq_ignore_ascii_case(name))
}
pub fn field_redacted(&self, name: &str) -> bool {
self.body_fields.iter().any(|f| f.eq_ignore_ascii_case(name))
}
pub fn is_empty(&self) -> bool {
self.headers.is_empty() && self.body_fields.is_empty()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CaptureConfig {
pub enabled: bool,
pub controlplane_url: String,
pub token_env: String,
pub max_body_bytes: usize,
pub ring_capacity: usize,
pub ring_bytes: usize,
pub ring_ttl: Duration,
pub queue_capacity: usize,
pub redaction: RedactionConfig,
}
impl Default for CaptureConfig {
fn default() -> Self {
Self {
enabled: false,
controlplane_url: String::new(),
token_env: "WAF_CAPTURE_TOKEN".to_string(),
max_body_bytes: 64 * 1024,
ring_capacity: 1024,
ring_bytes: 32 * 1024 * 1024,
ring_ttl: Duration::from_secs(5),
queue_capacity: 256,
redaction: RedactionConfig::default(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn config_default_is_off_and_raw() {
let c = CaptureConfig::default();
assert!(!c.enabled, "capture must default OFF");
assert!(c.redaction.is_empty(), "default is raw capture (no redaction)");
assert_eq!(c.token_env, "WAF_CAPTURE_TOKEN");
assert_eq!(c.max_body_bytes, 64 * 1024);
assert_eq!(c.ring_ttl, Duration::from_secs(5));
}
#[test]
fn redaction_matches_case_insensitively() {
let r = RedactionConfig {
headers: vec!["Authorization".to_string(), "Cookie".to_string()],
body_fields: vec!["password".to_string()],
};
assert!(r.header_redacted("authorization"));
assert!(r.header_redacted("COOKIE"));
assert!(!r.header_redacted("user-agent"));
assert!(r.field_redacted("PASSWORD"));
assert!(!r.field_redacted("username"));
assert!(!r.is_empty());
}
}