Bug 1777497, part 3 - Require a grant (auto or manual) for the requestStorageAccessUnderSite permission, r=timhuang,pbz,anti-tracking-reviewers

Depends on D151279

Differential Revision: https://phabricator.services.mozilla.com/D151280
This commit is contained in:
Benjamin VanderSloot 2022-08-12 16:12:06 +00:00
Родитель 04fdece310
Коммит 5eb779d9f9
6 изменённых файлов: 116 добавлений и 13 удалений

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

@ -282,6 +282,7 @@
#include "nsDeviceContext.h"
#include "nsDocShell.h"
#include "nsDocShellLoadTypes.h"
#include "nsEffectiveTLDService.h"
#include "nsError.h"
#include "nsEscape.h"
#include "nsFocusManager.h"
@ -17159,18 +17160,64 @@ 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
ContentChild* cc = ContentChild::GetSingleton();
if (!cc) {
// TODO(bug 1778561): Make this work in non-content processes.
// Test if the permission this is requesting is already set
nsCOMPtr<nsIPrincipal> argumentPrincipal =
BasePrincipal::CreateContentPrincipal(
siteURI, NodePrincipal()->OriginAttributesRef());
if (!argumentPrincipal) {
this->ConsumeTransientUserGestureActivation();
promise->MaybeRejectWithUndefined();
return promise.forget();
}
cc->SendSetAllowStorageAccessRequestFlag(NodePrincipal(), siteURI)
nsCString originNoSuffix;
rv = NodePrincipal()->GetOriginNoSuffix(originNoSuffix);
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->MaybeRejectWithUndefined();
return promise.forget();
}
ContentChild* cc = ContentChild::GetSingleton();
MOZ_ASSERT(cc);
RefPtr<Document> self(this);
cc->SendTestStorageAccessPermission(argumentPrincipal, originNoSuffix)
->Then(
GetCurrentSerialEventTarget(), __func__,
[promise, siteURI,
self](const ContentChild::TestStorageAccessPermissionPromise::
ResolveValueType& aResult) {
if (aResult) {
return StorageAccessAPIHelper::
StorageAccessPermissionGrantPromise::CreateAndResolve(
StorageAccessAPIHelper::eAllow, __func__);
}
// Get a grant for the storage access permission that will be set
// when this is completed in the embedding context
nsCString serializedSite;
RefPtr<nsEffectiveTLDService> etld =
nsEffectiveTLDService::GetInstance();
if (!etld) {
return StorageAccessAPIHelper::
StorageAccessPermissionGrantPromise::CreateAndReject(
false, __func__);
}
nsresult rv = etld->GetSite(siteURI, serializedSite);
if (NS_FAILED(rv)) {
return StorageAccessAPIHelper::
StorageAccessPermissionGrantPromise::CreateAndReject(
false, __func__);
}
return self->CreatePermissionGrantPromise(
self->GetInnerWindow(), self->NodePrincipal(), true,
Some(serializedSite))();
},
[](const ContentChild::TestStorageAccessPermissionPromise::
RejectValueType& aResult) {
return StorageAccessAPIHelper::StorageAccessPermissionGrantPromise::
CreateAndReject(false, __func__);
})
->Then(
GetCurrentSerialEventTarget(), __func__,
[promise, principal, siteURI](int result) {
@ -17178,11 +17225,26 @@ already_AddRefed<Promise> Document::RequestStorageAccessUnderSite(
if (!cc) {
// TODO(bug 1778561): Make this work in non-content processes.
promise->MaybeRejectWithUndefined();
return;
}
// Set a permission in the parent process that this document wants
// storage access under the argument's site, resolving our returned
// promise on success
cc->SendSetAllowStorageAccessRequestFlag(principal, siteURI)
->Then(
GetCurrentSerialEventTarget(), __func__,
[promise](bool success) {
if (success) {
promise->MaybeResolveWithUndefined();
} else {
promise->MaybeRejectWithUndefined();
}
},
[promise](mozilla::ipc::ResponseRejectReason reason) {
promise->MaybeRejectWithUndefined();
});
},
[promise](mozilla::ipc::ResponseRejectReason reason) {
promise->MaybeRejectWithUndefined();
});
[promise](bool result) { promise->MaybeRejectWithUndefined(); });
// Return the promise that is resolved in the async handler above
return promise.forget();

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

@ -6748,6 +6748,38 @@ mozilla::ipc::IPCResult ContentParent::RecvTestCookiePermissionDecided(
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvTestStorageAccessPermission(
nsIPrincipal* aEmbeddingPrincipal, const nsCString& aEmbeddedOrigin,
const TestStorageAccessPermissionResolver&& aResolver) {
// Get the permission manager and build the key.
RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
if (!permManager) {
aResolver(Nothing());
return IPC_OK();
}
nsCString requestPermissionKey;
AntiTrackingUtils::CreateStoragePermissionKey(aEmbeddedOrigin,
requestPermissionKey);
// Test the permission
uint32_t access = nsIPermissionManager::UNKNOWN_ACTION;
nsresult rv = permManager->TestPermissionFromPrincipal(
aEmbeddingPrincipal, requestPermissionKey, &access);
if (NS_FAILED(rv)) {
aResolver(Nothing());
return IPC_OK();
}
if (access == nsIPermissionManager::ALLOW_ACTION) {
aResolver(Some(true));
} else if (access == nsIPermissionManager::DENY_ACTION) {
aResolver(Some(false));
} else {
aResolver(Nothing());
}
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaPlaybackChanged(
const MaybeDiscarded<BrowsingContext>& aContext,
MediaPlaybackState aState) {

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

@ -1274,6 +1274,10 @@ class ContentParent final : public PContentParent,
const MaybeDiscarded<BrowsingContext>& aContext, nsIPrincipal* aPrincipal,
const TestCookiePermissionDecidedResolver&& aResolver);
mozilla::ipc::IPCResult RecvTestStorageAccessPermission(
nsIPrincipal* aEmbeddingPrincipal, const nsCString& aEmbeddedOrigin,
const TestStorageAccessPermissionResolver&& aResolver);
mozilla::ipc::IPCResult RecvNotifyMediaPlaybackChanged(
const MaybeDiscarded<BrowsingContext>& aContext,
MediaPlaybackState aState);

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

@ -1669,6 +1669,10 @@ parent:
nsIPrincipal aPrincipal)
returns (bool? allowed);
async TestStorageAccessPermission(nsIPrincipal aEmbeddingPrincipal,
nsCString aEmbeddedOrigin)
returns (bool? allowed);
/**
* When media element's controlled state changed in the content process, we
* have to notify the chrome process in order to update the status of the

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

@ -984,8 +984,8 @@ StorageAccessAPIHelper::RequestStorageAccessAsyncHelper(
aInnerWindow, principal, aHasUserInteraction, Nothing());
// Try to allow access for the given principal.
return StorageAccessAPIHelper::AllowAccessFor(principal, aBrowsingContext,
aNotifier, performPermissionGrant);
return StorageAccessAPIHelper::AllowAccessFor(
principal, aBrowsingContext, aNotifier, performPermissionGrant);
}
// There are two methods to handle permission update:

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

@ -163,7 +163,8 @@ class StorageAccessAPIHelper final {
// 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(
static RefPtr<StorageAccessPermissionGrantPromise>
RequestStorageAccessAsyncHelper(
dom::Document* aDocument, nsPIDOMWindowInner* aInnerWindow,
dom::BrowsingContext* aBrowsingContext, nsIPrincipal* aPrincipal,
bool aHasUserInteraction,