Skip to main content

max / makenotwork

2.6 KB · 81 lines History Blame Raw
1 /// Sanitization preset for ammonia HTML cleaning.
2 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3 pub enum SanitizePreset {
4 /// Default ammonia settings. Allows most safe HTML.
5 Permissive,
6 /// Default ammonia settings (same sanitization as Permissive; the difference
7 /// is at the Renderer level: Standard strips images, Permissive doesn't).
8 Standard,
9 /// Adds `rel="noopener noreferrer nofollow"` to all links.
10 Strict,
11 /// Only allows p, em, strong, code, br, pre tags.
12 Minimal,
13 }
14
15 impl SanitizePreset {
16 pub(crate) fn clean(&self, html: &str) -> String {
17 match self {
18 SanitizePreset::Permissive | SanitizePreset::Standard => ammonia::clean(html),
19 SanitizePreset::Strict => ammonia::Builder::default()
20 .link_rel(Some("noopener noreferrer nofollow"))
21 .clean(html)
22 .to_string(),
23 SanitizePreset::Minimal => {
24 let tags: std::collections::HashSet<&str> =
25 ["p", "em", "strong", "code", "br", "pre"]
26 .iter()
27 .copied()
28 .collect();
29 ammonia::Builder::default()
30 .tags(tags)
31 .clean(html)
32 .to_string()
33 }
34 }
35 }
36 }
37
38 #[cfg(test)]
39 mod tests {
40 use super::*;
41
42 #[test]
43 fn permissive_allows_safe_html() {
44 let html = "<p>Hello <strong>world</strong></p>";
45 let result = SanitizePreset::Permissive.clean(html);
46 assert!(result.contains("<strong>world</strong>"));
47 }
48
49 #[test]
50 fn permissive_strips_script() {
51 let html = "<p>Hello</p><script>alert(1)</script>";
52 let result = SanitizePreset::Permissive.clean(html);
53 assert!(!result.contains("<script>"));
54 }
55
56 #[test]
57 fn strict_adds_nofollow() {
58 let html = r#"<a href="https://example.com">link</a>"#;
59 let result = SanitizePreset::Strict.clean(html);
60 assert!(result.contains("nofollow"));
61 assert!(result.contains("noopener"));
62 }
63
64 #[test]
65 fn minimal_strips_extra_tags() {
66 let html = r#"<p>Hello <a href="x">link</a> <em>italic</em></p>"#;
67 let result = SanitizePreset::Minimal.clean(html);
68 assert!(result.contains("<em>italic</em>"));
69 assert!(!result.contains("<a"));
70 assert!(result.contains("link"));
71 }
72
73 #[test]
74 fn minimal_keeps_code() {
75 let html = "<pre><code>fn main()</code></pre>";
76 let result = SanitizePreset::Minimal.clean(html);
77 assert!(result.contains("<code>"));
78 assert!(result.contains("<pre>"));
79 }
80 }
81