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"
31 #include "NullPrincipalJSONHandler.h"
33 using namespace mozilla
;
35 NS_IMPL_CLASSINFO(NullPrincipal
, nullptr, 0, NS_NULLPRINCIPAL_CID
)
36 NS_IMPL_QUERY_INTERFACE_CI(NullPrincipal
, nsIPrincipal
)
37 NS_IMPL_CI_INTERFACE_GETTER(NullPrincipal
, nsIPrincipal
)
39 NullPrincipal::NullPrincipal(nsIURI
* aURI
, const nsACString
& aOriginNoSuffix
,
40 const OriginAttributes
& aOriginAttributes
)
41 : BasePrincipal(eNullPrincipal
, aOriginNoSuffix
, aOriginAttributes
),
45 already_AddRefed
<NullPrincipal
> NullPrincipal::CreateWithInheritedAttributes(
46 nsIPrincipal
* aInheritFrom
) {
47 MOZ_ASSERT(aInheritFrom
);
48 nsCOMPtr
<nsIURI
> uri
= CreateURI(aInheritFrom
);
49 return Create(Cast(aInheritFrom
)->OriginAttributesRef(), uri
);
53 already_AddRefed
<NullPrincipal
> NullPrincipal::Create(
54 const OriginAttributes
& aOriginAttributes
, nsIURI
* aNullPrincipalURI
) {
55 nsCOMPtr
<nsIURI
> uri
= aNullPrincipalURI
;
57 uri
= NullPrincipal::CreateURI(nullptr);
60 MOZ_RELEASE_ASSERT(uri
->SchemeIs(NS_NULLPRINCIPAL_SCHEME
));
62 nsAutoCString originNoSuffix
;
63 DebugOnly
<nsresult
> rv
= uri
->GetSpec(originNoSuffix
);
64 MOZ_ASSERT(NS_SUCCEEDED(rv
));
66 RefPtr
<NullPrincipal
> nullPrin
=
67 new NullPrincipal(uri
, originNoSuffix
, aOriginAttributes
);
68 return nullPrin
.forget();
72 already_AddRefed
<NullPrincipal
> NullPrincipal::CreateWithoutOriginAttributes() {
73 return NullPrincipal::Create(OriginAttributes(), nullptr);
76 void NullPrincipal::EscapePrecursorQuery(nsACString
& aPrecursorQuery
) {
77 // origins should not contain existing escape sequences, so set `esc_Forced`
78 // to force any `%` in the input to be escaped in addition to non-ascii,
79 // control characters and DEL.
81 if (NS_EscapeURLSpan(aPrecursorQuery
, esc_Query
| esc_Forced
, modified
)) {
82 aPrecursorQuery
.Assign(std::move(modified
));
86 void NullPrincipal::UnescapePrecursorQuery(nsACString
& aPrecursorQuery
) {
88 if (NS_UnescapeURL(aPrecursorQuery
.BeginReading(), aPrecursorQuery
.Length(),
89 /* aFlags */ 0, modified
)) {
90 aPrecursorQuery
.Assign(std::move(modified
));
94 already_AddRefed
<nsIURI
> NullPrincipal::CreateURI(
95 nsIPrincipal
* aPrecursor
, const nsID
* aNullPrincipalID
) {
96 nsCOMPtr
<nsIURIMutator
> iMutator
;
97 if (StaticPrefs::network_url_useDefaultURI()) {
98 iMutator
= new mozilla::net::DefaultURI::Mutator();
100 iMutator
= new mozilla::net::nsSimpleURI::Mutator();
103 nsID uuid
= aNullPrincipalID
? *aNullPrincipalID
: nsID::GenerateUUID();
105 NS_MutateURI
mutator(iMutator
);
106 mutator
.SetSpec(NS_NULLPRINCIPAL_SCHEME
":"_ns
+
107 nsDependentCString(nsIDToCString(uuid
).get()));
109 // If there's a precursor URI, encode it in the null principal URI's query.
111 nsAutoCString precursorOrigin
;
112 switch (BasePrincipal::Cast(aPrecursor
)->Kind()) {
113 case eNullPrincipal
: {
114 // If the precursor null principal has a precursor, inherit it.
115 if (nsCOMPtr
<nsIURI
> nullPrecursorURI
= aPrecursor
->GetURI()) {
116 MOZ_ALWAYS_SUCCEEDS(nullPrecursorURI
->GetQuery(precursorOrigin
));
120 case eContentPrincipal
: {
121 MOZ_ALWAYS_SUCCEEDS(aPrecursor
->GetOriginNoSuffix(precursorOrigin
));
123 nsAutoCString
original(precursorOrigin
);
125 EscapePrecursorQuery(precursorOrigin
);
127 nsAutoCString
unescaped(precursorOrigin
);
128 UnescapePrecursorQuery(unescaped
);
129 MOZ_ASSERT(unescaped
== original
,
130 "cannot recover original precursor origin after escape");
135 // For now, we won't track expanded or system principal precursors. We may
136 // want to track expanded principal precursors in the future, but it's
137 // unlikely we'll want to track system principal precursors.
138 case eExpandedPrincipal
:
139 case eSystemPrincipal
:
142 if (!precursorOrigin
.IsEmpty()) {
143 mutator
.SetQuery(precursorOrigin
);
147 nsCOMPtr
<nsIURI
> uri
;
148 MOZ_ALWAYS_SUCCEEDS(mutator
.Finalize(getter_AddRefs(uri
)));
152 nsresult
NullPrincipal::GetScriptLocation(nsACString
& aStr
) {
153 return mURI
->GetSpec(aStr
);
157 * nsIPrincipal implementation
160 uint32_t NullPrincipal::GetHashValue() { return (NS_PTR_TO_INT32(this) >> 2); }
163 NullPrincipal::GetURI(nsIURI
** aURI
) {
164 nsCOMPtr
<nsIURI
> uri
= mURI
;
169 NullPrincipal::GetIsOriginPotentiallyTrustworthy(bool* aResult
) {
175 NullPrincipal::GetDomain(nsIURI
** aDomain
) {
176 nsCOMPtr
<nsIURI
> uri
= mURI
;
182 NullPrincipal::SetDomain(nsIURI
* aDomain
) {
183 // I think the right thing to do here is to just throw... Silently failing
184 // seems counterproductive.
185 return NS_ERROR_NOT_AVAILABLE
;
188 bool NullPrincipal::MayLoadInternal(nsIURI
* aURI
) {
189 // Also allow the load if we are the principal of the URI being checked.
190 nsCOMPtr
<nsIPrincipal
> blobPrincipal
;
191 if (dom::BlobURLProtocolHandler::GetBlobURLPrincipal(
192 aURI
, getter_AddRefs(blobPrincipal
))) {
193 MOZ_ASSERT(blobPrincipal
);
194 return SubsumesInternal(blobPrincipal
,
195 BasePrincipal::ConsiderDocumentDomain
);
202 NullPrincipal::GetBaseDomain(nsACString
& aBaseDomain
) {
203 // For a null principal, we use our unique uuid as the base domain.
204 return mURI
->GetPathQueryRef(aBaseDomain
);
208 NullPrincipal::GetAddonId(nsAString
& aAddonId
) {
214 * nsISerializable implementation
217 NullPrincipal::Deserializer::Read(nsIObjectInputStream
* aStream
) {
219 nsresult rv
= aStream
->ReadCString(spec
);
220 NS_ENSURE_SUCCESS(rv
, rv
);
222 nsCOMPtr
<nsIURI
> uri
;
223 rv
= NS_NewURI(getter_AddRefs(uri
), spec
);
224 NS_ENSURE_SUCCESS(rv
, rv
);
226 nsAutoCString suffix
;
227 rv
= aStream
->ReadCString(suffix
);
228 NS_ENSURE_SUCCESS(rv
, rv
);
230 OriginAttributes attrs
;
231 bool ok
= attrs
.PopulateFromSuffix(suffix
);
232 NS_ENSURE_TRUE(ok
, NS_ERROR_FAILURE
);
234 mPrincipal
= NullPrincipal::Create(attrs
, uri
);
235 NS_ENSURE_TRUE(mPrincipal
, NS_ERROR_FAILURE
);
240 nsresult
NullPrincipal::WriteJSONInnerProperties(JSONWriter
& aWriter
) {
241 nsAutoCString principalURI
;
242 nsresult rv
= mURI
->GetSpec(principalURI
);
243 NS_ENSURE_SUCCESS(rv
, rv
);
244 WriteJSONProperty
<eSpec
>(aWriter
, principalURI
);
246 nsAutoCString suffix
;
247 OriginAttributesRef().CreateSuffix(suffix
);
248 if (suffix
.Length() > 0) {
249 WriteJSONProperty
<eSuffix
>(aWriter
, suffix
);
256 NullPrincipal::GetPrecursorPrincipal(nsIPrincipal
** aPrincipal
) {
257 *aPrincipal
= nullptr;
260 if (NS_FAILED(mURI
->GetQuery(query
)) || query
.IsEmpty()) {
263 UnescapePrecursorQuery(query
);
265 nsCOMPtr
<nsIURI
> precursorURI
;
266 if (NS_FAILED(NS_NewURI(getter_AddRefs(precursorURI
), query
))) {
267 MOZ_ASSERT_UNREACHABLE(
268 "Failed to parse precursor from nullprincipal query");
272 // If our precursor is another null principal, re-construct it. This can
273 // happen if a null principal without a precursor causes another principal to
275 if (precursorURI
->SchemeIs(NS_NULLPRINCIPAL_SCHEME
)) {
277 nsAutoCString precursorQuery
;
278 precursorURI
->GetQuery(precursorQuery
);
279 MOZ_ASSERT(precursorQuery
.IsEmpty(),
280 "Null principal with nested precursors?");
283 NullPrincipal::Create(OriginAttributesRef(), precursorURI
).take();
287 RefPtr
<BasePrincipal
> contentPrincipal
=
288 BasePrincipal::CreateContentPrincipal(precursorURI
,
289 OriginAttributesRef());
290 // If `CreateContentPrincipal` failed, it will create a new NullPrincipal and
291 // return that instead. We only want to return real content principals here.
292 if (!contentPrincipal
|| !contentPrincipal
->Is
<ContentPrincipal
>()) {
295 contentPrincipal
.forget(aPrincipal
);
299 bool NullPrincipalJSONHandler::startObject() {
302 mState
= State::StartObject
;
305 NS_WARNING("Unexpected object value");
306 mState
= State::Error
;
313 bool NullPrincipalJSONHandler::propertyName(const JS::Latin1Char
* name
,
316 case State::StartObject
:
317 case State::AfterPropertyValue
: {
320 nsPrintfCString("Unexpected property name length: %zu", length
)
322 mState
= State::Error
;
326 char key
= char(name
[0]);
328 case NullPrincipal::SpecKey
:
329 mState
= State::SpecKey
;
331 case NullPrincipal::SuffixKey
:
332 mState
= State::SuffixKey
;
336 nsPrintfCString("Unexpected property name: '%c'", key
).get());
337 mState
= State::Error
;
343 NS_WARNING("Unexpected property name");
344 mState
= State::Error
;
351 bool NullPrincipalJSONHandler::endObject() {
353 case State::AfterPropertyValue
:
356 mPrincipal
= NullPrincipal::Create(mAttrs
, mUri
);
357 MOZ_ASSERT(mPrincipal
);
359 mState
= State::EndObject
;
362 NS_WARNING("Unexpected end of object");
363 mState
= State::Error
;
370 bool NullPrincipalJSONHandler::stringValue(const JS::Latin1Char
* str
,
373 case State::SpecKey
: {
374 nsDependentCSubstring
spec(reinterpret_cast<const char*>(str
), length
);
375 nsresult rv
= NS_NewURI(getter_AddRefs(mUri
), spec
);
377 mState
= State::Error
;
381 mState
= State::AfterPropertyValue
;
384 case State::SuffixKey
: {
385 nsDependentCSubstring
attrs(reinterpret_cast<const char*>(str
), length
);
386 if (!mAttrs
.PopulateFromSuffix(attrs
)) {
387 mState
= State::Error
;
391 mState
= State::AfterPropertyValue
;
395 NS_WARNING("Unexpected string value");
396 mState
= State::Error
;