Bug 1777497, part 2 - Make "finalChecks" callback creation easier to use flexibly, r=anti-tracking-reviewers,pbz,timhuang

Depends on D151278

Differential Revision: https://phabricator.services.mozilla.com/D151279
This commit is contained in:
Benjamin VanderSloot 2022-08-12 16:12:05 +00:00
Родитель 64d2f3f974
Коммит 04fdece310
4 изменённых файлов: 77 добавлений и 51 удалений

Просмотреть файл

@ -16661,31 +16661,24 @@ Document::GetContentBlockingEvents() {
});
}
RefPtr<MozPromise<int, bool, true>> Document::RequestStorageAccessAsyncHelper(
nsPIDOMWindowInner* aInnerWindow, BrowsingContext* aBrowsingContext,
nsIPrincipal* aPrincipal, bool aHasUserInteraction,
ContentBlockingNotifier::StorageAccessPermissionGrantedReason aNotifier,
bool requireFinalChecks) {
if (!requireFinalChecks) {
// Try to allow access for the given principal.
return StorageAccessAPIHelper::AllowAccessFor(aPrincipal, aBrowsingContext,
aNotifier);
}
StorageAccessAPIHelper::PerformPermissionGrant
Document::CreatePermissionGrantPromise(
nsPIDOMWindowInner* aInnerWindow, nsIPrincipal* aPrincipal,
bool aHasUserInteraction, const Maybe<nsCString>& aTopLevelBaseDomain) {
MOZ_ASSERT(aInnerWindow);
MOZ_ASSERT(aPrincipal);
RefPtr<Document> self(this);
RefPtr<nsPIDOMWindowInner> inner(aInnerWindow);
RefPtr<nsIPrincipal> principal(aPrincipal);
// This is a lambda function that has some variables bound to it. It will be
// called later in CompleteAllowAccessFor inside of AllowAccessFor.
auto performFinalChecks = [inner, self, principal, aHasUserInteraction]() {
return [inner, self, principal, aHasUserInteraction, aTopLevelBaseDomain]() {
// Create the user prompt
RefPtr<StorageAccessAPIHelper::StorageAccessFinalCheckPromise::Private> p =
new StorageAccessAPIHelper::StorageAccessFinalCheckPromise::Private(
__func__);
RefPtr<StorageAccessAPIHelper::StorageAccessPermissionGrantPromise::Private>
p = new StorageAccessAPIHelper::StorageAccessPermissionGrantPromise::
Private(__func__);
RefPtr<StorageAccessPermissionRequest> sapr =
StorageAccessPermissionRequest::Create(
inner, principal,
inner, principal, aTopLevelBaseDomain,
// Allow
[p] {
Telemetry::AccumulateCategorical(
@ -16768,10 +16761,6 @@ RefPtr<MozPromise<int, bool, true>> Document::RequestStorageAccessAsyncHelper(
return p;
};
// Try to allow access for the given principal.
return StorageAccessAPIHelper::AllowAccessFor(principal, aBrowsingContext,
aNotifier, performFinalChecks);
}
already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccess(
@ -16906,9 +16895,9 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccess(
// perform an automatic decision or notify the user, then perform some follow
// on work changing state to reflect the result of the API. If it resolves,
// the request was granted. If it rejects it was denied.
RequestStorageAccessAsyncHelper(inner, bc, NodePrincipal(), true,
ContentBlockingNotifier::eStorageAccessAPI,
true)
StorageAccessAPIHelper::RequestStorageAccessAsyncHelper(
this, inner, bc, NodePrincipal(), true,
ContentBlockingNotifier::eStorageAccessAPI, true)
->Then(
GetCurrentSerialEventTarget(), __func__,
[self, inner, promise] {
@ -17061,8 +17050,8 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccessForOrigin(
// Step 4c: Try to request storage access, either automatically or
// with a user-prompt. This is the part that is async in the
// typical requestStorageAccess function.
return self->RequestStorageAccessAsyncHelper(
inner, bc, principal, hasUserActivation,
return StorageAccessAPIHelper::RequestStorageAccessAsyncHelper(
self, inner, bc, principal, hasUserActivation,
ContentBlockingNotifier::ePrivilegeStorageAccessForOriginAPI,
true);
},
@ -17170,6 +17159,8 @@ already_AddRefed<Promise> Document::RequestStorageAccessUnderSite(
promise->MaybeRejectWithUndefined();
return promise.forget();
}
nsCOMPtr<nsIPrincipal> principal(NodePrincipal());
// Set a permission in the parent process that this document wants storage
// access under the argument's site, resolving our returned promise on success
@ -17182,10 +17173,10 @@ already_AddRefed<Promise> Document::RequestStorageAccessUnderSite(
cc->SendSetAllowStorageAccessRequestFlag(NodePrincipal(), siteURI)
->Then(
GetCurrentSerialEventTarget(), __func__,
[promise](bool success) {
if (success) {
promise->MaybeResolveWithUndefined();
} else {
[promise, principal, siteURI](int result) {
ContentChild* cc = ContentChild::GetSingleton();
if (!cc) {
// TODO(bug 1778561): Make this work in non-content processes.
promise->MaybeRejectWithUndefined();
}
},
@ -17330,8 +17321,8 @@ already_AddRefed<Promise> Document::CompleteStorageAccessRequestFromSite(
// We ignore the final checks because this is where the "grant"
// either by prompt doorhanger or autogrant takes place. We already
// gathered an equivalent grant in requestStorageAccessUnderSite.
return self->RequestStorageAccessAsyncHelper(
inner, bc, principal, true,
return StorageAccessAPIHelper::RequestStorageAccessAsyncHelper(
self, inner, bc, principal, true,
ContentBlockingNotifier::eStorageAccessAPI, false);
},
// If the IPC rejects, we should reject our promise here which will

Просмотреть файл

@ -40,6 +40,7 @@
#include "mozilla/RefPtr.h"
#include "mozilla/Result.h"
#include "mozilla/SegmentedVector.h"
#include "mozilla/StorageAccessAPIHelper.h"
#include "mozilla/TaskCategory.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
@ -1260,16 +1261,10 @@ class Document : public nsINode,
nsresult HasStorageAccessSync(bool& aHasStorageAccess);
already_AddRefed<Promise> HasStorageAccess(ErrorResult& aRv);
// This function performs the asynchronous portion of checking if requests
// for storage access will be sucessful or not. This includes creating a
// permission prompt request and trying to perform an "autogrant"
// This will return a promise whose values correspond to those of a
// ContentBlocking::AllowAccessFor call that ends the funciton.
RefPtr<MozPromise<int, bool, true>> RequestStorageAccessAsyncHelper(
nsPIDOMWindowInner* aInnerWindow, BrowsingContext* aBrowsingContext,
nsIPrincipal* aPrincipal, bool aHasUserInteraction,
ContentBlockingNotifier::StorageAccessPermissionGrantedReason aNotifier,
bool performFinalChecks);
StorageAccessAPIHelper::PerformPermissionGrant CreatePermissionGrantPromise(
nsPIDOMWindowInner* aInnerWindow, nsIPrincipal* aPrincipal,
bool aHasUserInteraction, const Maybe<nsCString>& aTopLevelBaseDomain);
already_AddRefed<Promise> RequestStorageAccess(ErrorResult& aRv);
already_AddRefed<Promise> RequestStorageAccessForOrigin(

Просмотреть файл

@ -70,7 +70,7 @@ bool GetTopLevelWindowId(BrowsingContext* aParentContext, uint32_t aBehavior,
StorageAccessAPIHelper::AllowAccessFor(
nsIPrincipal* aPrincipal, dom::BrowsingContext* aParentContext,
ContentBlockingNotifier::StorageAccessPermissionGrantedReason aReason,
const StorageAccessAPIHelper::PerformFinalChecks& aPerformFinalChecks) {
const StorageAccessAPIHelper::PerformPermissionGrant& aPerformFinalChecks) {
MOZ_ASSERT(aParentContext);
switch (aReason) {
@ -289,7 +289,7 @@ StorageAccessAPIHelper::AllowAccessFor(
}
MOZ_ASSERT(XRE_IsContentProcess());
// Only support PerformFinalChecks when we run ::CompleteAllowAccessFor in
// Only support PerformPermissionGrant when we run ::CompleteAllowAccessFor in
// the same process. This callback is only used by eStorageAccessAPI,
// which is always runned in the same process.
MOZ_ASSERT(!aPerformFinalChecks);
@ -361,7 +361,7 @@ StorageAccessAPIHelper::CompleteAllowAccessFor(
nsIPrincipal* aTrackingPrincipal, const nsACString& aTrackingOrigin,
uint32_t aCookieBehavior,
ContentBlockingNotifier::StorageAccessPermissionGrantedReason aReason,
const PerformFinalChecks& aPerformFinalChecks) {
const PerformPermissionGrant& aPerformFinalChecks) {
MOZ_ASSERT(aParentContext);
MOZ_ASSERT_IF(XRE_IsContentProcess(), aParentContext->IsInProcess());
@ -960,6 +960,34 @@ StorageAccessAPIHelper::CheckExistingPermissionDecidesStorageAccessAPI(
return Nothing();
}
// static
RefPtr<StorageAccessAPIHelper::StorageAccessPermissionGrantPromise>
StorageAccessAPIHelper::RequestStorageAccessAsyncHelper(
dom::Document* aDocument, nsPIDOMWindowInner* aInnerWindow,
dom::BrowsingContext* aBrowsingContext, nsIPrincipal* aPrincipal,
bool aHasUserInteraction,
ContentBlockingNotifier::StorageAccessPermissionGrantedReason aNotifier,
bool aRequireGrant) {
MOZ_ASSERT(aDocument);
if (!aRequireGrant) {
// Try to allow access for the given principal.
return StorageAccessAPIHelper::AllowAccessFor(aPrincipal, aBrowsingContext,
aNotifier);
}
RefPtr<nsIPrincipal> principal(aPrincipal);
// This is a lambda function that has some variables bound to it. It will be
// called later in CompleteAllowAccessFor inside of AllowAccessFor.
auto performPermissionGrant = aDocument->CreatePermissionGrantPromise(
aInnerWindow, principal, aHasUserInteraction, Nothing());
// Try to allow access for the given principal.
return StorageAccessAPIHelper::AllowAccessFor(principal, aBrowsingContext,
aNotifier, performPermissionGrant);
}
// There are two methods to handle permission update:
// 1. UpdateAllowAccessOnCurrentProcess
// 2. UpdateAllowAccessOnParentProcess

Просмотреть файл

@ -53,15 +53,14 @@ class StorageAccessAPIHelper final {
// Ex: example.net import tracker.com/script.js which does opens a popup and
// the user interacts with it. tracker.com is allowed when loaded by
// example.net.
typedef MozPromise<int, bool, true> StorageAccessFinalCheckPromise;
typedef std::function<RefPtr<StorageAccessFinalCheckPromise>()>
PerformFinalChecks;
typedef MozPromise<int, bool, true> StorageAccessPermissionGrantPromise;
typedef std::function<RefPtr<StorageAccessPermissionGrantPromise>()>
PerformPermissionGrant;
[[nodiscard]] static RefPtr<StorageAccessPermissionGrantPromise>
AllowAccessFor(
nsIPrincipal* aPrincipal, dom::BrowsingContext* aParentContext,
ContentBlockingNotifier::StorageAccessPermissionGrantedReason aReason,
const PerformFinalChecks& aPerformFinalChecks = nullptr);
const PerformPermissionGrant& aPerformFinalChecks = nullptr);
// This function handles tasks that have to be done in the process
// of the window that we just grant permission for.
@ -158,6 +157,19 @@ class StorageAccessAPIHelper final {
static Maybe<bool> CheckExistingPermissionDecidesStorageAccessAPI(
dom::Document* aDocument, bool aRequestingStorageAccess);
// This function performs the asynchronous portion of checking if requests
// for storage access will be successful or not. This includes calling
// Document member functions that creating a permission prompt request and
// trying to perform an "autogrant" if aRequireGrant is true.
// This will return a promise whose values correspond to those of a
// ContentBlocking::AllowAccessFor call that ends the function.
static RefPtr<StorageAccessPermissionGrantPromise> RequestStorageAccessAsyncHelper(
dom::Document* aDocument, nsPIDOMWindowInner* aInnerWindow,
dom::BrowsingContext* aBrowsingContext, nsIPrincipal* aPrincipal,
bool aHasUserInteraction,
ContentBlockingNotifier::StorageAccessPermissionGrantedReason aNotifier,
bool aRequireGrant);
private:
friend class dom::ContentParent;
// This should be running either in the parent process or in the child
@ -168,7 +180,7 @@ class StorageAccessAPIHelper final {
nsIPrincipal* aTrackingPrincipal, const nsACString& aTrackingOrigin,
uint32_t aCookieBehavior,
ContentBlockingNotifier::StorageAccessPermissionGrantedReason aReason,
const PerformFinalChecks& aPerformFinalChecks = nullptr);
const PerformPermissionGrant& aPerformFinalChecks = nullptr);
static void UpdateAllowAccessOnCurrentProcess(
dom::BrowsingContext* aParentContext, const nsACString& aTrackingOrigin);