mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
67db960e48
Depends on D183229 Differential Revision: https://phabricator.services.mozilla.com/D183230
1607 lines
44 KiB
C++
1607 lines
44 KiB
C++
/* -*- 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;
|
|
}
|
|
|
|
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
|