use std::borrow::Cow;
const SENSITIVE_QUERY_KEYS: &[&str] = &[
"sig",
"signature",
"x-amz-signature",
"x-amz-credential",
"x-amz-security-token",
"access_token",
"token",
"id_token",
"refresh_token",
"sas",
"code",
"api_key",
"apikey",
"secret",
"password",
"auth",
];
fn is_sensitive_query_key(key: &str) -> bool {
SENSITIVE_QUERY_KEYS
.iter()
.any(|candidate| key.eq_ignore_ascii_case(candidate))
}
fn redact_query_params(query: &str) -> Option<String> {
let mut changed = false;
let mut out = String::with_capacity(query.len());
for (index, pair) in query.split('&').enumerate() {
if index > 0 {
out.push('&');
}
match pair.split_once('=') {
Some((key, _value)) if is_sensitive_query_key(key) => {
out.push_str(key);
out.push_str("=***");
changed = true;
}
_ => out.push_str(pair),
}
}
changed.then_some(out)
}
pub(crate) fn redact_url(url: &str) -> Cow<'_, str> {
let scheme_end = match url.find("://") {
Some(idx) => idx + 3,
None => return Cow::Borrowed(url),
};
let after_scheme = &url[scheme_end..];
let authority_end = after_scheme
.find(['/', '?', '#'])
.unwrap_or(after_scheme.len()); let authority = &after_scheme[..authority_end];
let userinfo_at = authority.rfind('@');
let rest = &after_scheme[authority_end..];
let redacted_query = rest.find('?').and_then(|q| {
let after_q = &rest[q + 1..];
let query_len = after_q.find('#').map_or(after_q.len(), |index| index);
redact_query_params(&after_q[..query_len]).map(|masked| (q + 1, query_len, masked))
});
if userinfo_at.is_none() && redacted_query.is_none() {
return Cow::Borrowed(url);
}
let mut out = String::with_capacity(url.len() + 8);
out.push_str(&url[..scheme_end]);
match userinfo_at {
Some(at) => {
out.push_str("***@");
out.push_str(&authority[at + 1..]);
}
None => out.push_str(authority),
}
match redacted_query {
Some((query_start, query_len, masked)) => {
out.push_str(&rest[..query_start]); out.push_str(&masked);
out.push_str(&rest[query_start + query_len..]); }
None => out.push_str(rest),
}
Cow::Owned(out)
}
#[cfg(test)]
#[path = "../tests/unit/url_redaction.rs"]
mod tests;