1use super::FieldNameMatching;
11use super::MaskPolicy;
12use super::MaskingPolicy;
13use super::PolicyError;
14use super::PolicyLocation;
15use super::RedactionFloor;
16use super::RedactionLimits;
17use super::RedactionLimitsBuilder;
18use super::RedactionPolicy;
19use super::RedactionRules;
20use super::RedactionRulesBuilder;
21use super::SensitiveFieldPreset;
22use super::Sensitivity;
23#[cfg(feature = "json")]
24use super::UnkeyedJsonValuePolicy;
25use super::UnknownFieldPolicy;
26
27#[derive(Debug, Clone)]
55pub struct RedactionPolicyBuilder {
56 disabled: bool,
58 rules: RedactionRulesBuilder,
60 masking: MaskingPolicy,
62 floor: Option<RedactionFloor>,
64 limits: RedactionLimits,
66 #[cfg(feature = "http")]
68 http: crate::formats::http::HttpPolicyBuilder,
69 #[cfg(feature = "uri")]
71 uri: crate::formats::uri::UriPolicyBuilder,
72 #[cfg(feature = "json")]
74 unkeyed_json_value_policy: UnkeyedJsonValuePolicy,
75}
76
77impl RedactionPolicyBuilder {
78 #[must_use]
80 pub fn new() -> Self {
81 Self {
82 disabled: false,
83 rules: RedactionRulesBuilder::empty(PolicyLocation::Rules),
84 masking: MaskingPolicy::default(),
85 floor: Some(RedactionFloor::standard()),
86 limits: RedactionLimits::default(),
87 #[cfg(feature = "http")]
88 http: crate::formats::http::HttpPolicyBuilder::new(),
89 #[cfg(feature = "uri")]
90 uri: crate::formats::uri::UriPolicyBuilder::new(),
91 #[cfg(feature = "json")]
92 unkeyed_json_value_policy: UnkeyedJsonValuePolicy::PassThrough,
93 }
94 }
95 #[must_use]
97 pub(super) fn from_policy(policy: &RedactionPolicy) -> Self {
98 Self {
99 disabled: policy.is_disabled(),
100 rules: RedactionRulesBuilder::from_inner(&policy.rules().clone_application(), PolicyLocation::Rules),
101 masking: policy.masking().clone(),
102 floor: policy.rules().floor().cloned(),
103 limits: *policy.limits(),
104 #[cfg(feature = "http")]
105 http: crate::formats::http::HttpPolicyBuilder::from_policy(policy.http()),
106 #[cfg(feature = "uri")]
107 uri: crate::formats::uri::UriPolicyBuilder::from_policy(policy.uri()),
108 #[cfg(feature = "json")]
109 unkeyed_json_value_policy: policy.unkeyed_json_value_policy(),
110 }
111 }
112
113 pub fn fields<F>(self, configure: F) -> Result<Self, PolicyError>
125 where
126 F: FnOnce(&mut FieldsBuilder<'_>),
127 {
128 let mut draft = self.clone();
129 let error = {
130 let mut fields = FieldsBuilder {
131 builder: &mut draft,
132 error: None,
133 };
134 configure(&mut fields);
135 fields.error.take()
136 };
137 if let Some(error) = error {
138 return Err(error);
139 }
140 Ok(draft)
141 }
142
143 #[cfg(feature = "http")]
153 pub fn http<F>(self, configure: F) -> Result<Self, PolicyError>
154 where
155 F: FnOnce(&mut HttpPolicyBuilderView<'_>),
156 {
157 let mut draft = self.clone();
158 let error = {
159 let mut view = HttpPolicyBuilderView {
160 builder: &mut draft,
161 error: None,
162 };
163 configure(&mut view);
164 view.error.take()
165 };
166 if let Some(error) = error {
167 return Err(error);
168 }
169 Ok(draft)
170 }
171
172 #[cfg(feature = "uri")]
179 pub fn uri<F>(self, configure: F) -> Result<Self, PolicyError>
180 where
181 F: FnOnce(&mut UriPolicyBuilderView<'_>),
182 {
183 let mut draft = self.clone();
184 let mut view = UriPolicyBuilderView {
185 builder: &mut draft.uri,
186 };
187 configure(&mut view);
188 Ok(draft)
189 }
190
191 pub fn limits<F>(mut self, configure: F) -> Result<Self, PolicyError>
202 where
203 F: FnOnce(&mut RedactionLimitsBuilder),
204 {
205 let mut limits = RedactionLimits::builder_from(&self.limits);
206 configure(&mut limits);
207 let limits = limits.build();
208 limits.validate()?;
209 self.limits = limits;
210 Ok(self)
211 }
212
213 pub fn validate_field_name(field: &str) -> Result<(), PolicyError> {
220 RedactionRulesBuilder::validate_field_name(field, PolicyLocation::Rules)
221 }
222
223 #[cfg(feature = "json")]
228 #[must_use]
229 pub const fn unkeyed_json_value_policy(mut self, policy: UnkeyedJsonValuePolicy) -> Self {
230 self.unkeyed_json_value_policy = policy;
231 self
232 }
233
234 pub fn build(self) -> Result<RedactionPolicy, PolicyError> {
240 let rules = RedactionRules::new(self.rules.build_inner()?, self.floor);
241 self.masking.validate(PolicyLocation::Rules)?;
242 #[cfg(feature = "http")]
243 let http = self.http.build()?;
244 #[cfg(feature = "uri")]
245 let uri = self.uri.build()?;
246 Ok(RedactionPolicy::from_rules(
247 rules,
248 self.masking,
249 self.limits,
250 #[cfg(feature = "http")]
251 http,
252 #[cfg(feature = "uri")]
253 uri,
254 #[cfg(feature = "json")]
255 self.unkeyed_json_value_policy,
256 self.disabled,
257 ))
258 }
259}
260
261mod views {
262 use super::FieldNameMatching;
263 use super::MaskPolicy;
264 use super::MaskingPolicy;
265 use super::PolicyError;
266 use super::PolicyLocation;
267 use super::RedactionFloor;
268 use super::RedactionPolicyBuilder;
269 #[cfg(feature = "http")]
270 use super::RedactionRules;
271 use super::SensitiveFieldPreset;
272 use super::Sensitivity;
273 use super::UnknownFieldPolicy;
274
275 pub struct FieldsBuilder<'a> {
277 pub(super) builder: &'a mut RedactionPolicyBuilder,
279 pub(super) error: Option<PolicyError>,
281 }
282
283 impl FieldsBuilder<'_> {
284 #[inline(always)]
286 fn set_sensitive(&mut self, field: &str, level: Sensitivity) -> &mut Self {
287 if self.error.is_none()
288 && let Err(error) = self.builder.rules.raise(field, level)
289 {
290 self.error = Some(error);
291 }
292 self
293 }
294
295 #[inline(always)]
297 pub fn low_sensitive(&mut self, field: &str) -> &mut Self {
298 self.set_sensitive(field, Sensitivity::Low)
299 }
300
301 #[inline(always)]
303 pub fn medium_sensitive(&mut self, field: &str) -> &mut Self {
304 self.set_sensitive(field, Sensitivity::Medium)
305 }
306
307 #[inline(always)]
309 pub fn high_sensitive(&mut self, field: &str) -> &mut Self {
310 self.set_sensitive(field, Sensitivity::High)
311 }
312
313 #[inline(always)]
315 pub fn secret_sensitive(&mut self, field: &str) -> &mut Self {
316 self.set_sensitive(field, Sensitivity::Secret)
317 }
318
319 #[inline(always)]
321 pub fn sensitive(&mut self, level: Sensitivity, field: &str) -> &mut Self {
322 self.set_sensitive(field, level)
323 }
324
325 #[inline(always)]
327 pub fn matching(&mut self, matching: FieldNameMatching) -> &mut Self {
328 self.builder.rules.matching(matching);
329 self
330 }
331
332 pub fn unknown_field_policy(&mut self, policy: UnknownFieldPolicy) -> &mut Self {
334 self.builder.rules.unknown_field_policy(policy);
335 self
336 }
337
338 pub fn include_preset(&mut self, preset: SensitiveFieldPreset) -> &mut Self {
340 self.builder.rules.include_preset(preset);
341 self
342 }
343
344 pub fn raise(&mut self, field: &str, level: Sensitivity) -> &mut Self {
346 if self.error.is_none()
347 && let Err(error) = self.builder.rules.raise(field, level)
348 {
349 self.error = Some(error);
350 }
351 self
352 }
353
354 pub fn override_level(&mut self, field: &str, level: Sensitivity) -> &mut Self {
356 if self.error.is_none()
357 && let Err(error) = self.builder.rules.override_level(field, level)
358 {
359 self.error = Some(error);
360 }
361 self
362 }
363
364 pub fn allow_exact(&mut self, field: &str) -> &mut Self {
366 if self.error.is_none()
367 && let Err(error) = self.builder.rules.allow_canonical_exact(field)
368 {
369 self.error = Some(error);
370 }
371 self
372 }
373
374 pub fn allow_suffix(&mut self, field: &str) -> &mut Self {
376 if self.error.is_none()
377 && let Err(error) = self.builder.rules.allow_suffix(field)
378 {
379 self.error = Some(error);
380 }
381 self
382 }
383
384 pub fn remove_allow_exact(&mut self, field: &str) -> &mut Self {
386 if self.error.is_none()
387 && let Err(error) = self.builder.rules.remove_allow_canonical_exact(field)
388 {
389 self.error = Some(error);
390 }
391 self
392 }
393
394 pub fn remove_allow_suffix(&mut self, field: &str) -> &mut Self {
396 if self.error.is_none()
397 && let Err(error) = self.builder.rules.remove_allow_suffix(field)
398 {
399 self.error = Some(error);
400 }
401 self
402 }
403
404 pub fn clear_allow_rules(&mut self) -> &mut Self {
406 self.builder.rules.clear_allow_rules();
407 self
408 }
409
410 #[inline(always)]
412 pub fn floor(&mut self, floor: RedactionFloor) -> &mut Self {
413 self.builder.floor = Some(floor);
414 self
415 }
416
417 pub fn disable_floor(&mut self) -> &mut Self {
419 self.builder.floor = None;
420 self
421 }
422
423 pub fn mask(&mut self, level: Sensitivity, policy: MaskPolicy) -> &mut Self {
425 let mut masking = MaskingPolicy::builder_from(&self.builder.masking);
426 masking.policy(level, policy);
427 let masking = masking.build();
428 if self.error.is_none() {
429 match masking.validate(PolicyLocation::Rules) {
430 Ok(()) => self.builder.masking = masking,
431 Err(error) => self.error = Some(error),
432 }
433 }
434 self
435 }
436 }
437
438 #[cfg(feature = "http")]
440 pub struct HttpPolicyBuilderView<'a> {
441 pub(super) builder: &'a mut RedactionPolicyBuilder,
443 pub(super) error: Option<PolicyError>,
445 }
446
447 #[cfg(feature = "uri")]
449 pub struct UriPolicyBuilderView<'a> {
450 pub(super) builder: &'a mut crate::formats::uri::UriPolicyBuilder,
452 }
453
454 #[cfg(feature = "uri")]
455 impl UriPolicyBuilderView<'_> {
456 pub fn path(&mut self, policy: crate::formats::uri::UriPathPolicy) -> &mut Self {
458 self.builder.path_policy_mut(policy);
459 self
460 }
461
462 pub fn fragment(&mut self, policy: crate::formats::uri::UriFragmentPolicy) -> &mut Self {
464 self.builder.fragment_policy_mut(policy);
465 self
466 }
467 }
468
469 #[cfg(feature = "http")]
470 impl HttpPolicyBuilderView<'_> {
471 #[must_use]
473 pub fn header(&mut self) -> HttpContextBuilderView<'_> {
474 HttpContextBuilderView {
475 builder: &mut self.builder.http,
476 error: &mut self.error,
477 context: crate::formats::http::HttpFieldContext::Header,
478 }
479 }
480
481 #[must_use]
483 pub fn query(&mut self) -> HttpContextBuilderView<'_> {
484 HttpContextBuilderView {
485 builder: &mut self.builder.http,
486 error: &mut self.error,
487 context: crate::formats::http::HttpFieldContext::Query,
488 }
489 }
490
491 #[must_use]
493 pub fn body(&mut self) -> HttpContextBuilderView<'_> {
494 HttpContextBuilderView {
495 builder: &mut self.builder.http,
496 error: &mut self.error,
497 context: crate::formats::http::HttpFieldContext::Body,
498 }
499 }
500
501 pub fn url_path(&mut self, policy: crate::formats::http::UrlPathPolicy) -> &mut Self {
503 self.builder.http.url_path_mut(policy);
504 self
505 }
506
507 pub fn text_body(&mut self, policy: crate::formats::http::TextBodyPolicy) -> &mut Self {
509 self.builder.http.text_body_mut(policy);
510 self
511 }
512
513 pub fn floor_all(&mut self, floor: RedactionFloor) -> &mut Self {
515 self.builder.http.floor_all_mut(floor);
516 self
517 }
518
519 pub fn disable_all_floors(&mut self) -> &mut Self {
521 self.builder.http.disable_all_floors_mut();
522 self
523 }
524
525 pub fn unkeyed_json(&mut self, policy: crate::UnkeyedJsonValuePolicy) -> &mut Self {
528 self.builder.unkeyed_json_value_policy = policy;
529 self
530 }
531 }
532
533 #[cfg(feature = "http")]
535 pub struct HttpContextBuilderView<'a> {
536 builder: &'a mut crate::formats::http::HttpPolicyBuilder,
538 error: &'a mut Option<PolicyError>,
540 context: crate::formats::http::HttpFieldContext,
542 }
543
544 #[cfg(feature = "http")]
545 impl HttpContextBuilderView<'_> {
546 pub fn replace_rules(&mut self, rules: RedactionRules) -> &mut Self {
548 self.builder.rules_mut(self.context, rules);
549 self
550 }
551
552 pub fn raise(&mut self, field: &str, level: Sensitivity) -> Result<&mut Self, PolicyError> {
558 if self.error.is_none()
559 && let Err(error) = self.builder.raise_mut(self.context, field, level)
560 {
561 *self.error = Some(error.clone());
562 return Err(error);
563 }
564 Ok(self)
565 }
566
567 pub fn override_level(&mut self, field: &str, level: Sensitivity) -> Result<&mut Self, PolicyError> {
573 if self.error.is_none()
574 && let Err(error) = self.builder.override_level_mut(self.context, field, level)
575 {
576 *self.error = Some(error.clone());
577 return Err(error);
578 }
579 Ok(self)
580 }
581
582 pub fn allow_exact(&mut self, field: &str) -> Result<&mut Self, PolicyError> {
588 if self.error.is_none()
589 && let Err(error) = self.builder.allow_exact_mut(self.context, field)
590 {
591 *self.error = Some(error.clone());
592 return Err(error);
593 }
594 Ok(self)
595 }
596
597 pub fn allow_suffix(&mut self, field: &str) -> Result<&mut Self, PolicyError> {
603 if self.error.is_none()
604 && let Err(error) = self.builder.allow_suffix_mut(self.context, field)
605 {
606 *self.error = Some(error.clone());
607 return Err(error);
608 }
609 Ok(self)
610 }
611
612 pub fn remove_allow_exact(&mut self, field: &str) -> Result<&mut Self, PolicyError> {
618 if self.error.is_none()
619 && let Err(error) = self.builder.remove_allow_exact_mut(self.context, field)
620 {
621 *self.error = Some(error.clone());
622 return Err(error);
623 }
624 Ok(self)
625 }
626
627 pub fn remove_allow_suffix(&mut self, field: &str) -> Result<&mut Self, PolicyError> {
633 if self.error.is_none()
634 && let Err(error) = self.builder.remove_allow_suffix_mut(self.context, field)
635 {
636 *self.error = Some(error.clone());
637 return Err(error);
638 }
639 Ok(self)
640 }
641
642 pub fn clear_allow_rules(&mut self) -> &mut Self {
644 self.builder.clear_allow_rules_mut(self.context);
645 self
646 }
647
648 #[must_use]
651 #[inline(always)]
652 pub fn floor(&mut self, floor: RedactionFloor) -> &mut Self {
653 self.builder.floor_mut(self.context, floor);
654 self
655 }
656
657 pub fn disable_floor(&mut self) -> &mut Self {
659 self.builder.disable_floor_mut(self.context);
660 self
661 }
662 }
663}
664
665pub use views::FieldsBuilder;
666#[cfg(feature = "http")]
667pub use views::HttpContextBuilderView;
668#[cfg(feature = "http")]
669pub use views::HttpPolicyBuilderView;
670#[cfg(feature = "uri")]
671pub use views::UriPolicyBuilderView;
672
673impl Default for RedactionPolicyBuilder {
674 fn default() -> Self {
676 Self::new()
677 }
678}