1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! HTML sanitization for accepting user-provided rich text safely (OWASP C3).
//!
//! Wraps the [`ammonia`] crate with secure defaults. Use [`sanitize_html`] for
//! quick sanitization with the default allowlist, or build a [`SanitizeConfig`]
//! to customise which tags and attributes are permitted.
//!
//! # Why sanitization, not encoding?
//!
//! Output encoding (e.g. `secure_output::html::encode`) converts *all* HTML
//! characters to entities — suitable when no HTML should render. Sanitization
//! keeps a *safe subset* of HTML intact (bold, italic, links, etc.) while
//! stripping dangerous elements (scripts, event handlers, `javascript:` URIs).
//! This is the correct control for WYSIWYG editors and user-authored HTML.
//!
//! # Examples
//!
//! ```
//! use secure_boundary::sanitize::{sanitize_html, SanitizeConfig};
//!
//! // Default sanitization — safe tags preserved, scripts removed
//! let safe = sanitize_html("<p>Hello</p><script>alert(1)</script>");
//! assert_eq!(safe, "<p>Hello</p>");
//!
//! // Custom allow-list — only <b> and <i>
//! let config = SanitizeConfig::new().allowed_tags(&["b", "i"]);
//! let safe = config.sanitize("<p>Hello <b>bold</b></p>");
//! assert!(safe.contains("<b>bold</b>"));
//! assert!(!safe.contains("<p>"));
//! ```
use HashSet;
/// Sanitizes HTML using secure defaults.
///
/// Strips dangerous elements (scripts, event handlers, `javascript:` URIs)
/// while preserving a safe subset of HTML tags and attributes as defined by
/// [`ammonia::Builder::default`].
///
/// This is the primary convenience API — use it for typical WYSIWYG input.
///
/// # Examples
///
/// ```
/// use secure_boundary::sanitize::sanitize_html;
///
/// let safe = sanitize_html("<p>Hello</p><script>alert(1)</script>");
/// assert_eq!(safe, "<p>Hello</p>");
/// ```
///
/// # Errors
///
/// This function is infallible — invalid HTML is cleaned, never rejected.
/// Configuration for HTML sanitization with a custom tag/attribute allowlist.
///
/// Build via [`SanitizeConfig::new`] and chain builder methods.
///
/// # Examples
///
/// ```
/// use secure_boundary::sanitize::SanitizeConfig;
///
/// let config = SanitizeConfig::new().allowed_tags(&["b", "i", "em"]);
/// let safe = config.sanitize("<p>Hello <b>bold</b></p>");
/// assert!(safe.contains("<b>bold</b>"));
/// assert!(!safe.contains("<p>"));
/// ```