Backed out 5 changesets (bug 1765313, bug 1770403) for causing bc failures on browser_storageAccessPrivilegeAPI.js. CLOSED TREE

Backed out changeset 22153c8641e1 (bug 1765313)
Backed out changeset 588d54f796a0 (bug 1765313)
Backed out changeset 2376ca53eb9c (bug 1765313)
Backed out changeset 9cf02ec5657a (bug 1770403)
Backed out changeset 7d8147ba25e8 (bug 1770403)
This commit is contained in:
Marian-Vasile Laza 2022-06-08 22:07:37 +03:00
parent 0a3aa8ec64
commit a0f6973887
34 changed files with 916 additions and 801 deletions

View File

@ -36,7 +36,7 @@
#include "prnetdb.h"
#include "nsIURIFixup.h"
#include "mozilla/dom/StorageUtils.h"
#include "mozilla/StorageAccess.h"
#include "mozilla/ContentBlocking.h"
#include "nsPIDOMWindow.h"
#include "nsIURIMutator.h"
#include "mozilla/PermissionManager.h"
@ -785,7 +785,8 @@ BasePrincipal::HasFirstpartyStorageAccess(mozIDOMWindow* aCheckWindow,
if (NS_FAILED(rv)) {
return rv;
}
*aOutAllowed = ShouldAllowAccessFor(win, uri, aRejectedReason);
*aOutAllowed =
ContentBlocking::ShouldAllowAccessFor(win, uri, aRejectedReason);
return NS_OK;
}

View File

