mirror of
https://github.com/lexmount/moli.git
synced 2026-10-12 16:01:22 +00:00
fix(trusted-types): expose shared attribute sink types
This commit is contained in:
@@ -3639,8 +3639,6 @@ trusted-types/ServiceWorkerContainer-register-from-DedicatedWorker.https.html
|
||||
trusted-types/ServiceWorkerContainer-register-from-ServiceWorker.https.html
|
||||
trusted-types/ServiceWorkerContainer-register-from-SharedWorker.https.html
|
||||
trusted-types/TrustedType-AttributeNodes.html
|
||||
trusted-types/TrustedTypePolicyFactory-getAttributeType-namespace.html
|
||||
trusted-types/TrustedTypePolicyFactory-getAttributeType-svg.html
|
||||
trusted-types/TrustedTypePolicyFactory-getAttributeType.html
|
||||
trusted-types/Window-TrustedTypes.html
|
||||
trusted-types/block-Document-execCommand.html
|
||||
|
||||
@@ -7994,6 +7994,8 @@ trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests.html
|
||||
trusted-types/TrustedTypePolicyFactory-createPolicy-non-tt-policy-name.html
|
||||
trusted-types/TrustedTypePolicyFactory-createPolicy-unenforced.html
|
||||
trusted-types/TrustedTypePolicyFactory-defaultPolicy.html
|
||||
trusted-types/TrustedTypePolicyFactory-getAttributeType-namespace.html
|
||||
trusted-types/TrustedTypePolicyFactory-getAttributeType-svg.html
|
||||
trusted-types/TrustedTypePolicyFactory-isXXX.html
|
||||
trusted-types/Window-block-eval-function-constructor.html
|
||||
trusted-types/Window-setTimeout-setInterval.html
|
||||
|
||||
@@ -90,6 +90,13 @@ struct TrustedTypePolicyFactoryInterfaceDeclaration {
|
||||
enumerable
|
||||
)]
|
||||
empty_script: (),
|
||||
#[webapi(
|
||||
method = "getAttributeType",
|
||||
callback = trusted_types_get_attribute_type_callback,
|
||||
length = 2,
|
||||
enumerable
|
||||
)]
|
||||
get_attribute_type: (),
|
||||
#[webapi(
|
||||
accessor_property = "defaultPolicy",
|
||||
getter = trusted_types_default_policy_getter_callback,
|
||||
@@ -109,6 +116,19 @@ struct TrustedTypesFactoryObjectDeclaration<'scope> {
|
||||
created_policy_names: v8::Local<'scope, v8::Array>,
|
||||
}
|
||||
|
||||
#[derive(webidl::WebIdlArgs)]
|
||||
#[webidl(prefix = "TrustedTypePolicyFactory.getAttributeType")]
|
||||
struct TrustedTypesGetAttributeTypeArgs {
|
||||
#[webidl(required)]
|
||||
tag_name: String,
|
||||
#[webidl(required)]
|
||||
attribute: String,
|
||||
#[webidl(nullable)]
|
||||
element_namespace: Option<String>,
|
||||
#[webidl(nullable)]
|
||||
attribute_namespace: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(WebApiObject)]
|
||||
#[webapi(plain)]
|
||||
struct TrustedTypeObjectDeclaration<'scope> {
|
||||
@@ -1078,6 +1098,41 @@ fn trusted_types_is_script_url_callback<'s>(
|
||||
rv.set_bool(trusted_type_string(scope, args.get(0), TrustedTypeKind::ScriptUrl).is_some());
|
||||
}
|
||||
|
||||
fn trusted_types_get_attribute_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::<TrustedTypesGetAttributeTypeArgs>(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 attribute_namespace = parsed
|
||||
.attribute_namespace
|
||||
.filter(|namespace| !namespace.is_empty());
|
||||
let tag_name = parsed.tag_name.to_ascii_lowercase();
|
||||
let attribute = parsed.attribute.to_ascii_lowercase();
|
||||
let Some(type_name) = crate::native_bridge::element::trusted_attribute_type_name_for_names(
|
||||
&element_namespace,
|
||||
&tag_name,
|
||||
attribute_namespace.as_deref(),
|
||||
&attribute,
|
||||
) 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,
|
||||
|
||||
@@ -54,13 +54,15 @@ mod trusted_types;
|
||||
pub(crate) use script_execution::{
|
||||
inline_script_source_for_execution, prepare_inline_classic_frame_script_job_for_execution,
|
||||
};
|
||||
pub(crate) use trusted_types::set_svg_animated_string_base_value;
|
||||
pub(in crate::native_bridge) use trusted_types::{
|
||||
TrustedAttributeSetter, trusted_attribute_string_value, trusted_attribute_value_string,
|
||||
};
|
||||
use trusted_types::{
|
||||
TrustedScriptElementSink, trusted_script_element_sink_string, trusted_script_url_sink_string,
|
||||
};
|
||||
pub(crate) use trusted_types::{
|
||||
set_svg_animated_string_base_value, trusted_attribute_type_name_for_names,
|
||||
};
|
||||
|
||||
pub(crate) use forms::{
|
||||
autocomplete_field_name, autofill_related_form_control_elements, form_associated_form_owner,
|
||||
|
||||
@@ -41,6 +41,80 @@ enum TrustedAttributeSink {
|
||||
ScriptUrl(&'static str),
|
||||
}
|
||||
|
||||
impl TrustedAttributeSink {
|
||||
fn type_name(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Script(_) => "TrustedScript",
|
||||
Self::ScriptUrl(_) => "TrustedScriptURL",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn trusted_attribute_sink_for_names(
|
||||
element_namespace: &str,
|
||||
element_local_name: &str,
|
||||
attribute_namespace: Option<&str>,
|
||||
attribute_local_name: &str,
|
||||
) -> Option<TrustedAttributeSink> {
|
||||
if attribute_namespace.is_none()
|
||||
&& matches!(
|
||||
element_namespace,
|
||||
"http://www.w3.org/1999/xhtml"
|
||||
| "http://www.w3.org/2000/svg"
|
||||
| "http://www.w3.org/1998/Math/MathML"
|
||||
)
|
||||
&& super::event_handlers::is_element_event_handler_content_attribute_name(
|
||||
attribute_local_name,
|
||||
)
|
||||
{
|
||||
return Some(TrustedAttributeSink::Script(format!(
|
||||
"Element {attribute_local_name}"
|
||||
)));
|
||||
}
|
||||
|
||||
match (
|
||||
element_namespace,
|
||||
element_local_name,
|
||||
attribute_namespace,
|
||||
attribute_local_name,
|
||||
) {
|
||||
("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",
|
||||
None | Some("http://www.w3.org/1999/xlink"),
|
||||
"href",
|
||||
) => Some(TrustedAttributeSink::ScriptUrl("SVGScriptElement href")),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn trusted_attribute_type_name_for_names(
|
||||
element_namespace: &str,
|
||||
element_local_name: &str,
|
||||
attribute_namespace: Option<&str>,
|
||||
attribute_local_name: &str,
|
||||
) -> Option<&'static str> {
|
||||
trusted_attribute_sink_for_names(
|
||||
element_namespace,
|
||||
element_local_name,
|
||||
attribute_namespace,
|
||||
attribute_local_name,
|
||||
)
|
||||
.map(|sink| sink.type_name())
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub(in crate::native_bridge::element) enum TrustedHtmlSink {
|
||||
ElementInnerHtml,
|
||||
@@ -179,49 +253,12 @@ pub(in crate::native_bridge) fn trusted_attribute_value_string<'s>(
|
||||
.dom_host()
|
||||
.node(handle)
|
||||
.and_then(|node| node.as_element())?;
|
||||
let element_namespace = element.namespace();
|
||||
|
||||
if attribute_namespace.is_none()
|
||||
&& matches!(
|
||||
element_namespace,
|
||||
"http://www.w3.org/1999/xhtml"
|
||||
| "http://www.w3.org/2000/svg"
|
||||
| "http://www.w3.org/1998/Math/MathML"
|
||||
)
|
||||
&& super::event_handlers::is_element_event_handler_content_attribute_name(local_name)
|
||||
{
|
||||
return Some((
|
||||
runtime_ptr,
|
||||
TrustedAttributeSink::Script(format!("Element {local_name}")),
|
||||
));
|
||||
}
|
||||
|
||||
let sink = match (
|
||||
element_namespace,
|
||||
let sink = trusted_attribute_sink_for_names(
|
||||
element.namespace(),
|
||||
element.local_name(),
|
||||
attribute_namespace,
|
||||
local_name,
|
||||
) {
|
||||
("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",
|
||||
None | Some("http://www.w3.org/1999/xlink"),
|
||||
"href",
|
||||
) => Some(TrustedAttributeSink::ScriptUrl("SVGScriptElement href")),
|
||||
_ => None,
|
||||
}?;
|
||||
)?;
|
||||
Some((runtime_ptr, sink))
|
||||
});
|
||||
|
||||
|
||||
@@ -198,6 +198,86 @@ fn trusted_type_factory_interface_exposes_stable_branded_empty_values() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trusted_type_factory_get_attribute_type_reuses_attribute_sink_classification() {
|
||||
let mut vm = new_storage_test_vm("https://trusted-type-attribute-types.test/");
|
||||
|
||||
let result = vm
|
||||
.eval(
|
||||
r#"
|
||||
(() => {
|
||||
const HTML = "http://www.w3.org/1999/xhtml";
|
||||
const SVG = "http://www.w3.org/2000/svg";
|
||||
const MATHML = "http://www.w3.org/1998/Math/MathML";
|
||||
const XLINK = "http://www.w3.org/1999/xlink";
|
||||
const OTHER = "https://example.test/namespace";
|
||||
const type = (...args) => trustedTypes.getAttributeType(...args);
|
||||
const errorName = callback => {
|
||||
try {
|
||||
callback();
|
||||
return "none";
|
||||
} catch (error) {
|
||||
return error.constructor.name;
|
||||
}
|
||||
};
|
||||
const descriptor = Object.getOwnPropertyDescriptor(
|
||||
TrustedTypePolicyFactory.prototype,
|
||||
"getAttributeType"
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
interface: [
|
||||
typeof descriptor.value,
|
||||
descriptor.value.name,
|
||||
descriptor.value.length,
|
||||
descriptor.enumerable,
|
||||
descriptor.configurable,
|
||||
Object.hasOwn(trustedTypes, "getAttributeType")
|
||||
],
|
||||
htmlDefaults: [
|
||||
type("script", "src"),
|
||||
type("SCRIPT", "SRC", undefined, undefined),
|
||||
type("script", "src", null, null),
|
||||
type("script", "src", "", ""),
|
||||
type("script", "src", HTML, ""),
|
||||
type("ſcript", "src"),
|
||||
type("script", "ſrc")
|
||||
],
|
||||
urls: [
|
||||
type("embed", "src"),
|
||||
type("object", "data"),
|
||||
type("object", "codebase"),
|
||||
type("script", "href"),
|
||||
type("script", "href", SVG),
|
||||
type("SCRIPT", "HREF", SVG, XLINK),
|
||||
type("script", "href", SVG, OTHER),
|
||||
type("script", "href", SVG.toUpperCase())
|
||||
],
|
||||
handlers: [
|
||||
type("div", "onclick"),
|
||||
type("g", "ondblclick", SVG),
|
||||
type("mrow", "onmousedown", MATHML),
|
||||
type("div", "onclick", HTML, OTHER),
|
||||
type("foo", "onmouseup", OTHER),
|
||||
type("div", "ondoesnotexist")
|
||||
],
|
||||
errors: [
|
||||
errorName(() => type()),
|
||||
errorName(() => type("script")),
|
||||
errorName(() => descriptor.value.call({}, "script", "src"))
|
||||
]
|
||||
});
|
||||
})()
|
||||
"#,
|
||||
)
|
||||
.expect("TrustedTypePolicyFactory getAttributeType 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"]}"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trusted_type_factory_default_policy_getter_tracks_the_branded_policy() {
|
||||
let mut vm = new_storage_test_vm("https://trusted-type-factory-default-policy.test/");
|
||||
|
||||
Reference in New Issue
Block a user