Bug 1890277: part 2) Add `require-trusted-types-for` directive to CSP parser, guarded...
[gecko.git] / caps / NullPrincipal.cpp
blob1742413d10893fae6f8a48bab2682e2a76824ee1
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/. */
7 /**
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"
22 #include "nsNetCID.h"
23 #include "nsError.h"
24 #include "nsEscape.h"
25 #include "ContentPrincipal.h"
26 #include "nsScriptSecurityManager.h"
27 #include "pratom.h"
28 #include "nsIObjectInputStream.h"
30 #include "js/JSON.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),
42 mURI(aURI) {}
44 /* static */
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);
52 /* static */
53 already_AddRefed<NullPrincipal> NullPrincipal::Create(
54 const OriginAttributes& aOriginAttributes, nsIURI* aNullPrincipalURI) {
55 nsCOMPtr<nsIURI> uri = aNullPrincipalURI;
56 if (!uri) {
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();
71 /* static */
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.
80 nsCString modified;
81 if (NS_EscapeURLSpan(aPrecursorQuery, esc_Query | esc_Forced, modified)) {
82 aPrecursorQuery.Assign(std::move(modified));
86 void NullPrincipal::UnescapePrecursorQuery(nsACString& aPrecursorQuery) {
87 nsCString modified;
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();
99 } else {
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.
110 if (aPrecursor) {
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));
118 break;
120 case eContentPrincipal: {
121 MOZ_ALWAYS_SUCCEEDS(aPrecursor->GetOriginNoSuffix(precursorOrigin));
122 #ifdef DEBUG
123 nsAutoCString original(precursorOrigin);
124 #endif
125 EscapePrecursorQuery(precursorOrigin);
126 #ifdef DEBUG
127 nsAutoCString unescaped(precursorOrigin);
128 UnescapePrecursorQuery(unescaped);
129 MOZ_ASSERT(unescaped == original,
130 "cannot recover original precursor origin after escape");
131 #endif
132 break;
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:
140 break;
142 if (!precursorOrigin.IsEmpty()) {
143 mutator.SetQuery(precursorOrigin);
147 nsCOMPtr<nsIURI> uri;
148 MOZ_ALWAYS_SUCCEEDS(mutator.Finalize(getter_AddRefs(uri)));
149 return uri.forget();
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); }
162 NS_IMETHODIMP
163 NullPrincipal::GetURI(nsIURI** aURI) {
164 nsCOMPtr<nsIURI> uri = mURI;
165 uri.forget(aURI);
166 return NS_OK;
168 NS_IMETHODIMP
169 NullPrincipal::GetIsOriginPotentiallyTrustworthy(bool* aResult) {
170 *aResult = false;
171 return NS_OK;
174 NS_IMETHODIMP
175 NullPrincipal::GetDomain(nsIURI** aDomain) {
176 nsCOMPtr<nsIURI> uri = mURI;
177 uri.forget(aDomain);
178 return NS_OK;
181 NS_IMETHODIMP
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);
198 return false;
201 NS_IMETHODIMP
202 NullPrincipal::GetBaseDomain(nsACString& aBaseDomain) {
203 // For a null principal, we use our unique uuid as the base domain.
204 return mURI->GetPathQueryRef(aBaseDomain);
207 NS_IMETHODIMP
208 NullPrincipal::GetAddonId(nsAString& aAddonId) {
209 aAddonId.Truncate();
210 return NS_OK;
214 * nsISerializable implementation
216 NS_IMETHODIMP
217 NullPrincipal::Deserializer::Read(nsIObjectInputStream* aStream) {
218 nsAutoCString spec;
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);
237 return NS_OK;
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);
252 return NS_OK;
255 NS_IMETHODIMP
256 NullPrincipal::GetPrecursorPrincipal(nsIPrincipal** aPrincipal) {
257 *aPrincipal = nullptr;
259 nsAutoCString query;
260 if (NS_FAILED(mURI->GetQuery(query)) || query.IsEmpty()) {
261 return NS_OK;
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");
269 return NS_OK;
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
274 // be created.
275 if (precursorURI->SchemeIs(NS_NULLPRINCIPAL_SCHEME)) {
276 #ifdef DEBUG
277 nsAutoCString precursorQuery;
278 precursorURI->GetQuery(precursorQuery);
279 MOZ_ASSERT(precursorQuery.IsEmpty(),
280 "Null principal with nested precursors?");
281 #endif
282 *aPrincipal =
283 NullPrincipal::Create(OriginAttributesRef(), precursorURI).take();
284 return NS_OK;
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>()) {
293 return NS_OK;
295 contentPrincipal.forget(aPrincipal);
296 return NS_OK;
299 bool NullPrincipalJSONHandler::startObject() {
300 switch (mState) {
301 case State::Init:
302 mState = State::StartObject;
303 break;
304 default:
305 NS_WARNING("Unexpected object value");
306 mState = State::Error;
307 return false;
310 return true;
313 bool NullPrincipalJSONHandler::propertyName(const JS::Latin1Char* name,
314 size_t length) {
315 switch (mState) {
316 case State::StartObject:
317 case State::AfterPropertyValue: {
318 if (length != 1) {
319 NS_WARNING(
320 nsPrintfCString("Unexpected property name length: %zu", length)
321 .get());
322 mState = State::Error;
323 return false;
326 char key = char(name[0]);
327 switch (key) {
328 case NullPrincipal::SpecKey:
329 mState = State::SpecKey;
330 break;
331 case NullPrincipal::SuffixKey:
332 mState = State::SuffixKey;
333 break;
334 default:
335 NS_WARNING(
336 nsPrintfCString("Unexpected property name: '%c'", key).get());
337 mState = State::Error;
338 return false;
340 break;
342 default:
343 NS_WARNING("Unexpected property name");
344 mState = State::Error;
345 return false;
348 return true;
351 bool NullPrincipalJSONHandler::endObject() {
352 switch (mState) {
353 case State::AfterPropertyValue:
354 MOZ_ASSERT(mUri);
356 mPrincipal = NullPrincipal::Create(mAttrs, mUri);
357 MOZ_ASSERT(mPrincipal);
359 mState = State::EndObject;
360 break;
361 default:
362 NS_WARNING("Unexpected end of object");
363 mState = State::Error;
364 return false;
367 return true;
370 bool NullPrincipalJSONHandler::stringValue(const JS::Latin1Char* str,
371 size_t length) {
372 switch (mState) {
373 case State::SpecKey: {
374 nsDependentCSubstring spec(reinterpret_cast<const char*>(str), length);
375 nsresult rv = NS_NewURI(getter_AddRefs(mUri), spec);
376 if (NS_FAILED(rv)) {
377 mState = State::Error;
378 return false;
381 mState = State::AfterPropertyValue;
382 break;
384 case State::SuffixKey: {
385 nsDependentCSubstring attrs(reinterpret_cast<const char*>(str), length);
386 if (!mAttrs.PopulateFromSuffix(attrs)) {
387 mState = State::Error;
388 return false;
391 mState = State::AfterPropertyValue;
392 break;
394 default:
395 NS_WARNING("Unexpected string value");
396 mState = State::Error;
397 return false;
400 return true;