1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 sts=2 ts=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/. */
8 * This is the principal that has no rights and can't be accessed by
9 * anything other than itself and chrome; null principals are not
10 * same-origin with anything but themselves.
13 #include "mozilla/ArrayUtils.h"
15 #include "mozilla/dom/BlobURLProtocolHandler.h"
16 #include "mozilla/StaticPrefs_network.h"
17 #include "nsDocShell.h"
18 #include "NullPrincipal.h"
19 #include "DefaultURI.h"
20 #include "nsSimpleURI.h"
21 #include "nsIClassInfoImpl.h"
25 #include "ContentPrincipal.h"
26 #include "nsScriptSecurityManager.h"
28 #include "nsIObjectInputStream.h"
30 #include "json/json.h"
32 using namespace mozilla
;
34 NS_IMPL_CLASSINFO(NullPrincipal
, nullptr, 0, NS_NULLPRINCIPAL_CID
)
35 NS_IMPL_QUERY_INTERFACE_CI(NullPrincipal
, nsIPrincipal
)
36 NS_IMPL_CI_INTERFACE_GETTER(NullPrincipal
, nsIPrincipal
)
38 NullPrincipal::NullPrincipal(nsIURI
* aURI
, const nsACString
& aOriginNoSuffix
,
39 const OriginAttributes
& aOriginAttributes
)
40 : BasePrincipal(eNullPrincipal
, aOriginNoSuffix
, aOriginAttributes
),
44 already_AddRefed
<NullPrincipal
> NullPrincipal::CreateWithInheritedAttributes(
45 nsIPrincipal
* aInheritFrom
) {
46 MOZ_ASSERT(aInheritFrom
);
47 nsCOMPtr
<nsIURI
> uri
= CreateURI(aInheritFrom
);
48 return Create(Cast(aInheritFrom
)->OriginAttributesRef(), uri
);
52 already_AddRefed
<NullPrincipal
> NullPrincipal::Create(
53 const OriginAttributes
& aOriginAttributes
, nsIURI
* aNullPrincipalURI
) {
54 nsCOMPtr
<nsIURI
> uri
= aNullPrincipalURI
;
56 uri
= NullPrincipal::CreateURI(nullptr);
59 MOZ_RELEASE_ASSERT(uri
->SchemeIs(NS_NULLPRINCIPAL_SCHEME
));
61 nsAutoCString originNoSuffix
;
62 DebugOnly
<nsresult
> rv
= uri
->GetSpec(originNoSuffix
);
63 MOZ_ASSERT(NS_SUCCEEDED(rv
));
65 RefPtr
<NullPrincipal
> nullPrin
=
66 new NullPrincipal(uri
, originNoSuffix
, aOriginAttributes
);
67 return nullPrin
.forget();
71 already_AddRefed
<NullPrincipal
> NullPrincipal::CreateWithoutOriginAttributes() {
72 return NullPrincipal::Create(OriginAttributes(), nullptr);
75 void NullPrincipal::EscapePrecursorQuery(nsACString
& aPrecursorQuery
) {
76 // origins should not contain existing escape sequences, so set `esc_Forced`
77 // to force any `%` in the input to be escaped in addition to non-ascii,
78 // control characters and DEL.
80 if (NS_EscapeURLSpan(aPrecursorQuery
, esc_Query
| esc_Forced
, modified
)) {
81 aPrecursorQuery
.Assign(std::move(modified
));
85 void NullPrincipal::UnescapePrecursorQuery(nsACString
& aPrecursorQuery
) {
87 if (NS_UnescapeURL(aPrecursorQuery
.BeginReading(), aPrecursorQuery
.Length(),
88 /* aFlags */ 0, modified
)) {
89 aPrecursorQuery
.Assign(std::move(modified
));
93 already_AddRefed
<nsIURI
> NullPrincipal::CreateURI(
94 nsIPrincipal
* aPrecursor
, const nsID
* aNullPrincipalID
) {
95 nsCOMPtr
<nsIURIMutator
> iMutator
;
96 if (StaticPrefs::network_url_useDefaultURI()) {
97 iMutator
= new mozilla::net::DefaultURI::Mutator();
99 iMutator
= new mozilla::net::nsSimpleURI::Mutator();
102 nsID uuid
= aNullPrincipalID
? *aNullPrincipalID
: nsID::GenerateUUID();
104 NS_MutateURI
mutator(iMutator
);
105 mutator
.SetSpec(NS_NULLPRINCIPAL_SCHEME
":"_ns
+
106 nsDependentCString(nsIDToCString(uuid
).get()));
108 // If there's a precursor URI, encode it in the null principal URI's query.
110 nsAutoCString precursorOrigin
;
111 switch (BasePrincipal::Cast(aPrecursor
)->Kind()) {
112 case eNullPrincipal
: {
113 // If the precursor null principal has a precursor, inherit it.
114 if (nsCOMPtr
<nsIURI
> nullPrecursorURI
= aPrecursor
->GetURI()) {
115 MOZ_ALWAYS_SUCCEEDS(nullPrecursorURI
->GetQuery(precursorOrigin
));
119 case eContentPrincipal
: {
120 MOZ_ALWAYS_SUCCEEDS(aPrecursor
->GetOriginNoSuffix(precursorOrigin
));
122 nsAutoCString
original(precursorOrigin
);
124 EscapePrecursorQuery(precursorOrigin
);
126 nsAutoCString
unescaped(precursorOrigin
);
127 UnescapePrecursorQuery(unescaped
);
128 MOZ_ASSERT(unescaped
== original
,
129 "cannot recover original precursor origin after escape");
134 // For now, we won't track expanded or system principal precursors. We may
135 // want to track expanded principal precursors in the future, but it's
136 // unlikely we'll want to track system principal precursors.
137 case eExpandedPrincipal
:
138 case eSystemPrincipal
:
141 if (!precursorOrigin
.IsEmpty()) {
142 mutator
.SetQuery(precursorOrigin
);
146 nsCOMPtr
<nsIURI
> uri
;
147 MOZ_ALWAYS_SUCCEEDS(mutator
.Finalize(getter_AddRefs(uri
)));
151 nsresult
NullPrincipal::GetScriptLocation(nsACString
& aStr
) {
152 return mURI
->GetSpec(aStr
);
156 * nsIPrincipal implementation
159 uint32_t NullPrincipal::GetHashValue() { return (NS_PTR_TO_INT32(this) >> 2); }
162 NullPrincipal::GetURI(nsIURI
** aURI
) {
163 nsCOMPtr
<nsIURI
> uri
= mURI
;
168 NullPrincipal::GetIsOriginPotentiallyTrustworthy(bool* aResult
) {
174 NullPrincipal::GetDomain(nsIURI
** aDomain
) {
175 nsCOMPtr
<nsIURI
> uri
= mURI
;
181 NullPrincipal::SetDomain(nsIURI
* aDomain
) {
182 // I think the right thing to do here is to just throw... Silently failing
183 // seems counterproductive.
184 return NS_ERROR_NOT_AVAILABLE
;
187 bool NullPrincipal::MayLoadInternal(nsIURI
* aURI
) {
188 // Also allow the load if we are the principal of the URI being checked.
189 nsCOMPtr
<nsIPrincipal
> blobPrincipal
;
190 if (dom::BlobURLProtocolHandler::GetBlobURLPrincipal(
191 aURI
, getter_AddRefs(blobPrincipal
))) {
192 MOZ_ASSERT(blobPrincipal
);
193 return SubsumesInternal(blobPrincipal
,
194 BasePrincipal::ConsiderDocumentDomain
);
201 NullPrincipal::GetBaseDomain(nsACString
& aBaseDomain
) {
202 // For a null principal, we use our unique uuid as the base domain.
203 return mURI
->GetPathQueryRef(aBaseDomain
);
207 NullPrincipal::GetAddonId(nsAString
& aAddonId
) {
213 * nsISerializable implementation
216 NullPrincipal::Deserializer::Read(nsIObjectInputStream
* aStream
) {
218 nsresult rv
= aStream
->ReadCString(spec
);
219 NS_ENSURE_SUCCESS(rv
, rv
);
221 nsCOMPtr
<nsIURI
> uri
;
222 rv
= NS_NewURI(getter_AddRefs(uri
), spec
);
223 NS_ENSURE_SUCCESS(rv
, rv
);
225 nsAutoCString suffix
;
226 rv
= aStream
->ReadCString(suffix
);
227 NS_ENSURE_SUCCESS(rv
, rv
);
229 OriginAttributes attrs
;
230 bool ok
= attrs
.PopulateFromSuffix(suffix
);
231 NS_ENSURE_TRUE(ok
, NS_ERROR_FAILURE
);
233 mPrincipal
= NullPrincipal::Create(attrs
, uri
);
234 NS_ENSURE_TRUE(mPrincipal
, NS_ERROR_FAILURE
);
239 nsresult
NullPrincipal::PopulateJSONObject(Json::Value
& aObject
) {
240 nsAutoCString principalURI
;
241 nsresult rv
= mURI
->GetSpec(principalURI
);
242 NS_ENSURE_SUCCESS(rv
, rv
);
243 SetJSONValue
<eSpec
>(aObject
, principalURI
);
245 nsAutoCString suffix
;
246 OriginAttributesRef().CreateSuffix(suffix
);
247 if (suffix
.Length() > 0) {
248 SetJSONValue
<eSuffix
>(aObject
, suffix
);
254 already_AddRefed
<BasePrincipal
> NullPrincipal::FromProperties(
255 nsTArray
<NullPrincipal::KeyVal
>& aFields
) {
256 MOZ_ASSERT(aFields
.Length() == eMax
+ 1, "Must have all the keys");
258 nsCOMPtr
<nsIURI
> uri
;
259 OriginAttributes attrs
;
261 // The odd structure here is to make the code to not compile
262 // if all the switch enum cases haven't been codified
263 for (const auto& field
: aFields
) {
265 case NullPrincipal::eSpec
:
266 if (!field
.valueWasSerialized
) {
268 "Null principals require a spec URI in serialized JSON");
271 rv
= NS_NewURI(getter_AddRefs(uri
), field
.value
);
272 NS_ENSURE_SUCCESS(rv
, nullptr);
274 case NullPrincipal::eSuffix
:
275 bool ok
= attrs
.PopulateFromSuffix(field
.value
);
284 MOZ_ASSERT(false, "No URI deserialized");
288 return NullPrincipal::Create(attrs
, uri
);
292 NullPrincipal::GetPrecursorPrincipal(nsIPrincipal
** aPrincipal
) {
293 *aPrincipal
= nullptr;
296 if (NS_FAILED(mURI
->GetQuery(query
)) || query
.IsEmpty()) {
299 UnescapePrecursorQuery(query
);
301 nsCOMPtr
<nsIURI
> precursorURI
;
302 if (NS_FAILED(NS_NewURI(getter_AddRefs(precursorURI
), query
))) {
303 MOZ_ASSERT_UNREACHABLE(
304 "Failed to parse precursor from nullprincipal query");
308 // If our precursor is another null principal, re-construct it. This can
309 // happen if a null principal without a precursor causes another principal to
311 if (precursorURI
->SchemeIs(NS_NULLPRINCIPAL_SCHEME
)) {
313 nsAutoCString precursorQuery
;
314 precursorURI
->GetQuery(precursorQuery
);
315 MOZ_ASSERT(precursorQuery
.IsEmpty(),
316 "Null principal with nested precursors?");
319 NullPrincipal::Create(OriginAttributesRef(), precursorURI
).take();
323 RefPtr
<BasePrincipal
> contentPrincipal
=
324 BasePrincipal::CreateContentPrincipal(precursorURI
,
325 OriginAttributesRef());
326 // If `CreateContentPrincipal` failed, it will create a new NullPrincipal and
327 // return that instead. We only want to return real content principals here.
328 if (!contentPrincipal
|| !contentPrincipal
->Is
<ContentPrincipal
>()) {
331 contentPrincipal
.forget(aPrincipal
);