Bug 1529847 - Move the Changes Front initialization to the Promise.all. r=rcaliman
[gecko.git] / caps / nsJSPrincipals.cpp
blob85ec59c52a21b2cab81550a0815637ceff259cf4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "xpcpublic.h"
7 #include "nsString.h"
8 #include "nsIObjectOutputStream.h"
9 #include "nsIObjectInputStream.h"
10 #include "nsJSPrincipals.h"
11 #include "plstr.h"
12 #include "nsCOMPtr.h"
13 #include "nsIServiceManager.h"
14 #include "nsMemory.h"
15 #include "nsStringBuffer.h"
17 #include "mozilla/dom/StructuredCloneTags.h"
18 // for mozilla::dom::workerinternals::kJSPrincipalsDebugToken
19 #include "mozilla/dom/workerinternals/JSSettings.h"
20 // for mozilla::dom::worklet::kJSPrincipalsDebugToken
21 #include "mozilla/dom/WorkletPrincipal.h"
22 #include "mozilla/ipc/BackgroundUtils.h"
24 using namespace mozilla;
25 using namespace mozilla::ipc;
27 NS_IMETHODIMP_(MozExternalRefCountType)
28 nsJSPrincipals::AddRef() {
29 MOZ_ASSERT(NS_IsMainThread());
30 MOZ_ASSERT(int32_t(refcount) >= 0, "illegal refcnt");
31 nsrefcnt count = ++refcount;
32 NS_LOG_ADDREF(this, count, "nsJSPrincipals", sizeof(*this));
33 return count;
36 NS_IMETHODIMP_(MozExternalRefCountType)
37 nsJSPrincipals::Release() {
38 MOZ_ASSERT(NS_IsMainThread());
39 MOZ_ASSERT(0 != refcount, "dup release");
40 nsrefcnt count = --refcount;
41 NS_LOG_RELEASE(this, count, "nsJSPrincipals");
42 if (count == 0) {
43 delete this;
46 return count;
49 /* static */ bool nsJSPrincipals::Subsume(JSPrincipals* jsprin,
50 JSPrincipals* other) {
51 bool result;
52 nsresult rv = nsJSPrincipals::get(jsprin)->Subsumes(
53 nsJSPrincipals::get(other), &result);
54 return NS_SUCCEEDED(rv) && result;
57 /* static */ void nsJSPrincipals::Destroy(JSPrincipals* jsprin) {
58 // The JS runtime can call this method during the last GC when
59 // nsScriptSecurityManager is destroyed. So we must not assume here that
60 // the security manager still exists.
62 nsJSPrincipals* nsjsprin = nsJSPrincipals::get(jsprin);
64 // We need to destroy the nsIPrincipal. We'll do this by adding
65 // to the refcount and calling release
67 #ifdef NS_BUILD_REFCNT_LOGGING
68 // The refcount logging considers AddRef-to-1 to indicate creation,
69 // so trick it into thinking it's otherwise, but balance the
70 // Release() we do below.
71 nsjsprin->refcount++;
72 nsjsprin->AddRef();
73 nsjsprin->refcount--;
74 #else
75 nsjsprin->refcount++;
76 #endif
77 nsjsprin->Release();
80 #ifdef DEBUG
82 // Defined here so one can do principals->dump() in the debugger
83 JS_PUBLIC_API void JSPrincipals::dump() {
84 if (debugToken == nsJSPrincipals::DEBUG_TOKEN) {
85 nsAutoCString str;
86 nsresult rv = static_cast<nsJSPrincipals*>(this)->GetScriptLocation(str);
87 fprintf(stderr, "nsIPrincipal (%p) = %s\n", static_cast<void*>(this),
88 NS_SUCCEEDED(rv) ? str.get() : "(unknown)");
89 } else if (debugToken == dom::workerinternals::kJSPrincipalsDebugToken) {
90 fprintf(stderr, "Web Worker principal singleton (%p)\n", this);
91 } else if (debugToken ==
92 mozilla::dom::WorkletPrincipal::kJSPrincipalsDebugToken) {
93 fprintf(stderr, "Web Worklet principal singleton (%p)\n", this);
94 } else {
95 fprintf(stderr,
96 "!!! JSPrincipals (%p) is not nsJSPrincipals instance - bad token: "
97 "actual=0x%x expected=0x%x\n",
98 this, unsigned(debugToken), unsigned(nsJSPrincipals::DEBUG_TOKEN));
102 #endif
104 /* static */ bool nsJSPrincipals::ReadPrincipals(
105 JSContext* aCx, JSStructuredCloneReader* aReader,
106 JSPrincipals** aOutPrincipals) {
107 uint32_t tag;
108 uint32_t unused;
109 if (!JS_ReadUint32Pair(aReader, &tag, &unused)) {
110 return false;
113 if (!(tag == SCTAG_DOM_NULL_PRINCIPAL || tag == SCTAG_DOM_SYSTEM_PRINCIPAL ||
114 tag == SCTAG_DOM_CONTENT_PRINCIPAL ||
115 tag == SCTAG_DOM_EXPANDED_PRINCIPAL)) {
116 xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
117 return false;
120 return ReadKnownPrincipalType(aCx, aReader, tag, aOutPrincipals);
123 static bool ReadPrincipalInfo(
124 JSStructuredCloneReader* aReader, OriginAttributes& aAttrs,
125 nsACString& aSpec, nsACString& aOriginNoSuffix,
126 nsTArray<ContentSecurityPolicy>* aPolicies = nullptr) {
127 uint32_t suffixLength, specLength;
128 if (!JS_ReadUint32Pair(aReader, &suffixLength, &specLength)) {
129 return false;
132 nsAutoCString suffix;
133 if (!suffix.SetLength(suffixLength, fallible)) {
134 return false;
137 if (!JS_ReadBytes(aReader, suffix.BeginWriting(), suffixLength)) {
138 return false;
141 if (!aAttrs.PopulateFromSuffix(suffix)) {
142 return false;
145 if (!aSpec.SetLength(specLength, fallible)) {
146 return false;
149 if (!JS_ReadBytes(aReader, aSpec.BeginWriting(), specLength)) {
150 return false;
153 uint32_t originNoSuffixLength, policyCount;
154 if (!JS_ReadUint32Pair(aReader, &originNoSuffixLength, &policyCount)) {
155 return false;
158 if (!aPolicies) {
159 MOZ_ASSERT(policyCount == 0);
162 if (!aOriginNoSuffix.SetLength(originNoSuffixLength, fallible)) {
163 return false;
166 if (!JS_ReadBytes(aReader, aOriginNoSuffix.BeginWriting(),
167 originNoSuffixLength)) {
168 return false;
171 for (uint32_t i = 0; i < policyCount; i++) {
172 uint32_t policyLength, reportAndMeta;
173 if (!JS_ReadUint32Pair(aReader, &policyLength, &reportAndMeta)) {
174 return false;
176 bool reportOnly = reportAndMeta & 1;
177 bool deliveredViaMetaTag = reportAndMeta & 2;
179 nsAutoCString policyStr;
180 if (!policyStr.SetLength(policyLength, fallible)) {
181 return false;
184 if (!JS_ReadBytes(aReader, policyStr.BeginWriting(), policyLength)) {
185 return false;
188 if (aPolicies) {
189 aPolicies->AppendElement(ContentSecurityPolicy(
190 NS_ConvertUTF8toUTF16(policyStr), reportOnly, deliveredViaMetaTag));
194 return true;
197 static bool ReadPrincipalInfo(JSStructuredCloneReader* aReader, uint32_t aTag,
198 PrincipalInfo& aInfo) {
199 if (aTag == SCTAG_DOM_SYSTEM_PRINCIPAL) {
200 aInfo = SystemPrincipalInfo();
201 } else if (aTag == SCTAG_DOM_NULL_PRINCIPAL) {
202 OriginAttributes attrs;
203 nsAutoCString spec;
204 nsAutoCString originNoSuffix;
205 if (!ReadPrincipalInfo(aReader, attrs, spec, originNoSuffix)) {
206 return false;
208 aInfo = NullPrincipalInfo(attrs, spec);
209 } else if (aTag == SCTAG_DOM_EXPANDED_PRINCIPAL) {
210 uint32_t length, unused;
211 if (!JS_ReadUint32Pair(aReader, &length, &unused)) {
212 return false;
215 ExpandedPrincipalInfo expanded;
217 for (uint32_t i = 0; i < length; i++) {
218 uint32_t tag;
219 if (!JS_ReadUint32Pair(aReader, &tag, &unused)) {
220 return false;
223 PrincipalInfo sub;
224 if (!ReadPrincipalInfo(aReader, tag, sub)) {
225 return false;
227 expanded.allowlist().AppendElement(sub);
230 aInfo = expanded;
231 } else if (aTag == SCTAG_DOM_CONTENT_PRINCIPAL) {
232 OriginAttributes attrs;
233 nsAutoCString spec;
234 nsAutoCString originNoSuffix;
235 nsTArray<ContentSecurityPolicy> policies;
236 if (!ReadPrincipalInfo(aReader, attrs, spec, originNoSuffix, &policies)) {
237 return false;
240 #ifdef FUZZING
241 if (originNoSuffix.IsEmpty()) {
242 return false;
244 #endif
246 MOZ_DIAGNOSTIC_ASSERT(!originNoSuffix.IsEmpty());
248 aInfo =
249 ContentPrincipalInfo(attrs, originNoSuffix, spec, std::move(policies));
250 } else {
251 #ifdef FUZZING
252 return false;
253 #else
254 MOZ_CRASH("unexpected principal structured clone tag");
255 #endif
258 return true;
261 /* static */ bool nsJSPrincipals::ReadKnownPrincipalType(
262 JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
263 JSPrincipals** aOutPrincipals) {
264 MOZ_ASSERT(aTag == SCTAG_DOM_NULL_PRINCIPAL ||
265 aTag == SCTAG_DOM_SYSTEM_PRINCIPAL ||
266 aTag == SCTAG_DOM_CONTENT_PRINCIPAL ||
267 aTag == SCTAG_DOM_EXPANDED_PRINCIPAL);
269 if (NS_WARN_IF(!NS_IsMainThread())) {
270 xpc::Throw(aCx, NS_ERROR_UNCATCHABLE_EXCEPTION);
271 return false;
274 PrincipalInfo info;
275 if (!ReadPrincipalInfo(aReader, aTag, info)) {
276 return false;
279 nsresult rv;
280 nsCOMPtr<nsIPrincipal> prin = PrincipalInfoToPrincipal(info, &rv);
281 if (NS_WARN_IF(NS_FAILED(rv))) {
282 xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
283 return false;
286 *aOutPrincipals = get(prin.forget().take());
287 return true;
290 static bool WritePrincipalInfo(
291 JSStructuredCloneWriter* aWriter, const OriginAttributes& aAttrs,
292 const nsCString& aSpec, const nsCString& aOriginNoSuffix,
293 const nsTArray<ContentSecurityPolicy>* aPolicies = nullptr) {
294 nsAutoCString suffix;
295 aAttrs.CreateSuffix(suffix);
296 size_t policyCount = aPolicies ? aPolicies->Length() : 0;
298 if (!(JS_WriteUint32Pair(aWriter, suffix.Length(), aSpec.Length()) &&
299 JS_WriteBytes(aWriter, suffix.get(), suffix.Length()) &&
300 JS_WriteBytes(aWriter, aSpec.get(), aSpec.Length()) &&
301 JS_WriteUint32Pair(aWriter, aOriginNoSuffix.Length(), policyCount) &&
302 JS_WriteBytes(aWriter, aOriginNoSuffix.get(),
303 aOriginNoSuffix.Length()))) {
304 return false;
307 for (uint32_t i = 0; i < policyCount; i++) {
308 nsCString policy;
309 CopyUTF16toUTF8((*aPolicies)[i].policy(), policy);
310 uint32_t reportAndMeta =
311 ((*aPolicies)[i].reportOnlyFlag() ? 1 : 0) |
312 ((*aPolicies)[i].deliveredViaMetaTagFlag() ? 2 : 0);
313 if (!(JS_WriteUint32Pair(aWriter, policy.Length(), reportAndMeta) &&
314 JS_WriteBytes(aWriter, PromiseFlatCString(policy).get(),
315 policy.Length()))) {
316 return false;
320 return true;
323 static bool WritePrincipalInfo(JSStructuredCloneWriter* aWriter,
324 const PrincipalInfo& aInfo) {
325 if (aInfo.type() == PrincipalInfo::TNullPrincipalInfo) {
326 const NullPrincipalInfo& nullInfo = aInfo;
327 return JS_WriteUint32Pair(aWriter, SCTAG_DOM_NULL_PRINCIPAL, 0) &&
328 WritePrincipalInfo(aWriter, nullInfo.attrs(), nullInfo.spec(),
329 EmptyCString());
331 if (aInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
332 return JS_WriteUint32Pair(aWriter, SCTAG_DOM_SYSTEM_PRINCIPAL, 0);
334 if (aInfo.type() == PrincipalInfo::TExpandedPrincipalInfo) {
335 const ExpandedPrincipalInfo& expanded = aInfo;
336 if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_EXPANDED_PRINCIPAL, 0) ||
337 !JS_WriteUint32Pair(aWriter, expanded.allowlist().Length(), 0)) {
338 return false;
341 for (uint32_t i = 0; i < expanded.allowlist().Length(); i++) {
342 if (!WritePrincipalInfo(aWriter, expanded.allowlist()[i])) {
343 return false;
346 return true;
349 MOZ_ASSERT(aInfo.type() == PrincipalInfo::TContentPrincipalInfo);
350 const ContentPrincipalInfo& cInfo = aInfo;
351 return JS_WriteUint32Pair(aWriter, SCTAG_DOM_CONTENT_PRINCIPAL, 0) &&
352 WritePrincipalInfo(aWriter, cInfo.attrs(), cInfo.spec(),
353 cInfo.originNoSuffix(),
354 &(cInfo.securityPolicies()));
357 bool nsJSPrincipals::write(JSContext* aCx, JSStructuredCloneWriter* aWriter) {
358 PrincipalInfo info;
359 if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(this, &info)))) {
360 xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
361 return false;
364 return WritePrincipalInfo(aWriter, info);