mirror of
https://github.com/lexmount/moli.git
synced 2026-10-04 00:00:50 +00:00
fix(trusted-types): align legacy URL sink metadata
This commit is contained in:
@@ -3702,7 +3702,6 @@ trusted-types/block-string-assignment-to-HTMLIFrameElement-srcdoc.html
|
||||
trusted-types/block-string-assignment-to-attribute-via-attribute-node.html
|
||||
trusted-types/eval-function-constructor-untrusted-arguments-and-applying-default-policy.html
|
||||
trusted-types/inheriting-csp-for-local-schemes.html
|
||||
trusted-types/legacy-trusted-script-urls.html
|
||||
trusted-types/modify-attributes-in-callback.html
|
||||
trusted-types/require-trusted-types-for-TypeError-belongs-to-the-global-object-realm.html
|
||||
trusted-types/script-enforcement-006.html
|
||||
|
||||
@@ -7851,6 +7851,7 @@ trusted-types/eval-no-csp-no-tt.html
|
||||
trusted-types/eval-with-non-trusted-script-object.html
|
||||
trusted-types/eval-with-permissive-csp.html
|
||||
trusted-types/get-trusted-types-compliant-attribute-value.html
|
||||
trusted-types/legacy-trusted-script-urls.html
|
||||
trusted-types/legacy-trusted-scripts.html
|
||||
trusted-types/navigate-to-javascript-url-001.html
|
||||
trusted-types/navigate-to-javascript-url-002.html
|
||||
|
||||
@@ -95,6 +95,13 @@ struct TrustedTypePolicyFactoryInterfaceDeclaration {
|
||||
enumerable
|
||||
)]
|
||||
get_attribute_type: (),
|
||||
#[webapi(
|
||||
method = "getPropertyType",
|
||||
callback = trusted_types_get_property_type_callback,
|
||||
length = 2,
|
||||
enumerable
|
||||
)]
|
||||
get_property_type: (),
|
||||
#[webapi(
|
||||
accessor_property = "defaultPolicy",
|
||||
getter = trusted_types_default_policy_getter_callback,
|
||||
@@ -127,6 +134,17 @@ struct TrustedTypesGetAttributeTypeArgs {
|
||||
attribute_namespace: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(webidl::WebIdlArgs)]
|
||||
#[webidl(prefix = "TrustedTypePolicyFactory.getPropertyType")]
|
||||
struct TrustedTypesGetPropertyTypeArgs {
|
||||
#[webidl(required)]
|
||||
tag_name: String,
|
||||
#[webidl(required)]
|
||||
property: String,
|
||||
#[webidl(nullable)]
|
||||
element_namespace: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(WebApiObject)]
|
||||
#[webapi(interface = "Object")]
|
||||
struct TrustedTypeObjectDeclaration<'scope> {
|
||||
@@ -1152,6 +1170,36 @@ fn trusted_types_get_attribute_type_callback<'s>(
|
||||
rv.set(type_name.into());
|
||||
}
|
||||
|
||||
fn trusted_types_get_property_type_callback<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
args: v8::FunctionCallbackArguments<'s>,
|
||||
mut rv: v8::ReturnValue<'_, v8::Value>,
|
||||
) {
|
||||
if !trusted_types_factory_receiver_is_valid(scope, args.this()) {
|
||||
return;
|
||||
}
|
||||
let Some(parsed) = webidl::parse_args::<TrustedTypesGetPropertyTypeArgs>(scope, &args) else {
|
||||
return;
|
||||
};
|
||||
let element_namespace = parsed
|
||||
.element_namespace
|
||||
.filter(|namespace| !namespace.is_empty())
|
||||
.unwrap_or_else(|| crate::native_bridge::document::XHTML_NS.to_owned());
|
||||
let tag_name = parsed.tag_name.to_ascii_lowercase();
|
||||
let Some(type_name) = crate::native_bridge::element::trusted_property_type_name_for_names(
|
||||
&element_namespace,
|
||||
&tag_name,
|
||||
&parsed.property,
|
||||
) else {
|
||||
rv.set_null();
|
||||
return;
|
||||
};
|
||||
let Some(type_name) = v8_string(scope, type_name) else {
|
||||
return;
|
||||
};
|
||||
rv.set(type_name.into());
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum FunctionConstructorKind {
|
||||
Function,
|
||||
|
||||
@@ -83,6 +83,7 @@ pub(super) fn install_lazy_trusted_types_runtime_state<'s>(
|
||||
empty_html: (),
|
||||
empty_script: (),
|
||||
get_attribute_type: (),
|
||||
get_property_type: (),
|
||||
default_policy: (),
|
||||
}
|
||||
.bind(scope, global)
|
||||
|
||||
@@ -62,6 +62,7 @@ use trusted_types::{
|
||||
};
|
||||
pub(crate) use trusted_types::{
|
||||
set_svg_animated_string_base_value, trusted_attribute_type_name_for_names,
|
||||
trusted_property_type_name_for_names,
|
||||
};
|
||||
|
||||
pub(crate) use forms::{
|
||||
|
||||
@@ -81,15 +81,6 @@ fn trusted_attribute_sink_for_names(
|
||||
("http://www.w3.org/1999/xhtml", "script", None, "src") => {
|
||||
Some(TrustedAttributeSink::ScriptUrl("HTMLScriptElement src"))
|
||||
}
|
||||
("http://www.w3.org/1999/xhtml", "embed", None, "src") => {
|
||||
Some(TrustedAttributeSink::ScriptUrl("HTMLEmbedElement src"))
|
||||
}
|
||||
("http://www.w3.org/1999/xhtml", "object", None, "data") => {
|
||||
Some(TrustedAttributeSink::ScriptUrl("HTMLObjectElement data"))
|
||||
}
|
||||
("http://www.w3.org/1999/xhtml", "object", None, "codebase") => Some(
|
||||
TrustedAttributeSink::ScriptUrl("HTMLObjectElement codebase"),
|
||||
),
|
||||
(
|
||||
"http://www.w3.org/2000/svg",
|
||||
"script",
|
||||
@@ -115,6 +106,24 @@ pub(crate) fn trusted_attribute_type_name_for_names(
|
||||
.map(|sink| sink.type_name())
|
||||
}
|
||||
|
||||
pub(crate) fn trusted_property_type_name_for_names(
|
||||
element_namespace: &str,
|
||||
element_local_name: &str,
|
||||
property_name: &str,
|
||||
) -> Option<&'static str> {
|
||||
if matches!(property_name, "innerHTML" | "outerHTML") {
|
||||
return Some("TrustedHTML");
|
||||
}
|
||||
match (element_namespace, element_local_name, property_name) {
|
||||
("http://www.w3.org/1999/xhtml", "iframe", "srcdoc") => Some("TrustedHTML"),
|
||||
("http://www.w3.org/1999/xhtml", "script", "innerText" | "text" | "textContent") => {
|
||||
Some("TrustedScript")
|
||||
}
|
||||
("http://www.w3.org/1999/xhtml", "script", "src") => Some("TrustedScriptURL"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub(in crate::native_bridge::element) enum TrustedHtmlSink {
|
||||
ElementInnerHtml,
|
||||
|
||||
@@ -159,7 +159,7 @@ fn trusted_type_factory_interface_exposes_stable_branded_empty_values() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trusted_type_factory_get_attribute_type_reuses_attribute_sink_classification() {
|
||||
fn trusted_type_factory_introspection_reuses_current_sink_classification() {
|
||||
let mut vm = new_storage_test_vm("https://trusted-type-attribute-types.test/");
|
||||
|
||||
let result = vm
|
||||
@@ -172,6 +172,7 @@ fn trusted_type_factory_get_attribute_type_reuses_attribute_sink_classification(
|
||||
const XLINK = "http://www.w3.org/1999/xlink";
|
||||
const OTHER = "https://example.test/namespace";
|
||||
const type = (...args) => trustedTypes.getAttributeType(...args);
|
||||
const propertyType = (...args) => trustedTypes.getPropertyType(...args);
|
||||
const errorName = callback => {
|
||||
try {
|
||||
callback();
|
||||
@@ -180,19 +181,28 @@ fn trusted_type_factory_get_attribute_type_reuses_attribute_sink_classification(
|
||||
return error.constructor.name;
|
||||
}
|
||||
};
|
||||
const descriptor = Object.getOwnPropertyDescriptor(
|
||||
const attributeDescriptor = Object.getOwnPropertyDescriptor(
|
||||
TrustedTypePolicyFactory.prototype,
|
||||
"getAttributeType"
|
||||
);
|
||||
const propertyDescriptor = Object.getOwnPropertyDescriptor(
|
||||
TrustedTypePolicyFactory.prototype,
|
||||
"getPropertyType"
|
||||
);
|
||||
const describe = descriptor => [
|
||||
typeof descriptor.value,
|
||||
descriptor.value.name,
|
||||
descriptor.value.length,
|
||||
descriptor.enumerable,
|
||||
descriptor.configurable
|
||||
];
|
||||
|
||||
return JSON.stringify({
|
||||
interface: [
|
||||
typeof descriptor.value,
|
||||
descriptor.value.name,
|
||||
descriptor.value.length,
|
||||
descriptor.enumerable,
|
||||
descriptor.configurable,
|
||||
Object.hasOwn(trustedTypes, "getAttributeType")
|
||||
describe(attributeDescriptor),
|
||||
describe(propertyDescriptor),
|
||||
Object.hasOwn(trustedTypes, "getAttributeType"),
|
||||
Object.hasOwn(trustedTypes, "getPropertyType")
|
||||
],
|
||||
htmlDefaults: [
|
||||
type("script", "src"),
|
||||
@@ -213,6 +223,17 @@ fn trusted_type_factory_get_attribute_type_reuses_attribute_sink_classification(
|
||||
type("script", "href", SVG, OTHER),
|
||||
type("script", "href", SVG.toUpperCase())
|
||||
],
|
||||
properties: [
|
||||
propertyType("script", "text"),
|
||||
propertyType("SCRIPT", "src"),
|
||||
propertyType("script", "sRc"),
|
||||
propertyType("div", "innerHTML"),
|
||||
propertyType("foo", "outerHTML", OTHER),
|
||||
propertyType("script", "src", SVG),
|
||||
propertyType("embed", "src"),
|
||||
propertyType("object", "data"),
|
||||
propertyType("object", "codeBase")
|
||||
],
|
||||
handlers: [
|
||||
type("div", "onclick"),
|
||||
type("g", "ondblclick", SVG),
|
||||
@@ -224,17 +245,20 @@ fn trusted_type_factory_get_attribute_type_reuses_attribute_sink_classification(
|
||||
errors: [
|
||||
errorName(() => type()),
|
||||
errorName(() => type("script")),
|
||||
errorName(() => descriptor.value.call({}, "script", "src"))
|
||||
errorName(() => attributeDescriptor.value.call({}, "script", "src")),
|
||||
errorName(() => propertyType()),
|
||||
errorName(() => propertyType("script")),
|
||||
errorName(() => propertyDescriptor.value.call({}, "script", "src"))
|
||||
]
|
||||
});
|
||||
})()
|
||||
"#,
|
||||
)
|
||||
.expect("TrustedTypePolicyFactory getAttributeType probe should evaluate");
|
||||
.expect("TrustedTypePolicyFactory introspection probe should evaluate");
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
r#"{"interface":["function","getAttributeType",2,true,true,false],"htmlDefaults":["TrustedScriptURL","TrustedScriptURL","TrustedScriptURL","TrustedScriptURL","TrustedScriptURL",null,null],"urls":["TrustedScriptURL","TrustedScriptURL","TrustedScriptURL",null,"TrustedScriptURL","TrustedScriptURL",null,null],"handlers":["TrustedScript","TrustedScript","TrustedScript",null,null,null],"errors":["TypeError","TypeError","TypeError"]}"#
|
||||
r#"{"interface":[["function","getAttributeType",2,true,true],["function","getPropertyType",2,true,true],false,false],"htmlDefaults":["TrustedScriptURL","TrustedScriptURL","TrustedScriptURL","TrustedScriptURL","TrustedScriptURL",null,null],"urls":[null,null,null,null,"TrustedScriptURL","TrustedScriptURL",null,null],"properties":["TrustedScript","TrustedScriptURL",null,"TrustedHTML","TrustedHTML",null,null,null,null],"handlers":["TrustedScript","TrustedScript","TrustedScript",null,null,null],"errors":["TypeError","TypeError","TypeError","TypeError","TypeError","TypeError"]}"#
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1298,7 +1322,7 @@ fn event_handler_attribute_writes_enforce_trusted_script_at_the_attribute_bounda
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn url_attribute_writes_enforce_the_non_iframe_trusted_script_url_sink_table() {
|
||||
fn url_attribute_writes_enforce_only_the_current_non_iframe_script_url_sinks() {
|
||||
let mut vm = new_storage_test_vm("https://url-attribute-trusted-types.test/");
|
||||
vm.set_response_content_security_policies(&["require-trusted-types-for 'script'".to_owned()]);
|
||||
|
||||
@@ -1333,10 +1357,7 @@ fn url_attribute_writes_enforce_the_non_iframe_trusted_script_url_sink_table() {
|
||||
[document.createElement("script"), element => element.setAttribute("src", "plain")],
|
||||
[document.createElement("script"), element => element.setAttributeNS(null, "src", null)],
|
||||
[document.createElementNS(svg, "script"), element => element.setAttribute("href", "plain")],
|
||||
[document.createElementNS(svg, "script"), element => element.setAttributeNS(xlink, "xlink:href", policy.createScript("wrong"))],
|
||||
[document.createElement("embed"), element => element.setAttribute("src", "plain")],
|
||||
[document.createElement("object"), element => element.setAttribute("data", "plain")],
|
||||
[document.createElement("object"), element => element.setAttribute("codebase", "plain")]
|
||||
[document.createElementNS(svg, "script"), element => element.setAttributeNS(xlink, "xlink:href", policy.createScript("wrong"))]
|
||||
]) {
|
||||
try {
|
||||
setter(element);
|
||||
@@ -1352,6 +1373,11 @@ fn url_attribute_writes_enforce_the_non_iframe_trusted_script_url_sink_table() {
|
||||
uppercaseSvg.setAttributeNS(null, "HREF", "uppercase");
|
||||
const div = document.createElement("div");
|
||||
div.setAttribute("src", "plain-div");
|
||||
const legacyEmbed = document.createElement("embed");
|
||||
legacyEmbed.setAttribute("src", "plain-embed");
|
||||
const legacyObject = document.createElement("object");
|
||||
legacyObject.setAttribute("data", "plain-object-data");
|
||||
legacyObject.setAttribute("codebase", "plain-object-codebase");
|
||||
|
||||
const defaultCalls = [];
|
||||
trustedTypes.createPolicy("default", {
|
||||
@@ -1381,7 +1407,10 @@ fn url_attribute_writes_enforce_the_non_iframe_trusted_script_url_sink_table() {
|
||||
ordinary: [
|
||||
ordinary.getAttributeNS("urn:test", "src"),
|
||||
uppercaseSvg.getAttribute("HREF"),
|
||||
div.getAttribute("src")
|
||||
div.getAttribute("src"),
|
||||
legacyEmbed.getAttribute("src"),
|
||||
legacyObject.getAttribute("data"),
|
||||
legacyObject.getAttribute("codebase")
|
||||
],
|
||||
defaultValues: [
|
||||
defaultHtml.getAttribute("src"),
|
||||
@@ -1397,7 +1426,7 @@ fn url_attribute_writes_enforce_the_non_iframe_trusted_script_url_sink_table() {
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
r#"{"trustedValues":["script.js","script-ns.js","svg.js","svg-xlink.js","embed.js","object-data.js","object-codebase.js"],"rejected":[true,true,true,true,true,true,true],"ordinary":["namespaced","uppercase","plain-div"],"defaultValues":["safe-default-html","safe-default-svg","safe-default-object"],"defaultCalls":[["default-html","TrustedScriptURL","HTMLScriptElement src"],["default-svg","TrustedScriptURL","SVGScriptElement href"],["default-object","TrustedScriptURL","HTMLObjectElement codebase"]]}"#
|
||||
r#"{"trustedValues":["script.js","script-ns.js","svg.js","svg-xlink.js","embed.js","object-data.js","object-codebase.js"],"rejected":[true,true,true,true],"ordinary":["namespaced","uppercase","plain-div","plain-embed","plain-object-data","plain-object-codebase"],"defaultValues":["safe-default-html","safe-default-svg","default-object"],"defaultCalls":[["default-html","TrustedScriptURL","HTMLScriptElement src"],["default-svg","TrustedScriptURL","SVGScriptElement href"]]}"#
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user