#[must_use]
pub fn millis(duration: std::time::Duration) -> u64 {
u64::try_from(duration.as_millis()).unwrap_or(u64::MAX)
}
#[must_use]
pub fn redact_url(url: &str) -> std::borrow::Cow<'_, str> {
let Some((scheme, rest)) = url.split_once("://") else {
return std::borrow::Cow::Borrowed(url);
};
let authority_end = rest.find('/').unwrap_or(rest.len());
let (authority, path) = rest.split_at(authority_end);
let Some((credential, host)) = authority.rsplit_once('@') else {
return std::borrow::Cow::Borrowed(url);
};
let user = credential.split_once(':').map_or(credential, |(u, _)| u);
std::borrow::Cow::Owned(format!("{scheme}://{user}:***@{host}{path}"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_password_never_survives() {
assert_eq!(
redact_url("postgres://acme:hunter2@db.internal:5432/acme"),
"postgres://acme:***@db.internal:5432/acme"
);
}
#[test]
fn a_url_without_credentials_is_returned_as_it_stands() {
for url in [
"sqlite://sqlite.db",
"sqlite:///var/lib/acme-proxy/acme.db",
"postgres://db.internal/acme",
"not a url at all",
"",
] {
assert_eq!(redact_url(url), url, "{url}");
}
}
#[test]
fn a_bare_user_is_kept_and_still_marked() {
assert_eq!(
redact_url("postgres://acme@db.internal/acme"),
"postgres://acme:***@db.internal/acme"
);
}
#[test]
fn the_last_at_sign_separates_the_credential() {
assert_eq!(
redact_url("postgres://acme:p@ss@db.internal/acme"),
"postgres://acme:***@db.internal/acme"
);
}
#[test]
fn an_at_sign_in_the_path_is_not_a_credential() {
assert_eq!(
redact_url("postgres://db.internal/acme@weird"),
"postgres://db.internal/acme@weird"
);
}
}