diff options
Diffstat (limited to 'caps/BasePrincipal.cpp')
-rw-r--r-- | caps/BasePrincipal.cpp | 1613 |
1 files changed, 1613 insertions, 0 deletions
diff --git a/caps/BasePrincipal.cpp b/caps/BasePrincipal.cpp new file mode 100644 index 0000000000..6cd94741b0 --- /dev/null +++ b/caps/BasePrincipal.cpp @@ -0,0 +1,1613 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 sw=2 et 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 "mozilla/BasePrincipal.h" + +#include "nsDocShell.h" + +#include "ExpandedPrincipal.h" +#include "nsNetUtil.h" +#include "nsContentUtils.h" +#include "nsIOService.h" +#include "nsIURIWithSpecialOrigin.h" +#include "nsScriptSecurityManager.h" +#include "nsServiceManagerUtils.h" +#include "nsAboutProtocolUtils.h" +#include "ThirdPartyUtil.h" +#include "mozilla/ContentPrincipal.h" +#include "mozilla/ExtensionPolicyService.h" +#include "mozilla/NullPrincipal.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" +#include "mozilla/dom/ChromeUtils.h" +#include "mozilla/dom/ReferrerInfo.h" +#include "mozilla/dom/ToJSValue.h" +#include "mozilla/dom/nsMixedContentBlocker.h" +#include "mozilla/Components.h" +#include "mozilla/dom/StorageUtils.h" +#include "mozilla/dom/StorageUtils.h" +#include "mozilla/JSONStringWriteFuncs.h" +#include "mozilla/JSONWriter.h" +#include "nsIURL.h" +#include "nsEffectiveTLDService.h" +#include "nsIURIMutator.h" +#include "mozilla/StaticPrefs_permissions.h" +#include "nsIURIMutator.h" +#include "nsMixedContentBlocker.h" +#include "prnetdb.h" +#include "nsIURIFixup.h" +#include "mozilla/dom/StorageUtils.h" +#include "mozilla/StorageAccess.h" +#include "nsPIDOMWindow.h" +#include "nsIURIMutator.h" +#include "mozilla/PermissionManager.h" + +#include "nsSerializationHelper.h" + +#include "js/JSON.h" +#include "ContentPrincipalJSONHandler.h" +#include "ExpandedPrincipalJSONHandler.h" +#include "NullPrincipalJSONHandler.h" +#include "PrincipalJSONHandler.h" +#include "SubsumedPrincipalJSONHandler.h" + +namespace mozilla { + +BasePrincipal::BasePrincipal(PrincipalKind aKind, + const nsACString& aOriginNoSuffix, + const OriginAttributes& aOriginAttributes) + : mOriginNoSuffix(NS_Atomize(aOriginNoSuffix)), + mOriginSuffix(aOriginAttributes.CreateSuffixAtom()), + mOriginAttributes(aOriginAttributes), + mKind(aKind), + mHasExplicitDomain(false) {} + +BasePrincipal::BasePrincipal(BasePrincipal* aOther, + const OriginAttributes& aOriginAttributes) + : mOriginNoSuffix(aOther->mOriginNoSuffix), + mOriginSuffix(aOriginAttributes.CreateSuffixAtom()), + mOriginAttributes(aOriginAttributes), + mKind(aOther->mKind), + mHasExplicitDomain(aOther->mHasExplicitDomain.load()) {} + +BasePrincipal::~BasePrincipal() = default; + +NS_IMETHODIMP +BasePrincipal::GetOrigin(nsACString& aOrigin) { + nsresult rv = GetOriginNoSuffix(aOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString suffix; + rv = GetOriginSuffix(suffix); + NS_ENSURE_SUCCESS(rv, rv); + aOrigin.Append(suffix); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetWebExposedOriginSerialization(nsACString& aOrigin) { + aOrigin.Truncate(); + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_ERROR_NOT_AVAILABLE; + } + return nsContentUtils::GetWebExposedOriginSerialization(prinURI, aOrigin); +} + +NS_IMETHODIMP +BasePrincipal::GetHostPort(nsACString& aRes) { + aRes.Truncate(); + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + return prinURI->GetHostPort(aRes); +} + +NS_IMETHODIMP +BasePrincipal::GetHost(nsACString& aRes) { + aRes.Truncate(); + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + return prinURI->GetHost(aRes); +} + +NS_IMETHODIMP +BasePrincipal::GetOriginNoSuffix(nsACString& aOrigin) { + mOriginNoSuffix->ToUTF8String(aOrigin); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetSiteOrigin(nsACString& aSiteOrigin) { + nsresult rv = GetSiteOriginNoSuffix(aSiteOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString suffix; + rv = GetOriginSuffix(suffix); + NS_ENSURE_SUCCESS(rv, rv); + aSiteOrigin.Append(suffix); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetSiteOriginNoSuffix(nsACString& aSiteOrigin) { + return GetOriginNoSuffix(aSiteOrigin); +} + +template <typename HandlerTypesT> +bool ContainerPrincipalJSONHandler<HandlerTypesT>::ProcessInnerResult( + bool aResult) { + if (!aResult) { + NS_WARNING("Failed to parse inner object"); + mState = State::Error; + return false; + } + return true; +} + +template <typename HandlerTypesT> +bool ContainerPrincipalJSONHandler<HandlerTypesT>::startObject() { + if (mInnerHandler.isSome()) { + return CallOnInner([&](auto& aInner) { return aInner.startObject(); }); + } + + switch (mState) { + case State::Init: + mState = State::StartObject; + break; + case State::SystemPrincipal_Key: + mState = State::SystemPrincipal_StartObject; + break; + default: + NS_WARNING("Unexpected object value"); + mState = State::Error; + return false; + } + + return true; +} + +template <typename HandlerTypesT> +bool ContainerPrincipalJSONHandler<HandlerTypesT>::propertyName( + const JS::Latin1Char* name, size_t length) { + if (mInnerHandler.isSome()) { + return CallOnInner( + [&](auto& aInner) { return aInner.propertyName(name, length); }); + } + + switch (mState) { + case State::StartObject: { + if (length != 1) { + NS_WARNING( + nsPrintfCString("Unexpected property name length: %zu", length) + .get()); + mState = State::Error; + return false; + } + + char key = char(name[0]); + switch (key) { + case BasePrincipal::NullPrincipalKey: + mState = State::NullPrincipal_Inner; + mInnerHandler.emplace(VariantType<NullPrincipalJSONHandler>()); + break; + case BasePrincipal::ContentPrincipalKey: + mState = State::ContentPrincipal_Inner; + mInnerHandler.emplace(VariantType<ContentPrincipalJSONHandler>()); + break; + case BasePrincipal::SystemPrincipalKey: + mState = State::SystemPrincipal_Key; + break; + default: + if constexpr (CanContainExpandedPrincipal) { + if (key == BasePrincipal::ExpandedPrincipalKey) { + mState = State::ExpandedPrincipal_Inner; + mInnerHandler.emplace( + VariantType<ExpandedPrincipalJSONHandler>()); + break; + } + } + NS_WARNING( + nsPrintfCString("Unexpected property name: '%c'", key).get()); + mState = State::Error; + return false; + } + break; + } + default: + NS_WARNING("Unexpected property name"); + mState = State::Error; + return false; + } + + return true; +} + +template <typename HandlerTypesT> +bool ContainerPrincipalJSONHandler<HandlerTypesT>::endObject() { + if (mInnerHandler.isSome()) { + return CallOnInner([&](auto& aInner) { + if (!aInner.endObject()) { + return false; + } + if (aInner.HasAccepted()) { + this->mPrincipal = aInner.mPrincipal.forget(); + MOZ_ASSERT(this->mPrincipal); + mInnerHandler.reset(); + } + return true; + }); + } + + switch (mState) { + case State::SystemPrincipal_StartObject: + mState = State::SystemPrincipal_EndObject; + break; + case State::SystemPrincipal_EndObject: + this->mPrincipal = + BasePrincipal::Cast(nsContentUtils::GetSystemPrincipal()); + mState = State::EndObject; + break; + case State::NullPrincipal_Inner: + mState = State::EndObject; + break; + case State::ContentPrincipal_Inner: + mState = State::EndObject; + break; + default: + if constexpr (CanContainExpandedPrincipal) { + if (mState == State::ExpandedPrincipal_Inner) { + mState = State::EndObject; + break; + } + } + NS_WARNING("Unexpected end of object"); + mState = State::Error; + return false; + } + + return true; +} + +template <typename HandlerTypesT> +bool ContainerPrincipalJSONHandler<HandlerTypesT>::startArray() { + if constexpr (CanContainExpandedPrincipal) { + if (mInnerHandler.isSome()) { + return CallOnInner([&](auto& aInner) { return aInner.startArray(); }); + } + } + + NS_WARNING("Unexpected array value"); + mState = State::Error; + return false; +} + +template <typename HandlerTypesT> +bool ContainerPrincipalJSONHandler<HandlerTypesT>::endArray() { + if constexpr (CanContainExpandedPrincipal) { + if (mInnerHandler.isSome()) { + return CallOnInner([&](auto& aInner) { return aInner.endArray(); }); + } + } + + NS_WARNING("Unexpected array value"); + mState = State::Error; + return false; +} + +template <typename HandlerTypesT> +bool ContainerPrincipalJSONHandler<HandlerTypesT>::stringValue( + const JS::Latin1Char* str, size_t length) { + if (mInnerHandler.isSome()) { + return CallOnInner( + [&](auto& aInner) { return aInner.stringValue(str, length); }); + } + + NS_WARNING("Unexpected string value"); + mState = State::Error; + return false; +} + +template class ContainerPrincipalJSONHandler<PrincipalJSONHandlerTypes>; +template class ContainerPrincipalJSONHandler<SubsumedPrincipalJSONHandlerTypes>; + +// Takes a JSON string and parses it turning it into a principal of the +// corresponding type +// +// Given a content principal: +// +// inner JSON object +// | +// --------------------------------------------------------- +// | | +// {"1": {"0": "https://mozilla.com", "2": "^privateBrowsingId=1"}} +// | | | | | +// | ----------------------------- | +// | | | | +// PrincipalKind | | | +// | ---------------------------- +// SerializableKeys | +// Value +// +already_AddRefed<BasePrincipal> BasePrincipal::FromJSON( + const nsACString& aJSON) { + PrincipalJSONHandler handler; + + if (!JS::ParseJSONWithHandler( + reinterpret_cast<const JS::Latin1Char*>(aJSON.BeginReading()), + aJSON.Length(), &handler)) { + NS_WARNING( + nsPrintfCString("Unable to parse: %s", aJSON.BeginReading()).get()); + MOZ_ASSERT(false, + "Unable to parse string as JSON to deserialize as a principal"); + return nullptr; + } + + return handler.Get(); +} + +// Returns a JSON representation of the principal. +// Calling BasePrincipal::FromJSON will deserialize the JSON into +// the corresponding principal type. +nsresult BasePrincipal::ToJSON(nsACString& aJSON) { + MOZ_ASSERT(aJSON.IsEmpty(), "ToJSON only supports an empty result input"); + aJSON.Truncate(); + + // NOTE: JSONWriter emits raw UTF-8 code units for non-ASCII range. + JSONStringRefWriteFunc func(aJSON); + JSONWriter writer(func, JSONWriter::CollectionStyle::SingleLineStyle); + + nsresult rv = ToJSON(writer); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +nsresult BasePrincipal::ToJSON(JSONWriter& aWriter) { + static_assert(eKindMax < ArrayLength(JSONEnumKeyStrings)); + + aWriter.Start(JSONWriter::CollectionStyle::SingleLineStyle); + + nsresult rv = WriteJSONProperties(aWriter); + NS_ENSURE_SUCCESS(rv, rv); + + aWriter.End(); + + return NS_OK; +} + +nsresult BasePrincipal::WriteJSONProperties(JSONWriter& aWriter) { + aWriter.StartObjectProperty(JSONEnumKeyStrings[Kind()], + JSONWriter::CollectionStyle::SingleLineStyle); + + nsresult rv = WriteJSONInnerProperties(aWriter); + NS_ENSURE_SUCCESS(rv, rv); + + aWriter.EndObject(); + + return NS_OK; +} + +nsresult BasePrincipal::WriteJSONInnerProperties(JSONWriter& aWriter) { + return NS_OK; +} + +bool BasePrincipal::FastSubsumesIgnoringFPD( + nsIPrincipal* aOther, DocumentDomainConsideration aConsideration) { + MOZ_ASSERT(aOther); + + if (Kind() == eContentPrincipal && + !dom::ChromeUtils::IsOriginAttributesEqualIgnoringFPD( + mOriginAttributes, Cast(aOther)->mOriginAttributes)) { + return false; + } + + return SubsumesInternal(aOther, aConsideration); +} + +bool BasePrincipal::Subsumes(nsIPrincipal* aOther, + DocumentDomainConsideration aConsideration) { + MOZ_ASSERT(aOther); + MOZ_ASSERT_IF(Kind() == eContentPrincipal, mOriginSuffix); + + // Expanded principals handle origin attributes for each of their + // sub-principals individually, null principals do only simple checks for + // pointer equality, and system principals are immune to origin attributes + // checks, so only do this check for content principals. + if (Kind() == eContentPrincipal && + mOriginSuffix != Cast(aOther)->mOriginSuffix) { + return false; + } + + return SubsumesInternal(aOther, aConsideration); +} + +NS_IMETHODIMP +BasePrincipal::Equals(nsIPrincipal* aOther, bool* aResult) { + NS_ENSURE_ARG_POINTER(aOther); + + *aResult = FastEquals(aOther); + + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::EqualsForPermission(nsIPrincipal* aOther, bool aExactHost, + bool* aResult) { + *aResult = false; + NS_ENSURE_ARG_POINTER(aOther); + NS_ENSURE_ARG_POINTER(aResult); + + auto* other = Cast(aOther); + if (Kind() != other->Kind()) { + // Principals of different kinds can't be equal. + return NS_OK; + } + + if (Kind() == eSystemPrincipal) { + *aResult = this == other; + return NS_OK; + } + + if (Kind() == eNullPrincipal) { + // We don't store permissions for NullPrincipals. + return NS_OK; + } + + MOZ_ASSERT(Kind() == eExpandedPrincipal || Kind() == eContentPrincipal); + + // Certain origin attributes should not be used to isolate permissions. + // Create a stripped copy of both OA sets to compare. + mozilla::OriginAttributes ourAttrs = mOriginAttributes; + PermissionManager::MaybeStripOriginAttributes(false, ourAttrs); + mozilla::OriginAttributes theirAttrs = aOther->OriginAttributesRef(); + PermissionManager::MaybeStripOriginAttributes(false, theirAttrs); + + if (ourAttrs != theirAttrs) { + return NS_OK; + } + + if (mOriginNoSuffix == other->mOriginNoSuffix) { + *aResult = true; + return NS_OK; + } + + // If we are matching with an exact host, we're done now - the permissions + // don't match otherwise, we need to start comparing subdomains! + if (aExactHost) { + return NS_OK; + } + + nsCOMPtr<nsIURI> ourURI; + nsresult rv = GetURI(getter_AddRefs(ourURI)); + NS_ENSURE_SUCCESS(rv, rv); + // Some principal types may indicate success, but still return nullptr for + // URI. + NS_ENSURE_TRUE(ourURI, NS_ERROR_FAILURE); + + nsCOMPtr<nsIURI> otherURI; + rv = other->GetURI(getter_AddRefs(otherURI)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(otherURI, NS_ERROR_FAILURE); + + // Compare schemes + nsAutoCString otherScheme; + rv = otherURI->GetScheme(otherScheme); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString ourScheme; + rv = ourURI->GetScheme(ourScheme); + NS_ENSURE_SUCCESS(rv, rv); + + if (otherScheme != ourScheme) { + return NS_OK; + } + + // Compare ports + int32_t otherPort; + rv = otherURI->GetPort(&otherPort); + NS_ENSURE_SUCCESS(rv, rv); + + int32_t ourPort; + rv = ourURI->GetPort(&ourPort); + NS_ENSURE_SUCCESS(rv, rv); + + if (otherPort != ourPort) { + return NS_OK; + } + + // Check if the host or any subdomain of their host matches. + nsAutoCString otherHost; + rv = otherURI->GetHost(otherHost); + if (NS_FAILED(rv) || otherHost.IsEmpty()) { + return NS_OK; + } + + nsAutoCString ourHost; + rv = ourURI->GetHost(ourHost); + if (NS_FAILED(rv) || ourHost.IsEmpty()) { + return NS_OK; + } + + nsCOMPtr<nsIEffectiveTLDService> tldService = + do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); + if (!tldService) { + NS_ERROR("Should have a tld service!"); + return NS_ERROR_FAILURE; + } + + // This loop will not loop forever, as GetNextSubDomain will eventually fail + // with NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS. + while (otherHost != ourHost) { + rv = tldService->GetNextSubDomain(otherHost, otherHost); + if (NS_FAILED(rv)) { + if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) { + return NS_OK; + } + return rv; + } + } + + *aResult = true; + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::EqualsConsideringDomain(nsIPrincipal* aOther, bool* aResult) { + NS_ENSURE_ARG_POINTER(aOther); + + *aResult = FastEqualsConsideringDomain(aOther); + + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::EqualsURI(nsIURI* aOtherURI, bool* aResult) { + *aResult = false; + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + return prinURI->EqualsExceptRef(aOtherURI, aResult); +} + +NS_IMETHODIMP +BasePrincipal::Subsumes(nsIPrincipal* aOther, bool* aResult) { + NS_ENSURE_ARG_POINTER(aOther); + + *aResult = FastSubsumes(aOther); + + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::SubsumesConsideringDomain(nsIPrincipal* aOther, bool* aResult) { + NS_ENSURE_ARG_POINTER(aOther); + + *aResult = FastSubsumesConsideringDomain(aOther); + + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::SubsumesConsideringDomainIgnoringFPD(nsIPrincipal* aOther, + bool* aResult) { + NS_ENSURE_ARG_POINTER(aOther); + + *aResult = FastSubsumesConsideringDomainIgnoringFPD(aOther); + + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::CheckMayLoad(nsIURI* aURI, bool aAllowIfInheritsPrincipal) { + AssertIsOnMainThread(); + return CheckMayLoadHelper(aURI, aAllowIfInheritsPrincipal, false, 0); +} + +NS_IMETHODIMP +BasePrincipal::CheckMayLoadWithReporting(nsIURI* aURI, + bool aAllowIfInheritsPrincipal, + uint64_t aInnerWindowID) { + AssertIsOnMainThread(); + return CheckMayLoadHelper(aURI, aAllowIfInheritsPrincipal, true, + aInnerWindowID); +} + +nsresult BasePrincipal::CheckMayLoadHelper(nsIURI* aURI, + bool aAllowIfInheritsPrincipal, + bool aReport, + uint64_t aInnerWindowID) { + AssertIsOnMainThread(); // Accesses non-threadsafe URI flags and the + // non-threadsafe ExtensionPolicyService + NS_ENSURE_ARG_POINTER(aURI); + MOZ_ASSERT( + aReport || aInnerWindowID == 0, + "Why do we have an inner window id if we're not supposed to report?"); + + // Check the internal method first, which allows us to quickly approve loads + // for the System Principal. + if (MayLoadInternal(aURI)) { + return NS_OK; + } + + nsresult rv; + if (aAllowIfInheritsPrincipal) { + // If the caller specified to allow loads of URIs that inherit + // our principal, allow the load if this URI inherits its principal. + bool doesInheritSecurityContext; + rv = NS_URIChainHasFlags(aURI, + nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, + &doesInheritSecurityContext); + if (NS_SUCCEEDED(rv) && doesInheritSecurityContext) { + return NS_OK; + } + } + + // Web Accessible Resources in MV2 Extensions are marked with + // URI_FETCHABLE_BY_ANYONE + bool fetchableByAnyone; + rv = NS_URIChainHasFlags(aURI, nsIProtocolHandler::URI_FETCHABLE_BY_ANYONE, + &fetchableByAnyone); + if (NS_SUCCEEDED(rv) && fetchableByAnyone) { + return NS_OK; + } + + // Get the principal uri for the last flag check or error. + nsCOMPtr<nsIURI> prinURI; + rv = GetURI(getter_AddRefs(prinURI)); + if (!(NS_SUCCEEDED(rv) && prinURI)) { + return NS_ERROR_DOM_BAD_URI; + } + + // If MV3 Extension uris are web accessible by this principal it is allowed to + // load. + bool maybeWebAccessible = false; + NS_URIChainHasFlags(aURI, nsIProtocolHandler::WEBEXT_URI_WEB_ACCESSIBLE, + &maybeWebAccessible); + NS_ENSURE_SUCCESS(rv, rv); + if (maybeWebAccessible) { + bool isWebAccessible = false; + rv = ExtensionPolicyService::GetSingleton().SourceMayLoadExtensionURI( + prinURI, aURI, &isWebAccessible); + if (NS_SUCCEEDED(rv) && isWebAccessible) { + return NS_OK; + } + } + + if (aReport) { + nsScriptSecurityManager::ReportError( + "CheckSameOriginError", prinURI, aURI, + mOriginAttributes.mPrivateBrowsingId > 0, aInnerWindowID); + } + + return NS_ERROR_DOM_BAD_URI; +} + +NS_IMETHODIMP +BasePrincipal::IsThirdPartyURI(nsIURI* aURI, bool* aRes) { + if (IsSystemPrincipal() || (AddonPolicyCore() && AddonAllowsLoad(aURI))) { + *aRes = false; + return NS_OK; + } + + *aRes = true; + // If we do not have a URI its always 3rd party. + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + ThirdPartyUtil* thirdPartyUtil = ThirdPartyUtil::GetInstance(); + return thirdPartyUtil->IsThirdPartyURI(prinURI, aURI, aRes); +} + +NS_IMETHODIMP +BasePrincipal::IsThirdPartyPrincipal(nsIPrincipal* aPrin, bool* aRes) { + *aRes = true; + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + return aPrin->IsThirdPartyURI(prinURI, aRes); +} + +NS_IMETHODIMP +BasePrincipal::IsThirdPartyChannel(nsIChannel* aChan, bool* aRes) { + AssertIsOnMainThread(); + if (IsSystemPrincipal()) { + // Nothing is 3rd party to the system principal. + *aRes = false; + return NS_OK; + } + + nsCOMPtr<nsIURI> prinURI; + GetURI(getter_AddRefs(prinURI)); + ThirdPartyUtil* thirdPartyUtil = ThirdPartyUtil::GetInstance(); + return thirdPartyUtil->IsThirdPartyChannel(aChan, prinURI, aRes); +} + +NS_IMETHODIMP +BasePrincipal::IsSameOrigin(nsIURI* aURI, bool* aRes) { + *aRes = false; + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + // Note that expanded and system principals return here, because they have + // no URI. + return NS_OK; + } + *aRes = nsScriptSecurityManager::SecurityCompareURIs(prinURI, aURI); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::IsL10nAllowed(nsIURI* aURI, bool* aRes) { + AssertIsOnMainThread(); // URI_DANGEROUS_TO_LOAD is not threadsafe to query. + *aRes = false; + + if (nsContentUtils::IsErrorPage(aURI)) { + *aRes = true; + return NS_OK; + } + + // The system principal is always allowed. + if (IsSystemPrincipal()) { + *aRes = true; + return NS_OK; + } + + nsCOMPtr<nsIURI> uri; + nsresult rv = GetURI(getter_AddRefs(uri)); + NS_ENSURE_SUCCESS(rv, NS_OK); + + bool hasFlags; + + // Allow access to uris that cannot be loaded by web content. + rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_DANGEROUS_TO_LOAD, + &hasFlags); + NS_ENSURE_SUCCESS(rv, NS_OK); + if (hasFlags) { + *aRes = true; + return NS_OK; + } + + // UI resources also get access. + rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_UI_RESOURCE, + &hasFlags); + NS_ENSURE_SUCCESS(rv, NS_OK); + if (hasFlags) { + *aRes = true; + return NS_OK; + } + + auto policy = AddonPolicyCore(); + *aRes = (policy && policy->IsPrivileged()); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::AllowsRelaxStrictFileOriginPolicy(nsIURI* aURI, bool* aRes) { + *aRes = false; + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + *aRes = NS_RelaxStrictFileOriginPolicy(aURI, prinURI); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetPrefLightCacheKey(nsIURI* aURI, bool aWithCredentials, + const OriginAttributes& aOriginAttributes, + nsACString& _retval) { + _retval.Truncate(); + constexpr auto space = " "_ns; + + nsCOMPtr<nsIURI> uri; + nsresult rv = GetURI(getter_AddRefs(uri)); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString scheme, host, port; + if (uri) { + uri->GetScheme(scheme); + uri->GetHost(host); + port.AppendInt(NS_GetRealPort(uri)); + } + + if (aWithCredentials) { + _retval.AssignLiteral("cred"); + } else { + _retval.AssignLiteral("nocred"); + } + + nsAutoCString spec; + rv = aURI->GetSpec(spec); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString originAttributesSuffix; + aOriginAttributes.CreateSuffix(originAttributesSuffix); + + _retval.Append(space + scheme + space + host + space + port + space + spec + + space + originAttributesSuffix); + + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::HasFirstpartyStorageAccess(mozIDOMWindow* aCheckWindow, + uint32_t* aRejectedReason, + bool* aOutAllowed) { + AssertIsOnMainThread(); + *aRejectedReason = 0; + *aOutAllowed = false; + + nsPIDOMWindowInner* win = nsPIDOMWindowInner::From(aCheckWindow); + nsCOMPtr<nsIURI> uri; + nsresult rv = GetURI(getter_AddRefs(uri)); + if (NS_FAILED(rv)) { + return rv; + } + *aOutAllowed = ShouldAllowAccessFor(win, uri, aRejectedReason); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetIsNullPrincipal(bool* aResult) { + *aResult = Kind() == eNullPrincipal; + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetIsContentPrincipal(bool* aResult) { + *aResult = Kind() == eContentPrincipal; + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetIsExpandedPrincipal(bool* aResult) { + *aResult = Kind() == eExpandedPrincipal; + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetAsciiSpec(nsACString& aSpec) { + aSpec.Truncate(); + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + return prinURI->GetAsciiSpec(aSpec); +} + +NS_IMETHODIMP +BasePrincipal::GetSpec(nsACString& aSpec) { + aSpec.Truncate(); + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + return prinURI->GetSpec(aSpec); +} + +NS_IMETHODIMP +BasePrincipal::GetAsciiHost(nsACString& aHost) { + aHost.Truncate(); + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + return prinURI->GetAsciiHost(aHost); +} + +NS_IMETHODIMP +BasePrincipal::GetExposablePrePath(nsACString& aPrepath) { + aPrepath.Truncate(); + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + + nsCOMPtr<nsIURI> exposableURI = net::nsIOService::CreateExposableURI(prinURI); + return exposableURI->GetDisplayPrePath(aPrepath); +} + +NS_IMETHODIMP +BasePrincipal::GetExposableSpec(nsACString& aSpec) { + aSpec.Truncate(); + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + nsCOMPtr<nsIURI> clone; + rv = NS_MutateURI(prinURI) + .SetQuery(""_ns) + .SetRef(""_ns) + .SetUserPass(""_ns) + .Finalize(clone); + NS_ENSURE_SUCCESS(rv, rv); + return clone->GetAsciiSpec(aSpec); +} + +NS_IMETHODIMP +BasePrincipal::GetPrePath(nsACString& aPath) { + aPath.Truncate(); + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + return prinURI->GetPrePath(aPath); +} + +NS_IMETHODIMP +BasePrincipal::GetFilePath(nsACString& aPath) { + aPath.Truncate(); + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + return prinURI->GetFilePath(aPath); +} + +NS_IMETHODIMP +BasePrincipal::GetIsSystemPrincipal(bool* aResult) { + *aResult = IsSystemPrincipal(); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetIsAddonOrExpandedAddonPrincipal(bool* aResult) { + *aResult = AddonPolicyCore() || ContentScriptAddonPolicyCore(); + return NS_OK; +} + +NS_IMETHODIMP BasePrincipal::GetIsOnion(bool* aIsOnion) { + *aIsOnion = false; + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + + nsAutoCString host; + rv = prinURI->GetHost(host); + if (NS_FAILED(rv)) { + return NS_OK; + } + *aIsOnion = StringEndsWith(host, ".onion"_ns); + return NS_OK; +} + +NS_IMETHODIMP BasePrincipal::GetIsIpAddress(bool* aIsIpAddress) { + *aIsIpAddress = false; + + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + + nsAutoCString host; + rv = prinURI->GetHost(host); + if (NS_FAILED(rv)) { + return NS_OK; + } + + PRNetAddr prAddr; + memset(&prAddr, 0, sizeof(prAddr)); + + if (PR_StringToNetAddr(host.get(), &prAddr) == PR_SUCCESS) { + *aIsIpAddress = true; + } + + return NS_OK; +} + +NS_IMETHODIMP BasePrincipal::GetIsLocalIpAddress(bool* aIsIpAddress) { + *aIsIpAddress = false; + + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + + nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv); + if (NS_FAILED(rv) || !ioService) { + return NS_OK; + } + rv = ioService->HostnameIsLocalIPAddress(prinURI, aIsIpAddress); + if (NS_FAILED(rv)) { + *aIsIpAddress = false; + } + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetScheme(nsACString& aScheme) { + aScheme.Truncate(); + + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + + return prinURI->GetScheme(aScheme); +} + +NS_IMETHODIMP +BasePrincipal::SchemeIs(const char* aScheme, bool* aResult) { + *aResult = false; + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_WARN_IF(NS_FAILED(rv)) || !prinURI) { + return NS_OK; + } + *aResult = prinURI->SchemeIs(aScheme); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::IsURIInPrefList(const char* aPref, bool* aResult) { + AssertIsOnMainThread(); + *aResult = false; + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + *aResult = nsContentUtils::IsURIInPrefList(prinURI, aPref); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::IsURIInList(const nsACString& aList, bool* aResult) { + *aResult = false; + nsCOMPtr<nsIURI> prinURI; + + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + + *aResult = nsContentUtils::IsURIInList(prinURI, nsCString(aList)); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::IsContentAccessibleAboutURI(bool* aResult) { + *aResult = false; + + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + + if (!prinURI->SchemeIs("about")) { + return NS_OK; + } + + *aResult = NS_IsContentAccessibleAboutURI(prinURI); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetIsOriginPotentiallyTrustworthy(bool* aResult) { + AssertIsOnMainThread(); + *aResult = false; + + nsCOMPtr<nsIURI> uri; + nsresult rv = GetURI(getter_AddRefs(uri)); + if (NS_FAILED(rv) || !uri) { + return NS_OK; + } + + *aResult = nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(uri); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetIsLoopbackHost(bool* aRes) { + AssertIsOnMainThread(); + *aRes = false; + nsAutoCString host; + nsresult rv = GetHost(host); + // Swallow potential failure as this method is infallible. + if (NS_FAILED(rv)) { + return NS_OK; + } + + *aRes = nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackHost(host); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetAboutModuleFlags(uint32_t* flags) { + AssertIsOnMainThread(); + *flags = 0; + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_ERROR_NOT_AVAILABLE; + } + if (!prinURI->SchemeIs("about")) { + return NS_OK; + } + + nsCOMPtr<nsIAboutModule> aboutModule; + rv = NS_GetAboutModule(prinURI, getter_AddRefs(aboutModule)); + if (NS_FAILED(rv) || !aboutModule) { + return rv; + } + return aboutModule->GetURIFlags(prinURI, flags); +} + +NS_IMETHODIMP +BasePrincipal::GetOriginAttributes(JSContext* aCx, + JS::MutableHandle<JS::Value> aVal) { + if (NS_WARN_IF(!ToJSValue(aCx, mOriginAttributes, aVal))) { + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetOriginSuffix(nsACString& aOriginAttributes) { + MOZ_ASSERT(mOriginSuffix); + mOriginSuffix->ToUTF8String(aOriginAttributes); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetUserContextId(uint32_t* aUserContextId) { + *aUserContextId = UserContextId(); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetPrivateBrowsingId(uint32_t* aPrivateBrowsingId) { + *aPrivateBrowsingId = PrivateBrowsingId(); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetIsInIsolatedMozBrowserElement( + bool* aIsInIsolatedMozBrowserElement) { + *aIsInIsolatedMozBrowserElement = IsInIsolatedMozBrowserElement(); + return NS_OK; +} + +nsresult BasePrincipal::GetAddonPolicy( + extensions::WebExtensionPolicy** aResult) { + AssertIsOnMainThread(); + RefPtr<extensions::WebExtensionPolicy> policy(AddonPolicy()); + policy.forget(aResult); + return NS_OK; +} + +nsresult BasePrincipal::GetContentScriptAddonPolicy( + extensions::WebExtensionPolicy** aResult) { + RefPtr<extensions::WebExtensionPolicy> policy(ContentScriptAddonPolicy()); + policy.forget(aResult); + return NS_OK; +} + +extensions::WebExtensionPolicy* BasePrincipal::AddonPolicy() { + AssertIsOnMainThread(); + RefPtr<extensions::WebExtensionPolicyCore> core = AddonPolicyCore(); + return core ? core->GetMainThreadPolicy() : nullptr; +} + +RefPtr<extensions::WebExtensionPolicyCore> BasePrincipal::AddonPolicyCore() { + if (Is<ContentPrincipal>()) { + return As<ContentPrincipal>()->AddonPolicyCore(); + } + return nullptr; +} + +bool BasePrincipal::AddonHasPermission(const nsAtom* aPerm) { + if (auto policy = AddonPolicyCore()) { + return policy->HasPermission(aPerm); + } + return false; +} + +nsIPrincipal* BasePrincipal::PrincipalToInherit(nsIURI* aRequestedURI) { + if (Is<ExpandedPrincipal>()) { + return As<ExpandedPrincipal>()->PrincipalToInherit(aRequestedURI); + } + return this; +} + +bool BasePrincipal::OverridesCSP(nsIPrincipal* aDocumentPrincipal) { + MOZ_ASSERT(aDocumentPrincipal); + + // Expanded principals override CSP if and only if they subsume the document + // principal. + if (mKind == eExpandedPrincipal) { + return FastSubsumes(aDocumentPrincipal); + } + // Extension principals always override the CSP of non-extension principals. + // This is primarily for the sake of their stylesheets, which are usually + // loaded from channels and cannot have expanded principals. + return (AddonPolicyCore() && + !BasePrincipal::Cast(aDocumentPrincipal)->AddonPolicyCore()); +} + +already_AddRefed<BasePrincipal> BasePrincipal::CreateContentPrincipal( + nsIURI* aURI, const OriginAttributes& aAttrs, nsIURI* aInitialDomain) { + MOZ_ASSERT(aURI); + + nsAutoCString originNoSuffix; + nsresult rv = + ContentPrincipal::GenerateOriginNoSuffixFromURI(aURI, originNoSuffix); + if (NS_FAILED(rv)) { + // If the generation of the origin fails, we still want to have a valid + // principal. Better to return a null principal here. + return NullPrincipal::Create(aAttrs); + } + + return CreateContentPrincipal(aURI, aAttrs, originNoSuffix, aInitialDomain); +} + +already_AddRefed<BasePrincipal> BasePrincipal::CreateContentPrincipal( + nsIURI* aURI, const OriginAttributes& aAttrs, + const nsACString& aOriginNoSuffix, nsIURI* aInitialDomain) { + MOZ_ASSERT(aURI); + MOZ_ASSERT(!aOriginNoSuffix.IsEmpty()); + + // If the URI is supposed to inherit the security context of whoever loads it, + // we shouldn't make a content principal for it. + bool inheritsPrincipal; + nsresult rv = NS_URIChainHasFlags( + aURI, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, + &inheritsPrincipal); + if (NS_FAILED(rv) || inheritsPrincipal) { + return NullPrincipal::Create(aAttrs); + } + + // Check whether the URI knows what its principal is supposed to be. +#if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) + nsCOMPtr<nsIURIWithSpecialOrigin> uriWithSpecialOrigin = + do_QueryInterface(aURI); + if (uriWithSpecialOrigin) { + nsCOMPtr<nsIURI> origin; + rv = uriWithSpecialOrigin->GetOrigin(getter_AddRefs(origin)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return nullptr; + } + MOZ_ASSERT(origin); + OriginAttributes attrs; + RefPtr<BasePrincipal> principal = + CreateContentPrincipal(origin, attrs, aInitialDomain); + return principal.forget(); + } +#endif + + nsCOMPtr<nsIPrincipal> blobPrincipal; + if (dom::BlobURLProtocolHandler::GetBlobURLPrincipal( + aURI, getter_AddRefs(blobPrincipal))) { + MOZ_ASSERT(blobPrincipal); + MOZ_ASSERT(!aInitialDomain, + "an initial domain for a blob URI makes no sense"); + RefPtr<BasePrincipal> principal = Cast(blobPrincipal); + return principal.forget(); + } + + // Mint a content principal. + RefPtr<ContentPrincipal> principal = + new ContentPrincipal(aURI, aAttrs, aOriginNoSuffix, aInitialDomain); + return principal.forget(); +} + +already_AddRefed<BasePrincipal> BasePrincipal::CreateContentPrincipal( + const nsACString& aOrigin) { + MOZ_ASSERT(!StringBeginsWith(aOrigin, "["_ns), + "CreateContentPrincipal does not support System and Expanded " + "principals"); + + MOZ_ASSERT( + !StringBeginsWith(aOrigin, nsLiteralCString(NS_NULLPRINCIPAL_SCHEME ":")), + "CreateContentPrincipal does not support NullPrincipal"); + + nsAutoCString originNoSuffix; + OriginAttributes attrs; + if (!attrs.PopulateFromOrigin(aOrigin, originNoSuffix)) { + return nullptr; + } + + nsCOMPtr<nsIURI> uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix); + NS_ENSURE_SUCCESS(rv, nullptr); + + return BasePrincipal::CreateContentPrincipal(uri, attrs); +} + +already_AddRefed<BasePrincipal> BasePrincipal::CloneForcingOriginAttributes( + const OriginAttributes& aOriginAttributes) { + if (NS_WARN_IF(!IsContentPrincipal())) { + return nullptr; + } + + nsAutoCString originNoSuffix; + nsresult rv = GetOriginNoSuffix(originNoSuffix); + NS_ENSURE_SUCCESS(rv, nullptr); + + nsCOMPtr<nsIURI> uri; + MOZ_ALWAYS_SUCCEEDS(GetURI(getter_AddRefs(uri))); + + // XXX: This does not copy over the domain. Should it? + RefPtr<ContentPrincipal> copy = + new ContentPrincipal(uri, aOriginAttributes, originNoSuffix, nullptr); + return copy.forget(); +} + +extensions::WebExtensionPolicy* BasePrincipal::ContentScriptAddonPolicy() { + AssertIsOnMainThread(); + RefPtr<extensions::WebExtensionPolicyCore> core = + ContentScriptAddonPolicyCore(); + return core ? core->GetMainThreadPolicy() : nullptr; +} + +RefPtr<extensions::WebExtensionPolicyCore> +BasePrincipal::ContentScriptAddonPolicyCore() { + if (!Is<ExpandedPrincipal>()) { + return nullptr; + } + + auto* expanded = As<ExpandedPrincipal>(); + for (const auto& prin : expanded->AllowList()) { + if (RefPtr<extensions::WebExtensionPolicyCore> policy = + BasePrincipal::Cast(prin)->AddonPolicyCore()) { + return policy; + } + } + + return nullptr; +} + +bool BasePrincipal::AddonAllowsLoad(nsIURI* aURI, + bool aExplicit /* = false */) { + if (Is<ExpandedPrincipal>()) { + return As<ExpandedPrincipal>()->AddonAllowsLoad(aURI, aExplicit); + } + if (auto policy = AddonPolicyCore()) { + return policy->CanAccessURI(aURI, aExplicit); + } + return false; +} + +NS_IMETHODIMP +BasePrincipal::GetLocalStorageQuotaKey(nsACString& aKey) { + aKey.Truncate(); + + nsCOMPtr<nsIURI> uri; + nsresult rv = GetURI(getter_AddRefs(uri)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED); + + // The special handling of the file scheme should be consistent with + // GetStorageOriginKey. + + nsAutoCString baseDomain; + rv = uri->GetAsciiHost(baseDomain); + NS_ENSURE_SUCCESS(rv, rv); + + if (baseDomain.IsEmpty() && uri->SchemeIs("file")) { + nsCOMPtr<nsIURL> url = do_QueryInterface(uri, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = url->GetDirectory(baseDomain); + NS_ENSURE_SUCCESS(rv, rv); + } else { + nsCOMPtr<nsIEffectiveTLDService> eTLDService( + do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString eTLDplusOne; + rv = eTLDService->GetBaseDomain(uri, 0, eTLDplusOne); + if (NS_SUCCEEDED(rv)) { + baseDomain = eTLDplusOne; + } else if (rv == NS_ERROR_HOST_IS_IP_ADDRESS || + rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) { + rv = NS_OK; + } + NS_ENSURE_SUCCESS(rv, rv); + } + + OriginAttributesRef().CreateSuffix(aKey); + + nsAutoCString subdomainsDBKey; + rv = dom::StorageUtils::CreateReversedDomain(baseDomain, subdomainsDBKey); + NS_ENSURE_SUCCESS(rv, rv); + + aKey.Append(':'); + aKey.Append(subdomainsDBKey); + + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetNextSubDomainPrincipal( + nsIPrincipal** aNextSubDomainPrincipal) { + nsCOMPtr<nsIURI> uri; + nsresult rv = GetURI(getter_AddRefs(uri)); + if (NS_FAILED(rv) || !uri) { + return NS_OK; + } + + nsAutoCString host; + rv = uri->GetHost(host); + if (NS_FAILED(rv) || host.IsEmpty()) { + return NS_OK; + } + + nsCString subDomain; + rv = nsEffectiveTLDService::GetInstance()->GetNextSubDomain(host, subDomain); + + if (NS_FAILED(rv) || subDomain.IsEmpty()) { + return NS_OK; + } + + nsCOMPtr<nsIURI> subDomainURI; + rv = NS_MutateURI(uri).SetHost(subDomain).Finalize(subDomainURI); + if (NS_FAILED(rv) || !subDomainURI) { + return NS_OK; + } + // Copy the attributes over + mozilla::OriginAttributes attrs = OriginAttributesRef(); + + if (!StaticPrefs::permissions_isolateBy_userContext()) { + // Disable userContext for permissions. + attrs.StripAttributes(mozilla::OriginAttributes::STRIP_USER_CONTEXT_ID); + } + RefPtr<nsIPrincipal> principal = + mozilla::BasePrincipal::CreateContentPrincipal(subDomainURI, attrs); + + if (!principal) { + return NS_OK; + } + principal.forget(aNextSubDomainPrincipal); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetStorageOriginKey(nsACString& aOriginKey) { + aOriginKey.Truncate(); + + nsCOMPtr<nsIURI> uri; + nsresult rv = GetURI(getter_AddRefs(uri)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED); + + // The special handling of the file scheme should be consistent with + // GetLocalStorageQuotaKey. + + nsAutoCString domainOrigin; + rv = uri->GetAsciiHost(domainOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + if (domainOrigin.IsEmpty()) { + // For the file:/// protocol use the exact directory as domain. + if (uri->SchemeIs("file")) { + nsCOMPtr<nsIURL> url = do_QueryInterface(uri, &rv); + NS_ENSURE_SUCCESS(rv, rv); + rv = url->GetDirectory(domainOrigin); + NS_ENSURE_SUCCESS(rv, rv); + } + } + + // Append reversed domain + nsAutoCString reverseDomain; + rv = dom::StorageUtils::CreateReversedDomain(domainOrigin, reverseDomain); + NS_ENSURE_SUCCESS(rv, rv); + + aOriginKey.Append(reverseDomain); + + // Append scheme + nsAutoCString scheme; + rv = uri->GetScheme(scheme); + NS_ENSURE_SUCCESS(rv, rv); + + aOriginKey.Append(':'); + aOriginKey.Append(scheme); + + // Append port if any + int32_t port = NS_GetRealPort(uri); + if (port != -1) { + aOriginKey.Append(nsPrintfCString(":%d", port)); + } + + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetIsScriptAllowedByPolicy(bool* aIsScriptAllowedByPolicy) { + AssertIsOnMainThread(); + *aIsScriptAllowedByPolicy = false; + nsCOMPtr<nsIURI> prinURI; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + return NS_OK; + } + nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); + if (!ssm) { + return NS_ERROR_UNEXPECTED; + } + return ssm->PolicyAllowsScript(prinURI, aIsScriptAllowedByPolicy); +} + +bool SiteIdentifier::Equals(const SiteIdentifier& aOther) const { + MOZ_ASSERT(IsInitialized()); + MOZ_ASSERT(aOther.IsInitialized()); + return mPrincipal->FastEquals(aOther.mPrincipal); +} + +NS_IMETHODIMP +BasePrincipal::CreateReferrerInfo(mozilla::dom::ReferrerPolicy aReferrerPolicy, + nsIReferrerInfo** _retval) { + nsCOMPtr<nsIURI> prinURI; + RefPtr<dom::ReferrerInfo> info; + nsresult rv = GetURI(getter_AddRefs(prinURI)); + if (NS_FAILED(rv) || !prinURI) { + info = new dom::ReferrerInfo(nullptr); + info.forget(_retval); + return NS_OK; + } + info = new dom::ReferrerInfo(prinURI, aReferrerPolicy); + info.forget(_retval); + return NS_OK; +} + +NS_IMETHODIMP +BasePrincipal::GetPrecursorPrincipal(nsIPrincipal** aPrecursor) { + *aPrecursor = nullptr; + return NS_OK; +} + +NS_IMPL_ADDREF(BasePrincipal::Deserializer) +NS_IMPL_RELEASE(BasePrincipal::Deserializer) + +NS_INTERFACE_MAP_BEGIN(BasePrincipal::Deserializer) + NS_INTERFACE_MAP_ENTRY(nsISupports) + NS_INTERFACE_MAP_ENTRY(nsISerializable) + if (mPrincipal) { + return mPrincipal->QueryInterface(aIID, aInstancePtr); + } else +NS_INTERFACE_MAP_END + +NS_IMETHODIMP +BasePrincipal::Deserializer::Write(nsIObjectOutputStream* aStream) { + // Read is used still for legacy principals + MOZ_RELEASE_ASSERT(false, "Old style serialization is removed"); + return NS_OK; +} + +/* static */ +void BasePrincipal::WriteJSONProperty(JSONWriter& aWriter, + const Span<const char>& aKey, + const nsCString& aValue) { + aWriter.StringProperty(aKey, aValue); +} + +} // namespace mozilla |