Implement script prepare text for Trusted Types (#37466)

Recently added WPT tests for this are now mostly passing. The remaining
tests fail on importmap support.

Part of #36258

Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
This commit is contained in:
Tim van der Lippe 2025-06-15 00:33:25 +02:00 committed by GitHub
parent f963f2731d
commit c74a422e4c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 46 additions and 221 deletions

View file

@ -41,6 +41,7 @@ use crate::HasParent;
use crate::document_loader::LoadType;
use crate::dom::activation::Activatable;
use crate::dom::attr::Attr;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use crate::dom::bindings::codegen::Bindings::HTMLScriptElementBinding::HTMLScriptElementMethods;
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
@ -207,6 +208,9 @@ pub(crate) struct HTMLScriptElement {
/// Unique id for each script element
#[ignore_malloc_size_of = "Defined in uuid"]
id: ScriptId,
/// <https://w3c.github.io/trusted-types/dist/spec/#htmlscriptelement-script-text>
script_text: DomRefCell<DOMString>,
}
impl HTMLScriptElement {
@ -225,6 +229,7 @@ impl HTMLScriptElement {
parser_document: Dom::from_ref(document),
preparation_time_document: MutNullableDom::new(None),
line_number: creator.return_line_number(),
script_text: DomRefCell::new(DOMString::new()),
}
}
@ -650,6 +655,30 @@ fn fetch_a_classic_script(
}
impl HTMLScriptElement {
/// <https://w3c.github.io/trusted-types/dist/spec/#setting-slot-values-from-parser>
pub(crate) fn set_initial_script_text(&self) {
*self.script_text.borrow_mut() = self.text();
}
/// <https://w3c.github.io/trusted-types/dist/spec/#abstract-opdef-prepare-the-script-text>
fn prepare_the_script_text(&self, can_gc: CanGc) -> Fallible<()> {
// Step 1. If scripts script text value is not equal to its child text content,
// set scripts script text to the result of executing
// Get Trusted Type compliant string, with the following arguments:
if self.script_text.borrow().clone() != self.text() {
*self.script_text.borrow_mut() = TrustedScript::get_trusted_script_compliant_string(
&self.owner_global(),
self.Text(),
"HTMLScriptElement",
"text",
can_gc,
)?
.into();
}
Ok(())
}
/// <https://html.spec.whatwg.org/multipage/#prepare-the-script-element>
pub(crate) fn prepare(&self, can_gc: CanGc) {
// Step 1. If el's already started is true, then return.
@ -673,9 +702,14 @@ impl HTMLScriptElement {
self.non_blocking.set(true);
}
// Step 5. Let source text be el's child text content.
// Step 5. Execute the Prepare the script text algorithm on el.
// If that algorithm threw an error, then return.
if self.prepare_the_script_text(can_gc).is_err() {
return;
}
// Step 5a. Let source text be els script text value.
let text = self.script_text.borrow().clone();
// Step 6. If el has no src attribute, and source text is the empty string, then return.
let text = self.text();
if text.is_empty() && !element.has_attribute(&local_name!("src")) {
return;
}
@ -1490,9 +1524,10 @@ impl HTMLScriptElementMethods<crate::DomTypeHolder> for HTMLScriptElement {
"innerText",
can_gc,
)?;
let value = DOMString::from(value);
*self.script_text.borrow_mut() = value.clone();
// Step 3: Run set the inner text steps with this and value.
self.upcast::<HTMLElement>()
.set_inner_text(DOMString::from(value), can_gc);
self.upcast::<HTMLElement>().set_inner_text(value, can_gc);
Ok(())
}
@ -1513,9 +1548,10 @@ impl HTMLScriptElementMethods<crate::DomTypeHolder> for HTMLScriptElement {
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
let value = DOMString::from(value);
*self.script_text.borrow_mut() = value.clone();
// Step 3: String replace all with the given value within this.
Node::string_replace_all(DOMString::from(value), self.upcast::<Node>(), can_gc);
Node::string_replace_all(value, self.upcast::<Node>(), can_gc);
Ok(())
}
@ -1539,10 +1575,10 @@ impl HTMLScriptElementMethods<crate::DomTypeHolder> for HTMLScriptElement {
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
let value = DOMString::from(value);
*self.script_text.borrow_mut() = value.clone();
// Step 3: Run set text content with this and value.
self.upcast::<Node>()
.SetTextContent(Some(DOMString::from(value)), can_gc);
self.upcast::<Node>().SetTextContent(Some(value), can_gc);
Ok(())
}

View file

@ -654,6 +654,7 @@ impl ServoParser {
let script_nesting_level = self.script_nesting_level.get();
self.script_nesting_level.set(script_nesting_level + 1);
script.set_initial_script_text();
script.prepare(can_gc);
self.script_nesting_level.set(script_nesting_level);

View file

@ -1,28 +0,0 @@
[block-text-node-insertion-into-script-element.html]
expected: ERROR
[Regression test: Bypass via insertAdjacentText, initial comment.]
expected: FAIL
[Regression test: Bypass via insertAdjacentText, textContent.]
expected: FAIL
[Spot tests around script + innerHTML interaction.]
expected: FAIL
[Test that default policy applies.]
expected: FAIL
[Test a failing default policy.]
expected: FAIL
[Spot tests around script + innerHTML interaction with default policy.]
expected: FAIL
[Regression test: Bypass via appendChild into off-document script element.]
expected: FAIL
[Regression test: Bypass via appendChild into live script element.]
expected: FAIL
[Test that default policy applies to module script.]
expected: FAIL

View file

@ -1,3 +0,0 @@
[script-enforcement-001-outerHTML.xhtml]
[Script source set via TrustedHTML sink Element.outerHTML drops trustworthiness.]
expected: FAIL

View file

@ -1,78 +1,3 @@
[script-enforcement-001.html]
[Script source set via TrustedHTML sink Element.innerHTML drops trustworthiness.]
expected: FAIL
[Script source set via TrustedHTML sink Element.setHTMLUnsafe() drops trustworthiness.]
expected: FAIL
[Script source set via Node.nodeValue drops trustworthiness.]
expected: FAIL
[Setting script source via CharacterData.data drops trustworthiness.]
expected: FAIL
[Setting script source via CharacterData.appendData() drops trustworthiness.]
expected: FAIL
[Setting script source via CharacterData.insertData() drops trustworthiness.]
expected: FAIL
[Setting script source via CharacterData.replaceData() drops trustworthiness.]
expected: FAIL
[Setting script source via CharacterData.deleteData() drops trustworthiness.]
expected: FAIL
[Setting script source via CharacterData.before() drops trustworthiness.]
expected: FAIL
[Setting script source via CharacterData.after() drops trustworthiness.]
expected: FAIL
[Setting script source via CharacterData.remove() drops trustworthiness.]
expected: FAIL
[Setting script source via CharacterData.replaceWith() drops trustworthiness.]
expected: FAIL
[Setting script source via Node.appendChild() drops trustworthiness.]
expected: FAIL
[Setting script source via Node.insertBefore() drops trustworthiness.]
expected: FAIL
[Setting script source via Node.replaceChild() drops trustworthiness.]
expected: FAIL
[Setting script source via Node.removeChild() drops trustworthiness.]
expected: FAIL
[Setting script source via Element.prepend() drops trustworthiness.]
expected: FAIL
[Setting script source via Element.append() drops trustworthiness.]
expected: FAIL
[Setting script source via Element.replaceChildren() drops trustworthiness.]
expected: FAIL
[Setting script source via Element.moveBefore() drops trustworthiness.]
expected: FAIL
[Setting script source via TrustedHTML sink Node.insertAdjacentHTML() drops trustworthiness.]
expected: FAIL
[Setting script source via Node.insertAdjacentText() drops trustworthiness.]
expected: FAIL
[Setting script source via Range.insertNode() drops trustworthiness.]
expected: FAIL
[Setting script source via Range.deleteContents() drops trustworthiness.]
expected: FAIL
[Cloning a script via Node.cloneNode() drops trustworthiness.]
expected: FAIL
[Cloning a script via Range.cloneContents() drops trustworthiness.]
expected: FAIL

View file

@ -1,3 +0,0 @@
[script-enforcement-002-outerHTML.xhtml]
[Default policy's calls when setting script source via Element.outerHTML.]
expected: FAIL

View file

@ -1,78 +1,3 @@
[script-enforcement-002.html]
[Default policy's calls when setting script source via Element.innerHTML.]
expected: FAIL
[Default policy's calls when setting script source via Element.setHTMLUnsafe().]
expected: FAIL
[Default policy's calls when setting script source via Node.nodeValue.]
expected: FAIL
[Default policy's calls when setting script source via CharacterData.data.]
expected: FAIL
[Default policy's calls when setting script source via CharacterData.appendData().]
expected: FAIL
[Default policy's calls when setting script source via CharacterData.insertData().]
expected: FAIL
[Default policy's calls when setting script source via CharacterData.replaceData().]
expected: FAIL
[Default policy's calls when setting script source via CharacterData.deleteData().]
expected: FAIL
[Default policy's calls when setting script source via CharacterData.before().]
expected: FAIL
[Default policy's calls when setting script source via CharacterData.after().]
expected: FAIL
[Default policy's calls when setting script source via CharacterData.remove().]
expected: FAIL
[Default policy's calls when setting script source via CharacterData.replaceWith().]
expected: FAIL
[Default policy's calls when setting script source via Node.appendChild().]
expected: FAIL
[Default policy's calls when setting script source via Node.insertBefore().]
expected: FAIL
[Default policy's calls when setting script source via Node.replaceChild().]
expected: FAIL
[Default policy's calls when setting script source via Node.removeChild().]
expected: FAIL
[Default policy's calls when setting script source via Element.prepend().]
expected: FAIL
[Default policy's calls when setting script source via Element.append().]
expected: FAIL
[Default policy's calls when setting script source via Element.replaceChildren().]
expected: FAIL
[Default policy's calls when setting script source via Element.moveBefore().]
expected: FAIL
[Default policy's calls when setting script source via Node.insertAdjacentText().]
expected: FAIL
[Default policy's calls when setting script source via Node.insertAdjacentHTML().]
expected: FAIL
[Default policy's calls when setting source via Range.insertNode().]
expected: FAIL
[Default policy's calls when setting script source via Range.deleteContents().]
expected: FAIL
[Default policy's calls when cloning a script via Node.cloneNode().]
expected: FAIL
[Default policy's calls when cloning a script via Range.cloneContents().]
expected: FAIL

View file

@ -1,10 +1,4 @@
[script-enforcement-005.html]
[Empty HTMLScriptElement is executed if the default policy makes it non-empty.]
expected: FAIL
[Non-empty HTMLScriptElement is not executed if the default policy makes it empty.]
expected: FAIL
[Empty SVGScriptElement is executed if the default policy makes it non-empty.]
expected: FAIL

View file

@ -1,10 +1,3 @@
[script-enforcement-006.html]
expected: ERROR
[Untrusted HTMLScriptElement with classic type uses the source text returned by the default policy.]
expected: FAIL
[Untrusted HTMLScriptElement of importmap type uses the source text returned by the default policy.]
expected: FAIL
[Untrusted HTMLScriptElement of module type uses the source text returned by the default policy.]
expected: FAIL

View file

@ -2,11 +2,5 @@
[script-src CSP directive is properly set.]
expected: FAIL
[Untrusted HTMLScriptElement with classic type uses the source text returned by the default policy for inline CSP check.]
expected: FAIL
[Untrusted HTMLScriptElement of importmap type uses the source text returned by the default policy for inline CSP check.]
expected: FAIL
[Untrusted HTMLScriptElement of module type uses the source text returned by the default policy for inline CSP check.]
expected: FAIL

View file

@ -1,6 +0,0 @@
[script-enforcement-010.html]
[Changing script's type from classic to module in the default policy works.]
expected: FAIL
[Changing script's type from module to classic in the default policy works.]
expected: FAIL

View file

@ -1,3 +0,0 @@
[trusted-types-reporting-for-HTMLScriptElement-children-change.html]
[sink mismatch violation report when the script text is changed by manipulating its children.]
expected: FAIL