apollo-redaction 0.1.0

Redaction utility for sensitive data in error messages, debug logs, etc.
Documentation
use crate::RedactionStrategy;
use std::fmt;

/// Redact email addresses.
///
/// ```rust
/// use apollo_redaction::Redacted;
/// use apollo_redaction::strategy::EmailRedactor;
///
/// fn email(input: &str) -> String {
///     Redacted::<_, EmailRedactor>::new(input).to_string()
/// }
///
/// assert_eq!(email("user@example.com"), "u***r@example.com");
/// assert_eq!(email("ab@example.com"), "***@example.com");
/// ```
#[derive(Default, Clone)]
pub struct EmailRedactor;

impl<T: AsRef<str>> RedactionStrategy<T> for EmailRedactor {
    fn display(&self, value: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        redact_email(value.as_ref(), f)
    }
}

fn redact_email(email: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    // For emails: show first/last char of local part, full domain
    if let Some((local, domain)) = email.split_once('@') {
        let mut chars = local.chars();
        let first = chars.next();
        let last = chars.next_back();
        // Just to check that there are actually more than 2 characters
        let more = chars.next();
        if let (Some(first), Some(last), Some(_)) = (first, last, more) {
            write!(f, "{first}***{last}@{domain}")
        } else {
            write!(f, "***@{domain}")
        }
    } else {
        // Fallback for malformed input
        write!(f, "[REDACTED: invalid email]")
    }
}

#[cfg(test)]
mod tests {
    use crate::Redacted;
    use crate::strategy::EmailRedactor;

    fn email(input: &str) -> String {
        Redacted::<_, EmailRedactor>::new(input).to_string()
    }

    #[test]
    fn special_inputs() {
        assert_eq!(email("not an email"), "[REDACTED: invalid email]");
        assert_eq!(email("@nolocal.com"), "***@nolocal.com");
        assert_eq!(email("nodomain@"), "n***n@");
        assert_eq!(email("a@onechar.com"), "***@onechar.com");
        assert_eq!(email("ab@twochar.com"), "***@twochar.com");
        assert_eq!(email("abc@threechar.com"), "a***c@threechar.com");
        assert_eq!(email("안녕하세요@unicode.com"), "안***요@unicode.com");
        assert_eq!(email("안녕@unicode.com"), "***@unicode.com");
    }
}