From 1368744d33a233a5e5da6ab779bf19a5f67538ed Mon Sep 17 00:00:00 2001 From: Tete17 Date: Fri, 8 Aug 2025 17:34:23 +0200 Subject: [PATCH] LibWeb: Amend Document interface to make it compatible with TrustedTypes --- Libraries/LibWeb/DOM/Document.cpp | 56 ++++++++++++++----- Libraries/LibWeb/DOM/Document.h | 8 +-- Libraries/LibWeb/DOM/Document.idl | 10 ++-- Libraries/LibWeb/TrustedTypes/InjectionSink.h | 1 + 4 files changed, 50 insertions(+), 25 deletions(-) diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index cd5db9f7b6..4b285a0d37 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -165,6 +165,8 @@ #include #include #include +#include +#include #include #include #include @@ -644,41 +646,56 @@ GC::Ptr Document::get_selection() const } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-document-write -WebIDL::ExceptionOr Document::write(Vector const& text) +WebIDL::ExceptionOr Document::write(Vector const& text) { // The document.write(...text) method steps are to run the document write steps with this, text, false, and "Document write". return run_the_document_write_steps(text, AddLineFeed::No, TrustedTypes::InjectionSink::Documentwrite); } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-document-writeln -WebIDL::ExceptionOr Document::writeln(Vector const& text) +WebIDL::ExceptionOr Document::writeln(Vector const& text) { // The document.writeln(...text) method steps are to run the document write steps with this, text, true, and "Document writeln". return run_the_document_write_steps(text, AddLineFeed::Yes, TrustedTypes::InjectionSink::Documentwriteln); } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#document-write-steps -WebIDL::ExceptionOr Document::run_the_document_write_steps(Vector const& text, AddLineFeed line_feed, TrustedTypes::InjectionSink sink) +WebIDL::ExceptionOr Document::run_the_document_write_steps(Vector const& text, AddLineFeed line_feed, TrustedTypes::InjectionSink sink) { // 1. Let string be the empty string. StringBuilder string; // 2. Let isTrusted be false if text contains a string; otherwise true. - // FIXME: We currently only accept strings. Revisit this once we support the TrustedHTML type. auto is_trusted = true; + for (auto const& value : text) { + if (value.has()) { + is_trusted = false; + break; + } + } // 3. For each value of text: for (auto const& value : text) { - // FIXME: 1. If value is a TrustedHTML object, then append value's associated data to string. - - // 2. Otherwise, append value to string. - string.append(value); + string.append(value.visit( + // 1. If value is a TrustedHTML object, then append value's associated data to string. + [](GC::Root const& value) { return value->to_string(); }, + // 2. Otherwise, append value to string. + [](Utf16String const& value) { return value; }) + .to_utf8_but_should_be_ported_to_utf16()); } - // FIXME: 4. If isTrusted is false, set string to the result of invoking the Get Trusted Type compliant string algorithm + // 4. If isTrusted is false, set string to the result of invoking the Get Trusted Type compliant string algorithm // with TrustedHTML, this's relevant global object, string, sink, and "script". - (void)is_trusted; - (void)sink; + if (!is_trusted) { + auto const new_string = TRY(TrustedTypes::get_trusted_type_compliant_string( + TrustedTypes::TrustedTypeName::TrustedHTML, + relevant_global_object(*this), + Utf16String::from_utf8(MUST(string.to_string())), + sink, + TrustedTypes::Script.to_string())); + string.clear(); + string.append(new_string.to_utf8_but_should_be_ported_to_utf16()); + } // 5. If lineFeed is true, append U+000A LINE FEED to string. if (line_feed == AddLineFeed::Yes) @@ -6345,10 +6362,19 @@ void Document::parse_html_from_a_string(StringView html) } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-parsehtmlunsafe -GC::Ref Document::parse_html_unsafe(JS::VM& vm, StringView html) +WebIDL::ExceptionOr> Document::parse_html_unsafe(JS::VM& vm, TrustedTypes::TrustedHTMLOrString const& html) { auto& realm = *vm.current_realm(); - // FIXME: 1. Let compliantHTML to the result of invoking the Get Trusted Type compliant string algorithm with TrustedHTML, this's relevant global object, html, "Document parseHTMLUnsafe", and "script". + + // FIXME: update description once https://github.com/whatwg/html/issues/11778 gets solved + // 1. Let compliantHTML to the result of invoking the Get Trusted Type compliant string algorithm with + // TrustedHTML, this's relevant global object, html, "Document parseHTMLUnsafe", and "script". + auto const compliant_html = TRY(TrustedTypes::get_trusted_type_compliant_string( + TrustedTypes::TrustedTypeName::TrustedHTML, + HTML::current_principal_global_object(), + html, + TrustedTypes::InjectionSink::DocumentparseHTMLUnsafe, + TrustedTypes::Script.to_string())); // 2. Let document be a new Document, whose content type is "text/html". auto document = Document::create_for_fragment_parsing(realm); @@ -6357,8 +6383,8 @@ GC::Ref Document::parse_html_unsafe(JS::VM& vm, StringView html) // 3. Set document's allow declarative shadow roots to true. document->set_allow_declarative_shadow_roots(true); - // 4. Parse HTML from a string given document and compliantHTML. // FIXME: Use compliantHTML. - document->parse_html_from_a_string(html); + // 4. Parse HTML from a string given document and compliantHTML. + document->parse_html_from_a_string(compliant_html.to_utf8_but_should_be_ported_to_utf16()); // AD-HOC: Setting the origin to match that of the associated document matches the behavior of existing browsers. auto& associated_document = as(realm.global_object()).associated_document(); diff --git a/Libraries/LibWeb/DOM/Document.h b/Libraries/LibWeb/DOM/Document.h index b97efe03de..154b1976d0 100644 --- a/Libraries/LibWeb/DOM/Document.h +++ b/Libraries/LibWeb/DOM/Document.h @@ -472,8 +472,8 @@ public: void set_window(HTML::Window&); - WebIDL::ExceptionOr write(Vector const& strings); - WebIDL::ExceptionOr writeln(Vector const& strings); + WebIDL::ExceptionOr write(Vector const& text); + WebIDL::ExceptionOr writeln(Vector const& text); WebIDL::ExceptionOr open(Optional const& = {}, Optional const& = {}); WebIDL::ExceptionOr> open(StringView url, StringView name, StringView features); @@ -828,7 +828,7 @@ public: Vector> find_matching_text(String const&, CaseSensitivity); void parse_html_from_a_string(StringView); - static GC::Ref parse_html_unsafe(JS::VM&, StringView); + static WebIDL::ExceptionOr> parse_html_unsafe(JS::VM&, TrustedTypes::TrustedHTMLOrString const&); void set_console_client(GC::Ptr console_client) { m_console_client = console_client; } GC::Ptr console_client() const { return m_console_client; } @@ -972,7 +972,7 @@ private: Yes, No, }; - WebIDL::ExceptionOr run_the_document_write_steps(Vector const& text, AddLineFeed line_feed, TrustedTypes::InjectionSink sink); + WebIDL::ExceptionOr run_the_document_write_steps(Vector const& text, AddLineFeed line_feed, TrustedTypes::InjectionSink sink); void queue_intersection_observer_task(); void queue_an_intersection_observer_entry(IntersectionObserver::IntersectionObserver&, HighResolutionTime::DOMHighResTimeStamp time, GC::Ref root_bounds, GC::Ref bounding_client_rect, GC::Ref intersection_rect, bool is_intersecting, double intersection_ratio, GC::Ref target); diff --git a/Libraries/LibWeb/DOM/Document.idl b/Libraries/LibWeb/DOM/Document.idl index 986faddec9..347f19e14c 100644 --- a/Libraries/LibWeb/DOM/Document.idl +++ b/Libraries/LibWeb/DOM/Document.idl @@ -26,6 +26,7 @@ #import #import #import +#import #import #import #import @@ -56,13 +57,10 @@ interface Document : Node { [CEReactions] Document open(optional DOMString unused1, optional DOMString unused2); WindowProxy? open(USVString url, DOMString name, DOMString features); [CEReactions] undefined close(); - // FIXME: [CEReactions] undefined write((TrustedHTML or DOMString)... text); - [CEReactions] undefined write(DOMString... text); - // FIXME: [CEReactions] undefined writeln((TrustedHTML or DOMString)... text); - [CEReactions] undefined writeln(DOMString... text); + [CEReactions] undefined write((TrustedHTML or Utf16DOMString)... text); + [CEReactions] undefined writeln((TrustedHTML or Utf16DOMString)... text); - // FIXME: static Document parseHTMLUnsafe((TrustedHTML or DOMString) html); - static Document parseHTMLUnsafe(DOMString html); + static Document parseHTMLUnsafe((TrustedHTML or Utf16DOMString) html); attribute DOMString cookie; diff --git a/Libraries/LibWeb/TrustedTypes/InjectionSink.h b/Libraries/LibWeb/TrustedTypes/InjectionSink.h index 75441b115c..5c6ad5c9dc 100644 --- a/Libraries/LibWeb/TrustedTypes/InjectionSink.h +++ b/Libraries/LibWeb/TrustedTypes/InjectionSink.h @@ -17,6 +17,7 @@ namespace Web::TrustedTypes { // https://w3c.github.io/trusted-types/dist/spec/#injection-sink #define ENUMERATE_INJECTION_SINKS \ + __ENUMERATE_INJECTION_SINKS(DocumentparseHTMLUnsafe, "Document parseHTMLUnsafe") \ __ENUMERATE_INJECTION_SINKS(Documentwrite, "Document write") \ __ENUMERATE_INJECTION_SINKS(Documentwriteln, "Document writeln") \ __ENUMERATE_INJECTION_SINKS(DocumentexecCommand, "Document execCommand") \