mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1583142 - Remove third-party "persistent-storage" prompting support r=baku
Differential Revision: https://phabricator.services.mozilla.com/D50908 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
dcda6f6b3d
commit
f431604a62
@ -423,6 +423,12 @@ pref("permissions.postPrompt.animate", true);
|
||||
pref("permissions.eventTelemetry.enabled", false);
|
||||
#endif
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("permissions.delegation.enable", true);
|
||||
#else
|
||||
pref("permissions.delegation.enable", false);
|
||||
#endif
|
||||
|
||||
// handle links targeting new windows
|
||||
// 1=current window/tab, 2=new window, 3=new tab in most recent window
|
||||
pref("browser.link.open_newwindow", 3);
|
||||
|
@ -15147,6 +15147,11 @@ PermissionDelegateHandler* Document::GetPermissionDelegateHandler() {
|
||||
mPermissionDelegateHandler =
|
||||
mozilla::MakeAndAddRef<PermissionDelegateHandler>(this);
|
||||
}
|
||||
|
||||
if (!mPermissionDelegateHandler->Initialize()) {
|
||||
mPermissionDelegateHandler = nullptr;
|
||||
}
|
||||
|
||||
return mPermissionDelegateHandler;
|
||||
}
|
||||
|
||||
|
@ -4596,7 +4596,7 @@ class Document : public nsINode,
|
||||
UniquePtr<ResizeObserverController> mResizeObserverController;
|
||||
|
||||
// Permission Delegate Handler, lazily-initialized in
|
||||
// PermissionDelegateHandler
|
||||
// GetPermissionDelegateHandler
|
||||
RefPtr<PermissionDelegateHandler> mPermissionDelegateHandler;
|
||||
|
||||
// True if BIDI is enabled.
|
||||
|
@ -563,6 +563,8 @@ ContentPermissionRequestBase::ContentPermissionRequestBase(
|
||||
return;
|
||||
}
|
||||
|
||||
mPermissionHandler = doc->GetPermissionDelegateHandler();
|
||||
|
||||
mUserHadInteractedWithDocument = doc->UserHasInteracted();
|
||||
|
||||
nsDOMNavigationTiming* navTiming = doc->GetNavigationTiming();
|
||||
@ -655,8 +657,25 @@ ContentPermissionRequestBase::CheckPromptPrefs() {
|
||||
return PromptResult::Pending;
|
||||
}
|
||||
|
||||
bool ContentPermissionRequestBase::CheckPermissionDelegate() {
|
||||
// There is case that ContentPermissionRequestBase is constructed without
|
||||
// window, then mPermissionHandler will be null. So we only check permission
|
||||
// delegate if we have non-null mPermissionHandler
|
||||
if (mPermissionHandler &&
|
||||
!mPermissionHandler->HasPermissionDelegated(mType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult ContentPermissionRequestBase::ShowPrompt(
|
||||
ContentPermissionRequestBase::PromptResult& aResult) {
|
||||
if (!CheckPermissionDelegate()) {
|
||||
aResult = PromptResult::Denied;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aResult = CheckPromptPrefs();
|
||||
|
||||
if (aResult != PromptResult::Pending) {
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "mozilla/dom/PContentPermissionRequestChild.h"
|
||||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "PermissionDelegateHandler.h"
|
||||
|
||||
// Microsoft's API Name hackery sucks
|
||||
// XXXbz Doing this in a header is a gigantic footgun. See
|
||||
@ -140,6 +141,9 @@ class ContentPermissionRequestBase : public nsIContentPermissionRequest {
|
||||
|
||||
PromptResult CheckPromptPrefs();
|
||||
|
||||
// Check if the permission has an opportunity to request.
|
||||
bool CheckPermissionDelegate();
|
||||
|
||||
enum class DelayedTaskType {
|
||||
Allow,
|
||||
Deny,
|
||||
@ -158,6 +162,7 @@ class ContentPermissionRequestBase : public nsIContentPermissionRequest {
|
||||
nsCOMPtr<nsIPrincipal> mTopLevelPrincipal;
|
||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
||||
nsCOMPtr<nsIContentPermissionRequester> mRequester;
|
||||
RefPtr<PermissionDelegateHandler> mPermissionHandler;
|
||||
nsCString mPrefName;
|
||||
nsCString mType;
|
||||
bool mIsHandlingUserInput;
|
||||
|
@ -79,6 +79,10 @@ nsresult PermissionStatus::UpdateState() {
|
||||
|
||||
PermissionDelegateHandler* permissionHandler =
|
||||
document->GetPermissionDelegateHandler();
|
||||
if (NS_WARN_IF(!permissionHandler)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = permissionHandler->GetPermissionForPermissionsAPI(
|
||||
PermissionNameToType(mName), &action);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -92,7 +92,7 @@
|
||||
top: UNKNOWN_ACTION,
|
||||
name: 'persistent-storage',
|
||||
type: 'persistent-storage',
|
||||
expected: 'prompt',
|
||||
expected: 'denied',
|
||||
},
|
||||
{
|
||||
id: 'query navigation top prompt',
|
||||
@ -120,7 +120,7 @@
|
||||
top: PROMPT_ACTION,
|
||||
name: 'persistent-storage',
|
||||
type: 'persistent-storage',
|
||||
expected: 'prompt',
|
||||
expected: 'denied',
|
||||
},
|
||||
{
|
||||
id: 'query navigation top denied',
|
||||
@ -148,7 +148,7 @@
|
||||
top: DENY_ACTION,
|
||||
name: 'persistent-storage',
|
||||
type: 'persistent-storage',
|
||||
expected: 'prompt',
|
||||
expected: 'denied',
|
||||
},
|
||||
{
|
||||
id: 'query navigation top granted',
|
||||
@ -176,7 +176,7 @@
|
||||
top: ALLOW_ACTION,
|
||||
name: 'persistent-storage',
|
||||
type: 'persistent-storage',
|
||||
expected: 'prompt',
|
||||
expected: 'denied',
|
||||
},
|
||||
{
|
||||
id: 'query navigation top denied, iframe has allow attribute',
|
||||
|
@ -286,6 +286,8 @@ already_AddRefed<Promise> ExecuteOpOnMainOrWorkerThread(
|
||||
// In private browsing mode, no permission prompt.
|
||||
if (nsContentUtils::IsInPrivateBrowsing(doc)) {
|
||||
aRv = request->Cancel();
|
||||
} else if (!request->CheckPermissionDelegate()) {
|
||||
aRv = request->Cancel();
|
||||
} else {
|
||||
aRv = request->Start();
|
||||
}
|
||||
|
@ -5,7 +5,9 @@ support-files =
|
||||
browser_permissionsPrompt.html
|
||||
head-shared.js
|
||||
head.js
|
||||
empty.html
|
||||
|
||||
[browser_permissionsCrossOrigin.js]
|
||||
[browser_permissionsPromptAllow.js]
|
||||
skip-if = fission
|
||||
[browser_permissionsPromptDeny.js]
|
||||
|
56
dom/quota/test/browser_permissionsCrossOrigin.js
Normal file
56
dom/quota/test/browser_permissionsCrossOrigin.js
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
const emptyURL = "https://example.com/browser/dom/quota/test/empty.html";
|
||||
|
||||
add_task(async function testNoPermissionPrompt() {
|
||||
registerPopupEventHandler("popupshowing", function() {
|
||||
ok(false, "Shouldn't show a popup this time");
|
||||
});
|
||||
registerPopupEventHandler("popupshown", function() {
|
||||
ok(false, "Shouldn't show a popup this time");
|
||||
});
|
||||
registerPopupEventHandler("popuphidden", function() {
|
||||
ok(false, "Shouldn't show a popup this time");
|
||||
});
|
||||
|
||||
info("Creating tab");
|
||||
|
||||
await BrowserTestUtils.withNewTab(emptyURL, async function(browser) {
|
||||
await new Promise(r => {
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{
|
||||
set: [
|
||||
["dom.security.featurePolicy.enabled", true],
|
||||
["permissions.delegation.enable", true],
|
||||
["dom.security.featurePolicy.header.enabled", true],
|
||||
["dom.security.featurePolicy.webidl.enabled", true],
|
||||
],
|
||||
},
|
||||
r
|
||||
);
|
||||
});
|
||||
|
||||
await ContentTask.spawn(browser, null, async function(host0) {
|
||||
let frame = content.document.createElement("iframe");
|
||||
// Cross origin src
|
||||
frame.src = "https://example.org/browser/dom/quota/test/empty.html";
|
||||
content.document.body.appendChild(frame);
|
||||
await ContentTaskUtils.waitForEvent(frame, "load");
|
||||
|
||||
await content.SpecialPowers.spawn(frame, [], async function() {
|
||||
// Request a permission.
|
||||
const persistAllowed = await this.content.navigator.storage.persist();
|
||||
Assert.ok(
|
||||
!persistAllowed,
|
||||
"navigator.storage.persist() has been denied"
|
||||
);
|
||||
});
|
||||
content.document.body.removeChild(frame);
|
||||
});
|
||||
});
|
||||
|
||||
unregisterAllPopupEventHandlers();
|
||||
});
|
8
dom/quota/test/empty.html
Normal file
8
dom/quota/test/empty.html
Normal file
@ -0,0 +1,8 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Empty file</title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
@ -7,10 +7,11 @@
|
||||
#include "nsGlobalWindowInner.h"
|
||||
#include "PermissionDelegateHandler.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsPermissionManager.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StaticPrefs_permissions.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/FeaturePolicyUtils.h"
|
||||
|
||||
@ -24,9 +25,12 @@ typedef PermissionDelegateHandler::PermissionDelegateInfo DelegateInfo;
|
||||
static const DelegateInfo sPermissionsMap[] = {
|
||||
// Permissions API map
|
||||
{"geo", u"geolocation", DelegatePolicy::eDelegateUseFeaturePolicy},
|
||||
// The same with geo, but we support both to save some conversions between
|
||||
// "geo" and "geolocation"
|
||||
{"geolocation", u"geolocation", DelegatePolicy::eDelegateUseFeaturePolicy},
|
||||
{"desktop-notification", nullptr,
|
||||
DelegatePolicy::ePersistDeniedCrossOrigin},
|
||||
{"persistent-storage", nullptr, DelegatePolicy::eDelegateUseIframeOrigin},
|
||||
{"persistent-storage", nullptr, DelegatePolicy::ePersistDeniedCrossOrigin},
|
||||
};
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(PermissionDelegateHandler)
|
||||
@ -56,48 +60,87 @@ const DelegateInfo* PermissionDelegateHandler::GetPermissionDelegateInfo(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsresult PermissionDelegateHandler::GetPermissionForPermissionsAPI(
|
||||
const nsACString& aType, uint32_t* aPermission) {
|
||||
bool PermissionDelegateHandler::Initialize() {
|
||||
MOZ_ASSERT(mDocument);
|
||||
|
||||
mPermissionManager = nsPermissionManager::GetInstance();
|
||||
if (!mPermissionManager) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mPrincipal = mDocument->NodePrincipal();
|
||||
nsPIDOMWindowInner* window = mDocument->GetInnerWindow();
|
||||
nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(window);
|
||||
if (innerWindow) {
|
||||
mTopLevelPrincipal = innerWindow->GetTopLevelAntiTrackingPrincipal();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsTopWindowContent(Document* aDocument) {
|
||||
MOZ_ASSERT(aDocument);
|
||||
|
||||
BrowsingContext* browsingContext = aDocument->GetBrowsingContext();
|
||||
return browsingContext && browsingContext->IsTopContent();
|
||||
}
|
||||
|
||||
bool PermissionDelegateHandler::HasPermissionDelegated(
|
||||
const nsACString& aType) {
|
||||
MOZ_ASSERT(mDocument);
|
||||
|
||||
if (!StaticPrefs::permissions_delegation_enable()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// System principal should have right to make permission request
|
||||
if (mPrincipal->IsSystemPrincipal()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const DelegateInfo* info =
|
||||
GetPermissionDelegateInfo(NS_ConvertUTF8toUTF16(aType));
|
||||
|
||||
// If the type is not in the supported list, auto denied
|
||||
if (!info) {
|
||||
*aPermission = nsIPermissionManager::DENY_ACTION;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info->mPolicy == DelegatePolicy::eDelegateUseFeaturePolicy &&
|
||||
info->mFeatureName) {
|
||||
nsAutoString featureName(info->mFeatureName);
|
||||
// Default allowlist for a feature used in permissions delegate should be
|
||||
// set to eSelf, to ensure that permission is denied by default and only
|
||||
// have the opportunity to request permission with allow attribute.
|
||||
if (!FeaturePolicyUtils::IsFeatureAllowed(mDocument, featureName)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->mPolicy == DelegatePolicy::ePersistDeniedCrossOrigin &&
|
||||
!IsTopWindowContent(mDocument) &&
|
||||
!mPrincipal->Subsumes(mTopLevelPrincipal)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult PermissionDelegateHandler::GetPermission(const nsACString& aType,
|
||||
uint32_t* aPermission,
|
||||
bool aExactHostMatch) {
|
||||
MOZ_ASSERT(mDocument);
|
||||
|
||||
if (mPrincipal->IsSystemPrincipal()) {
|
||||
*aPermission = nsIPermissionManager::ALLOW_ACTION;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPermissionManager> permMgr =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
*aPermission = nsIPermissionManager::DENY_ACTION;
|
||||
return rv;
|
||||
}
|
||||
const DelegateInfo* info =
|
||||
GetPermissionDelegateInfo(NS_ConvertUTF8toUTF16(aType));
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = mDocument->NodePrincipal();
|
||||
if (!Preferences::GetBool("permissions.delegation.enable", false)) {
|
||||
return permMgr->TestPermissionFromPrincipal(principal, aType, aPermission);
|
||||
}
|
||||
|
||||
if (mDocument->GetWindow()->IsTopLevelWindow() ||
|
||||
info->mPolicy == DelegatePolicy::eDelegateUseIframeOrigin) {
|
||||
return permMgr->TestPermissionFromPrincipal(principal, aType, aPermission);
|
||||
}
|
||||
|
||||
nsPIDOMWindowInner* window = mDocument->GetInnerWindow();
|
||||
nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(window);
|
||||
nsIPrincipal* topPrincipal = innerWindow->GetTopLevelAntiTrackingPrincipal();
|
||||
|
||||
// Permission is delegated in same origin
|
||||
if (principal->Subsumes(topPrincipal)) {
|
||||
return permMgr->TestPermissionFromPrincipal(topPrincipal, aType,
|
||||
aPermission);
|
||||
}
|
||||
|
||||
if (info->mPolicy == DelegatePolicy::ePersistDeniedCrossOrigin) {
|
||||
// If the type is not in the supported list, auto denied
|
||||
if (!info) {
|
||||
*aPermission = nsIPermissionManager::DENY_ACTION;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -114,5 +157,35 @@ nsresult PermissionDelegateHandler::GetPermissionForPermissionsAPI(
|
||||
}
|
||||
}
|
||||
|
||||
return permMgr->TestPermissionFromPrincipal(topPrincipal, aType, aPermission);
|
||||
if (info->mPolicy == DelegatePolicy::ePersistDeniedCrossOrigin &&
|
||||
!IsTopWindowContent(mDocument) &&
|
||||
!mPrincipal->Subsumes(mTopLevelPrincipal)) {
|
||||
*aPermission = nsIPermissionManager::DENY_ACTION;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult (nsIPermissionManager::*testPermission)(
|
||||
nsIPrincipal*, const nsACString&, uint32_t*) =
|
||||
aExactHostMatch ? &nsIPermissionManager::TestExactPermissionFromPrincipal
|
||||
: &nsIPermissionManager::TestPermissionFromPrincipal;
|
||||
|
||||
if (!StaticPrefs::permissions_delegation_enable()) {
|
||||
return (mPermissionManager->*testPermission)(mPrincipal, aType,
|
||||
aPermission);
|
||||
}
|
||||
|
||||
nsIPrincipal* principal = mPrincipal;
|
||||
if (mTopLevelPrincipal &&
|
||||
(info->mPolicy == DelegatePolicy::eDelegateUseTopOrigin ||
|
||||
(info->mPolicy == DelegatePolicy::eDelegateUseFeaturePolicy &&
|
||||
StaticPrefs::dom_security_featurePolicy_enabled()))) {
|
||||
principal = mTopLevelPrincipal;
|
||||
}
|
||||
|
||||
return (mPermissionManager->*testPermission)(principal, aType, aPermission);
|
||||
}
|
||||
|
||||
nsresult PermissionDelegateHandler::GetPermissionForPermissionsAPI(
|
||||
const nsACString& aType, uint32_t* aPermission) {
|
||||
return GetPermission(aType, aPermission, false);
|
||||
}
|
||||
|
@ -28,6 +28,9 @@
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
class nsIContentPermissionRequest;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Document;
|
||||
@ -41,9 +44,34 @@ class PermissionDelegateHandler final : nsISupports {
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(PermissionDelegateHandler)
|
||||
|
||||
bool Initialize();
|
||||
|
||||
/*
|
||||
* Get permission state for permission api with aType, which applied
|
||||
* Indicates if we has the right to make permission request with aType
|
||||
*/
|
||||
bool HasPermissionDelegated(const nsACString& aType);
|
||||
|
||||
/*
|
||||
* Get permission state, which applied permission delegate policy.
|
||||
*
|
||||
* @param aType the permission type to get
|
||||
* @param aPermission out argument which will be a permission type that we
|
||||
* will return from this function.
|
||||
* @param aExactHostMatch whether to look for the exact host name or also for
|
||||
* subdomains that can have the same permission.
|
||||
*/
|
||||
nsresult GetPermission(const nsACString& aType, uint32_t* aPermission,
|
||||
bool aExactHostMatch);
|
||||
|
||||
/*
|
||||
* Get permission state for permission api, which applied
|
||||
* permission delegate policy.
|
||||
*
|
||||
* @param aType the permission type to get
|
||||
* @param aExactHostMatch whether to look for the exact host name or also for
|
||||
* subdomains that can have the same permission.
|
||||
* @param aPermission out argument which will be a permission type that we
|
||||
* will return from this function.
|
||||
*/
|
||||
nsresult GetPermissionForPermissionsAPI(const nsACString& aType,
|
||||
uint32_t* aPermission);
|
||||
@ -91,13 +119,18 @@ class PermissionDelegateHandler final : nsISupports {
|
||||
virtual ~PermissionDelegateHandler() = default;
|
||||
|
||||
/*
|
||||
* Helper function to return the delegate info value for aPermissionName.
|
||||
* Helper function to return the delegate info value for aPermissionName.
|
||||
* @param aPermissionName the permission name to get
|
||||
*/
|
||||
const PermissionDelegateInfo* GetPermissionDelegateInfo(
|
||||
const nsAString& aPermissionName) const;
|
||||
|
||||
// A weak pointer to our document. Nulled out by DropDocumentReference.
|
||||
mozilla::dom::Document* mDocument;
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsCOMPtr<nsIPrincipal> mTopLevelPrincipal;
|
||||
RefPtr<nsIPermissionManager> mPermissionManager;
|
||||
};
|
||||
|
||||
#endif // PermissionDelegateHandler_h__
|
||||
|
Loading…
Reference in New Issue
Block a user