apollo_redaction/strategy/
ip.rs1use crate::RedactionStrategy;
2use std::fmt;
3
4#[derive(Default, Clone)]
32pub struct IpRedactor;
33
34impl<T: AsRef<str>> RedactionStrategy<T> for IpRedactor {
35 fn display(&self, value: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 redact_ip(value.as_ref(), f)
37 }
38}
39
40fn redact_ip(ip: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 if ip.contains(':') {
44 let parts: Vec<&str> = ip.split(':').collect();
46 if parts.len() >= 4 {
47 write!(
48 f,
49 "{}:{}:{}:{}:****:****:****:****",
50 parts[0], parts[1], parts[2], parts[3]
51 )
52 } else {
53 write!(f, "****:****:****:****:****:****:****:****")
54 }
55 } else {
56 let parts: Vec<&str> = ip.split('.').collect();
58 if parts.len() == 4 {
59 write!(f, "{}.{}.*.*", parts[0], parts[1])
60 } else {
61 write!(f, "[REDACTED: invalid IP]")
63 }
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn display_ipv4() {
73 let my_secret = "192.168.1.100";
74 let redacted = crate::Redacted::<_, IpRedactor>::new(my_secret);
75
76 assert_eq!(
77 format!("private ip is {redacted}"),
78 "private ip is 192.168.*.*",
79 );
80 }
81
82 #[test]
83 fn display_ipv6() {
84 let my_secret = "4fd3:694a:d3f4:c465:9b17:18af:e6ae:a243";
85 let redacted = crate::Redacted::<_, IpRedactor>::new(my_secret);
86
87 assert_eq!(
88 format!("private ip is {redacted}"),
89 "private ip is 4fd3:694a:d3f4:c465:****:****:****:****",
90 );
91 }
92
93 #[test]
94 fn display_invalid() {
95 let my_secret = "this is not an ip address";
96 let redacted = crate::Redacted::<_, IpRedactor>::new(my_secret);
97
98 assert_eq!(
99 format!("private ip is {redacted}"),
100 "private ip is [REDACTED: invalid IP]",
101 "must not leak secret if it's malformed"
102 );
103 }
104}