Bug 1678389 - Use transient user activation for <input> file/color picker. r=edgar,smaug

This matches other browsers, see [1], and should fix this and other
similar bugs like bug 1610726.

[1]: https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/core/html/forms/file_input_type.cc;l=163;drc=8a5de62dd01360cfe3d150640d3ff4d974bbe842

Differential Revision: https://phabricator.services.mozilla.com/D97640
This commit is contained in:
Emilio Cobos Álvarez 2020-11-30 16:00:02 +00:00
parent 042903ae82
commit debb6b0fa5
7 changed files with 29 additions and 50 deletions

View File

@ -3223,7 +3223,6 @@ static void WarnIfSandboxIneffective(nsIDocShell* aDocShell,
if (aSandboxFlags != SANDBOXED_NONE &&
!(aSandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION) &&
!(aSandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION_USER_ACTIVATION)) {
nsCOMPtr<nsIURI> iframeUri;
nsContentUtils::ReportToConsole(
nsIScriptError::warningFlag, "Iframe Sandbox"_ns,
aDocShell->GetDocument(), nsContentUtils::eSECURITY_PROPERTIES,

View File

@ -117,21 +117,6 @@ PopupBlocker::GetPopupControlState() {
return sPopupControlState;
}
/* static */
bool PopupBlocker::CanShowPopupByPermission(nsIPrincipal* aPrincipal) {
MOZ_ASSERT(aPrincipal);
uint32_t permit = GetPopupPermission(aPrincipal);
if (permit == nsIPermissionManager::ALLOW_ACTION) {
return true;
}
if (permit == nsIPermissionManager::DENY_ACTION) {
return false;
}
return !StaticPrefs::dom_disable_open_during_load();
}
/* static */
uint32_t PopupBlocker::GetPopupPermission(nsIPrincipal* aPrincipal) {
uint32_t permit = nsIPermissionManager::UNKNOWN_ACTION;

View File

@ -44,10 +44,6 @@ class PopupBlocker final {
static void PopupStatePusherCreated();
static void PopupStatePusherDestroyed();
// This method checks if the principal is allowed by open popups by user
// permissions. In this case, the caller should not block popups.
static bool CanShowPopupByPermission(nsIPrincipal* aPrincipal);
static uint32_t GetPopupPermission(nsIPrincipal* aPrincipal);
// This method returns true if the caller is allowed to show a popup, and it

View File

@ -18,6 +18,7 @@
#include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/GetFilesHelper.h"
#include "mozilla/dom/HTMLFormSubmission.h"
#include "mozilla/dom/WindowContext.h"
#include "mozilla/dom/InputType.h"
#include "mozilla/dom/UserActivation.h"
#include "mozilla/dom/MutationEventBinding.h"
@ -663,19 +664,20 @@ nsColorPickerShownCallback::Done(const nsAString& aColor) {
NS_IMPL_ISUPPORTS(nsColorPickerShownCallback, nsIColorPickerShownCallback)
bool HTMLInputElement::IsPopupBlocked() const {
nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
MOZ_ASSERT(win, "window should not be null");
if (!win) {
return true;
static bool IsPopupBlocked(Document* aDoc) {
if (aDoc->ConsumeTransientUserGestureActivation()) {
return false;
}
// Check if page can open a popup without abuse regardless of allowed events
if (PopupBlocker::GetPopupControlState() <= PopupBlocker::openBlocked) {
return !PopupBlocker::TryUsePopupOpeningToken(OwnerDoc()->NodePrincipal());
WindowContext* wc = aDoc->GetWindowContext();
if (wc && wc->CanShowPopup()) {
return false;
}
return !PopupBlocker::CanShowPopupByPermission(OwnerDoc()->NodePrincipal());
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "DOM"_ns, aDoc,
nsContentUtils::eDOM_PROPERTIES,
"InputPickerBlockedNoUserActivation");
return true;
}
nsresult HTMLInputElement::InitColorPicker() {
@ -691,7 +693,7 @@ nsresult HTMLInputElement::InitColorPicker() {
return NS_ERROR_FAILURE;
}
if (IsPopupBlocked()) {
if (IsPopupBlocked(doc)) {
return NS_OK;
}
@ -736,7 +738,7 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) {
return NS_ERROR_FAILURE;
}
if (IsPopupBlocked()) {
if (IsPopupBlocked(doc)) {
return NS_OK;
}

View File

@ -1397,15 +1397,6 @@ class HTMLInputElement final : public TextControlElement,
nsresult InitFilePicker(FilePickerType aType);
nsresult InitColorPicker();
/**
* Use this function before trying to open a picker.
* It checks if the page is allowed to open a new pop-up.
* If it returns true, you should not create the picker.
*
* @return true if popup should be blocked, false otherwise
*/
bool IsPopupBlocked() const;
GetFilesHelper* GetOrCreateGetFilesHelper(bool aRecursiveFlag,
ErrorResult& aRv);

View File

@ -29,17 +29,22 @@ MockFilePicker.init(window);
let pickerCount = 0;
SpecialPowers.pushPrefEnv({
set: [["dom.disable_open_during_load", true]],
})
// Let's do the first click.
(new Promise(resolve => {
MockFilePicker.showCallback = function(filepicker) {
++pickerCount;
resolve();
}
setTimeout(_ => {
is(pickerCount, 0, "No file picker initially");
sendMouseEvent({type:'click'}, 'foo');
}, 0);
}))
.then(() => {
return new Promise(resolve => {
MockFilePicker.showCallback = function(filepicker) {
++pickerCount;
resolve();
}
setTimeout(_ => {
is(pickerCount, 0, "No file picker initially");
synthesizeMouseAtCenter(foo, {});
}, 0);
})
})
// Let's wait a bit more, then let's do a click.
.then(() => {

View File

@ -405,3 +405,4 @@ FolderUploadPrompt.title = Confirm Upload
# LOCALIZATION NOTE: %S is the name of the folder the user selected in the file picker.
FolderUploadPrompt.message = Are you sure you want to upload all files from “%S”? Only do this if you trust the site.
FolderUploadPrompt.acceptButtonLabel = Upload
InputPickerBlockedNoUserActivation=<input> picker was blocked due to lack of user activation.