use std::collections::HashSet; use std::iter::FromIterator; use ammonia::Builder; pub fn clean_html(unsafe_html: &str) -> String { let safe_html = Builder::default() .add_generic_attributes(&["class"]) // Remove src from external images to prevent tracking .set_tag_attribute_value("img", "src", "") // Always add rel="noopener" .link_rel(Some("noopener")) .clean(unsafe_html) .to_string(); safe_html } pub fn clean_html_strict( unsafe_html: &str, allowed_tags: &[&str], ) -> String { let allowed_tags = HashSet::from_iter(allowed_tags.iter().copied()); let safe_html = Builder::default() .tags(allowed_tags) .link_rel(Some("noopener")) .clean(unsafe_html) .to_string(); safe_html } pub fn clean_html_all(html: &str) -> String { let text = Builder::empty() .clean(html) .to_string(); text } #[cfg(test)] mod tests { use super::*; #[test] fn test_clean_html() { let unsafe_html = concat!( r#"

@user test

"#, r#"

"#, ); let expected_safe_html = concat!( r#"

@user test

"#, r#"

"#, ); let safe_html = clean_html(unsafe_html); assert_eq!(safe_html, expected_safe_html); } #[test] fn test_clean_html_strict() { let unsafe_html = r#"

test bold with link and code

"#; let safe_html = clean_html_strict(unsafe_html, &["a", "br", "code"]); assert_eq!(safe_html, r#"test bold with link and code"#); } #[test] fn test_clean_html_all() { let html = r#"

test bold with link and code

"#; let text = clean_html_all(html); assert_eq!(text, "test bold with link and code"); } }