pub fn secret_class(line: &str) -> Option<&'static str> {
let lower = line.to_ascii_lowercase();
if lower.contains("kernel command line") || lower.contains("/proc/cmdline") || lower.contains("korp.args") || lower.contains("korp.log_udp=") || lower.contains("clock_key=") {
return Some("cmdline");
}
if lower.contains("token") || lower.contains("bearer ") || lower.contains("password") || lower.contains("secret") {
return Some("token");
}
if lower.contains("private key") || lower.contains("begin openssh") || lower.contains("ssh-ed25519") || lower.contains("ssh-rsa") || lower.contains("signing.key") || lower.contains("time_ed25519") {
return Some("key");
}
if lower.contains("pubkey") || lower.contains("public key") || lower.contains("sha256:") {
return Some("pubkey");
}
if lower.contains(".env") {
return Some("env");
}
if longest_opaque_run(line) >= 40 {
return Some("highentropy");
}
None
}
fn longest_opaque_run(line: &str) -> usize {
let mut best = 0usize;
let mut run = 0usize;
for c in line.chars() {
if c.is_ascii_alphanumeric() || c == '+' || c == '/' || c == '=' {
run += 1;
best = best.max(run);
} else {
run = 0;
}
}
best
}
pub fn withheld(class: &str, bytes: usize) -> String {
format!("<<WITHHELD: a {class}-class line of {bytes} bytes was not recorded>>")
}
pub fn clean(line: &str) -> std::borrow::Cow<'_, str> {
match secret_class(line) {
None => std::borrow::Cow::Borrowed(line),
Some(class) => std::borrow::Cow::Owned(withheld(class, line.len())),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn progress_is_kept_and_every_secret_class_is_withheld_without_its_content() {
assert_eq!(clean("korp-start: stage net up at 6.34 s"), "korp-start: stage net up at 6.34 s");
for (line, class) in [
("[ 0.000000] Kernel command line: korp.args=monetize_pubkey=abc", "cmdline"),
("GUNNAR_UI_ADMIN_TOKEN=xyz", "token"),
("-----BEGIN OPENSSH PRIVATE KEY-----", "key"),
("fed monetize pubkey eb16", "pubkey"),
("reading /etc/monetize/monetize.env", "env"),
("AAAAC3NzaC1lZDI1NTE5AAAAIGx8r8b4v8v5r7q2Zk1pQ3a", "highentropy"),
] {
assert_eq!(secret_class(line), Some(class), "{line}");
let c = clean(line);
assert!(c.starts_with("<<WITHHELD: a ") && c.contains(class) && !c.contains(line), "{c}");
}
}
}