From 0aa08042d54947e9d9f01457b293081a835a70ba Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Fri, 11 Apr 2025 10:38:00 +0200 Subject: [PATCH] Implement attribute and property lookup for Trusted Types (#36422) These algorithms are used to check whether an attribute/property can accept a Trusted Type. Part of #36258 Signed-off-by: Tim van der Lippe --- .../script/dom/trustedtypepolicyfactory.rs | 142 ++++++++++++++++-- .../HTMLElement-generic.html.ini | 13 +- ...actory-getAttributeType-namespace.html.ini | 63 -------- ...olicyFactory-getAttributeType-svg.html.ini | 12 -- ...ypePolicyFactory-getAttributeType.html.ini | 60 -------- ...Factory-getPropertyType.tentative.html.ini | 39 ----- .../legacy-trusted-script-urls.html.ini | 6 - 7 files changed, 143 insertions(+), 192 deletions(-) delete mode 100644 tests/wpt/meta/trusted-types/TrustedTypePolicyFactory-getAttributeType-namespace.html.ini delete mode 100644 tests/wpt/meta/trusted-types/TrustedTypePolicyFactory-getAttributeType-svg.html.ini delete mode 100644 tests/wpt/meta/trusted-types/legacy-trusted-script-urls.html.ini diff --git a/components/script/dom/trustedtypepolicyfactory.rs b/components/script/dom/trustedtypepolicyfactory.rs index 02bafb021f1..86a1d54e066 100644 --- a/components/script/dom/trustedtypepolicyfactory.rs +++ b/components/script/dom/trustedtypepolicyfactory.rs @@ -4,6 +4,7 @@ use std::cell::RefCell; use dom_struct::dom_struct; +use html5ever::{LocalName, Namespace, QualName, local_name, namespace_url, ns}; use js::rust::HandleValue; use crate::dom::bindings::codegen::Bindings::TrustedTypePolicyFactoryBinding::{ @@ -85,6 +86,49 @@ impl TrustedTypePolicyFactory { // Step 9: Return policy. Ok(policy) } + + /// + #[allow(clippy::if_same_then_else)] + fn get_trusted_type_data_for_attribute( + element: QualName, + attribute: String, + attribute_namespace: Option, + ) -> Option { + // Step 1: Let data be null. + let mut data = None; + // Step 2: If attributeNs is null, and attribute is the name of an event handler content attribute, then: + // TODO(36258): look up event handlers + // Step 3: Find the row in the following table, where element is in the first column, + // attributeNs is in the second column, and attribute is in the third column. + // If a matching row is found, set data to that row. + if element.ns == ns!(html) && + element.local == local_name!("iframe") && + attribute_namespace.is_none() && + attribute == "srcdoc" + { + data = Some(DOMString::from("TrustedHTML")) + } else if element.ns == ns!(html) && + element.local == local_name!("script") && + attribute_namespace.is_none() && + attribute == "src" + { + data = Some(DOMString::from("TrustedScriptURL")) + } else if element.ns == ns!(svg) && + element.local == local_name!("script") && + attribute_namespace.is_none() && + attribute == "href" + { + data = Some(DOMString::from("TrustedScriptURL")) + } else if element.ns == ns!(svg) && + element.local == local_name!("script") && + attribute_namespace == Some(ns!(xlink)) && + attribute == "href" + { + data = Some(DOMString::from("TrustedScriptURL")) + } + // Step 4: Return data. + data + } } impl TrustedTypePolicyFactoryMethods for TrustedTypePolicyFactory { @@ -135,23 +179,99 @@ impl TrustedTypePolicyFactoryMethods for TrustedTypePolicy /// fn GetAttributeType( &self, - _: DOMString, - _: DOMString, - _: Option, - _: Option, + tag_name: DOMString, + attribute: DOMString, + element_namespace: Option, + attribute_namespace: Option, ) -> Option { - // TODO(36258): implement algorithm - Some(DOMString::from("".to_string())) + // Step 1: Set localName to tagName in ASCII lowercase. + let local_name = tag_name.to_ascii_lowercase(); + // Step 2: Set attribute to attribute in ASCII lowercase. + let attribute = attribute.to_ascii_lowercase(); + // Step 3: If elementNs is null or an empty string, set elementNs to HTML namespace. + let element_namespace = match element_namespace { + Some(namespace) if !namespace.is_empty() => Namespace::from(namespace), + Some(_) | None => ns!(html), + }; + // Step 4: If attrNs is an empty string, set attrNs to null. + let attribute_namespace = match attribute_namespace { + Some(namespace) if !namespace.is_empty() => Some(Namespace::from(namespace)), + Some(_) | None => None, + }; + // Step 5: Let interface be the element interface for localName and elementNs. + let interface = QualName::new(None, element_namespace, LocalName::from(local_name)); + // Step 6: Let expectedType be null. + let mut expected_type = None; + // Step 7: Set attributeData to the result of Get Trusted Type data for attribute algorithm, + // with the following arguments: interface as element, attribute, attrNs + let attribute_data = TrustedTypePolicyFactory::get_trusted_type_data_for_attribute( + interface, + attribute, + attribute_namespace, + ); + // Step 8: If attributeData is not null, then set expectedType to the interface’s name of + // the value of the fourth member of attributeData. + if let Some(trusted_type) = attribute_data { + expected_type = Some(trusted_type) + } + // Step 9: Return expectedType. + expected_type } /// + #[allow(clippy::if_same_then_else)] fn GetPropertyType( &self, - _: DOMString, - _: DOMString, - _: Option, + tag_name: DOMString, + property: DOMString, + element_namespace: Option, ) -> Option { - // TODO(36258): implement algorithm - Some(DOMString::from("".to_string())) + // Step 1: Set localName to tagName in ASCII lowercase. + let local_name = tag_name.to_ascii_lowercase(); + // Step 2: If elementNs is null or an empty string, set elementNs to HTML namespace. + let element_namespace = match element_namespace { + Some(namespace) if !namespace.is_empty() => Namespace::from(namespace), + Some(_) | None => ns!(html), + }; + // Step 3: Let interface be the element interface for localName and elementNs. + let interface = QualName::new(None, element_namespace, LocalName::from(local_name)); + // Step 4: Let expectedType be null. + let mut expected_type = None; + // Step 5: Find the row in the following table, where the first column is "*" or interface’s name, + // and property is in the second column. If a matching row is found, set expectedType to + // the interface’s name of the value of the third column. + let property = property.str(); + if interface.ns == ns!(html) && + interface.local == local_name!("iframe") && + property == "srcdoc" + { + expected_type = Some(DOMString::from("TrustedHTML")) + } else if interface.ns == ns!(html) && + interface.local == local_name!("script") && + property == "innerText" + { + expected_type = Some(DOMString::from("TrustedScript")) + } else if interface.ns == ns!(html) && + interface.local == local_name!("script") && + property == "src" + { + expected_type = Some(DOMString::from("TrustedScriptURL")) + } else if interface.ns == ns!(html) && + interface.local == local_name!("script") && + property == "text" + { + expected_type = Some(DOMString::from("TrustedScript")) + } else if interface.ns == ns!(html) && + interface.local == local_name!("script") && + property == "textContent" + { + expected_type = Some(DOMString::from("TrustedScript")) + } else if property == "innerHTML" { + expected_type = Some(DOMString::from("TrustedHTML")) + } else if property == "outerHTML" { + expected_type = Some(DOMString::from("TrustedHTML")) + } + // Step 6: Return expectedType. + expected_type } /// fn GetDefaultPolicy(&self) -> Option> { diff --git a/tests/wpt/meta/trusted-types/HTMLElement-generic.html.ini b/tests/wpt/meta/trusted-types/HTMLElement-generic.html.ini index 80ff76472e5..13fbd908f76 100644 --- a/tests/wpt/meta/trusted-types/HTMLElement-generic.html.ini +++ b/tests/wpt/meta/trusted-types/HTMLElement-generic.html.ini @@ -1,5 +1,4 @@ [HTMLElement-generic.html] - expected: ERROR [TT enabled: script.src\n = String on a\n connected element\n ] expected: FAIL @@ -71,3 +70,15 @@ [TT enabled: script.textContent\n = String on a\n non-connected element\n after removing the "require-trusted-types-for 'script' directive] expected: FAIL + + [TT enabled: script.src\n = TrustedScript on a\n connected element\n ] + expected: FAIL + + [TT enabled: script.src\n = TrustedScript on a\n non-connected element\n ] + expected: FAIL + + [TT enabled: script.src\n = TrustedScript on a\n connected element\n after removing the "require-trusted-types-for 'script' directive] + expected: FAIL + + [TT enabled: script.src\n = TrustedScript on a\n non-connected element\n after removing the "require-trusted-types-for 'script' directive] + expected: FAIL diff --git a/tests/wpt/meta/trusted-types/TrustedTypePolicyFactory-getAttributeType-namespace.html.ini b/tests/wpt/meta/trusted-types/TrustedTypePolicyFactory-getAttributeType-namespace.html.ini deleted file mode 100644 index 538b1d0518c..00000000000 --- a/tests/wpt/meta/trusted-types/TrustedTypePolicyFactory-getAttributeType-namespace.html.ini +++ /dev/null @@ -1,63 +0,0 @@ -[TrustedTypePolicyFactory-getAttributeType-namespace.html] - [0: getAttributeType with full namespace info.] - expected: FAIL - - [0: getAttributeType with element namespace and empty attribute namespace] - expected: FAIL - - [0: getAttributeType without namespaces.] - expected: FAIL - - [0: getAttributeType with undefined and empty namespace.] - expected: FAIL - - [0: getAttributeType with empty and undefined namespace.] - expected: FAIL - - [0: getAttributeType with empty namespaces.] - expected: FAIL - - [0: getAttributeType with element namespace and empty attribute namespace.] - expected: FAIL - - [1: getAttributeType with full namespace info.] - expected: FAIL - - [1: getAttributeType with element namespace and empty attribute namespace] - expected: FAIL - - [1: getAttributeType without namespaces.] - expected: FAIL - - [1: getAttributeType with undefined and empty namespace.] - expected: FAIL - - [1: getAttributeType with empty and undefined namespace.] - expected: FAIL - - [1: getAttributeType with empty namespaces.] - expected: FAIL - - [1: getAttributeType with element namespace and empty attribute namespace.] - expected: FAIL - - [2: getAttributeType with full namespace info.] - expected: FAIL - - [2: getAttributeType with element namespace and empty attribute namespace] - expected: FAIL - - [2: getAttributeType without namespaces.] - expected: FAIL - - [2: getAttributeType with undefined and empty namespace.] - expected: FAIL - - [2: getAttributeType with empty and undefined namespace.] - expected: FAIL - - [2: getAttributeType with empty namespaces.] - expected: FAIL - - [2: getAttributeType with element namespace and empty attribute namespace.] - expected: FAIL diff --git a/tests/wpt/meta/trusted-types/TrustedTypePolicyFactory-getAttributeType-svg.html.ini b/tests/wpt/meta/trusted-types/TrustedTypePolicyFactory-getAttributeType-svg.html.ini deleted file mode 100644 index 98d6ec011a3..00000000000 --- a/tests/wpt/meta/trusted-types/TrustedTypePolicyFactory-getAttributeType-svg.html.ini +++ /dev/null @@ -1,12 +0,0 @@ -[TrustedTypePolicyFactory-getAttributeType-svg.html] - [trustedTypes.getAttributeType html script[href\]] - expected: FAIL - - [trustedTypes.getAttributeType svg script[href\]] - expected: FAIL - - [trustedTypes.getAttributeType svg script[href\] xlink href] - expected: FAIL - - [trustedTypes.getAttributeType svg script[href\] other href] - expected: FAIL diff --git a/tests/wpt/meta/trusted-types/TrustedTypePolicyFactory-getAttributeType.html.ini b/tests/wpt/meta/trusted-types/TrustedTypePolicyFactory-getAttributeType.html.ini index 42baaa861f1..e442d6b4a42 100644 --- a/tests/wpt/meta/trusted-types/TrustedTypePolicyFactory-getAttributeType.html.ini +++ b/tests/wpt/meta/trusted-types/TrustedTypePolicyFactory-getAttributeType.html.ini @@ -7,63 +7,3 @@ [getAttributeType(\n "mrow",\n "onmousedown",\n "http://www.w3.org/1998/Math/MathML",\n "null") == "TrustedScript"] expected: FAIL - - [getAttributeType(\n "IFRAME",\n "srcdoc",\n "http://www.w3.org/1999/xhtml",\n "null") == "TrustedHTML"] - expected: FAIL - - [getAttributeType(\n "SCRIPT",\n "src",\n "http://www.w3.org/1999/xhtml",\n "null") == "TrustedScriptURL"] - expected: FAIL - - [getAttributeType(\n "script",\n "href",\n "http://www.w3.org/2000/svg",\n "null") == "TrustedScriptURL"] - expected: FAIL - - [getAttributeType(\n "script",\n "href",\n "http://www.w3.org/2000/svg",\n "http://www.w3.org/1999/xlink") == "TrustedScriptURL"] - expected: FAIL - - [getAttributeType(\n "foo",\n "onmouseup",\n "https://example.com/namespace",\n "null") == "null"] - expected: FAIL - - [getAttributeType(\n "DIV",\n "onclick",\n "http://www.w3.org/1999/xhtml",\n "https://example.com/namespace") == "null"] - expected: FAIL - - [getAttributeType(\n "DIV",\n "ondoesnotexist",\n "http://www.w3.org/1999/xhtml",\n "null") == "null"] - expected: FAIL - - [getAttributeType(\n "DIV",\n "data-onclick",\n "http://www.w3.org/1999/xhtml",\n "null") == "null"] - expected: FAIL - - [getAttributeType(\n "DIV",\n "srcdoc",\n "http://www.w3.org/1999/xhtml",\n "null") == "null"] - expected: FAIL - - [getAttributeType(\n "iframe",\n "srcdoc",\n "https://example.com/namespace",\n "null") == "null"] - expected: FAIL - - [getAttributeType(\n "IFRAME",\n "srcdoc",\n "http://www.w3.org/1999/xhtml",\n "https://example.com/namespace") == "null"] - expected: FAIL - - [getAttributeType(\n "IFRAME",\n "data-srcdoc",\n "http://www.w3.org/1999/xhtml",\n "null") == "null"] - expected: FAIL - - [getAttributeType(\n "DIV",\n "src",\n "http://www.w3.org/1999/xhtml",\n "null") == "null"] - expected: FAIL - - [getAttributeType(\n "script",\n "src",\n "https://example.com/namespace",\n "null") == "null"] - expected: FAIL - - [getAttributeType(\n "SCRIPT",\n "src",\n "http://www.w3.org/1999/xhtml",\n "https://example.com/namespace") == "null"] - expected: FAIL - - [getAttributeType(\n "SCRIPT",\n "data-src",\n "http://www.w3.org/1999/xhtml",\n "null") == "null"] - expected: FAIL - - [getAttributeType(\n "g",\n "href",\n "http://www.w3.org/2000/svg",\n "null") == "null"] - expected: FAIL - - [getAttributeType(\n "SCRIPT",\n "href",\n "http://www.w3.org/1999/xhtml",\n "null") == "null"] - expected: FAIL - - [getAttributeType(\n "script",\n "href",\n "http://www.w3.org/2000/svg",\n "https://example.com/namespace") == "null"] - expected: FAIL - - [getAttributeType(\n "script",\n "src",\n "http://www.w3.org/2000/svg",\n "null") == "null"] - expected: FAIL diff --git a/tests/wpt/meta/trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html.ini b/tests/wpt/meta/trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html.ini index 79d44e7984a..545aad66cfa 100644 --- a/tests/wpt/meta/trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html.ini +++ b/tests/wpt/meta/trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html.ini @@ -1,48 +1,9 @@ [TrustedTypePolicyFactory-getPropertyType.tentative.html] - [sanity check trustedTypes.getPropertyType for the HTML script element.] - expected: FAIL - [sanity check trustedTypes.getAttributeType.] expected: FAIL - [getPropertyType tests adapted from w3c/trusted-types polyfill] - expected: FAIL - [getAttributeType tests adapted from w3c/trusted-types polyfill] expected: FAIL - [iframe.srcDoc is maybe defined] - expected: FAIL - - [IFRAME.srcDoc is maybe defined] - expected: FAIL - - [iFrAmE.srcDoc is maybe defined] - expected: FAIL - - [iframe.SRCDOC is maybe defined] - expected: FAIL - - [IFRAME.SRCDOC is maybe defined] - expected: FAIL - - [iFrAmE.SRCDOC is maybe defined] - expected: FAIL - [getPropertyType vs getAttributeType for event handler.] expected: FAIL - - [ASCII case-insensitivity of tag name and attribute parameters] - expected: FAIL - - [getPropertyType with an explicit elementNs parameter] - expected: FAIL - - [getAttributeType with explicit elementNs and attrNs parameters] - expected: FAIL - - [getAttributeType with qualified attribute name] - expected: FAIL - - [getPropertyType/getAttributeType with explicit null elementNs/attrNs] - expected: FAIL diff --git a/tests/wpt/meta/trusted-types/legacy-trusted-script-urls.html.ini b/tests/wpt/meta/trusted-types/legacy-trusted-script-urls.html.ini deleted file mode 100644 index 77047059ac5..00000000000 --- a/tests/wpt/meta/trusted-types/legacy-trusted-script-urls.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[legacy-trusted-script-urls.html] - [getPropertyType() with legacy TrustedScriptURLs properties return null.] - expected: FAIL - - [getAttributeType() with legacy TrustedScriptURLs attributes return null.] - expected: FAIL