Backed out changeset af2c13b9fdb7 (bug 1801244) per developer request.
[gecko.git] / caps / NullPrincipal.cpp
blobb6961f0727f8a50dc3bd38582c40706631c2b853
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 "json/json.h"
32 using namespace mozilla;
34 NS_IMPL_CLASSINFO(NullPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY,
35 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::PopulateJSONObject(Json::Value& aObject) {
241 nsAutoCString principalURI;
242 nsresult rv = mURI->GetSpec(principalURI);
243 NS_ENSURE_SUCCESS(rv, rv);
244 aObject[std::to_string(eSpec)] = principalURI.get();
246 nsAutoCString suffix;
247 OriginAttributesRef().CreateSuffix(suffix);
248 if (suffix.Length() > 0) {
249 aObject[std::to_string(eSuffix)] = suffix.get();
252 return NS_OK;
255 already_AddRefed<BasePrincipal> NullPrincipal::FromProperties(
256 nsTArray<NullPrincipal::KeyVal>& aFields) {
257 MOZ_ASSERT(aFields.Length() == eMax + 1, "Must have all the keys");
258 nsresult rv;
259 nsCOMPtr<nsIURI> uri;
260 OriginAttributes attrs;
262 // The odd structure here is to make the code to not compile
263 // if all the switch enum cases haven't been codified
264 for (const auto& field : aFields) {
265 switch (field.key) {
266 case NullPrincipal::eSpec:
267 if (!field.valueWasSerialized) {
268 MOZ_ASSERT(false,
269 "Null principals require a spec URI in serialized JSON");
270 return nullptr;
272 rv = NS_NewURI(getter_AddRefs(uri), field.value);
273 NS_ENSURE_SUCCESS(rv, nullptr);
274 break;
275 case NullPrincipal::eSuffix:
276 bool ok = attrs.PopulateFromSuffix(field.value);
277 if (!ok) {
278 return nullptr;
280 break;
284 if (!uri) {
285 MOZ_ASSERT(false, "No URI deserialized");
286 return nullptr;
289 return NullPrincipal::Create(attrs, uri);
292 NS_IMETHODIMP
293 NullPrincipal::GetPrecursorPrincipal(nsIPrincipal** aPrincipal) {
294 *aPrincipal = nullptr;
296 nsAutoCString query;
297 if (NS_FAILED(mURI->GetQuery(query)) || query.IsEmpty()) {
298 return NS_OK;
300 UnescapePrecursorQuery(query);
302 nsCOMPtr<nsIURI> precursorURI;
303 if (NS_FAILED(NS_NewURI(getter_AddRefs(precursorURI), query))) {
304 MOZ_ASSERT_UNREACHABLE(
305 "Failed to parse precursor from nullprincipal query");
306 return NS_OK;
309 // If our precursor is another null principal, re-construct it. This can
310 // happen if a null principal without a precursor causes another principal to
311 // be created.
312 if (precursorURI->SchemeIs(NS_NULLPRINCIPAL_SCHEME)) {
313 #ifdef DEBUG
314 nsAutoCString precursorQuery;
315 precursorURI->GetQuery(precursorQuery);
316 MOZ_ASSERT(precursorQuery.IsEmpty(),
317 "Null principal with nested precursors?");
318 #endif
319 *aPrincipal =
320 NullPrincipal::Create(OriginAttributesRef(), precursorURI).take();
321 return NS_OK;
324 RefPtr<BasePrincipal> contentPrincipal =
325 BasePrincipal::CreateContentPrincipal(precursorURI,
326 OriginAttributesRef());
327 // If `CreateContentPrincipal` failed, it will create a new NullPrincipal and
328 // return that instead. We only want to return real content principals here.
329 if (!contentPrincipal || !contentPrincipal->Is<ContentPrincipal>()) {
330 return NS_OK;
332 contentPrincipal.forget(aPrincipal);
333 return NS_OK;