tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 330f81172340b3a484f98fd9969ab3e1ad080e22
parent 3e8fc8711ca6686c64c15690e6b18bd98bf907fa
Author: Edgar Chen <echen@mozilla.com>
Date:   Thu, 27 Nov 2025 19:37:06 +0000

Bug 2002020 - Make queryCommandEnabled() and queryCommandSupported() for clipboard comments returning proper result for Web Extension; r=webidl,smaug

Web Extension with clipboard permission have greater privileges to use clipboard
commands, queryCommandSupported() and queryCommandEnabled() should reflect that.

Differential Revision: https://phabricator.services.mozilla.com/D273904

Diffstat:
Mdom/base/Document.cpp | 31++++++++++++++++---------------
Mdom/base/Document.h | 2+-
Mdom/events/test/clipboard/browser_document_command_copy.js | 12+++---------
Mdom/events/test/clipboard/browser_document_command_cut.js | 12+++---------
Mdom/events/test/clipboard/browser_document_command_paste.js | 56++++++++++++++++++++++++++++----------------------------
Mdom/webidl/Document.webidl | 2+-
6 files changed, 52 insertions(+), 63 deletions(-)

diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp @@ -5988,13 +5988,16 @@ bool Document::QueryCommandEnabled(const nsAString& aHTMLCommandName, break; } - // cut & copy are always allowed + // Report false for restricted commands if (commandData.IsCutOrCopyCommand()) { + // XXX: should we report "disabled" when the target is not editable for cut + // command? return nsContentUtils::IsCutCopyAllowed(this, aSubjectPrincipal); } - // Report false for restricted commands - if (commandData.IsPasteCommand() && !aSubjectPrincipal.IsSystemPrincipal()) { + if (commandData.IsPasteCommand() && + !nsContentUtils::PrincipalHasPermission(aSubjectPrincipal, + nsGkAtoms::clipboardRead)) { return false; } @@ -6182,7 +6185,7 @@ bool Document::QueryCommandState(const nsAString& aHTMLCommandName, } bool Document::QueryCommandSupported(const nsAString& aHTMLCommandName, - CallerType aCallerType, ErrorResult& aRv) { + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { // Only allow on HTML documents. if (!IsHTMLOrXHTML()) { aRv.ThrowInvalidStateError( @@ -6213,17 +6216,15 @@ bool Document::QueryCommandSupported(const nsAString& aHTMLCommandName, // may also be disallowed to be called from non-privileged content. // For that reason, we report the support status of corresponding // command accordingly. - if (aCallerType != CallerType::System) { - if (commandData.IsPasteCommand()) { - return false; - } - if (commandData.IsCutOrCopyCommand() && - !StaticPrefs::dom_allow_cut_copy()) { - // XXXbz should we worry about correctly reporting "true" in the - // "restricted, but we're an addon with clipboardWrite permissions" case? - // See also nsContentUtils::IsCutCopyAllowed. - return false; - } + if (commandData.IsPasteCommand() && + !nsContentUtils::PrincipalHasPermission(aSubjectPrincipal, + nsGkAtoms::clipboardRead)) { + return false; + } + if (commandData.IsCutOrCopyCommand() && !StaticPrefs::dom_allow_cut_copy() && + !nsContentUtils::PrincipalHasPermission(aSubjectPrincipal, + nsGkAtoms::clipboardWrite)) { + return false; } // aHTMLCommandName is supported if it can be converted to a Midas command diff --git a/dom/base/Document.h b/dom/base/Document.h @@ -3549,7 +3549,7 @@ class Document : public nsINode, MOZ_CAN_RUN_SCRIPT bool QueryCommandState(const nsAString& aHTMLCommandName, mozilla::ErrorResult& aRv); MOZ_CAN_RUN_SCRIPT bool QueryCommandSupported( - const nsAString& aHTMLCommandName, mozilla::dom::CallerType aCallerType, + const nsAString& aHTMLCommandName, nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aRv); MOZ_CAN_RUN_SCRIPT void QueryCommandValue(const nsAString& aHTMLCommandName, nsAString& aValue, diff --git a/dom/events/test/clipboard/browser_document_command_copy.js b/dom/events/test/clipboard/browser_document_command_copy.js @@ -165,11 +165,9 @@ const kContentFileUrl = kBaseUrlForContent + "simple_page_ext.html"; await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => { let [supported, enabled, succeed] = await extension.awaitMessage("ready"); - // XXX: should "copy" command be supported if extension has - // clipboardWrite permission? is( supported, - aPrefValue, + aPrefValue || aPermission, "Check if the 'copy' command is supported" ); is( @@ -246,11 +244,9 @@ const kContentFileUrl = kBaseUrlForContent + "simple_page_ext.html"; await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => { let [supported, enabled, succeed] = await extension.awaitMessage("ready"); - // XXX: should "copy" command be supported if extension has - // clipboardWrite permission? is( supported, - aPrefValue, + aPrefValue || aPermission, "Check if the 'copy' command is supported" ); is( @@ -301,11 +297,9 @@ const kContentFileUrl = kBaseUrlForContent + "simple_page_ext.html"; await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => { let [supported, enabled, succeed] = await extension.awaitMessage("ready"); - // XXX: should "copy" command be supported if extension has - // clipboardWrite permission. is( supported, - aPrefValue, + aPrefValue || aPermission, "Check if the 'copy' command is supported" ); is(enabled, aPermission, "Check if the 'copy' command is enabled"); diff --git a/dom/events/test/clipboard/browser_document_command_cut.js b/dom/events/test/clipboard/browser_document_command_cut.js @@ -172,11 +172,9 @@ const kContentFileUrl = kBaseUrlForContent + "simple_page_ext.html"; await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => { let [supported, enabled, succeed] = await extension.awaitMessage("ready"); - // XXX: should "cut" command be supported if extension has - // clipboardWrite permission? is( supported, - aPrefValue, + aPrefValue || aPermission, "Check if the 'cut' command is supported" ); @@ -252,11 +250,9 @@ const kContentFileUrl = kBaseUrlForContent + "simple_page_ext.html"; await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => { let [supported, enabled, succeed] = await extension.awaitMessage("ready"); - // XXX: should "cut" command be supported if extension has - // clipboardWrite permission? is( supported, - aPrefValue, + aPrefValue || aPermission, "Check if the 'cut' command is supported" ); @@ -309,11 +305,9 @@ const kContentFileUrl = kBaseUrlForContent + "simple_page_ext.html"; await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => { let [supported, enabled, succeed] = await extension.awaitMessage("ready"); - // XXX: should "cut" command be supported if extension has - // clipboardWrite permission. is( supported, - aPrefValue, + aPrefValue || aPermission, "Check if the 'cut' command is supported" ); // XXX: should "cut" command be disabled without an editing target? diff --git a/dom/events/test/clipboard/browser_document_command_paste.js b/dom/events/test/clipboard/browser_document_command_paste.js @@ -159,13 +159,14 @@ describe("test paste comment", () => { await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => { let [supported, enabled, succeed] = await extension.awaitMessage("ready"); - // XXX: should "paste" command be supported if extension has - // clipboardRead permission? - ok(!supported, "Check if the 'paste' command is supported"); - // XXX: should "paste" command be enabled if extension has - // clipboardRead permission? - ok( - !enabled, + is( + supported, + aPermission, + "Check if the 'paste' command is supported" + ); + is( + enabled, + aPermission, "Check if the 'paste' command is enabled without user activation" ); is( @@ -178,10 +179,9 @@ describe("test paste comment", () => { promiseClickContentElement(browser, "btn"); [supported, enabled, succeed] = await extension.awaitMessage("result"); - // XXX: should "paste" command be enabled if extension has - // clipboardRead permission? - ok( - !enabled, + is( + enabled, + aPermission, "Check if the 'paste' command is enabled with user activation" ); is( @@ -235,13 +235,14 @@ describe("test paste comment", () => { await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => { let [supported, enabled, succeed] = await extension.awaitMessage("ready"); - // XXX: should "paste" command be supported if extension has - // clipboardRead permission? - ok(!supported, "Check if the 'paste' command is supported"); - // XXX: should "paste" command be enabled if extension has - // clipboardRead permission? - ok( - !enabled, + is( + supported, + aPermission, + "Check if the 'paste' command is supported" + ); + is( + enabled, + aPermission, "Check if the 'paste' command is enabled without user activation" ); is( @@ -254,10 +255,9 @@ describe("test paste comment", () => { promiseClickContentElement(browser, "btn"); [supported, enabled, succeed] = await extension.awaitMessage("result"); - // XXX: should "paste" command be enabled if extension has - // clipboardRead permission? - ok( - !enabled, + is( + enabled, + aPermission, "Check if the 'paste' command is enabled with user activation" ); is( @@ -288,12 +288,12 @@ describe("test paste comment", () => { await BrowserTestUtils.withNewTab(kContentFileUrl, async browser => { let [supported, enabled, succeed] = await extension.awaitMessage("ready"); - // XXX: should "paste" command be supported if extension has - // clipboardRead permission? - ok(!supported, "Check if the 'paste' command is supported"); - // XXX: should "paste" command be enabled if extension has - // clipboardRead permission? - ok(!enabled, "Check if the 'paste' command is enabled"); + is( + supported, + aPermission, + "Check if the 'paste' command is supported" + ); + is(enabled, aPermission, "Check if the 'paste' command is enabled"); is(succeed, aPermission, "Check if the 'paste' command is succeed"); }); await extension.unload(); diff --git a/dom/webidl/Document.webidl b/dom/webidl/Document.webidl @@ -176,7 +176,7 @@ partial interface Document { boolean queryCommandIndeterm(DOMString commandId); [Throws] boolean queryCommandState(DOMString commandId); - [Throws, NeedsCallerType] + [Throws, NeedsSubjectPrincipal] boolean queryCommandSupported(DOMString commandId); [Throws] DOMString queryCommandValue(DOMString commandId);