mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 04:41:11 +00:00
Bug 1861819 - Use JS::ParseJSONWithHandler in BasePrincipal. r=peterv
This avoid intermediate object tree for "JSON to principal" case. Differential Revision: https://phabricator.services.mozilla.com/D192146
This commit is contained in:
parent
081d863ef2
commit
31ceef48aa
@ -44,9 +44,15 @@
|
||||
#include "nsIURIMutator.h"
|
||||
#include "mozilla/PermissionManager.h"
|
||||
|
||||
#include "json/json.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,
|
||||
@ -136,113 +142,183 @@ BasePrincipal::GetSiteOriginNoSuffix(nsACString& aSiteOrigin) {
|
||||
return GetOriginNoSuffix(aSiteOrigin);
|
||||
}
|
||||
|
||||
// Returns the inner Json::value of the serialized principal
|
||||
// Example input and return values:
|
||||
// Null principal:
|
||||
// {"0":{"0":"moz-nullprincipal:{56cac540-864d-47e7-8e25-1614eab5155e}"}} ->
|
||||
// {"0":"moz-nullprincipal:{56cac540-864d-47e7-8e25-1614eab5155e}"}
|
||||
//
|
||||
// Content principal:
|
||||
// {"1":{"0":"https://mozilla.com"}} -> {"0":"https://mozilla.com"}
|
||||
//
|
||||
// Expanded principal:
|
||||
// {"2":{"0":"<base64principal1>,<base64principal2>"}} ->
|
||||
// {"0":"<base64principal1>,<base64principal2>"}
|
||||
//
|
||||
// System principal:
|
||||
// {"3":{}} -> {}
|
||||
// The aKey passed in also returns the corresponding PrincipalKind enum
|
||||
//
|
||||
// Warning: The Json::Value* pointer is into the aRoot object
|
||||
static const Json::Value* GetPrincipalObject(const Json::Value& aRoot,
|
||||
int& aOutPrincipalKind) {
|
||||
const Json::Value::Members members = aRoot.getMemberNames();
|
||||
// We only support one top level key in the object
|
||||
if (members.size() != 1) {
|
||||
return nullptr;
|
||||
template <typename HandlerTypesT>
|
||||
bool ContainerPrincipalJSONHandler<HandlerTypesT>::ProcessInnerResult(
|
||||
bool aResult) {
|
||||
if (!aResult) {
|
||||
NS_WARNING("Failed to parse inner object");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
// members[0] here is the "0", "1", "2", "3" principalKind
|
||||
// that is the top level of the serialized JSON principal
|
||||
const std::string stringPrincipalKind = members[0];
|
||||
|
||||
// Next we take the string value from the JSON
|
||||
// and convert it into the int for the BasePrincipal::PrincipalKind enum
|
||||
|
||||
// Verify that the key is within the valid range
|
||||
int principalKind = std::stoi(stringPrincipalKind);
|
||||
MOZ_ASSERT(BasePrincipal::eNullPrincipal == 0,
|
||||
"We need to rely on 0 being a bounds check for the first "
|
||||
"principal kind.");
|
||||
if (principalKind < 0 || principalKind > BasePrincipal::eKindMax) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(principalKind == BasePrincipal::eNullPrincipal ||
|
||||
principalKind == BasePrincipal::eContentPrincipal ||
|
||||
principalKind == BasePrincipal::eExpandedPrincipal ||
|
||||
principalKind == BasePrincipal::eSystemPrincipal);
|
||||
aOutPrincipalKind = principalKind;
|
||||
|
||||
if (!aRoot[stringPrincipalKind].isObject()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Return the inner value of the principal object
|
||||
return &aRoot[stringPrincipalKind];
|
||||
return true;
|
||||
}
|
||||
|
||||
// Accepts the JSON inner object without the wrapping principalKind
|
||||
// (See GetPrincipalObject for the inner object response examples)
|
||||
// Creates an array of KeyVal objects that are all defined on the principal
|
||||
// Each principal type (null, content, expanded) has a KeyVal that stores the
|
||||
// fields of the JSON
|
||||
//
|
||||
// This simplifies deserializing elsewhere as we do the checking for presence
|
||||
// and string values here for the complete set of serializable keys that the
|
||||
// corresponding principal supports.
|
||||
//
|
||||
// The KeyVal object has the following fields:
|
||||
// - valueWasSerialized: is true if the deserialized JSON contained a string
|
||||
// value
|
||||
// - value: The string that was serialized for this key
|
||||
// - key: an SerializableKeys enum value specific to the principal.
|
||||
// For example content principal is an enum of: eURI, eDomain,
|
||||
// eSuffix, eCSP
|
||||
//
|
||||
//
|
||||
// Given an inner content principal:
|
||||
// {"0": "https://mozilla.com", "2": "^privateBrowsingId=1"}
|
||||
// | | | |
|
||||
// ----------------------------- |
|
||||
// | | |
|
||||
// Key ----------------------
|
||||
// |
|
||||
// Value
|
||||
//
|
||||
// They Key "0" corresponds to ContentPrincipal::eURI
|
||||
// They Key "1" corresponds to ContentPrincipal::eSuffix
|
||||
template <typename T>
|
||||
static nsTArray<typename T::KeyVal> GetJSONKeys(const Json::Value* aInput) {
|
||||
int size = T::eMax + 1;
|
||||
nsTArray<typename T::KeyVal> fields;
|
||||
for (int i = 0; i != size; i++) {
|
||||
typename T::KeyVal* field = fields.AppendElement();
|
||||
// field->valueWasSerialized returns if the field was found in the
|
||||
// deserialized code. This simplifies the consumers from having to check
|
||||
// length.
|
||||
field->valueWasSerialized = false;
|
||||
field->key = static_cast<typename T::SerializableKeys>(i);
|
||||
const std::string key = std::to_string(field->key);
|
||||
if (aInput->isMember(key)) {
|
||||
const Json::Value& val = (*aInput)[key];
|
||||
if (val.isString()) {
|
||||
field->value.Append(nsDependentCString(val.asCString()));
|
||||
field->valueWasSerialized = 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(); });
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
|
||||
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
|
||||
//
|
||||
@ -261,110 +337,21 @@ static nsTArray<typename T::KeyVal> GetJSONKeys(const Json::Value* aInput) {
|
||||
// SerializableKeys |
|
||||
// Value
|
||||
//
|
||||
// The string is first deserialized with jsoncpp to get the Json::Value of the
|
||||
// object. The inner JSON object is parsed with GetPrincipalObject which returns
|
||||
// a KeyVal array of the inner object's fields. PrincipalKind is returned by
|
||||
// GetPrincipalObject which is then used to decide which principal
|
||||
// implementation of FromProperties to call. The corresponding FromProperties
|
||||
// call takes the KeyVal fields and turns it into a principal.
|
||||
already_AddRefed<BasePrincipal> BasePrincipal::FromJSON(
|
||||
const nsACString& aJSON) {
|
||||
Json::Value root;
|
||||
Json::CharReaderBuilder builder;
|
||||
std::unique_ptr<Json::CharReader> const reader(builder.newCharReader());
|
||||
bool parseSuccess =
|
||||
reader->parse(aJSON.BeginReading(), aJSON.EndReading(), &root, nullptr);
|
||||
if (!parseSuccess) {
|
||||
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 FromJSON(root);
|
||||
}
|
||||
|
||||
// Checks if an ExpandedPrincipal is using the legacy format, where
|
||||
// sub-principals are Base64 encoded.
|
||||
//
|
||||
// Given a legacy expanded principal:
|
||||
//
|
||||
// *
|
||||
// {"2": {"0": "eyIxIjp7IjAiOiJodHRwczovL2EuY29tLyJ9fQ=="}}
|
||||
// | | |
|
||||
// | ---------- Value
|
||||
// | |
|
||||
// PrincipalKind |
|
||||
// |
|
||||
// SerializableKeys
|
||||
//
|
||||
// The value is a CSV list of Base64 encoded prinipcals. The new format for this
|
||||
// principal is:
|
||||
//
|
||||
// Subsumed principals
|
||||
// |
|
||||
// ------------------------------------
|
||||
// * | |
|
||||
// {"2": {"0": [{"1": {"0": https://mozilla.com"}}]}}
|
||||
// | | |
|
||||
// -------------- Value
|
||||
// |
|
||||
// PrincipalKind
|
||||
//
|
||||
// It is possible to tell these apart by checking the type of the property noted
|
||||
// in both diagrams with an asterisk. In the legacy format the type will be a
|
||||
// string and in the new format it will be an array.
|
||||
static bool IsLegacyFormat(const Json::Value& aValue) {
|
||||
const auto& specs = std::to_string(ExpandedPrincipal::eSpecs);
|
||||
return aValue.isMember(specs) && aValue[specs].isString();
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<BasePrincipal> BasePrincipal::FromJSON(
|
||||
const Json::Value& aJSON) {
|
||||
int principalKind = -1;
|
||||
const Json::Value* value = GetPrincipalObject(aJSON, principalKind);
|
||||
if (!value) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Unexpected JSON principal %s\n",
|
||||
aJSON.toStyledString().c_str());
|
||||
#endif
|
||||
MOZ_ASSERT(false, "Unexpected JSON to deserialize as a principal");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(principalKind != -1,
|
||||
"PrincipalKind should always be >=0 by this point");
|
||||
|
||||
if (principalKind == eSystemPrincipal) {
|
||||
RefPtr<BasePrincipal> principal =
|
||||
BasePrincipal::Cast(nsContentUtils::GetSystemPrincipal());
|
||||
return principal.forget();
|
||||
}
|
||||
|
||||
if (principalKind == eNullPrincipal) {
|
||||
nsTArray<NullPrincipal::KeyVal> res = GetJSONKeys<NullPrincipal>(value);
|
||||
return NullPrincipal::FromProperties(res);
|
||||
}
|
||||
|
||||
if (principalKind == eContentPrincipal) {
|
||||
nsTArray<ContentPrincipal::KeyVal> res =
|
||||
GetJSONKeys<ContentPrincipal>(value);
|
||||
return ContentPrincipal::FromProperties(res);
|
||||
}
|
||||
|
||||
if (principalKind == eExpandedPrincipal) {
|
||||
// Check if expanded principals is stored in the new or the old format. See
|
||||
// comment for `IsLegacyFormat`.
|
||||
if (IsLegacyFormat(*value)) {
|
||||
nsTArray<ExpandedPrincipal::KeyVal> res =
|
||||
GetJSONKeys<ExpandedPrincipal>(value);
|
||||
return ExpandedPrincipal::FromProperties(res);
|
||||
}
|
||||
|
||||
return ExpandedPrincipal::FromProperties(*value);
|
||||
}
|
||||
|
||||
MOZ_RELEASE_ASSERT(false, "Unexpected enum to deserialize as a principal");
|
||||
return handler.Get();
|
||||
}
|
||||
|
||||
// Returns a JSON representation of the principal.
|
||||
|
@ -27,9 +27,6 @@ class nsIChannel;
|
||||
class nsIReferrerInfo;
|
||||
class nsISupports;
|
||||
class nsIURI;
|
||||
namespace Json {
|
||||
class Value;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -93,6 +90,15 @@ class BasePrincipal : public nsJSPrincipals {
|
||||
eKindMax = eSystemPrincipal
|
||||
};
|
||||
|
||||
static constexpr char NullPrincipalKey = '0';
|
||||
static_assert(eNullPrincipal == 0);
|
||||
static constexpr char ContentPrincipalKey = '1';
|
||||
static_assert(eContentPrincipal == 1);
|
||||
static constexpr char ExpandedPrincipalKey = '2';
|
||||
static_assert(eExpandedPrincipal == 2);
|
||||
static constexpr char SystemPrincipalKey = '3';
|
||||
static_assert(eSystemPrincipal == 3);
|
||||
|
||||
template <typename T>
|
||||
bool Is() const {
|
||||
return mKind == T::Kind();
|
||||
@ -195,7 +201,6 @@ class BasePrincipal : public nsJSPrincipals {
|
||||
nsresult WriteJSONProperties(JSONWriter& aWriter);
|
||||
|
||||
static already_AddRefed<BasePrincipal> FromJSON(const nsACString& aJSON);
|
||||
static already_AddRefed<BasePrincipal> FromJSON(const Json::Value& aJSON);
|
||||
|
||||
// Method to write serializable fields which represent all of the fields to
|
||||
// deserialize the principal.
|
||||
|
@ -39,6 +39,9 @@
|
||||
|
||||
#include "nsSerializationHelper.h"
|
||||
|
||||
#include "js/JSON.h"
|
||||
#include "ContentPrincipalJSONHandler.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_CLASSINFO(ContentPrincipal, nullptr, 0, NS_PRINCIPAL_CID)
|
||||
@ -643,66 +646,147 @@ nsresult ContentPrincipal::WriteJSONInnerProperties(JSONWriter& aWriter) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<BasePrincipal> ContentPrincipal::FromProperties(
|
||||
nsTArray<ContentPrincipal::KeyVal>& aFields) {
|
||||
MOZ_ASSERT(aFields.Length() == eMax + 1, "Must have all the keys");
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIURI> principalURI;
|
||||
nsCOMPtr<nsIURI> domain;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
OriginAttributes attrs;
|
||||
|
||||
// The odd structure here is to make the code to not compile
|
||||
// if all the switch enum cases haven't been codified
|
||||
for (const auto& field : aFields) {
|
||||
switch (field.key) {
|
||||
case ContentPrincipal::eURI:
|
||||
if (!field.valueWasSerialized) {
|
||||
MOZ_ASSERT(
|
||||
false,
|
||||
"Content principals require a principal URI in serialized JSON");
|
||||
return nullptr;
|
||||
}
|
||||
rv = NS_NewURI(getter_AddRefs(principalURI), field.value.get());
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
{
|
||||
// Enforce re-parsing about: URIs so that if they change, we
|
||||
// continue to use their new principals correctly.
|
||||
if (principalURI->SchemeIs("about")) {
|
||||
nsAutoCString spec;
|
||||
principalURI->GetSpec(spec);
|
||||
if (NS_FAILED(NS_NewURI(getter_AddRefs(principalURI), spec))) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ContentPrincipal::eDomain:
|
||||
if (field.valueWasSerialized) {
|
||||
rv = NS_NewURI(getter_AddRefs(domain), field.value.get());
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
}
|
||||
break;
|
||||
case ContentPrincipal::eSuffix:
|
||||
if (field.valueWasSerialized) {
|
||||
bool ok = attrs.PopulateFromSuffix(field.value);
|
||||
if (!ok) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
nsAutoCString originNoSuffix;
|
||||
rv = ContentPrincipal::GenerateOriginNoSuffixFromURI(principalURI,
|
||||
originNoSuffix);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
bool ContentPrincipalJSONHandler::startObject() {
|
||||
switch (mState) {
|
||||
case State::Init:
|
||||
mState = State::StartObject;
|
||||
break;
|
||||
default:
|
||||
NS_WARNING("Unexpected object value");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<ContentPrincipal> principal =
|
||||
new ContentPrincipal(principalURI, attrs, originNoSuffix, domain);
|
||||
|
||||
return principal.forget();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContentPrincipalJSONHandler::propertyName(const JS::Latin1Char* name,
|
||||
size_t length) {
|
||||
switch (mState) {
|
||||
case State::StartObject:
|
||||
case State::AfterPropertyValue: {
|
||||
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 ContentPrincipal::URIKey:
|
||||
mState = State::URIKey;
|
||||
break;
|
||||
case ContentPrincipal::DomainKey:
|
||||
mState = State::DomainKey;
|
||||
break;
|
||||
case ContentPrincipal::SuffixKey:
|
||||
mState = State::SuffixKey;
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
|
||||
bool ContentPrincipalJSONHandler::endObject() {
|
||||
switch (mState) {
|
||||
case State::AfterPropertyValue: {
|
||||
MOZ_ASSERT(mPrincipalURI);
|
||||
// NOTE: mDomain is optional.
|
||||
|
||||
nsAutoCString originNoSuffix;
|
||||
nsresult rv = ContentPrincipal::GenerateOriginNoSuffixFromURI(
|
||||
mPrincipalURI, originNoSuffix);
|
||||
if (NS_FAILED(rv)) {
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
mPrincipal =
|
||||
new ContentPrincipal(mPrincipalURI, mAttrs, originNoSuffix, mDomain);
|
||||
MOZ_ASSERT(mPrincipal);
|
||||
|
||||
mState = State::EndObject;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NS_WARNING("Unexpected end of object");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContentPrincipalJSONHandler::stringValue(const JS::Latin1Char* str,
|
||||
size_t length) {
|
||||
switch (mState) {
|
||||
case State::URIKey: {
|
||||
nsDependentCSubstring spec(reinterpret_cast<const char*>(str), length);
|
||||
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(mPrincipalURI), spec);
|
||||
if (NS_FAILED(rv)) {
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
// Enforce re-parsing about: URIs so that if they change, we
|
||||
// continue to use their new principals correctly.
|
||||
if (mPrincipalURI->SchemeIs("about")) {
|
||||
nsAutoCString spec;
|
||||
mPrincipalURI->GetSpec(spec);
|
||||
rv = NS_NewURI(getter_AddRefs(mPrincipalURI), spec);
|
||||
if (NS_FAILED(rv)) {
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mState = State::AfterPropertyValue;
|
||||
break;
|
||||
}
|
||||
case State::DomainKey: {
|
||||
nsDependentCSubstring spec(reinterpret_cast<const char*>(str), length);
|
||||
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(mDomain), spec);
|
||||
if (NS_FAILED(rv)) {
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
mState = State::AfterPropertyValue;
|
||||
break;
|
||||
}
|
||||
case State::SuffixKey: {
|
||||
nsDependentCSubstring attrs(reinterpret_cast<const char*>(str), length);
|
||||
if (!mAttrs.PopulateFromSuffix(attrs)) {
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
mState = State::AfterPropertyValue;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NS_WARNING("Unexpected string value");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -56,10 +56,13 @@ class ContentPrincipal final : public BasePrincipal {
|
||||
eSuffix,
|
||||
eMax = eSuffix
|
||||
};
|
||||
typedef mozilla::BasePrincipal::KeyValT<SerializableKeys> KeyVal;
|
||||
|
||||
static already_AddRefed<BasePrincipal> FromProperties(
|
||||
nsTArray<ContentPrincipal::KeyVal>& aFields);
|
||||
static constexpr char URIKey = '0';
|
||||
static_assert(eURI == 0);
|
||||
static constexpr char DomainKey = '1';
|
||||
static_assert(eDomain == 1);
|
||||
static constexpr char SuffixKey = '2';
|
||||
static_assert(eSuffix == 2);
|
||||
|
||||
class Deserializer : public BasePrincipal::Deserializer {
|
||||
public:
|
||||
|
94
caps/ContentPrincipalJSONHandler.h
Normal file
94
caps/ContentPrincipalJSONHandler.h
Normal file
@ -0,0 +1,94 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_ContentPrincipalJSONHandler_h
|
||||
#define mozilla_ContentPrincipalJSONHandler_h
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
#include <stdint.h> // uint32_t
|
||||
|
||||
#include "js/TypeDecls.h" // JS::Latin1Char
|
||||
|
||||
#include "mozilla/AlreadyAddRefed.h" // already_AddRefed
|
||||
#include "mozilla/RefPtr.h" // RefPtr
|
||||
|
||||
#include "nsCOMPtr.h" // nsCOMPtr
|
||||
#include "nsDebug.h" // NS_WARNING
|
||||
#include "nsIURI.h" // nsIURI
|
||||
|
||||
#include "ContentPrincipal.h"
|
||||
#include "OriginAttributes.h"
|
||||
#include "SharedJSONHandler.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// JSON parse handler for an inner object for ContentPrincipal.
|
||||
// Used by PrincipalJSONHandler or SubsumedPrincipalJSONHandler.
|
||||
class ContentPrincipalJSONHandler : public PrincipalJSONHandlerShared {
|
||||
enum class State {
|
||||
Init,
|
||||
|
||||
// After the inner object's '{'.
|
||||
StartObject,
|
||||
|
||||
// After the property key for eURI.
|
||||
URIKey,
|
||||
|
||||
// After the property key for eDomain.
|
||||
DomainKey,
|
||||
|
||||
// After the property key for eSuffix.
|
||||
SuffixKey,
|
||||
|
||||
// After the property value for eURI, eDomain, or eSuffix.
|
||||
AfterPropertyValue,
|
||||
|
||||
// After the inner object's '}'.
|
||||
EndObject,
|
||||
|
||||
Error,
|
||||
};
|
||||
|
||||
public:
|
||||
ContentPrincipalJSONHandler() = default;
|
||||
virtual ~ContentPrincipalJSONHandler() = default;
|
||||
|
||||
virtual bool startObject() override;
|
||||
|
||||
using PrincipalJSONHandlerShared::propertyName;
|
||||
virtual bool propertyName(const JS::Latin1Char* name, size_t length) override;
|
||||
|
||||
virtual bool endObject() override;
|
||||
|
||||
virtual bool startArray() override {
|
||||
NS_WARNING("Unexpected array value");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
virtual bool endArray() override {
|
||||
NS_WARNING("Unexpected array value");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
using PrincipalJSONHandlerShared::stringValue;
|
||||
virtual bool stringValue(const JS::Latin1Char* str, size_t length) override;
|
||||
|
||||
bool HasAccepted() const { return mState == State::EndObject; }
|
||||
|
||||
protected:
|
||||
virtual void SetErrorState() override { mState = State::Error; }
|
||||
|
||||
private:
|
||||
State mState = State::Init;
|
||||
|
||||
nsCOMPtr<nsIURI> mPrincipalURI;
|
||||
nsCOMPtr<nsIURI> mDomain;
|
||||
OriginAttributes mAttrs;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ContentPrincipalJSONHandler_h
|
@ -11,7 +11,10 @@
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/extensions/WebExtensionPolicy.h"
|
||||
#include "mozilla/JSONWriter.h"
|
||||
#include "json/json.h"
|
||||
|
||||
#include "js/JSON.h"
|
||||
#include "ExpandedPrincipalJSONHandler.h"
|
||||
#include "SubsumedPrincipalJSONHandler.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -287,100 +290,187 @@ nsresult ExpandedPrincipal::WriteJSONInnerProperties(JSONWriter& aWriter) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<BasePrincipal> ExpandedPrincipal::FromProperties(
|
||||
nsTArray<ExpandedPrincipal::KeyVal>& aFields) {
|
||||
MOZ_ASSERT(aFields.Length() == eMax + 1, "Must have all the keys");
|
||||
nsTArray<nsCOMPtr<nsIPrincipal>> allowList;
|
||||
OriginAttributes attrs;
|
||||
// The odd structure here is to make the code to not compile
|
||||
// if all the switch enum cases haven't been codified
|
||||
|
||||
for (const auto& field : aFields) {
|
||||
switch (field.key) {
|
||||
case ExpandedPrincipal::eSpecs:
|
||||
if (!field.valueWasSerialized) {
|
||||
MOZ_ASSERT(false,
|
||||
"Expanded principals require specs in serialized JSON");
|
||||
return nullptr;
|
||||
}
|
||||
for (const nsACString& each : field.value.Split(',')) {
|
||||
nsAutoCString result;
|
||||
nsresult rv;
|
||||
rv = Base64Decode(each, result);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to decode");
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
nsCOMPtr<nsIPrincipal> principal = BasePrincipal::FromJSON(result);
|
||||
allowList.AppendElement(principal);
|
||||
}
|
||||
break;
|
||||
case ExpandedPrincipal::eSuffix:
|
||||
if (field.valueWasSerialized) {
|
||||
bool ok = attrs.PopulateFromSuffix(field.value);
|
||||
if (!ok) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
bool ExpandedPrincipalJSONHandler::ProcessSubsumedResult(bool aResult) {
|
||||
if (!aResult) {
|
||||
NS_WARNING("Failed to parse subsumed principal");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (allowList.Length() == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<ExpandedPrincipal> expandedPrincipal =
|
||||
ExpandedPrincipal::Create(allowList, attrs);
|
||||
|
||||
return expandedPrincipal.forget();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<BasePrincipal> ExpandedPrincipal::FromProperties(
|
||||
const Json::Value& aJSON) {
|
||||
MOZ_ASSERT(aJSON.size() <= eMax + 1, "Must have at most, all the properties");
|
||||
const std::string specs = std::to_string(eSpecs);
|
||||
const std::string suffix = std::to_string(eSuffix);
|
||||
MOZ_ASSERT(aJSON.isMember(specs), "The eSpecs member is required");
|
||||
MOZ_ASSERT(aJSON.size() == 1 || aJSON.isMember(suffix),
|
||||
"eSuffix is optional");
|
||||
|
||||
const auto* specsValue =
|
||||
aJSON.find(specs.c_str(), specs.c_str() + specs.length());
|
||||
if (!specsValue) {
|
||||
MOZ_ASSERT(false, "Expanded principals require specs in serialized JSON");
|
||||
return nullptr;
|
||||
bool ExpandedPrincipalJSONHandler::startObject() {
|
||||
if (mSubsumedHandler.isSome()) {
|
||||
return ProcessSubsumedResult(mSubsumedHandler->startObject());
|
||||
}
|
||||
|
||||
nsTArray<nsCOMPtr<nsIPrincipal>> allowList;
|
||||
for (const auto& principalJSON : *specsValue) {
|
||||
if (nsCOMPtr<nsIPrincipal> principal =
|
||||
BasePrincipal::FromJSON(principalJSON)) {
|
||||
allowList.AppendElement(principal);
|
||||
switch (mState) {
|
||||
case State::Init:
|
||||
mState = State::StartObject;
|
||||
break;
|
||||
case State::StartArray:
|
||||
mState = State::SubsumedPrincipal;
|
||||
[[fallthrough]];
|
||||
case State::SubsumedPrincipal:
|
||||
mSubsumedHandler.emplace();
|
||||
|
||||
return ProcessSubsumedResult(mSubsumedHandler->startObject());
|
||||
default:
|
||||
NS_WARNING("Unexpected object value");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExpandedPrincipalJSONHandler::propertyName(const JS::Latin1Char* name,
|
||||
size_t length) {
|
||||
if (mSubsumedHandler.isSome()) {
|
||||
return ProcessSubsumedResult(mSubsumedHandler->propertyName(name, length));
|
||||
}
|
||||
|
||||
switch (mState) {
|
||||
case State::StartObject:
|
||||
case State::AfterPropertyValue: {
|
||||
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 ExpandedPrincipal::SpecsKey:
|
||||
mState = State::SpecsKey;
|
||||
break;
|
||||
case ExpandedPrincipal::SuffixKey:
|
||||
mState = State::SuffixKey;
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
|
||||
if (allowList.Length() == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
OriginAttributes attrs;
|
||||
if (aJSON.isMember(suffix)) {
|
||||
const auto& value = aJSON[suffix];
|
||||
if (!value.isString()) {
|
||||
return nullptr;
|
||||
bool ExpandedPrincipalJSONHandler::endObject() {
|
||||
if (mSubsumedHandler.isSome()) {
|
||||
if (!ProcessSubsumedResult(mSubsumedHandler->endObject())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = attrs.PopulateFromSuffix(nsDependentCString(value.asCString()));
|
||||
if (!ok) {
|
||||
return nullptr;
|
||||
if (mSubsumedHandler->HasAccepted()) {
|
||||
nsCOMPtr<nsIPrincipal> principal = mSubsumedHandler->mPrincipal.forget();
|
||||
mSubsumedHandler.reset();
|
||||
mAllowList.AppendElement(principal);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<ExpandedPrincipal> expandedPrincipal =
|
||||
ExpandedPrincipal::Create(allowList, attrs);
|
||||
switch (mState) {
|
||||
case State::AfterPropertyValue:
|
||||
mPrincipal = ExpandedPrincipal::Create(mAllowList, mAttrs);
|
||||
MOZ_ASSERT(mPrincipal);
|
||||
|
||||
return expandedPrincipal.forget();
|
||||
mState = State::EndObject;
|
||||
break;
|
||||
default:
|
||||
NS_WARNING("Unexpected end of object");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExpandedPrincipalJSONHandler::startArray() {
|
||||
switch (mState) {
|
||||
case State::SpecsKey:
|
||||
mState = State::StartArray;
|
||||
break;
|
||||
default:
|
||||
NS_WARNING("Unexpected array value");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExpandedPrincipalJSONHandler::endArray() {
|
||||
switch (mState) {
|
||||
case State::SubsumedPrincipal: {
|
||||
mState = State::AfterPropertyValue;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NS_WARNING("Unexpected end of array");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExpandedPrincipalJSONHandler::stringValue(const JS::Latin1Char* str,
|
||||
size_t length) {
|
||||
if (mSubsumedHandler.isSome()) {
|
||||
return ProcessSubsumedResult(mSubsumedHandler->stringValue(str, length));
|
||||
}
|
||||
|
||||
switch (mState) {
|
||||
case State::SpecsKey: {
|
||||
nsDependentCSubstring specs(reinterpret_cast<const char*>(str), length);
|
||||
|
||||
for (const nsACString& each : specs.Split(',')) {
|
||||
nsAutoCString result;
|
||||
nsresult rv = Base64Decode(each, result);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to decode");
|
||||
if (NS_FAILED(rv)) {
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = BasePrincipal::FromJSON(result);
|
||||
if (!principal) {
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
mAllowList.AppendElement(principal);
|
||||
}
|
||||
|
||||
mState = State::AfterPropertyValue;
|
||||
break;
|
||||
}
|
||||
case State::SuffixKey: {
|
||||
nsDependentCSubstring attrs(reinterpret_cast<const char*>(str), length);
|
||||
if (!mAttrs.PopulateFromSuffix(attrs)) {
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
mState = State::AfterPropertyValue;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NS_WARNING("Unexpected string value");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -15,10 +15,6 @@
|
||||
|
||||
class nsIContentSecurityPolicy;
|
||||
|
||||
namespace Json {
|
||||
class Value;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
class JSONWriter;
|
||||
} // namespace mozilla
|
||||
@ -66,17 +62,11 @@ class ExpandedPrincipal : public nsIExpandedPrincipal,
|
||||
|
||||
// Serializable keys are the valid enum fields the serialization supports
|
||||
enum SerializableKeys : uint8_t { eSpecs = 0, eSuffix, eMax = eSuffix };
|
||||
typedef mozilla::BasePrincipal::KeyValT<SerializableKeys> KeyVal;
|
||||
|
||||
// This is the legacy serializer for expanded principals. See note for
|
||||
// `IsLegacyFormat` in BasePrincipal.cpp.
|
||||
static already_AddRefed<BasePrincipal> FromProperties(
|
||||
nsTArray<ExpandedPrincipal::KeyVal>& aFields);
|
||||
|
||||
// This is the new serializer for expanded principals. See note for
|
||||
// `IsLegacyFormat` in BasePrincipal.cpp.
|
||||
static already_AddRefed<BasePrincipal> FromProperties(
|
||||
const Json::Value& aJSON);
|
||||
static constexpr char SpecsKey = '0';
|
||||
static_assert(eSpecs == 0);
|
||||
static constexpr char SuffixKey = '1';
|
||||
static_assert(eSuffix == 1);
|
||||
|
||||
class Deserializer : public BasePrincipal::Deserializer {
|
||||
public:
|
||||
|
130
caps/ExpandedPrincipalJSONHandler.h
Normal file
130
caps/ExpandedPrincipalJSONHandler.h
Normal file
@ -0,0 +1,130 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_ExpandedPrincipalJSONHandler_h
|
||||
#define mozilla_ExpandedPrincipalJSONHandler_h
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
#include <stdint.h> // uint32_t
|
||||
|
||||
#include "js/TypeDecls.h" // JS::Latin1Char
|
||||
|
||||
#include "mozilla/AlreadyAddRefed.h" // already_AddRefed
|
||||
#include "mozilla/Maybe.h" // Maybe
|
||||
#include "mozilla/RefPtr.h" // RefPtr
|
||||
|
||||
#include "nsCOMPtr.h" // nsCOMPtr
|
||||
#include "nsDebug.h" // NS_WARNING
|
||||
#include "nsIPrincipal.h" // nsIPrincipal
|
||||
#include "nsTArray.h" // nsTArray
|
||||
|
||||
#include "OriginAttributes.h"
|
||||
#include "ExpandedPrincipal.h"
|
||||
#include "SubsumedPrincipalJSONHandler.h"
|
||||
#include "SharedJSONHandler.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// JSON parse handler for an inner object for ExpandedPrincipal.
|
||||
//
|
||||
// # Legacy format
|
||||
//
|
||||
// inner object
|
||||
// |
|
||||
// -------------------------------------------------
|
||||
// | |
|
||||
// {"2": {"0": "eyIxIjp7IjAiOiJodHRwczovL2EuY29tLyJ9fQ=="}}
|
||||
// | | |
|
||||
// | ---------- Value
|
||||
// | |
|
||||
// PrincipalKind |
|
||||
// |
|
||||
// SerializableKeys
|
||||
//
|
||||
// The value is a CSV list of Base64 encoded prinipcals.
|
||||
//
|
||||
// # New format
|
||||
//
|
||||
// inner object
|
||||
// |
|
||||
// -------------------------------------------
|
||||
// | |
|
||||
// | Subsumed principals |
|
||||
// | | |
|
||||
// | ------------------------------------|
|
||||
// | | ||
|
||||
// {"2": {"0": [{"1": {"0": https://mozilla.com"}}]}}
|
||||
// | | |
|
||||
// -------------- Value
|
||||
// |
|
||||
// PrincipalKind
|
||||
//
|
||||
// Used by PrincipalJSONHandler.
|
||||
class ExpandedPrincipalJSONHandler : public PrincipalJSONHandlerShared {
|
||||
enum class State {
|
||||
Init,
|
||||
|
||||
// After the inner object's '{'.
|
||||
StartObject,
|
||||
|
||||
// After the property key for eSpecs.
|
||||
SpecsKey,
|
||||
|
||||
// After the property key for eSuffix.
|
||||
SuffixKey,
|
||||
|
||||
// After the subsumed principals array's '['.
|
||||
StartArray,
|
||||
|
||||
// Subsumed principals array's item.
|
||||
// Delegates to mSubsumedHandler until the subsumed object's '}'.
|
||||
SubsumedPrincipal,
|
||||
|
||||
// After the property value for eSpecs or eSuffix,
|
||||
// including after the subsumed principals array's ']'.
|
||||
AfterPropertyValue,
|
||||
|
||||
// After the inner object's '}'.
|
||||
EndObject,
|
||||
|
||||
Error,
|
||||
};
|
||||
|
||||
public:
|
||||
ExpandedPrincipalJSONHandler() = default;
|
||||
virtual ~ExpandedPrincipalJSONHandler() = default;
|
||||
|
||||
virtual bool startObject() override;
|
||||
|
||||
using PrincipalJSONHandlerShared::propertyName;
|
||||
virtual bool propertyName(const JS::Latin1Char* name, size_t length) override;
|
||||
|
||||
virtual bool endObject() override;
|
||||
|
||||
virtual bool startArray() override;
|
||||
virtual bool endArray() override;
|
||||
|
||||
using PrincipalJSONHandlerShared::stringValue;
|
||||
virtual bool stringValue(const JS::Latin1Char* str, size_t length) override;
|
||||
|
||||
bool HasAccepted() const { return mState == State::EndObject; }
|
||||
|
||||
protected:
|
||||
virtual void SetErrorState() override { mState = State::Error; }
|
||||
|
||||
private:
|
||||
bool ProcessSubsumedResult(bool aResult);
|
||||
|
||||
private:
|
||||
State mState = State::Init;
|
||||
|
||||
nsTArray<nsCOMPtr<nsIPrincipal>> mAllowList;
|
||||
OriginAttributes mAttrs;
|
||||
Maybe<SubsumedPrincipalJSONHandler> mSubsumedHandler;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ExpandedPrincipalJSONHandler_h
|
@ -27,6 +27,9 @@
|
||||
#include "pratom.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
|
||||
#include "js/JSON.h"
|
||||
#include "NullPrincipalJSONHandler.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_CLASSINFO(NullPrincipal, nullptr, 0, NS_NULLPRINCIPAL_CID)
|
||||
@ -249,43 +252,6 @@ nsresult NullPrincipal::WriteJSONInnerProperties(JSONWriter& aWriter) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<BasePrincipal> NullPrincipal::FromProperties(
|
||||
nsTArray<NullPrincipal::KeyVal>& aFields) {
|
||||
MOZ_ASSERT(aFields.Length() == eMax + 1, "Must have all the keys");
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
OriginAttributes attrs;
|
||||
|
||||
// The odd structure here is to make the code to not compile
|
||||
// if all the switch enum cases haven't been codified
|
||||
for (const auto& field : aFields) {
|
||||
switch (field.key) {
|
||||
case NullPrincipal::eSpec:
|
||||
if (!field.valueWasSerialized) {
|
||||
MOZ_ASSERT(false,
|
||||
"Null principals require a spec URI in serialized JSON");
|
||||
return nullptr;
|
||||
}
|
||||
rv = NS_NewURI(getter_AddRefs(uri), field.value);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
break;
|
||||
case NullPrincipal::eSuffix:
|
||||
bool ok = attrs.PopulateFromSuffix(field.value);
|
||||
if (!ok) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!uri) {
|
||||
MOZ_ASSERT(false, "No URI deserialized");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return NullPrincipal::Create(attrs, uri);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NullPrincipal::GetPrecursorPrincipal(nsIPrincipal** aPrincipal) {
|
||||
*aPrincipal = nullptr;
|
||||
@ -329,3 +295,107 @@ NullPrincipal::GetPrecursorPrincipal(nsIPrincipal** aPrincipal) {
|
||||
contentPrincipal.forget(aPrincipal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool NullPrincipalJSONHandler::startObject() {
|
||||
switch (mState) {
|
||||
case State::Init:
|
||||
mState = State::StartObject;
|
||||
break;
|
||||
default:
|
||||
NS_WARNING("Unexpected object value");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NullPrincipalJSONHandler::propertyName(const JS::Latin1Char* name,
|
||||
size_t length) {
|
||||
switch (mState) {
|
||||
case State::StartObject:
|
||||
case State::AfterPropertyValue: {
|
||||
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 NullPrincipal::SpecKey:
|
||||
mState = State::SpecKey;
|
||||
break;
|
||||
case NullPrincipal::SuffixKey:
|
||||
mState = State::SuffixKey;
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
|
||||
bool NullPrincipalJSONHandler::endObject() {
|
||||
switch (mState) {
|
||||
case State::AfterPropertyValue:
|
||||
MOZ_ASSERT(mUri);
|
||||
|
||||
mPrincipal = NullPrincipal::Create(mAttrs, mUri);
|
||||
MOZ_ASSERT(mPrincipal);
|
||||
|
||||
mState = State::EndObject;
|
||||
break;
|
||||
default:
|
||||
NS_WARNING("Unexpected end of object");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NullPrincipalJSONHandler::stringValue(const JS::Latin1Char* str,
|
||||
size_t length) {
|
||||
switch (mState) {
|
||||
case State::SpecKey: {
|
||||
nsDependentCSubstring spec(reinterpret_cast<const char*>(str), length);
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(mUri), spec);
|
||||
if (NS_FAILED(rv)) {
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
mState = State::AfterPropertyValue;
|
||||
break;
|
||||
}
|
||||
case State::SuffixKey: {
|
||||
nsDependentCSubstring attrs(reinterpret_cast<const char*>(str), length);
|
||||
if (!mAttrs.PopulateFromSuffix(attrs)) {
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
mState = State::AfterPropertyValue;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NS_WARNING("Unexpected string value");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -88,10 +88,11 @@ class NullPrincipal final : public BasePrincipal {
|
||||
|
||||
// Serializable keys are the valid enum fields the serialization supports
|
||||
enum SerializableKeys : uint8_t { eSpec = 0, eSuffix, eMax = eSuffix };
|
||||
typedef mozilla::BasePrincipal::KeyValT<SerializableKeys> KeyVal;
|
||||
|
||||
static already_AddRefed<BasePrincipal> FromProperties(
|
||||
nsTArray<NullPrincipal::KeyVal>& aFields);
|
||||
static constexpr char SpecKey = '0';
|
||||
static_assert(eSpec == 0);
|
||||
static constexpr char SuffixKey = '1';
|
||||
static_assert(eSuffix == 1);
|
||||
|
||||
class Deserializer : public BasePrincipal::Deserializer {
|
||||
public:
|
||||
|
91
caps/NullPrincipalJSONHandler.h
Normal file
91
caps/NullPrincipalJSONHandler.h
Normal file
@ -0,0 +1,91 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_NullPrincipalJSONHandler_h
|
||||
#define mozilla_NullPrincipalJSONHandler_h
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
#include <stdint.h> // uint32_t
|
||||
|
||||
#include "js/TypeDecls.h" // JS::Latin1Char
|
||||
|
||||
#include "mozilla/AlreadyAddRefed.h" // already_AddRefed
|
||||
#include "mozilla/Assertions.h" // MOZ_ASSERT_UNREACHABLE
|
||||
#include "mozilla/RefPtr.h" // RefPtr
|
||||
|
||||
#include "nsCOMPtr.h" // nsCOMPtr
|
||||
#include "nsDebug.h" // NS_WARNING
|
||||
#include "nsIURI.h" // nsIURI
|
||||
|
||||
#include "NullPrincipal.h"
|
||||
#include "OriginAttributes.h"
|
||||
#include "SharedJSONHandler.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// JSON parse handler for an inner object for NullPrincipal.
|
||||
// Used by PrincipalJSONHandler or SubsumedPrincipalJSONHandler.
|
||||
class NullPrincipalJSONHandler : public PrincipalJSONHandlerShared {
|
||||
enum class State {
|
||||
Init,
|
||||
|
||||
// After the inner object's '{'.
|
||||
StartObject,
|
||||
|
||||
// After the property key for eSpec.
|
||||
SpecKey,
|
||||
|
||||
// After the property key for eSuffix.
|
||||
SuffixKey,
|
||||
|
||||
// After the property value for eSpec or eSuffix.
|
||||
AfterPropertyValue,
|
||||
|
||||
// After the inner object's '}'.
|
||||
EndObject,
|
||||
|
||||
Error,
|
||||
};
|
||||
|
||||
public:
|
||||
NullPrincipalJSONHandler() = default;
|
||||
virtual ~NullPrincipalJSONHandler() = default;
|
||||
|
||||
virtual bool startObject() override;
|
||||
|
||||
using PrincipalJSONHandlerShared::propertyName;
|
||||
virtual bool propertyName(const JS::Latin1Char* name, size_t length) override;
|
||||
|
||||
virtual bool endObject() override;
|
||||
|
||||
virtual bool startArray() override {
|
||||
NS_WARNING("Unexpected array value");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
virtual bool endArray() override {
|
||||
NS_WARNING("Unexpected array value");
|
||||
mState = State::Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
using PrincipalJSONHandlerShared::stringValue;
|
||||
virtual bool stringValue(const JS::Latin1Char* str, size_t length) override;
|
||||
|
||||
bool HasAccepted() const { return mState == State::EndObject; }
|
||||
|
||||
protected:
|
||||
virtual void SetErrorState() override { mState = State::Error; }
|
||||
|
||||
private:
|
||||
State mState = State::Init;
|
||||
|
||||
nsCOMPtr<nsIURI> mUri;
|
||||
OriginAttributes mAttrs;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_NullPrincipalJSONHandler_h
|
116
caps/PrincipalJSONHandler.h
Normal file
116
caps/PrincipalJSONHandler.h
Normal file
@ -0,0 +1,116 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_PrincipalJSONHandler_h
|
||||
#define mozilla_PrincipalJSONHandler_h
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
#include <stdint.h> // uint32_t
|
||||
|
||||
#include "js/JSON.h" // JS::JSONParseHandler
|
||||
#include "js/TypeDecls.h" // JS::Latin1Char
|
||||
|
||||
#include "mozilla/AlreadyAddRefed.h" // already_AddRefed
|
||||
#include "mozilla/RefPtr.h" // RefPtr
|
||||
#include "mozilla/Variant.h" // Variant
|
||||
|
||||
#include "nsDebug.h" // NS_WARNING
|
||||
#include "nsPrintfCString.h" // nsPrintfCString
|
||||
|
||||
#include "BasePrincipal.h"
|
||||
#include "ContentPrincipalJSONHandler.h"
|
||||
#include "ExpandedPrincipalJSONHandler.h"
|
||||
#include "NullPrincipalJSONHandler.h"
|
||||
#include "SharedJSONHandler.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class PrincipalJSONHandlerTypes {
|
||||
public:
|
||||
enum class State {
|
||||
Init,
|
||||
|
||||
// After top-level object's '{'.
|
||||
StartObject,
|
||||
|
||||
// After the PrincipalKind property key for SystemPrincipal.
|
||||
SystemPrincipal_Key,
|
||||
// After the SystemPrincipal's inner object's '{'.
|
||||
SystemPrincipal_StartObject,
|
||||
// After the SystemPrincipal's inner object's '}'.
|
||||
SystemPrincipal_EndObject,
|
||||
|
||||
// After the PrincipalKind property key for NullPrincipal, ContentPrincipal,
|
||||
// or ExpandedPrincipal, and also the entire inner object.
|
||||
// Delegates to mInnerHandler until the inner object's '}'.
|
||||
NullPrincipal_Inner,
|
||||
ContentPrincipal_Inner,
|
||||
ExpandedPrincipal_Inner,
|
||||
|
||||
// After top-level object's '}'.
|
||||
EndObject,
|
||||
|
||||
Error,
|
||||
};
|
||||
|
||||
using InnerHandlerT =
|
||||
Maybe<Variant<NullPrincipalJSONHandler, ContentPrincipalJSONHandler,
|
||||
ExpandedPrincipalJSONHandler>>;
|
||||
|
||||
static constexpr bool CanContainExpandedPrincipal = true;
|
||||
};
|
||||
|
||||
// JSON parse handler for the top-level object for principal.
|
||||
//
|
||||
// inner object
|
||||
// |
|
||||
// ---------------------------------------------------------
|
||||
// | |
|
||||
// {"1": {"0": "https://mozilla.com", "2": "^privateBrowsingId=1"}}
|
||||
// |
|
||||
// |
|
||||
// |
|
||||
// PrincipalKind
|
||||
//
|
||||
// For inner object except for the system principal case, this delegates
|
||||
// to NullPrincipalJSONHandler, ContentPrincipalJSONHandler, or
|
||||
// ExpandedPrincipalJSONHandler.
|
||||
//
|
||||
//// Null principal:
|
||||
// {"0":{"0":"moz-nullprincipal:{56cac540-864d-47e7-8e25-1614eab5155e}"}}
|
||||
//
|
||||
// Content principal:
|
||||
// {"1":{"0":"https://mozilla.com"}} -> {"0":"https://mozilla.com"}
|
||||
//
|
||||
// Expanded principal:
|
||||
// {"2":{"0":"<base64principal1>,<base64principal2>"}}
|
||||
//
|
||||
// System principal:
|
||||
// {"3":{}}
|
||||
class PrincipalJSONHandler
|
||||
: public ContainerPrincipalJSONHandler<PrincipalJSONHandlerTypes> {
|
||||
using State = PrincipalJSONHandlerTypes::State;
|
||||
using InnerHandlerT = PrincipalJSONHandlerTypes::InnerHandlerT;
|
||||
|
||||
public:
|
||||
PrincipalJSONHandler() = default;
|
||||
virtual ~PrincipalJSONHandler() = default;
|
||||
|
||||
virtual void error(const char* msg, uint32_t line, uint32_t column) override {
|
||||
NS_WARNING(
|
||||
nsPrintfCString("JSON Error: %s at line %u column %u of the JSON data",
|
||||
msg, line, column)
|
||||
.get());
|
||||
}
|
||||
|
||||
already_AddRefed<BasePrincipal> Get() { return mPrincipal.forget(); }
|
||||
|
||||
protected:
|
||||
virtual void SetErrorState() override { mState = State::Error; }
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_PrincipalJSONHandler_h
|
114
caps/SharedJSONHandler.h
Normal file
114
caps/SharedJSONHandler.h
Normal file
@ -0,0 +1,114 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_SharedJSONHandler_h
|
||||
#define mozilla_SharedJSONHandler_h
|
||||
|
||||
#include "js/JSON.h" // JS::JSONParseHandler
|
||||
|
||||
#include "mozilla/RefPtr.h" // RefPtr
|
||||
|
||||
#include "BasePrincipal.h" // BasePrincipal
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Base class of all principal JSON parse handlers.
|
||||
class PrincipalJSONHandlerShared : public JS::JSONParseHandler {
|
||||
public:
|
||||
// Common handlers for inner objects.
|
||||
|
||||
// NOTE: propertyName and stringValue are partial overloads.
|
||||
// Subclasses should put the following:
|
||||
// * `using PrincipalJSONHandlerShared::propertyName`
|
||||
// * `using PrincipalJSONHandlerShared::stringValue`
|
||||
virtual bool propertyName(const char16_t* name, size_t length) override {
|
||||
NS_WARNING("Principal JSON shouldn't use non-ASCII");
|
||||
SetErrorState();
|
||||
return false;
|
||||
};
|
||||
|
||||
virtual bool stringValue(const char16_t* str, size_t length) override {
|
||||
NS_WARNING("Principal JSON shouldn't use non-ASCII");
|
||||
SetErrorState();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool numberValue(double d) override {
|
||||
NS_WARNING("Unexpected number value");
|
||||
SetErrorState();
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool booleanValue(bool v) override {
|
||||
NS_WARNING("Unexpected boolean value");
|
||||
SetErrorState();
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool nullValue() override {
|
||||
NS_WARNING("Unexpected null value");
|
||||
SetErrorState();
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void error(const char* msg, uint32_t line, uint32_t column) override {
|
||||
// Unused.
|
||||
}
|
||||
|
||||
protected:
|
||||
// Set to the error state for the above handlers.
|
||||
virtual void SetErrorState() = 0;
|
||||
|
||||
public:
|
||||
RefPtr<BasePrincipal> mPrincipal;
|
||||
};
|
||||
|
||||
// Base class shared between PrincipalJSONHandler and
|
||||
// SubsumedPrincipalJSONHandler.
|
||||
// This implements the common code for them, absorbing the difference about
|
||||
// whether it can contain ExpandedPrincipal or not.
|
||||
template <typename HandlerTypesT>
|
||||
class ContainerPrincipalJSONHandler : public PrincipalJSONHandlerShared {
|
||||
using State = typename HandlerTypesT::State;
|
||||
using InnerHandlerT = typename HandlerTypesT::InnerHandlerT;
|
||||
static constexpr bool CanContainExpandedPrincipal =
|
||||
HandlerTypesT::CanContainExpandedPrincipal;
|
||||
|
||||
public:
|
||||
// Common handlers.
|
||||
|
||||
virtual bool startObject() override;
|
||||
|
||||
using PrincipalJSONHandlerShared::propertyName;
|
||||
virtual bool propertyName(const JS::Latin1Char* name, size_t length) override;
|
||||
virtual bool endObject() override;
|
||||
|
||||
virtual bool startArray() override;
|
||||
|
||||
virtual bool endArray() override;
|
||||
|
||||
using PrincipalJSONHandlerShared::stringValue;
|
||||
virtual bool stringValue(const JS::Latin1Char* str, size_t length) override;
|
||||
|
||||
private:
|
||||
bool ProcessInnerResult(bool aResult);
|
||||
|
||||
template <class Func>
|
||||
bool CallOnInner(Func&& aFunc) {
|
||||
return mInnerHandler->match([&](auto& aInner) {
|
||||
bool result = aFunc(aInner);
|
||||
return ProcessInnerResult(result);
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
State mState = State::Init;
|
||||
|
||||
InnerHandlerT mInnerHandler;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_SharedJSONHandler_h
|
96
caps/SubsumedPrincipalJSONHandler.h
Normal file
96
caps/SubsumedPrincipalJSONHandler.h
Normal file
@ -0,0 +1,96 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_SubsumedPrincipalJSONHandler_h
|
||||
#define mozilla_SubsumedPrincipalJSONHandler_h
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
#include <stdint.h> // uint32_t
|
||||
|
||||
#include "js/TypeDecls.h" // JS::Latin1Char
|
||||
|
||||
#include "mozilla/AlreadyAddRefed.h" // already_AddRefed
|
||||
#include "mozilla/Variant.h" // Variant
|
||||
#include "mozilla/RefPtr.h" // RefPtr
|
||||
|
||||
#include "nsDebug.h" // NS_WARNING
|
||||
|
||||
#include "BasePrincipal.h"
|
||||
#include "ContentPrincipalJSONHandler.h"
|
||||
#include "NullPrincipalJSONHandler.h"
|
||||
#include "SharedJSONHandler.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class SubsumedPrincipalJSONHandlerTypes {
|
||||
public:
|
||||
enum class State {
|
||||
Init,
|
||||
|
||||
// After the subsumed principal object's '{'.
|
||||
StartObject,
|
||||
|
||||
// After the PrincipalKind property key for SystemPrincipal.
|
||||
SystemPrincipal_Key,
|
||||
// After the SystemPrincipal's inner object's '{'.
|
||||
SystemPrincipal_StartObject,
|
||||
// After the SystemPrincipal's inner object's '}'.
|
||||
SystemPrincipal_EndObject,
|
||||
|
||||
// After the PrincipalKind property key for NullPrincipal or
|
||||
// ContentPrincipal, and also the entire inner object.
|
||||
// Delegates to mInnerHandler until the inner object's '}'.
|
||||
//
|
||||
// Unlike PrincipalJSONHandler, subsumed principal doesn't contain
|
||||
// ExpandedPrincipal.
|
||||
NullPrincipal_Inner,
|
||||
ContentPrincipal_Inner,
|
||||
|
||||
// After the subsumed principal object's '}'.
|
||||
EndObject,
|
||||
|
||||
Error,
|
||||
};
|
||||
|
||||
using InnerHandlerT =
|
||||
Maybe<Variant<NullPrincipalJSONHandler, ContentPrincipalJSONHandler>>;
|
||||
|
||||
static constexpr bool CanContainExpandedPrincipal = false;
|
||||
};
|
||||
|
||||
// JSON parse handler for subsumed principal object inside ExpandedPrincipal's
|
||||
// new format.
|
||||
//
|
||||
// Subsumed principal object
|
||||
// |
|
||||
// ----------------------------------
|
||||
// | |
|
||||
// {"2": {"0": [{"1": {"0": https://mozilla.com"}}]}}
|
||||
// | | |
|
||||
// | ---------------------------
|
||||
// | |
|
||||
// | inner object
|
||||
// PrincipalKind
|
||||
//
|
||||
// For inner object except for the system principal case, this delegates
|
||||
// to NullPrincipalJSONHandler or ContentPrincipalJSONHandler.
|
||||
class SubsumedPrincipalJSONHandler
|
||||
: public ContainerPrincipalJSONHandler<SubsumedPrincipalJSONHandlerTypes> {
|
||||
using State = SubsumedPrincipalJSONHandlerTypes::State;
|
||||
using InnerHandlerT = SubsumedPrincipalJSONHandlerTypes::InnerHandlerT;
|
||||
|
||||
public:
|
||||
SubsumedPrincipalJSONHandler() = default;
|
||||
virtual ~SubsumedPrincipalJSONHandler() = default;
|
||||
|
||||
bool HasAccepted() const { return mState == State::EndObject; }
|
||||
|
||||
protected:
|
||||
virtual void SetErrorState() override { mState = State::Error; }
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_SubsumedPrincipalJSONHandler_h
|
@ -24,10 +24,6 @@
|
||||
|
||||
class nsScriptSecurityManager;
|
||||
|
||||
namespace Json {
|
||||
class Value;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class SystemPrincipal final : public BasePrincipal, public nsISerializable {
|
||||
|
@ -17,7 +17,7 @@ using mozilla::SystemPrincipal;
|
||||
// None of these tests work in debug due to assert guards
|
||||
#ifndef MOZ_DEBUG
|
||||
|
||||
// calling toJson() twice with the same string arg
|
||||
// calling toJSON() twice with the same string arg
|
||||
// (ensure that we truncate correctly where needed)
|
||||
TEST(PrincipalSerialization, ReusedJSONArgument)
|
||||
{
|
||||
@ -46,28 +46,6 @@ TEST(PrincipalSerialization, ReusedJSONArgument)
|
||||
ASSERT_TRUE(JSON.EqualsLiteral("{\"1\":{\"0\":\"https://example.com/\"}}"));
|
||||
}
|
||||
|
||||
// Assure that calling FromProperties() with an empty array list always returns
|
||||
// a nullptr The exception here is SystemPrincipal which doesn't have fields but
|
||||
// it also doesn't implement FromProperties These are overly cautious checks
|
||||
// that we don't try to create a principal in reality FromProperties is only
|
||||
// called with a populated array.
|
||||
TEST(PrincipalSerialization, FromPropertiesEmpty)
|
||||
{
|
||||
nsTArray<ContentPrincipal::KeyVal> resContent;
|
||||
nsCOMPtr<nsIPrincipal> contentPrincipal =
|
||||
ContentPrincipal::FromProperties(resContent);
|
||||
ASSERT_EQ(nullptr, contentPrincipal);
|
||||
|
||||
nsTArray<ExpandedPrincipal::KeyVal> resExpanded;
|
||||
nsCOMPtr<nsIPrincipal> expandedPrincipal =
|
||||
ExpandedPrincipal::FromProperties(resExpanded);
|
||||
ASSERT_EQ(nullptr, expandedPrincipal);
|
||||
|
||||
nsTArray<NullPrincipal::KeyVal> resNull;
|
||||
nsCOMPtr<nsIPrincipal> nullprincipal = NullPrincipal::FromProperties(resNull);
|
||||
ASSERT_EQ(nullptr, nullprincipal);
|
||||
}
|
||||
|
||||
// Double check that if we have two valid principals in a serialized JSON that
|
||||
// nullptr is returned
|
||||
TEST(PrincipalSerialization, TwoKeys)
|
||||
|
Loading…
Reference in New Issue
Block a user