Skip to content

Commit

Permalink
Add support for sanitizing (filtering) style properties
Browse files Browse the repository at this point in the history
Matches what I understand of Bleach's `CSSSanitizer`: CSS properties
are filtered by name and global.

Fixes #179
  • Loading branch information
xmo-odoo committed Oct 29, 2024
1 parent d11ff76 commit 52de977
Show file tree
Hide file tree
Showing 3 changed files with 373 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ maplit = "1.0"
tendril = "0.4"
url = "2"
once_cell = "1.10"
cssparser = "0.34.0"

[dev-dependencies]
version-sync = "0.9"
Expand Down
40 changes: 40 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ pub mod rcdom;
#[cfg(not(ammonia_unstable))]
mod rcdom;

mod style;

use html5ever::interface::Attribute;
use html5ever::serialize::{serialize, SerializeOpts};
use html5ever::tree_builder::{NodeOrText, TreeSink};
Expand Down Expand Up @@ -367,6 +369,7 @@ pub struct Builder<'a> {
strip_comments: bool,
id_prefix: Option<&'a str>,
generic_attribute_prefixes: Option<HashSet<&'a str>>,
style_properties: Option<HashSet<&'a str>>,
}

impl<'a> Default for Builder<'a> {
Expand Down Expand Up @@ -487,6 +490,7 @@ impl<'a> Default for Builder<'a> {
strip_comments: true,
id_prefix: None,
generic_attribute_prefixes: None,
style_properties: None,
}
}
}
Expand Down Expand Up @@ -1651,6 +1655,34 @@ impl<'a> Builder<'a> {
self
}

/// Only allows the specified properties in `style` attributes.
///
/// Irrelevant if `style` is not an allowed attribute.
///
/// Note that if style filtering is enabled style properties will be normalised e.g.
/// invalid declarations and @rules will be removed, with only syntactically valid
/// declarations kept.
///
/// # Examples
///
/// use ammonia::Builder;
/// use maplit::hashset;
///
/// # fn main() {
/// let attributes = hashset!["style"];
/// let properties = hashset!["color"];
/// let a = Builder::new()
/// .generic_attributes(attributes)
/// .filter_style_properties(properties)
/// .clean("<p style=\"font-weight: heavy; color: red\">my html</p>")
/// .to_string();
/// assert_eq!(a, "<p style=\"color:red\">my html</p>");
/// # }
pub fn filter_style_properties(&mut self, value: HashSet<&'a str>) -> &mut Self {
self.style_properties = Some(value);
self
}

/// Constructs a [`Builder`] instance configured with the [default options].
///
/// # Examples
Expand Down Expand Up @@ -2048,6 +2080,7 @@ impl<'a> Builder<'a> {
///
/// * relative URL rewriting
/// * adding `<a rel>` attributes
/// * filtering out banned style properties
/// * filtering out banned classes
fn adjust_node_attributes(
&self,
Expand Down Expand Up @@ -2141,6 +2174,13 @@ impl<'a> Builder<'a> {
attrs.swap_remove(i);
}
}
if let Some(allowed_values) = &self.style_properties {
for attr in &mut *attrs.borrow_mut() {
if &attr.name.local == "style" {
attr.value = style::filter_style_attribute(&attr.value, allowed_values).into();
}
}
}
if let Some(allowed_values) = self.allowed_classes.get(&*name.local) {
for attr in &mut *attrs.borrow_mut() {
if &attr.name.local == "class" {
Expand Down
Loading

0 comments on commit 52de977

Please sign in to comment.