/* 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() = InheritedPolicy(aBrowsingContext); fields.Get() = nsIPermissionManager::UNKNOWN_ACTION; fields.Get() = true; fields.Get() = 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() = Some(doc->CookieJarSettings()->GetCookieBehavior()); fields.Get() = doc->CookieJarSettings()->GetIsOnContentBlockingAllowList(); fields.Get() = doc->HasThirdPartyChannel(); fields.Get() = nsContentUtils::IsThirdPartyTrackingResourceWindow(aWindow); fields.Get() = doc->ShouldResistFingerprinting(RFPTarget::IsAlwaysEnabledForPrecompute); fields.Get() = doc->GetOverriddenFingerprintingSettings(); fields.Get() = aWindow->IsSecureContext(); fields.Get() = aWindow->GetBrowsingContext()->ComputeIsFramebustingAllowed(); // Initialze permission fields fields.Get() = media::AutoplayPolicy::GetSiteAutoplayPermission(init.principal()); fields.Get() = PopupBlocker::GetPopupPermission(init.principal()); // Initialize top level permission fields if (aWindow->GetBrowsingContext()->IsTop()) { fields.Get() = nsGlobalWindowInner::GetShortcutsPermission(init.principal()); } if (auto policy = doc->GetEmbedderPolicy()) { fields.Get() = *policy; } // Init Mixed Content Fields nsCOMPtr innerDocURI = NS_GetInnermostURI(doc->GetDocumentURI()); fields.Get() = innerDocURI && innerDocURI->SchemeIs("https"); if (nsCOMPtr channel = doc->GetChannel()) { nsCOMPtr loadInfo(channel->LoadInfo()); fields.Get() = loadInfo->GetOriginalFrameSrcLoad(); nsILoadInfo::StoragePermissionState storageAccess = loadInfo->GetStoragePermission(); fields.Get() = storageAccess == nsILoadInfo::HasStoragePermission || storageAccess == nsILoadInfo::StoragePermissionAllowListed; } fields.Get() = 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 WindowGlobalActor::MatchingJSActorProtocol( JSActorService* aActorSvc, const nsACString& aName, ErrorResult& aRv) { RefPtr 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