use super::FieldNameMatching;
use super::MaskPolicy;
use super::MaskingPolicy;
use super::PolicyError;
use super::PolicyLocation;
use super::RedactionFloor;
use super::RedactionLimits;
use super::RedactionLimitsBuilder;
use super::RedactionPolicy;
use super::RedactionRules;
use super::RedactionRulesBuilder;
use super::SensitiveFieldPreset;
use super::Sensitivity;
#[cfg(feature = "json")]
use super::UnkeyedJsonValuePolicy;
use super::UnknownFieldPolicy;
#[derive(Debug, Clone)]
pub struct RedactionPolicyBuilder {
disabled: bool,
rules: RedactionRulesBuilder,
masking: MaskingPolicy,
floor: Option<RedactionFloor>,
limits: RedactionLimits,
#[cfg(feature = "http")]
http: crate::formats::http::HttpPolicyBuilder,
#[cfg(feature = "uri")]
uri: crate::formats::uri::UriPolicyBuilder,
#[cfg(feature = "json")]
unkeyed_json_value_policy: UnkeyedJsonValuePolicy,
}
impl RedactionPolicyBuilder {
#[must_use]
pub fn new() -> Self {
Self {
disabled: false,
rules: RedactionRulesBuilder::empty(PolicyLocation::Rules),
masking: MaskingPolicy::default(),
floor: Some(RedactionFloor::standard()),
limits: RedactionLimits::default(),
#[cfg(feature = "http")]
http: crate::formats::http::HttpPolicyBuilder::new(),
#[cfg(feature = "uri")]
uri: crate::formats::uri::UriPolicyBuilder::new(),
#[cfg(feature = "json")]
unkeyed_json_value_policy: UnkeyedJsonValuePolicy::PassThrough,
}
}
#[must_use]
pub(super) fn from_policy(policy: &RedactionPolicy) -> Self {
Self {
disabled: policy.is_disabled(),
rules: RedactionRulesBuilder::from_inner(&policy.rules().clone_application(), PolicyLocation::Rules),
masking: policy.masking().clone(),
floor: policy.rules().floor().cloned(),
limits: *policy.limits(),
#[cfg(feature = "http")]
http: crate::formats::http::HttpPolicyBuilder::from_policy(policy.http()),
#[cfg(feature = "uri")]
uri: crate::formats::uri::UriPolicyBuilder::from_policy(policy.uri()),
#[cfg(feature = "json")]
unkeyed_json_value_policy: policy.unkeyed_json_value_policy(),
}
}
pub fn fields<F>(self, configure: F) -> Result<Self, PolicyError>
where
F: FnOnce(&mut FieldsBuilder<'_>),
{
let mut draft = self.clone();
let error = {
let mut fields = FieldsBuilder {
builder: &mut draft,
error: None,
};
configure(&mut fields);
fields.error.take()
};
if let Some(error) = error {
return Err(error);
}
Ok(draft)
}
#[cfg(feature = "http")]
pub fn http<F>(self, configure: F) -> Result<Self, PolicyError>
where
F: FnOnce(&mut HttpPolicyBuilderView<'_>),
{
let mut draft = self.clone();
let error = {
let mut view = HttpPolicyBuilderView {
builder: &mut draft,
error: None,
};
configure(&mut view);
view.error.take()
};
if let Some(error) = error {
return Err(error);
}
Ok(draft)
}
#[cfg(feature = "uri")]
pub fn uri<F>(self, configure: F) -> Result<Self, PolicyError>
where
F: FnOnce(&mut UriPolicyBuilderView<'_>),
{
let mut draft = self.clone();
let mut view = UriPolicyBuilderView {
builder: &mut draft.uri,
};
configure(&mut view);
Ok(draft)
}
pub fn limits<F>(mut self, configure: F) -> Result<Self, PolicyError>
where
F: FnOnce(&mut RedactionLimitsBuilder),
{
let mut limits = RedactionLimits::builder_from(&self.limits);
configure(&mut limits);
let limits = limits.build();
limits.validate()?;
self.limits = limits;
Ok(self)
}
pub fn validate_field_name(field: &str) -> Result<(), PolicyError> {
RedactionRulesBuilder::validate_field_name(field, PolicyLocation::Rules)
}
#[cfg(feature = "json")]
#[must_use]
pub const fn unkeyed_json_value_policy(mut self, policy: UnkeyedJsonValuePolicy) -> Self {
self.unkeyed_json_value_policy = policy;
self
}
pub fn build(self) -> Result<RedactionPolicy, PolicyError> {
let rules = RedactionRules::new(self.rules.build_inner()?, self.floor);
self.masking.validate(PolicyLocation::Rules)?;
#[cfg(feature = "http")]
let http = self.http.build()?;
#[cfg(feature = "uri")]
let uri = self.uri.build()?;
Ok(RedactionPolicy::from_rules(
rules,
self.masking,
self.limits,
#[cfg(feature = "http")]
http,
#[cfg(feature = "uri")]
uri,
#[cfg(feature = "json")]
self.unkeyed_json_value_policy,
self.disabled,
))
}
}
mod views {
use super::FieldNameMatching;
use super::MaskPolicy;
use super::MaskingPolicy;
use super::PolicyError;
use super::PolicyLocation;
use super::RedactionFloor;
use super::RedactionPolicyBuilder;
#[cfg(feature = "http")]
use super::RedactionRules;
use super::SensitiveFieldPreset;
use super::Sensitivity;
use super::UnknownFieldPolicy;
pub struct FieldsBuilder<'a> {
pub(super) builder: &'a mut RedactionPolicyBuilder,
pub(super) error: Option<PolicyError>,
}
impl FieldsBuilder<'_> {
#[inline(always)]
fn set_sensitive(&mut self, field: &str, level: Sensitivity) -> &mut Self {
if self.error.is_none()
&& let Err(error) = self.builder.rules.raise(field, level)
{
self.error = Some(error);
}
self
}
#[inline(always)]
pub fn low_sensitive(&mut self, field: &str) -> &mut Self {
self.set_sensitive(field, Sensitivity::Low)
}
#[inline(always)]
pub fn medium_sensitive(&mut self, field: &str) -> &mut Self {
self.set_sensitive(field, Sensitivity::Medium)
}
#[inline(always)]
pub fn high_sensitive(&mut self, field: &str) -> &mut Self {
self.set_sensitive(field, Sensitivity::High)
}
#[inline(always)]
pub fn secret_sensitive(&mut self, field: &str) -> &mut Self {
self.set_sensitive(field, Sensitivity::Secret)
}
#[inline(always)]
pub fn sensitive(&mut self, level: Sensitivity, field: &str) -> &mut Self {
self.set_sensitive(field, level)
}
#[inline(always)]
pub fn matching(&mut self, matching: FieldNameMatching) -> &mut Self {
self.builder.rules.matching(matching);
self
}
pub fn unknown_field_policy(&mut self, policy: UnknownFieldPolicy) -> &mut Self {
self.builder.rules.unknown_field_policy(policy);
self
}
pub fn include_preset(&mut self, preset: SensitiveFieldPreset) -> &mut Self {
self.builder.rules.include_preset(preset);
self
}
pub fn raise(&mut self, field: &str, level: Sensitivity) -> &mut Self {
if self.error.is_none()
&& let Err(error) = self.builder.rules.raise(field, level)
{
self.error = Some(error);
}
self
}
pub fn override_level(&mut self, field: &str, level: Sensitivity) -> &mut Self {
if self.error.is_none()
&& let Err(error) = self.builder.rules.override_level(field, level)
{
self.error = Some(error);
}
self
}
pub fn allow_exact(&mut self, field: &str) -> &mut Self {
if self.error.is_none()
&& let Err(error) = self.builder.rules.allow_canonical_exact(field)
{
self.error = Some(error);
}
self
}
pub fn allow_suffix(&mut self, field: &str) -> &mut Self {
if self.error.is_none()
&& let Err(error) = self.builder.rules.allow_suffix(field)
{
self.error = Some(error);
}
self
}
pub fn remove_allow_exact(&mut self, field: &str) -> &mut Self {
if self.error.is_none()
&& let Err(error) = self.builder.rules.remove_allow_canonical_exact(field)
{
self.error = Some(error);
}
self
}
pub fn remove_allow_suffix(&mut self, field: &str) -> &mut Self {
if self.error.is_none()
&& let Err(error) = self.builder.rules.remove_allow_suffix(field)
{
self.error = Some(error);
}
self
}
pub fn clear_allow_rules(&mut self) -> &mut Self {
self.builder.rules.clear_allow_rules();
self
}
#[inline(always)]
pub fn floor(&mut self, floor: RedactionFloor) -> &mut Self {
self.builder.floor = Some(floor);
self
}
pub fn disable_floor(&mut self) -> &mut Self {
self.builder.floor = None;
self
}
pub fn mask(&mut self, level: Sensitivity, policy: MaskPolicy) -> &mut Self {
let mut masking = MaskingPolicy::builder_from(&self.builder.masking);
masking.policy(level, policy);
let masking = masking.build();
if self.error.is_none() {
match masking.validate(PolicyLocation::Rules) {
Ok(()) => self.builder.masking = masking,
Err(error) => self.error = Some(error),
}
}
self
}
}
#[cfg(feature = "http")]
pub struct HttpPolicyBuilderView<'a> {
pub(super) builder: &'a mut RedactionPolicyBuilder,
pub(super) error: Option<PolicyError>,
}
#[cfg(feature = "uri")]
pub struct UriPolicyBuilderView<'a> {
pub(super) builder: &'a mut crate::formats::uri::UriPolicyBuilder,
}
#[cfg(feature = "uri")]
impl UriPolicyBuilderView<'_> {
pub fn path(&mut self, policy: crate::formats::uri::UriPathPolicy) -> &mut Self {
self.builder.path_policy_mut(policy);
self
}
pub fn fragment(&mut self, policy: crate::formats::uri::UriFragmentPolicy) -> &mut Self {
self.builder.fragment_policy_mut(policy);
self
}
}
#[cfg(feature = "http")]
impl HttpPolicyBuilderView<'_> {
#[must_use]
pub fn header(&mut self) -> HttpContextBuilderView<'_> {
HttpContextBuilderView {
builder: &mut self.builder.http,
error: &mut self.error,
context: crate::formats::http::HttpFieldContext::Header,
}
}
#[must_use]
pub fn query(&mut self) -> HttpContextBuilderView<'_> {
HttpContextBuilderView {
builder: &mut self.builder.http,
error: &mut self.error,
context: crate::formats::http::HttpFieldContext::Query,
}
}
#[must_use]
pub fn body(&mut self) -> HttpContextBuilderView<'_> {
HttpContextBuilderView {
builder: &mut self.builder.http,
error: &mut self.error,
context: crate::formats::http::HttpFieldContext::Body,
}
}
pub fn url_path(&mut self, policy: crate::formats::http::UrlPathPolicy) -> &mut Self {
self.builder.http.url_path_mut(policy);
self
}
pub fn text_body(&mut self, policy: crate::formats::http::TextBodyPolicy) -> &mut Self {
self.builder.http.text_body_mut(policy);
self
}
pub fn floor_all(&mut self, floor: RedactionFloor) -> &mut Self {
self.builder.http.floor_all_mut(floor);
self
}
pub fn disable_all_floors(&mut self) -> &mut Self {
self.builder.http.disable_all_floors_mut();
self
}
pub fn unkeyed_json(&mut self, policy: crate::UnkeyedJsonValuePolicy) -> &mut Self {
self.builder.unkeyed_json_value_policy = policy;
self
}
}
#[cfg(feature = "http")]
pub struct HttpContextBuilderView<'a> {
builder: &'a mut crate::formats::http::HttpPolicyBuilder,
error: &'a mut Option<PolicyError>,
context: crate::formats::http::HttpFieldContext,
}
#[cfg(feature = "http")]
impl HttpContextBuilderView<'_> {
pub fn replace_rules(&mut self, rules: RedactionRules) -> &mut Self {
self.builder.rules_mut(self.context, rules);
self
}
pub fn raise(&mut self, field: &str, level: Sensitivity) -> Result<&mut Self, PolicyError> {
if self.error.is_none()
&& let Err(error) = self.builder.raise_mut(self.context, field, level)
{
*self.error = Some(error.clone());
return Err(error);
}
Ok(self)
}
pub fn override_level(&mut self, field: &str, level: Sensitivity) -> Result<&mut Self, PolicyError> {
if self.error.is_none()
&& let Err(error) = self.builder.override_level_mut(self.context, field, level)
{
*self.error = Some(error.clone());
return Err(error);
}
Ok(self)
}
pub fn allow_exact(&mut self, field: &str) -> Result<&mut Self, PolicyError> {
if self.error.is_none()
&& let Err(error) = self.builder.allow_exact_mut(self.context, field)
{
*self.error = Some(error.clone());
return Err(error);
}
Ok(self)
}
pub fn allow_suffix(&mut self, field: &str) -> Result<&mut Self, PolicyError> {
if self.error.is_none()
&& let Err(error) = self.builder.allow_suffix_mut(self.context, field)
{
*self.error = Some(error.clone());
return Err(error);
}
Ok(self)
}
pub fn remove_allow_exact(&mut self, field: &str) -> Result<&mut Self, PolicyError> {
if self.error.is_none()
&& let Err(error) = self.builder.remove_allow_exact_mut(self.context, field)
{
*self.error = Some(error.clone());
return Err(error);
}
Ok(self)
}
pub fn remove_allow_suffix(&mut self, field: &str) -> Result<&mut Self, PolicyError> {
if self.error.is_none()
&& let Err(error) = self.builder.remove_allow_suffix_mut(self.context, field)
{
*self.error = Some(error.clone());
return Err(error);
}
Ok(self)
}
pub fn clear_allow_rules(&mut self) -> &mut Self {
self.builder.clear_allow_rules_mut(self.context);
self
}
#[must_use]
#[inline(always)]
pub fn floor(&mut self, floor: RedactionFloor) -> &mut Self {
self.builder.floor_mut(self.context, floor);
self
}
pub fn disable_floor(&mut self) -> &mut Self {
self.builder.disable_floor_mut(self.context);
self
}
}
}
pub use views::FieldsBuilder;
#[cfg(feature = "http")]
pub use views::HttpContextBuilderView;
#[cfg(feature = "http")]
pub use views::HttpPolicyBuilderView;
#[cfg(feature = "uri")]
pub use views::UriPolicyBuilderView;
impl Default for RedactionPolicyBuilder {
fn default() -> Self {
Self::new()
}
}