apollo_redaction/strategy/
email.rs1use crate::RedactionStrategy;
2use std::fmt;
3
4#[derive(Default, Clone)]
18pub struct EmailRedactor;
19
20impl<T: AsRef<str>> RedactionStrategy<T> for EmailRedactor {
21 fn display(&self, value: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 redact_email(value.as_ref(), f)
23 }
24}
25
26fn redact_email(email: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 if let Some((local, domain)) = email.split_once('@') {
29 let mut chars = local.chars();
30 let first = chars.next();
31 let last = chars.next_back();
32 let more = chars.next();
34 if let (Some(first), Some(last), Some(_)) = (first, last, more) {
35 write!(f, "{first}***{last}@{domain}")
36 } else {
37 write!(f, "***@{domain}")
38 }
39 } else {
40 write!(f, "[REDACTED: invalid email]")
42 }
43}
44
45#[cfg(test)]
46mod tests {
47 use crate::Redacted;
48 use crate::strategy::EmailRedactor;
49
50 fn email(input: &str) -> String {
51 Redacted::<_, EmailRedactor>::new(input).to_string()
52 }
53
54 #[test]
55 fn special_inputs() {
56 assert_eq!(email("not an email"), "[REDACTED: invalid email]");
57 assert_eq!(email("@nolocal.com"), "***@nolocal.com");
58 assert_eq!(email("nodomain@"), "n***n@");
59 assert_eq!(email("a@onechar.com"), "***@onechar.com");
60 assert_eq!(email("ab@twochar.com"), "***@twochar.com");
61 assert_eq!(email("abc@threechar.com"), "a***c@threechar.com");
62 assert_eq!(email("안녕하세요@unicode.com"), "안***요@unicode.com");
63 assert_eq!(email("안녕@unicode.com"), "***@unicode.com");
64 }
65}