Skip to content

Commit d01e8cc

Browse files
committed
Check if policy name adheres to spec grammar
Before we were accepting any policy name. However, there is a grammar that specifies which characters are valid. Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
1 parent cf67beb commit d01e8cc

File tree

1 file changed

+27
-14
lines changed

1 file changed

+27
-14
lines changed

src/lib.rs

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ impl Display for CspList {
183183
}
184184
}
185185

186+
/// https://www.w3.org/TR/trusted-types/#trusted-types-csp-directive
187+
static TRUSTED_POLICY_SOURCE_GRAMMAR: Lazy<Regex> =
188+
Lazy::new(|| Regex::new(r#"^[0-9a-zA-Z\-\#=_\/@\.%]+$"#).unwrap());
189+
186190
impl CspList {
187191
pub fn is_valid(&self) -> bool {
188192
self.0.iter().all(Policy::is_valid)
@@ -361,7 +365,7 @@ impl CspList {
361365
Note that, while this algoritm is defined as operating on a global object, the only property it
362366
actually uses is the global's CSP List. So this function operates on that.
363367
*/
364-
pub fn is_trusted_type_policy_creation_allowed(&self, policy_name: String, created_policy_names: Vec<String>) -> (CheckResult, Vec<Violation>) {
368+
pub fn is_trusted_type_policy_creation_allowed(&self, policy_name: &str, created_policy_names: &[&str]) -> (CheckResult, Vec<Violation>) {
365369
use CheckResult::*;
366370
// Step 1: Let result be "Allowed".
367371
let mut result = Allowed;
@@ -380,12 +384,12 @@ impl CspList {
380384
}
381385
// Step 2.5: If createdPolicyNames contains policyName and directive’s value does not contain a tt-keyword
382386
// which is a match for a value 'allow-duplicates', set createViolation to true.
383-
if created_policy_names.contains(&policy_name.clone()) && !directive.value.contains(&"'allow-duplicates'".to_string()) {
387+
if created_policy_names.contains(&policy_name) && !directive.value.iter().any(|v| v == "'allow-duplicates'") {
384388
create_violation = true;
385389
}
386390
// Step 2.6: If directive’s value does not contain a tt-policy-name, which value is policyName,
387391
// and directive’s value does not contain a tt-wildcard, set createViolation to true.
388-
if !directive.value.contains(&policy_name) && !directive.value.contains(&"*".to_string()) {
392+
if !(TRUSTED_POLICY_SOURCE_GRAMMAR.is_match(&policy_name) && (directive.value.iter().any(|p| p == policy_name) || directive.value.iter().any(|v| v == "*"))) {
389393
create_violation = true;
390394
}
391395
// Step 2.7: If createViolation is false, skip to the next policy.
@@ -2241,7 +2245,7 @@ mod test {
22412245
pub fn no_trusted_types_specified_allows_all_policies() {
22422246
let csp_list = CspList::parse("default-src 'none'; child-src 'self'", PolicySource::Meta, PolicyDisposition::Enforce);
22432247
assert!(csp_list.is_valid());
2244-
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("MyPolicy".to_owned(), vec![]);
2248+
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("MyPolicy", vec![]);
22452249
assert_eq!(check_result, CheckResult::Allowed);
22462250
assert!(violations.is_empty());
22472251
}
@@ -2250,7 +2254,7 @@ mod test {
22502254
pub fn none_does_not_allow_for_any_policy() {
22512255
let csp_list = CspList::parse("trusted-types 'none'", PolicySource::Meta, PolicyDisposition::Enforce);
22522256
assert!(csp_list.is_valid());
2253-
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("some-policy".to_owned(), vec![]);
2257+
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("some-policy", vec![]);
22542258
assert!(check_result == CheckResult::Blocked);
22552259
assert_eq!(violations.len(), 1);
22562260
}
@@ -2259,7 +2263,7 @@ mod test {
22592263
pub fn extra_none_allows_all_policies() {
22602264
let csp_list = CspList::parse("trusted-types some-policy 'none'", PolicySource::Meta, PolicyDisposition::Enforce);
22612265
assert!(csp_list.is_valid());
2262-
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("some-policy".to_owned(), vec![]);
2266+
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("some-policy", vec![]);
22632267
assert!(check_result == CheckResult::Allowed);
22642268
assert!(violations.is_empty());
22652269
}
@@ -2268,7 +2272,7 @@ mod test {
22682272
pub fn explicit_policy_named_is_allowed() {
22692273
let csp_list = CspList::parse("trusted-types MyPolicy", PolicySource::Meta, PolicyDisposition::Enforce);
22702274
assert!(csp_list.is_valid());
2271-
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("MyPolicy".to_owned(), vec![]);
2275+
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("MyPolicy", vec![]);
22722276
assert_eq!(check_result, CheckResult::Allowed);
22732277
assert!(violations.is_empty());
22742278
}
@@ -2277,7 +2281,16 @@ mod test {
22772281
pub fn other_policy_name_is_blocked() {
22782282
let csp_list = CspList::parse("trusted-types MyPolicy", PolicySource::Meta, PolicyDisposition::Enforce);
22792283
assert!(csp_list.is_valid());
2280-
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("MyOtherPolicy".to_owned(), vec![]);
2284+
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("MyOtherPolicy", vec![]);
2285+
assert!(check_result == CheckResult::Blocked);
2286+
assert_eq!(violations.len(), 1);
2287+
}
2288+
2289+
#[test]
2290+
pub fn invalid_characters_in_policy_name_is_blocked() {
2291+
let csp_list = CspList::parse("trusted-types My?Policy", PolicySource::Meta, PolicyDisposition::Enforce);
2292+
assert!(csp_list.is_valid());
2293+
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("My?Policy", vec!["My?Policy"]);
22812294
assert!(check_result == CheckResult::Blocked);
22822295
assert_eq!(violations.len(), 1);
22832296
}
@@ -2286,7 +2299,7 @@ mod test {
22862299
pub fn already_created_policy_is_blocked() {
22872300
let csp_list = CspList::parse("trusted-types MyPolicy", PolicySource::Meta, PolicyDisposition::Enforce);
22882301
assert!(csp_list.is_valid());
2289-
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("MyPolicy".to_owned(), vec!["MyPolicy".to_owned()]);
2302+
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("MyPolicy", vec!["MyPolicy"]);
22902303
assert!(check_result == CheckResult::Blocked);
22912304
assert_eq!(violations.len(), 1);
22922305
}
@@ -2295,7 +2308,7 @@ mod test {
22952308
pub fn already_created_policy_is_allowed_with_allow_duplicates() {
22962309
let csp_list = CspList::parse("trusted-types MyPolicy 'allow-duplicates'", PolicySource::Meta, PolicyDisposition::Enforce);
22972310
assert!(csp_list.is_valid());
2298-
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("MyPolicy".to_owned(), vec!["MyPolicy".to_owned()]);
2311+
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("MyPolicy", vec!["MyPolicy"]);
22992312
assert!(check_result == CheckResult::Allowed);
23002313
assert!(violations.is_empty());
23012314
}
@@ -2304,7 +2317,7 @@ mod test {
23042317
pub fn only_report_policy_issues_for_disposition_report() {
23052318
let csp_list = CspList::parse("trusted-types MyPolicy", PolicySource::Meta, PolicyDisposition::Report);
23062319
assert!(csp_list.is_valid());
2307-
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("MyPolicy".to_owned(), vec!["MyPolicy".to_owned()]);
2320+
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("MyPolicy", vec!["MyPolicy"]);
23082321
assert!(check_result == CheckResult::Allowed);
23092322
assert_eq!(violations.len(), 1);
23102323
}
@@ -2313,7 +2326,7 @@ mod test {
23132326
pub fn wildcard_allows_all_policies() {
23142327
let csp_list = CspList::parse("trusted-types *", PolicySource::Meta, PolicyDisposition::Report);
23152328
assert!(csp_list.is_valid());
2316-
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("MyPolicy".to_owned(), vec![]);
2329+
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("MyPolicy", vec![]);
23172330
assert!(check_result == CheckResult::Allowed);
23182331
assert!(violations.is_empty());
23192332
}
@@ -2322,7 +2335,7 @@ mod test {
23222335
pub fn violation_has_correct_directive() {
23232336
let csp_list = CspList::parse("trusted-types MyPolicy", PolicySource::Meta, PolicyDisposition::Enforce);
23242337
assert!(csp_list.is_valid());
2325-
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("MyOtherPolicy".to_owned(), vec![]);
2338+
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("MyOtherPolicy", vec![]);
23262339
assert!(check_result == CheckResult::Blocked);
23272340
assert_eq!(violations.len(), 1);
23282341
assert_eq!(violations[0].directive, csp_list.0[0].directive_set[0]);
@@ -2332,7 +2345,7 @@ mod test {
23322345
pub fn long_policy_name_is_truncated() {
23332346
let csp_list = CspList::parse("trusted-types MyPolicy", PolicySource::Meta, PolicyDisposition::Enforce);
23342347
assert!(csp_list.is_valid());
2335-
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("SuperLongPolicyNameThatExceeds40Characters".to_owned(), vec![]);
2348+
let (check_result, violations) = csp_list.is_trusted_type_policy_creation_allowed("SuperLongPolicyNameThatExceeds40Characters", vec![]);
23362349
assert!(check_result == CheckResult::Blocked);
23372350
assert_eq!(violations.len(), 1);
23382351
assert!(matches!(&violations[0].resource, ViolationResource::TrustedTypePolicy { sample } if sample == "SuperLongPolicyNameThatExceeds40Characte"));

0 commit comments

Comments
 (0)