Bug 1777448 - Part 1: Don't not show paste contextmenu for background tab; r=nika,hsivonen

Displaying the paste context menu for background tabs can be surprising and
confusing for users, so we reject the request and don't allow it being associated
with existing pending request.

Depends on D190405

Differential Revision: https://phabricator.services.mozilla.com/D190761
This commit is contained in:
Edgar Chen
2023-12-08 07:08:42 +00:00
parent a53113cbfc
commit 88ac2e701c
2 changed files with 56 additions and 20 deletions

View File

@@ -226,20 +226,14 @@ add_task(async function test_multiple_readText_from_background_frame() {
info( info(
"readText() from background tab again before interact with paste button" "readText() from background tab again before interact with paste button"
); );
const readTextRequest2 = SpecialPowers.spawn( await Assert.rejects(
backgroundTab.linkedBrowser, SpecialPowers.spawn(backgroundTab.linkedBrowser, [], async () => {
[],
async () => {
content.document.notifyUserGestureActivation(); content.document.notifyUserGestureActivation();
return content.eval(`navigator.clipboard.readText();`); return content.eval(`navigator.clipboard.readText();`);
} }),
/NotAllowedError/,
"Second request should be rejected"
); );
// Give some time for the second request to arrive parent process.
await SpecialPowers.spawn(backgroundTab.linkedBrowser, [], async () => {
return new Promise(resolve => {
content.setTimeout(resolve, 0);
});
});
info("Click paste button, both request should be resolved"); info("Click paste button, both request should be resolved");
await promiseClickPasteButton(); await promiseClickPasteButton();
@@ -248,11 +242,6 @@ add_task(async function test_multiple_readText_from_background_frame() {
clipboardText, clipboardText,
"First request should be resolved" "First request should be resolved"
); );
is(
await readTextRequest2,
clipboardText,
"Second request should be resolved"
);
}); });
await BrowserTestUtils.removeTab(backgroundTab); await BrowserTestUtils.removeTab(backgroundTab);
@@ -270,6 +259,16 @@ add_task(async function test_multiple_readText_from_background_window() {
); );
await SimpleTest.promiseFocus(browser); await SimpleTest.promiseFocus(browser);
info("readText() from background window");
await Assert.rejects(
SpecialPowers.spawn(backgroundTab.linkedBrowser, [], async () => {
content.document.notifyUserGestureActivation();
return content.eval(`navigator.clipboard.readText();`);
}),
/NotAllowedError/,
"Request from background window should be rejected"
);
const pasteButtonIsShown = waitForPasteContextMenu(); const pasteButtonIsShown = waitForPasteContextMenu();
const readTextRequest1 = SpecialPowers.spawn(browser, [], async () => { const readTextRequest1 = SpecialPowers.spawn(browser, [], async () => {
content.document.notifyUserGestureActivation(); content.document.notifyUserGestureActivation();
@@ -300,3 +299,29 @@ add_task(async function test_multiple_readText_from_background_window() {
await BrowserTestUtils.closeWindow(newWin); await BrowserTestUtils.closeWindow(newWin);
}); });
}); });
add_task(async function test_multiple_readText_focuse_in_chrome_document() {
// Randomized text to avoid overlapping with other tests.
const clipboardText = await promiseWritingRandomTextToClipboard();
const win = await BrowserTestUtils.openNewBrowserWindow();
const tab = await BrowserTestUtils.openNewForegroundTab(
win.gBrowser,
kContentFileUrl
);
info("Move focus to url bar");
win.gURLBar.focus();
info("readText() from web content");
await Assert.rejects(
SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
content.document.notifyUserGestureActivation();
return content.eval(`navigator.clipboard.readText();`);
}),
/NotAllowedError/,
"Request should be rejected when focus is not in content"
);
await BrowserTestUtils.closeWindow(win);
});

View File

@@ -17,6 +17,7 @@
#include "mozilla/StaticPrefs_dom.h" #include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_widget.h" #include "mozilla/StaticPrefs_widget.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsFocusManager.h"
#include "nsIClipboardOwner.h" #include "nsIClipboardOwner.h"
#include "nsIPromptService.h" #include "nsIPromptService.h"
#include "nsError.h" #include "nsError.h"
@@ -734,14 +735,24 @@ void nsBaseClipboard::RequestUserConfirmation(
CanonicalBrowsingContext* cbc = CanonicalBrowsingContext* cbc =
CanonicalBrowsingContext::Cast(aWindowContext->GetBrowsingContext()); CanonicalBrowsingContext::Cast(aWindowContext->GetBrowsingContext());
if (!cbc) { MOZ_ASSERT(
cbc->IsContent(),
"Should not require user confirmation when access from chrome window");
RefPtr<CanonicalBrowsingContext> chromeTop = cbc->TopCrossChromeBoundary();
Document* chromeDoc = chromeTop ? chromeTop->GetDocument() : nullptr;
if (!chromeDoc || !chromeDoc->HasFocus(mozilla::IgnoreErrors())) {
MOZ_CLIPBOARD_LOG("%s: reject due to not in the focused window",
__FUNCTION__);
aCallback->OnError(NS_ERROR_FAILURE); aCallback->OnError(NS_ERROR_FAILURE);
return; return;
} }
RefPtr<CanonicalBrowsingContext> chromeTop = cbc->TopCrossChromeBoundary(); mozilla::dom::Element* activeElementInChromeDoc =
Document* chromeDoc = chromeTop ? chromeTop->GetDocument() : nullptr; chromeDoc->GetActiveElement();
if (!chromeDoc) { if (activeElementInChromeDoc != cbc->Top()->GetEmbedderElement()) {
// Reject if the request is not from web content that is in the focused tab.
MOZ_CLIPBOARD_LOG("%s: reject due to not in the focused tab", __FUNCTION__);
aCallback->OnError(NS_ERROR_FAILURE); aCallback->OnError(NS_ERROR_FAILURE);
return; return;
} }