pub fn redact_secret(s: &str) -> String {
let char_count = s.chars().count();
if char_count < 12 {
"****".to_string()
} else {
let prefix_end = s.char_indices().nth(4).map(|(i, _)| i).unwrap_or(s.len());
let suffix_start = s
.char_indices()
.nth(char_count - 4)
.map(|(i, _)| i)
.unwrap_or(0);
format!("{}...{}", &s[..prefix_end], &s[suffix_start..])
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_string() {
assert_eq!(redact_secret(""), "****");
}
#[test]
fn short_string() {
assert_eq!(redact_secret("abc"), "****");
}
#[test]
fn exactly_11_chars() {
assert_eq!(redact_secret("12345678901"), "****");
}
#[test]
fn exactly_12_chars() {
assert_eq!(redact_secret("123456789012"), "1234...9012");
}
#[test]
fn typical_api_key() {
let key = "sk-proj-abcdefghijklmnop";
let redacted = redact_secret(key);
assert_eq!(redacted, "sk-p...mnop");
}
#[test]
fn multibyte_utf8_does_not_panic() {
let key = "\u{00e9}\u{00e9}\u{00e9}\u{00e9}\u{00e9}\u{00e9}\u{00e9}\u{00e9}\u{00e9}\u{00e9}\u{00e9}\u{00e9}";
assert_eq!(key.chars().count(), 12);
let redacted = redact_secret(key);
assert_eq!(
redacted,
"\u{00e9}\u{00e9}\u{00e9}\u{00e9}...\u{00e9}\u{00e9}\u{00e9}\u{00e9}"
);
}
#[test]
fn multibyte_short_string() {
let key = "\u{00e9}\u{00e9}\u{00e9}\u{00e9}\u{00e9}\u{00e9}";
assert_eq!(key.chars().count(), 6);
assert_eq!(redact_secret(key), "****");
}
}