css_sanitizer/lib.rs
1//! # css-sanitizer
2//!
3//! Policy-driven CSS sanitization on top of `lightningcss`.
4//!
5//! This crate exposes `lightningcss` and lets you sanitize parsed CSS AST nodes
6//! directly through [`CssSanitizationPolicy`]. There is no built-in safe preset:
7//! the safety properties come from the policy you implement.
8//!
9//! Default trait methods are fail-open and return
10//! [`NodeAction::Continue`]. A strict sanitizer must explicitly drop the rules,
11//! selectors, properties, and descriptors it does not want to keep.
12//!
13//! ## String API
14//!
15//! ```rust
16//! use css_sanitizer::{
17//! clean_stylesheet_with_policy, CssSanitizationPolicy, NodeAction, PropertyContext,
18//! RuleContext,
19//! };
20//! use css_sanitizer::lightningcss::rules::CssRule;
21//!
22//! struct StyleColorOnly;
23//!
24//! impl CssSanitizationPolicy for StyleColorOnly {
25//! fn visit_rule(
26//! &self,
27//! rule: &mut CssRule<'_>,
28//! _ctx: RuleContext,
29//! ) -> NodeAction {
30//! match rule {
31//! CssRule::Style(_) => NodeAction::Continue,
32//! _ => NodeAction::Drop,
33//! }
34//! }
35//!
36//! fn visit_property(
37//! &self,
38//! property: &mut css_sanitizer::lightningcss::properties::Property<'_>,
39//! _ctx: PropertyContext,
40//! ) -> NodeAction {
41//! if property.property_id().name() == "color" {
42//! NodeAction::Continue
43//! } else {
44//! NodeAction::Drop
45//! }
46//! }
47//! }
48//!
49//! let safe = clean_stylesheet_with_policy(
50//! "@import url('evil.css'); .card { color: red; position: fixed }",
51//! &StyleColorOnly,
52//! );
53//!
54//! assert!(!safe.contains("@import"));
55//! assert!(safe.contains("color"));
56//! assert!(!safe.contains("position"));
57//! ```
58//!
59//! ## AST API
60//!
61//! ```rust
62//! use css_sanitizer::{
63//! sanitize_stylesheet_ast, CssSanitizationPolicy, NodeAction, RuleContext,
64//! };
65//! use css_sanitizer::lightningcss::rules::CssRule;
66//! use css_sanitizer::lightningcss::stylesheet::{ParserOptions, StyleSheet};
67//!
68//! struct NoImports;
69//!
70//! impl CssSanitizationPolicy for NoImports {
71//! fn visit_rule(
72//! &self,
73//! rule: &mut CssRule<'_>,
74//! _ctx: RuleContext,
75//! ) -> NodeAction {
76//! if matches!(rule, CssRule::Import(_)) {
77//! NodeAction::Drop
78//! } else {
79//! NodeAction::Continue
80//! }
81//! }
82//! }
83//!
84//! let mut stylesheet =
85//! StyleSheet::parse("@import url('evil.css'); .card { color: blue }", ParserOptions::default())
86//! .expect("stylesheet should parse");
87//!
88//! sanitize_stylesheet_ast(&mut stylesheet, &NoImports);
89//!
90//! let output = stylesheet
91//! .to_css(Default::default())
92//! .expect("stylesheet should serialize")
93//! .code;
94//! assert!(!output.contains("@import"));
95//! assert!(output.contains(".card"));
96//! ```
97
98mod policy;
99mod sanitize;
100
101pub use lightningcss;
102pub use policy::{
103 CssSanitizationPolicy, DescriptorContext, NodeAction, PropertyContext, RuleContext,
104 SelectorContext,
105};
106pub use sanitize::{
107 clean_declaration_list_with_policy, clean_stylesheet_with_policy,
108 sanitize_declaration_block_ast, sanitize_stylesheet_ast,
109};