Files
sousa-gecko/dom/ipc/WindowGlobalActor.cpp
Nika Layzell e2b0dec0fc Bug 2030806 - Expose PartitionedPrincipal on WindowGlobalParent, r=smaug,emz
Currently only the DocumentPrincipal and StoragePrincipal (which is
either the document's principal or the partitioned principal) are
exposed on WindowGlobalParent. These are generally the most useful
flags, but sometimes you need the raw partitioned principal.

This patch simplifies the setup by sending down the partitioned
principal when requested, and using a boolean flag to track which
principal should be used as the storage principal.

Differential Revision: https://phabricator.services.mozilla.com/D293366
2026-07-13 19:01:00 +00:00

231 lines
8.7 KiB
C++

/* 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 "mozilla/dom/WindowGlobalActor.h"
#include "AutoplayPolicy.h"
#include "mozilla/Components.h"
#include "mozilla/ContentBlockingAllowList.h"
#include "mozilla/Logging.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/JSActorService.h"
#include "mozilla/dom/JSWindowActorChild.h"
#include "mozilla/dom/JSWindowActorParent.h"
#include "mozilla/dom/JSWindowActorProtocol.h"
#include "mozilla/dom/ParentProcessChannelHandle.h"
#include "mozilla/dom/PopupBlocker.h"
#include "mozilla/dom/WindowContext.h"
#include "mozilla/dom/WindowGlobalChild.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "mozilla/net/CookieJarSettings.h"
#include "nsContentUtils.h"
#include "nsGlobalWindowInner.h"
#include "nsNetUtil.h"
#include "nsPIDOMWindowInlines.h"
namespace mozilla::dom {
// CORPP 3.1.3 https://mikewest.github.io/corpp/#integration-html
static nsILoadInfo::CrossOriginEmbedderPolicy InheritedPolicy(
dom::BrowsingContext* aBrowsingContext) {
WindowContext* inherit = aBrowsingContext->GetParentWindowContext();
if (inherit) {
return inherit->GetEmbedderPolicy();
}
return nsILoadInfo::EMBEDDER_POLICY_NULL;
}
// Common WindowGlobalInit creation code used by both `AboutBlankInitializer`
// and `WindowInitializer`.
WindowGlobalInit WindowGlobalActor::BaseInitializer(
dom::BrowsingContext* aBrowsingContext, uint64_t aInnerWindowId,
uint64_t aOuterWindowId) {
MOZ_DIAGNOSTIC_ASSERT(aBrowsingContext);
using Indexes = WindowContext::FieldIndexes;
WindowGlobalInit init;
auto& ctx = init.context();
ctx.mInnerWindowId = aInnerWindowId;
ctx.mOuterWindowId = aOuterWindowId;
ctx.mBrowsingContextId = aBrowsingContext->Id();
// If any synced fields need to be initialized from our BrowsingContext, we
// can initialize them here.
auto& fields = ctx.mFields;
fields.Get<Indexes::IDX_EmbedderPolicy>() = InheritedPolicy(aBrowsingContext);
fields.Get<Indexes::IDX_AutoplayPermission>() =
nsIPermissionManager::UNKNOWN_ACTION;
fields.Get<Indexes::IDX_AllowJavascript>() = true;
fields.Get<Indexes::IDX_IsFramebustingAllowed>() = aBrowsingContext->IsTop();
return init;
}
WindowGlobalInit WindowGlobalActor::AboutBlankInitializer(
dom::BrowsingContext* aBrowsingContext, nsIPrincipal* aPrincipal) {
MOZ_DIAGNOSTIC_ASSERT(
aPrincipal && aPrincipal->GetIsNullPrincipal(),
"AboutBlankInitializer is a dummy that should not be web-exposed");
WindowGlobalInit init =
BaseInitializer(aBrowsingContext, nsContentUtils::GenerateWindowId(),
nsContentUtils::GenerateWindowId());
init.principal() = aPrincipal;
init.partitionedPrincipal() = aPrincipal;
(void)NS_NewURI(getter_AddRefs(init.documentURI()), "about:blank");
init.isInitialDocument() = true;
init.isUncommittedInitialDocument() = true;
init.partitionStoragePrincipal() = false;
return init;
}
WindowGlobalInit WindowGlobalActor::WindowInitializer(
nsGlobalWindowInner* aWindow) {
WindowGlobalInit init =
BaseInitializer(aWindow->GetBrowsingContext(), aWindow->WindowID(),
aWindow->GetOuterWindow()->WindowID());
init.principal() = aWindow->GetPrincipal();
init.partitionedPrincipal() = aWindow->PartitionedPrincipal();
init.documentURI() = aWindow->GetDocumentURI();
MOZ_RELEASE_ASSERT(VerifyPartitionedPrincipalMatchesDocumentPrincipal(
init.principal(), init.partitionedPrincipal()));
Document* doc = aWindow->GetDocument();
init.isInitialDocument() = doc->IsInitialDocument();
if (Document* original = doc->GetOriginalDocument()) {
init.staticCloneOf() = original->GetWindowContext();
}
init.isUncommittedInitialDocument() = doc->IsUncommittedInitialDocument();
init.isVideoDocument() =
doc->MediaDocumentKind() == Document::MediaDocumentKind::Video;
init.blockAllMixedContent() = doc->GetBlockAllMixedContent(false);
init.upgradeInsecureRequests() = doc->GetUpgradeInsecureRequests(false);
init.partitionStoragePrincipal() = !doc->UseRegularPrincipal();
init.sandboxFlags() = doc->GetSandboxFlags();
net::CookieJarSettings::Cast(doc->CookieJarSettings())
->Serialize(init.cookieJarSettings());
init.httpsOnlyStatus() = doc->HttpsOnlyStatus();
if (nsIChannel* chan = doc->GetChannel()) {
(void)chan->GetParentProcessChannelHandle(
getter_AddRefs(init.documentChannelHandle()));
}
if (nsIChannel* chan = doc->GetFailedChannel()) {
(void)chan->GetParentProcessChannelHandle(
getter_AddRefs(init.failedChannelHandle()));
}
using Indexes = WindowContext::FieldIndexes;
auto& fields = init.context().mFields;
fields.Get<Indexes::IDX_CookieBehavior>() =
Some(doc->CookieJarSettings()->GetCookieBehavior());
fields.Get<Indexes::IDX_IsOnContentBlockingAllowList>() =
doc->CookieJarSettings()->GetIsOnContentBlockingAllowList();
fields.Get<Indexes::IDX_IsThirdPartyWindow>() = doc->HasThirdPartyChannel();
fields.Get<Indexes::IDX_IsThirdPartyTrackingResourceWindow>() =
nsContentUtils::IsThirdPartyTrackingResourceWindow(aWindow);
fields.Get<Indexes::IDX_ShouldResistFingerprinting>() =
doc->ShouldResistFingerprinting(RFPTarget::IsAlwaysEnabledForPrecompute);
fields.Get<Indexes::IDX_OverriddenFingerprintingSettings>() =
doc->GetOverriddenFingerprintingSettings();
fields.Get<Indexes::IDX_IsSecureContext>() = aWindow->IsSecureContext();
fields.Get<Indexes::IDX_IsFramebustingAllowed>() =
aWindow->GetBrowsingContext()->ComputeIsFramebustingAllowed();
// Initialze permission fields
fields.Get<Indexes::IDX_AutoplayPermission>() =
media::AutoplayPolicy::GetSiteAutoplayPermission(init.principal());
fields.Get<Indexes::IDX_PopupPermission>() =
PopupBlocker::GetPopupPermission(init.principal());
// Initialize top level permission fields
if (aWindow->GetBrowsingContext()->IsTop()) {
fields.Get<Indexes::IDX_ShortcutsPermission>() =
nsGlobalWindowInner::GetShortcutsPermission(init.principal());
}
if (auto policy = doc->GetEmbedderPolicy()) {
fields.Get<Indexes::IDX_EmbedderPolicy>() = *policy;
}
// Init Mixed Content Fields
nsCOMPtr<nsIURI> innerDocURI = NS_GetInnermostURI(doc->GetDocumentURI());
fields.Get<Indexes::IDX_IsSecure>() =
innerDocURI && innerDocURI->SchemeIs("https");
if (nsCOMPtr<nsIChannel> channel = doc->GetChannel()) {
nsCOMPtr<nsILoadInfo> loadInfo(channel->LoadInfo());
fields.Get<Indexes::IDX_IsOriginalFrameSource>() =
loadInfo->GetOriginalFrameSrcLoad();
nsILoadInfo::StoragePermissionState storageAccess =
loadInfo->GetStoragePermission();
fields.Get<Indexes::IDX_UsingStorageAccess>() =
storageAccess == nsILoadInfo::HasStoragePermission ||
storageAccess == nsILoadInfo::StoragePermissionAllowListed;
}
fields.Get<Indexes::IDX_IsLocalIP>() =
init.principal()->GetIsLocalIpAddress();
// Most data here is specific to the Document, which can change without
// creating a new WindowGlobal. Anything new added here which fits that
// description should also be synchronized in
// WindowGlobalChild::OnNewDocument.
return init;
}
bool WindowGlobalActor::VerifyPartitionedPrincipalMatchesDocumentPrincipal(
nsIPrincipal* aPrincipal, nsIPrincipal* aPartitionedPrincipal) {
if (!aPrincipal || !aPartitionedPrincipal) {
return false;
}
// OAs must match, with an exemption for the partition key.
if (!aPrincipal->OriginAttributesRef().EqualsIgnoringPartitionKey(
aPartitionedPrincipal->OriginAttributesRef())) {
return false;
}
// The document principal shouldn't have a partition key set.
if (!aPrincipal->OriginAttributesRef().mPartitionKey.IsEmpty()) {
return false;
}
// The rest of the origin must perfectly match.
nsCString noSuffix, partitionedNoSuffix;
MOZ_ALWAYS_SUCCEEDS(aPrincipal->GetOriginNoSuffix(noSuffix));
MOZ_ALWAYS_SUCCEEDS(
aPartitionedPrincipal->GetOriginNoSuffix(partitionedNoSuffix));
return noSuffix == partitionedNoSuffix;
}
already_AddRefed<JSActorProtocol> WindowGlobalActor::MatchingJSActorProtocol(
JSActorService* aActorSvc, const nsACString& aName, ErrorResult& aRv) {
RefPtr<JSWindowActorProtocol> proto =
aActorSvc->GetJSWindowActorProtocol(aName);
if (!proto) {
aRv.ThrowNotFoundError(nsPrintfCString("No such JSWindowActor '%s'",
PromiseFlatCString(aName).get()));
return nullptr;
}
if (!proto->Matches(BrowsingContext(), GetDocumentURI(), GetRemoteType(),
aRv)) {
MOZ_ASSERT(aRv.Failed());
return nullptr;
}
MOZ_ASSERT(!aRv.Failed());
return proto.forget();
}
} // namespace mozilla::dom