diff --git a/LayoutTests/imported/w3c/web-platform-tests/trusted-types/block-Document-execCommand-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/trusted-types/block-Document-execCommand-expected.txt index 52242ff5f0a2..56069ed1a1dd 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/trusted-types/block-Document-execCommand-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/trusted-types/block-Document-execCommand-expected.txt @@ -1,5 +1,6 @@ +CONSOLE MESSAGE: This requires a TrustedHTML value else it violates the following Content Security Policy directive: "require-trusted-types-for 'script'" -FAIL Document.execCommand("insertHTML") throws. assert_throws_js: function "_ => document.execCommand(command, false, "Hello World")" did not throw +PASS Document.execCommand("insertHTML") throws. PASS Document.execCommand("insertHTML") works with a TrustedHTML argument. PASS Document.execCommand("paste") works as usual." PASS Document.execCommand("paste") works with a TrustedHTML argument. diff --git a/Source/WebCore/dom/Document+HTML.idl b/Source/WebCore/dom/Document+HTML.idl index d9fe8ab2add8..602ceb7309f6 100644 --- a/Source/WebCore/dom/Document+HTML.idl +++ b/Source/WebCore/dom/Document+HTML.idl @@ -68,7 +68,7 @@ partial interface Document { [ImplementedAs=windowProxy] readonly attribute WindowProxy? defaultView; boolean hasFocus(); [CEReactions=Needed] attribute DOMString designMode; - [CEReactions=Needed] boolean execCommand(DOMString commandId, optional boolean showUI = false, optional DOMString value = ""); + [CEReactions=Needed] boolean execCommand(DOMString commandId, optional boolean showUI = false, optional (DOMString or TrustedHTML) value = ""); boolean queryCommandEnabled(DOMString commandId); boolean queryCommandIndeterm(DOMString commandId); boolean queryCommandState(DOMString commandId); diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp index e3fc31129fd3..6e3f29790c6c 100644 --- a/Source/WebCore/dom/Document.cpp +++ b/Source/WebCore/dom/Document.cpp @@ -272,6 +272,7 @@ #include "TouchAction.h" #include "TransformSource.h" #include "TreeWalker.h" +#include "TrustedType.h" #include "TypedElementDescendantIteratorInlines.h" #include "UndoManager.h" #include "UserGestureIndicator.h" @@ -6895,13 +6896,27 @@ static Editor::Command command(Document* document, const String& commandName, bo userInterface ? EditorCommandSource::DOMWithUserInterface : EditorCommandSource::DOM); } -ExceptionOr Document::execCommand(const String& commandName, bool userInterface, const String& value) +ExceptionOr Document::execCommand(const String& commandName, bool userInterface, const std::variant>& value) { if (UNLIKELY(!isHTMLDocument() && !isXHTMLDocument())) return Exception { ExceptionCode::InvalidStateError, "execCommand is only supported on HTML documents."_s }; + auto stringValueHolder = WTF::switchOn(value, + [&commandName, this](const String& str) -> ExceptionOr { + if (commandName != "insertHTML"_s) + return String(str); + return trustedTypeCompliantString(TrustedType::TrustedHTML, *scriptExecutionContext(), str, "Document execCommand"_s); + }, + [](const RefPtr& trustedHtml) -> ExceptionOr { + return trustedHtml->toString(); + } + ); + + if (stringValueHolder.hasException()) + return stringValueHolder.releaseException(); + EventQueueScope eventQueueScope; - return command(this, commandName, userInterface).execute(value); + return command(this, commandName, userInterface).execute(stringValueHolder.releaseReturnValue()); } ExceptionOr Document::queryCommandEnabled(const String& commandName) diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h index 9476aaf98f81..e33017edd227 100644 --- a/Source/WebCore/dom/Document.h +++ b/Source/WebCore/dom/Document.h @@ -46,6 +46,7 @@ #include "Supplementable.h" #include "Timer.h" #include "TreeScope.h" +#include "TrustedHTML.h" #include "URLKeepingBlobAlive.h" #include "UserActionElementSet.h" #include "ViewportArguments.h" @@ -1197,7 +1198,7 @@ class Document inline CheckedRef checkedMarkers(); // Defined in DocumentInlines.h. inline CheckedRef checkedMarkers() const; // Defined in DocumentInlines.h. - WEBCORE_EXPORT ExceptionOr execCommand(const String& command, bool userInterface = false, const String& value = String()); + WEBCORE_EXPORT ExceptionOr execCommand(const String& command, bool userInterface = false, const std::variant>& value = String()); WEBCORE_EXPORT ExceptionOr queryCommandEnabled(const String& command); WEBCORE_EXPORT ExceptionOr queryCommandIndeterm(const String& command); WEBCORE_EXPORT ExceptionOr queryCommandState(const String& command); diff --git a/Source/WebCore/dom/TrustedHTML.h b/Source/WebCore/dom/TrustedHTML.h index 76a6b777b3c0..8dfdcdedfeb6 100644 --- a/Source/WebCore/dom/TrustedHTML.h +++ b/Source/WebCore/dom/TrustedHTML.h @@ -31,7 +31,7 @@ namespace WebCore { -class TrustedHTML : public ScriptWrappable, public RefCounted { +class WEBCORE_EXPORT TrustedHTML : public ScriptWrappable, public RefCounted { WTF_MAKE_ISO_ALLOCATED(TrustedHTML); public: static Ref create(const String& data);