use std::fmt;
use std::sync::Arc;
use std::sync::LazyLock;
use super::FieldNameMatching;
use super::RedactionFloorBuilder;
use super::SensitiveFieldPreset;
use super::SensitiveFieldRule;
use super::UnknownFieldPolicy;
use crate::policy::internal::RedactionPolicyInner;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RedactionFloor {
pub(crate) inner: Arc<RedactionPolicyInner>,
}
static STANDARD_FLOOR: LazyLock<RedactionFloor> = LazyLock::new(|| {
let mut builder = RedactionFloor::builder();
for preset in [
SensitiveFieldPreset::Credentials,
SensitiveFieldPreset::CredentialContainers,
SensitiveFieldPreset::AuthTokens,
SensitiveFieldPreset::Http,
SensitiveFieldPreset::Session,
] {
builder = builder.include_preset(preset);
}
for &(field, level) in super::super::redaction_policy::STANDARD_EXTRA_FIELDS {
builder = builder
.raise(field, level)
.expect("built-in standard floor fields must be valid");
}
builder.build().expect("the built-in redaction floor is valid")
});
impl RedactionFloor {
#[must_use]
#[inline(always)]
pub fn standard() -> Self {
STANDARD_FLOOR.clone()
}
#[must_use]
#[inline(always)]
pub fn builder() -> RedactionFloorBuilder {
RedactionFloorBuilder::empty()
}
pub fn sensitive_rules(&self) -> impl Iterator<Item = SensitiveFieldRule<'_>> {
self.inner
.sensitive
.iter()
.map(|(field, level)| SensitiveFieldRule::new(field, *level))
}
#[must_use]
#[inline(always)]
pub fn to_builder(&self) -> RedactionFloorBuilder {
RedactionFloorBuilder::from_floor(self)
}
#[must_use]
pub(crate) fn combine(&self, other: &Self) -> Self {
let mut sensitive = self.inner.sensitive.clone();
for (field, level) in &other.inner.sensitive {
sensitive
.entry(field.clone())
.and_modify(|current| *current = (*current).max(*level))
.or_insert(*level);
}
let unknown = match (
self.inner.unknown_field_policy.sensitivity(),
other.inner.unknown_field_policy.sensitivity(),
) {
(Some(left), Some(right)) => Some(left.max(right)),
(Some(level), None) | (None, Some(level)) => Some(level),
(None, None) => None,
};
let unknown_field_policy = unknown.map_or(UnknownFieldPolicy::PassThrough, UnknownFieldPolicy::Redact);
Self {
inner: std::sync::Arc::new(RedactionPolicyInner {
sensitive,
allow_exact: Default::default(),
allow_suffix: Default::default(),
matching: if self.inner.matching == FieldNameMatching::ExactOrTokenSuffix
|| other.inner.matching == FieldNameMatching::ExactOrTokenSuffix
{
FieldNameMatching::ExactOrTokenSuffix
} else {
FieldNameMatching::Exact
},
unknown_field_policy,
}),
}
}
}
impl Default for RedactionFloor {
#[inline(always)]
fn default() -> Self {
Self::standard()
}
}
impl fmt::Display for RedactionFloor {
#[inline(always)]
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("RedactionFloor")
}
}