use crate::config::Config;
use regex::Regex;
use std::path::Path;
pub fn should_skip(path: &Path, cfg: &Config) -> bool {
if !cfg.redact {
return false;
}
let lower = path.to_string_lossy().to_lowercase();
// sensitive dirs
for seg in [".ssh", ".gnupg", ".pki", ".password-store", "monero", ".bitmonero"] {
if lower.contains(seg) {
return true;
}
}
if let Some(name) = path.file_name().and_then(|s| s.to_str()) {
let n = name.to_lowercase();
if n == ".env"
|| n.ends_with(".key")
|| n.ends_with(".pem")
|| n.ends_with(".p12")
|| n.ends_with(".pfx")
|| n.contains("secret")
|| n.contains("credential")
|| n.contains("password")
|| n == "id_rsa"
|| n == "id_ed25519"
|| n == "id_ecdsa"
|| n == "known_hosts"
{
return true;
}
}
false
}
pub fn redact(text: &str) -> String {
let patterns = [
// private key blocks
(r"-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----", "[REDACTED_PRIVATE_KEY]"),
// github tokens
(r"gh[pousr]_[A-Za-z0-9]{30,}", "[REDACTED_GITHUB_TOKEN]"),
// aws access key
(r"AKIA[0-9A-Z]{16}", "[REDACTED_AWS_KEY]"),
// generic api key / token assignments
(r#"(?i)(api[_-]?key|token|secret|password)\s*[:=]\s*["']?[A-Za-z0-9_\-]{16,}["']?"#, "$1=[REDACTED]"),
// emails? keep emails (useful for profile) but redact passwords nearby handled
// monero/seed-like 25 word phrases not attempted
];
let mut s = text.to_string();
for (p, r) in patterns {
if let Ok(re) = Regex::new(p) {
s = re.replace_all(&s, r).to_string();
}
}
s
}