Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 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/. */
6 :
7 : #include "nsCOMPtr.h"
8 : #include "nsContentPolicyUtils.h"
9 : #include "nsContentUtils.h"
10 : #include "nsCSPContext.h"
11 : #include "nsCSPParser.h"
12 : #include "nsCSPService.h"
13 : #include "nsError.h"
14 : #include "nsIAsyncVerifyRedirectCallback.h"
15 : #include "nsIClassInfoImpl.h"
16 : #include "nsIDocShell.h"
17 : #include "nsIDocShellTreeItem.h"
18 : #include "nsIDOMHTMLDocument.h"
19 : #include "nsIDOMHTMLElement.h"
20 : #include "nsIDOMNode.h"
21 : #include "nsIHttpChannel.h"
22 : #include "nsIInterfaceRequestor.h"
23 : #include "nsIInterfaceRequestorUtils.h"
24 : #include "nsIObjectInputStream.h"
25 : #include "nsIObjectOutputStream.h"
26 : #include "nsIObserver.h"
27 : #include "nsIObserverService.h"
28 : #include "nsIStringStream.h"
29 : #include "nsIUploadChannel.h"
30 : #include "nsIScriptError.h"
31 : #include "nsIWebNavigation.h"
32 : #include "nsMimeTypes.h"
33 : #include "nsNetUtil.h"
34 : #include "nsIContentPolicy.h"
35 : #include "nsSupportsPrimitives.h"
36 : #include "nsThreadUtils.h"
37 : #include "nsString.h"
38 : #include "nsScriptSecurityManager.h"
39 : #include "nsStringStream.h"
40 : #include "mozilla/Logging.h"
41 : #include "mozilla/dom/CSPReportBinding.h"
42 : #include "mozilla/dom/CSPDictionariesBinding.h"
43 : #include "mozilla/net/ReferrerPolicy.h"
44 : #include "nsINetworkInterceptController.h"
45 : #include "nsSandboxFlags.h"
46 : #include "nsIScriptElement.h"
47 : #include "nsIEventTarget.h"
48 : #include "mozilla/dom/DocGroup.h"
49 : #include "nsXULAppAPI.h"
50 :
51 : using namespace mozilla;
52 :
53 : static LogModule*
54 0 : GetCspContextLog()
55 : {
56 : static LazyLogModule gCspContextPRLog("CSPContext");
57 0 : return gCspContextPRLog;
58 : }
59 :
60 : #define CSPCONTEXTLOG(args) MOZ_LOG(GetCspContextLog(), mozilla::LogLevel::Debug, args)
61 : #define CSPCONTEXTLOGENABLED() MOZ_LOG_TEST(GetCspContextLog(), mozilla::LogLevel::Debug)
62 :
63 : static const uint32_t CSP_CACHE_URI_CUTOFF_SIZE = 512;
64 :
65 : /**
66 : * Creates a key for use in the ShouldLoad cache.
67 : * Looks like: <uri>!<nsIContentPolicy::LOAD_TYPE>
68 : */
69 : nsresult
70 0 : CreateCacheKey_Internal(nsIURI* aContentLocation,
71 : nsContentPolicyType aContentType,
72 : nsACString& outCacheKey)
73 : {
74 0 : if (!aContentLocation) {
75 0 : return NS_ERROR_FAILURE;
76 : }
77 :
78 0 : bool isDataScheme = false;
79 0 : nsresult rv = aContentLocation->SchemeIs("data", &isDataScheme);
80 0 : NS_ENSURE_SUCCESS(rv, rv);
81 :
82 0 : outCacheKey.Truncate();
83 0 : if (aContentType != nsIContentPolicy::TYPE_SCRIPT && isDataScheme) {
84 : // For non-script data: URI, use ("data:", aContentType) as the cache key.
85 0 : outCacheKey.Append(NS_LITERAL_CSTRING("data:"));
86 0 : outCacheKey.AppendInt(aContentType);
87 0 : return NS_OK;
88 : }
89 :
90 0 : nsAutoCString spec;
91 0 : rv = aContentLocation->GetSpec(spec);
92 0 : NS_ENSURE_SUCCESS(rv, rv);
93 :
94 : // Don't cache for a URI longer than the cutoff size.
95 0 : if (spec.Length() <= CSP_CACHE_URI_CUTOFF_SIZE) {
96 0 : outCacheKey.Append(spec);
97 0 : outCacheKey.Append(NS_LITERAL_CSTRING("!"));
98 0 : outCacheKey.AppendInt(aContentType);
99 : }
100 :
101 0 : return NS_OK;
102 : }
103 :
104 : /* ===== nsIContentSecurityPolicy impl ====== */
105 :
106 : NS_IMETHODIMP
107 0 : nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
108 : nsIURI* aContentLocation,
109 : nsIURI* aRequestOrigin,
110 : nsISupports* aRequestContext,
111 : const nsACString& aMimeTypeGuess,
112 : nsISupports* aExtra,
113 : int16_t* outDecision)
114 : {
115 0 : if (CSPCONTEXTLOGENABLED()) {
116 0 : CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, aContentLocation: %s",
117 : aContentLocation->GetSpecOrDefault().get()));
118 0 : CSPCONTEXTLOG((">>>> aContentType: %d", aContentType));
119 : }
120 :
121 0 : bool isPreload = nsContentUtils::IsPreloadType(aContentType);
122 :
123 : // Since we know whether we are dealing with a preload, we have to convert
124 : // the internal policytype ot the external policy type before moving on.
125 : // We still need to know if this is a worker so child-src can handle that
126 : // case correctly.
127 0 : aContentType = nsContentUtils::InternalContentPolicyTypeToExternalOrWorker(aContentType);
128 :
129 0 : nsresult rv = NS_OK;
130 :
131 : // This ShouldLoad function is called from nsCSPService::ShouldLoad,
132 : // which already checked a number of things, including:
133 : // * aContentLocation is not null; we can consume this without further checks
134 : // * scheme is not a whitelisted scheme (about: chrome:, etc).
135 : // * CSP is enabled
136 : // * Content Type is not whitelisted (CSP Reports, TYPE_DOCUMENT, etc).
137 : // * Fast Path for Apps
138 :
139 0 : nsAutoCString cacheKey;
140 0 : rv = CreateCacheKey_Internal(aContentLocation, aContentType, cacheKey);
141 0 : NS_ENSURE_SUCCESS(rv, rv);
142 :
143 0 : bool isCached = mShouldLoadCache.Get(cacheKey, outDecision);
144 0 : if (isCached && cacheKey.Length() > 0) {
145 : // this is cached, use the cached value.
146 0 : return NS_OK;
147 : }
148 :
149 : // Default decision, CSP can revise it if there's a policy to enforce
150 0 : *outDecision = nsIContentPolicy::ACCEPT;
151 :
152 : // If the content type doesn't map to a CSP directive, there's nothing for
153 : // CSP to do.
154 0 : CSPDirective dir = CSP_ContentTypeToDirective(aContentType);
155 0 : if (dir == nsIContentSecurityPolicy::NO_DIRECTIVE) {
156 0 : return NS_OK;
157 : }
158 :
159 0 : nsAutoString nonce;
160 0 : bool parserCreated = false;
161 0 : if (!isPreload) {
162 0 : if (aContentType == nsIContentPolicy::TYPE_SCRIPT ||
163 : aContentType == nsIContentPolicy::TYPE_STYLESHEET) {
164 0 : nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(aRequestContext);
165 0 : if (htmlElement) {
166 0 : rv = htmlElement->GetAttribute(NS_LITERAL_STRING("nonce"), nonce);
167 0 : NS_ENSURE_SUCCESS(rv, rv);
168 : }
169 : }
170 :
171 0 : nsCOMPtr<nsIScriptElement> script = do_QueryInterface(aRequestContext);
172 0 : if (script && script->GetParserCreated() != mozilla::dom::NOT_FROM_PARSER) {
173 0 : parserCreated = true;
174 : }
175 : }
176 :
177 : // aExtra holds the original URI of the channel if the
178 : // channel got redirected (until we fix Bug 1332422).
179 0 : nsCOMPtr<nsIURI> originalURI = do_QueryInterface(aExtra);
180 0 : bool wasRedirected = originalURI;
181 :
182 0 : bool permitted = permitsInternal(dir,
183 : aContentLocation,
184 : originalURI,
185 : nonce,
186 : wasRedirected,
187 : isPreload,
188 : false, // allow fallback to default-src
189 : true, // send violation reports
190 : true, // send blocked URI in violation reports
191 0 : parserCreated);
192 :
193 0 : *outDecision = permitted ? nsIContentPolicy::ACCEPT
194 0 : : nsIContentPolicy::REJECT_SERVER;
195 :
196 : // Done looping, cache any relevant result
197 0 : if (cacheKey.Length() > 0 && !isPreload) {
198 0 : mShouldLoadCache.Put(cacheKey, *outDecision);
199 : }
200 :
201 0 : if (CSPCONTEXTLOGENABLED()) {
202 0 : CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, decision: %s, "
203 : "aContentLocation: %s",
204 : *outDecision > 0 ? "load" : "deny",
205 : aContentLocation->GetSpecOrDefault().get()));
206 : }
207 0 : return NS_OK;
208 : }
209 :
210 : bool
211 0 : nsCSPContext::permitsInternal(CSPDirective aDir,
212 : nsIURI* aContentLocation,
213 : nsIURI* aOriginalURI,
214 : const nsAString& aNonce,
215 : bool aWasRedirected,
216 : bool aIsPreload,
217 : bool aSpecific,
218 : bool aSendViolationReports,
219 : bool aSendContentLocationInViolationReports,
220 : bool aParserCreated)
221 : {
222 0 : bool permits = true;
223 :
224 0 : nsAutoString violatedDirective;
225 0 : for (uint32_t p = 0; p < mPolicies.Length(); p++) {
226 :
227 : // According to the W3C CSP spec, frame-ancestors checks are ignored for
228 : // report-only policies (when "monitoring").
229 0 : if (aDir == nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE &&
230 0 : mPolicies[p]->getReportOnlyFlag()) {
231 0 : continue;
232 : }
233 :
234 0 : if (!mPolicies[p]->permits(aDir,
235 : aContentLocation,
236 : aNonce,
237 : aWasRedirected,
238 : aSpecific,
239 : aParserCreated,
240 : violatedDirective)) {
241 : // If the policy is violated and not report-only, reject the load and
242 : // report to the console
243 0 : if (!mPolicies[p]->getReportOnlyFlag()) {
244 0 : CSPCONTEXTLOG(("nsCSPContext::permitsInternal, false"));
245 0 : permits = false;
246 : }
247 :
248 : // Do not send a report or notify observers if this is a preload - the
249 : // decision may be wrong due to the inability to get the nonce, and will
250 : // incorrectly fail the unit tests.
251 0 : if (!aIsPreload && aSendViolationReports) {
252 0 : this->AsyncReportViolation((aSendContentLocationInViolationReports ?
253 : aContentLocation : nullptr),
254 : aOriginalURI, /* in case of redirect originalURI is not null */
255 : violatedDirective,
256 : p, /* policy index */
257 0 : EmptyString(), /* no observer subject */
258 0 : EmptyString(), /* no source file */
259 0 : EmptyString(), /* no script sample */
260 0 : 0); /* no line number */
261 : }
262 : }
263 : }
264 :
265 0 : return permits;
266 : }
267 :
268 :
269 :
270 : /* ===== nsISupports implementation ========== */
271 :
272 3 : NS_IMPL_CLASSINFO(nsCSPContext,
273 : nullptr,
274 : nsIClassInfo::MAIN_THREAD_ONLY,
275 : NS_CSPCONTEXT_CID)
276 :
277 0 : NS_IMPL_ISUPPORTS_CI(nsCSPContext,
278 : nsIContentSecurityPolicy,
279 : nsISerializable)
280 :
281 0 : nsCSPContext::nsCSPContext()
282 : : mInnerWindowID(0)
283 : , mLoadingContext(nullptr)
284 : , mLoadingPrincipal(nullptr)
285 0 : , mQueueUpMessages(true)
286 : {
287 0 : CSPCONTEXTLOG(("nsCSPContext::nsCSPContext"));
288 0 : }
289 :
290 0 : nsCSPContext::~nsCSPContext()
291 : {
292 0 : CSPCONTEXTLOG(("nsCSPContext::~nsCSPContext"));
293 0 : for (uint32_t i = 0; i < mPolicies.Length(); i++) {
294 0 : delete mPolicies[i];
295 : }
296 0 : mShouldLoadCache.Clear();
297 0 : }
298 :
299 : NS_IMETHODIMP
300 0 : nsCSPContext::GetPolicyString(uint32_t aIndex, nsAString& outStr)
301 : {
302 0 : if (aIndex >= mPolicies.Length()) {
303 0 : return NS_ERROR_ILLEGAL_VALUE;
304 : }
305 0 : mPolicies[aIndex]->toString(outStr);
306 0 : return NS_OK;
307 : }
308 :
309 : const nsCSPPolicy*
310 0 : nsCSPContext::GetPolicy(uint32_t aIndex)
311 : {
312 0 : if (aIndex >= mPolicies.Length()) {
313 0 : return nullptr;
314 : }
315 0 : return mPolicies[aIndex];
316 : }
317 :
318 : NS_IMETHODIMP
319 0 : nsCSPContext::GetPolicyCount(uint32_t *outPolicyCount)
320 : {
321 0 : *outPolicyCount = mPolicies.Length();
322 0 : return NS_OK;
323 : }
324 :
325 : NS_IMETHODIMP
326 0 : nsCSPContext::GetUpgradeInsecureRequests(bool *outUpgradeRequest)
327 : {
328 0 : *outUpgradeRequest = false;
329 0 : for (uint32_t i = 0; i < mPolicies.Length(); i++) {
330 0 : if (mPolicies[i]->hasDirective(nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE)) {
331 0 : *outUpgradeRequest = true;
332 0 : return NS_OK;
333 : }
334 : }
335 0 : return NS_OK;
336 : }
337 :
338 : NS_IMETHODIMP
339 0 : nsCSPContext::GetBlockAllMixedContent(bool *outBlockAllMixedContent)
340 : {
341 0 : *outBlockAllMixedContent = false;
342 0 : for (uint32_t i = 0; i < mPolicies.Length(); i++) {
343 0 : if (!mPolicies[i]->getReportOnlyFlag() &&
344 0 : mPolicies[i]->hasDirective(nsIContentSecurityPolicy::BLOCK_ALL_MIXED_CONTENT)) {
345 0 : *outBlockAllMixedContent = true;
346 0 : return NS_OK;
347 : }
348 : }
349 0 : return NS_OK;
350 : }
351 :
352 : NS_IMETHODIMP
353 0 : nsCSPContext::GetEnforcesFrameAncestors(bool *outEnforcesFrameAncestors)
354 : {
355 0 : *outEnforcesFrameAncestors = false;
356 0 : for (uint32_t i = 0; i < mPolicies.Length(); i++) {
357 0 : if (!mPolicies[i]->getReportOnlyFlag() &&
358 0 : mPolicies[i]->hasDirective(nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE)) {
359 0 : *outEnforcesFrameAncestors = true;
360 0 : return NS_OK;
361 : }
362 : }
363 0 : return NS_OK;
364 : }
365 :
366 : NS_IMETHODIMP
367 0 : nsCSPContext::GetReferrerPolicy(uint32_t* outPolicy, bool* outIsSet)
368 : {
369 0 : *outIsSet = false;
370 0 : *outPolicy = mozilla::net::RP_Unset;
371 0 : nsAutoString refpol;
372 0 : mozilla::net::ReferrerPolicy previousPolicy = mozilla::net::RP_Unset;
373 0 : for (uint32_t i = 0; i < mPolicies.Length(); i++) {
374 0 : mPolicies[i]->getReferrerPolicy(refpol);
375 : // only set the referrer policy if not delievered through a CSPRO and
376 : // note that and an empty string in refpol means it wasn't set
377 : // (that's the default in nsCSPPolicy).
378 0 : if (!mPolicies[i]->getReportOnlyFlag() && !refpol.IsEmpty()) {
379 : // Referrer Directive in CSP is no more used and going to be replaced by
380 : // Referrer-Policy HTTP header. But we still keep using referrer directive,
381 : // and would remove it later.
382 : // Referrer Directive specs is not fully compliant with new referrer policy
383 : // specs. What we are using here:
384 : // - If the value of the referrer directive is invalid, the user agent
385 : // should set the referrer policy to no-referrer.
386 : // - If there are two policies that specify a referrer policy, then they
387 : // must agree or the employed policy is no-referrer.
388 0 : if (!mozilla::net::IsValidReferrerPolicy(refpol)) {
389 0 : *outPolicy = mozilla::net::RP_No_Referrer;
390 0 : *outIsSet = true;
391 0 : return NS_OK;
392 : }
393 :
394 0 : uint32_t currentPolicy = mozilla::net::ReferrerPolicyFromString(refpol);
395 0 : if (*outIsSet && previousPolicy != currentPolicy) {
396 0 : *outPolicy = mozilla::net::RP_No_Referrer;
397 0 : return NS_OK;
398 : }
399 :
400 0 : *outPolicy = currentPolicy;
401 0 : *outIsSet = true;
402 : }
403 : }
404 :
405 0 : return NS_OK;
406 : }
407 :
408 : NS_IMETHODIMP
409 0 : nsCSPContext::AppendPolicy(const nsAString& aPolicyString,
410 : bool aReportOnly,
411 : bool aDeliveredViaMetaTag)
412 : {
413 0 : CSPCONTEXTLOG(("nsCSPContext::AppendPolicy: %s",
414 : NS_ConvertUTF16toUTF8(aPolicyString).get()));
415 :
416 : // Use the mSelfURI from setRequestContext, see bug 991474
417 0 : NS_ASSERTION(mSelfURI, "mSelfURI required for AppendPolicy, but not set");
418 0 : nsCSPPolicy* policy = nsCSPParser::parseContentSecurityPolicy(aPolicyString, mSelfURI,
419 : aReportOnly, this,
420 0 : aDeliveredViaMetaTag);
421 0 : if (policy) {
422 0 : mPolicies.AppendElement(policy);
423 : // reset cache since effective policy changes
424 0 : mShouldLoadCache.Clear();
425 : }
426 0 : return NS_OK;
427 : }
428 :
429 : NS_IMETHODIMP
430 0 : nsCSPContext::GetAllowsEval(bool* outShouldReportViolation,
431 : bool* outAllowsEval)
432 : {
433 0 : *outShouldReportViolation = false;
434 0 : *outAllowsEval = true;
435 :
436 0 : for (uint32_t i = 0; i < mPolicies.Length(); i++) {
437 0 : if (!mPolicies[i]->allows(nsIContentPolicy::TYPE_SCRIPT,
438 : CSP_UNSAFE_EVAL,
439 0 : EmptyString(),
440 : false)) {
441 : // policy is violated: must report the violation and allow the inline
442 : // script if the policy is report-only.
443 0 : *outShouldReportViolation = true;
444 0 : if (!mPolicies[i]->getReportOnlyFlag()) {
445 0 : *outAllowsEval = false;
446 : }
447 : }
448 : }
449 0 : return NS_OK;
450 : }
451 :
452 : // Helper function to report inline violations
453 : void
454 0 : nsCSPContext::reportInlineViolation(nsContentPolicyType aContentType,
455 : const nsAString& aNonce,
456 : const nsAString& aContent,
457 : const nsAString& aViolatedDirective,
458 : uint32_t aViolatedPolicyIndex, // TODO, use report only flag for that
459 : uint32_t aLineNumber)
460 : {
461 0 : nsString observerSubject;
462 : // if the nonce is non empty, then we report the nonce error, otherwise
463 : // let's report the hash error; no need to report the unsafe-inline error
464 : // anymore.
465 0 : if (!aNonce.IsEmpty()) {
466 : observerSubject = (aContentType == nsIContentPolicy::TYPE_SCRIPT)
467 0 : ? NS_LITERAL_STRING(SCRIPT_NONCE_VIOLATION_OBSERVER_TOPIC)
468 0 : : NS_LITERAL_STRING(STYLE_NONCE_VIOLATION_OBSERVER_TOPIC);
469 : }
470 : else {
471 : observerSubject = (aContentType == nsIContentPolicy::TYPE_SCRIPT)
472 0 : ? NS_LITERAL_STRING(SCRIPT_HASH_VIOLATION_OBSERVER_TOPIC)
473 0 : : NS_LITERAL_STRING(STYLE_HASH_VIOLATION_OBSERVER_TOPIC);
474 : }
475 :
476 0 : nsCOMPtr<nsISupportsCString> selfICString(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
477 0 : if (selfICString) {
478 0 : selfICString->SetData(nsDependentCString("self"));
479 : }
480 0 : nsCOMPtr<nsISupports> selfISupports(do_QueryInterface(selfICString));
481 :
482 : // use selfURI as the sourceFile
483 0 : nsAutoCString sourceFile;
484 0 : if (mSelfURI) {
485 0 : mSelfURI->GetSpec(sourceFile);
486 : }
487 :
488 0 : nsAutoString codeSample(aContent);
489 : // cap the length of the script sample at 40 chars
490 0 : if (codeSample.Length() > 40) {
491 0 : codeSample.Truncate(40);
492 0 : codeSample.AppendLiteral("...");
493 : }
494 0 : AsyncReportViolation(selfISupports, // aBlockedContentSource
495 : mSelfURI, // aOriginalURI
496 : aViolatedDirective, // aViolatedDirective
497 : aViolatedPolicyIndex, // aViolatedPolicyIndex
498 : observerSubject, // aObserverSubject
499 0 : NS_ConvertUTF8toUTF16(sourceFile), // aSourceFile
500 : codeSample, // aScriptSample
501 0 : aLineNumber); // aLineNum
502 0 : }
503 :
504 : NS_IMETHODIMP
505 0 : nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
506 : const nsAString& aNonce,
507 : bool aParserCreated,
508 : const nsAString& aContent,
509 : uint32_t aLineNumber,
510 : bool* outAllowsInline)
511 : {
512 0 : *outAllowsInline = true;
513 :
514 0 : MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType),
515 : "We should only see external content policy types here.");
516 :
517 0 : if (aContentType != nsIContentPolicy::TYPE_SCRIPT &&
518 : aContentType != nsIContentPolicy::TYPE_STYLESHEET) {
519 0 : MOZ_ASSERT(false, "can only allow inline for script or style");
520 : return NS_OK;
521 : }
522 :
523 : // always iterate all policies, otherwise we might not send out all reports
524 0 : for (uint32_t i = 0; i < mPolicies.Length(); i++) {
525 : bool allowed =
526 0 : mPolicies[i]->allows(aContentType, CSP_UNSAFE_INLINE, EmptyString(), aParserCreated) ||
527 0 : mPolicies[i]->allows(aContentType, CSP_NONCE, aNonce, aParserCreated) ||
528 0 : mPolicies[i]->allows(aContentType, CSP_HASH, aContent, aParserCreated);
529 :
530 0 : if (!allowed) {
531 : // policy is violoated: deny the load unless policy is report only and
532 : // report the violation.
533 0 : if (!mPolicies[i]->getReportOnlyFlag()) {
534 0 : *outAllowsInline = false;
535 : }
536 0 : nsAutoString violatedDirective;
537 0 : mPolicies[i]->getDirectiveStringForContentType(aContentType, violatedDirective);
538 : reportInlineViolation(aContentType,
539 : aNonce,
540 : aContent,
541 : violatedDirective,
542 : i,
543 0 : aLineNumber);
544 : }
545 : }
546 0 : return NS_OK;
547 : }
548 :
549 :
550 : /**
551 : * Reduces some code repetition for the various logging situations in
552 : * LogViolationDetails.
553 : *
554 : * Call-sites for the eval/inline checks recieve two return values: allows
555 : * and violates. Based on those, they must choose whether to call
556 : * LogViolationDetails or not. Policies that are report-only allow the
557 : * loads/compilations but violations should still be reported. Not all
558 : * policies in this nsIContentSecurityPolicy instance will be violated,
559 : * which is why we must check allows() again here.
560 : *
561 : * Note: This macro uses some parameters from its caller's context:
562 : * p, mPolicies, this, aSourceFile, aScriptSample, aLineNum, selfISupports
563 : *
564 : * @param violationType: the VIOLATION_TYPE_* constant (partial symbol)
565 : * such as INLINE_SCRIPT
566 : * @param contentPolicyType: a constant from nsIContentPolicy such as TYPE_STYLESHEET
567 : * @param nonceOrHash: for NONCE and HASH violations, it's the nonce or content
568 : * string. For other violations, it is an empty string.
569 : * @param keyword: the keyword corresponding to violation (UNSAFE_INLINE for most)
570 : * @param observerTopic: the observer topic string to send with the CSP
571 : * observer notifications.
572 : *
573 : * Please note that inline violations for scripts are reported within
574 : * GetAllowsInline() and do not call this macro, hence we can pass 'false'
575 : * as the argument _aParserCreated_ to allows().
576 : */
577 : #define CASE_CHECK_AND_REPORT(violationType, contentPolicyType, nonceOrHash, \
578 : keyword, observerTopic) \
579 : case nsIContentSecurityPolicy::VIOLATION_TYPE_ ## violationType : \
580 : PR_BEGIN_MACRO \
581 : if (!mPolicies[p]->allows(nsIContentPolicy::TYPE_ ## contentPolicyType, \
582 : keyword, nonceOrHash, false)) \
583 : { \
584 : nsAutoString violatedDirective; \
585 : mPolicies[p]->getDirectiveStringForContentType( \
586 : nsIContentPolicy::TYPE_ ## contentPolicyType, \
587 : violatedDirective); \
588 : this->AsyncReportViolation(selfISupports, nullptr, violatedDirective, p, \
589 : NS_LITERAL_STRING(observerTopic), \
590 : aSourceFile, aScriptSample, aLineNum); \
591 : } \
592 : PR_END_MACRO; \
593 : break
594 :
595 : /**
596 : * For each policy, log any violation on the Error Console and send a report
597 : * if a report-uri is present in the policy
598 : *
599 : * @param aViolationType
600 : * one of the VIOLATION_TYPE_* constants, e.g. inline-script or eval
601 : * @param aSourceFile
602 : * name of the source file containing the violation (if available)
603 : * @param aContentSample
604 : * sample of the violating content (to aid debugging)
605 : * @param aLineNum
606 : * source line number of the violation (if available)
607 : * @param aNonce
608 : * (optional) If this is a nonce violation, include the nonce so we can
609 : * recheck to determine which policies were violated and send the
610 : * appropriate reports.
611 : * @param aContent
612 : * (optional) If this is a hash violation, include contents of the inline
613 : * resource in the question so we can recheck the hash in order to
614 : * determine which policies were violated and send the appropriate
615 : * reports.
616 : */
617 : NS_IMETHODIMP
618 0 : nsCSPContext::LogViolationDetails(uint16_t aViolationType,
619 : const nsAString& aSourceFile,
620 : const nsAString& aScriptSample,
621 : int32_t aLineNum,
622 : const nsAString& aNonce,
623 : const nsAString& aContent)
624 : {
625 0 : for (uint32_t p = 0; p < mPolicies.Length(); p++) {
626 0 : NS_ASSERTION(mPolicies[p], "null pointer in nsTArray<nsCSPPolicy>");
627 :
628 0 : nsCOMPtr<nsISupportsCString> selfICString(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
629 0 : if (selfICString) {
630 0 : selfICString->SetData(nsDependentCString("self"));
631 : }
632 0 : nsCOMPtr<nsISupports> selfISupports(do_QueryInterface(selfICString));
633 :
634 0 : switch (aViolationType) {
635 0 : CASE_CHECK_AND_REPORT(EVAL, SCRIPT, NS_LITERAL_STRING(""),
636 : CSP_UNSAFE_EVAL, EVAL_VIOLATION_OBSERVER_TOPIC);
637 0 : CASE_CHECK_AND_REPORT(INLINE_STYLE, STYLESHEET, NS_LITERAL_STRING(""),
638 : CSP_UNSAFE_INLINE, INLINE_STYLE_VIOLATION_OBSERVER_TOPIC);
639 0 : CASE_CHECK_AND_REPORT(INLINE_SCRIPT, SCRIPT, NS_LITERAL_STRING(""),
640 : CSP_UNSAFE_INLINE, INLINE_SCRIPT_VIOLATION_OBSERVER_TOPIC);
641 0 : CASE_CHECK_AND_REPORT(NONCE_SCRIPT, SCRIPT, aNonce,
642 : CSP_UNSAFE_INLINE, SCRIPT_NONCE_VIOLATION_OBSERVER_TOPIC);
643 0 : CASE_CHECK_AND_REPORT(NONCE_STYLE, STYLESHEET, aNonce,
644 : CSP_UNSAFE_INLINE, STYLE_NONCE_VIOLATION_OBSERVER_TOPIC);
645 0 : CASE_CHECK_AND_REPORT(HASH_SCRIPT, SCRIPT, aContent,
646 : CSP_UNSAFE_INLINE, SCRIPT_HASH_VIOLATION_OBSERVER_TOPIC);
647 0 : CASE_CHECK_AND_REPORT(HASH_STYLE, STYLESHEET, aContent,
648 : CSP_UNSAFE_INLINE, STYLE_HASH_VIOLATION_OBSERVER_TOPIC);
649 0 : CASE_CHECK_AND_REPORT(REQUIRE_SRI_FOR_STYLE, STYLESHEET, NS_LITERAL_STRING(""),
650 : CSP_REQUIRE_SRI_FOR, REQUIRE_SRI_STYLE_VIOLATION_OBSERVER_TOPIC);
651 0 : CASE_CHECK_AND_REPORT(REQUIRE_SRI_FOR_SCRIPT, SCRIPT, NS_LITERAL_STRING(""),
652 : CSP_REQUIRE_SRI_FOR, REQUIRE_SRI_SCRIPT_VIOLATION_OBSERVER_TOPIC);
653 :
654 :
655 : default:
656 0 : NS_ASSERTION(false, "LogViolationDetails with invalid type");
657 0 : break;
658 : }
659 : }
660 0 : return NS_OK;
661 : }
662 :
663 : #undef CASE_CHECK_AND_REPORT
664 :
665 : NS_IMETHODIMP
666 0 : nsCSPContext::SetRequestContext(nsIDOMDocument* aDOMDocument,
667 : nsIPrincipal* aPrincipal)
668 : {
669 0 : NS_PRECONDITION(aDOMDocument || aPrincipal,
670 : "Can't set context without doc or principal");
671 0 : NS_ENSURE_ARG(aDOMDocument || aPrincipal);
672 :
673 0 : if (aDOMDocument) {
674 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDOMDocument);
675 0 : mLoadingContext = do_GetWeakReference(doc);
676 0 : mSelfURI = doc->GetDocumentURI();
677 0 : mLoadingPrincipal = doc->NodePrincipal();
678 0 : doc->GetReferrer(mReferrer);
679 0 : mInnerWindowID = doc->InnerWindowID();
680 : // the innerWindowID is not available for CSPs delivered through the
681 : // header at the time setReqeustContext is called - let's queue up
682 : // console messages until it becomes available, see flushConsoleMessages
683 0 : mQueueUpMessages = !mInnerWindowID;
684 0 : mCallingChannelLoadGroup = doc->GetDocumentLoadGroup();
685 :
686 : // set the flag on the document for CSP telemetry
687 0 : doc->SetHasCSP(true);
688 0 : mEventTarget = doc->EventTargetFor(TaskCategory::Other);
689 : }
690 : else {
691 0 : CSPCONTEXTLOG(("No Document in SetRequestContext; can not query loadgroup; sending reports may fail."));
692 0 : mLoadingPrincipal = aPrincipal;
693 0 : mLoadingPrincipal->GetURI(getter_AddRefs(mSelfURI));
694 : // if no document is available, then it also does not make sense to queue console messages
695 : // sending messages to the browser conolse instead of the web console in that case.
696 0 : mQueueUpMessages = false;
697 : }
698 :
699 0 : NS_ASSERTION(mSelfURI, "mSelfURI not available, can not translate 'self' into actual URI");
700 0 : return NS_OK;
701 : }
702 :
703 : NS_IMETHODIMP
704 0 : nsCSPContext::EnsureEventTarget(nsIEventTarget* aEventTarget)
705 : {
706 0 : NS_ENSURE_ARG(aEventTarget);
707 : // Don't bother if we did have a valid event target (if the csp object is
708 : // tied to a document in SetRequestContext)
709 0 : if (mEventTarget) {
710 0 : return NS_OK;
711 : }
712 :
713 0 : mEventTarget = aEventTarget;
714 0 : return NS_OK;
715 : }
716 :
717 0 : struct ConsoleMsgQueueElem {
718 : nsXPIDLString mMsg;
719 : nsString mSourceName;
720 : nsString mSourceLine;
721 : uint32_t mLineNumber;
722 : uint32_t mColumnNumber;
723 : uint32_t mSeverityFlag;
724 : };
725 :
726 : void
727 0 : nsCSPContext::flushConsoleMessages()
728 : {
729 : // should flush messages even if doc is not available
730 0 : nsCOMPtr<nsIDocument> doc = do_QueryReferent(mLoadingContext);
731 0 : if (doc) {
732 0 : mInnerWindowID = doc->InnerWindowID();
733 : }
734 0 : mQueueUpMessages = false;
735 :
736 0 : for (uint32_t i = 0; i < mConsoleMsgQueue.Length(); i++) {
737 0 : ConsoleMsgQueueElem &elem = mConsoleMsgQueue[i];
738 0 : CSP_LogMessage(elem.mMsg, elem.mSourceName, elem.mSourceLine,
739 : elem.mLineNumber, elem.mColumnNumber,
740 0 : elem.mSeverityFlag, "CSP", mInnerWindowID);
741 : }
742 0 : mConsoleMsgQueue.Clear();
743 0 : }
744 :
745 : void
746 0 : nsCSPContext::logToConsole(const char16_t* aName,
747 : const char16_t** aParams,
748 : uint32_t aParamsLength,
749 : const nsAString& aSourceName,
750 : const nsAString& aSourceLine,
751 : uint32_t aLineNumber,
752 : uint32_t aColumnNumber,
753 : uint32_t aSeverityFlag)
754 : {
755 : // let's check if we have to queue up console messages
756 0 : if (mQueueUpMessages) {
757 0 : nsXPIDLString msg;
758 0 : CSP_GetLocalizedStr(aName, aParams, aParamsLength, getter_Copies(msg));
759 0 : ConsoleMsgQueueElem &elem = *mConsoleMsgQueue.AppendElement();
760 0 : elem.mMsg = msg;
761 0 : elem.mSourceName = PromiseFlatString(aSourceName);
762 0 : elem.mSourceLine = PromiseFlatString(aSourceLine);
763 0 : elem.mLineNumber = aLineNumber;
764 0 : elem.mColumnNumber = aColumnNumber;
765 0 : elem.mSeverityFlag = aSeverityFlag;
766 0 : return;
767 : }
768 0 : CSP_LogLocalizedStr(aName, aParams, aParamsLength, aSourceName,
769 : aSourceLine, aLineNumber, aColumnNumber,
770 0 : aSeverityFlag, "CSP", mInnerWindowID);
771 : }
772 :
773 : /**
774 : * Strip URI for reporting according to:
775 : * http://www.w3.org/TR/CSP/#violation-reports
776 : *
777 : * @param aURI
778 : * The uri to be stripped for reporting
779 : * @param aSelfURI
780 : * The uri of the protected resource
781 : * which is needed to enforce the SOP.
782 : * @return ASCII serialization of the uri to be reported.
783 : */
784 : void
785 0 : StripURIForReporting(nsIURI* aURI,
786 : nsIURI* aSelfURI,
787 : nsACString& outStrippedURI)
788 : {
789 : // 1) If the origin of uri is a globally unique identifier (for example,
790 : // aURI has a scheme of data, blob, or filesystem), then return the
791 : // ASCII serialization of uri’s scheme.
792 : bool isHttpOrFtp =
793 0 : (NS_SUCCEEDED(aURI->SchemeIs("http", &isHttpOrFtp)) && isHttpOrFtp) ||
794 0 : (NS_SUCCEEDED(aURI->SchemeIs("https", &isHttpOrFtp)) && isHttpOrFtp) ||
795 0 : (NS_SUCCEEDED(aURI->SchemeIs("ftp", &isHttpOrFtp)) && isHttpOrFtp);
796 :
797 0 : if (!isHttpOrFtp) {
798 : // not strictly spec compliant, but what we really care about is
799 : // http/https and also ftp. If it's not http/https or ftp, then treat aURI
800 : // as if it's a globally unique identifier and just return the scheme.
801 0 : aURI->GetScheme(outStrippedURI);
802 0 : return;
803 : }
804 :
805 : // 2) If the origin of uri is not the same as the origin of the protected
806 : // resource, then return the ASCII serialization of uri’s origin.
807 0 : if (!NS_SecurityCompareURIs(aSelfURI, aURI, false)) {
808 : // cross origin redirects also fall into this category, see:
809 : // http://www.w3.org/TR/CSP/#violation-reports
810 0 : aURI->GetPrePath(outStrippedURI);
811 0 : return;
812 : }
813 :
814 : // 3) Return uri, with any fragment component removed.
815 0 : aURI->GetSpecIgnoringRef(outStrippedURI);
816 : }
817 :
818 : /**
819 : * Sends CSP violation reports to all sources listed under report-uri.
820 : *
821 : * @param aBlockedContentSource
822 : * Either a CSP Source (like 'self', as string) or nsIURI: the source
823 : * of the violation.
824 : * @param aOriginalUri
825 : * The original URI if the blocked content is a redirect, else null
826 : * @param aViolatedDirective
827 : * the directive that was violated (string).
828 : * @param aSourceFile
829 : * name of the file containing the inline script violation
830 : * @param aScriptSample
831 : * a sample of the violating inline script
832 : * @param aLineNum
833 : * source line number of the violation (if available)
834 : */
835 : nsresult
836 0 : nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
837 : nsIURI* aOriginalURI,
838 : nsAString& aViolatedDirective,
839 : uint32_t aViolatedPolicyIndex,
840 : nsAString& aSourceFile,
841 : nsAString& aScriptSample,
842 : uint32_t aLineNum)
843 : {
844 0 : NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
845 :
846 : #ifdef MOZ_B2G
847 : // load group information (on process-split necko implementations like b2g).
848 : // (fix this in bug 1011086)
849 : if (!mCallingChannelLoadGroup) {
850 : NS_WARNING("Load group required but not present for report sending; cannot send CSP violation reports");
851 : return NS_ERROR_FAILURE;
852 : }
853 : #endif
854 :
855 0 : dom::CSPReport report;
856 : nsresult rv;
857 :
858 : // blocked-uri
859 0 : if (aBlockedContentSource) {
860 0 : nsAutoCString reportBlockedURI;
861 0 : nsCOMPtr<nsIURI> uri = do_QueryInterface(aBlockedContentSource);
862 : // could be a string or URI
863 0 : if (uri) {
864 0 : StripURIForReporting(uri, mSelfURI, reportBlockedURI);
865 : } else {
866 0 : nsCOMPtr<nsISupportsCString> cstr = do_QueryInterface(aBlockedContentSource);
867 0 : if (cstr) {
868 0 : cstr->GetData(reportBlockedURI);
869 : }
870 : }
871 0 : if (reportBlockedURI.IsEmpty()) {
872 : // this can happen for frame-ancestors violation where the violating
873 : // ancestor is cross-origin.
874 0 : NS_WARNING("No blocked URI (null aBlockedContentSource) for CSP violation report.");
875 : }
876 0 : report.mCsp_report.mBlocked_uri = NS_ConvertUTF8toUTF16(reportBlockedURI);
877 : }
878 :
879 : // document-uri
880 0 : nsAutoCString reportDocumentURI;
881 0 : StripURIForReporting(mSelfURI, mSelfURI, reportDocumentURI);
882 0 : report.mCsp_report.mDocument_uri = NS_ConvertUTF8toUTF16(reportDocumentURI);
883 :
884 : // original-policy
885 0 : nsAutoString originalPolicy;
886 0 : rv = this->GetPolicyString(aViolatedPolicyIndex, originalPolicy);
887 0 : NS_ENSURE_SUCCESS(rv, rv);
888 0 : report.mCsp_report.mOriginal_policy = originalPolicy;
889 :
890 : // referrer
891 0 : if (!mReferrer.IsEmpty()) {
892 0 : report.mCsp_report.mReferrer = mReferrer;
893 : }
894 :
895 : // violated-directive
896 0 : report.mCsp_report.mViolated_directive = aViolatedDirective;
897 :
898 : // source-file
899 0 : if (!aSourceFile.IsEmpty()) {
900 : // if aSourceFile is a URI, we have to make sure to strip fragments
901 0 : nsCOMPtr<nsIURI> sourceURI;
902 0 : NS_NewURI(getter_AddRefs(sourceURI), aSourceFile);
903 0 : if (sourceURI) {
904 0 : nsAutoCString spec;
905 0 : sourceURI->GetSpecIgnoringRef(spec);
906 0 : aSourceFile = NS_ConvertUTF8toUTF16(spec);
907 : }
908 0 : report.mCsp_report.mSource_file.Construct();
909 0 : report.mCsp_report.mSource_file.Value() = aSourceFile;
910 : }
911 :
912 : // script-sample
913 0 : if (!aScriptSample.IsEmpty()) {
914 0 : report.mCsp_report.mScript_sample.Construct();
915 0 : report.mCsp_report.mScript_sample.Value() = aScriptSample;
916 : }
917 :
918 : // line-number
919 0 : if (aLineNum != 0) {
920 0 : report.mCsp_report.mLine_number.Construct();
921 0 : report.mCsp_report.mLine_number.Value() = aLineNum;
922 : }
923 :
924 0 : nsString csp_report;
925 0 : if (!report.ToJSON(csp_report)) {
926 0 : return NS_ERROR_FAILURE;
927 : }
928 :
929 : // ---------- Assembled, now send it to all the report URIs ----------- //
930 :
931 0 : nsTArray<nsString> reportURIs;
932 0 : mPolicies[aViolatedPolicyIndex]->getReportURIs(reportURIs);
933 :
934 :
935 0 : nsCOMPtr<nsIDocument> doc = do_QueryReferent(mLoadingContext);
936 0 : nsCOMPtr<nsIURI> reportURI;
937 0 : nsCOMPtr<nsIChannel> reportChannel;
938 :
939 0 : for (uint32_t r = 0; r < reportURIs.Length(); r++) {
940 0 : nsAutoCString reportURICstring = NS_ConvertUTF16toUTF8(reportURIs[r]);
941 : // try to create a new uri from every report-uri string
942 0 : rv = NS_NewURI(getter_AddRefs(reportURI), reportURIs[r]);
943 0 : if (NS_FAILED(rv)) {
944 0 : const char16_t* params[] = { reportURIs[r].get() };
945 0 : CSPCONTEXTLOG(("Could not create nsIURI for report URI %s",
946 : reportURICstring.get()));
947 0 : logToConsole(u"triedToSendReport", params, ArrayLength(params),
948 0 : aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag);
949 0 : continue; // don't return yet, there may be more URIs
950 : }
951 :
952 : // try to create a new channel for every report-uri
953 0 : nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI;
954 0 : if (doc) {
955 0 : rv = NS_NewChannel(getter_AddRefs(reportChannel),
956 : reportURI,
957 : doc,
958 : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
959 : nsIContentPolicy::TYPE_CSP_REPORT,
960 : nullptr, // aLoadGroup
961 : nullptr, // aCallbacks
962 0 : loadFlags);
963 : }
964 : else {
965 0 : rv = NS_NewChannel(getter_AddRefs(reportChannel),
966 : reportURI,
967 : mLoadingPrincipal,
968 : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
969 : nsIContentPolicy::TYPE_CSP_REPORT,
970 : nullptr, // aLoadGroup
971 : nullptr, // aCallbacks
972 0 : loadFlags);
973 : }
974 :
975 0 : if (NS_FAILED(rv)) {
976 0 : CSPCONTEXTLOG(("Could not create new channel for report URI %s",
977 : reportURICstring.get()));
978 0 : continue; // don't return yet, there may be more URIs
979 : }
980 :
981 : // log a warning to console if scheme is not http or https
982 : bool isHttpScheme =
983 0 : (NS_SUCCEEDED(reportURI->SchemeIs("http", &isHttpScheme)) && isHttpScheme) ||
984 0 : (NS_SUCCEEDED(reportURI->SchemeIs("https", &isHttpScheme)) && isHttpScheme);
985 :
986 0 : if (!isHttpScheme) {
987 0 : const char16_t* params[] = { reportURIs[r].get() };
988 0 : logToConsole(u"reportURInotHttpsOrHttp2", params, ArrayLength(params),
989 0 : aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag);
990 0 : continue;
991 : }
992 :
993 : // make sure this is an anonymous request (no cookies) so in case the
994 : // policy URI is injected, it can't be abused for CSRF.
995 : nsLoadFlags flags;
996 0 : rv = reportChannel->GetLoadFlags(&flags);
997 0 : NS_ENSURE_SUCCESS(rv, rv);
998 0 : flags |= nsIRequest::LOAD_ANONYMOUS;
999 0 : rv = reportChannel->SetLoadFlags(flags);
1000 0 : NS_ENSURE_SUCCESS(rv, rv);
1001 :
1002 : // we need to set an nsIChannelEventSink on the channel object
1003 : // so we can tell it to not follow redirects when posting the reports
1004 0 : RefPtr<CSPReportRedirectSink> reportSink = new CSPReportRedirectSink();
1005 0 : if (doc && doc->GetDocShell()) {
1006 : nsCOMPtr<nsINetworkInterceptController> interceptController =
1007 0 : do_QueryInterface(doc->GetDocShell());
1008 0 : reportSink->SetInterceptController(interceptController);
1009 : }
1010 0 : reportChannel->SetNotificationCallbacks(reportSink);
1011 :
1012 : // apply the loadgroup from the channel taken by setRequestContext. If
1013 : // there's no loadgroup, AsyncOpen will fail on process-split necko (since
1014 : // the channel cannot query the iTabChild).
1015 0 : rv = reportChannel->SetLoadGroup(mCallingChannelLoadGroup);
1016 0 : NS_ENSURE_SUCCESS(rv, rv);
1017 :
1018 : // wire in the string input stream to send the report
1019 0 : nsCOMPtr<nsIStringInputStream> sis(do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID));
1020 0 : NS_ASSERTION(sis, "nsIStringInputStream is needed but not available to send CSP violation reports");
1021 0 : nsAutoCString utf8CSPReport = NS_ConvertUTF16toUTF8(csp_report);
1022 0 : rv = sis->SetData(utf8CSPReport.get(), utf8CSPReport.Length());
1023 0 : NS_ENSURE_SUCCESS(rv, rv);
1024 :
1025 0 : nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(reportChannel));
1026 0 : if (!uploadChannel) {
1027 : // It's possible the URI provided can't be uploaded to, in which case
1028 : // we skip this one. We'll already have warned about a non-HTTP URI earlier.
1029 0 : continue;
1030 : }
1031 :
1032 0 : rv = uploadChannel->SetUploadStream(sis, NS_LITERAL_CSTRING("application/csp-report"), -1);
1033 0 : NS_ENSURE_SUCCESS(rv, rv);
1034 :
1035 : // if this is an HTTP channel, set the request method to post
1036 0 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(reportChannel));
1037 0 : if (httpChannel) {
1038 0 : rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
1039 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
1040 : }
1041 :
1042 0 : RefPtr<CSPViolationReportListener> listener = new CSPViolationReportListener();
1043 0 : rv = reportChannel->AsyncOpen2(listener);
1044 :
1045 : // AsyncOpen should not fail, but could if there's no load group (like if
1046 : // SetRequestContext is not given a channel). This should fail quietly and
1047 : // not return an error since it's really ok if reports don't go out, but
1048 : // it's good to log the error locally.
1049 :
1050 0 : if (NS_FAILED(rv)) {
1051 0 : const char16_t* params[] = { reportURIs[r].get() };
1052 0 : CSPCONTEXTLOG(("AsyncOpen failed for report URI %s", NS_ConvertUTF16toUTF8(params[0]).get()));
1053 0 : logToConsole(u"triedToSendReport", params, ArrayLength(params),
1054 0 : aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag);
1055 : } else {
1056 0 : CSPCONTEXTLOG(("Sent violation report to URI %s", reportURICstring.get()));
1057 : }
1058 : }
1059 0 : return NS_OK;
1060 : }
1061 :
1062 : /**
1063 : * Dispatched from the main thread to send reports for one CSP violation.
1064 : */
1065 0 : class CSPReportSenderRunnable final : public Runnable
1066 : {
1067 : public:
1068 0 : CSPReportSenderRunnable(nsISupports* aBlockedContentSource,
1069 : nsIURI* aOriginalURI,
1070 : uint32_t aViolatedPolicyIndex,
1071 : bool aReportOnlyFlag,
1072 : const nsAString& aViolatedDirective,
1073 : const nsAString& aObserverSubject,
1074 : const nsAString& aSourceFile,
1075 : const nsAString& aScriptSample,
1076 : uint32_t aLineNum,
1077 : nsCSPContext* aCSPContext)
1078 0 : : mozilla::Runnable("CSPReportSenderRunnable")
1079 : , mBlockedContentSource(aBlockedContentSource)
1080 : , mOriginalURI(aOriginalURI)
1081 : , mViolatedPolicyIndex(aViolatedPolicyIndex)
1082 : , mReportOnlyFlag(aReportOnlyFlag)
1083 : , mViolatedDirective(aViolatedDirective)
1084 : , mSourceFile(aSourceFile)
1085 : , mScriptSample(aScriptSample)
1086 : , mLineNum(aLineNum)
1087 0 : , mCSPContext(aCSPContext)
1088 : {
1089 0 : NS_ASSERTION(!aViolatedDirective.IsEmpty(), "Can not send reports without a violated directive");
1090 : // the observer subject is an nsISupports: either an nsISupportsCString
1091 : // from the arg passed in directly, or if that's empty, it's the blocked
1092 : // source.
1093 0 : if (aObserverSubject.IsEmpty()) {
1094 0 : mObserverSubject = aBlockedContentSource;
1095 : } else {
1096 : nsCOMPtr<nsISupportsCString> supportscstr =
1097 0 : do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
1098 0 : NS_ASSERTION(supportscstr, "Couldn't allocate nsISupportsCString");
1099 0 : supportscstr->SetData(NS_ConvertUTF16toUTF8(aObserverSubject));
1100 0 : mObserverSubject = do_QueryInterface(supportscstr);
1101 : }
1102 0 : }
1103 :
1104 0 : NS_IMETHOD Run() override
1105 : {
1106 0 : MOZ_ASSERT(NS_IsMainThread());
1107 :
1108 : // 1) notify observers
1109 0 : nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
1110 0 : NS_ASSERTION(observerService, "needs observer service");
1111 0 : nsresult rv = observerService->NotifyObservers(mObserverSubject,
1112 : CSP_VIOLATION_TOPIC,
1113 0 : mViolatedDirective.get());
1114 0 : NS_ENSURE_SUCCESS(rv, rv);
1115 :
1116 : // 2) send reports for the policy that was violated
1117 0 : mCSPContext->SendReports(mBlockedContentSource, mOriginalURI,
1118 : mViolatedDirective, mViolatedPolicyIndex,
1119 0 : mSourceFile, mScriptSample, mLineNum);
1120 :
1121 : // 3) log to console (one per policy violation)
1122 : // mBlockedContentSource could be a URI or a string.
1123 0 : nsCOMPtr<nsIURI> blockedURI = do_QueryInterface(mBlockedContentSource);
1124 : // if mBlockedContentSource is not a URI, it could be a string
1125 0 : nsCOMPtr<nsISupportsCString> blockedString = do_QueryInterface(mBlockedContentSource);
1126 :
1127 0 : nsCString blockedDataStr;
1128 :
1129 0 : if (blockedURI) {
1130 0 : blockedURI->GetSpec(blockedDataStr);
1131 0 : bool isData = false;
1132 0 : rv = blockedURI->SchemeIs("data", &isData);
1133 0 : if (NS_SUCCEEDED(rv) && isData) {
1134 0 : blockedDataStr.Truncate(40);
1135 0 : blockedDataStr.AppendASCII("...");
1136 : }
1137 0 : } else if (blockedString) {
1138 0 : blockedString->GetData(blockedDataStr);
1139 : }
1140 :
1141 0 : if (blockedDataStr.Length() > 0) {
1142 0 : nsString blockedDataChar16 = NS_ConvertUTF8toUTF16(blockedDataStr);
1143 0 : const char16_t* params[] = { mViolatedDirective.get(),
1144 0 : blockedDataChar16.get() };
1145 0 : mCSPContext->logToConsole(mReportOnlyFlag ? u"CSPROViolationWithURI" :
1146 : u"CSPViolationWithURI",
1147 0 : params, ArrayLength(params), mSourceFile, mScriptSample,
1148 0 : mLineNum, 0, nsIScriptError::errorFlag);
1149 : }
1150 0 : return NS_OK;
1151 : }
1152 :
1153 : private:
1154 : nsCOMPtr<nsISupports> mBlockedContentSource;
1155 : nsCOMPtr<nsIURI> mOriginalURI;
1156 : uint32_t mViolatedPolicyIndex;
1157 : bool mReportOnlyFlag;
1158 : nsString mViolatedDirective;
1159 : nsCOMPtr<nsISupports> mObserverSubject;
1160 : nsString mSourceFile;
1161 : nsString mScriptSample;
1162 : uint32_t mLineNum;
1163 : RefPtr<nsCSPContext> mCSPContext;
1164 : };
1165 :
1166 : /**
1167 : * Asynchronously notifies any nsIObservers listening to the CSP violation
1168 : * topic that a violation occurred. Also triggers report sending and console
1169 : * logging. All asynchronous on the main thread.
1170 : *
1171 : * @param aBlockedContentSource
1172 : * Either a CSP Source (like 'self', as string) or nsIURI: the source
1173 : * of the violation.
1174 : * @param aOriginalUri
1175 : * The original URI if the blocked content is a redirect, else null
1176 : * @param aViolatedDirective
1177 : * the directive that was violated (string).
1178 : * @param aViolatedPolicyIndex
1179 : * the index of the policy that was violated (so we know where to send
1180 : * the reports).
1181 : * @param aObserverSubject
1182 : * optional, subject sent to the nsIObservers listening to the CSP
1183 : * violation topic.
1184 : * @param aSourceFile
1185 : * name of the file containing the inline script violation
1186 : * @param aScriptSample
1187 : * a sample of the violating inline script
1188 : * @param aLineNum
1189 : * source line number of the violation (if available)
1190 : */
1191 : nsresult
1192 0 : nsCSPContext::AsyncReportViolation(nsISupports* aBlockedContentSource,
1193 : nsIURI* aOriginalURI,
1194 : const nsAString& aViolatedDirective,
1195 : uint32_t aViolatedPolicyIndex,
1196 : const nsAString& aObserverSubject,
1197 : const nsAString& aSourceFile,
1198 : const nsAString& aScriptSample,
1199 : uint32_t aLineNum)
1200 : {
1201 0 : NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
1202 :
1203 : nsCOMPtr<nsIRunnable> task =
1204 : new CSPReportSenderRunnable(aBlockedContentSource,
1205 : aOriginalURI,
1206 : aViolatedPolicyIndex,
1207 0 : mPolicies[aViolatedPolicyIndex]->getReportOnlyFlag(),
1208 : aViolatedDirective,
1209 : aObserverSubject,
1210 : aSourceFile,
1211 : aScriptSample,
1212 : aLineNum,
1213 0 : this);
1214 :
1215 0 : if (XRE_IsContentProcess()) {
1216 0 : if (mEventTarget) {
1217 0 : if (nsCOMPtr<nsINamed> named = do_QueryInterface(task)) {
1218 0 : named->SetName("CSPReportSenderRunnable");
1219 : }
1220 0 : mEventTarget->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
1221 0 : return NS_OK;
1222 : }
1223 : }
1224 :
1225 0 : NS_DispatchToMainThread(task.forget());
1226 0 : return NS_OK;
1227 : }
1228 :
1229 : NS_IMETHODIMP
1230 0 : nsCSPContext::RequireSRIForType(nsContentPolicyType aContentType, bool* outRequiresSRIForType)
1231 : {
1232 0 : *outRequiresSRIForType = false;
1233 0 : for (uint32_t i = 0; i < mPolicies.Length(); i++) {
1234 0 : if (mPolicies[i]->hasDirective(REQUIRE_SRI_FOR)) {
1235 0 : if (mPolicies[i]->requireSRIForType(aContentType)) {
1236 0 : *outRequiresSRIForType = true;
1237 0 : return NS_OK;
1238 : }
1239 : }
1240 : }
1241 0 : return NS_OK;
1242 : }
1243 :
1244 : /**
1245 : * Based on the given docshell, determines if this CSP context allows the
1246 : * ancestry.
1247 : *
1248 : * In order to determine the URI of the parent document (one causing the load
1249 : * of this protected document), this function obtains the docShellTreeItem,
1250 : * then walks up the hierarchy until it finds a privileged (chrome) tree item.
1251 : * Getting the a tree item's URI looks like this in pseudocode:
1252 : *
1253 : * nsIDocShellTreeItem->GetDocument()->GetDocumentURI();
1254 : *
1255 : * aDocShell is the docShell for the protected document.
1256 : */
1257 : NS_IMETHODIMP
1258 0 : nsCSPContext::PermitsAncestry(nsIDocShell* aDocShell, bool* outPermitsAncestry)
1259 : {
1260 : nsresult rv;
1261 :
1262 : // Can't check ancestry without a docShell.
1263 0 : if (aDocShell == nullptr) {
1264 0 : return NS_ERROR_FAILURE;
1265 : }
1266 :
1267 0 : *outPermitsAncestry = true;
1268 :
1269 : // extract the ancestry as an array
1270 0 : nsCOMArray<nsIURI> ancestorsArray;
1271 :
1272 0 : nsCOMPtr<nsIInterfaceRequestor> ir(do_QueryInterface(aDocShell));
1273 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem(do_GetInterface(ir));
1274 0 : nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
1275 0 : nsCOMPtr<nsIURI> currentURI;
1276 0 : nsCOMPtr<nsIURI> uriClone;
1277 :
1278 : // iterate through each docShell parent item
1279 0 : while (NS_SUCCEEDED(treeItem->GetParent(getter_AddRefs(parentTreeItem))) &&
1280 0 : parentTreeItem != nullptr) {
1281 : // stop when reaching chrome
1282 0 : if (parentTreeItem->ItemType() == nsIDocShellTreeItem::typeChrome) {
1283 0 : break;
1284 : }
1285 :
1286 0 : nsIDocument* doc = parentTreeItem->GetDocument();
1287 0 : NS_ASSERTION(doc, "Could not get nsIDocument from nsIDocShellTreeItem in nsCSPContext::PermitsAncestry");
1288 0 : NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
1289 :
1290 0 : currentURI = doc->GetDocumentURI();
1291 :
1292 0 : if (currentURI) {
1293 : // delete the userpass from the URI.
1294 0 : rv = currentURI->CloneIgnoringRef(getter_AddRefs(uriClone));
1295 0 : NS_ENSURE_SUCCESS(rv, rv);
1296 :
1297 : // We don't care if this succeeds, just want to delete a userpass if
1298 : // there was one.
1299 0 : uriClone->SetUserPass(EmptyCString());
1300 :
1301 0 : if (CSPCONTEXTLOGENABLED()) {
1302 0 : CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, found ancestor: %s",
1303 : uriClone->GetSpecOrDefault().get()));
1304 : }
1305 0 : ancestorsArray.AppendElement(uriClone);
1306 : }
1307 :
1308 : // next ancestor
1309 0 : treeItem = parentTreeItem;
1310 : }
1311 :
1312 0 : nsAutoString violatedDirective;
1313 :
1314 : // Now that we've got the ancestry chain in ancestorsArray, time to check
1315 : // them against any CSP.
1316 : // NOTE: the ancestors are not allowed to be sent cross origin; this is a
1317 : // restriction not placed on subresource loads.
1318 :
1319 0 : for (uint32_t a = 0; a < ancestorsArray.Length(); a++) {
1320 0 : if (CSPCONTEXTLOGENABLED()) {
1321 0 : CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, checking ancestor: %s",
1322 : ancestorsArray[a]->GetSpecOrDefault().get()));
1323 : }
1324 : // omit the ancestor URI in violation reports if cross-origin as per spec
1325 : // (it is a violation of the same-origin policy).
1326 0 : bool okToSendAncestor = NS_SecurityCompareURIs(ancestorsArray[a], mSelfURI, true);
1327 :
1328 :
1329 0 : bool permits = permitsInternal(nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE,
1330 : ancestorsArray[a],
1331 : nullptr, // no redirect here.
1332 0 : EmptyString(), // no nonce
1333 : false, // no redirect here.
1334 : false, // not a preload.
1335 : true, // specific, do not use default-src
1336 : true, // send violation reports
1337 : okToSendAncestor,
1338 0 : false); // not parser created
1339 0 : if (!permits) {
1340 0 : *outPermitsAncestry = false;
1341 : }
1342 : }
1343 0 : return NS_OK;
1344 : }
1345 :
1346 : NS_IMETHODIMP
1347 0 : nsCSPContext::Permits(nsIURI* aURI,
1348 : CSPDirective aDir,
1349 : bool aSpecific,
1350 : bool* outPermits)
1351 : {
1352 : // Can't perform check without aURI
1353 0 : if (aURI == nullptr) {
1354 0 : return NS_ERROR_FAILURE;
1355 : }
1356 :
1357 0 : *outPermits = permitsInternal(aDir,
1358 : aURI,
1359 : nullptr, // no original (pre-redirect) URI
1360 0 : EmptyString(), // no nonce
1361 : false, // not redirected.
1362 : false, // not a preload.
1363 : aSpecific,
1364 : true, // send violation reports
1365 : true, // send blocked URI in violation reports
1366 : false); // not parser created
1367 :
1368 0 : if (CSPCONTEXTLOGENABLED()) {
1369 0 : CSPCONTEXTLOG(("nsCSPContext::Permits, aUri: %s, aDir: %d, isAllowed: %s",
1370 : aURI->GetSpecOrDefault().get(), aDir,
1371 : *outPermits ? "allow" : "deny"));
1372 : }
1373 :
1374 0 : return NS_OK;
1375 : }
1376 :
1377 : NS_IMETHODIMP
1378 0 : nsCSPContext::ToJSON(nsAString& outCSPinJSON)
1379 : {
1380 0 : outCSPinJSON.Truncate();
1381 0 : dom::CSPPolicies jsonPolicies;
1382 0 : jsonPolicies.mCsp_policies.Construct();
1383 :
1384 0 : for (uint32_t p = 0; p < mPolicies.Length(); p++) {
1385 0 : dom::CSP jsonCSP;
1386 0 : mPolicies[p]->toDomCSPStruct(jsonCSP);
1387 0 : jsonPolicies.mCsp_policies.Value().AppendElement(jsonCSP, fallible);
1388 : }
1389 :
1390 : // convert the gathered information to JSON
1391 0 : if (!jsonPolicies.ToJSON(outCSPinJSON)) {
1392 0 : return NS_ERROR_FAILURE;
1393 : }
1394 0 : return NS_OK;
1395 : }
1396 :
1397 : NS_IMETHODIMP
1398 0 : nsCSPContext::GetCSPSandboxFlags(uint32_t* aOutSandboxFlags)
1399 : {
1400 0 : if (!aOutSandboxFlags) {
1401 0 : return NS_ERROR_FAILURE;
1402 : }
1403 0 : *aOutSandboxFlags = SANDBOXED_NONE;
1404 :
1405 0 : for (uint32_t i = 0; i < mPolicies.Length(); i++) {
1406 0 : uint32_t flags = mPolicies[i]->getSandboxFlags();
1407 :
1408 : // current policy doesn't have sandbox flag, check next policy
1409 0 : if (!flags) {
1410 0 : continue;
1411 : }
1412 :
1413 : // current policy has sandbox flags, if the policy is in enforcement-mode
1414 : // (i.e. not report-only) set these flags and check for policies with more
1415 : // restrictions
1416 0 : if (!mPolicies[i]->getReportOnlyFlag()) {
1417 0 : *aOutSandboxFlags |= flags;
1418 : } else {
1419 : // sandbox directive is ignored in report-only mode, warn about it and
1420 : // continue the loop checking for an enforcement policy.
1421 0 : nsAutoString policy;
1422 0 : mPolicies[i]->toString(policy);
1423 :
1424 0 : CSPCONTEXTLOG(("nsCSPContext::GetCSPSandboxFlags, report only policy, ignoring sandbox in: %s",
1425 : NS_ConvertUTF16toUTF8(policy).get()));
1426 :
1427 0 : const char16_t* params[] = { policy.get() };
1428 0 : logToConsole(u"ignoringReportOnlyDirective", params, ArrayLength(params),
1429 0 : EmptyString(), EmptyString(), 0, 0, nsIScriptError::warningFlag);
1430 : }
1431 : }
1432 :
1433 0 : return NS_OK;
1434 : }
1435 :
1436 : /* ========== CSPViolationReportListener implementation ========== */
1437 :
1438 0 : NS_IMPL_ISUPPORTS(CSPViolationReportListener, nsIStreamListener, nsIRequestObserver, nsISupports);
1439 :
1440 0 : CSPViolationReportListener::CSPViolationReportListener()
1441 : {
1442 0 : }
1443 :
1444 0 : CSPViolationReportListener::~CSPViolationReportListener()
1445 : {
1446 0 : }
1447 :
1448 : nsresult
1449 0 : AppendSegmentToString(nsIInputStream* aInputStream,
1450 : void* aClosure,
1451 : const char* aRawSegment,
1452 : uint32_t aToOffset,
1453 : uint32_t aCount,
1454 : uint32_t* outWrittenCount)
1455 : {
1456 0 : nsCString* decodedData = static_cast<nsCString*>(aClosure);
1457 0 : decodedData->Append(aRawSegment, aCount);
1458 0 : *outWrittenCount = aCount;
1459 0 : return NS_OK;
1460 : }
1461 :
1462 : NS_IMETHODIMP
1463 0 : CSPViolationReportListener::OnDataAvailable(nsIRequest* aRequest,
1464 : nsISupports* aContext,
1465 : nsIInputStream* aInputStream,
1466 : uint64_t aOffset,
1467 : uint32_t aCount)
1468 : {
1469 : uint32_t read;
1470 0 : nsCString decodedData;
1471 : return aInputStream->ReadSegments(AppendSegmentToString,
1472 : &decodedData,
1473 : aCount,
1474 0 : &read);
1475 : }
1476 :
1477 : NS_IMETHODIMP
1478 0 : CSPViolationReportListener::OnStopRequest(nsIRequest* aRequest,
1479 : nsISupports* aContext,
1480 : nsresult aStatus)
1481 : {
1482 0 : return NS_OK;
1483 : }
1484 :
1485 : NS_IMETHODIMP
1486 0 : CSPViolationReportListener::OnStartRequest(nsIRequest* aRequest,
1487 : nsISupports* aContext)
1488 : {
1489 0 : return NS_OK;
1490 : }
1491 :
1492 : /* ========== CSPReportRedirectSink implementation ========== */
1493 :
1494 0 : NS_IMPL_ISUPPORTS(CSPReportRedirectSink, nsIChannelEventSink, nsIInterfaceRequestor);
1495 :
1496 0 : CSPReportRedirectSink::CSPReportRedirectSink()
1497 : {
1498 0 : }
1499 :
1500 0 : CSPReportRedirectSink::~CSPReportRedirectSink()
1501 : {
1502 0 : }
1503 :
1504 : NS_IMETHODIMP
1505 0 : CSPReportRedirectSink::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
1506 : nsIChannel* aNewChannel,
1507 : uint32_t aRedirFlags,
1508 : nsIAsyncVerifyRedirectCallback* aCallback)
1509 : {
1510 : // cancel the old channel so XHR failure callback happens
1511 0 : nsresult rv = aOldChannel->Cancel(NS_ERROR_ABORT);
1512 0 : NS_ENSURE_SUCCESS(rv, rv);
1513 :
1514 : // notify an observer that we have blocked the report POST due to a redirect,
1515 : // used in testing, do this async since we're in an async call now to begin with
1516 0 : nsCOMPtr<nsIURI> uri;
1517 0 : rv = aOldChannel->GetURI(getter_AddRefs(uri));
1518 0 : NS_ENSURE_SUCCESS(rv, rv);
1519 :
1520 0 : nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
1521 0 : NS_ASSERTION(observerService, "Observer service required to log CSP violations");
1522 0 : observerService->NotifyObservers(uri,
1523 : CSP_VIOLATION_TOPIC,
1524 0 : u"denied redirect while sending violation report");
1525 :
1526 0 : return NS_BINDING_REDIRECTED;
1527 : }
1528 :
1529 : NS_IMETHODIMP
1530 0 : CSPReportRedirectSink::GetInterface(const nsIID& aIID, void** aResult)
1531 : {
1532 0 : if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController)) &&
1533 0 : mInterceptController) {
1534 0 : nsCOMPtr<nsINetworkInterceptController> copy(mInterceptController);
1535 0 : *aResult = copy.forget().take();
1536 :
1537 0 : return NS_OK;
1538 : }
1539 :
1540 0 : return QueryInterface(aIID, aResult);
1541 : }
1542 :
1543 : void
1544 0 : CSPReportRedirectSink::SetInterceptController(nsINetworkInterceptController* aInterceptController)
1545 : {
1546 0 : mInterceptController = aInterceptController;
1547 0 : }
1548 :
1549 : /* ===== nsISerializable implementation ====== */
1550 :
1551 : NS_IMETHODIMP
1552 0 : nsCSPContext::Read(nsIObjectInputStream* aStream)
1553 : {
1554 : nsresult rv;
1555 0 : nsCOMPtr<nsISupports> supports;
1556 :
1557 0 : rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
1558 0 : NS_ENSURE_SUCCESS(rv, rv);
1559 :
1560 0 : mSelfURI = do_QueryInterface(supports);
1561 0 : NS_ASSERTION(mSelfURI, "need a self URI to de-serialize");
1562 :
1563 : uint32_t numPolicies;
1564 0 : rv = aStream->Read32(&numPolicies);
1565 0 : NS_ENSURE_SUCCESS(rv, rv);
1566 :
1567 0 : nsAutoString policyString;
1568 :
1569 0 : while (numPolicies > 0) {
1570 0 : numPolicies--;
1571 :
1572 0 : rv = aStream->ReadString(policyString);
1573 0 : NS_ENSURE_SUCCESS(rv, rv);
1574 :
1575 0 : bool reportOnly = false;
1576 0 : rv = aStream->ReadBoolean(&reportOnly);
1577 0 : NS_ENSURE_SUCCESS(rv, rv);
1578 :
1579 : // @param deliveredViaMetaTag:
1580 : // when parsing the CSP policy string initially we already remove directives
1581 : // that should not be processed when delivered via the meta tag. Such directives
1582 : // will not be present at this point anymore.
1583 0 : nsCSPPolicy* policy = nsCSPParser::parseContentSecurityPolicy(policyString,
1584 : mSelfURI,
1585 : reportOnly,
1586 : this,
1587 0 : false);
1588 0 : if (policy) {
1589 0 : mPolicies.AppendElement(policy);
1590 : }
1591 : }
1592 :
1593 0 : return NS_OK;
1594 : }
1595 :
1596 : NS_IMETHODIMP
1597 0 : nsCSPContext::Write(nsIObjectOutputStream* aStream)
1598 : {
1599 : nsresult rv = NS_WriteOptionalCompoundObject(aStream,
1600 : mSelfURI,
1601 : NS_GET_IID(nsIURI),
1602 0 : true);
1603 0 : NS_ENSURE_SUCCESS(rv, rv);
1604 :
1605 : // Serialize all the policies.
1606 0 : aStream->Write32(mPolicies.Length());
1607 :
1608 0 : nsAutoString polStr;
1609 0 : for (uint32_t p = 0; p < mPolicies.Length(); p++) {
1610 0 : polStr.Truncate();
1611 0 : mPolicies[p]->toString(polStr);
1612 0 : aStream->WriteWStringZ(polStr.get());
1613 0 : aStream->WriteBoolean(mPolicies[p]->getReportOnlyFlag());
1614 : }
1615 0 : return NS_OK;
1616 : }
|