@@ -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+
186190impl 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