use url::Url;
const SECRET_PARAMS: &[&str] = &["key", "token"];
pub(crate) fn redact_api_key(url: &Url) -> String {
let mut redacted = url.clone();
let pairs: Vec<(String, String)> = redacted
.query_pairs()
.map(|(k, v)| {
if SECRET_PARAMS.iter().any(|s| *s == k.as_ref()) {
(k.into_owned(), "***".to_string())
} else {
(k.into_owned(), v.into_owned())
}
})
.collect();
redacted
.query_pairs_mut()
.clear()
.extend_pairs(pairs.iter().map(|(k, v)| (k.as_str(), v.as_str())));
redacted.to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn redacts_key_query_param() {
let u = Url::parse("https://opencellid.org/cell/get?key=SECRET&mcc=250&mnc=1").unwrap();
let s = redact_api_key(&u);
assert!(!s.contains("SECRET"));
assert!(s.contains("key=***"));
assert!(s.contains("mcc=250"));
}
#[test]
fn redacts_token_query_param() {
let u =
Url::parse("https://opencellid.org/ocid/downloads?token=SECRET&type=full").unwrap();
let s = redact_api_key(&u);
assert!(!s.contains("SECRET"));
assert!(s.contains("token=***"));
assert!(s.contains("type=full"));
}
#[test]
fn leaves_url_without_secrets_alone() {
let u = Url::parse("https://opencellid.org/cell/get?mcc=250").unwrap();
let s = redact_api_key(&u);
assert!(s.contains("mcc=250"));
}
}