use serde_json::Value;
use super::JsonRedactionOutcome;
use super::JsonUnkeyedValuePolicy;
use crate::MaskingPolicy;
use crate::RedactionRules;
use crate::Sensitivity;
use crate::policy::ResolvedField;
pub(crate) struct JsonRedactionState<'policy, 'marker> {
base_rules: &'policy RedactionRules,
context_rules: &'policy RedactionRules,
masking: &'policy MaskingPolicy,
unkeyed: JsonUnkeyedValuePolicy<'marker>,
passed_unkeyed: bool,
}
impl<'policy, 'marker> JsonRedactionState<'policy, 'marker> {
#[inline(always)]
pub(crate) const fn new(
base_rules: &'policy RedactionRules,
context_rules: &'policy RedactionRules,
masking: &'policy MaskingPolicy,
unkeyed: JsonUnkeyedValuePolicy<'marker>,
) -> Self {
Self {
base_rules,
context_rules,
masking,
unkeyed,
passed_unkeyed: false,
}
}
pub(crate) fn redact(&mut self, value: &mut Value) -> JsonRedactionOutcome {
self.passed_unkeyed = false;
self.redact_unkeyed(value);
JsonRedactionOutcome::Complete {
passed_unkeyed: self.passed_unkeyed,
}
}
fn redact_unkeyed(&mut self, value: &mut Value) {
match value {
Value::Array(values) => {
for value in values {
self.redact_unkeyed(value);
}
}
Value::Object(entries) => {
for (key, value) in entries {
self.redact_keyed(key, value);
}
}
Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => {
self.redact_unkeyed_scalar(value);
}
}
}
fn redact_keyed(&mut self, key: &str, value: &mut Value) {
match self.resolve_field(key) {
ResolvedField::Sensitive { sensitivity } => self.mask_keyed_value(value, sensitivity),
ResolvedField::PassThrough => match value {
Value::Array(values) => {
for value in values {
self.redact_unkeyed(value);
}
}
Value::Object(entries) => {
for (key, value) in entries {
self.redact_keyed(key, value);
}
}
Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => {}
},
}
}
fn redact_unkeyed_scalar(&mut self, value: &mut Value) {
match self.unkeyed {
JsonUnkeyedValuePolicy::PassThrough => self.passed_unkeyed = true,
JsonUnkeyedValuePolicy::Redact { marker, .. } => {
*value = Value::String(marker.to_owned());
}
}
}
fn resolve_field(&self, key: &str) -> ResolvedField {
self.base_rules
.resolve_field(key)
.stronger(self.context_rules.resolve_field(key))
}
fn mask_keyed_value(&self, value: &mut Value, level: Sensitivity) {
let masked = if let Value::String(text) = value {
self.masking.mask(level, text).into_owned()
} else {
self.masking.mask_opaque(level).to_owned()
};
*value = Value::String(masked);
}
}