Bug 1782737 - Update symbol-scrapers fetch job for correct store_name r=gsvelto
[gecko.git] / caps / ContentPrincipal.cpp
blob0a30202893695f35eb895b27f550175f7881ff84
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ContentPrincipal.h"
9 #include "mozIThirdPartyUtil.h"
10 #include "nsContentUtils.h"
11 #include "nscore.h"
12 #include "nsScriptSecurityManager.h"
13 #include "nsString.h"
14 #include "nsReadableUtils.h"
15 #include "pratom.h"
16 #include "nsIURI.h"
17 #include "nsIURL.h"
18 #include "nsIStandardURL.h"
19 #include "nsIURIWithSpecialOrigin.h"
20 #include "nsIURIMutator.h"
21 #include "nsJSPrincipals.h"
22 #include "nsIEffectiveTLDService.h"
23 #include "nsIClassInfoImpl.h"
24 #include "nsIObjectInputStream.h"
25 #include "nsIObjectOutputStream.h"
26 #include "nsIProtocolHandler.h"
27 #include "nsError.h"
28 #include "nsIContentSecurityPolicy.h"
29 #include "nsNetCID.h"
30 #include "js/RealmIterators.h"
31 #include "js/Wrapper.h"
33 #include "mozilla/dom/BlobURLProtocolHandler.h"
34 #include "mozilla/dom/ScriptSettings.h"
35 #include "mozilla/ClearOnShutdown.h"
36 #include "mozilla/ExtensionPolicyService.h"
37 #include "mozilla/Preferences.h"
38 #include "mozilla/HashFunctions.h"
40 #include "nsSerializationHelper.h"
41 #include "json/json.h"
43 using namespace mozilla;
45 static inline ExtensionPolicyService& EPS() {
46 return ExtensionPolicyService::GetSingleton();
49 NS_IMPL_CLASSINFO(ContentPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY,
50 NS_PRINCIPAL_CID)
51 NS_IMPL_QUERY_INTERFACE_CI(ContentPrincipal, nsIPrincipal)
52 NS_IMPL_CI_INTERFACE_GETTER(ContentPrincipal, nsIPrincipal)
54 ContentPrincipal::ContentPrincipal(nsIURI* aURI,
55 const OriginAttributes& aOriginAttributes,
56 const nsACString& aOriginNoSuffix)
57 : BasePrincipal(eContentPrincipal, aOriginNoSuffix, aOriginAttributes),
58 mURI(aURI) {
59 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
60 // Assert that the URI we get here isn't any of the schemes that we know we
61 // should not get here. These schemes always either inherit their principal
62 // or fall back to a null principal. These are schemes which return
63 // URI_INHERITS_SECURITY_CONTEXT from their protocol handler's
64 // GetProtocolFlags function.
65 bool hasFlag = false;
66 MOZ_DIAGNOSTIC_ASSERT(
67 NS_SUCCEEDED(NS_URIChainHasFlags(
68 aURI, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, &hasFlag)) &&
69 !hasFlag);
70 #endif
73 ContentPrincipal::ContentPrincipal(ContentPrincipal* aOther,
74 const OriginAttributes& aOriginAttributes)
75 : BasePrincipal(aOther, aOriginAttributes),
76 mURI(aOther->mURI),
77 mDomain(aOther->mDomain),
78 mAddon(aOther->mAddon) {}
80 ContentPrincipal::~ContentPrincipal() = default;
82 nsresult ContentPrincipal::GetScriptLocation(nsACString& aStr) {
83 return mURI->GetSpec(aStr);
86 /* static */
87 nsresult ContentPrincipal::GenerateOriginNoSuffixFromURI(
88 nsIURI* aURI, nsACString& aOriginNoSuffix) {
89 if (!aURI) {
90 return NS_ERROR_FAILURE;
93 nsCOMPtr<nsIURI> origin = NS_GetInnermostURI(aURI);
94 if (!origin) {
95 return NS_ERROR_FAILURE;
98 MOZ_ASSERT(!NS_IsAboutBlank(origin),
99 "The inner URI for about:blank must be moz-safe-about:blank");
101 // Handle non-strict file:// uris.
102 if (!nsScriptSecurityManager::GetStrictFileOriginPolicy() &&
103 NS_URIIsLocalFile(origin)) {
104 // If strict file origin policy is not in effect, all local files are
105 // considered to be same-origin, so return a known dummy origin here.
106 aOriginNoSuffix.AssignLiteral("file://UNIVERSAL_FILE_URI_ORIGIN");
107 return NS_OK;
110 nsresult rv;
111 // NB: This is only compiled for Thunderbird/Suite.
112 #if IS_ORIGIN_IS_FULL_SPEC_DEFINED
113 bool fullSpec = false;
114 rv = NS_URIChainHasFlags(origin, nsIProtocolHandler::ORIGIN_IS_FULL_SPEC,
115 &fullSpec);
116 NS_ENSURE_SUCCESS(rv, rv);
117 if (fullSpec) {
118 return origin->GetAsciiSpec(aOriginNoSuffix);
120 #endif
122 // We want the invariant that prinA.origin == prinB.origin i.f.f.
123 // prinA.equals(prinB). However, this requires that we impose certain
124 // constraints on the behavior and origin semantics of principals, and in
125 // particular, forbid creating origin strings for principals whose equality
126 // constraints are not expressible as strings (i.e. object equality).
127 // Moreover, we want to forbid URIs containing the magic "^" we use as a
128 // separating character for origin attributes.
130 // These constraints can generally be achieved by restricting .origin to
131 // nsIStandardURL-based URIs, but there are a few other URI schemes that we
132 // need to handle.
133 if (origin->SchemeIs("about") ||
134 (origin->SchemeIs("moz-safe-about") &&
135 // We generally consider two about:foo origins to be same-origin, but
136 // about:blank is special since it can be generated from different
137 // sources. We check for moz-safe-about:blank since origin is an
138 // innermost URI.
139 !StringBeginsWith(origin->GetSpecOrDefault(),
140 "moz-safe-about:blank"_ns))) {
141 rv = origin->GetAsciiSpec(aOriginNoSuffix);
142 NS_ENSURE_SUCCESS(rv, rv);
144 int32_t pos = aOriginNoSuffix.FindChar('?');
145 int32_t hashPos = aOriginNoSuffix.FindChar('#');
147 if (hashPos != kNotFound && (pos == kNotFound || hashPos < pos)) {
148 pos = hashPos;
151 if (pos != kNotFound) {
152 aOriginNoSuffix.Truncate(pos);
155 // These URIs could technically contain a '^', but they never should.
156 if (NS_WARN_IF(aOriginNoSuffix.FindChar('^', 0) != -1)) {
157 aOriginNoSuffix.Truncate();
158 return NS_ERROR_FAILURE;
160 return NS_OK;
163 // This URL can be a blobURL. In this case, we should use the 'parent'
164 // principal instead.
165 nsCOMPtr<nsIPrincipal> blobPrincipal;
166 if (dom::BlobURLProtocolHandler::GetBlobURLPrincipal(
167 origin, getter_AddRefs(blobPrincipal))) {
168 MOZ_ASSERT(blobPrincipal);
169 return blobPrincipal->GetOriginNoSuffix(aOriginNoSuffix);
172 // If we reached this branch, we can only create an origin if we have a
173 // nsIStandardURL. So, we query to a nsIStandardURL, and fail if we aren't
174 // an instance of an nsIStandardURL nsIStandardURLs have the good property
175 // of escaping the '^' character in their specs, which means that we can be
176 // sure that the caret character (which is reserved for delimiting the end
177 // of the spec, and the beginning of the origin attributes) is not present
178 // in the origin string
179 nsCOMPtr<nsIStandardURL> standardURL = do_QueryInterface(origin);
180 if (!standardURL) {
181 return NS_ERROR_FAILURE;
184 // See whether we have a useful hostPort. If we do, use that.
185 nsAutoCString hostPort;
186 if (!origin->SchemeIs("chrome")) {
187 rv = origin->GetAsciiHostPort(hostPort);
188 NS_ENSURE_SUCCESS(rv, rv);
190 if (!hostPort.IsEmpty()) {
191 rv = origin->GetScheme(aOriginNoSuffix);
192 NS_ENSURE_SUCCESS(rv, rv);
193 aOriginNoSuffix.AppendLiteral("://");
194 aOriginNoSuffix.Append(hostPort);
195 return NS_OK;
198 rv = aURI->GetAsciiSpec(aOriginNoSuffix);
199 NS_ENSURE_SUCCESS(rv, rv);
201 // The origin, when taken from the spec, should not contain the ref part of
202 // the URL.
204 int32_t pos = aOriginNoSuffix.FindChar('?');
205 int32_t hashPos = aOriginNoSuffix.FindChar('#');
207 if (hashPos != kNotFound && (pos == kNotFound || hashPos < pos)) {
208 pos = hashPos;
211 if (pos != kNotFound) {
212 aOriginNoSuffix.Truncate(pos);
215 return NS_OK;
218 bool ContentPrincipal::SubsumesInternal(
219 nsIPrincipal* aOther,
220 BasePrincipal::DocumentDomainConsideration aConsideration) {
221 MOZ_ASSERT(aOther);
223 // For ContentPrincipal, Subsumes is equivalent to Equals.
224 if (aOther == this) {
225 return true;
228 // If either the subject or the object has changed its principal by
229 // explicitly setting document.domain then the other must also have
230 // done so in order to be considered the same origin. This prevents
231 // DNS spoofing based on document.domain (154930)
232 if (aConsideration == ConsiderDocumentDomain) {
233 // Get .domain on each principal.
234 nsCOMPtr<nsIURI> thisDomain, otherDomain;
235 GetDomain(getter_AddRefs(thisDomain));
236 aOther->GetDomain(getter_AddRefs(otherDomain));
238 // If either has .domain set, we have equality i.f.f. the domains match.
239 // Otherwise, we fall through to the non-document-domain-considering case.
240 if (thisDomain || otherDomain) {
241 bool isMatch =
242 nsScriptSecurityManager::SecurityCompareURIs(thisDomain, otherDomain);
243 #ifdef DEBUG
244 if (isMatch) {
245 nsAutoCString thisSiteOrigin, otherSiteOrigin;
246 MOZ_ALWAYS_SUCCEEDS(GetSiteOrigin(thisSiteOrigin));
247 MOZ_ALWAYS_SUCCEEDS(aOther->GetSiteOrigin(otherSiteOrigin));
248 MOZ_ASSERT(
249 thisSiteOrigin == otherSiteOrigin,
250 "SubsumesConsideringDomain passed with mismatched siteOrigin!");
252 #endif
253 return isMatch;
257 // Compare uris.
258 return aOther->IsSameOrigin(mURI);
261 NS_IMETHODIMP
262 ContentPrincipal::GetURI(nsIURI** aURI) {
263 *aURI = do_AddRef(mURI).take();
264 return NS_OK;
267 bool ContentPrincipal::MayLoadInternal(nsIURI* aURI) {
268 MOZ_ASSERT(aURI);
270 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
271 nsCOMPtr<nsIURIWithSpecialOrigin> uriWithSpecialOrigin =
272 do_QueryInterface(aURI);
273 if (uriWithSpecialOrigin) {
274 nsCOMPtr<nsIURI> origin;
275 nsresult rv = uriWithSpecialOrigin->GetOrigin(getter_AddRefs(origin));
276 if (NS_WARN_IF(NS_FAILED(rv))) {
277 return false;
279 MOZ_ASSERT(origin);
280 OriginAttributes attrs;
281 RefPtr<BasePrincipal> principal =
282 BasePrincipal::CreateContentPrincipal(origin, attrs);
283 return nsIPrincipal::Subsumes(principal);
285 #endif
287 nsCOMPtr<nsIPrincipal> blobPrincipal;
288 if (dom::BlobURLProtocolHandler::GetBlobURLPrincipal(
289 aURI, getter_AddRefs(blobPrincipal))) {
290 MOZ_ASSERT(blobPrincipal);
291 return nsIPrincipal::Subsumes(blobPrincipal);
294 // If this principal is associated with an addon, check whether that addon
295 // has been given permission to load from this domain.
296 if (AddonAllowsLoad(aURI)) {
297 return true;
300 if (nsScriptSecurityManager::SecurityCompareURIs(mURI, aURI)) {
301 return true;
304 // If strict file origin policy is in effect, local files will always fail
305 // SecurityCompareURIs unless they are identical. Explicitly check file origin
306 // policy, in that case.
307 if (nsScriptSecurityManager::GetStrictFileOriginPolicy() &&
308 NS_URIIsLocalFile(aURI) && NS_RelaxStrictFileOriginPolicy(aURI, mURI)) {
309 return true;
312 return false;
315 uint32_t ContentPrincipal::GetHashValue() {
316 MOZ_ASSERT(mURI, "Need a principal URI");
318 nsCOMPtr<nsIURI> uri;
319 GetDomain(getter_AddRefs(uri));
320 if (!uri) {
321 GetURI(getter_AddRefs(uri));
323 return NS_SecurityHashURI(uri);
326 NS_IMETHODIMP
327 ContentPrincipal::GetDomain(nsIURI** aDomain) {
328 if (!mDomain) {
329 *aDomain = nullptr;
330 return NS_OK;
333 NS_ADDREF(*aDomain = mDomain);
334 return NS_OK;
337 NS_IMETHODIMP
338 ContentPrincipal::SetDomain(nsIURI* aDomain) {
339 MOZ_ASSERT(aDomain);
341 mDomain = aDomain;
342 SetHasExplicitDomain();
344 // Set the changed-document-domain flag on compartments containing realms
345 // using this principal.
346 auto cb = [](JSContext*, void*, JS::Realm* aRealm,
347 const JS::AutoRequireNoGC& nogc) {
348 JS::Compartment* comp = JS::GetCompartmentForRealm(aRealm);
349 xpc::SetCompartmentChangedDocumentDomain(comp);
351 JSPrincipals* principals =
352 nsJSPrincipals::get(static_cast<nsIPrincipal*>(this));
354 dom::AutoJSAPI jsapi;
355 jsapi.Init();
356 JS::IterateRealmsWithPrincipals(jsapi.cx(), principals, nullptr, cb);
358 return NS_OK;
361 static nsresult GetSpecialBaseDomain(const nsCOMPtr<nsIURI>& aURI,
362 bool* aHandled, nsACString& aBaseDomain) {
363 *aHandled = false;
365 // Special handling for a file URI.
366 if (NS_URIIsLocalFile(aURI)) {
367 // If strict file origin policy is not in effect, all local files are
368 // considered to be same-origin, so return a known dummy domain here.
369 if (!nsScriptSecurityManager::GetStrictFileOriginPolicy()) {
370 *aHandled = true;
371 aBaseDomain.AssignLiteral("UNIVERSAL_FILE_URI_ORIGIN");
372 return NS_OK;
375 // Otherwise, we return the file path.
376 nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
378 if (url) {
379 *aHandled = true;
380 return url->GetFilePath(aBaseDomain);
384 bool hasNoRelativeFlag;
385 nsresult rv = NS_URIChainHasFlags(aURI, nsIProtocolHandler::URI_NORELATIVE,
386 &hasNoRelativeFlag);
387 if (NS_WARN_IF(NS_FAILED(rv))) {
388 return rv;
391 // In case of FTP we want to get base domain via TLD service even if FTP
392 // protocol handler is disabled and the scheme is handled by external protocol
393 // handler which returns URI_NORELATIVE flag.
394 if (hasNoRelativeFlag && !aURI->SchemeIs("ftp")) {
395 *aHandled = true;
396 return aURI->GetSpec(aBaseDomain);
399 if (aURI->SchemeIs("indexeddb")) {
400 *aHandled = true;
401 return aURI->GetSpec(aBaseDomain);
404 return NS_OK;
407 NS_IMETHODIMP
408 ContentPrincipal::GetBaseDomain(nsACString& aBaseDomain) {
409 // Handle some special URIs first.
410 bool handled;
411 nsresult rv = GetSpecialBaseDomain(mURI, &handled, aBaseDomain);
412 NS_ENSURE_SUCCESS(rv, rv);
414 if (handled) {
415 return NS_OK;
418 // For everything else, we ask the TLD service via the ThirdPartyUtil.
419 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
420 do_GetService(THIRDPARTYUTIL_CONTRACTID);
421 if (!thirdPartyUtil) {
422 return NS_ERROR_FAILURE;
425 return thirdPartyUtil->GetBaseDomain(mURI, aBaseDomain);
428 NS_IMETHODIMP
429 ContentPrincipal::GetSiteOriginNoSuffix(nsACString& aSiteOrigin) {
430 nsresult rv = GetOriginNoSuffix(aSiteOrigin);
431 NS_ENSURE_SUCCESS(rv, rv);
433 // It is possible for two principals with the same origin to have different
434 // mURI values. In order to ensure that two principals with matching origins
435 // also have matching siteOrigins, we derive the siteOrigin entirely from the
436 // origin string and do not rely on mURI at all here.
437 nsCOMPtr<nsIURI> origin;
438 rv = NS_NewURI(getter_AddRefs(origin), aSiteOrigin);
439 if (NS_FAILED(rv)) {
440 // We got an error parsing the origin as a URI? siteOrigin == origin
441 // aSiteOrigin was already filled with `OriginNoSuffix`
442 return rv;
445 // Handle some special URIs first.
446 nsAutoCString baseDomain;
447 bool handled;
448 rv = GetSpecialBaseDomain(origin, &handled, baseDomain);
449 NS_ENSURE_SUCCESS(rv, rv);
451 if (handled) {
452 // This is a special URI ("file:", "about:", "view-source:", etc). Just
453 // return the origin.
454 return NS_OK;
457 // For everything else, we ask the TLD service. Note that, unlike in
458 // GetBaseDomain, we don't use ThirdPartyUtil.getBaseDomain because if the
459 // host is an IP address that returns the raw address and we can't use it with
460 // SetHost below because SetHost expects '[' and ']' around IPv6 addresses.
461 // See bug 1491728.
462 nsCOMPtr<nsIEffectiveTLDService> tldService =
463 do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
464 if (!tldService) {
465 return NS_ERROR_FAILURE;
468 bool gotBaseDomain = false;
469 rv = tldService->GetBaseDomain(origin, 0, baseDomain);
470 if (NS_SUCCEEDED(rv)) {
471 gotBaseDomain = true;
472 } else {
473 // If this is an IP address or something like "localhost", we just continue
474 // with gotBaseDomain = false.
475 if (rv != NS_ERROR_HOST_IS_IP_ADDRESS &&
476 rv != NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS &&
477 rv != NS_ERROR_INVALID_ARG) {
478 return rv;
482 // NOTE: Calling `SetHostPort` with a portless domain is insufficient to clear
483 // the port, so an extra `SetPort` call has to be made.
484 nsCOMPtr<nsIURI> siteUri;
485 NS_MutateURI mutator(origin);
486 mutator.SetUserPass(""_ns).SetPort(-1);
487 if (gotBaseDomain) {
488 mutator.SetHost(baseDomain);
490 rv = mutator.Finalize(siteUri);
491 MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to create siteUri");
492 NS_ENSURE_SUCCESS(rv, rv);
494 aSiteOrigin.Truncate();
495 rv = GenerateOriginNoSuffixFromURI(siteUri, aSiteOrigin);
496 MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to create siteOriginNoSuffix");
497 return rv;
500 nsresult ContentPrincipal::GetSiteIdentifier(SiteIdentifier& aSite) {
501 nsCString siteOrigin;
502 nsresult rv = GetSiteOrigin(siteOrigin);
503 NS_ENSURE_SUCCESS(rv, rv);
505 RefPtr<BasePrincipal> principal = CreateContentPrincipal(siteOrigin);
506 if (!principal) {
507 NS_WARNING("could not instantiate content principal");
508 return NS_ERROR_FAILURE;
511 aSite.Init(principal);
512 return NS_OK;
515 WebExtensionPolicy* ContentPrincipal::AddonPolicy() {
516 if (!mAddon.isSome()) {
517 NS_ENSURE_TRUE(mURI, nullptr);
519 if (mURI->SchemeIs("moz-extension")) {
520 mAddon.emplace(EPS().GetByURL(mURI.get()));
521 } else {
522 mAddon.emplace(nullptr);
526 return mAddon.value();
529 NS_IMETHODIMP
530 ContentPrincipal::GetAddonId(nsAString& aAddonId) {
531 auto* policy = AddonPolicy();
532 if (policy) {
533 policy->GetId(aAddonId);
534 } else {
535 aAddonId.Truncate();
537 return NS_OK;
540 NS_IMETHODIMP
541 ContentPrincipal::Deserializer::Read(nsIObjectInputStream* aStream) {
542 MOZ_ASSERT(!mPrincipal);
544 nsCOMPtr<nsISupports> supports;
545 nsCOMPtr<nsIURI> principalURI;
546 nsresult rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
547 if (NS_FAILED(rv)) {
548 return rv;
551 principalURI = do_QueryInterface(supports);
552 // Enforce re-parsing about: URIs so that if they change, we continue to use
553 // their new principals correctly.
554 if (principalURI->SchemeIs("about")) {
555 nsAutoCString spec;
556 principalURI->GetSpec(spec);
557 NS_ENSURE_SUCCESS(NS_NewURI(getter_AddRefs(principalURI), spec),
558 NS_ERROR_FAILURE);
561 nsCOMPtr<nsIURI> domain;
562 rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
563 if (NS_FAILED(rv)) {
564 return rv;
567 domain = do_QueryInterface(supports);
569 nsAutoCString suffix;
570 rv = aStream->ReadCString(suffix);
571 NS_ENSURE_SUCCESS(rv, rv);
573 OriginAttributes attrs;
574 bool ok = attrs.PopulateFromSuffix(suffix);
575 NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
577 // Since Bug 965637 we do not serialize the CSP within the
578 // Principal anymore. Nevertheless there might still be
579 // serialized Principals that do have a serialized CSP.
580 // For now, we just read the CSP here but do not actually
581 // consume it. Please note that we deliberately ignore
582 // the return value to avoid CSP deserialization problems.
583 // After Bug 1508939 we will have a new serialization for
584 // Principals which allows us to update the code here.
585 // Additionally, the format for serialized CSPs changed
586 // within Bug 965637 which also can cause failures within
587 // the CSP deserialization code.
588 Unused << NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
590 nsAutoCString originNoSuffix;
591 rv = GenerateOriginNoSuffixFromURI(principalURI, originNoSuffix);
592 NS_ENSURE_SUCCESS(rv, rv);
594 RefPtr<ContentPrincipal> principal =
595 new ContentPrincipal(principalURI, attrs, originNoSuffix);
597 // Note: we don't call SetDomain here because we don't need the wrapper
598 // recomputation code there (we just created this principal).
599 if (domain) {
600 principal->mDomain = domain;
601 principal->SetHasExplicitDomain();
604 mPrincipal = principal.forget();
605 return NS_OK;
608 nsresult ContentPrincipal::PopulateJSONObject(Json::Value& aObject) {
609 nsAutoCString principalURI;
610 nsresult rv = mURI->GetSpec(principalURI);
611 NS_ENSURE_SUCCESS(rv, rv);
613 // We turn each int enum field into a JSON string key of the object
614 // aObject is the inner JSON object that has stringified enum keys
615 // An example aObject might be:
617 // eURI eSuffix
618 // | |
619 // {"0": "https://mozilla.com", "2": "^privateBrowsingId=1"}
620 // | | | |
621 // ----------------------------- |
622 // | | |
623 // Key ----------------------
624 // |
625 // Value
626 aObject[std::to_string(eURI)] = principalURI.get();
628 if (mDomain) {
629 nsAutoCString domainStr;
630 rv = mDomain->GetSpec(domainStr);
631 NS_ENSURE_SUCCESS(rv, rv);
632 aObject[std::to_string(eDomain)] = domainStr.get();
635 nsAutoCString suffix;
636 OriginAttributesRef().CreateSuffix(suffix);
637 if (suffix.Length() > 0) {
638 aObject[std::to_string(eSuffix)] = suffix.get();
641 return NS_OK;
644 already_AddRefed<BasePrincipal> ContentPrincipal::FromProperties(
645 nsTArray<ContentPrincipal::KeyVal>& aFields) {
646 MOZ_ASSERT(aFields.Length() == eMax + 1, "Must have all the keys");
647 nsresult rv;
648 nsCOMPtr<nsIURI> principalURI;
649 nsCOMPtr<nsIURI> domain;
650 nsCOMPtr<nsIContentSecurityPolicy> csp;
651 OriginAttributes attrs;
653 // The odd structure here is to make the code to not compile
654 // if all the switch enum cases haven't been codified
655 for (const auto& field : aFields) {
656 switch (field.key) {
657 case ContentPrincipal::eURI:
658 if (!field.valueWasSerialized) {
659 MOZ_ASSERT(
660 false,
661 "Content principals require a principal URI in serialized JSON");
662 return nullptr;
664 rv = NS_NewURI(getter_AddRefs(principalURI), field.value.get());
665 NS_ENSURE_SUCCESS(rv, nullptr);
668 // Enforce re-parsing about: URIs so that if they change, we
669 // continue to use their new principals correctly.
670 if (principalURI->SchemeIs("about")) {
671 nsAutoCString spec;
672 principalURI->GetSpec(spec);
673 if (NS_FAILED(NS_NewURI(getter_AddRefs(principalURI), spec))) {
674 return nullptr;
678 break;
679 case ContentPrincipal::eDomain:
680 if (field.valueWasSerialized) {
681 rv = NS_NewURI(getter_AddRefs(domain), field.value.get());
682 NS_ENSURE_SUCCESS(rv, nullptr);
684 break;
685 case ContentPrincipal::eSuffix:
686 if (field.valueWasSerialized) {
687 bool ok = attrs.PopulateFromSuffix(field.value);
688 if (!ok) {
689 return nullptr;
692 break;
695 nsAutoCString originNoSuffix;
696 rv = ContentPrincipal::GenerateOriginNoSuffixFromURI(principalURI,
697 originNoSuffix);
698 if (NS_FAILED(rv)) {
699 return nullptr;
702 RefPtr<ContentPrincipal> principal =
703 new ContentPrincipal(principalURI, attrs, originNoSuffix);
705 principal->mDomain = domain;
706 if (principal->mDomain) {
707 principal->SetHasExplicitDomain();
710 return principal.forget();