@ -2743,9 +2743,29 @@ nsresult nsDocShell::SetDocLoaderParent(nsDocLoader* aParent) {
mContentListener->SetParentContentListener(parentURIListener);
}
// Inform windows when they're being removed from their parent.
if (!aParent) {
MaybeClearStorageAccessFlag();
}
return NS_OK;
}
void nsDocShell::MaybeClearStorageAccessFlag() {
if (mScriptGlobal) {
// Tell our window that the parent has now changed.
mScriptGlobal->ParentWindowChanged();
// Tell all of our children about the change recursively as well.
for (auto* childDocLoader : mChildList.ForwardRange()) {
nsCOMPtr<nsIDocShell> child = do_QueryObject(childDocLoader);
if (child) {
static_cast<nsDocShell*>(child.get())->MaybeClearStorageAccessFlag();
}
}
}
}
void nsDocShell::MaybeRestoreWindowName() {
if (!StaticPrefs::privacy_window_name_update_enabled()) {
return;

View File

@ -401,6 +401,9 @@ class nsDocShell final : public nsDocLoader,
nsDocShellLoadState* aLoadState,
mozilla::Maybe<uint32_t> aCacheKey = mozilla::Nothing());
// Clear the document's storage access flag if needed.
void MaybeClearStorageAccessFlag();
void MaybeRestoreWindowName();
void StoreWindowNameToSHEntries();

View File

@ -49,6 +49,7 @@
#include "mozilla/Base64.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/CSSEnabledState.h"
#include "mozilla/ContentBlocking.h"
#include "mozilla/ContentBlockingAllowList.h"
#include "mozilla/ContentBlockingNotifier.h"
#include "mozilla/ContentBlockingUserInteraction.h"
@ -95,7 +96,6 @@
#include "mozilla/PresShellInlines.h"
#include "mozilla/PseudoStyleType.h"
#include "mozilla/RefCountType.h"
#include "mozilla/RejectForeignAllowList.h"
#include "mozilla/RelativeTo.h"
#include "mozilla/RestyleManager.h"
#include "mozilla/ReverseIterator.h"
@ -16425,7 +16425,7 @@ void Document::MaybeAllowStorageForOpenerAfterUserInteraction() {
}
// We don't care when the asynchronous work finishes here.
Unused << StorageAccessAPIHelper::AllowAccessFor(
Unused << ContentBlocking::AllowAccessFor(
NodePrincipal(), openerBC,
ContentBlockingNotifier::eOpenerAfterUserInteraction);
}
@ -16834,7 +16834,7 @@ nsresult Document::HasStorageAccessSync(bool& aHasStorageAccess) {
return NS_OK;
}
Maybe<bool> resultBecauseCookiesApproved =
StorageAccessAPIHelper::CheckCookiesPermittedDecidesStorageAccessAPI(
ContentBlocking::CheckCookiesPermittedDecidesStorageAccessAPI(
CookieJarSettings(), NodePrincipal());
if (resultBecauseCookiesApproved.isSome()) {
if (resultBecauseCookiesApproved.value()) {
@ -16849,19 +16849,9 @@ nsresult Document::HasStorageAccessSync(bool& aHasStorageAccess) {
// Step 2: Check if the browser settings determine whether or not this
// document has access to its unpartitioned cookies.
bool isThirdPartyDocument = AntiTrackingUtils::IsThirdPartyDocument(this);
bool isOnRejectForeignAllowList = RejectForeignAllowList::Check(this);
bool isOnThirdPartySkipList = false;
if (mChannel) {
nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
isOnThirdPartySkipList = loadInfo->GetStoragePermission() ==
nsILoadInfo::StoragePermissionAllowListed;
}
bool isThirdPartyTracker =
nsContentUtils::IsThirdPartyTrackingResourceWindow(inner);
Maybe<bool> resultBecauseBrowserSettings =
StorageAccessAPIHelper::CheckBrowserSettingsDecidesStorageAccessAPI(
CookieJarSettings(), isThirdPartyDocument, isOnRejectForeignAllowList,
isOnThirdPartySkipList, isThirdPartyTracker);
ContentBlocking::CheckBrowserSettingsDecidesStorageAccessAPI(
CookieJarSettings(), isThirdPartyDocument);
if (resultBecauseBrowserSettings.isSome()) {
if (resultBecauseBrowserSettings.value()) {
aHasStorageAccess = true;
@ -16875,8 +16865,7 @@ nsresult Document::HasStorageAccessSync(bool& aHasStorageAccess) {
// Step 3: Check if the location of this call (embedded, top level, same-site)
// determines if cookies are permitted or not.
Maybe<bool> resultBecauseCallContext =
StorageAccessAPIHelper::CheckCallingContextDecidesStorageAccessAPI(this,
false);
ContentBlocking::CheckCallingContextDecidesStorageAccessAPI(this, false);
if (resultBecauseCallContext.isSome()) {
if (resultBecauseCallContext.value()) {
aHasStorageAccess = true;
@ -16890,8 +16879,7 @@ nsresult Document::HasStorageAccessSync(bool& aHasStorageAccess) {
// Step 4: Check if the permissions for this document determine if if has
// access or is denied cookies.
Maybe<bool> resultBecausePreviousPermission =
StorageAccessAPIHelper::CheckExistingPermissionDecidesStorageAccessAPI(
this);
ContentBlocking::CheckExistingPermissionDecidesStorageAccessAPI(this);
if (resultBecausePreviousPermission.isSome()) {
if (resultBecausePreviousPermission.value()) {
aHasStorageAccess = true;
@ -16901,6 +16889,7 @@ nsresult Document::HasStorageAccessSync(bool& aHasStorageAccess) {
return NS_OK;
}
}
// If you get here, we default to not giving you permission.
aHasStorageAccess = false;
return NS_OK;
@ -16969,9 +16958,8 @@ RefPtr<MozPromise<int, bool, true>> Document::RequestStorageAccessAsyncHelper(
// called later in CompleteAllowAccessFor inside of AllowAccessFor.
auto performFinalChecks = [inner, self, principal, aHasUserInteraction]() {
// Create the user prompt
RefPtr<StorageAccessAPIHelper::StorageAccessFinalCheckPromise::Private> p =
new StorageAccessAPIHelper::StorageAccessFinalCheckPromise::Private(
__func__);
RefPtr<ContentBlocking::StorageAccessFinalCheckPromise::Private> p =
new ContentBlocking::StorageAccessFinalCheckPromise::Private(__func__);
RefPtr<StorageAccessPermissionRequest> sapr =
StorageAccessPermissionRequest::Create(
inner, principal,
@ -16979,7 +16967,7 @@ RefPtr<MozPromise<int, bool, true>> Document::RequestStorageAccessAsyncHelper(
[p] {
Telemetry::AccumulateCategorical(
Telemetry::LABELS_STORAGE_ACCESS_API_UI::Allow);
p->Resolve(StorageAccessAPIHelper::eAllow, __func__);
p->Resolve(ContentBlocking::eAllow, __func__);
},
// Block
[p] {
@ -17029,10 +17017,10 @@ RefPtr<MozPromise<int, bool, true>> Document::RequestStorageAccessAsyncHelper(
MOZ_ASSERT_IF(pr2 != PromptResult::Granted,
pr2 == PromptResult::Denied);
if (pr2 == PromptResult::Granted) {
StorageAccessAPIHelper::StorageAccessPromptChoices choice =
StorageAccessAPIHelper::eAllow;
ContentBlocking::StorageAccessPromptChoices choice =
ContentBlocking::eAllow;
if (autoGrant) {
choice = StorageAccessAPIHelper::eAllowAutoGrant;
choice = ContentBlocking::eAllowAutoGrant;
}
if (!autoGrant) {
p->Resolve(choice, __func__);
@ -17059,8 +17047,8 @@ RefPtr<MozPromise<int, bool, true>> Document::RequestStorageAccessAsyncHelper(
};
// Try to allow access for the given principal.
return StorageAccessAPIHelper::AllowAccessFor(principal, aBrowsingContext,
aNotifier, performFinalChecks);
return ContentBlocking::AllowAccessFor(principal, aBrowsingContext, aNotifier,
performFinalChecks);
}
already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccess(
@ -17076,33 +17064,12 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccess(
return nullptr;
}
// Step 0: Check that we have user activation before proceeding to prevent
// rapid calls to the API to leak information.
if (!HasValidTransientUserGestureActivation()) {
// Report an error to the console for this case
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
nsLiteralCString("requestStorageAccess"),
this, nsContentUtils::eDOM_PROPERTIES,
"RequestStorageAccessUserGesture");
this->ConsumeTransientUserGestureActivation();
promise->MaybeRejectWithUndefined();
return promise.forget();
}
// Get a pointer to the inner window- We need this for convenience sake
RefPtr<nsPIDOMWindowInner> inner = this->GetInnerWindow();
if (!inner) {
this->ConsumeTransientUserGestureActivation();
promise->MaybeRejectWithUndefined();
return promise.forget();
}
// Step 1: Check if the principal calling this has a permission that lets
// them use cookies or forbids them from using cookies.
// This is outside of the spec of the StorageAccess API, but makes the return
// values to have proper semantics.
Maybe<bool> resultBecauseCookiesApproved =
StorageAccessAPIHelper::CheckCookiesPermittedDecidesStorageAccessAPI(
ContentBlocking::CheckCookiesPermittedDecidesStorageAccessAPI(
CookieJarSettings(), NodePrincipal());
if (resultBecauseCookiesApproved.isSome()) {
if (resultBecauseCookiesApproved.value()) {
@ -17120,19 +17087,9 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccess(
// This is outside of the spec of the StorageAccess API, but makes the return
// values to have proper semantics.
bool isThirdPartyDocument = AntiTrackingUtils::IsThirdPartyDocument(this);
bool isOnRejectForeignAllowList = RejectForeignAllowList::Check(this);
bool isOnThirdPartySkipList = false;
if (mChannel) {
nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
isOnThirdPartySkipList = loadInfo->GetStoragePermission() ==
nsILoadInfo::StoragePermissionAllowListed;
}
bool isThirdPartyTracker =
nsContentUtils::IsThirdPartyTrackingResourceWindow(inner);
Maybe<bool> resultBecauseBrowserSettings =
StorageAccessAPIHelper::CheckBrowserSettingsDecidesStorageAccessAPI(
CookieJarSettings(), isThirdPartyDocument, isOnRejectForeignAllowList,
isOnThirdPartySkipList, isThirdPartyTracker);
ContentBlocking::CheckBrowserSettingsDecidesStorageAccessAPI(
CookieJarSettings(), isThirdPartyDocument);
if (resultBecauseBrowserSettings.isSome()) {
if (resultBecauseBrowserSettings.value()) {
promise->MaybeResolveWithUndefined();
@ -17147,8 +17104,7 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccess(
// Step 3: Check if the Document calling requestStorageAccess has anything to
// gain from storage access. It should be embedded, non-null, etc.
Maybe<bool> resultBecauseCallContext =
StorageAccessAPIHelper::CheckCallingContextDecidesStorageAccessAPI(this,
true);
ContentBlocking::CheckCallingContextDecidesStorageAccessAPI(this, true);
if (resultBecauseCallContext.isSome()) {
if (resultBecauseCallContext.value()) {
promise->MaybeResolveWithUndefined();
@ -17163,8 +17119,7 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccess(
// Step 4: Check if we already allowed or denied storage access for this
// document's storage key.
Maybe<bool> resultBecausePreviousPermission =
StorageAccessAPIHelper::CheckExistingPermissionDecidesStorageAccessAPI(
this);
ContentBlocking::CheckExistingPermissionDecidesStorageAccessAPI(this);
if (resultBecausePreviousPermission.isSome()) {
if (resultBecausePreviousPermission.value()) {
promise->MaybeResolveWithUndefined();
@ -17178,6 +17133,12 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccess(
// Get pointers to some objects that will be used in the async portion
RefPtr<BrowsingContext> bc = this->GetBrowsingContext();
nsPIDOMWindowInner* inner = this->GetInnerWindow();
if (!inner) {
this->ConsumeTransientUserGestureActivation();
promise->MaybeRejectWithUndefined();
return promise.forget();
}
RefPtr<nsGlobalWindowOuter> outer =
nsGlobalWindowOuter::Cast(inner->GetOuterWindow());
if (!outer) {
@ -17199,12 +17160,19 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccess(
ContentBlockingNotifier::eStorageAccessAPI)
->Then(
GetCurrentSerialEventTarget(), __func__,
[self, inner, promise] {
inner->SaveStorageAccessPermissionGranted();
[self, outer, promise] {
// Step 10. Grant the document access to cookies and store
// that fact for
// the purposes of future calls to
// hasStorageAccess() and requestStorageAccess().
outer->SetStorageAccessPermissionGranted(true);
self->NotifyUserGestureActivation();
promise->MaybeResolveWithUndefined();
},
[promise] { promise->MaybeRejectWithUndefined(); });
[outer, promise] {
outer->SetStorageAccessPermissionGranted(false);
promise->MaybeRejectWithUndefined();
});
return promise.forget();
}
@ -17222,19 +17190,6 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccessForOrigin(
return nullptr;
}
// Step 0: Check that we have user activation before proceeding to prevent
// rapid calls to the API to leak information.
if (!HasValidTransientUserGestureActivation()) {
// Report an error to the console for this case
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
nsLiteralCString("requestStorageAccess"),
this, nsContentUtils::eDOM_PROPERTIES,
"RequestStorageAccessUserGesture");
this->ConsumeTransientUserGestureActivation();
promise->MaybeRejectWithUndefined();
return promise.forget();
}
// Step 1: Check if the provided URI is different-site to this Document
nsCOMPtr<nsIURI> thirdPartyURI;
nsresult rv = NS_NewURI(getter_AddRefs(thirdPartyURI), aThirdPartyOrigin);
@ -17248,12 +17203,9 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccessForOrigin(
aRv.Throw(rv);
return nullptr;
}
bool isOnRejectForeignAllowList =
RejectForeignAllowList::Check(thirdPartyURI);
Maybe<bool> resultBecauseBrowserSettings =
StorageAccessAPIHelper::CheckBrowserSettingsDecidesStorageAccessAPI(
CookieJarSettings(), isThirdPartyDocument, isOnRejectForeignAllowList,
false, true);
ContentBlocking::CheckBrowserSettingsDecidesStorageAccessAPI(
CookieJarSettings(), isThirdPartyDocument);
if (resultBecauseBrowserSettings.isSome()) {
if (resultBecauseBrowserSettings.value()) {
promise->MaybeResolveWithUndefined();
@ -17266,8 +17218,8 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccessForOrigin(
// Step 2: Check that this Document is same-site to the top, and check that
// we have user activation if we require it.
Maybe<bool> resultBecauseCallContext = StorageAccessAPIHelper::
CheckSameSiteCallingContextDecidesStorageAccessAPI(
Maybe<bool> resultBecauseCallContext =
ContentBlocking::CheckSameSiteCallingContextDecidesStorageAccessAPI(
this, aRequireUserActivation);
if (resultBecauseCallContext.isSome()) {
if (resultBecauseCallContext.value()) {
@ -17314,7 +17266,7 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccessForOrigin(
// permission, but this can't be done in this process. We needs the cookie
// permission of the URL as if it were embedded on this page, so we need to
// make this check in the ContentParent.
StorageAccessAPIHelper::AsyncCheckCookiesPermittedDecidesStorageAccessAPI(
ContentBlocking::AsyncCheckCookiesPermittedDecidesStorageAccessAPI(
GetBrowsingContext(), principal)
->Then(
GetCurrentSerialEventTarget(), __func__,
@ -17363,8 +17315,7 @@ already_AddRefed<mozilla::dom::Promise> Document::RequestStorageAccessForOrigin(
GetCurrentSerialEventTarget(), __func__,
// If the previous handlers resolved, we should reinstate user
// activation and resolve the promise we returned in Step 5.
[self, inner, promise] {
inner->SaveStorageAccessPermissionGranted();
[self, promise] {
self->NotifyUserGestureActivation();
promise->MaybeResolveWithUndefined();
},
@ -17705,7 +17656,8 @@ nsIPrincipal* Document::EffectiveStoragePrincipal() const {
// We use the lower-level ContentBlocking API here to ensure this
// check doesn't send notifications.
uint32_t rejectedReason = 0;
if (ShouldAllowAccessFor(inner, GetDocumentURI(), &rejectedReason)) {
if (ContentBlocking::ShouldAllowAccessFor(inner, GetDocumentURI(),
&rejectedReason)) {
return mActiveStoragePrincipal = NodePrincipal();
}

View File

@ -12,6 +12,7 @@
#include "nsPluginArray.h"
#include "nsMimeTypeArray.h"
#include "mozilla/Components.h"
#include "mozilla/ContentBlocking.h"
#include "mozilla/ContentBlockingNotifier.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/BodyExtractor.h"

View File

@ -13,12 +13,12 @@
#include "mozilla/Assertions.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/ContentBlocking.h"
#include "mozilla/ContentBlockingNotifier.h"
#include "mozilla/Logging.h"
#include "mozilla/MacroForEach.h"
#include "mozilla/Components.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/StorageAccess.h"
#include "mozilla/TextUtils.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/BrowsingContext.h"
@ -512,8 +512,8 @@ ThirdPartyUtil::AnalyzeChannel(nsIChannel* aChannel, bool aNotify, nsIURI* aURI,
aRequireThirdPartyCheck ? result.contains(ThirdPartyAnalysis::IsForeign)
: true;
if (performStorageChecks &&
ShouldAllowAccessFor(aChannel, aURI ? aURI : uri.get(),
aRejectedReason)) {
ContentBlocking::ShouldAllowAccessFor(aChannel, aURI ? aURI : uri.get(),
aRejectedReason)) {
result += ThirdPartyAnalysis::IsStorageAccessPermissionGranted;
}

View File

@ -750,6 +750,12 @@ nsresult nsFrameLoader::ReallyStartLoadingInternal() {
return NS_OK;
}
if (GetDocShell()) {
// If we already have a docshell, ensure that the docshell's storage access
// flag is cleared.
GetDocShell()->MaybeClearStorageAccessFlag();
}
nsresult rv = MaybeCreateDocShell();
if (NS_FAILED(rv)) {
return rv;
@ -1167,6 +1173,8 @@ void nsFrameLoader::Hide() {
return;
}
GetDocShell()->MaybeClearStorageAccessFlag();
nsCOMPtr<nsIContentViewer> contentViewer;
GetDocShell()->GetContentViewer(getter_AddRefs(contentViewer));
if (contentViewer) contentViewer->SetSticky(false);

View File

@ -24,6 +24,7 @@
#include "nsISecureBrowserUI.h"
#include "nsIWebProgressListener.h"
#include "mozilla/AntiTrackingUtils.h"
#include "mozilla/ContentBlocking.h"
#include "mozilla/dom/AutoPrintEventDispatcher.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/BrowserChild.h"
@ -51,7 +52,6 @@
#include "mozilla/dom/WindowFeatures.h" // WindowFeatures
#include "mozilla/dom/WindowProxyHolder.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/StorageAccessAPIHelper.h"
#include "nsBaseCommandController.h"
#include "nsError.h"
#include "nsICookieService.h"
@ -1310,6 +1310,7 @@ nsGlobalWindowOuter::nsGlobalWindowOuter(uint64_t aWindowID)
mIsChrome(false),
mAllowScriptsToClose(false),
mTopLevelOuterContentWindow(false),
mStorageAccessPermissionGranted(false),
mDelayedPrintUntilAfterLoad(false),
mDelayedCloseForPrinting(false),
mShouldDelayPrintUntilAfterLoad(false),
@ -2506,6 +2507,9 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
PreloadLocalStorage();
mStorageAccessPermissionGranted = ContentBlocking::ShouldAllowAccessFor(
newInnerWindow, aDocument->GetDocumentURI(), nullptr);
// Do this here rather than in say the Document constructor, since
// we need a WindowContext available.
mDoc->InitUseCounters();
@ -7134,8 +7138,8 @@ void nsGlobalWindowOuter::MaybeAllowStorageForOpenedWindow(nsIURI* aURI) {
aURI, doc->NodePrincipal()->OriginAttributesRef());
// We don't care when the asynchronous work finishes here.
Unused << StorageAccessAPIHelper::AllowAccessFor(
principal, GetBrowsingContext(), ContentBlockingNotifier::eOpener);
Unused << ContentBlocking::AllowAccessFor(principal, GetBrowsingContext(),
ContentBlockingNotifier::eOpener);
}
//*****************************************************************************

View File

@ -677,6 +677,11 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
virtual bool IsInSyncOperation() override;
void ParentWindowChanged() {
// Reset our storage access permission flag when we get reparented.
mStorageAccessPermissionGranted = false;
}
public:
double GetInnerWidthOuter(mozilla::ErrorResult& aError);
@ -871,6 +876,13 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
bool IsInModalState();
bool IsStorageAccessPermissionGranted() const {
return mStorageAccessPermissionGranted;
}
void SetStorageAccessPermissionGranted(bool aStorageAccessPermissionGranted) {
mStorageAccessPermissionGranted = aStorageAccessPermissionGranted;
}
// Convenience functions for the many methods that need to scale
// from device to CSS pixels. This computes it with cached scale in
// PresContext which may be not recent information of the widget.
@ -1087,6 +1099,9 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
bool mTopLevelOuterContentWindow : 1;
// whether storage access has been granted to this frame.
bool mStorageAccessPermissionGranted : 1;
// Whether we've delayed a print until after load.
bool mDelayedPrintUntilAfterLoad : 1;
// Whether we've delayed a close() operation because there was a pending

View File

@ -939,6 +939,8 @@ mozilla::ipc::IPCResult BrowserChild::RecvLoadURL(
}
docShell->LoadURI(aLoadState, true);
nsDocShell::Cast(docShell)->MaybeClearStorageAccessFlag();
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::URL, spec);
return IPC_OK();
}

View File

@ -18,6 +18,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/BackgroundHangMonitor.h"
#include "mozilla/BenchmarkStorageChild.h"
#include "mozilla/ContentBlocking.h"
#include "mozilla/FOGIPC.h"
#include "GMPServiceChild.h"
#include "Geolocation.h"
@ -48,7 +49,6 @@
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_fission.h"
#include "mozilla/StaticPrefs_media.h"
#include "mozilla/StorageAccessAPIHelper.h"
#include "mozilla/TelemetryIPC.h"
#include "mozilla/Unused.h"
#include "mozilla/WebBrowserPersistDocumentChild.h"
@ -3621,8 +3621,8 @@ mozilla::ipc::IPCResult ContentChild::RecvOnAllowAccessFor(
aReason) {
MOZ_ASSERT(!aContext.IsNull(), "Browsing context cannot be null");
StorageAccessAPIHelper::OnAllowAccessFor(
aContext.GetMaybeDiscarded(), aTrackingOrigin, aCookieBehavior, aReason);
ContentBlocking::OnAllowAccessFor(aContext.GetMaybeDiscarded(),
aTrackingOrigin, aCookieBehavior, aReason);
return IPC_OK();
}

View File

@ -55,6 +55,7 @@
#include "gfxPlatformFontList.h"
#include "mozilla/AppShutdown.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/ContentBlocking.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/BenchmarkStorageParent.h"
#include "mozilla/ContentBlockingUserInteraction.h"
@ -82,7 +83,6 @@
#include "mozilla/StaticPrefs_fission.h"
#include "mozilla/StaticPrefs_media.h"
#include "mozilla/StaticPrefs_widget.h"
#include "mozilla/StorageAccessAPIHelper.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
#include "mozilla/Telemetry.h"
@ -6406,17 +6406,18 @@ ContentParent::RecvStorageAccessPermissionGrantedForOrigin(
aReason.value());
}
StorageAccessAPIHelper::SaveAccessForOriginOnParentProcess(
ContentBlocking::SaveAccessForOriginOnParentProcess(
aTopLevelWindowId, aParentContext.get_canonical(), aTrackingPrincipal,
aAllowMode)
->Then(GetCurrentSerialEventTarget(), __func__,
[aResolver = std::move(aResolver)](
StorageAccessAPIHelper::ParentAccessGrantPromise::
ResolveOrRejectValue&& aValue) {
bool success =
aValue.IsResolve() && NS_SUCCEEDED(aValue.ResolveValue());
aResolver(success);
});
->Then(
GetCurrentSerialEventTarget(), __func__,
[aResolver = std::move(aResolver)](
ContentBlocking::ParentAccessGrantPromise::ResolveOrRejectValue&&
aValue) {
bool success =
aValue.IsResolve() && NS_SUCCEEDED(aValue.ResolveValue());
aResolver(success);
});
return IPC_OK();
}
@ -6431,12 +6432,12 @@ mozilla::ipc::IPCResult ContentParent::RecvCompleteAllowAccessFor(
return IPC_OK();
}
StorageAccessAPIHelper::CompleteAllowAccessFor(
ContentBlocking::CompleteAllowAccessFor(
aParentContext.get_canonical(), aTopLevelWindowId, aTrackingPrincipal,
aTrackingOrigin, aCookieBehavior, aReason, nullptr)
->Then(GetCurrentSerialEventTarget(), __func__,
[aResolver = std::move(aResolver)](
StorageAccessAPIHelper::StorageAccessPermissionGrantPromise::
ContentBlocking::StorageAccessPermissionGrantPromise::
ResolveOrRejectValue&& aValue) {
Maybe<StorageAccessPromptChoices> choice;
if (aValue.IsResolve()) {
@ -6470,8 +6471,8 @@ mozilla::ipc::IPCResult ContentParent::RecvTestCookiePermissionDecided(
nsCOMPtr<nsICookieJarSettings> cjs = wgp->CookieJarSettings();
Maybe<bool> result =
StorageAccessAPIHelper::CheckCookiesPermittedDecidesStorageAccessAPI(
cjs, aPrincipal);
ContentBlocking::CheckCookiesPermittedDecidesStorageAccessAPI(cjs,
aPrincipal);
aResolver(result);
return IPC_OK();
}

View File

@ -140,7 +140,7 @@ using mozilla::dom::PositionState from "mozilla/dom/MediaSession.h";
using mozilla::dom::ServiceWorkerShutdownState::Progress from "mozilla/dom/ServiceWorkerShutdownState.h";
using mozilla::ContentBlockingNotifier::StorageAccessPermissionGrantedReason from "mozilla/ContentBlockingNotifier.h";
using mozilla::ContentBlockingNotifier::BlockingDecision from "mozilla/ContentBlockingNotifier.h";
using mozilla::StorageAccessAPIHelper::StorageAccessPromptChoices from "mozilla/StorageAccessAPIHelper.h";
using mozilla::ContentBlocking::StorageAccessPromptChoices from "mozilla/ContentBlocking.h";
using JSActorMessageKind from "mozilla/dom/JSActor.h";
using JSActorMessageMeta from "mozilla/dom/PWindowGlobal.h";
using mozilla::PermissionDelegateHandler::DelegatedPermissionList from "mozilla/PermissionDelegateHandler.h";

View File

@ -479,6 +479,12 @@ WindowGlobalChild::RecvSaveStorageAccessPermissionGranted() {
inner->SaveStorageAccessPermissionGranted();
}
nsCOMPtr<nsPIDOMWindowOuter> outer =
nsPIDOMWindowOuter::GetFromCurrentInner(inner);
if (outer) {
nsGlobalWindowOuter::Cast(outer)->SetStorageAccessPermissionGranted(true);
}
return IPC_OK();
}

View File

@ -20,13 +20,13 @@
#include "ReferrerInfo.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/ContentBlocking.h"
#include "mozilla/ContentBlockingAllowList.h"
#include "mozilla/net/CookieJarSettings.h"
#include "mozilla/net/HttpBaseChannel.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/Element.h"
#include "mozilla/StaticPrefs_network.h"
#include "mozilla/StorageAccess.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/Telemetry.h"
#include "nsIWebProgressListener.h"
@ -210,7 +210,8 @@ ReferrerPolicy ReferrerInfo::GetDefaultReferrerPolicy(nsIHttpChannel* aChannel,
if (XRE_IsParentProcess() && cjs->GetRejectThirdPartyContexts()) {
uint32_t rejectedReason = 0;
thirdPartyTrackerIsolated =
!ShouldAllowAccessFor(aChannel, aURI, &rejectedReason) &&
!ContentBlocking::ShouldAllowAccessFor(aChannel, aURI,
&rejectedReason) &&
rejectedReason !=
static_cast<uint32_t>(
nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN);

View File

@ -8,6 +8,7 @@
#include <utility>
#include "mozilla/AntiTrackingUtils.h"
#include "mozilla/ContentBlocking.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/StorageAccess.h"
#include "mozilla/StoragePrincipalHelper.h"
@ -16,7 +17,6 @@
#include "mozilla/dom/File.h"
#include "mozilla/dom/ServiceWorkerManager.h"
#include "mozilla/StaticPrefs_privacy.h"
#include "mozilla/StorageAccess.h"
#include "nsContentUtils.h"
#include "nsHashKeys.h"
#include "nsLayoutUtils.h"
@ -153,8 +153,8 @@ nsCString ImageCacheKey::GetIsolationKey(Document* aDocument, nsIURI* aURI) {
// this point. The best approach here is to be conservative: if we are sure
// that the permission is granted, let's return 0. Otherwise, let's make a
// unique image cache per the top-level document eTLD+1.
if (!ApproximateAllowAccessForWithoutChannel(aDocument->GetInnerWindow(),
aURI)) {
if (!ContentBlocking::ApproximateAllowAccessForWithoutChannel(
aDocument->GetInnerWindow(), aURI)) {
// If we are here, the image is a 3rd-party resource loaded by a first-party
// context. We can just use the document's base domain as the key because it
// should be the same as the top-level document's base domain.

View File

@ -7,11 +7,11 @@
#include "CookieCommons.h"
#include "CookieLogging.h"
#include "CookieService.h"
#include "mozilla/ContentBlocking.h"
#include "mozilla/ConsoleReportCollector.h"
#include "mozilla/ContentBlockingNotifier.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/StaticPrefs_network.h"
#include "mozilla/StorageAccess.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/nsMixedContentBlocker.h"
#include "mozilla/net/CookieJarSettings.h"
@ -386,7 +386,8 @@ already_AddRefed<Cookie> CookieCommons::CreateCookieFromDocument(
if (aDocument->CookieJarSettings()->GetLimitForeignContexts() &&
!aHasExistingCookiesLambda(baseDomain,
storagePrincipal->OriginAttributesRef()) &&
!ShouldAllowAccessFor(innerWindow, principalURI, &dummyRejectedReason)) {
!ContentBlocking::ShouldAllowAccessFor(innerWindow, principalURI,
&dummyRejectedReason)) {
return nullptr;
}

View File

@ -7,18 +7,19 @@
#include "ClassifierDummyChannel.h"
#include "mozilla/ContentBlocking.h"
#include "mozilla/net/ClassifierDummyChannelChild.h"
#include "mozilla/net/UrlClassifierCommon.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs_privacy.h"
#include "mozilla/StorageAccess.h"
#include "nsContentSecurityManager.h"
#include "nsIChannel.h"
#include "nsIURI.h"
#include "nsProxyRelease.h"
#include "nsQueryObject.h"
#include "NeckoChild.h"
#include "mozilla/ContentBlocking.h"
#include "nsIHttpChannel.h"
#include "nsIStreamListener.h"
@ -63,7 +64,7 @@ ClassifierDummyChannel::StorageAllowed(
return eAsyncNeeded;
}
if (ShouldAllowAccessFor(httpChannel, uri, nullptr)) {
if (ContentBlocking::ShouldAllowAccessFor(httpChannel, uri, nullptr)) {
return eStorageGranted;
}

View File

@ -5,11 +5,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ClassifierDummyChannelChild.h"
#include "mozilla/ContentBlocking.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/ipc/URIUtils.h"
#include "nsIURI.h"
#include "mozilla/AntiTrackingUtils.h"
#include "mozilla/StorageAccess.h"
#include "nsIHttpChannelInternal.h"
#include "nsIHttpChannel.h"
#include "mozilla/net/NeckoChannelParams.h"
@ -82,7 +82,8 @@ mozilla::ipc::IPCResult ClassifierDummyChannelChild::Recv__delete__(
RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(channel);
httpChannel->AddClassificationFlags(aClassificationFlags, mIsThirdParty);
bool storageGranted = ShouldAllowAccessFor(httpChannel, mURI, nullptr);
bool storageGranted =
ContentBlocking::ShouldAllowAccessFor(httpChannel, mURI, nullptr);
mCallback(storageGranted);
return IPC_OK();
}

View File

@ -59,6 +59,7 @@
#include "mozilla/AntiTrackingUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/ContentBlocking.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Preferences.h"
#include "mozilla/ProfilerLabels.h"

View File

@ -10,7 +10,7 @@
#include "ipc/EnumSerializer.h"
#include "mozilla/ContentBlockingNotifier.h"
#include "mozilla/StorageAccessAPIHelper.h"
#include "mozilla/ContentBlocking.h"
#include "nsILoadInfo.h"
@ -38,13 +38,13 @@ struct ParamTraits<mozilla::ContentBlockingNotifier::BlockingDecision>
mozilla::ContentBlockingNotifier::BlockingDecision::eBlock,
mozilla::ContentBlockingNotifier::BlockingDecision::eAllow> {};
// StorageAccessAPIHelper::StorageAccessPromptChoices over IPC.
// ContentBlocking::StorageAccessPromptChoices over IPC.
template <>
struct ParamTraits<mozilla::StorageAccessAPIHelper::StorageAccessPromptChoices>
struct ParamTraits<mozilla::ContentBlocking::StorageAccessPromptChoices>
: public ContiguousEnumSerializerInclusive<
mozilla::StorageAccessAPIHelper::StorageAccessPromptChoices,
mozilla::StorageAccessAPIHelper::StorageAccessPromptChoices::eAllow,
mozilla::StorageAccessAPIHelper::StorageAccessPromptChoices::
mozilla::ContentBlocking::StorageAccessPromptChoices,
mozilla::ContentBlocking::StorageAccessPromptChoices::eAllow,
mozilla::ContentBlocking::StorageAccessPromptChoices::
eAllowAutoGrant> {};
// nsILoadInfo::StoragePermissionState over IPC.

View File

@ -6,9 +6,9 @@
#include "AntiTrackingLog.h"
#include "AntiTrackingRedirectHeuristic.h"
#include "ContentBlocking.h"
#include "ContentBlockingAllowList.h"
#include "ContentBlockingUserInteraction.h"
#include "StorageAccessAPIHelper.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/Document.h"
@ -422,10 +422,10 @@ void FinishAntiTrackingRedirectHeuristic(nsIChannel* aNewChannel,
Telemetry::LABELS_STORAGE_ACCESS_GRANTED_COUNT::Redirect);
// We don't care about this promise because the operation is actually sync.
RefPtr<StorageAccessAPIHelper::ParentAccessGrantPromise> promise =
StorageAccessAPIHelper::SaveAccessForOriginOnParentProcess(
RefPtr<ContentBlocking::ParentAccessGrantPromise> promise =
ContentBlocking::SaveAccessForOriginOnParentProcess(
newPrincipal, oldPrincipal,
StorageAccessAPIHelper::StorageAccessPromptChoices::eAllow,
ContentBlocking::StorageAccessPromptChoices::eAllow,
StaticPrefs::privacy_restrict3rdpartystorage_expiration_redirect());
Unused << promise;
}

View File

@ -5,7 +5,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AntiTrackingLog.h"
#include "StorageAccessAPIHelper.h"
#include "ContentBlocking.h"
#include "AntiTrackingUtils.h"
#include "TemporaryAccessGrantObserver.h"
@ -64,13 +64,80 @@ bool GetTopLevelWindowId(BrowsingContext* aParentContext, uint32_t aBehavior,
return aTopLevelInnerWindowId != 0;
}
// This internal method returns ACCESS_DENY if the access is denied,
// ACCESS_DEFAULT if unknown, some other access code if granted.
uint32_t CheckCookiePermissionForPrincipal(
nsICookieJarSettings* aCookieJarSettings, nsIPrincipal* aPrincipal) {
MOZ_ASSERT(aCookieJarSettings);
MOZ_ASSERT(aPrincipal);
uint32_t cookiePermission = nsICookiePermission::ACCESS_DEFAULT;
if (!aPrincipal->GetIsContentPrincipal()) {
return cookiePermission;
}
nsresult rv =
aCookieJarSettings->CookiePermission(aPrincipal, &cookiePermission);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nsICookiePermission::ACCESS_DEFAULT;
}
// If we have a custom cookie permission, let's use it.
return cookiePermission;
}
int32_t CookiesBehavior(Document* a3rdPartyDocument) {
MOZ_ASSERT(a3rdPartyDocument);
// WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior
// (See Bug 1406675 and Bug 1525917 for rationale).
if (BasePrincipal::Cast(a3rdPartyDocument->NodePrincipal())->AddonPolicy()) {
return nsICookieService::BEHAVIOR_ACCEPT;
}
return a3rdPartyDocument->CookieJarSettings()->GetCookieBehavior();
}
int32_t CookiesBehavior(nsILoadInfo* aLoadInfo, nsIURI* a3rdPartyURI) {
MOZ_ASSERT(aLoadInfo);
MOZ_ASSERT(a3rdPartyURI);
// WebExtensions 3rd party URI always get BEHAVIOR_ACCEPT as cookieBehavior,
// this is semantically equivalent to the principal having a AddonPolicy().
if (a3rdPartyURI->SchemeIs("moz-extension")) {
return nsICookieService::BEHAVIOR_ACCEPT;
}
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
nsresult rv =
aLoadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nsICookieService::BEHAVIOR_REJECT;
}
return cookieJarSettings->GetCookieBehavior();
}
int32_t CookiesBehavior(nsIPrincipal* aPrincipal,
nsICookieJarSettings* aCookieJarSettings) {
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aCookieJarSettings);
// WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior
// (See Bug 1406675 for rationale).
if (BasePrincipal::Cast(aPrincipal)->AddonPolicy()) {
return nsICookieService::BEHAVIOR_ACCEPT;
}
return aCookieJarSettings->GetCookieBehavior();
}
} // namespace
/* static */ RefPtr<StorageAccessAPIHelper::StorageAccessPermissionGrantPromise>
StorageAccessAPIHelper::AllowAccessFor(
/* static */ RefPtr<ContentBlocking::StorageAccessPermissionGrantPromise>
ContentBlocking::AllowAccessFor(
nsIPrincipal* aPrincipal, dom::BrowsingContext* aParentContext,
ContentBlockingNotifier::StorageAccessPermissionGrantedReason aReason,
const StorageAccessAPIHelper::PerformFinalChecks& aPerformFinalChecks) {
const ContentBlocking::PerformFinalChecks& aPerformFinalChecks) {
MOZ_ASSERT(aParentContext);
switch (aReason) {
@ -283,7 +350,7 @@ StorageAccessAPIHelper::AllowAccessFor(
}
if (runInSameProcess) {
return StorageAccessAPIHelper::CompleteAllowAccessFor(
return ContentBlocking::CompleteAllowAccessFor(
aParentContext, topLevelWindowId, trackingPrincipal, trackingOrigin,
behavior, aReason, aPerformFinalChecks);
}
@ -313,8 +380,8 @@ StorageAccessAPIHelper::AllowAccessFor(
if (aReason == ContentBlockingNotifier::eOpener &&
!bc->IsDiscarded()) {
MOZ_ASSERT(bc->IsInProcess());
StorageAccessAPIHelper::OnAllowAccessFor(bc, trackingOrigin,
behavior, aReason);
ContentBlocking::OnAllowAccessFor(bc, trackingOrigin,
behavior, aReason);
}
return StorageAccessPermissionGrantPromise::CreateAndResolve(
aValue.ResolveValue().value(), __func__);
@ -355,8 +422,8 @@ StorageAccessAPIHelper::AllowAccessFor(
// privilege API. So, it is always in-process. And we don't need to check the
// user interaction permission for the tracking origin in this case. We can
// run in the same process.
/* static */ RefPtr<StorageAccessAPIHelper::StorageAccessPermissionGrantPromise>
StorageAccessAPIHelper::CompleteAllowAccessFor(
/* static */ RefPtr<ContentBlocking::StorageAccessPermissionGrantPromise>
ContentBlocking::CompleteAllowAccessFor(
dom::BrowsingContext* aParentContext, uint64_t aTopLevelWindowId,
nsIPrincipal* aTrackingPrincipal, const nsCString& aTrackingOrigin,
uint32_t aCookieBehavior,
@ -440,8 +507,8 @@ StorageAccessAPIHelper::CompleteAllowAccessFor(
// Inform the window we granted permission for. This has to be done in the
// window's process.
if (aParentContext->IsInProcess()) {
StorageAccessAPIHelper::OnAllowAccessFor(aParentContext, trackingOrigin,
aCookieBehavior, aReason);
ContentBlocking::OnAllowAccessFor(aParentContext, trackingOrigin,
aCookieBehavior, aReason);
} else {
MOZ_ASSERT(XRE_IsParentProcess());
@ -493,7 +560,7 @@ StorageAccessAPIHelper::CompleteAllowAccessFor(
ContentBlockingUserInteraction::Observe(trackingPrincipal);
}
return StorageAccessPermissionGrantPromise::CreateAndResolve(
StorageAccessAPIHelper::eAllow, __func__);
ContentBlocking::eAllow, __func__);
});
}
@ -547,7 +614,7 @@ StorageAccessAPIHelper::CompleteAllowAccessFor(
return storePermission(false);
}
/* static */ void StorageAccessAPIHelper::OnAllowAccessFor(
/* static */ void ContentBlocking::OnAllowAccessFor(
dom::BrowsingContext* aParentContext, const nsCString& aTrackingOrigin,
uint32_t aCookieBehavior,
ContentBlockingNotifier::StorageAccessPermissionGrantedReason aReason) {
@ -555,8 +622,8 @@ StorageAccessAPIHelper::CompleteAllowAccessFor(
// Let's inform the parent window and the other windows having the
// same tracking origin about the storage permission is granted.
StorageAccessAPIHelper::UpdateAllowAccessOnCurrentProcess(aParentContext,
aTrackingOrigin);
ContentBlocking::UpdateAllowAccessOnCurrentProcess(aParentContext,
aTrackingOrigin);
// Let's inform the parent window.
nsCOMPtr<nsPIDOMWindowInner> parentInner =
@ -609,8 +676,8 @@ StorageAccessAPIHelper::CompleteAllowAccessFor(
}
/* static */
RefPtr<mozilla::StorageAccessAPIHelper::ParentAccessGrantPromise>
StorageAccessAPIHelper::SaveAccessForOriginOnParentProcess(
RefPtr<mozilla::ContentBlocking::ParentAccessGrantPromise>
ContentBlocking::SaveAccessForOriginOnParentProcess(
uint64_t aTopLevelWindowId, BrowsingContext* aParentContext,
nsIPrincipal* aTrackingPrincipal, int aAllowMode,
uint64_t aExpirationTime) {
@ -640,17 +707,17 @@ StorageAccessAPIHelper::SaveAccessForOriginOnParentProcess(
// If the permission is granted on a first-party window, also have to update
// the permission to all the other windows with the same tracking origin (in
// the same tab), if any.
StorageAccessAPIHelper::UpdateAllowAccessOnParentProcess(aParentContext,
trackingOrigin);
ContentBlocking::UpdateAllowAccessOnParentProcess(aParentContext,
trackingOrigin);
return StorageAccessAPIHelper::SaveAccessForOriginOnParentProcess(
return ContentBlocking::SaveAccessForOriginOnParentProcess(
wgp->DocumentPrincipal(), aTrackingPrincipal, aAllowMode,
aExpirationTime);
}
/* static */
RefPtr<mozilla::StorageAccessAPIHelper::ParentAccessGrantPromise>
StorageAccessAPIHelper::SaveAccessForOriginOnParentProcess(
RefPtr<mozilla::ContentBlocking::ParentAccessGrantPromise>
ContentBlocking::SaveAccessForOriginOnParentProcess(
nsIPrincipal* aParentPrincipal, nsIPrincipal* aTrackingPrincipal,
int aAllowMode, uint64_t aExpirationTime) {
MOZ_ASSERT(XRE_IsParentProcess());
@ -736,8 +803,7 @@ StorageAccessAPIHelper::SaveAccessForOriginOnParentProcess(
}
// static
Maybe<bool>
StorageAccessAPIHelper::CheckCookiesPermittedDecidesStorageAccessAPI(
Maybe<bool> ContentBlocking::CheckCookiesPermittedDecidesStorageAccessAPI(
nsICookieJarSettings* aCookieJarSettings,
nsIPrincipal* aRequestingPrincipal) {
MOZ_ASSERT(aCookieJarSettings);
@ -759,7 +825,7 @@ StorageAccessAPIHelper::CheckCookiesPermittedDecidesStorageAccessAPI(
// static
RefPtr<MozPromise<Maybe<bool>, nsresult, true>>
StorageAccessAPIHelper::AsyncCheckCookiesPermittedDecidesStorageAccessAPI(
ContentBlocking::AsyncCheckCookiesPermittedDecidesStorageAccessAPI(
dom::BrowsingContext* aBrowsingContext,
nsIPrincipal* aRequestingPrincipal) {
MOZ_ASSERT(XRE_IsContentProcess());
@ -784,55 +850,21 @@ StorageAccessAPIHelper::AsyncCheckCookiesPermittedDecidesStorageAccessAPI(
}
// static
Maybe<bool> StorageAccessAPIHelper::CheckBrowserSettingsDecidesStorageAccessAPI(
nsICookieJarSettings* aCookieJarSettings, bool aThirdParty,
bool aOnRejectForeignAllowlist, bool aIsOnThirdPartySkipList,
bool aIsThirdPartyTracker) {
Maybe<bool> ContentBlocking::CheckBrowserSettingsDecidesStorageAccessAPI(
nsICookieJarSettings* aCookieJarSettings, bool aThirdParty) {
MOZ_ASSERT(aCookieJarSettings);
uint32_t behavior = aCookieJarSettings->GetCookieBehavior();
switch (behavior) {
case nsICookieService::BEHAVIOR_ACCEPT:
return Some(true);
case nsICookieService::BEHAVIOR_REJECT_FOREIGN:
if (!aThirdParty) {
return Some(true);
}
if (!StaticPrefs::network_cookie_rejectForeignWithExceptions_enabled()) {
return Some(false);
}
return Some(aOnRejectForeignAllowlist);
case nsICookieService::BEHAVIOR_REJECT:
return Some(false);
case nsICookieService::BEHAVIOR_LIMIT_FOREIGN:
if (!aThirdParty) {
return Some(true);
}
return Some(false);
case nsICookieService::BEHAVIOR_REJECT_TRACKER:
if (!aIsThirdPartyTracker) {
return Some(true);
}
if (aIsOnThirdPartySkipList) {
return Some(true);
}
return Nothing();
case nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN:
if (!aThirdParty) {
return Some(true);
}
if (aIsOnThirdPartySkipList) {
return Some(true);
}
return Nothing();
default:
MOZ_ASSERT_UNREACHABLE("Must not have undefined cookie behavior");
if (aCookieJarSettings->GetBlockingAllContexts() ||
(aCookieJarSettings->GetBlockingAllThirdPartyContexts() && aThirdParty)) {
return Some(false);
}
if (!aCookieJarSettings->GetRejectThirdPartyContexts()) {
return Some(true);
}
MOZ_ASSERT_UNREACHABLE("Must not have undefined cookie behavior");
return Nothing();
}
// static
Maybe<bool> StorageAccessAPIHelper::CheckCallingContextDecidesStorageAccessAPI(
Maybe<bool> ContentBlocking::CheckCallingContextDecidesStorageAccessAPI(
Document* aDocument, bool aRequestingStorageAccess) {
MOZ_ASSERT(aDocument);
// Window doesn't have user activation and we are asking for access -> reject.
@ -904,8 +936,7 @@ Maybe<bool> StorageAccessAPIHelper::CheckCallingContextDecidesStorageAccessAPI(
}
// static
Maybe<bool>
StorageAccessAPIHelper::CheckSameSiteCallingContextDecidesStorageAccessAPI(
Maybe<bool> ContentBlocking::CheckSameSiteCallingContextDecidesStorageAccessAPI(
dom::Document* aDocument, bool aRequireUserActivation) {
MOZ_ASSERT(aDocument);
if (aRequireUserActivation) {
@ -941,18 +972,20 @@ StorageAccessAPIHelper::CheckSameSiteCallingContextDecidesStorageAccessAPI(
}
// static
Maybe<bool>
StorageAccessAPIHelper::CheckExistingPermissionDecidesStorageAccessAPI(
Maybe<bool> ContentBlocking::CheckExistingPermissionDecidesStorageAccessAPI(
dom::Document* aDocument) {
MOZ_ASSERT(aDocument);
if (aDocument->StorageAccessSandboxed()) {
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
nsLiteralCString("requestStorageAccess"),
aDocument, nsContentUtils::eDOM_PROPERTIES,
"RequestStorageAccessSandboxed");
nsPIDOMWindowInner* inner = aDocument->GetInnerWindow();
if (!inner) {
return Some(false);
}
if (aDocument->HasStorageAccessPermissionGranted()) {
nsGlobalWindowOuter* outer =
nsGlobalWindowOuter::Cast(inner->GetOuterWindow());
if (!outer) {
return Some(false);
}
bool explicitPermissionGranted = outer->IsStorageAccessPermissionGranted();
if (explicitPermissionGranted) {
return Some(true);
}
return Nothing();
@ -977,7 +1010,7 @@ StorageAccessAPIHelper::CheckExistingPermissionDecidesStorageAccessAPI(
// This function is used to update permission to all in-process windows, so it
// can be called either from the parent or the child.
/* static */
void StorageAccessAPIHelper::UpdateAllowAccessOnCurrentProcess(
void ContentBlocking::UpdateAllowAccessOnCurrentProcess(
BrowsingContext* aParentContext, const nsACString& aTrackingOrigin) {
MOZ_ASSERT(aParentContext && aParentContext->IsInProcess());
@ -1006,13 +1039,20 @@ void StorageAccessAPIHelper::UpdateAllowAccessOnCurrentProcess(
if (inner) {
inner->SaveStorageAccessPermissionGranted();
}
nsCOMPtr<nsPIDOMWindowOuter> outer =
nsPIDOMWindowOuter::GetFromCurrentInner(inner);
if (outer) {
nsGlobalWindowOuter::Cast(outer)->SetStorageAccessPermissionGranted(
true);
}
}
}
});
}
/* static */
void StorageAccessAPIHelper::UpdateAllowAccessOnParentProcess(
void ContentBlocking::UpdateAllowAccessOnParentProcess(
BrowsingContext* aParentContext, const nsACString& aTrackingOrigin) {
MOZ_ASSERT(XRE_IsParentProcess());
@ -1069,3 +1109,554 @@ void StorageAccessAPIHelper::UpdateAllowAccessOnParentProcess(
});
}
}
bool ContentBlocking::ShouldAllowAccessFor(nsPIDOMWindowInner* aWindow,
nsIURI* aURI,
uint32_t* aRejectedReason) {
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aURI);
// Let's avoid a null check on aRejectedReason everywhere else.
uint32_t rejectedReason = 0;
if (!aRejectedReason) {
aRejectedReason = &rejectedReason;
}
LOG_SPEC(("Computing whether window %p has access to URI %s", aWindow, _spec),
aURI);
nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(aWindow);
Document* document = innerWindow->GetExtantDoc();
if (!document) {
LOG(("Our window has no document"));
return false;
}
uint32_t cookiePermission = CheckCookiePermissionForPrincipal(
document->CookieJarSettings(), document->NodePrincipal());
if (cookiePermission != nsICookiePermission::ACCESS_DEFAULT) {
LOG(
("CheckCookiePermissionForPrincipal() returned a non-default access "
"code (%d) for window's principal, returning %s",
int(cookiePermission),
cookiePermission != nsICookiePermission::ACCESS_DENY ? "success"
: "failure"));
if (cookiePermission != nsICookiePermission::ACCESS_DENY) {
return true;
}
*aRejectedReason =
nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
return false;
}
int32_t behavior = CookiesBehavior(document);
if (behavior == nsICookieService::BEHAVIOR_ACCEPT) {
LOG(("The cookie behavior pref mandates accepting all cookies!"));
return true;
}
if (ContentBlockingAllowList::Check(aWindow)) {
return true;
}
if (behavior == nsICookieService::BEHAVIOR_REJECT) {
LOG(("The cookie behavior pref mandates rejecting all cookies!"));
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL;
return false;
}
// As a performance optimization, we only perform this check for
// BEHAVIOR_REJECT_FOREIGN and BEHAVIOR_LIMIT_FOREIGN. For
// BEHAVIOR_REJECT_TRACKER and BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
// third-partiness is implicily checked later below.
if (behavior != nsICookieService::BEHAVIOR_REJECT_TRACKER &&
behavior !=
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
// Let's check if this is a 3rd party context.
if (!AntiTrackingUtils::IsThirdPartyWindow(aWindow, aURI)) {
LOG(("Our window isn't a third-party window"));
return true;
}
}
if ((behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN &&
!CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior)) ||
behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
// XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
// simply rejecting the request to use the storage. In the future, if we
// change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
// for non-cookie storage types, this may change.
LOG(("Nothing more to do due to the behavior code %d", int(behavior)));
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
return false;
}
// The document has been allowlisted. We can return from here directly.
if (document->HasStorageAccessPermissionGrantedByAllowList()) {
return true;
}
MOZ_ASSERT(
CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior) ||
behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
behavior ==
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
uint32_t blockedReason =
nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
if (behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER) {
if (!nsContentUtils::IsThirdPartyTrackingResourceWindow(aWindow)) {
LOG(("Our window isn't a third-party tracking window"));
return true;
}
nsCOMPtr<nsIClassifiedChannel> classifiedChannel =
do_QueryInterface(document->GetChannel());
if (classifiedChannel) {
uint32_t classificationFlags =
classifiedChannel->GetThirdPartyClassificationFlags();
if (classificationFlags & nsIClassifiedChannel::ClassificationFlags::
CLASSIFIED_SOCIALTRACKING) {
blockedReason =
nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER;
}
}
} else if (behavior ==
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
if (nsContentUtils::IsThirdPartyTrackingResourceWindow(aWindow)) {
// fall through
} else if (AntiTrackingUtils::IsThirdPartyWindow(aWindow, aURI)) {
LOG(("We're in the third-party context, storage should be partitioned"));
// fall through, but remember that we're partitioning.
blockedReason = nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN;
} else {
LOG(("Our window isn't a third-party window, storage is allowed"));
return true;
}
} else {
MOZ_ASSERT(CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior));
if (RejectForeignAllowList::Check(document)) {
LOG(("This window is exceptionlisted for reject foreign"));
return true;
}
blockedReason = nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN;
}
Document* doc = aWindow->GetExtantDoc();
// Make sure storage access isn't disabled
if (doc && (doc->StorageAccessSandboxed())) {
LOG(("Our document is sandboxed"));
*aRejectedReason = blockedReason;
return false;
}
// Document::HasStoragePermission first checks if storage access granted is
// cached in the inner window, if no, it then checks the storage permission
// flag in the channel's loadinfo
bool allowed = document->HasStorageAccessPermissionGranted();
if (!allowed) {
*aRejectedReason = blockedReason;
} else {
if (MOZ_LOG_TEST(gAntiTrackingLog, mozilla::LogLevel::Debug) &&
aWindow->HasStorageAccessPermissionGranted()) {
LOG(("Permission stored in the window. All good."));
}
}
return allowed;
}
bool ContentBlocking::ShouldAllowAccessFor(nsIChannel* aChannel, nsIURI* aURI,
uint32_t* aRejectedReason) {
MOZ_ASSERT(aURI);
MOZ_ASSERT(aChannel);
// Let's avoid a null check on aRejectedReason everywhere else.
uint32_t rejectedReason = 0;
if (!aRejectedReason) {
aRejectedReason = &rejectedReason;
}
nsIScriptSecurityManager* ssm =
nsScriptSecurityManager::GetScriptSecurityManager();
MOZ_ASSERT(ssm);
nsCOMPtr<nsIURI> channelURI;
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
if (NS_FAILED(rv)) {
LOG(("Failed to get the channel final URI, bail out early"));
return true;
}
LOG_SPEC(
("Computing whether channel %p has access to URI %s", aChannel, _spec),
channelURI);
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
rv = loadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(
("Failed to get the cookie jar settings from the loadinfo, bail out "
"early"));
return true;
}
nsCOMPtr<nsIPrincipal> channelPrincipal;
rv = ssm->GetChannelURIPrincipal(aChannel, getter_AddRefs(channelPrincipal));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("No channel principal, bail out early"));
return false;
}
uint32_t cookiePermission =
CheckCookiePermissionForPrincipal(cookieJarSettings, channelPrincipal);
if (cookiePermission != nsICookiePermission::ACCESS_DEFAULT) {
LOG(
("CheckCookiePermissionForPrincipal() returned a non-default access "
"code (%d) for channel's principal, returning %s",
int(cookiePermission),
cookiePermission != nsICookiePermission::ACCESS_DENY ? "success"
: "failure"));
if (cookiePermission != nsICookiePermission::ACCESS_DENY) {
return true;
}
*aRejectedReason =
nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
return false;
}
if (!channelURI) {
LOG(("No channel uri, bail out early"));
return false;
}
int32_t behavior = CookiesBehavior(loadInfo, channelURI);
if (behavior == nsICookieService::BEHAVIOR_ACCEPT) {
LOG(("The cookie behavior pref mandates accepting all cookies!"));
return true;
}
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (httpChannel && ContentBlockingAllowList::Check(httpChannel)) {
return true;
}
if (behavior == nsICookieService::BEHAVIOR_REJECT) {
LOG(("The cookie behavior pref mandates rejecting all cookies!"));
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL;
return false;
}
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
components::ThirdPartyUtil::Service();
if (!thirdPartyUtil) {
LOG(("No thirdPartyUtil, bail out early"));
return true;
}
bool thirdParty = false;
rv = thirdPartyUtil->IsThirdPartyChannel(aChannel, aURI, &thirdParty);
// Grant if it's not a 3rd party.
// Be careful to check the return value of IsThirdPartyChannel, since
// IsThirdPartyChannel() will fail if the channel's loading principal is the
// system principal...
if (NS_SUCCEEDED(rv) && !thirdParty) {
LOG(("Our channel isn't a third-party channel"));
return true;
}
if ((behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN &&
!CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior)) ||
behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
// XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
// simply rejecting the request to use the storage. In the future, if we
// change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
// for non-cookie storage types, this may change.
LOG(("Nothing more to do due to the behavior code %d", int(behavior)));
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
return false;
}
// The channel has been allowlisted. We can return from here.
if (loadInfo->GetStoragePermission() ==
nsILoadInfo::StoragePermissionAllowListed) {
return true;
}
MOZ_ASSERT(
CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior) ||
behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
behavior ==
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
uint32_t blockedReason =
nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
// Not a tracker.
nsCOMPtr<nsIClassifiedChannel> classifiedChannel =
do_QueryInterface(aChannel);
if (behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER) {
if (classifiedChannel) {
if (!classifiedChannel->IsThirdPartyTrackingResource()) {
LOG(("Our channel isn't a third-party tracking channel"));
return true;
}
uint32_t classificationFlags =
classifiedChannel->GetThirdPartyClassificationFlags();
if (classificationFlags & nsIClassifiedChannel::ClassificationFlags::
CLASSIFIED_SOCIALTRACKING) {
blockedReason =
nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER;
}
}
} else if (behavior ==
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
if (classifiedChannel &&
classifiedChannel->IsThirdPartyTrackingResource()) {
// fall through
} else if (AntiTrackingUtils::IsThirdPartyChannel(aChannel)) {
LOG(("We're in the third-party context, storage should be partitioned"));
// fall through but remember that we're partitioning.
blockedReason = nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN;
} else {
LOG(("Our channel isn't a third-party channel, storage is allowed"));
return true;
}
} else {
MOZ_ASSERT(CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior));
if (httpChannel && RejectForeignAllowList::Check(httpChannel)) {
LOG(("This channel is exceptionlisted"));
return true;
}
blockedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
}
RefPtr<BrowsingContext> targetBC;
rv = loadInfo->GetTargetBrowsingContext(getter_AddRefs(targetBC));
if (!targetBC || NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Failed to get the channel's target browsing context"));
return false;
}
if (Document::StorageAccessSandboxed(targetBC->GetSandboxFlags())) {
LOG(("Our document is sandboxed"));
*aRejectedReason = blockedReason;
return false;
}
// Let's see if we have to grant the access for this particular channel.
// HasStorageAccessPermissionGranted only applies to channels that load
// documents, for sub-resources loads, just returns the result from loadInfo.
bool isDocument = false;
aChannel->GetIsDocument(&isDocument);
if (isDocument) {
nsCOMPtr<nsPIDOMWindowInner> inner =
AntiTrackingUtils::GetInnerWindow(targetBC);
if (inner && inner->HasStorageAccessPermissionGranted()) {
LOG(("Permission stored in the window. All good."));
return true;
}
}
bool allowed =
loadInfo->GetStoragePermission() != nsILoadInfo::NoStoragePermission;
if (!allowed) {
*aRejectedReason = blockedReason;
}
return allowed;
}
bool ContentBlocking::ShouldAllowAccessFor(
nsIPrincipal* aPrincipal, nsICookieJarSettings* aCookieJarSettings) {
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aCookieJarSettings);
uint32_t access = nsICookiePermission::ACCESS_DEFAULT;
if (aPrincipal->GetIsContentPrincipal()) {
PermissionManager* permManager = PermissionManager::GetInstance();
if (permManager) {
Unused << NS_WARN_IF(NS_FAILED(permManager->TestPermissionFromPrincipal(
aPrincipal, "cookie"_ns, &access)));
}
}
if (access != nsICookiePermission::ACCESS_DEFAULT) {
return access != nsICookiePermission::ACCESS_DENY;
}
int32_t behavior = CookiesBehavior(aPrincipal, aCookieJarSettings);
return behavior != nsICookieService::BEHAVIOR_REJECT;
}
/* static */
bool ContentBlocking::ApproximateAllowAccessForWithoutChannel(
nsPIDOMWindowInner* aFirstPartyWindow, nsIURI* aURI) {
MOZ_ASSERT(aFirstPartyWindow);
MOZ_ASSERT(aURI);
LOG_SPEC(
("Computing a best guess as to whether window %p has access to URI %s",
aFirstPartyWindow, _spec),
aURI);
Document* parentDocument =
nsGlobalWindowInner::Cast(aFirstPartyWindow)->GetExtantDoc();
if (NS_WARN_IF(!parentDocument)) {
LOG(("Failed to get the first party window's document"));
return false;
}
if (!parentDocument->CookieJarSettings()->GetRejectThirdPartyContexts()) {
LOG(("Disabled by the pref (%d), bail out early",
parentDocument->CookieJarSettings()->GetCookieBehavior()));
return true;
}
if (ContentBlockingAllowList::Check(aFirstPartyWindow)) {
return true;
}
if (!AntiTrackingUtils::IsThirdPartyWindow(aFirstPartyWindow, aURI)) {
LOG(("Our window isn't a third-party window"));
return true;
}
uint32_t cookiePermission = CheckCookiePermissionForPrincipal(
parentDocument->CookieJarSettings(), parentDocument->NodePrincipal());
if (cookiePermission != nsICookiePermission::ACCESS_DEFAULT) {
LOG(
("CheckCookiePermissionForPrincipal() returned a non-default access "
"code (%d), returning %s",
int(cookiePermission),
cookiePermission != nsICookiePermission::ACCESS_DENY ? "success"
: "failure"));
return cookiePermission != nsICookiePermission::ACCESS_DENY;
}
nsAutoCString origin;
nsresult rv = nsContentUtils::GetASCIIOrigin(aURI, origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG_SPEC(("Failed to compute the origin from %s", _spec), aURI);
return false;
}
nsIPrincipal* parentPrincipal = parentDocument->NodePrincipal();
nsAutoCString type;
AntiTrackingUtils::CreateStoragePermissionKey(origin, type);
return AntiTrackingUtils::CheckStoragePermission(
parentPrincipal, type,
nsContentUtils::IsInPrivateBrowsing(parentDocument), nullptr, 0);
}
NS_IMPL_ISUPPORTS(ContentBlocking::TrackerClassifierFeatureCallback,
nsIUrlClassifierFeatureCallback)
NS_IMETHODIMP
ContentBlocking::TrackerClassifierFeatureCallback::OnClassifyComplete(
const nsTArray<RefPtr<nsIUrlClassifierFeatureResult>>& aResults) {
MOZ_ASSERT(NS_IsMainThread());
if (aResults.IsEmpty()) {
// Reject if we can not find url in tracker list.
mHolder.RejectIfExists(NS_OK, __func__);
return NS_OK;
}
bool isSocialTracker = false;
// Check if the principal is listed in the social tracking list to report
// different tracker type.
for (const auto& result : aResults) {
nsCOMPtr<nsIUrlClassifierFeature> feature;
result->GetFeature(getter_AddRefs(feature));
if (!feature) {
continue;
}
nsAutoCString name;
feature->GetName(name);
if (name.EqualsLiteral("socialtracking-annotation")) {
isSocialTracker = true;
break;
}
}
mHolder.ResolveIfExists(
isSocialTracker
? nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER
: nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER,
__func__);
return NS_OK;
}
/* static */
RefPtr<ContentBlocking::CheckTrackerForPrincipalPromise>
ContentBlocking::CheckTrackerForPrincipal(nsIPrincipal* aPrincipal) {
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(XRE_IsParentProcess());
nsCOMPtr<nsIURI> uri;
auto* basePrincipal = BasePrincipal::Cast(aPrincipal);
basePrincipal->GetURI(getter_AddRefs(uri));
if (!uri) {
LOG(("Cannot get uri from the principal."));
return CheckTrackerForPrincipalPromise::CreateAndReject(NS_ERROR_FAILURE,
__func__);
}
nsresult rv;
nsCOMPtr<nsIURIClassifier> uriClassifier =
mozilla::components::UrlClassifierDB::Service(&rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Cannot get the uri classifier."));
return CheckTrackerForPrincipalPromise::CreateAndReject(rv, __func__);
}
// Check the uri of the principal with the tracking annotation features
// including the social tracker.
nsTArray<nsCString> featureNames = {"tracking-annotation"_ns,
"socialtracking-annotation"_ns};
nsTArray<RefPtr<nsIUrlClassifierFeature>> features;
for (auto& name : featureNames) {
nsCOMPtr<nsIUrlClassifierFeature> feature;
uriClassifier->GetFeatureByName(name, getter_AddRefs(feature));
MOZ_ASSERT(feature);
if (!feature) {
LOG(("Cannot get feature for feature name(%s)", name.get()));
return CheckTrackerForPrincipalPromise::CreateAndReject(NS_ERROR_FAILURE,
__func__);
}
features.AppendElement(feature);
}
auto callback = MakeRefPtr<TrackerClassifierFeatureCallback>();
RefPtr<CheckTrackerForPrincipalPromise> promise = callback->Promise();
rv = uriClassifier->AsyncClassifyLocalWithFeatures(
uri, features, nsIUrlClassifierFeature::blocklist, callback);
if (NS_FAILED(rv)) {
LOG(("Fail on classifying the url."));
callback->Reject(rv);
}
return promise;
}

View File

@ -33,8 +33,44 @@ class ContentParent;
class Document;
} // namespace dom
class StorageAccessAPIHelper final {
class ContentBlocking final {
public:
// This method returns true if the URI has first party storage access when
// loaded inside the passed 3rd party context tracking resource window.
// If the window is first party context, please use
// ApproximateAllowAccessForWithoutChannel();
//
// aRejectedReason could be set to one of these values if passed and if the
// storage permission is not granted:
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN
static bool ShouldAllowAccessFor(nsPIDOMWindowInner* a3rdPartyTrackingWindow,
nsIURI* aURI, uint32_t* aRejectedReason);
// Note: you should use ShouldAllowAccessFor() passing the nsIChannel! Use
// this method _only_ if the channel is not available. For first party
// window, it's impossible to know if the aURI is a tracking resource
// synchronously, so here we return the best guest: if we are sure that the
// permission is granted for the origin of aURI, this method returns true,
// otherwise false.
static bool ApproximateAllowAccessForWithoutChannel(
nsPIDOMWindowInner* aFirstPartyWindow, nsIURI* aURI);
// It returns true if the URI has access to the first party storage.
// aChannel can be a 3rd party channel, or not.
// See ShouldAllowAccessFor(window) to see the possible values of
// aRejectedReason.
static bool ShouldAllowAccessFor(nsIChannel* aChannel, nsIURI* aURI,
uint32_t* aRejectedReason);
// This method checks if the principal has the permission to access to the
// first party storage.
static bool ShouldAllowAccessFor(nsIPrincipal* aPrincipal,
nsICookieJarSettings* aCookieJarSettings);
enum StorageAccessPromptChoices { eAllow, eAllowAutoGrant };
// Grant the permission for aOrigin to have access to the first party storage.
@ -111,9 +147,7 @@ class StorageAccessAPIHelper final {
// Some(false) if unpartitioned cookies will be blocked
// None if it is not clear from settings alone what to do
static Maybe<bool> CheckBrowserSettingsDecidesStorageAccessAPI(
nsICookieJarSettings* aCookieJarSettings, bool aThirdParty,
bool aOnRejectForeignAllowlist, bool aIsOnThirdPartySkipList,
bool aIsThirdPartyTracker);
nsICookieJarSettings* aCookieJarSettings, bool aThirdParty);
// This function checks if the document's context (like if it is third-party
// or an iframe) gives an answer of how a the StorageAccessAPI call, that is
@ -175,6 +209,32 @@ class StorageAccessAPIHelper final {
static void UpdateAllowAccessOnParentProcess(
dom::BrowsingContext* aParentContext, const nsACString& aTrackingOrigin);
typedef MozPromise<uint32_t, nsresult, true> CheckTrackerForPrincipalPromise;
class TrackerClassifierFeatureCallback final
: public nsIUrlClassifierFeatureCallback {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIURLCLASSIFIERFEATURECALLBACK
RefPtr<CheckTrackerForPrincipalPromise> Promise() {
return mHolder.Ensure(__func__);
}
void Reject(nsresult rv) { mHolder.Reject(rv, __func__); }
TrackerClassifierFeatureCallback() = default;
private:
~TrackerClassifierFeatureCallback() = default;
MozPromiseHolder<CheckTrackerForPrincipalPromise> mHolder;
};
// This method checks if the given princpal belongs to a tracker or a social
// tracker.
[[nodiscard]] static RefPtr<CheckTrackerForPrincipalPromise>
CheckTrackerForPrincipal(nsIPrincipal* aPrincipal);
};
} // namespace mozilla

View File

@ -30,10 +30,6 @@ class ContentBlockingAllowList final {
bool aIsPrivateBrowsing, bool& aIsAllowListed);
static bool Check(nsIHttpChannel* aChannel);
// Utility APIs for ContentBlocking.
static bool Check(nsPIDOMWindowInner* aWindow);
static bool Check(nsIPrincipal* aTopWinPrincipal, bool aIsPrivateBrowsing);
static bool Check(nsICookieJarSettings* aCookieJarSettings);
// Computes the principal used to check the content blocking allow list for a
// top-level document based on the document principal. This function is used
@ -44,6 +40,14 @@ class ContentBlockingAllowList final {
static void RecomputePrincipal(nsIURI* aURIBeingLoaded,
const OriginAttributes& aAttrs,
nsIPrincipal** aPrincipal);
private:
// Utility APIs for ContentBlocking.
static bool Check(nsIPrincipal* aTopWinPrincipal, bool aIsPrivateBrowsing);
static bool Check(nsPIDOMWindowInner* aWindow);
static bool Check(nsICookieJarSettings* aCookieJarSettings);
friend class ContentBlocking;
};
} // namespace mozilla

View File

@ -12,7 +12,6 @@
#include "mozilla/StaticPrefs_privacy.h"
#include "mozilla/dom/BrowserChild.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "nsIClassifiedChannel.h"
#include "nsIRunnable.h"

View File

@ -6,9 +6,9 @@
#include "AntiTrackingLog.h"
#include "DynamicFpiRedirectHeuristic.h"
#include "ContentBlocking.h"
#include "ContentBlockingAllowList.h"
#include "ContentBlockingUserInteraction.h"
#include "StorageAccessAPIHelper.h"
#include "mozilla/net/HttpBaseChannel.h"
#include "mozilla/Telemetry.h"
@ -329,10 +329,10 @@ void DynamicFpiRedirectHeuristic(nsIChannel* aOldChannel, nsIURI* aOldURI,
Telemetry::LABELS_STORAGE_ACCESS_GRANTED_COUNT::Redirect);
// We don't care about this promise because the operation is actually sync.
RefPtr<StorageAccessAPIHelper::ParentAccessGrantPromise> promise =
StorageAccessAPIHelper::SaveAccessForOriginOnParentProcess(
RefPtr<ContentBlocking::ParentAccessGrantPromise> promise =
ContentBlocking::SaveAccessForOriginOnParentProcess(
newPrincipal, oldPrincipal,
StorageAccessAPIHelper::StorageAccessPromptChoices::eAllow,
ContentBlocking::StorageAccessPromptChoices::eAllow,
StaticPrefs::privacy_restrict3rdpartystorage_expiration_visited());
Unused << promise;
}

View File

@ -78,11 +78,6 @@ RejectForeignAllowList* RejectForeignAllowList::GetOrCreate() {
return gRejectForeignAllowList;
}
// static
bool RejectForeignAllowList::Check(nsIURI* aURI) {
return GetOrCreate()->CheckInternal(aURI);
}
bool RejectForeignAllowList::CheckInternal(nsIURI* aURI) {
MOZ_ASSERT(aURI);
return nsContentUtils::IsURIInList(aURI, mList);

View File

@ -27,7 +27,6 @@ class RejectForeignAllowList final
static bool Check(dom::Document* aDocument);
static bool Check(nsIHttpChannel* aChannel);
static bool Check(nsIPrincipal* aPrincipal);
static bool Check(nsIURI* aURI);
private:
static RejectForeignAllowList* GetOrCreate();

View File

@ -8,6 +8,7 @@
#include "mozilla/dom/Document.h"
#include "mozilla/net/CookieJarSettings.h"
#include "mozilla/ContentBlocking.h"
#include "mozilla/StaticPrefs_browser.h"
#include "mozilla/StaticPrefs_network.h"
#include "mozilla/StaticPrefs_privacy.h"
@ -22,7 +23,6 @@
using namespace mozilla;
using namespace mozilla::dom;
using mozilla::net::CookieJarSettings;
/**
* Gets the cookie lifetime policy for a given cookieJarSettings and a given
@ -57,28 +57,6 @@ static void GetCookieLifetimePolicyFromCookieJarSettings(
}
}
// This internal method returns ACCESS_DENY if the access is denied,
// ACCESS_DEFAULT if unknown, some other access code if granted.
uint32_t CheckCookiePermissionForPrincipal(
nsICookieJarSettings* aCookieJarSettings, nsIPrincipal* aPrincipal) {
MOZ_ASSERT(aCookieJarSettings);
MOZ_ASSERT(aPrincipal);
uint32_t cookiePermission = nsICookiePermission::ACCESS_DEFAULT;
if (!aPrincipal->GetIsContentPrincipal()) {
return cookiePermission;
}
nsresult rv =
aCookieJarSettings->CookiePermission(aPrincipal, &cookiePermission);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nsICookiePermission::ACCESS_DEFAULT;
}
// If we have a custom cookie permission, let's use it.
return cookiePermission;
}
/*
* Checks if storage for a given principal is permitted by the user's
* preferences. If aWindow is non-null, its principal must be passed as
@ -249,8 +227,8 @@ static bool StorageDisabledByAntiTrackingInternal(
if (aWindow) {
nsIURI* documentURI = aURI ? aURI : aWindow->GetDocumentURI();
return !documentURI ||
!ShouldAllowAccessFor(aWindow, documentURI, &aRejectedReason);
return !documentURI || !ContentBlocking::ShouldAllowAccessFor(
aWindow, documentURI, &aRejectedReason);
}
if (aChannel) {
@ -260,11 +238,12 @@ static bool StorageDisabledByAntiTrackingInternal(
return false;
}
return !ShouldAllowAccessFor(aChannel, uri, &aRejectedReason);
return !ContentBlocking::ShouldAllowAccessFor(aChannel, uri,
&aRejectedReason);
}
MOZ_ASSERT(aPrincipal);
return !ShouldAllowAccessFor(aPrincipal, aCookieJarSettings);
return !ContentBlocking::ShouldAllowAccessFor(aPrincipal, aCookieJarSettings);
}
namespace mozilla {
@ -438,498 +417,4 @@ bool StoragePartitioningEnabled(uint32_t aRejectedReason,
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN;
}
int32_t CookiesBehavior(Document* a3rdPartyDocument) {
MOZ_ASSERT(a3rdPartyDocument);
// WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior
// (See Bug 1406675 and Bug 1525917 for rationale).
if (BasePrincipal::Cast(a3rdPartyDocument->NodePrincipal())->AddonPolicy()) {
return nsICookieService::BEHAVIOR_ACCEPT;
}
return a3rdPartyDocument->CookieJarSettings()->GetCookieBehavior();
}
int32_t CookiesBehavior(nsILoadInfo* aLoadInfo, nsIURI* a3rdPartyURI) {
MOZ_ASSERT(aLoadInfo);
MOZ_ASSERT(a3rdPartyURI);
// WebExtensions 3rd party URI always get BEHAVIOR_ACCEPT as cookieBehavior,
// this is semantically equivalent to the principal having a AddonPolicy().
if (a3rdPartyURI->SchemeIs("moz-extension")) {
return nsICookieService::BEHAVIOR_ACCEPT;
}
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
nsresult rv =
aLoadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nsICookieService::BEHAVIOR_REJECT;
}
return cookieJarSettings->GetCookieBehavior();
}
int32_t CookiesBehavior(nsIPrincipal* aPrincipal,
nsICookieJarSettings* aCookieJarSettings) {
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aCookieJarSettings);
// WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior
// (See Bug 1406675 for rationale).
if (BasePrincipal::Cast(aPrincipal)->AddonPolicy()) {
return nsICookieService::BEHAVIOR_ACCEPT;
}
return aCookieJarSettings->GetCookieBehavior();
}
bool ShouldAllowAccessFor(nsPIDOMWindowInner* aWindow, nsIURI* aURI,
uint32_t* aRejectedReason) {
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aURI);
// Let's avoid a null check on aRejectedReason everywhere else.
uint32_t rejectedReason = 0;
if (!aRejectedReason) {
aRejectedReason = &rejectedReason;
}
LOG_SPEC(("Computing whether window %p has access to URI %s", aWindow, _spec),
aURI);
nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(aWindow);
Document* document = innerWindow->GetExtantDoc();
if (!document) {
LOG(("Our window has no document"));
return false;
}
uint32_t cookiePermission = CheckCookiePermissionForPrincipal(
document->CookieJarSettings(), document->NodePrincipal());
if (cookiePermission != nsICookiePermission::ACCESS_DEFAULT) {
LOG(
("CheckCookiePermissionForPrincipal() returned a non-default access "
"code (%d) for window's principal, returning %s",
int(cookiePermission),
cookiePermission != nsICookiePermission::ACCESS_DENY ? "success"
: "failure"));
if (cookiePermission != nsICookiePermission::ACCESS_DENY) {
return true;
}
*aRejectedReason =
nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
return false;
}
int32_t behavior = CookiesBehavior(document);
if (behavior == nsICookieService::BEHAVIOR_ACCEPT) {
LOG(("The cookie behavior pref mandates accepting all cookies!"));
return true;
}
if (ContentBlockingAllowList::Check(aWindow)) {
return true;
}
if (behavior == nsICookieService::BEHAVIOR_REJECT) {
LOG(("The cookie behavior pref mandates rejecting all cookies!"));
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL;
return false;
}
// As a performance optimization, we only perform this check for
// BEHAVIOR_REJECT_FOREIGN and BEHAVIOR_LIMIT_FOREIGN. For
// BEHAVIOR_REJECT_TRACKER and BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
// third-partiness is implicily checked later below.
if (behavior != nsICookieService::BEHAVIOR_REJECT_TRACKER &&
behavior !=
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
// Let's check if this is a 3rd party context.
if (!AntiTrackingUtils::IsThirdPartyWindow(aWindow, aURI)) {
LOG(("Our window isn't a third-party window"));
return true;
}
}
if ((behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN &&
!CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior)) ||
behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
// XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
// simply rejecting the request to use the storage. In the future, if we
// change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
// for non-cookie storage types, this may change.
LOG(("Nothing more to do due to the behavior code %d", int(behavior)));
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
return false;
}
// The document has been allowlisted. We can return from here directly.
if (document->HasStorageAccessPermissionGrantedByAllowList()) {
return true;
}
MOZ_ASSERT(
CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior) ||
behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
behavior ==
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
uint32_t blockedReason =
nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
if (behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER) {
if (!nsContentUtils::IsThirdPartyTrackingResourceWindow(aWindow)) {
LOG(("Our window isn't a third-party tracking window"));
return true;
}
nsCOMPtr<nsIClassifiedChannel> classifiedChannel =
do_QueryInterface(document->GetChannel());
if (classifiedChannel) {
uint32_t classificationFlags =
classifiedChannel->GetThirdPartyClassificationFlags();
if (classificationFlags & nsIClassifiedChannel::ClassificationFlags::
CLASSIFIED_SOCIALTRACKING) {
blockedReason =
nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER;
}
}
} else if (behavior ==
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
if (nsContentUtils::IsThirdPartyTrackingResourceWindow(aWindow)) {
// fall through
} else if (AntiTrackingUtils::IsThirdPartyWindow(aWindow, aURI)) {
LOG(("We're in the third-party context, storage should be partitioned"));
// fall through, but remember that we're partitioning.
blockedReason = nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN;
} else {
LOG(("Our window isn't a third-party window, storage is allowed"));
return true;
}
} else {
MOZ_ASSERT(CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior));
if (RejectForeignAllowList::Check(document)) {
LOG(("This window is exceptionlisted for reject foreign"));
return true;
}
blockedReason = nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN;
}
Document* doc = aWindow->GetExtantDoc();
// Make sure storage access isn't disabled
if (doc && (doc->StorageAccessSandboxed())) {
LOG(("Our document is sandboxed"));
*aRejectedReason = blockedReason;
return false;
}
// Document::HasStoragePermission first checks if storage access granted is
// cached in the inner window, if no, it then checks the storage permission
// flag in the channel's loadinfo
bool allowed = document->HasStorageAccessPermissionGranted();
if (!allowed) {
*aRejectedReason = blockedReason;
} else {
if (MOZ_LOG_TEST(gAntiTrackingLog, mozilla::LogLevel::Debug) &&
aWindow->HasStorageAccessPermissionGranted()) {
LOG(("Permission stored in the window. All good."));
}
}
return allowed;
}
bool ShouldAllowAccessFor(nsIChannel* aChannel, nsIURI* aURI,
uint32_t* aRejectedReason) {
MOZ_ASSERT(aURI);
MOZ_ASSERT(aChannel);
// Let's avoid a null check on aRejectedReason everywhere else.
uint32_t rejectedReason = 0;
if (!aRejectedReason) {
aRejectedReason = &rejectedReason;
}
nsIScriptSecurityManager* ssm =
nsScriptSecurityManager::GetScriptSecurityManager();
MOZ_ASSERT(ssm);
nsCOMPtr<nsIURI> channelURI;
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
if (NS_FAILED(rv)) {
LOG(("Failed to get the channel final URI, bail out early"));
return true;
}
LOG_SPEC(
("Computing whether channel %p has access to URI %s", aChannel, _spec),
channelURI);
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
rv = loadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(
("Failed to get the cookie jar settings from the loadinfo, bail out "
"early"));
return true;
}
nsCOMPtr<nsIPrincipal> channelPrincipal;
rv = ssm->GetChannelURIPrincipal(aChannel, getter_AddRefs(channelPrincipal));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("No channel principal, bail out early"));
return false;
}
uint32_t cookiePermission =
CheckCookiePermissionForPrincipal(cookieJarSettings, channelPrincipal);
if (cookiePermission != nsICookiePermission::ACCESS_DEFAULT) {
LOG(
("CheckCookiePermissionForPrincipal() returned a non-default access "
"code (%d) for channel's principal, returning %s",
int(cookiePermission),
cookiePermission != nsICookiePermission::ACCESS_DENY ? "success"
: "failure"));
if (cookiePermission != nsICookiePermission::ACCESS_DENY) {
return true;
}
*aRejectedReason =
nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
return false;
}
if (!channelURI) {
LOG(("No channel uri, bail out early"));
return false;
}
int32_t behavior = CookiesBehavior(loadInfo, channelURI);
if (behavior == nsICookieService::BEHAVIOR_ACCEPT) {
LOG(("The cookie behavior pref mandates accepting all cookies!"));
return true;
}
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (httpChannel && ContentBlockingAllowList::Check(httpChannel)) {
return true;
}
if (behavior == nsICookieService::BEHAVIOR_REJECT) {
LOG(("The cookie behavior pref mandates rejecting all cookies!"));
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL;
return false;
}
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
components::ThirdPartyUtil::Service();
if (!thirdPartyUtil) {
LOG(("No thirdPartyUtil, bail out early"));
return true;
}
bool thirdParty = false;
rv = thirdPartyUtil->IsThirdPartyChannel(aChannel, aURI, &thirdParty);
// Grant if it's not a 3rd party.
// Be careful to check the return value of IsThirdPartyChannel, since
// IsThirdPartyChannel() will fail if the channel's loading principal is the
// system principal...
if (NS_SUCCEEDED(rv) && !thirdParty) {
LOG(("Our channel isn't a third-party channel"));
return true;
}
if ((behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN &&
!CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior)) ||
behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
// XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
// simply rejecting the request to use the storage. In the future, if we
// change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
// for non-cookie storage types, this may change.
LOG(("Nothing more to do due to the behavior code %d", int(behavior)));
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
return false;
}
// The channel has been allowlisted. We can return from here.
if (loadInfo->GetStoragePermission() ==
nsILoadInfo::StoragePermissionAllowListed) {
return true;
}
MOZ_ASSERT(
CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior) ||
behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
behavior ==
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
uint32_t blockedReason =
nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
// Not a tracker.
nsCOMPtr<nsIClassifiedChannel> classifiedChannel =
do_QueryInterface(aChannel);
if (behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER) {
if (classifiedChannel) {
if (!classifiedChannel->IsThirdPartyTrackingResource()) {
LOG(("Our channel isn't a third-party tracking channel"));
return true;
}
uint32_t classificationFlags =
classifiedChannel->GetThirdPartyClassificationFlags();
if (classificationFlags & nsIClassifiedChannel::ClassificationFlags::
CLASSIFIED_SOCIALTRACKING) {
blockedReason =
nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER;
}
}
} else if (behavior ==
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
if (classifiedChannel &&
classifiedChannel->IsThirdPartyTrackingResource()) {
// fall through
} else if (AntiTrackingUtils::IsThirdPartyChannel(aChannel)) {
LOG(("We're in the third-party context, storage should be partitioned"));
// fall through but remember that we're partitioning.
blockedReason = nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN;
} else {
LOG(("Our channel isn't a third-party channel, storage is allowed"));
return true;
}
} else {
MOZ_ASSERT(CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior));
if (httpChannel && RejectForeignAllowList::Check(httpChannel)) {
LOG(("This channel is exceptionlisted"));
return true;
}
blockedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
}
RefPtr<BrowsingContext> targetBC;
rv = loadInfo->GetTargetBrowsingContext(getter_AddRefs(targetBC));
if (!targetBC || NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Failed to get the channel's target browsing context"));
return false;
}
if (Document::StorageAccessSandboxed(targetBC->GetSandboxFlags())) {
LOG(("Our document is sandboxed"));
*aRejectedReason = blockedReason;
return false;
}
// Let's see if we have to grant the access for this particular channel.
// HasStorageAccessPermissionGranted only applies to channels that load
// documents, for sub-resources loads, just returns the result from loadInfo.
bool isDocument = false;
aChannel->GetIsDocument(&isDocument);
if (isDocument) {
nsCOMPtr<nsPIDOMWindowInner> inner =
AntiTrackingUtils::GetInnerWindow(targetBC);
if (inner && inner->HasStorageAccessPermissionGranted()) {
LOG(("Permission stored in the window. All good."));
return true;
}
}
bool allowed =
loadInfo->GetStoragePermission() != nsILoadInfo::NoStoragePermission;
if (!allowed) {
*aRejectedReason = blockedReason;
}
return allowed;
}
bool ShouldAllowAccessFor(nsIPrincipal* aPrincipal,
nsICookieJarSettings* aCookieJarSettings) {
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aCookieJarSettings);
uint32_t access = nsICookiePermission::ACCESS_DEFAULT;
if (aPrincipal->GetIsContentPrincipal()) {
PermissionManager* permManager = PermissionManager::GetInstance();
if (permManager) {
Unused << NS_WARN_IF(NS_FAILED(permManager->TestPermissionFromPrincipal(
aPrincipal, "cookie"_ns, &access)));
}
}
if (access != nsICookiePermission::ACCESS_DEFAULT) {
return access != nsICookiePermission::ACCESS_DENY;
}
int32_t behavior = CookiesBehavior(aPrincipal, aCookieJarSettings);
return behavior != nsICookieService::BEHAVIOR_REJECT;
}
/* static */
bool ApproximateAllowAccessForWithoutChannel(
nsPIDOMWindowInner* aFirstPartyWindow, nsIURI* aURI) {
MOZ_ASSERT(aFirstPartyWindow);
MOZ_ASSERT(aURI);
LOG_SPEC(
("Computing a best guess as to whether window %p has access to URI %s",
aFirstPartyWindow, _spec),
aURI);
Document* parentDocument =
nsGlobalWindowInner::Cast(aFirstPartyWindow)->GetExtantDoc();
if (NS_WARN_IF(!parentDocument)) {
LOG(("Failed to get the first party window's document"));
return false;
}
if (!parentDocument->CookieJarSettings()->GetRejectThirdPartyContexts()) {
LOG(("Disabled by the pref (%d), bail out early",
parentDocument->CookieJarSettings()->GetCookieBehavior()));
return true;
}
if (ContentBlockingAllowList::Check(aFirstPartyWindow)) {
return true;
}
if (!AntiTrackingUtils::IsThirdPartyWindow(aFirstPartyWindow, aURI)) {
LOG(("Our window isn't a third-party window"));
return true;
}
uint32_t cookiePermission = CheckCookiePermissionForPrincipal(
parentDocument->CookieJarSettings(), parentDocument->NodePrincipal());
if (cookiePermission != nsICookiePermission::ACCESS_DEFAULT) {
LOG(
("CheckCookiePermissionForPrincipal() returned a non-default access "
"code (%d), returning %s",
int(cookiePermission),
cookiePermission != nsICookiePermission::ACCESS_DENY ? "success"
: "failure"));
return cookiePermission != nsICookiePermission::ACCESS_DENY;
}
nsAutoCString origin;
nsresult rv = nsContentUtils::GetASCIIOrigin(aURI, origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG_SPEC(("Failed to compute the origin from %s", _spec), aURI);
return false;
}
nsIPrincipal* parentPrincipal = parentDocument->NodePrincipal();
nsAutoCString type;
AntiTrackingUtils::CreateStoragePermissionKey(origin, type);
return AntiTrackingUtils::CheckStoragePermission(
parentPrincipal, type,
nsContentUtils::IsInPrivateBrowsing(parentDocument), nullptr, 0);
}
} // namespace mozilla

View File

@ -120,42 +120,6 @@ bool StoragePartitioningEnabled(StorageAccess aAccess,
bool StoragePartitioningEnabled(uint32_t aRejectedReason,
nsICookieJarSettings* aCookieJarSettings);
// This method returns true if the URI has first party storage access when
// loaded inside the passed 3rd party context tracking resource window.
// If the window is first party context, please use
// ApproximateAllowAccessForWithoutChannel();
//
// aRejectedReason could be set to one of these values if passed and if the
// storage permission is not granted:
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL
// * nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN
bool ShouldAllowAccessFor(nsPIDOMWindowInner* a3rdPartyTrackingWindow,
nsIURI* aURI, uint32_t* aRejectedReason);
// Note: you should use ShouldAllowAccessFor() passing the nsIChannel! Use
// this method _only_ if the channel is not available. For first party
// window, it's impossible to know if the aURI is a tracking resource
// synchronously, so here we return the best guest: if we are sure that the
// permission is granted for the origin of aURI, this method returns true,
// otherwise false.
bool ApproximateAllowAccessForWithoutChannel(
nsPIDOMWindowInner* aFirstPartyWindow, nsIURI* aURI);
// It returns true if the URI has access to the first party storage.
// aChannel can be a 3rd party channel, or not.
// See ShouldAllowAccessFor(window) to see the possible values of
// aRejectedReason.
bool ShouldAllowAccessFor(nsIChannel* aChannel, nsIURI* aURI,
uint32_t* aRejectedReason);
// This method checks if the principal has the permission to access to the
// first party storage.
bool ShouldAllowAccessFor(nsIPrincipal* aPrincipal,
nsICookieJarSettings* aCookieJarSettings);
} // namespace mozilla
#endif // mozilla_StorageAccess_h

View File

@ -7,6 +7,7 @@
#include "StoragePrincipalHelper.h"
#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "mozilla/ContentBlocking.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/StaticPrefs_privacy.h"
@ -30,7 +31,7 @@ bool ShouldPartitionChannel(nsIChannel* aChannel,
}
uint32_t rejectedReason = 0;
if (ShouldAllowAccessFor(aChannel, uri, &rejectedReason)) {
if (ContentBlocking::ShouldAllowAccessFor(aChannel, uri, &rejectedReason)) {
return false;
}

View File

@ -38,6 +38,7 @@ EXPORTS.mozilla = [
"AntiTrackingIPCUtils.h",
"AntiTrackingRedirectHeuristic.h",
"AntiTrackingUtils.h",
"ContentBlocking.h",
"ContentBlockingAllowList.h",
"ContentBlockingLog.h",
"ContentBlockingNotifier.h",
@ -45,9 +46,7 @@ EXPORTS.mozilla = [
"ContentBlockingUserInteraction.h",
"DynamicFpiRedirectHeuristic.h",
"PartitioningExceptionList.h",
"RejectForeignAllowList.h",
"StorageAccess.h",
"StorageAccessAPIHelper.h",
"StoragePrincipalHelper.h",
"URLDecorationStripper.h",
"URLQueryStringStripper.h",
@ -56,6 +55,7 @@ EXPORTS.mozilla = [
UNIFIED_SOURCES += [
"AntiTrackingRedirectHeuristic.cpp",
"AntiTrackingUtils.cpp",
"ContentBlocking.cpp",
"ContentBlockingAllowList.cpp",
"ContentBlockingLog.cpp",
"ContentBlockingNotifier.cpp",
@ -66,7 +66,6 @@ UNIFIED_SOURCES += [
"RejectForeignAllowList.cpp",
"SettingsChangeObserver.cpp",
"StorageAccess.cpp",
"StorageAccessAPIHelper.cpp",
"StoragePrincipalHelper.cpp",
"TemporaryAccessGrantObserver.cpp",
"URLDecorationStripper.cpp",

View File

@ -323,7 +323,7 @@ avoid-blacklist-and-whitelist:
- toolkit/actors/RemotePageChild.jsm
- toolkit/actors/WebChannelChild.jsm
- toolkit/components/aboutperformance/content/aboutPerformance.js
- toolkit/components/antitracking/StorageAccessAPIHelper.cpp
- toolkit/components/antitracking/ContentBlocking.cpp
- toolkit/components/antitracking/PurgeTrackerService.jsm
- toolkit/components/antitracking/StorageAccess.cpp
- toolkit/components/antitracking/test/browser/antitracking_head.js