gecko-dev/toolkit/components/antitracking/AntiTrackingUtils.cpp

781 строка
25 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AntiTrackingUtils.h"
#include "AntiTrackingLog.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/Components.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/net/CookieJarSettings.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "mozilla/dom/WindowContext.h"
#include "mozilla/net/NeckoChannelParams.h"
#include "mozilla/PermissionManager.h"
#include "mozIThirdPartyUtil.h"
#include "nsGlobalWindowInner.h"
#include "nsIChannel.h"
#include "nsIHttpChannel.h"
#include "nsIPermission.h"
#include "nsIURI.h"
#include "nsNetUtil.h"
#include "nsPIDOMWindow.h"
#include "nsSandboxFlags.h"
#include "nsScriptSecurityManager.h"
#include "PartitioningExceptionList.h"
#define ANTITRACKING_PERM_KEY "3rdPartyStorage"
using namespace mozilla;
using namespace mozilla::dom;
/* static */ already_AddRefed<nsPIDOMWindowInner>
AntiTrackingUtils::GetInnerWindow(BrowsingContext* aBrowsingContext) {
MOZ_ASSERT(aBrowsingContext);
nsCOMPtr<nsPIDOMWindowOuter> outer = aBrowsingContext->GetDOMWindow();
if (!outer) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowInner> inner = outer->GetCurrentInnerWindow();
return inner.forget();
}
/* static */ already_AddRefed<nsPIDOMWindowOuter>
AntiTrackingUtils::GetTopWindow(nsPIDOMWindowInner* aWindow) {
Document* document = aWindow->GetExtantDoc();
if (!document) {
return nullptr;
}
nsIChannel* channel = document->GetChannel();
if (!channel) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowOuter> pwin =
aWindow->GetBrowsingContext()->Top()->GetDOMWindow();
if (!pwin) {
return nullptr;
}
return pwin.forget();
}
/* static */
already_AddRefed<nsIURI> AntiTrackingUtils::MaybeGetDocumentURIBeingLoaded(
nsIChannel* aChannel) {
nsCOMPtr<nsIURI> uriBeingLoaded;
nsLoadFlags loadFlags = 0;
nsresult rv = aChannel->GetLoadFlags(&loadFlags);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) {
// If the channel being loaded is a document channel, this call may be
// coming from an OnStopRequest notification, which might mean that our
// document may still be in the loading process, so we may need to pass in
// the uriBeingLoaded argument explicitly.
rv = aChannel->GetURI(getter_AddRefs(uriBeingLoaded));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
}
return uriBeingLoaded.forget();
}
// static
void AntiTrackingUtils::CreateStoragePermissionKey(
const nsACString& aTrackingOrigin, nsACString& aPermissionKey) {
MOZ_ASSERT(aPermissionKey.IsEmpty());
static const nsLiteralCString prefix =
nsLiteralCString(ANTITRACKING_PERM_KEY "^");
aPermissionKey.SetCapacity(prefix.Length() + aTrackingOrigin.Length());
aPermissionKey.Append(prefix);
aPermissionKey.Append(aTrackingOrigin);
}
// static
bool AntiTrackingUtils::CreateStoragePermissionKey(nsIPrincipal* aPrincipal,
nsACString& aKey) {
if (!aPrincipal) {
return false;
}
nsAutoCString origin;
nsresult rv = aPrincipal->GetOriginNoSuffix(origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
CreateStoragePermissionKey(origin, aKey);
return true;
}
// static
bool AntiTrackingUtils::IsStorageAccessPermission(nsIPermission* aPermission,
nsIPrincipal* aPrincipal) {
MOZ_ASSERT(aPermission);
MOZ_ASSERT(aPrincipal);
// The permission key may belong either to a tracking origin on the same
// origin as the granted origin, or on another origin as the granted origin
// (for example when a tracker in a third-party context uses window.open to
// open another origin where that second origin would be the granted origin.)
// But even in the second case, the type of the permission would still be
// formed by concatenating the granted origin to the end of the type name
// (see CreatePermissionKey). Therefore, we pass in the same argument to
// both tracking origin and granted origin here in order to compute the
// shorter permission key and will then do a prefix match on the type of the
// input permission to see if it is a storage access permission or not.
nsAutoCString permissionKey;
bool result = CreateStoragePermissionKey(aPrincipal, permissionKey);
if (NS_WARN_IF(!result)) {
return false;
}
nsAutoCString type;
nsresult rv = aPermission->GetType(type);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
return StringBeginsWith(type, permissionKey);
}
// static
bool AntiTrackingUtils::CheckStoragePermission(nsIPrincipal* aPrincipal,
const nsAutoCString& aType,
bool aIsInPrivateBrowsing,
uint32_t* aRejectedReason,
uint32_t aBlockedReason) {
PermissionManager* permManager = PermissionManager::GetInstance();
if (NS_WARN_IF(!permManager)) {
LOG(("Failed to obtain the permission manager"));
return false;
}
uint32_t result = 0;
if (aIsInPrivateBrowsing) {
LOG_PRIN(("Querying the permissions for private modei looking for a "
"permission of type %s for %s",
aType.get(), _spec),
aPrincipal);
if (!permManager->PermissionAvailable(aPrincipal, aType)) {
LOG(
("Permission isn't available for this principal in the current "
"process"));
return false;
}
nsTArray<RefPtr<nsIPermission>> permissions;
nsresult rv = permManager->GetAllForPrincipal(aPrincipal, permissions);
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Failed to get the list of permissions"));
return false;
}
bool found = false;
for (const auto& permission : permissions) {
if (!permission) {
LOG(("Couldn't get the permission for unknown reasons"));
continue;
}
nsAutoCString permissionType;
if (NS_SUCCEEDED(permission->GetType(permissionType)) &&
permissionType != aType) {
LOG(("Non-matching permission type: %s", aType.get()));
continue;
}
uint32_t capability = 0;
if (NS_SUCCEEDED(permission->GetCapability(&capability)) &&
capability != nsIPermissionManager::ALLOW_ACTION) {
LOG(("Non-matching permission capability: %d", capability));
continue;
}
uint32_t expirationType = 0;
if (NS_SUCCEEDED(permission->GetExpireType(&expirationType)) &&
expirationType != nsIPermissionManager ::EXPIRE_SESSION) {
LOG(("Non-matching permission expiration type: %d", expirationType));
continue;
}
int64_t expirationTime = 0;
if (NS_SUCCEEDED(permission->GetExpireTime(&expirationTime)) &&
expirationTime != 0) {
LOG(("Non-matching permission expiration time: %" PRId64,
expirationTime));
continue;
}
LOG(("Found a matching permission"));
found = true;
break;
}
if (!found) {
if (aRejectedReason) {
*aRejectedReason = aBlockedReason;
}
return false;
}
} else {
nsresult rv = permManager->TestPermissionWithoutDefaultsFromPrincipal(
aPrincipal, aType, &result);
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Failed to test the permission"));
return false;
}
LOG_PRIN(
("Testing permission type %s for %s resulted in %d (%s)", aType.get(),
_spec, int(result),
result == nsIPermissionManager::ALLOW_ACTION ? "success" : "failure"),
aPrincipal);
if (result != nsIPermissionManager::ALLOW_ACTION) {
if (aRejectedReason) {
*aRejectedReason = aBlockedReason;
}
return false;
}
}
return true;
}
/* static */
nsILoadInfo::StoragePermissionState
AntiTrackingUtils::GetStoragePermissionStateInParent(nsIChannel* aChannel) {
MOZ_ASSERT(aChannel);
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
auto policyType = loadInfo->GetExternalContentPolicyType();
// The channel is for the document load of the top-level window. The top-level
// window should always has 'hasStoragePermission' flag as false. So, we can
// return here directly.
if (policyType == ExtContentPolicy::TYPE_DOCUMENT) {
return nsILoadInfo::NoStoragePermission;
}
nsresult rv =
loadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nsILoadInfo::NoStoragePermission;
}
int32_t cookieBehavior = cookieJarSettings->GetCookieBehavior();
// We only need to check the storage permission if the cookie behavior is
// BEHAVIOR_REJECT_TRACKER, BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN or
// BEHAVIOR_REJECT_FOREIGN with exceptions. Because ContentBlocking wouldn't
// update or check the storage permission if the cookie behavior is not
// belongs to these three.
if (!net::CookieJarSettings::IsRejectThirdPartyContexts(cookieBehavior)) {
return nsILoadInfo::NoStoragePermission;
}
RefPtr<BrowsingContext> bc;
rv = loadInfo->GetTargetBrowsingContext(getter_AddRefs(bc));
if (NS_WARN_IF(NS_FAILED(rv)) || !bc) {
return nsILoadInfo::NoStoragePermission;
}
uint64_t targetWindowId = GetTopLevelAntiTrackingWindowId(bc);
nsCOMPtr<nsIPrincipal> targetPrincipal;
if (targetWindowId) {
RefPtr<WindowGlobalParent> wgp =
WindowGlobalParent::GetByInnerWindowId(targetWindowId);
if (NS_WARN_IF(!wgp)) {
return nsILoadInfo::NoStoragePermission;
}
targetPrincipal = wgp->DocumentPrincipal();
} else {
// We try to use the loading principal if there is no AntiTrackingWindowId.
targetPrincipal = loadInfo->GetLoadingPrincipal();
}
if (!targetPrincipal) {
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (httpChannel) {
// We don't have a loading principal, let's see if this is a document
// channel which belongs to a top-level window.
bool isDocument = false;
rv = httpChannel->GetIsMainDocumentChannel(&isDocument);
if (NS_SUCCEEDED(rv) && isDocument) {
nsIScriptSecurityManager* ssm =
nsScriptSecurityManager::GetScriptSecurityManager();
Unused << ssm->GetChannelResultPrincipal(
aChannel, getter_AddRefs(targetPrincipal));
}
}
}
// Let's use the triggering principal if we still have nothing on the hand.
if (!targetPrincipal) {
targetPrincipal = loadInfo->TriggeringPrincipal();
}
// Cannot get the target principal, bail out.
if (NS_WARN_IF(!targetPrincipal)) {
return nsILoadInfo::NoStoragePermission;
}
nsAutoCString targetOrigin;
if (NS_FAILED(targetPrincipal->GetAsciiOrigin(targetOrigin))) {
return nsILoadInfo::NoStoragePermission;
}
nsCOMPtr<nsIURI> trackingURI;
rv = aChannel->GetURI(getter_AddRefs(trackingURI));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nsILoadInfo::NoStoragePermission;
}
nsAutoCString trackingOrigin;
rv = nsContentUtils::GetASCIIOrigin(trackingURI, trackingOrigin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nsILoadInfo::NoStoragePermission;
}
nsAutoCString type;
AntiTrackingUtils::CreateStoragePermissionKey(trackingOrigin, type);
uint32_t unusedReason = 0;
if (PartitioningExceptionList::Check(targetOrigin, trackingOrigin)) {
return nsILoadInfo::StoragePermissionAllowListed;
}
if (AntiTrackingUtils::CheckStoragePermission(targetPrincipal, type,
NS_UsePrivateBrowsing(aChannel),
&unusedReason, unusedReason)) {
return nsILoadInfo::HasStoragePermission;
}
return nsILoadInfo::NoStoragePermission;
}
uint64_t AntiTrackingUtils::GetTopLevelAntiTrackingWindowId(
BrowsingContext* aBrowsingContext) {
MOZ_ASSERT(aBrowsingContext);
RefPtr<WindowContext> winContext =
aBrowsingContext->GetCurrentWindowContext();
if (!winContext || winContext->GetCookieBehavior().isNothing()) {
return 0;
}
// Do not check BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN her because when
// a third-party subresource is inside the main frame, we need to return the
// top-level window id to partition its cookies correctly.
uint32_t behavior = *winContext->GetCookieBehavior();
if (behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER &&
aBrowsingContext->IsTop()) {
return 0;
}
return aBrowsingContext->Top()->GetCurrentInnerWindowId();
}
uint64_t AntiTrackingUtils::GetTopLevelStorageAreaWindowId(
BrowsingContext* aBrowsingContext) {
MOZ_ASSERT(aBrowsingContext);
if (Document::StorageAccessSandboxed(aBrowsingContext->GetSandboxFlags())) {
return 0;
}
BrowsingContext* parentBC = aBrowsingContext->GetParent();
if (!parentBC) {
// No parent browsing context available!
return 0;
}
if (!parentBC->IsTop()) {
return 0;
}
return parentBC->GetCurrentInnerWindowId();
}
/* static */
already_AddRefed<nsIPrincipal> AntiTrackingUtils::GetPrincipal(
BrowsingContext* aBrowsingContext) {
MOZ_ASSERT(aBrowsingContext);
nsCOMPtr<nsIPrincipal> principal;
if (XRE_IsContentProcess()) {
// Passing an out-of-process browsing context in child processes to
// this API won't get any result, so just assert.
MOZ_ASSERT(aBrowsingContext->IsInProcess());
nsPIDOMWindowOuter* outer = aBrowsingContext->GetDOMWindow();
if (NS_WARN_IF(!outer)) {
return nullptr;
}
nsPIDOMWindowInner* inner = outer->GetCurrentInnerWindow();
if (NS_WARN_IF(!inner)) {
return nullptr;
}
principal = nsGlobalWindowInner::Cast(inner)->GetPrincipal();
} else {
WindowGlobalParent* wgp =
aBrowsingContext->Canonical()->GetCurrentWindowGlobal();
if (NS_WARN_IF(!wgp)) {
return nullptr;
}
principal = wgp->DocumentPrincipal();
}
return principal.forget();
}
/* static */
bool AntiTrackingUtils::GetPrincipalAndTrackingOrigin(
BrowsingContext* aBrowsingContext, nsIPrincipal** aPrincipal,
nsACString& aTrackingOrigin) {
MOZ_ASSERT(aBrowsingContext);
// Passing an out-of-process browsing context in child processes to
// this API won't get any result, so just assert.
MOZ_ASSERT_IF(XRE_IsContentProcess(), aBrowsingContext->IsInProcess());
// Let's take the principal and the origin of the tracker.
nsCOMPtr<nsIPrincipal> principal =
AntiTrackingUtils::GetPrincipal(aBrowsingContext);
if (NS_WARN_IF(!principal)) {
return false;
}
nsresult rv = principal->GetOriginNoSuffix(aTrackingOrigin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
if (aPrincipal) {
principal.forget(aPrincipal);
}
return true;
};
/* static */
uint32_t AntiTrackingUtils::GetCookieBehavior(
BrowsingContext* aBrowsingContext) {
MOZ_ASSERT(aBrowsingContext);
RefPtr<dom::WindowContext> win = aBrowsingContext->GetCurrentWindowContext();
if (!win || win->GetCookieBehavior().isNothing()) {
return nsICookieService::BEHAVIOR_REJECT;
}
return *win->GetCookieBehavior();
}
/* static */
already_AddRefed<WindowGlobalParent>
AntiTrackingUtils::GetTopWindowExcludingExtensionAccessibleContentFrames(
CanonicalBrowsingContext* aBrowsingContext, nsIURI* aURIBeingLoaded) {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(aBrowsingContext);
CanonicalBrowsingContext* bc = aBrowsingContext;
RefPtr<WindowGlobalParent> prev;
while (RefPtr<WindowGlobalParent> parent = bc->GetParentWindowContext()) {
CanonicalBrowsingContext* parentBC = parent->BrowsingContext();
nsIPrincipal* parentPrincipal = parent->DocumentPrincipal();
nsIURI* uri = prev ? prev->GetDocumentURI() : aURIBeingLoaded;
// If the new parent has permission to load the current page, we're
// at a moz-extension:// frame which has a host permission that allows
// it to load the document that we've loaded. In that case, stop at
// this frame and consider it the top-level frame.
if (uri &&
BasePrincipal::Cast(parentPrincipal)->AddonAllowsLoad(uri, true)) {
break;
}
bc = parentBC;
prev = parent;
}
if (!prev) {
prev = bc->GetCurrentWindowGlobal();
}
return prev.forget();
}
/* static */
void AntiTrackingUtils::ComputeIsThirdPartyToTopWindow(nsIChannel* aChannel) {
MOZ_ASSERT(aChannel);
MOZ_ASSERT(XRE_IsParentProcess());
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
// When a top-level load is opened by window.open, BrowsingContext from
// LoadInfo is its opener, which may make the third-party caculation code
// below returns an incorrect result. So we use TYPE_DOCUMENT to
// ensure a top-level load is not considered 3rd-party.
auto policyType = loadInfo->GetExternalContentPolicyType();
if (policyType == ExtContentPolicy::TYPE_DOCUMENT) {
loadInfo->SetIsThirdPartyContextToTopWindow(false);
return;
}
RefPtr<BrowsingContext> bc;
loadInfo->GetBrowsingContext(getter_AddRefs(bc));
nsCOMPtr<nsIURI> uri;
Unused << aChannel->GetURI(getter_AddRefs(uri));
// In some cases we don't have a browsingContext. For example, in xpcshell
// tests or channels that are used to download images.
if (!bc) {
// We turn to check the loading principal if there is no browsing context.
auto* loadingPrincipal =
BasePrincipal::Cast(loadInfo->GetLoadingPrincipal());
if (uri && loadingPrincipal) {
bool isThirdParty = true;
nsresult rv = loadingPrincipal->IsThirdPartyURI(uri, &isThirdParty);
if (NS_SUCCEEDED(rv)) {
loadInfo->SetIsThirdPartyContextToTopWindow(isThirdParty);
}
}
return;
}
RefPtr<WindowGlobalParent> topWindow =
GetTopWindowExcludingExtensionAccessibleContentFrames(bc->Canonical(),
uri);
if (NS_WARN_IF(!topWindow)) {
return;
}
nsCOMPtr<nsIPrincipal> topWindowPrincipal = topWindow->DocumentPrincipal();
if (topWindowPrincipal && !topWindowPrincipal->GetIsNullPrincipal()) {
auto* basePrin = BasePrincipal::Cast(topWindowPrincipal);
bool isThirdParty = true;
// For about:blank, we can't just compare uri to determine whether the page
// is third-party, so we use channel result principal instead. By doing
// this, an about:blank inherits the principal from its parent is considered
// not a third-party.
if (NS_IsAboutBlank(uri)) {
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
if (NS_WARN_IF(!ssm)) {
return;
}
nsCOMPtr<nsIPrincipal> principal;
nsresult rv =
ssm->GetChannelResultPrincipal(aChannel, getter_AddRefs(principal));
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
basePrin->IsThirdPartyPrincipal(principal, &isThirdParty);
} else {
basePrin->IsThirdPartyURI(uri, &isThirdParty);
}
loadInfo->SetIsThirdPartyContextToTopWindow(isThirdParty);
}
}
/* static */
bool AntiTrackingUtils::IsThirdPartyChannel(nsIChannel* aChannel) {
MOZ_ASSERT(aChannel);
// We only care whether the channel is 3rd-party with respect to
// the top-level.
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
return loadInfo->GetIsThirdPartyContextToTopWindow();
}
/* static */
bool AntiTrackingUtils::IsThirdPartyWindow(nsPIDOMWindowInner* aWindow,
nsIURI* aURI) {
MOZ_ASSERT(aWindow);
// We assume that the window is foreign to the URI by default.
bool thirdParty = true;
// This is to comply with ThirdPartyUtil::IsThirdPartyWindow API.
if (aURI && !NS_IsAboutBlank(aURI)) {
nsCOMPtr<nsIScriptObjectPrincipal> scriptObjPrin =
do_QueryInterface(aWindow);
if (!scriptObjPrin) {
return thirdParty;
}
nsCOMPtr<nsIPrincipal> prin = scriptObjPrin->GetPrincipal();
if (!prin) {
return thirdParty;
}
// Determine whether aURI is foreign with respect to the current principal.
nsresult rv = prin->IsThirdPartyURI(aURI, &thirdParty);
if (NS_FAILED(rv)) {
return thirdParty;
}
if (thirdParty) {
return thirdParty;
}
}
RefPtr<Document> doc = aWindow->GetDoc();
if (!doc) {
// If we can't get the document from the window, ex, about:blank, fallback
// to use IsThirdPartyWindow check that examine the whole hierarchy.
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
components::ThirdPartyUtil::Service();
Unused << thirdPartyUtil->IsThirdPartyWindow(aWindow->GetOuterWindow(),
nullptr, &thirdParty);
return thirdParty;
}
if (!doc->GetChannel()) {
// If we can't get the channel from the document, i.e. initial about:blank
// page, we use the browsingContext of the document to check if it's in the
// third-party context. If the browsing context is still not available, we
// will treat the window as third-party.
RefPtr<BrowsingContext> bc = doc->GetBrowsingContext();
return bc ? IsThirdPartyContext(bc) : true;
}
// We only care whether the channel is 3rd-party with respect to
// the top-level.
nsCOMPtr<nsILoadInfo> loadInfo = doc->GetChannel()->LoadInfo();
return loadInfo->GetIsThirdPartyContextToTopWindow();
}
/* static */
bool AntiTrackingUtils::IsThirdPartyContext(BrowsingContext* aBrowsingContext) {
MOZ_ASSERT(aBrowsingContext);
MOZ_ASSERT(aBrowsingContext->IsInProcess());
if (aBrowsingContext->IsTopContent()) {
return false;
}
// If the top browsing context is not in the same process, it's cross-origin.
if (!aBrowsingContext->Top()->IsInProcess()) {
return true;
}
nsIDocShell* docShell = aBrowsingContext->GetDocShell();
if (!docShell) {
return true;
}
Document* doc = docShell->GetExtantDocument();
if (!doc) {
return true;
}
nsIPrincipal* principal = doc->NodePrincipal();
nsIDocShell* topDocShell = aBrowsingContext->Top()->GetDocShell();
if (!topDocShell) {
return true;
}
Document* topDoc = topDocShell->GetDocument();
if (!topDoc) {
return true;
}
nsIPrincipal* topPrincipal = topDoc->NodePrincipal();
auto* topBasePrin = BasePrincipal::Cast(topPrincipal);
bool isThirdParty = true;
topBasePrin->IsThirdPartyPrincipal(principal, &isThirdParty);
return isThirdParty;
}
/* static */
nsCString AntiTrackingUtils::GrantedReasonToString(
ContentBlockingNotifier::StorageAccessPermissionGrantedReason aReason) {
switch (aReason) {
case ContentBlockingNotifier::eOpener:
return "opener"_ns;
case ContentBlockingNotifier::eOpenerAfterUserInteraction:
return "user interaction"_ns;
default:
return "stroage access API"_ns;
}
}
/* static */
void AntiTrackingUtils::UpdateAntiTrackingInfoForChannel(nsIChannel* aChannel) {
MOZ_ASSERT(aChannel);
if (!XRE_IsParentProcess()) {
return;
}
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
Unused << loadInfo->SetStoragePermission(
AntiTrackingUtils::GetStoragePermissionStateInParent(aChannel));
AntiTrackingUtils::ComputeIsThirdPartyToTopWindow(aChannel);
// We only update the IsOnContentBlockingAllowList flag and the partition key
// for the top-level http channel.
//
// The IsOnContentBlockingAllowList is only for http. For other types of
// channels, such as 'file:', there will be no interface to modify this. So,
// we only update it in http channels.
//
// The partition key is computed based on the site, so it's no point to set it
// for channels other than http channels.
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (!httpChannel || loadInfo->GetExternalContentPolicyType() !=
ExtContentPolicy::TYPE_DOCUMENT) {
return;
}
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
Unused << loadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
// Update the IsOnContentBlockingAllowList flag in the CookieJarSettings
// if this is a top level loading. For sub-document loading, this flag
// would inherit from the parent.
net::CookieJarSettings::Cast(cookieJarSettings)
->UpdateIsOnContentBlockingAllowList(aChannel);
// We only need to set FPD for top-level loads. FPD will automatically be
// propagated to non-top level loads via CookieJarSetting.
nsCOMPtr<nsIURI> uri;
Unused << aChannel->GetURI(getter_AddRefs(uri));
net::CookieJarSettings::Cast(cookieJarSettings)->SetPartitionKey(uri);
}