Implement all trusted sinks in HTMLScriptElement (#36668)

As a follow-up to the recent introduction of `script.src`
as trusted sink, this PR refactors machinery to also
support `TrustedScript`. In doing so, all trusted sinks
in `HTMLScriptElement` are now covered.

Instead of calling the callbacks in `policy.createX`,
we now have a `TrustedType` enum that specifies which callback
to invoke. Unfortunately we still have the `USVString` vs
`DOMString` problem, which is why we need to `.map` twice
to retrieve the backing `String` and avoid two different
types.

Additionally, I saw that `script.text` should have called
the "String replace all" algorithm rather than setting the
child contents. So that's also now fixed.

Part of #36258
Requires servo/html5ever#608

Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>

Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
This commit is contained in:
Tim van der Lippe 2025-05-03 10:35:46 +02:00 committed by GitHub
parent dd63325f50
commit 4164f76769
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 320 additions and 353 deletions

View file

@ -149,7 +149,6 @@ use crate::dom::raredata::ElementRareData;
use crate::dom::servoparser::ServoParser;
use crate::dom::shadowroot::{IsUserAgentWidget, ShadowRoot};
use crate::dom::text::Text;
use crate::dom::types::TrustedTypePolicyFactory;
use crate::dom::validation::Validatable;
use crate::dom::validitystate::ValidationFlags;
use crate::dom::virtualmethods::{VirtualMethods, vtable_for};
@ -1961,35 +1960,6 @@ impl Element {
.unwrap_or_else(|_| TrustedScriptURLOrUSVString::USVString(USVString(value.to_owned())))
}
pub(crate) fn set_trusted_type_url_attribute(
&self,
local_name: &LocalName,
value: TrustedScriptURLOrUSVString,
can_gc: CanGc,
) -> Fallible<()> {
assert_eq!(*local_name, local_name.to_ascii_lowercase());
let value = match value {
TrustedScriptURLOrUSVString::USVString(url) => {
let global = self.owner_global();
// TODO(36258): Reflectively get the name of the class
let sink = format!("{} {}", "HTMLScriptElement", &local_name);
let result = TrustedTypePolicyFactory::get_trusted_type_compliant_string(
&global,
url.to_string(),
&sink,
"'script'",
can_gc,
);
result?
},
// This partially implements <https://w3c.github.io/trusted-types/dist/spec/#get-trusted-type-compliant-string-algorithm>
// Step 1: If input is an instance of expectedType, return stringified input and abort these steps.
TrustedScriptURLOrUSVString::TrustedScriptURL(script_url) => script_url.to_string(),
};
self.set_attribute(local_name, AttrValue::String(value), can_gc);
Ok(())
}
pub(crate) fn get_string_attribute(&self, local_name: &LocalName) -> DOMString {
match self.get_attribute(&ns!(), local_name) {
Some(x) => x.Value(),

View file

@ -116,7 +116,7 @@ impl HTMLElement {
/// `.outerText` in JavaScript.`
///
/// <https://html.spec.whatwg.org/multipage/#get-the-text-steps>
fn get_inner_outer_text(&self, can_gc: CanGc) -> DOMString {
pub(crate) fn get_inner_outer_text(&self, can_gc: CanGc) -> DOMString {
let node = self.upcast::<Node>();
let window = node.owner_window();
let element = self.as_element();
@ -134,6 +134,16 @@ impl HTMLElement {
DOMString::from(text)
}
/// <https://html.spec.whatwg.org/multipage/#set-the-inner-text-steps>
pub(crate) fn set_inner_text(&self, input: DOMString, can_gc: CanGc) {
// Step 1: Let fragment be the rendered text fragment for value given element's node
// document.
let fragment = self.rendered_text_fragment(input, can_gc);
// Step 2: Replace all with fragment within element.
Node::replace_all(Some(fragment.upcast()), self.upcast::<Node>(), can_gc);
}
}
impl HTMLElementMethods<crate::DomTypeHolder> for HTMLElement {
@ -494,12 +504,7 @@ impl HTMLElementMethods<crate::DomTypeHolder> for HTMLElement {
/// <https://html.spec.whatwg.org/multipage/#set-the-inner-text-steps>
fn SetInnerText(&self, input: DOMString, can_gc: CanGc) {
// Step 1: Let fragment be the rendered text fragment for value given element's node
// document.
let fragment = self.rendered_text_fragment(input, can_gc);
// Step 2: Replace all with fragment within element.
Node::replace_all(Some(fragment.upcast()), self.upcast::<Node>(), can_gc);
self.set_inner_text(input, can_gc)
}
/// <https://html.spec.whatwg.org/multipage/#dom-outertext>

View file

@ -32,6 +32,7 @@ use net_traits::{
};
use servo_config::pref;
use servo_url::{ImmutableOrigin, ServoUrl};
use style::attr::AttrValue;
use style::str::{HTML_SPACE_CHARACTERS, StaticStringVec};
use stylo_atoms::Atom;
use uuid::Uuid;
@ -44,7 +45,9 @@ use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use crate::dom::bindings::codegen::Bindings::HTMLScriptElementBinding::HTMLScriptElementMethods;
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use crate::dom::bindings::codegen::GenericBindings::HTMLElementBinding::HTMLElement_Binding::HTMLElementMethods;
use crate::dom::bindings::codegen::UnionTypes::TrustedScriptURLOrUSVString;
use crate::dom::bindings::codegen::UnionTypes::{
TrustedScriptOrString, TrustedScriptURLOrUSVString,
};
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::Trusted;
@ -64,6 +67,8 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlelement::HTMLElement;
use crate::dom::node::{ChildrenMutation, CloneChildrenFlag, Node, NodeTraits};
use crate::dom::performanceresourcetiming::InitiatorType;
use crate::dom::trustedscript::TrustedScript;
use crate::dom::trustedscripturl::TrustedScriptURL;
use crate::dom::virtualmethods::VirtualMethods;
use crate::fetch::create_a_potential_cors_request;
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
@ -667,7 +672,7 @@ impl HTMLScriptElement {
// Step 5. Let source text be el's child text content.
// Step 6. If el has no src attribute, and source text is the empty string, then return.
let text = self.Text();
let text = self.text();
if text.is_empty() && !element.has_attribute(&local_name!("src")) {
return;
}
@ -1272,6 +1277,15 @@ impl HTMLScriptElement {
let event = Event::new(window.upcast(), type_, bubbles, cancelable, can_gc);
event.fire(self.upcast(), can_gc)
}
fn text(&self) -> DOMString {
match self.Text() {
TrustedScriptOrString::String(value) => value,
TrustedScriptOrString::TrustedScript(trusted_script) => {
DOMString::from(trusted_script.to_string())
},
}
}
}
impl VirtualMethods for HTMLScriptElement {
@ -1286,7 +1300,7 @@ impl VirtualMethods for HTMLScriptElement {
if *attr.local_name() == local_name!("src") {
if let AttributeMutation::Set(_) = mutation {
if !self.parser_inserted.get() && self.upcast::<Node>().is_connected() {
self.prepare(CanGc::note());
self.prepare(can_gc);
}
}
}
@ -1344,10 +1358,25 @@ impl VirtualMethods for HTMLScriptElement {
impl HTMLScriptElementMethods<crate::DomTypeHolder> for HTMLScriptElement {
// https://html.spec.whatwg.org/multipage/#dom-script-src
make_trusted_type_url_getter!(Src, "src");
fn Src(&self) -> TrustedScriptURLOrUSVString {
let element = self.upcast::<Element>();
element.get_trusted_type_url_attribute(&local_name!("src"))
}
// https://html.spec.whatwg.org/multipage/#dom-script-src
make_trusted_type_url_setter!(SetSrc, "src");
/// <https://w3c.github.io/trusted-types/dist/spec/#the-src-idl-attribute>
fn SetSrc(&self, value: TrustedScriptURLOrUSVString, can_gc: CanGc) -> Fallible<()> {
let element = self.upcast::<Element>();
let local_name = &local_name!("src");
let value = TrustedScriptURL::get_trusted_script_url_compliant_string(
&element.owner_global(),
value,
"HTMLScriptElement",
local_name,
can_gc,
)?;
element.set_attribute(local_name, AttrValue::String(value), can_gc);
Ok(())
}
// https://html.spec.whatwg.org/multipage/#dom-script-type
make_getter!(Type, "type");
@ -1416,14 +1445,77 @@ impl HTMLScriptElementMethods<crate::DomTypeHolder> for HTMLScriptElement {
// https://html.spec.whatwg.org/multipage/#dom-script-referrerpolicy
make_setter!(SetReferrerPolicy, "referrerpolicy");
// https://html.spec.whatwg.org/multipage/#dom-script-text
fn Text(&self) -> DOMString {
self.upcast::<Node>().child_text_content()
/// <https://w3c.github.io/trusted-types/dist/spec/#dom-htmlscriptelement-innertext>
fn InnerText(&self, can_gc: CanGc) -> TrustedScriptOrString {
// Step 1: Return the result of running get the text steps with this.
TrustedScriptOrString::String(self.upcast::<HTMLElement>().get_inner_outer_text(can_gc))
}
// https://html.spec.whatwg.org/multipage/#dom-script-text
fn SetText(&self, value: DOMString, can_gc: CanGc) {
self.upcast::<Node>().SetTextContent(Some(value), can_gc)
/// <https://w3c.github.io/trusted-types/dist/spec/#the-innerText-idl-attribute>
fn SetInnerText(&self, input: TrustedScriptOrString, can_gc: CanGc) -> Fallible<()> {
// Step 1: Let value be the result of calling Get Trusted Type compliant string with TrustedScript,
// this's relevant global object, the given value, HTMLScriptElement innerText, and script.
let value = TrustedScript::get_trusted_script_compliant_string(
&self.owner_global(),
input,
"HTMLScriptElement",
"innerText",
can_gc,
)?;
// Step 3: Run set the inner text steps with this and value.
self.upcast::<HTMLElement>()
.set_inner_text(DOMString::from(value), can_gc);
Ok(())
}
/// <https://html.spec.whatwg.org/multipage/#dom-script-text>
fn Text(&self) -> TrustedScriptOrString {
TrustedScriptOrString::String(self.upcast::<Node>().child_text_content())
}
/// <https://w3c.github.io/trusted-types/dist/spec/#the-text-idl-attribute>
fn SetText(&self, value: TrustedScriptOrString, can_gc: CanGc) -> Fallible<()> {
// Step 1: Let value be the result of calling Get Trusted Type compliant string with TrustedScript,
// this's relevant global object, the given value, HTMLScriptElement text, and script.
let value = TrustedScript::get_trusted_script_compliant_string(
&self.owner_global(),
value,
"HTMLScriptElement",
"text",
can_gc,
)?;
// Step 2: Set this's script text value to the given value.
// TODO: Implement for https://w3c.github.io/trusted-types/dist/spec/#prepare-script-text
// Step 3: String replace all with the given value within this.
Node::string_replace_all(DOMString::from(value), self.upcast::<Node>(), can_gc);
Ok(())
}
/// <https://w3c.github.io/trusted-types/dist/spec/#the-textContent-idl-attribute>
fn GetTextContent(&self) -> Option<TrustedScriptOrString> {
// Step 1: Return the result of running get text content with this.
Some(TrustedScriptOrString::String(
self.upcast::<Node>().GetTextContent()?,
))
}
/// <https://w3c.github.io/trusted-types/dist/spec/#the-textContent-idl-attribute>
fn SetTextContent(&self, value: Option<TrustedScriptOrString>, can_gc: CanGc) -> Fallible<()> {
// Step 1: Let value be the result of calling Get Trusted Type compliant string with TrustedScript,
// this's relevant global object, the given value, HTMLScriptElement textContent, and script.
let value = TrustedScript::get_trusted_script_compliant_string(
&self.owner_global(),
value.unwrap_or(TrustedScriptOrString::String(DOMString::from(""))),
"HTMLScriptElement",
"textContent",
can_gc,
)?;
// Step 2: Set this's script text value to value.
// TODO: Implement for https://w3c.github.io/trusted-types/dist/spec/#prepare-script-text
// Step 3: Run set text content with this and value.
self.upcast::<Node>()
.SetTextContent(Some(DOMString::from(value)), can_gc);
Ok(())
}
}

View file

@ -121,32 +121,6 @@ macro_rules! make_url_setter(
);
);
#[macro_export]
macro_rules! make_trusted_type_url_getter(
( $attr:ident, $htmlname:tt ) => (
fn $attr(&self) -> TrustedScriptURLOrUSVString {
use $crate::dom::bindings::inheritance::Castable;
use $crate::dom::element::Element;
let element = self.upcast::<Element>();
element.get_trusted_type_url_attribute(&html5ever::local_name!($htmlname))
}
);
);
#[macro_export]
macro_rules! make_trusted_type_url_setter(
( $attr:ident, $htmlname:tt ) => (
fn $attr(&self, value: TrustedScriptURLOrUSVString, can_gc: CanGc) -> Fallible<()> {
use $crate::dom::bindings::inheritance::Castable;
use $crate::dom::element::Element;
use $crate::script_runtime::CanGc;
let element = self.upcast::<Element>();
element.set_trusted_type_url_attribute(&html5ever::local_name!($htmlname),
value, can_gc)
}
);
);
#[macro_export]
macro_rules! make_form_action_getter(
( $attr:ident, $htmlname:tt ) => (

View file

@ -1,14 +1,19 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::fmt;
use dom_struct::dom_struct;
use crate::dom::bindings::codegen::Bindings::TrustedScriptBinding::TrustedScriptMethods;
use crate::dom::bindings::codegen::UnionTypes::TrustedScriptOrString;
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
use crate::dom::trustedtypepolicy::TrustedType;
use crate::dom::trustedtypepolicyfactory::TrustedTypePolicyFactory;
use crate::script_runtime::CanGc;
#[dom_struct]
@ -30,6 +35,37 @@ impl TrustedScript {
pub(crate) fn new(data: String, global: &GlobalScope, can_gc: CanGc) -> DomRoot<Self> {
reflect_dom_object(Box::new(Self::new_inherited(data)), global, can_gc)
}
pub(crate) fn get_trusted_script_compliant_string(
global: &GlobalScope,
value: TrustedScriptOrString,
containing_class: &str,
field: &str,
can_gc: CanGc,
) -> Fallible<String> {
match value {
TrustedScriptOrString::String(value) => {
let sink = format!("{} {}", containing_class, field);
TrustedTypePolicyFactory::get_trusted_type_compliant_string(
TrustedType::TrustedScript,
global,
value.as_ref().to_owned(),
&sink,
"'script'",
can_gc,
)
},
TrustedScriptOrString::TrustedScript(trusted_script) => Ok(trusted_script.to_string()),
}
}
}
impl fmt::Display for TrustedScript {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.data)
}
}
impl TrustedScriptMethods<crate::DomTypeHolder> for TrustedScript {

View file

@ -7,10 +7,14 @@ use std::fmt;
use dom_struct::dom_struct;
use crate::dom::bindings::codegen::Bindings::TrustedScriptURLBinding::TrustedScriptURLMethods;
use crate::dom::bindings::codegen::UnionTypes::TrustedScriptURLOrUSVString;
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
use crate::dom::trustedtypepolicy::TrustedType;
use crate::dom::trustedtypepolicyfactory::TrustedTypePolicyFactory;
use crate::script_runtime::CanGc;
#[dom_struct]
@ -32,6 +36,31 @@ impl TrustedScriptURL {
pub(crate) fn new(data: String, global: &GlobalScope, can_gc: CanGc) -> DomRoot<Self> {
reflect_dom_object(Box::new(Self::new_inherited(data)), global, can_gc)
}
pub(crate) fn get_trusted_script_url_compliant_string(
global: &GlobalScope,
value: TrustedScriptURLOrUSVString,
containing_class: &str,
field: &str,
can_gc: CanGc,
) -> Fallible<String> {
match value {
TrustedScriptURLOrUSVString::USVString(value) => {
let sink = format!("{} {}", containing_class, field);
TrustedTypePolicyFactory::get_trusted_type_compliant_string(
TrustedType::TrustedScriptURL,
global,
value.as_ref().to_owned(),
&sink,
"'script'",
can_gc,
)
},
TrustedScriptURLOrUSVString::TrustedScriptURL(trusted_script_url) => {
Ok(trusted_script_url.to_string())
},
}
}
}
impl fmt::Display for TrustedScriptURL {

View file

@ -7,6 +7,7 @@ use std::rc::Rc;
use dom_struct::dom_struct;
use js::jsapi::JSObject;
use js::rust::HandleValue;
use strum_macros::IntoStaticStr;
use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::codegen::Bindings::TrustedTypePolicyBinding::TrustedTypePolicyMethods;
@ -38,6 +39,13 @@ pub struct TrustedTypePolicy {
create_script_url: Option<Rc<CreateScriptURLCallback>>,
}
#[derive(Clone, IntoStaticStr)]
pub(crate) enum TrustedType {
TrustedHTML,
TrustedScript,
TrustedScriptURL,
}
impl TrustedTypePolicy {
fn new_inherited(name: String, options: &TrustedTypePolicyOptions) -> Self {
Self {
@ -59,51 +67,87 @@ impl TrustedTypePolicy {
reflect_dom_object(Box::new(Self::new_inherited(name, options)), global, can_gc)
}
// TODO(36258): Remove when we refactor get_trusted_type_policy_value to take an enum
// value to handle which callback to call. The callback should not be exposed outside
// of the policy object, but is currently used in TrustedPolicyFactory::process_value_with_default_policy
pub(crate) fn create_script_url(&self) -> Option<Rc<CreateScriptURLCallback>> {
self.create_script_url.clone()
/// <https://w3c.github.io/trusted-types/dist/spec/#get-trusted-type-policy-value-algorithm>
fn check_callback_if_missing(throw_if_missing: bool) -> Fallible<Option<String>> {
// Step 3.1: If throwIfMissing throw a TypeError.
if throw_if_missing {
Err(Type("Cannot find type".to_owned()))
} else {
// Step 3.2: Else return null.
Ok(None)
}
}
/// This does not take all arguments as specified. That's because the return type of the
/// trusted type function and object are not the same. 2 of the 3 string callbacks return
/// a DOMString, while the other one returns an USVString. Additionally, all three callbacks
/// have a unique type signature in WebIDL.
///
/// To circumvent these type problems, rather than implementing the full functionality here,
/// part of the algorithm is implemented on the caller side. There, we only call the callback
/// and create the object. The rest of the machinery is ensuring the right values pass through
/// to the relevant callbacks.
///
/// <https://w3c.github.io/trusted-types/dist/spec/#get-trusted-type-policy-value-algorithm>
pub(crate) fn get_trusted_type_policy_value<S, PolicyCallback>(
pub(crate) fn get_trusted_type_policy_value(
&self,
policy_value_callback: PolicyCallback,
expected_type: TrustedType,
cx: JSContext,
input: DOMString,
arguments: Vec<HandleValue>,
throw_if_missing: bool,
) -> Fallible<Option<S>>
where
S: AsRef<str>,
PolicyCallback: FnOnce() -> Option<Fallible<Option<S>>>,
{
can_gc: CanGc,
) -> Fallible<Option<String>> {
rooted!(in(*cx) let this_object: *mut JSObject);
// Step 1: Let functionName be a function name for the given trustedTypeName, based on the following table:
// Step 2: Let function be policys options[functionName].
let function = policy_value_callback();
match function {
// Step 3: If function is null, then:
None => {
// Step 3.1: If throwIfMissing throw a TypeError.
if throw_if_missing {
Err(Type("Cannot find type".to_owned()))
} else {
// Step 3.2: Else return null.
Ok(None)
}
match expected_type {
TrustedType::TrustedHTML => match &self.create_html {
// Step 3: If function is null, then:
None => TrustedTypePolicy::check_callback_if_missing(throw_if_missing),
// Step 2: Let function be policys options[functionName].
Some(callback) => {
// Step 4: Let policyValue be the result of invoking function with value as a first argument,
// items of arguments as subsequent arguments, and callback **this** value set to null,
// rethrowing any exceptions.
callback
.Call_(
&this_object.handle(),
input,
arguments,
ExceptionHandling::Rethrow,
can_gc,
)
.map(|result| result.map(|str| str.as_ref().to_owned()))
},
},
TrustedType::TrustedScript => match &self.create_script {
// Step 3: If function is null, then:
None => TrustedTypePolicy::check_callback_if_missing(throw_if_missing),
// Step 2: Let function be policys options[functionName].
Some(callback) => {
// Step 4: Let policyValue be the result of invoking function with value as a first argument,
// items of arguments as subsequent arguments, and callback **this** value set to null,
// rethrowing any exceptions.
callback
.Call_(
&this_object.handle(),
input,
arguments,
ExceptionHandling::Rethrow,
can_gc,
)
.map(|result| result.map(|str| str.as_ref().to_owned()))
},
},
TrustedType::TrustedScriptURL => match &self.create_script_url {
// Step 3: If function is null, then:
None => TrustedTypePolicy::check_callback_if_missing(throw_if_missing),
// Step 2: Let function be policys options[functionName].
Some(callback) => {
// Step 4: Let policyValue be the result of invoking function with value as a first argument,
// items of arguments as subsequent arguments, and callback **this** value set to null,
// rethrowing any exceptions.
callback
.Call_(
&this_object.handle(),
input,
arguments,
ExceptionHandling::Rethrow,
can_gc,
)
.map(|result| result.map(|str| str.as_ref().to_owned()))
},
},
// Step 4: Let policyValue be the result of invoking function with value as a first argument,
// items of arguments as subsequent arguments, and callback **this** value set to null,
// rethrowing any exceptions.
Some(policy_value) => policy_value,
}
}
@ -118,27 +162,30 @@ impl TrustedTypePolicy {
/// to the relevant callbacks.
///
/// <https://w3c.github.io/trusted-types/dist/spec/#create-a-trusted-type-algorithm>
pub(crate) fn create_trusted_type<R, S, PolicyCallback, TrustedTypeCallback>(
pub(crate) fn create_trusted_type<R, TrustedTypeCallback>(
&self,
policy_value_callback: PolicyCallback,
expected_type: TrustedType,
cx: JSContext,
input: DOMString,
arguments: Vec<HandleValue>,
trusted_type_creation_callback: TrustedTypeCallback,
can_gc: CanGc,
) -> Fallible<DomRoot<R>>
where
R: DomObject,
S: AsRef<str>,
PolicyCallback: FnOnce() -> Option<Fallible<Option<S>>>,
TrustedTypeCallback: FnOnce(String) -> DomRoot<R>,
{
// Step 1: Let policyValue be the result of executing Get Trusted Type policy value
// with the same arguments as this algorithm and additionally true as throwIfMissing.
let policy_value = self.get_trusted_type_policy_value(policy_value_callback, true);
let policy_value =
self.get_trusted_type_policy_value(expected_type, cx, input, arguments, true, can_gc);
match policy_value {
// Step 2: If the algorithm threw an error, rethrow the error and abort the following steps.
Err(error) => Err(error),
Ok(policy_value) => {
// Step 3: Let dataString be the result of stringifying policyValue.
let data_string = match policy_value {
Some(value) => value.as_ref().into(),
Some(value) => value,
// Step 4: If policyValue is null or undefined, set dataString to the empty string.
None => "".to_owned(),
};
@ -164,22 +211,12 @@ impl TrustedTypePolicyMethods<crate::DomTypeHolder> for TrustedTypePolicy {
can_gc: CanGc,
) -> Fallible<DomRoot<TrustedHTML>> {
self.create_trusted_type(
|| {
self.create_html.clone().map(|callback| {
rooted!(in(*cx) let this_object: *mut JSObject);
// Step 4: Let policyValue be the result of invoking function with value as a first argument,
// items of arguments as subsequent arguments, and callback **this** value set to null,
// rethrowing any exceptions.
callback.Call_(
&this_object.handle(),
input,
arguments,
ExceptionHandling::Rethrow,
can_gc,
)
})
},
TrustedType::TrustedHTML,
cx,
input,
arguments,
|data_string| TrustedHTML::new(data_string, &self.global(), can_gc),
can_gc,
)
}
/// <https://www.w3.org/TR/trusted-types/#dom-trustedtypepolicy-createscript>
@ -191,22 +228,12 @@ impl TrustedTypePolicyMethods<crate::DomTypeHolder> for TrustedTypePolicy {
can_gc: CanGc,
) -> Fallible<DomRoot<TrustedScript>> {
self.create_trusted_type(
|| {
self.create_script.clone().map(|callback| {
rooted!(in(*cx) let this_object: *mut JSObject);
// Step 4: Let policyValue be the result of invoking function with value as a first argument,
// items of arguments as subsequent arguments, and callback **this** value set to null,
// rethrowing any exceptions.
callback.Call_(
&this_object.handle(),
input,
arguments,
ExceptionHandling::Rethrow,
can_gc,
)
})
},
TrustedType::TrustedScript,
cx,
input,
arguments,
|data_string| TrustedScript::new(data_string, &self.global(), can_gc),
can_gc,
)
}
/// <https://www.w3.org/TR/trusted-types/#dom-trustedtypepolicy-createscripturl>
@ -218,22 +245,12 @@ impl TrustedTypePolicyMethods<crate::DomTypeHolder> for TrustedTypePolicy {
can_gc: CanGc,
) -> Fallible<DomRoot<TrustedScriptURL>> {
self.create_trusted_type(
|| {
self.create_script_url.clone().map(|callback| {
rooted!(in(*cx) let this_object: *mut JSObject);
// Step 4: Let policyValue be the result of invoking function with value as a first argument,
// items of arguments as subsequent arguments, and callback **this** value set to null,
// rethrowing any exceptions.
callback.Call_(
&this_object.handle(),
input,
arguments,
ExceptionHandling::Rethrow,
can_gc,
)
})
},
TrustedType::TrustedScriptURL,
cx,
input,
arguments,
|data_string| TrustedScriptURL::new(data_string, &self.global(), can_gc),
can_gc,
)
}
}

View file

@ -6,11 +6,9 @@ use std::cell::RefCell;
use content_security_policy::CheckResult;
use dom_struct::dom_struct;
use html5ever::{LocalName, Namespace, QualName, local_name, ns};
use js::jsapi::JSObject;
use js::jsval::NullValue;
use js::rust::HandleValue;
use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::codegen::Bindings::TrustedTypePolicyFactoryBinding::{
TrustedTypePolicyFactoryMethods, TrustedTypePolicyOptions,
};
@ -23,7 +21,7 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::trustedhtml::TrustedHTML;
use crate::dom::trustedscript::TrustedScript;
use crate::dom::trustedscripturl::TrustedScriptURL;
use crate::dom::trustedtypepolicy::TrustedTypePolicy;
use crate::dom::trustedtypepolicy::{TrustedType, TrustedTypePolicy};
use crate::js::conversions::ToJSValConvertible;
use crate::script_runtime::{CanGc, JSContext};
@ -144,50 +142,40 @@ impl TrustedTypePolicyFactory {
/// <https://w3c.github.io/trusted-types/dist/spec/#process-value-with-a-default-policy-algorithm>
#[allow(unsafe_code)]
pub(crate) fn process_value_with_default_policy(
expected_type: TrustedType,
global: &GlobalScope,
input: String,
sink: &str,
can_gc: CanGc,
) -> Fallible<Option<DomRoot<TrustedScriptURL>>> {
) -> Fallible<Option<String>> {
// Step 1: Let defaultPolicy be the value of globals trusted type policy factory's default policy.
let global_policy_factory = global.trusted_types(can_gc);
let default_policy = match global_policy_factory.default_policy.get() {
None => return Ok(Some(TrustedScriptURL::new(input, global, can_gc))),
None => return Ok(None),
Some(default_policy) => default_policy,
};
let cx = GlobalScope::get_cx();
// Step 2: Let policyValue be the result of executing Get Trusted Type policy value,
// with the following arguments:
rooted!(in(*cx) let mut trusted_type_name_value = NullValue());
unsafe {
let trusted_type_name: &'static str = expected_type.clone().into();
trusted_type_name.to_jsval(*cx, trusted_type_name_value.handle_mut());
}
rooted!(in(*cx) let mut sink_value = NullValue());
unsafe {
sink.to_jsval(*cx, sink_value.handle_mut());
}
let arguments = vec![trusted_type_name_value.handle(), sink_value.handle()];
let policy_value = default_policy.get_trusted_type_policy_value(
|| {
// TODO(36258): support other trusted types as well by changing get_trusted_type_policy_value to accept
// the trusted type as enum and call the appropriate callback based on that.
default_policy.create_script_url().map(|callback| {
rooted!(in(*cx) let this_object: *mut JSObject);
rooted!(in(*cx) let mut trusted_type_name_value = NullValue());
unsafe {
"TrustedScriptURL".to_jsval(*cx, trusted_type_name_value.handle_mut());
}
rooted!(in(*cx) let mut sink_value = NullValue());
unsafe {
sink.to_jsval(*cx, sink_value.handle_mut());
}
let args = vec![trusted_type_name_value.handle(), sink_value.handle()];
// Step 4: Let policyValue be the result of invoking function with value as a first argument,
// items of arguments as subsequent arguments, and callback **this** value set to null,
// rethrowing any exceptions.
callback.Call_(
&this_object.handle(),
DOMString::from(input.to_owned()),
args,
ExceptionHandling::Rethrow,
can_gc,
)
})
},
expected_type,
cx,
DOMString::from(input.to_owned()),
arguments,
false,
can_gc,
);
let data_string = match policy_value {
// Step 3: If the algorithm threw an error, rethrow the error and abort the following steps.
@ -196,14 +184,15 @@ impl TrustedTypePolicyFactory {
// Step 4: If policyValue is null or undefined, return policyValue.
None => return Ok(None),
// Step 5: Let dataString be the result of stringifying policyValue.
Some(policy_value) => policy_value.as_ref().into(),
Some(policy_value) => policy_value,
},
};
Ok(Some(TrustedScriptURL::new(data_string, global, can_gc)))
Ok(Some(data_string))
}
/// Step 1 is implemented by the caller
/// <https://w3c.github.io/trusted-types/dist/spec/#get-trusted-type-compliant-string-algorithm>
pub(crate) fn get_trusted_type_compliant_string(
expected_type: TrustedType,
global: &GlobalScope,
input: String,
sink: &str,
@ -224,6 +213,7 @@ impl TrustedTypePolicyFactory {
// Step 4: Let convertedInput be the result of executing Process value with a default policy
// with the same arguments as this algorithm.
let converted_input = TrustedTypePolicyFactory::process_value_with_default_policy(
expected_type,
global,
input.clone(),
sink,
@ -252,7 +242,7 @@ impl TrustedTypePolicyFactory {
}
},
// Step 8: Return stringified convertedInput.
Some(converted_input) => Ok((*converted_input).to_string()),
Some(converted_input) => Ok(converted_input),
}
// Step 7: Assert: convertedInput is an instance of expectedType.
// TODO(https://github.com/w3c/trusted-types/issues/566): Implement when spec is resolved

View file

@ -416,7 +416,7 @@ DOMInterfaces = {
},
'HTMLScriptElement': {
'canGc': ['SetAsync', 'SetCrossOrigin', 'SetSrc', 'SetText']
'canGc': ['InnerText', 'SetAsync', 'SetCrossOrigin', 'SetInnerText', 'SetSrc', 'SetText', 'SetTextContent']
},
'HTMLSelectElement': {

View file

@ -21,8 +21,12 @@ interface HTMLScriptElement : HTMLElement {
attribute boolean defer;
[CEReactions]
attribute DOMString? crossOrigin;
[CEReactions, Pure]
attribute DOMString text;
[CEReactions, SetterThrows]
attribute (TrustedScript or DOMString) innerText;
[CEReactions, Pure, SetterThrows]
attribute (TrustedScript or DOMString) text;
[CEReactions, SetterThrows]
attribute (TrustedScript or DOMString)? textContent;
[CEReactions]
attribute DOMString integrity;
[CEReactions]

View file

@ -1,10 +1,4 @@
[HTMLElement-generic.html]
[TT enabled: script.src\n = String on a\n connected element\n ]
expected: FAIL
[TT enabled: script.src\n = String on a\n non-connected element\n ]
expected: FAIL
[TT enabled: div.innerHTML\n = String on a\n connected element\n ]
expected: FAIL
@ -17,30 +11,6 @@
[TT enabled: iframe.srcdoc\n = String on a\n non-connected element\n ]
expected: FAIL
[TT enabled: script.text\n = String on a\n connected element\n ]
expected: FAIL
[TT enabled: script.text\n = String on a\n non-connected element\n ]
expected: FAIL
[TT enabled: script.innerText\n = String on a\n connected element\n ]
expected: FAIL
[TT enabled: script.innerText\n = String on a\n non-connected element\n ]
expected: FAIL
[TT enabled: script.textContent\n = String on a\n connected element\n ]
expected: FAIL
[TT enabled: script.textContent\n = String on a\n non-connected element\n ]
expected: FAIL
[TT enabled: script.src\n = String on a\n connected element\n after removing the "require-trusted-types-for 'script' directive]
expected: FAIL
[TT enabled: script.src\n = String on a\n non-connected element\n after removing the "require-trusted-types-for 'script' directive]
expected: FAIL
[TT enabled: div.innerHTML\n = String on a\n connected element\n after removing the "require-trusted-types-for 'script' directive]
expected: FAIL
@ -52,33 +22,3 @@
[TT enabled: iframe.srcdoc\n = String on a\n non-connected element\n after removing the "require-trusted-types-for 'script' directive]
expected: FAIL
[TT enabled: script.text\n = String on a\n connected element\n after removing the "require-trusted-types-for 'script' directive]
expected: FAIL
[TT enabled: script.text\n = String on a\n non-connected element\n after removing the "require-trusted-types-for 'script' directive]
expected: FAIL
[TT enabled: script.innerText\n = String on a\n connected element\n after removing the "require-trusted-types-for 'script' directive]
expected: FAIL
[TT enabled: script.innerText\n = String on a\n non-connected element\n after removing the "require-trusted-types-for 'script' directive]
expected: FAIL
[TT enabled: script.textContent\n = String on a\n connected element\n after removing the "require-trusted-types-for 'script' directive]
expected: FAIL
[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

View file

@ -1,7 +1,4 @@
[block-string-assignment-to-HTMLElement-generic.html]
[script.src accepts only TrustedScriptURL]
expected: FAIL
[div.innerHTML accepts only TrustedHTML]
expected: FAIL
@ -13,12 +10,3 @@
[iframe.srcdoc accepts string and null after default policy was created]
expected: FAIL
[script.text accepts only TrustedScript]
expected: FAIL
[script.innerText accepts only TrustedScript]
expected: FAIL
[script.textContent accepts only TrustedScript]
expected: FAIL

View file

@ -7,12 +7,3 @@
[Setting SVGScriptElement.innerHTML to a plain string]
expected: FAIL
[Setting HTMLScriptElement.innerText to a plain string]
expected: FAIL
[Setting HTMLScriptElement.textContent to a plain string]
expected: FAIL
[Setting HTMLScriptElement.text to a plain string]
expected: FAIL

View file

@ -3,15 +3,9 @@
[Count SecurityPolicyViolation events.]
expected: TIMEOUT
[script.src no default policy]
expected: FAIL
[div.innerHTML no default policy]
expected: FAIL
[script.text no default policy]
expected: FAIL
[div.innerHTML default]
expected: FAIL
@ -26,18 +20,3 @@
[div.innerHTML typeerror]
expected: FAIL
[script.text default]
expected: FAIL
[script.text null]
expected: FAIL
[script.text throw]
expected: FAIL
[script.text undefined]
expected: FAIL
[script.text typeerror]
expected: FAIL

View file

@ -5,6 +5,3 @@
[div.innerHTML default]
expected: FAIL
[script.text default]
expected: FAIL

View file

@ -1,9 +1,3 @@
[require-trusted-types-for-report-only.html]
[Require trusted types for 'script' block create HTML.]
expected: FAIL
[Require trusted types for 'script' block create script.]
expected: FAIL
[Require trusted types for 'script' block create script URL.]
expected: FAIL

View file

@ -1,9 +1,3 @@
[require-trusted-types-for.html]
[Require trusted types for 'script' block create HTML.]
expected: FAIL
[Require trusted types for 'script' block create script.]
expected: FAIL
[Require trusted types for 'script' block create script URL.]
expected: FAIL

View file

@ -1,25 +1,13 @@
[trusted-types-createHTMLDocument.html]
[Trusted Type assignment is blocked. (document)]
expected: FAIL
[Trusted Type instances created in the main doc can be used. (document)]
expected: FAIL
[Trusted Type assignment is blocked. (createHTMLDocument)]
expected: FAIL
[Trusted Type instances created in the main doc can be used. (createHTMLDocument)]
expected: FAIL
[Trusted Type assignment is blocked. (DOMParser)]
expected: FAIL
[Trusted Type instances created in the main doc can be used. (DOMParser)]
expected: FAIL
[Trusted Type assignment is blocked. (XHR)]
expected: FAIL
[Trusted Type instances created in the main doc can be used. (XHR)]
expected: FAIL

View file

@ -1,15 +1,6 @@
[trusted-types-report-only.html]
[Trusted Type violation report-only: assign string to script url]
expected: FAIL
[Trusted Type violation report-only: assign string to html]
expected: FAIL
[Trusted Type violation report-only: assign string to script.src]
expected: FAIL
[Trusted Type violation report-only: assign string to script content]
expected: FAIL
[Trusted Type violation report: check report contents]
expected: FAIL

View file

@ -1,12 +0,0 @@
[trusted-types-reporting-for-HTMLScriptElement.html]
[Violation report for plain string (innerText)]
expected: FAIL
[Violation report for plain string (textContent)]
expected: FAIL
[Violation report for plain string (src)]
expected: FAIL
[Violation report for plain string (text)]
expected: FAIL