///|
fn masked_last4(text : String, finding : Finding) -> String {
let length = finding.end - finding.start
if length <= 4 {
return "[REDACTED:" + finding.kind.to_string() + "]"
}
"[REDACTED:" +
finding.kind.to_string() +
":*" +
text[finding.end - 4:finding.end].to_owned() +
"]"
}
///|
fn replacement(
text : String,
finding : Finding,
style : RedactionStyle,
) -> String {
match style {
Marker => "[REDACTED]"
Typed => "[REDACTED:" + finding.kind.to_string() + "]"
PreserveLast4 => masked_last4(text, finding)
}
}
///|
/// Redact all enabled findings. Already-produced markers contain no detector
/// pattern, so applying the same policy again is idempotent.
pub fn redact(
text : String,
style? : RedactionStyle = Typed,
policy? : ScanPolicy = ScanPolicy::standard(),
) -> RedactionResult {
redact_with_config(text, policy.to_config(), style~)
}
///|
/// Redact with full detector configuration, suppressor toggles and extra
/// prefixed-token rules.
pub fn redact_with_config(
text : String,
config : ScanConfig,
style? : RedactionStyle = Typed,
) -> RedactionResult {
let findings = scan_with_config(text, config)
{
text: redact_with_findings(text, findings, style),
findings,
changed: findings.length() > 0,
}
}
///|
/// Redact with both built-in detectors under full configuration and
/// caller-supplied exact-value rules.
pub fn redact_full(
text : String,
rules : Array[CustomRule],
config : ScanConfig,
style? : RedactionStyle = Typed,
) -> RedactionResult {
let findings = scan_full(text, rules, config)
{
text: redact_with_findings(text, findings, style),
findings,
changed: findings.length() > 0,
}
}
///|
/// Return true only when a fresh scan finds no enabled sensitive values.
pub fn verify_clean(
text : String,
policy? : ScanPolicy = ScanPolicy::standard(),
) -> Bool {
scan(text, policy~).length() == 0
}
///|
/// Return true only when a fresh configured scan finds nothing.
///|
/// Redact while sparing caller-certified literals, such as a load balancer
/// IP that is safe to publish. Everything else runs under the given config.
pub fn redact_except(
text : String,
keep : Array[String],
style? : RedactionStyle = Typed,
config? : ScanConfig = ScanConfig::standard(),
) -> RedactionResult {
let findings = scan_except(text, keep, config~)
{
text: redact_with_findings(text, findings, style),
findings,
changed: findings.length() > 0,
}
}
///|
///|
/// Return true only when neither built-in detectors under the configuration
/// nor caller-supplied exact-value rules find anything.
pub fn verify_clean_with_rules(
text : String,
rules : Array[CustomRule],
config? : ScanConfig = ScanConfig::standard(),
) -> Bool {
scan_full(text, rules, config).length() == 0
}
///|
pub fn verify_clean_with_config(text : String, config : ScanConfig) -> Bool {
scan_with_config(text, config).length() == 0
}