pub mod clickhouse;
pub mod mongo;
pub mod redis;
pub(crate) fn redact_userinfo(s: &str) -> String {
let mut result = String::with_capacity(s.len());
let mut i = 0;
while i < s.len() {
match s[i..].find("://") {
Some(pos) => {
let sep = i + pos + 3;
result.push_str(&s[i..sep]);
let rest = &s[sep..];
let section_end = rest
.find(|c: char| c.is_whitespace())
.map(|p| sep + p)
.unwrap_or_else(|| s.len());
match s[sep..section_end].rfind('@') {
Some(at_rel) => {
let at = sep + at_rel;
result.push_str("***@");
i = at + 1;
}
None => {
i = sep;
}
}
}
None => {
result.push_str(&s[i..]);
break;
}
}
}
result
}
pub(crate) fn redact_uri(uri: &str) -> String {
match uri.find("://") {
Some(pos) => {
let sep = pos + 3;
match uri[sep..].rfind('@') {
Some(at_rel) => {
let at = sep + at_rel;
format!("{}***@{}", &uri[..sep], &uri[at + 1..])
}
None => uri.to_string(),
}
}
None => uri.to_string(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_redact_userinfo_user_and_password() {
assert_eq!(
redact_userinfo("mongodb://admin:s3cret@localhost:27017"),
"mongodb://***@localhost:27017"
);
}
#[test]
fn test_redact_userinfo_username_only() {
assert_eq!(
redact_userinfo("redis://user@localhost:6379"),
"redis://***@localhost:6379"
);
}
#[test]
fn test_redact_userinfo_password_only() {
assert_eq!(
redact_userinfo("redis://:s3cret@localhost:6379"),
"redis://***@localhost:6379"
);
}
#[test]
fn test_redact_userinfo_no_userinfo_unchanged() {
let input = "redis://localhost:6379/3";
assert_eq!(redact_userinfo(input), input);
}
#[test]
fn test_redact_userinfo_multiple_urls() {
assert_eq!(
redact_userinfo("redis://u:p@h1:6379 and mongodb://a:b@h2:27017"),
"redis://***@h1:6379 and mongodb://***@h2:27017"
);
}
#[test]
fn test_redact_userinfo_at_in_path_over_redacts_conservatively() {
assert_eq!(
redact_userinfo("redis://localhost:6379/some@path"),
"redis://***@path"
);
}
#[test]
fn test_redact_userinfo_slash_in_password() {
let out = redact_userinfo("connect failed: redis://user:p/secret@localhost:6379 timeout");
assert!(!out.contains("p/secret"));
assert_eq!(out, "connect failed: redis://***@localhost:6379 timeout");
}
#[test]
fn test_redact_uri_slash_in_password() {
assert_eq!(
redact_uri("mongodb://admin:p/secret@localhost:27017"),
"mongodb://***@localhost:27017"
);
}
#[test]
fn test_redact_uri_whitespace_in_password() {
assert_eq!(
redact_uri("mongodb://admin:p secret@localhost:27017"),
"mongodb://***@localhost:27017"
);
}
#[test]
fn test_redact_uri_no_userinfo_unchanged() {
let input = "mongodb://localhost:27017";
assert_eq!(redact_uri(input), input);
}
#[test]
fn test_redact_uri_plain_text_unchanged() {
let input = "no uri here";
assert_eq!(redact_uri(input), input);
}
#[test]
fn test_redact_userinfo_unencoded_at_in_password() {
assert_eq!(
redact_userinfo("redis://user:p@ss@localhost:6379"),
"redis://***@localhost:6379"
);
}
#[test]
fn test_redact_userinfo_plain_text_unchanged() {
let input = "no url here";
assert_eq!(redact_userinfo(input), input);
}
}