mirror of
https://github.com/lexmount/moli.git
synced 2026-10-04 08:00:45 +00:00
fix(svg): reflect animated strings through trusted types
This commit is contained in:
@@ -3736,7 +3736,6 @@ trusted-types/trusted-types-reporting-for-ServiceWorker-ServiceWorkerContainer-r
|
||||
trusted-types/trusted-types-reporting-for-SharedWorker-ServiceWorkerContainer-register.https.html
|
||||
trusted-types/trusted-types-reporting.html
|
||||
trusted-types/trusted-types-secondary-document.html
|
||||
trusted-types/trusted-types-svg-script-set-href.html
|
||||
uievents/order-of-events/focus-events/focus-automated-blink-webkit.html
|
||||
url/a-element.html?exclude=(file|javascript|mailto)
|
||||
url/a-element.html?include=file
|
||||
|
||||
@@ -7913,9 +7913,11 @@ trusted-types/trusted-types-reporting-for-Window-SharedWorker-constructor.html
|
||||
trusted-types/trusted-types-reporting-for-Window-eval.html
|
||||
trusted-types/trusted-types-reporting-for-Window-function-constructor.html
|
||||
trusted-types/trusted-types-reporting-for-Window-setTimeout-setInterval.html
|
||||
trusted-types/trusted-types-reporting.html
|
||||
trusted-types/trusted-types-sandbox-allow-scripts.html
|
||||
trusted-types/trusted-types-sandbox-no-allow-scripts.html
|
||||
trusted-types/trusted-types-source-file-path.html
|
||||
trusted-types/trusted-types-svg-script-set-href.html
|
||||
trusted-types/trusted-types-tojson.html
|
||||
trusted-types/tt-block-eval.html
|
||||
uievents/constructors/inputevent-constructor.html
|
||||
|
||||
@@ -1696,6 +1696,7 @@ pub(crate) fn finish_context_bootstrap(
|
||||
("SVGLength", "SVGLength"),
|
||||
("SVGNumber", "SVGNumber"),
|
||||
("SVGRect", "SVGRect"),
|
||||
("SVGAnimatedString", "SVGAnimatedString"),
|
||||
("SVGAnimatedLength", "SVGAnimatedLength"),
|
||||
("SVGLengthList", "SVGLengthList"),
|
||||
("SVGAnimatedLengthList", "SVGAnimatedLengthList"),
|
||||
|
||||
@@ -113,6 +113,11 @@ const CONSTRUCTOR_SPECS_BEFORE_STREAMS: &[ConstructorSpec] = &[
|
||||
parent: None,
|
||||
kind: ConstructorKind::Illegal,
|
||||
},
|
||||
ConstructorSpec {
|
||||
name: "SVGAnimatedString",
|
||||
parent: None,
|
||||
kind: ConstructorKind::Illegal,
|
||||
},
|
||||
ConstructorSpec {
|
||||
name: "SVGAnimatedLength",
|
||||
parent: None,
|
||||
|
||||
@@ -499,6 +499,26 @@ struct SvgLengthTemplateAccessorsDeclaration {
|
||||
value_as_string: (),
|
||||
}
|
||||
|
||||
#[derive(WebApiFunctionTemplate)]
|
||||
#[webapi(name = "SVGAnimatedString", enumerable)]
|
||||
struct SvgAnimatedStringTemplateAccessorsDeclaration {
|
||||
#[webapi(
|
||||
accessor_property = "baseVal",
|
||||
getter = svg_animated_string_getter,
|
||||
setter = svg_animated_string_setter,
|
||||
data = callback_data_index_value(scope, 0)
|
||||
)]
|
||||
base_val: (),
|
||||
|
||||
#[webapi(
|
||||
accessor_property = "animVal",
|
||||
getter = svg_animated_string_getter,
|
||||
data = callback_data_index_value(scope, 1)
|
||||
)]
|
||||
anim_val: (),
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(WebApiFunctionTemplate)]
|
||||
#[webapi(name = "SVGAnimatedLength", enumerable)]
|
||||
struct SvgAnimatedLengthTemplateAccessorsDeclaration {
|
||||
@@ -876,6 +896,23 @@ struct SvgGraphicsBoxElementPrototypeAccessorsDeclaration {
|
||||
height: (),
|
||||
}
|
||||
|
||||
#[derive(WebApiFunctionTemplate)]
|
||||
#[webapi(name = "SVGElement", enumerable)]
|
||||
struct SvgElementPrototypeAccessorsDeclaration {
|
||||
#[webapi(
|
||||
accessor_property = "className",
|
||||
getter = svg_element_class_name_getter
|
||||
)]
|
||||
class_name: (),
|
||||
}
|
||||
|
||||
#[derive(WebApiFunctionTemplate)]
|
||||
#[webapi(name = "SVGURIReference", enumerable)]
|
||||
struct SvgUriReferencePrototypeAccessorsDeclaration {
|
||||
#[webapi(accessor_property = "href", getter = svg_uri_href_getter)]
|
||||
href: (),
|
||||
}
|
||||
|
||||
pub(super) fn install_svg_length_bindings<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_, ()>,
|
||||
template: v8::Local<'s, v8::FunctionTemplate>,
|
||||
@@ -902,6 +939,14 @@ pub(super) fn install_svg_number_bindings<'s>(
|
||||
SvgNumberTemplateAccessorsDeclaration::initialize_prototype_template(scope, proto);
|
||||
}
|
||||
|
||||
pub(super) fn install_svg_animated_string_bindings<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_, ()>,
|
||||
template: v8::Local<'s, v8::FunctionTemplate>,
|
||||
) {
|
||||
let proto = template.prototype_template(scope);
|
||||
SvgAnimatedStringTemplateAccessorsDeclaration::initialize_prototype_template(scope, proto);
|
||||
}
|
||||
|
||||
pub(super) fn install_svg_animated_length_list_bindings<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_, ()>,
|
||||
template: v8::Local<'s, v8::FunctionTemplate>,
|
||||
@@ -1068,6 +1113,9 @@ pub(super) fn install_svg_element_accessor_bindings<'s>(
|
||||
SvgPatternElementPrototypeAccessorsDeclaration::initialize_prototype_template(
|
||||
scope, prototype,
|
||||
);
|
||||
SvgUriReferencePrototypeAccessorsDeclaration::initialize_prototype_template(
|
||||
scope, prototype,
|
||||
);
|
||||
}
|
||||
"SVGGradientElement" => {
|
||||
SvgGradientElementPrototypeAccessorsDeclaration::initialize_prototype_template(
|
||||
@@ -1094,7 +1142,28 @@ pub(super) fn install_svg_element_accessor_bindings<'s>(
|
||||
scope, prototype,
|
||||
);
|
||||
}
|
||||
"SVGImageElement" | "SVGUseElement" | "SVGForeignObjectElement" => {
|
||||
"SVGElement" => {
|
||||
SvgElementPrototypeAccessorsDeclaration::initialize_prototype_template(
|
||||
scope, prototype,
|
||||
);
|
||||
}
|
||||
"SVGAElement"
|
||||
| "SVGLinearGradientElement"
|
||||
| "SVGRadialGradientElement"
|
||||
| "SVGScriptElement" => {
|
||||
SvgUriReferencePrototypeAccessorsDeclaration::initialize_prototype_template(
|
||||
scope, prototype,
|
||||
);
|
||||
}
|
||||
"SVGImageElement" | "SVGUseElement" => {
|
||||
SvgGraphicsBoxElementPrototypeAccessorsDeclaration::initialize_prototype_template(
|
||||
scope, prototype,
|
||||
);
|
||||
SvgUriReferencePrototypeAccessorsDeclaration::initialize_prototype_template(
|
||||
scope, prototype,
|
||||
);
|
||||
}
|
||||
"SVGForeignObjectElement" => {
|
||||
SvgGraphicsBoxElementPrototypeAccessorsDeclaration::initialize_prototype_template(
|
||||
scope, prototype,
|
||||
);
|
||||
|
||||
@@ -3,6 +3,18 @@ use super::*;
|
||||
use crate::util::serialize_v8_iter_array;
|
||||
use moli_webapi_declare::WebApiObject;
|
||||
|
||||
#[derive(WebApiObject)]
|
||||
#[webapi(
|
||||
interface = "SVGAnimatedString",
|
||||
own_to_string_tag = "SVGAnimatedString"
|
||||
)]
|
||||
struct SvgAnimatedStringObjectDeclaration {
|
||||
#[webapi(slot = SVG_ANIMATED_STRING_BASE_VAL_SLOT)]
|
||||
base_val: String,
|
||||
#[webapi(slot = SVG_ANIMATED_STRING_ANIM_VAL_SLOT)]
|
||||
anim_val: String,
|
||||
}
|
||||
|
||||
#[derive(WebApiObject)]
|
||||
#[webapi(
|
||||
interface = "SVGAnimatedNumber",
|
||||
@@ -250,6 +262,19 @@ struct SvgTransformObjectDeclaration<'scope> {
|
||||
set_skew_y: (),
|
||||
}
|
||||
|
||||
pub(super) fn build_svg_animated_string_for_attribute<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
owner: v8::Local<'s, v8::Object>,
|
||||
attribute: &str,
|
||||
) -> v8::Local<'s, v8::Object> {
|
||||
let value = svg_owner_attribute_value(scope, owner, attribute).unwrap_or_default();
|
||||
let object = SvgAnimatedStringObjectDeclaration::new(value.clone(), value)
|
||||
.bind(scope)
|
||||
.expect("SVGAnimatedString declaration should bind");
|
||||
set_svg_animated_string_owner_attribute(scope, object, owner, attribute);
|
||||
object
|
||||
}
|
||||
|
||||
pub(super) fn build_svg_animated_length_list<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
) -> v8::Local<'s, v8::Object> {
|
||||
@@ -1787,6 +1812,69 @@ pub(super) fn sync_svg_animated_length_from_owner_attribute<'s>(
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn set_svg_animated_string_owner_attribute<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
animated: v8::Local<'s, v8::Object>,
|
||||
owner: v8::Local<'s, v8::Object>,
|
||||
attribute: &str,
|
||||
) {
|
||||
set_private_value(
|
||||
scope,
|
||||
animated,
|
||||
SVG_ANIMATED_STRING_OWNER_ELEMENT_SLOT,
|
||||
owner.into(),
|
||||
);
|
||||
set_private_value(
|
||||
scope,
|
||||
animated,
|
||||
SVG_ANIMATED_STRING_OWNER_ATTRIBUTE_SLOT,
|
||||
v8_string(scope, attribute)
|
||||
.unwrap_or_else(|| v8str(scope, ""))
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn sync_svg_animated_string_from_owner_attribute<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
animated: v8::Local<'s, v8::Object>,
|
||||
) {
|
||||
let Some(owner) = get_private_value(scope, animated, SVG_ANIMATED_STRING_OWNER_ELEMENT_SLOT)
|
||||
.and_then(|value| v8::Local::<v8::Object>::try_from(value).ok())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let Some(attribute) =
|
||||
get_private_value(scope, animated, SVG_ANIMATED_STRING_OWNER_ATTRIBUTE_SLOT)
|
||||
.and_then(|value| value.to_string(scope))
|
||||
.map(|value| value.to_rust_string_lossy(scope))
|
||||
.filter(|value| !value.is_empty())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let value = svg_owner_attribute_value(scope, owner, &attribute).unwrap_or_default();
|
||||
set_svg_animated_string_values(scope, animated, &value);
|
||||
}
|
||||
|
||||
pub(super) fn set_svg_animated_string_values(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
animated: v8::Local<'_, v8::Object>,
|
||||
value: &str,
|
||||
) {
|
||||
let value = v8_string(scope, value).unwrap_or_else(|| v8str(scope, ""));
|
||||
set_private_value(
|
||||
scope,
|
||||
animated,
|
||||
SVG_ANIMATED_STRING_BASE_VAL_SLOT,
|
||||
value.into(),
|
||||
);
|
||||
set_private_value(
|
||||
scope,
|
||||
animated,
|
||||
SVG_ANIMATED_STRING_ANIM_VAL_SLOT,
|
||||
value.into(),
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn set_svg_animated_number_owner_attribute<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
animated: v8::Local<'s, v8::Object>,
|
||||
|
||||
@@ -46,6 +46,42 @@ fn require_svg_receiver<'s>(
|
||||
false
|
||||
}
|
||||
|
||||
pub(super) fn svg_element_class_name_getter<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
args: v8::FunctionCallbackArguments<'s>,
|
||||
rv: v8::ReturnValue<'_, v8::Value>,
|
||||
) {
|
||||
svg_animated_string_attribute_getter(scope, args, rv, SVG_ELEMENT_CLASS_NAME_SLOT, "class");
|
||||
}
|
||||
|
||||
pub(super) fn svg_uri_href_getter<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
args: v8::FunctionCallbackArguments<'s>,
|
||||
rv: v8::ReturnValue<'_, v8::Value>,
|
||||
) {
|
||||
svg_animated_string_attribute_getter(scope, args, rv, SVG_URI_HREF_SLOT, "href");
|
||||
}
|
||||
|
||||
fn svg_animated_string_attribute_getter<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
args: v8::FunctionCallbackArguments<'s>,
|
||||
mut rv: v8::ReturnValue<'_, v8::Value>,
|
||||
slot: &str,
|
||||
attribute: &str,
|
||||
) {
|
||||
let owner = args.this();
|
||||
if let Some(value) = get_private_value(scope, owner, slot) {
|
||||
if let Ok(animated) = v8::Local::<v8::Object>::try_from(value) {
|
||||
sync_svg_animated_string_from_owner_attribute(scope, animated);
|
||||
}
|
||||
rv.set(value);
|
||||
return;
|
||||
}
|
||||
let value = build_svg_animated_string_for_attribute(scope, owner, attribute);
|
||||
set_private_value(scope, owner, slot, value.into());
|
||||
rv.set(value.into());
|
||||
}
|
||||
|
||||
pub(super) fn svg_rect_animated_length_getter<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
args: v8::FunctionCallbackArguments<'s>,
|
||||
@@ -282,6 +318,83 @@ pub(super) fn svg_text_positioning_list_getter<'s>(
|
||||
rv.set(value);
|
||||
}
|
||||
|
||||
pub(super) fn svg_animated_string_getter<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
args: v8::FunctionCallbackArguments<'s>,
|
||||
mut rv: v8::ReturnValue<'_, v8::Value>,
|
||||
) {
|
||||
let Some(name) = callback_data_item(
|
||||
scope,
|
||||
&args,
|
||||
SVG_ANIMATED_ACCESSOR_NAMES,
|
||||
"SVGAnimatedString attributes",
|
||||
) else {
|
||||
rv.set_undefined();
|
||||
return;
|
||||
};
|
||||
if !require_svg_receiver(
|
||||
scope,
|
||||
args.this(),
|
||||
SVG_ANIMATED_STRING_BASE_VAL_SLOT,
|
||||
"SVGAnimatedString",
|
||||
&format!("{name} getter"),
|
||||
) {
|
||||
return;
|
||||
}
|
||||
let slot = match name {
|
||||
"baseVal" => SVG_ANIMATED_STRING_BASE_VAL_SLOT,
|
||||
"animVal" => SVG_ANIMATED_STRING_ANIM_VAL_SLOT,
|
||||
_ => {
|
||||
rv.set_undefined();
|
||||
return;
|
||||
}
|
||||
};
|
||||
let animated = args.this();
|
||||
sync_svg_animated_string_from_owner_attribute(scope, animated);
|
||||
rv.set(
|
||||
get_private_value(scope, animated, slot).unwrap_or_else(|| v8::String::empty(scope).into()),
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn svg_animated_string_setter<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
args: v8::FunctionCallbackArguments<'s>,
|
||||
_rv: v8::ReturnValue<'_, v8::Value>,
|
||||
) {
|
||||
if !require_svg_receiver(
|
||||
scope,
|
||||
args.this(),
|
||||
SVG_ANIMATED_STRING_BASE_VAL_SLOT,
|
||||
"SVGAnimatedString",
|
||||
"baseVal setter",
|
||||
) {
|
||||
return;
|
||||
}
|
||||
let animated = args.this();
|
||||
let Some(owner) = get_private_value(scope, animated, SVG_ANIMATED_STRING_OWNER_ELEMENT_SLOT)
|
||||
.and_then(|value| v8::Local::<v8::Object>::try_from(value).ok())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let Some(attribute) =
|
||||
get_private_value(scope, animated, SVG_ANIMATED_STRING_OWNER_ATTRIBUTE_SLOT)
|
||||
.and_then(|value| value.to_string(scope))
|
||||
.map(|value| value.to_rust_string_lossy(scope))
|
||||
.filter(|value| !value.is_empty())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let Some(value) = crate::native_bridge::element::set_svg_animated_string_base_value(
|
||||
scope,
|
||||
owner,
|
||||
&attribute,
|
||||
args.get(0),
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
set_svg_animated_string_values(scope, animated, &value);
|
||||
}
|
||||
|
||||
pub(super) fn svg_animated_length_getter<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
args: v8::FunctionCallbackArguments<'s>,
|
||||
|
||||
@@ -18,6 +18,12 @@ const SVG_GRAPHICS_TRANSFORM_SLOT: &str = "__moliSvgGraphicsTransform";
|
||||
const SVG_PATTERN_TRANSFORM_SLOT: &str = "__moliSvgPatternTransform";
|
||||
const SVG_GRADIENT_TRANSFORM_SLOT: &str = "__moliSvgGradientTransform";
|
||||
const SVG_GEOMETRY_PATH_LENGTH_SLOT: &str = "__moliSvgGeometryPathLength";
|
||||
const SVG_ELEMENT_CLASS_NAME_SLOT: &str = "__moliSvgElementClassName";
|
||||
const SVG_URI_HREF_SLOT: &str = "__moliSvgUriHref";
|
||||
const SVG_ANIMATED_STRING_BASE_VAL_SLOT: &str = "__moliSvgAnimatedStringBaseVal";
|
||||
const SVG_ANIMATED_STRING_ANIM_VAL_SLOT: &str = "__moliSvgAnimatedStringAnimVal";
|
||||
const SVG_ANIMATED_STRING_OWNER_ELEMENT_SLOT: &str = "__moliSvgAnimatedStringOwnerElement";
|
||||
const SVG_ANIMATED_STRING_OWNER_ATTRIBUTE_SLOT: &str = "__moliSvgAnimatedStringOwnerAttribute";
|
||||
const SVG_ANIMATED_LENGTH_BASE_VAL_SLOT: &str = "__moliSvgAnimatedLengthBaseVal";
|
||||
const SVG_ANIMATED_LENGTH_ANIM_VAL_SLOT: &str = "__moliSvgAnimatedLengthAnimVal";
|
||||
const SVG_ANIMATED_LENGTH_LIST_BASE_VAL_SLOT: &str = "__moliSvgAnimatedLengthListBaseVal";
|
||||
@@ -246,6 +252,7 @@ pub(in crate::context_bootstrap) fn install_svg_template_bindings<'s>(
|
||||
"SVGLength" => bindings::install_svg_length_bindings(scope, template),
|
||||
"SVGNumber" => bindings::install_svg_number_bindings(scope, template),
|
||||
"SVGRect" => rect::install_bindings(scope, template),
|
||||
"SVGAnimatedString" => bindings::install_svg_animated_string_bindings(scope, template),
|
||||
"SVGAnimatedLength" => bindings::install_svg_animated_length_bindings(scope, template),
|
||||
"SVGLengthList" => bindings::install_svg_length_list_bindings(scope, template),
|
||||
"SVGAnimatedLengthList" => {
|
||||
|
||||
@@ -54,6 +54,7 @@ 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,
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ pub(in crate::native_bridge) enum TrustedAttributeSetter {
|
||||
SetAttributeNs,
|
||||
SetAttributeNode,
|
||||
AttrValue,
|
||||
SvgAnimatedStringBaseVal,
|
||||
}
|
||||
|
||||
impl TrustedAttributeSetter {
|
||||
@@ -16,6 +17,7 @@ impl TrustedAttributeSetter {
|
||||
Self::SetAttributeNs => "setAttributeNS",
|
||||
Self::SetAttributeNode => "setAttributeNode",
|
||||
Self::AttrValue => "value",
|
||||
Self::SvgAnimatedStringBaseVal => "baseVal",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +29,9 @@ impl TrustedAttributeSetter {
|
||||
crate::webidl::Context::argument("Element setAttributeNode", 1)
|
||||
}
|
||||
Self::AttrValue => crate::webidl::Context::member("Attr", "value"),
|
||||
Self::SvgAnimatedStringBaseVal => {
|
||||
crate::webidl::Context::member("SVGAnimatedString", "baseVal")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -276,6 +281,27 @@ pub(in crate::native_bridge) fn trusted_attribute_string_value<'s>(
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn set_svg_animated_string_base_value<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
owner: v8::Local<'s, v8::Object>,
|
||||
attribute: &str,
|
||||
value: v8::Local<'s, v8::Value>,
|
||||
) -> Option<String> {
|
||||
let (runtime_ptr, handle) =
|
||||
crate::native_bridge::node_runtime_and_handle_from_object(scope, owner).ok()?;
|
||||
let value = trusted_attribute_value_string(
|
||||
scope,
|
||||
Some((runtime_ptr, handle)),
|
||||
None,
|
||||
attribute,
|
||||
value,
|
||||
TrustedAttributeSetter::SvgAnimatedStringBaseVal,
|
||||
)?;
|
||||
let _ =
|
||||
unsafe { &mut *runtime_ptr }.set_attribute(scope, runtime_ptr, handle, attribute, &value);
|
||||
Some(value)
|
||||
}
|
||||
|
||||
pub(crate) fn trusted_script_source_for_execution(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
runtime_ptr: *mut JsContextHost,
|
||||
|
||||
@@ -1161,6 +1161,117 @@ fn url_attribute_writes_enforce_the_non_iframe_trusted_script_url_sink_table() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn svg_script_href_base_val_uses_the_owner_reflected_trusted_script_url_sink() {
|
||||
let mut vm = new_storage_test_vm("https://svg-script-href-trusted-types.test/");
|
||||
vm.set_response_content_security_policies(&["require-trusted-types-for 'script'".to_owned()]);
|
||||
|
||||
let result = vm
|
||||
.eval(
|
||||
r#"
|
||||
(() => {
|
||||
const violations = [];
|
||||
document.addEventListener("securitypolicyviolation", event => {
|
||||
violations.push({
|
||||
blockedURI: event.blockedURI,
|
||||
effectiveDirective: event.effectiveDirective,
|
||||
sample: event.sample
|
||||
});
|
||||
});
|
||||
globalThis.__svgScriptHrefViolations = violations;
|
||||
|
||||
const svgScript = document.createElementNS("http://www.w3.org/2000/svg", "script");
|
||||
const href = svgScript.href;
|
||||
let illegalConstructor = false;
|
||||
try {
|
||||
new SVGAnimatedString();
|
||||
} catch (error) {
|
||||
illegalConstructor = error instanceof TypeError;
|
||||
}
|
||||
let plainRejected = false;
|
||||
try {
|
||||
href.baseVal = "plain.js";
|
||||
} catch (error) {
|
||||
plainRejected = error instanceof TypeError;
|
||||
}
|
||||
const rejectedAttribute = svgScript.getAttribute("href");
|
||||
|
||||
const explicit = trustedTypes.createPolicy("svg-script-href", {
|
||||
createScriptURL: value => value
|
||||
});
|
||||
href.baseVal = explicit.createScriptURL("trusted.js");
|
||||
const trustedValues = [
|
||||
svgScript.getAttribute("href"),
|
||||
href.baseVal,
|
||||
href.animVal
|
||||
];
|
||||
svgScript.setAttribute("href", explicit.createScriptURL("attribute.js"));
|
||||
const externallySynced = [href.baseVal, href.animVal];
|
||||
const className = svgScript.className;
|
||||
className.baseVal = explicit.createScriptURL("trusted-class");
|
||||
const use = document.createElementNS("http://www.w3.org/2000/svg", "use");
|
||||
const useHref = use.href;
|
||||
useHref.baseVal = explicit.createScriptURL("trusted-use");
|
||||
|
||||
const defaultCalls = [];
|
||||
trustedTypes.createPolicy("default", {
|
||||
createScriptURL: (value, type, sink) => {
|
||||
defaultCalls.push([value, type, sink]);
|
||||
return `safe-${value}`;
|
||||
}
|
||||
});
|
||||
href.baseVal = "default-input";
|
||||
className.baseVal = "plain-class";
|
||||
useHref.baseVal = "plain-use";
|
||||
|
||||
return JSON.stringify({
|
||||
shape: [
|
||||
href instanceof SVGAnimatedString,
|
||||
Object.prototype.toString.call(href),
|
||||
svgScript.href === href,
|
||||
illegalConstructor
|
||||
],
|
||||
plainRejected,
|
||||
rejectedAttribute,
|
||||
trustedValues,
|
||||
externallySynced,
|
||||
ordinaryAnimatedStrings: [
|
||||
className instanceof SVGAnimatedString,
|
||||
svgScript.className === className,
|
||||
className.baseVal,
|
||||
className.animVal,
|
||||
svgScript.getAttribute("class"),
|
||||
useHref instanceof SVGAnimatedString,
|
||||
use.href === useHref,
|
||||
useHref.baseVal,
|
||||
useHref.animVal,
|
||||
use.getAttribute("href")
|
||||
],
|
||||
defaulted: [svgScript.getAttribute("href"), href.baseVal, href.animVal],
|
||||
defaultCalls,
|
||||
violations
|
||||
});
|
||||
})()
|
||||
"#,
|
||||
)
|
||||
.expect("SVGScriptElement href Trusted Types sink probe should evaluate");
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
r#"{"shape":[true,"[object SVGAnimatedString]",true,true],"plainRejected":true,"rejectedAttribute":null,"trustedValues":["trusted.js","trusted.js","trusted.js"],"externallySynced":["attribute.js","attribute.js"],"ordinaryAnimatedStrings":[true,true,"plain-class","plain-class","plain-class",true,true,"plain-use","plain-use","plain-use"],"defaulted":["safe-default-input","safe-default-input","safe-default-input"],"defaultCalls":[["default-input","TrustedScriptURL","SVGScriptElement href"]],"violations":[]}"#
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
drain_pre_domcontentloaded_non_script_page_tasks_for_test(&mut vm),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
vm.eval("JSON.stringify(globalThis.__svgScriptHrefViolations)")
|
||||
.expect("queued SVGScriptElement href violation should be observable"),
|
||||
r#"[{"blockedURI":"trusted-types-sink","effectiveDirective":"require-trusted-types-for","sample":"SVGScriptElement href|plain.js"}]"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn attached_attribute_mutations_recheck_trusted_types_after_domstring_conversion() {
|
||||
let mut vm = new_storage_test_vm("https://attached-attribute-trusted-types.test/");
|
||||
|
||||
Reference in New Issue
Block a user