Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/security/nsCSPUtils.cpp
Line
Count
Source (jump to first uncovered line)
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 "nsAttrValue.h"
8
#include "nsCharSeparatedTokenizer.h"
9
#include "nsContentUtils.h"
10
#include "nsCSPUtils.h"
11
#include "nsDebug.h"
12
#include "nsIConsoleService.h"
13
#include "nsICryptoHash.h"
14
#include "nsIScriptError.h"
15
#include "nsIServiceManager.h"
16
#include "nsIStringBundle.h"
17
#include "nsIURL.h"
18
#include "nsReadableUtils.h"
19
#include "nsSandboxFlags.h"
20
21
0
#define DEFAULT_PORT -1
22
23
static mozilla::LogModule*
24
GetCspUtilsLog()
25
11.5k
{
26
11.5k
  static mozilla::LazyLogModule gCspUtilsPRLog("CSPUtils");
27
11.5k
  return gCspUtilsPRLog;
28
11.5k
}
29
30
11.5k
#define CSPUTILSLOG(args) MOZ_LOG(GetCspUtilsLog(), mozilla::LogLevel::Debug, args)
31
0
#define CSPUTILSLOGENABLED() MOZ_LOG_TEST(GetCspUtilsLog(), mozilla::LogLevel::Debug)
32
33
void
34
CSP_PercentDecodeStr(const nsAString& aEncStr, nsAString& outDecStr)
35
11.2k
{
36
11.2k
  outDecStr.Truncate();
37
11.2k
38
11.2k
  // helper function that should not be visible outside this methods scope
39
11.2k
  struct local {
40
11.2k
    static inline char16_t convertHexDig(char16_t aHexDig) {
41
2.64k
      if (isNumberToken(aHexDig)) {
42
2.04k
        return aHexDig - '0';
43
2.04k
      }
44
605
      if (aHexDig >= 'A' && aHexDig <= 'F') {
45
310
        return aHexDig - 'A' + 10;
46
310
      }
47
295
      // must be a lower case character
48
295
      // (aHexDig >= 'a' && aHexDig <= 'f')
49
295
      return aHexDig - 'a' + 10;
50
295
    }
51
11.2k
  };
52
11.2k
53
11.2k
  const char16_t *cur, *end, *hexDig1, *hexDig2;
54
11.2k
  cur = aEncStr.BeginReading();
55
11.2k
  end = aEncStr.EndReading();
56
11.2k
57
122k
  while (cur != end) {
58
111k
    // if it's not a percent sign then there is
59
111k
    // nothing to do for that character
60
111k
    if (*cur != PERCENT_SIGN) {
61
109k
      outDecStr.Append(*cur);
62
109k
      cur++;
63
109k
      continue;
64
109k
    }
65
1.32k
66
1.32k
    // get the two hexDigs following the '%'-sign
67
1.32k
    hexDig1 = cur + 1;
68
1.32k
    hexDig2 = cur + 2;
69
1.32k
70
1.32k
    // if there are no hexdigs after the '%' then
71
1.32k
    // there is nothing to do for us.
72
1.32k
    if (hexDig1 == end || hexDig2 == end ||
73
1.32k
        !isValidHexDig(*hexDig1) ||
74
1.32k
        !isValidHexDig(*hexDig2)) {
75
0
      outDecStr.Append(PERCENT_SIGN);
76
0
      cur++;
77
0
      continue;
78
0
    }
79
1.32k
80
1.32k
    // decode "% hexDig1 hexDig2" into a character.
81
1.32k
    char16_t decChar = (local::convertHexDig(*hexDig1) << 4) +
82
1.32k
                       local::convertHexDig(*hexDig2);
83
1.32k
    outDecStr.Append(decChar);
84
1.32k
85
1.32k
    // increment 'cur' to after the second hexDig
86
1.32k
    cur = ++hexDig2;
87
1.32k
  }
88
11.2k
}
89
90
void
91
CSP_GetLocalizedStr(const char* aName,
92
                    const char16_t** aParams,
93
                    uint32_t aLength,
94
                    nsAString& outResult)
95
0
{
96
0
  nsCOMPtr<nsIStringBundle> keyStringBundle;
97
0
  nsCOMPtr<nsIStringBundleService> stringBundleService =
98
0
    mozilla::services::GetStringBundleService();
99
0
100
0
  NS_ASSERTION(stringBundleService, "String bundle service must be present!");
101
0
  stringBundleService->CreateBundle("chrome://global/locale/security/csp.properties",
102
0
                                      getter_AddRefs(keyStringBundle));
103
0
104
0
  NS_ASSERTION(keyStringBundle, "Key string bundle must be available!");
105
0
106
0
  if (!keyStringBundle) {
107
0
    return;
108
0
  }
109
0
  keyStringBundle->FormatStringFromName(aName, aParams, aLength,
110
0
                                        outResult);
111
0
}
112
113
void
114
CSP_LogStrMessage(const nsAString& aMsg)
115
0
{
116
0
  nsCOMPtr<nsIConsoleService> console(do_GetService("@mozilla.org/consoleservice;1"));
117
0
118
0
  if (!console) {
119
0
    return;
120
0
  }
121
0
  nsString msg(aMsg);
122
0
  console->LogStringMessage(msg.get());
123
0
}
124
125
void
126
CSP_LogMessage(const nsAString& aMessage,
127
               const nsAString& aSourceName,
128
               const nsAString& aSourceLine,
129
               uint32_t aLineNumber,
130
               uint32_t aColumnNumber,
131
               uint32_t aFlags,
132
               const nsACString& aCategory,
133
               uint64_t aInnerWindowID,
134
               bool aFromPrivateWindow)
135
0
{
136
0
  nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
137
0
138
0
  nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
139
0
140
0
  if (!console || !error) {
141
0
    return;
142
0
  }
143
0
144
0
  // Prepending CSP to the outgoing console message
145
0
  nsString cspMsg;
146
0
  cspMsg.AppendLiteral(u"Content Security Policy: ");
147
0
  cspMsg.Append(aMessage);
148
0
149
0
  // Currently 'aSourceLine' is not logged to the console, because similar
150
0
  // information is already included within the source link of the message.
151
0
  // For inline violations however, the line and column number are 0 and
152
0
  // information contained within 'aSourceLine' can be really useful for devs.
153
0
  // E.g. 'aSourceLine' might be: 'onclick attribute on DIV element'.
154
0
  // In such cases we append 'aSourceLine' directly to the error message.
155
0
  if (!aSourceLine.IsEmpty()) {
156
0
    cspMsg.AppendLiteral(u" Source: ");
157
0
    cspMsg.Append(aSourceLine);
158
0
    cspMsg.AppendLiteral(u".");
159
0
  }
160
0
161
0
  // Since we are leveraging csp errors as the category names which
162
0
  // we pass to devtools, we should prepend them with "CSP_" to
163
0
  // allow easy distincution in devtools code. e.g.
164
0
  // upgradeInsecureRequest -> CSP_upgradeInsecureRequest
165
0
  nsCString category("CSP_");
166
0
  category.Append(aCategory);
167
0
168
0
  nsresult rv;
169
0
  if (aInnerWindowID > 0) {
170
0
    rv = error->InitWithWindowID(cspMsg, aSourceName,
171
0
                                 aSourceLine, aLineNumber,
172
0
                                 aColumnNumber, aFlags,
173
0
                                 category, aInnerWindowID);
174
0
  }
175
0
  else {
176
0
    rv = error->Init(cspMsg, aSourceName,
177
0
                     aSourceLine, aLineNumber,
178
0
                     aColumnNumber, aFlags,
179
0
                     category.get(), aFromPrivateWindow);
180
0
  }
181
0
  if (NS_FAILED(rv)) {
182
0
    return;
183
0
  }
184
0
  console->LogMessage(error);
185
0
}
186
187
/**
188
 * Combines CSP_LogMessage and CSP_GetLocalizedStr into one call.
189
 */
190
void
191
CSP_LogLocalizedStr(const char* aName,
192
                    const char16_t** aParams,
193
                    uint32_t aLength,
194
                    const nsAString& aSourceName,
195
                    const nsAString& aSourceLine,
196
                    uint32_t aLineNumber,
197
                    uint32_t aColumnNumber,
198
                    uint32_t aFlags,
199
                    const nsACString& aCategory,
200
                    uint64_t aInnerWindowID,
201
                    bool aFromPrivateWindow)
202
0
{
203
0
  nsAutoString logMsg;
204
0
  CSP_GetLocalizedStr(aName, aParams, aLength, logMsg);
205
0
  CSP_LogMessage(logMsg, aSourceName, aSourceLine,
206
0
                 aLineNumber, aColumnNumber, aFlags,
207
0
                 aCategory, aInnerWindowID, aFromPrivateWindow);
208
0
}
209
210
/* ===== Helpers ============================ */
211
CSPDirective
212
CSP_ContentTypeToDirective(nsContentPolicyType aType)
213
0
{
214
0
  switch (aType) {
215
0
    case nsIContentPolicy::TYPE_IMAGE:
216
0
    case nsIContentPolicy::TYPE_IMAGESET:
217
0
      return nsIContentSecurityPolicy::IMG_SRC_DIRECTIVE;
218
0
219
0
    // BLock XSLT as script, see bug 910139
220
0
    case nsIContentPolicy::TYPE_XSLT:
221
0
    case nsIContentPolicy::TYPE_SCRIPT:
222
0
    case nsIContentPolicy::TYPE_INTERNAL_SCRIPT:
223
0
    case nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD:
224
0
    case nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS:
225
0
      return nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE;
226
0
227
0
    case nsIContentPolicy::TYPE_STYLESHEET:
228
0
      return nsIContentSecurityPolicy::STYLE_SRC_DIRECTIVE;
229
0
230
0
    case nsIContentPolicy::TYPE_FONT:
231
0
      return nsIContentSecurityPolicy::FONT_SRC_DIRECTIVE;
232
0
233
0
    case nsIContentPolicy::TYPE_MEDIA:
234
0
      return nsIContentSecurityPolicy::MEDIA_SRC_DIRECTIVE;
235
0
236
0
    case nsIContentPolicy::TYPE_WEB_MANIFEST:
237
0
      return nsIContentSecurityPolicy::WEB_MANIFEST_SRC_DIRECTIVE;
238
0
239
0
    case nsIContentPolicy::TYPE_INTERNAL_WORKER:
240
0
    case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
241
0
    case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER:
242
0
      return nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE;
243
0
244
0
    case nsIContentPolicy::TYPE_SUBDOCUMENT:
245
0
      return nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE;
246
0
247
0
    case nsIContentPolicy::TYPE_WEBSOCKET:
248
0
    case nsIContentPolicy::TYPE_XMLHTTPREQUEST:
249
0
    case nsIContentPolicy::TYPE_BEACON:
250
0
    case nsIContentPolicy::TYPE_PING:
251
0
    case nsIContentPolicy::TYPE_FETCH:
252
0
      return nsIContentSecurityPolicy::CONNECT_SRC_DIRECTIVE;
253
0
254
0
    case nsIContentPolicy::TYPE_OBJECT:
255
0
    case nsIContentPolicy::TYPE_OBJECT_SUBREQUEST:
256
0
      return nsIContentSecurityPolicy::OBJECT_SRC_DIRECTIVE;
257
0
258
0
    case nsIContentPolicy::TYPE_XBL:
259
0
    case nsIContentPolicy::TYPE_DTD:
260
0
    case nsIContentPolicy::TYPE_OTHER:
261
0
    case nsIContentPolicy::TYPE_SPECULATIVE:
262
0
      return nsIContentSecurityPolicy::DEFAULT_SRC_DIRECTIVE;
263
0
264
0
    // csp shold not block top level loads, e.g. in case
265
0
    // of a redirect.
266
0
    case nsIContentPolicy::TYPE_DOCUMENT:
267
0
    // CSP can not block csp reports
268
0
    case nsIContentPolicy::TYPE_CSP_REPORT:
269
0
      return nsIContentSecurityPolicy::NO_DIRECTIVE;
270
0
271
0
    case nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD:
272
0
      return nsIContentSecurityPolicy::NO_DIRECTIVE;
273
0
274
0
    // Fall through to error for all other directives
275
0
    default:
276
0
      MOZ_ASSERT(false, "Can not map nsContentPolicyType to CSPDirective");
277
0
  }
278
0
  return nsIContentSecurityPolicy::DEFAULT_SRC_DIRECTIVE;
279
0
}
280
281
nsCSPHostSrc*
282
CSP_CreateHostSrcFromSelfURI(nsIURI* aSelfURI)
283
289
{
284
289
  // Create the host first
285
289
  nsCString host;
286
289
  aSelfURI->GetAsciiHost(host);
287
289
  nsCSPHostSrc *hostsrc = new nsCSPHostSrc(NS_ConvertUTF8toUTF16(host));
288
289
  hostsrc->setGeneratedFromSelfKeyword();
289
289
290
289
  // Add the scheme.
291
289
  nsCString scheme;
292
289
  aSelfURI->GetScheme(scheme);
293
289
  hostsrc->setScheme(NS_ConvertUTF8toUTF16(scheme));
294
289
295
289
  // An empty host (e.g. for data:) indicates it's effectively a unique origin.
296
289
  // Please note that we still need to set the scheme on hostsrc (see above),
297
289
  // because it's used for reporting.
298
289
  if (host.EqualsLiteral("")) {
299
0
    hostsrc->setIsUniqueOrigin();
300
0
    // no need to query the port in that case.
301
0
    return hostsrc;
302
0
  }
303
289
304
289
  int32_t port;
305
289
  aSelfURI->GetPort(&port);
306
289
  // Only add port if it's not default port.
307
289
  if (port > 0) {
308
0
    nsAutoString portStr;
309
0
    portStr.AppendInt(port);
310
0
    hostsrc->setPort(portStr);
311
0
  }
312
289
  return hostsrc;
313
289
}
314
315
bool
316
CSP_IsEmptyDirective(const nsAString& aValue, const nsAString& aDir)
317
315k
{
318
315k
  return (aDir.Length() == 0 &&
319
315k
          aValue.Length() == 0);
320
315k
}
321
bool
322
CSP_IsValidDirective(const nsAString& aDir)
323
315k
{
324
315k
  uint32_t numDirs = (sizeof(CSPStrDirectives) / sizeof(CSPStrDirectives[0]));
325
315k
326
7.12M
  for (uint32_t i = 0; i < numDirs; i++) {
327
6.82M
    if (aDir.LowerCaseEqualsASCII(CSPStrDirectives[i])) {
328
12.3k
      return true;
329
12.3k
    }
330
6.82M
  }
331
315k
  return false;
332
315k
}
333
bool
334
CSP_IsDirective(const nsAString& aValue, CSPDirective aDir)
335
96.3k
{
336
96.3k
  return aValue.LowerCaseEqualsASCII(CSP_CSPDirectiveToString(aDir));
337
96.3k
}
338
339
bool
340
CSP_IsKeyword(const nsAString& aValue, enum CSPKeyword aKey)
341
1.22M
{
342
1.22M
  return aValue.LowerCaseEqualsASCII(CSP_EnumToUTF8Keyword(aKey));
343
1.22M
}
344
345
bool
346
CSP_IsQuotelessKeyword(const nsAString& aKey)
347
176k
{
348
176k
  nsString lowerKey;
349
176k
  ToLowerCase(aKey, lowerKey);
350
176k
351
176k
  nsAutoString keyword;
352
1.58M
  for (uint32_t i = 0; i < CSP_LAST_KEYWORD_VALUE; i++) {
353
1.40M
    // skipping the leading ' and trimming the trailing '
354
1.40M
    keyword.AssignASCII(gCSPUTF8Keywords[i] + 1);
355
1.40M
    keyword.Trim("'", false, true);
356
1.40M
    if (lowerKey.Equals(keyword)) {
357
76
      return true;
358
76
    }
359
1.40M
  }
360
176k
  return false;
361
176k
}
362
363
/*
364
 * Checks whether the current directive permits a specific
365
 * scheme. This function is called from nsCSPSchemeSrc() and
366
 * also nsCSPHostSrc.
367
 * @param aEnforcementScheme
368
 *        The scheme that this directive allows
369
 * @param aUri
370
 *        The uri of the subresource load.
371
 * @param aReportOnly
372
 *        Whether the enforced policy is report only or not.
373
 * @param aUpgradeInsecure
374
 *        Whether the policy makes use of the directive
375
 *        'upgrade-insecure-requests'.
376
 * @param aFromSelfURI
377
 *        Whether a scheme was generated from the keyword 'self'
378
 *        which then allows schemeless sources to match ws and wss.
379
 */
380
381
bool
382
permitsScheme(const nsAString& aEnforcementScheme,
383
              nsIURI* aUri,
384
              bool aReportOnly,
385
              bool aUpgradeInsecure,
386
              bool aFromSelfURI)
387
0
{
388
0
  nsAutoCString scheme;
389
0
  nsresult rv = aUri->GetScheme(scheme);
390
0
  NS_ENSURE_SUCCESS(rv, false);
391
0
392
0
  // no scheme to enforce, let's allow the load (e.g. script-src *)
393
0
  if (aEnforcementScheme.IsEmpty()) {
394
0
    return true;
395
0
  }
396
0
397
0
  // if the scheme matches, all good - allow the load
398
0
  if (aEnforcementScheme.EqualsASCII(scheme.get())) {
399
0
    return true;
400
0
  }
401
0
402
0
  // allow scheme-less sources where the protected resource is http
403
0
  // and the load is https, see:
404
0
  // http://www.w3.org/TR/CSP2/#match-source-expression
405
0
  if (aEnforcementScheme.EqualsASCII("http")) {
406
0
    if (scheme.EqualsASCII("https")) {
407
0
      return true;
408
0
    }
409
0
    if ((scheme.EqualsASCII("ws") || scheme.EqualsASCII("wss")) && aFromSelfURI) {
410
0
      return true;
411
0
    }
412
0
  }
413
0
  if (aEnforcementScheme.EqualsASCII("https")) {
414
0
    if (scheme.EqualsLiteral("wss") && aFromSelfURI) {
415
0
      return true;
416
0
    }
417
0
  }
418
0
  if (aEnforcementScheme.EqualsASCII("ws") && scheme.EqualsASCII("wss")) {
419
0
    return true;
420
0
  }
421
0
422
0
  // Allow the load when enforcing upgrade-insecure-requests with the
423
0
  // promise the request gets upgraded from http to https and ws to wss.
424
0
  // See nsHttpChannel::Connect() and also WebSocket.cpp. Please note,
425
0
  // the report only policies should not allow the load and report
426
0
  // the error back to the page.
427
0
  return ((aUpgradeInsecure && !aReportOnly) &&
428
0
          ((scheme.EqualsASCII("http") && aEnforcementScheme.EqualsASCII("https")) ||
429
0
           (scheme.EqualsASCII("ws") && aEnforcementScheme.EqualsASCII("wss"))));
430
0
}
431
432
/*
433
 * A helper function for appending a CSP header to an existing CSP
434
 * policy.
435
 *
436
 * @param aCsp           the CSP policy
437
 * @param aHeaderValue   the header
438
 * @param aReportOnly    is this a report-only header?
439
 */
440
441
nsresult
442
CSP_AppendCSPFromHeader(nsIContentSecurityPolicy* aCsp,
443
                        const nsAString& aHeaderValue,
444
                        bool aReportOnly)
445
0
{
446
0
  NS_ENSURE_ARG(aCsp);
447
0
448
0
  // Need to tokenize the header value since multiple headers could be
449
0
  // concatenated into one comma-separated list of policies.
450
0
  // See RFC2616 section 4.2 (last paragraph)
451
0
  nsresult rv = NS_OK;
452
0
  nsCharSeparatedTokenizer tokenizer(aHeaderValue, ',');
453
0
  while (tokenizer.hasMoreTokens()) {
454
0
    const nsAString& policy = tokenizer.nextToken();
455
0
    rv = aCsp->AppendPolicy(policy, aReportOnly, false);
456
0
    NS_ENSURE_SUCCESS(rv, rv);
457
0
    {
458
0
      CSPUTILSLOG(("CSP refined with policy: \"%s\"",
459
0
                   NS_ConvertUTF16toUTF8(policy).get()));
460
0
    }
461
0
  }
462
0
  return NS_OK;
463
0
}
464
465
/* ===== nsCSPSrc ============================ */
466
467
nsCSPBaseSrc::nsCSPBaseSrc()
468
  : mInvalidated(false)
469
3.18M
{
470
3.18M
}
471
472
nsCSPBaseSrc::~nsCSPBaseSrc()
473
3.18M
{
474
3.18M
}
475
476
// ::permits is only called for external load requests, therefore:
477
// nsCSPKeywordSrc and nsCSPHashSource fall back to this base class
478
// implementation which will never allow the load.
479
bool
480
nsCSPBaseSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
481
                      bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const
482
0
{
483
0
  if (CSPUTILSLOGENABLED()) {
484
0
    CSPUTILSLOG(("nsCSPBaseSrc::permits, aUri: %s",
485
0
                 aUri->GetSpecOrDefault().get()));
486
0
  }
487
0
  return false;
488
0
}
489
490
// ::allows is only called for inlined loads, therefore:
491
// nsCSPSchemeSrc, nsCSPHostSrc fall back
492
// to this base class implementation which will never allow the load.
493
bool
494
nsCSPBaseSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
495
                     bool aParserCreated) const
496
0
{
497
0
  CSPUTILSLOG(("nsCSPBaseSrc::allows, aKeyWord: %s, a HashOrNonce: %s",
498
0
              aKeyword == CSP_HASH ? "hash" : CSP_EnumToUTF8Keyword(aKeyword),
499
0
              NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
500
0
  return false;
501
0
}
502
503
/* ====== nsCSPSchemeSrc ===================== */
504
505
nsCSPSchemeSrc::nsCSPSchemeSrc(const nsAString& aScheme)
506
  : mScheme(aScheme)
507
10.1k
{
508
10.1k
  ToLowerCase(mScheme);
509
10.1k
}
510
511
nsCSPSchemeSrc::~nsCSPSchemeSrc()
512
10.1k
{
513
10.1k
}
514
515
bool
516
nsCSPSchemeSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
517
                        bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const
518
0
{
519
0
  if (CSPUTILSLOGENABLED()) {
520
0
    CSPUTILSLOG(("nsCSPSchemeSrc::permits, aUri: %s",
521
0
                 aUri->GetSpecOrDefault().get()));
522
0
  }
523
0
  MOZ_ASSERT((!mScheme.EqualsASCII("")), "scheme can not be the empty string");
524
0
  if (mInvalidated) {
525
0
    return false;
526
0
  }
527
0
  return permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure, false);
528
0
}
529
530
bool
531
nsCSPSchemeSrc::visit(nsCSPSrcVisitor* aVisitor) const
532
0
{
533
0
  return aVisitor->visitSchemeSrc(*this);
534
0
}
535
536
void
537
nsCSPSchemeSrc::toString(nsAString& outStr) const
538
6.00k
{
539
6.00k
  outStr.Append(mScheme);
540
6.00k
  outStr.AppendLiteral(":");
541
6.00k
}
542
543
/* ===== nsCSPHostSrc ======================== */
544
545
nsCSPHostSrc::nsCSPHostSrc(const nsAString& aHost)
546
  : mHost(aHost)
547
  , mGeneratedFromSelfKeyword(false)
548
  , mIsUniqueOrigin(false)
549
  , mWithinFrameAncstorsDir(false)
550
180k
{
551
180k
  ToLowerCase(mHost);
552
180k
}
553
554
nsCSPHostSrc::~nsCSPHostSrc()
555
180k
{
556
180k
}
557
558
/*
559
 * Checks whether the current directive permits a specific port.
560
 * @param aEnforcementScheme
561
 *        The scheme that this directive allows
562
 *        (used to query the default port for that scheme)
563
 * @param aEnforcementPort
564
 *        The port that this directive allows
565
 * @param aResourceURI
566
 *        The uri of the subresource load
567
 */
568
bool
569
permitsPort(const nsAString& aEnforcementScheme,
570
            const nsAString& aEnforcementPort,
571
            nsIURI* aResourceURI)
572
0
{
573
0
  // If enforcement port is the wildcard, don't block the load.
574
0
  if (aEnforcementPort.EqualsASCII("*")) {
575
0
    return true;
576
0
  }
577
0
578
0
  int32_t resourcePort;
579
0
  nsresult rv = aResourceURI->GetPort(&resourcePort);
580
0
  NS_ENSURE_SUCCESS(rv, false);
581
0
582
0
  // Avoid unnecessary string creation/manipulation and don't block the
583
0
  // load if the resource to be loaded uses the default port for that
584
0
  // scheme and there is no port to be enforced.
585
0
  // Note, this optimization relies on scheme checks within permitsScheme().
586
0
  if (resourcePort == DEFAULT_PORT && aEnforcementPort.IsEmpty()) {
587
0
    return true;
588
0
  }
589
0
590
0
  // By now we know at that either the resourcePort does not use the default
591
0
  // port or there is a port restriction to be enforced. A port value of -1
592
0
  // corresponds to the protocol's default port (eg. -1 implies port 80 for
593
0
  // http URIs), in such a case we have to query the default port of the
594
0
  // resource to be loaded.
595
0
  if (resourcePort == DEFAULT_PORT) {
596
0
    nsAutoCString resourceScheme;
597
0
    rv = aResourceURI->GetScheme(resourceScheme);
598
0
    NS_ENSURE_SUCCESS(rv, false);
599
0
    resourcePort = NS_GetDefaultPort(resourceScheme.get());
600
0
  }
601
0
602
0
  // If there is a port to be enforced and the ports match, then
603
0
  // don't block the load.
604
0
  nsString resourcePortStr;
605
0
  resourcePortStr.AppendInt(resourcePort);
606
0
  if (aEnforcementPort.Equals(resourcePortStr)) {
607
0
    return true;
608
0
  }
609
0
610
0
  // If there is no port to be enforced, query the default port for the load.
611
0
  nsString enforcementPort(aEnforcementPort);
612
0
  if (enforcementPort.IsEmpty()) {
613
0
    // For scheme less sources, our parser always generates a scheme
614
0
    // which is the scheme of the protected resource.
615
0
    MOZ_ASSERT(!aEnforcementScheme.IsEmpty(),
616
0
               "need a scheme to query default port");
617
0
    int32_t defaultEnforcementPort =
618
0
      NS_GetDefaultPort(NS_ConvertUTF16toUTF8(aEnforcementScheme).get());
619
0
    enforcementPort.Truncate();
620
0
    enforcementPort.AppendInt(defaultEnforcementPort);
621
0
  }
622
0
623
0
  // If default ports match, don't block the load
624
0
  if (enforcementPort.Equals(resourcePortStr)) {
625
0
    return true;
626
0
  }
627
0
628
0
  // Additional port matching where the regular URL matching algorithm
629
0
  // treats insecure ports as matching their secure variants.
630
0
  // default port for http is  :80
631
0
  // default port for https is :443
632
0
  if (enforcementPort.EqualsLiteral("80") &&
633
0
      resourcePortStr.EqualsLiteral("443")) {
634
0
    return true;
635
0
  }
636
0
637
0
  // ports do not match, block the load.
638
0
  return false;
639
0
}
640
641
bool
642
nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
643
                      bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const
644
0
{
645
0
  if (CSPUTILSLOGENABLED()) {
646
0
    CSPUTILSLOG(("nsCSPHostSrc::permits, aUri: %s",
647
0
                 aUri->GetSpecOrDefault().get()));
648
0
  }
649
0
650
0
  if (mInvalidated || mIsUniqueOrigin) {
651
0
    return false;
652
0
  }
653
0
654
0
  // we are following the enforcement rules from the spec, see:
655
0
  // http://www.w3.org/TR/CSP11/#match-source-expression
656
0
657
0
  // 4.3) scheme matching: Check if the scheme matches.
658
0
  if (!permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure, mGeneratedFromSelfKeyword)) {
659
0
    return false;
660
0
  }
661
0
662
0
  // The host in nsCSpHostSrc should never be empty. In case we are enforcing
663
0
  // just a specific scheme, the parser should generate a nsCSPSchemeSource.
664
0
  NS_ASSERTION((!mHost.IsEmpty()), "host can not be the empty string");
665
0
666
0
  // 2) host matching: Enforce a single *
667
0
  if (mHost.EqualsASCII("*")) {
668
0
    // The single ASTERISK character (*) does not match a URI's scheme of a type
669
0
    // designating a globally unique identifier (such as blob:, data:, or filesystem:)
670
0
    // At the moment firefox does not support filesystem; but for future compatibility
671
0
    // we support it in CSP according to the spec, see: 4.2.2 Matching Source Expressions
672
0
    // Note, that whitelisting any of these schemes would call nsCSPSchemeSrc::permits().
673
0
    bool isBlobScheme =
674
0
      (NS_SUCCEEDED(aUri->SchemeIs("blob", &isBlobScheme)) && isBlobScheme);
675
0
    bool isDataScheme =
676
0
      (NS_SUCCEEDED(aUri->SchemeIs("data", &isDataScheme)) && isDataScheme);
677
0
    bool isFileScheme =
678
0
      (NS_SUCCEEDED(aUri->SchemeIs("filesystem", &isFileScheme)) && isFileScheme);
679
0
680
0
    if (isBlobScheme || isDataScheme || isFileScheme) {
681
0
      return false;
682
0
    }
683
0
    return true;
684
0
  }
685
0
686
0
  // Before we can check if the host matches, we have to
687
0
  // extract the host part from aUri.
688
0
  nsAutoCString uriHost;
689
0
  nsresult rv = aUri->GetAsciiHost(uriHost);
690
0
  NS_ENSURE_SUCCESS(rv, false);
691
0
692
0
  nsString decodedUriHost;
693
0
  CSP_PercentDecodeStr(NS_ConvertUTF8toUTF16(uriHost), decodedUriHost);
694
0
695
0
  // 4.5) host matching: Check if the allowed host starts with a wilcard.
696
0
  if (mHost.First() == '*') {
697
0
    NS_ASSERTION(mHost[1] == '.', "Second character needs to be '.' whenever host starts with '*'");
698
0
699
0
    // Eliminate leading "*", but keeping the FULL STOP (.) thereafter before checking
700
0
    // if the remaining characters match
701
0
    nsString wildCardHost = mHost;
702
0
    wildCardHost = Substring(wildCardHost, 1, wildCardHost.Length() - 1);
703
0
    if (!StringEndsWith(decodedUriHost, wildCardHost)) {
704
0
      return false;
705
0
    }
706
0
  }
707
0
  // 4.6) host matching: Check if hosts match.
708
0
  else if (!mHost.Equals(decodedUriHost)) {
709
0
    return false;
710
0
  }
711
0
712
0
  // Port matching: Check if the ports match.
713
0
  if (!permitsPort(mScheme, mPort, aUri)) {
714
0
    return false;
715
0
  }
716
0
717
0
  // 4.9) Path matching: If there is a path, we have to enforce
718
0
  // path-level matching, unless the channel got redirected, see:
719
0
  // http://www.w3.org/TR/CSP11/#source-list-paths-and-redirects
720
0
  if (!aWasRedirected && !mPath.IsEmpty()) {
721
0
    // converting aUri into nsIURL so we can strip query and ref
722
0
    // example.com/test#foo     -> example.com/test
723
0
    // example.com/test?val=foo -> example.com/test
724
0
    nsCOMPtr<nsIURL> url = do_QueryInterface(aUri);
725
0
    if (!url) {
726
0
      NS_ASSERTION(false, "can't QI into nsIURI");
727
0
      return false;
728
0
    }
729
0
    nsAutoCString uriPath;
730
0
    rv = url->GetFilePath(uriPath);
731
0
    NS_ENSURE_SUCCESS(rv, false);
732
0
733
0
    if (mWithinFrameAncstorsDir) {
734
0
      // no path matching for frame-ancestors to not leak any path information.
735
0
      return true;
736
0
    }
737
0
738
0
    nsString decodedUriPath;
739
0
    CSP_PercentDecodeStr(NS_ConvertUTF8toUTF16(uriPath), decodedUriPath);
740
0
741
0
    // check if the last character of mPath is '/'; if so
742
0
    // we just have to check loading resource is within
743
0
    // the allowed path.
744
0
    if (mPath.Last() == '/') {
745
0
      if (!StringBeginsWith(decodedUriPath, mPath)) {
746
0
        return false;
747
0
      }
748
0
    }
749
0
    // otherwise mPath whitelists a specific file, and we have to
750
0
    // check if the loading resource matches that whitelisted file.
751
0
    else {
752
0
      if (!mPath.Equals(decodedUriPath)) {
753
0
        return false;
754
0
      }
755
0
    }
756
0
  }
757
0
758
0
  // At the end: scheme, host, port and path match -> allow the load.
759
0
  return true;
760
0
}
761
762
bool
763
nsCSPHostSrc::visit(nsCSPSrcVisitor* aVisitor) const
764
0
{
765
0
  return aVisitor->visitHostSrc(*this);
766
0
}
767
768
void
769
nsCSPHostSrc::toString(nsAString& outStr) const
770
879
{
771
879
  if (mGeneratedFromSelfKeyword) {
772
25
    outStr.AppendLiteral("'self'");
773
25
    return;
774
25
  }
775
854
776
854
  // If mHost is a single "*", we append the wildcard and return.
777
854
  if (mHost.EqualsASCII("*") &&
778
854
      mScheme.IsEmpty() &&
779
854
      mPort.IsEmpty()) {
780
58
    outStr.Append(mHost);
781
58
    return;
782
58
  }
783
796
784
796
  // append scheme
785
796
  outStr.Append(mScheme);
786
796
787
796
  // append host
788
796
  outStr.AppendLiteral("://");
789
796
  outStr.Append(mHost);
790
796
791
796
  // append port
792
796
  if (!mPort.IsEmpty()) {
793
77
    outStr.AppendLiteral(":");
794
77
    outStr.Append(mPort);
795
77
  }
796
796
797
796
  // append path
798
796
  outStr.Append(mPath);
799
796
}
800
801
void
802
nsCSPHostSrc::setScheme(const nsAString& aScheme)
803
21.3k
{
804
21.3k
  mScheme = aScheme;
805
21.3k
  ToLowerCase(mScheme);
806
21.3k
}
807
808
void
809
nsCSPHostSrc::setPort(const nsAString& aPort)
810
531
{
811
531
  mPort = aPort;
812
531
}
813
814
void
815
nsCSPHostSrc::appendPath(const nsAString& aPath)
816
14.7k
{
817
14.7k
  mPath.Append(aPath);
818
14.7k
}
819
820
/* ===== nsCSPKeywordSrc ===================== */
821
822
nsCSPKeywordSrc::nsCSPKeywordSrc(enum CSPKeyword aKeyword)
823
 : mKeyword(aKeyword)
824
917
{
825
917
  NS_ASSERTION((aKeyword != CSP_SELF),
826
917
               "'self' should have been replaced in the parser");
827
917
}
828
829
nsCSPKeywordSrc::~nsCSPKeywordSrc()
830
{
831
}
832
833
bool
834
nsCSPKeywordSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
835
                         bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const
836
0
{
837
0
  // no need to check for invalidated, this will always return false unless
838
0
  // it is an nsCSPKeywordSrc for 'strict-dynamic', which should allow non
839
0
  // parser created scripts.
840
0
  return ((mKeyword == CSP_STRICT_DYNAMIC) && !aParserCreated);
841
0
}
842
843
bool
844
nsCSPKeywordSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
845
                        bool aParserCreated) const
846
0
{
847
0
  CSPUTILSLOG(("nsCSPKeywordSrc::allows, aKeyWord: %s, aHashOrNonce: %s, mInvalidated: %s",
848
0
              CSP_EnumToUTF8Keyword(aKeyword),
849
0
              NS_ConvertUTF16toUTF8(aHashOrNonce).get(),
850
0
              mInvalidated ? "yes" : "false"));
851
0
852
0
  if (mInvalidated) {
853
0
    // only 'self' and 'unsafe-inline' are keywords that can be ignored. Please note that
854
0
    // the parser already translates 'self' into a uri (see assertion in constructor).
855
0
    MOZ_ASSERT(mKeyword == CSP_UNSAFE_INLINE,
856
0
               "should only invalidate unsafe-inline");
857
0
    return false;
858
0
  }
859
0
  // either the keyword allows the load or the policy contains 'strict-dynamic', in which
860
0
  // case we have to make sure the script is not parser created before allowing the load
861
0
  // and also eval should be blocked even if 'strict-dynamic' is present. Should be
862
0
  // allowed only if 'unsafe-eval' is present.
863
0
  return ((mKeyword == aKeyword) ||
864
0
          ((mKeyword == CSP_STRICT_DYNAMIC) && !aParserCreated &&
865
0
            aKeyword != CSP_UNSAFE_EVAL));
866
0
}
867
868
bool
869
nsCSPKeywordSrc::visit(nsCSPSrcVisitor* aVisitor) const
870
0
{
871
0
  return aVisitor->visitKeywordSrc(*this);
872
0
}
873
874
void
875
nsCSPKeywordSrc::toString(nsAString& outStr) const
876
279
{
877
279
  outStr.Append(CSP_EnumToUTF16Keyword(mKeyword));
878
279
}
879
880
/* ===== nsCSPNonceSrc ==================== */
881
882
nsCSPNonceSrc::nsCSPNonceSrc(const nsAString& aNonce)
883
  : mNonce(aNonce)
884
316
{
885
316
}
886
887
nsCSPNonceSrc::~nsCSPNonceSrc()
888
316
{
889
316
}
890
891
bool
892
nsCSPNonceSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
893
                       bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const
894
0
{
895
0
  if (CSPUTILSLOGENABLED()) {
896
0
    CSPUTILSLOG(("nsCSPNonceSrc::permits, aUri: %s, aNonce: %s",
897
0
                 aUri->GetSpecOrDefault().get(),
898
0
                 NS_ConvertUTF16toUTF8(aNonce).get()));
899
0
  }
900
0
901
0
  // nonces can not be invalidated by strict-dynamic
902
0
  return mNonce.Equals(aNonce);
903
0
}
904
905
bool
906
nsCSPNonceSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
907
                      bool aParserCreated) const
908
0
{
909
0
  CSPUTILSLOG(("nsCSPNonceSrc::allows, aKeyWord: %s, a HashOrNonce: %s",
910
0
              CSP_EnumToUTF8Keyword(aKeyword),
911
0
              NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
912
0
913
0
  if (aKeyword != CSP_NONCE) {
914
0
    return false;
915
0
  }
916
0
  // nonces can not be invalidated by strict-dynamic
917
0
  return mNonce.Equals(aHashOrNonce);
918
0
}
919
920
bool
921
nsCSPNonceSrc::visit(nsCSPSrcVisitor* aVisitor) const
922
0
{
923
0
  return aVisitor->visitNonceSrc(*this);
924
0
}
925
926
void
927
nsCSPNonceSrc::toString(nsAString& outStr) const
928
6
{
929
6
  outStr.Append(CSP_EnumToUTF16Keyword(CSP_NONCE));
930
6
  outStr.Append(mNonce);
931
6
  outStr.AppendLiteral("'");
932
6
}
933
934
/* ===== nsCSPHashSrc ===================== */
935
936
nsCSPHashSrc::nsCSPHashSrc(const nsAString& aAlgo, const nsAString& aHash)
937
 : mAlgorithm(aAlgo)
938
 , mHash(aHash)
939
408
{
940
408
  // Only the algo should be rewritten to lowercase, the hash must remain the same.
941
408
  ToLowerCase(mAlgorithm);
942
408
}
943
944
nsCSPHashSrc::~nsCSPHashSrc()
945
408
{
946
408
}
947
948
bool
949
nsCSPHashSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
950
                     bool aParserCreated) const
951
0
{
952
0
  CSPUTILSLOG(("nsCSPHashSrc::allows, aKeyWord: %s, a HashOrNonce: %s",
953
0
              CSP_EnumToUTF8Keyword(aKeyword),
954
0
              NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
955
0
956
0
  if (aKeyword != CSP_HASH) {
957
0
    return false;
958
0
  }
959
0
960
0
  // hashes can not be invalidated by strict-dynamic
961
0
962
0
  // Convert aHashOrNonce to UTF-8
963
0
  NS_ConvertUTF16toUTF8 utf8_hash(aHashOrNonce);
964
0
965
0
  nsresult rv;
966
0
  nsCOMPtr<nsICryptoHash> hasher;
967
0
  hasher = do_CreateInstance("@mozilla.org/security/hash;1", &rv);
968
0
  NS_ENSURE_SUCCESS(rv, false);
969
0
970
0
  rv = hasher->InitWithString(NS_ConvertUTF16toUTF8(mAlgorithm));
971
0
  NS_ENSURE_SUCCESS(rv, false);
972
0
973
0
  rv = hasher->Update((uint8_t *)utf8_hash.get(), utf8_hash.Length());
974
0
  NS_ENSURE_SUCCESS(rv, false);
975
0
976
0
  nsAutoCString hash;
977
0
  rv = hasher->Finish(true, hash);
978
0
  NS_ENSURE_SUCCESS(rv, false);
979
0
980
0
  return NS_ConvertUTF16toUTF8(mHash).Equals(hash);
981
0
}
982
983
bool
984
nsCSPHashSrc::visit(nsCSPSrcVisitor* aVisitor) const
985
0
{
986
0
  return aVisitor->visitHashSrc(*this);
987
0
}
988
989
void
990
nsCSPHashSrc::toString(nsAString& outStr) const
991
156
{
992
156
  outStr.AppendLiteral("'");
993
156
  outStr.Append(mAlgorithm);
994
156
  outStr.AppendLiteral("-");
995
156
  outStr.Append(mHash);
996
156
  outStr.AppendLiteral("'");
997
156
}
998
999
/* ===== nsCSPReportURI ===================== */
1000
1001
nsCSPReportURI::nsCSPReportURI(nsIURI *aURI)
1002
  :mReportURI(aURI)
1003
2.99M
{
1004
2.99M
}
1005
1006
nsCSPReportURI::~nsCSPReportURI()
1007
2.99M
{
1008
2.99M
}
1009
1010
bool
1011
nsCSPReportURI::visit(nsCSPSrcVisitor* aVisitor) const
1012
0
{
1013
0
  return false;
1014
0
}
1015
1016
void
1017
nsCSPReportURI::toString(nsAString& outStr) const
1018
0
{
1019
0
  nsAutoCString spec;
1020
0
  nsresult rv = mReportURI->GetSpec(spec);
1021
0
  if (NS_FAILED(rv)) {
1022
0
    return;
1023
0
  }
1024
0
  outStr.AppendASCII(spec.get());
1025
0
}
1026
1027
/* ===== nsCSPSandboxFlags ===================== */
1028
1029
nsCSPSandboxFlags::nsCSPSandboxFlags(const nsAString& aFlags)
1030
  : mFlags(aFlags)
1031
103
{
1032
103
  ToLowerCase(mFlags);
1033
103
}
1034
1035
nsCSPSandboxFlags::~nsCSPSandboxFlags()
1036
103
{
1037
103
}
1038
1039
bool
1040
nsCSPSandboxFlags::visit(nsCSPSrcVisitor* aVisitor) const
1041
0
{
1042
0
  return false;
1043
0
}
1044
1045
void
1046
nsCSPSandboxFlags::toString(nsAString& outStr) const
1047
0
{
1048
0
  outStr.Append(mFlags);
1049
0
}
1050
1051
/* ===== nsCSPDirective ====================== */
1052
1053
nsCSPDirective::nsCSPDirective(CSPDirective aDirective)
1054
8.72k
{
1055
8.72k
  mDirective = aDirective;
1056
8.72k
}
1057
1058
nsCSPDirective::~nsCSPDirective()
1059
8.72k
{
1060
3.03M
  for (uint32_t i = 0; i < mSrcs.Length(); i++) {
1061
3.02M
    delete mSrcs[i];
1062
3.02M
  }
1063
8.72k
}
1064
1065
bool
1066
nsCSPDirective::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
1067
                        bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const
1068
0
{
1069
0
  if (CSPUTILSLOGENABLED()) {
1070
0
    CSPUTILSLOG(("nsCSPDirective::permits, aUri: %s",
1071
0
                 aUri->GetSpecOrDefault().get()));
1072
0
  }
1073
0
1074
0
  for (uint32_t i = 0; i < mSrcs.Length(); i++) {
1075
0
    if (mSrcs[i]->permits(aUri, aNonce, aWasRedirected, aReportOnly, aUpgradeInsecure, aParserCreated)) {
1076
0
      return true;
1077
0
    }
1078
0
  }
1079
0
  return false;
1080
0
}
1081
1082
bool
1083
nsCSPDirective::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
1084
                       bool aParserCreated) const
1085
0
{
1086
0
  CSPUTILSLOG(("nsCSPDirective::allows, aKeyWord: %s, a HashOrNonce: %s",
1087
0
              CSP_EnumToUTF8Keyword(aKeyword),
1088
0
              NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
1089
0
1090
0
  for (uint32_t i = 0; i < mSrcs.Length(); i++) {
1091
0
    if (mSrcs[i]->allows(aKeyword, aHashOrNonce, aParserCreated)) {
1092
0
      return true;
1093
0
    }
1094
0
  }
1095
0
  return false;
1096
0
}
1097
1098
void
1099
nsCSPDirective::toString(nsAString& outStr) const
1100
0
{
1101
0
  // Append directive name
1102
0
  outStr.AppendASCII(CSP_CSPDirectiveToString(mDirective));
1103
0
  outStr.AppendLiteral(" ");
1104
0
1105
0
  // Append srcs
1106
0
  uint32_t length = mSrcs.Length();
1107
0
  for (uint32_t i = 0; i < length; i++) {
1108
0
    mSrcs[i]->toString(outStr);
1109
0
    if (i != (length - 1)) {
1110
0
      outStr.AppendLiteral(" ");
1111
0
    }
1112
0
  }
1113
0
}
1114
1115
void
1116
nsCSPDirective::toDomCSPStruct(mozilla::dom::CSP& outCSP) const
1117
0
{
1118
0
  mozilla::dom::Sequence<nsString> srcs;
1119
0
  nsString src;
1120
0
  for (uint32_t i = 0; i < mSrcs.Length(); i++) {
1121
0
    src.Truncate();
1122
0
    mSrcs[i]->toString(src);
1123
0
    srcs.AppendElement(src, mozilla::fallible);
1124
0
  }
1125
0
1126
0
  switch(mDirective) {
1127
0
    case nsIContentSecurityPolicy::DEFAULT_SRC_DIRECTIVE:
1128
0
      outCSP.mDefault_src.Construct();
1129
0
      outCSP.mDefault_src.Value() = std::move(srcs);
1130
0
      return;
1131
0
1132
0
    case nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE:
1133
0
      outCSP.mScript_src.Construct();
1134
0
      outCSP.mScript_src.Value() = std::move(srcs);
1135
0
      return;
1136
0
1137
0
    case nsIContentSecurityPolicy::OBJECT_SRC_DIRECTIVE:
1138
0
      outCSP.mObject_src.Construct();
1139
0
      outCSP.mObject_src.Value() = std::move(srcs);
1140
0
      return;
1141
0
1142
0
    case nsIContentSecurityPolicy::STYLE_SRC_DIRECTIVE:
1143
0
      outCSP.mStyle_src.Construct();
1144
0
      outCSP.mStyle_src.Value() = std::move(srcs);
1145
0
      return;
1146
0
1147
0
    case nsIContentSecurityPolicy::IMG_SRC_DIRECTIVE:
1148
0
      outCSP.mImg_src.Construct();
1149
0
      outCSP.mImg_src.Value() = std::move(srcs);
1150
0
      return;
1151
0
1152
0
    case nsIContentSecurityPolicy::MEDIA_SRC_DIRECTIVE:
1153
0
      outCSP.mMedia_src.Construct();
1154
0
      outCSP.mMedia_src.Value() = std::move(srcs);
1155
0
      return;
1156
0
1157
0
    case nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE:
1158
0
      outCSP.mFrame_src.Construct();
1159
0
      outCSP.mFrame_src.Value() = std::move(srcs);
1160
0
      return;
1161
0
1162
0
    case nsIContentSecurityPolicy::FONT_SRC_DIRECTIVE:
1163
0
      outCSP.mFont_src.Construct();
1164
0
      outCSP.mFont_src.Value() = std::move(srcs);
1165
0
      return;
1166
0
1167
0
    case nsIContentSecurityPolicy::CONNECT_SRC_DIRECTIVE:
1168
0
      outCSP.mConnect_src.Construct();
1169
0
      outCSP.mConnect_src.Value() = std::move(srcs);
1170
0
      return;
1171
0
1172
0
    case nsIContentSecurityPolicy::REPORT_URI_DIRECTIVE:
1173
0
      outCSP.mReport_uri.Construct();
1174
0
      outCSP.mReport_uri.Value() = std::move(srcs);
1175
0
      return;
1176
0
1177
0
    case nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE:
1178
0
      outCSP.mFrame_ancestors.Construct();
1179
0
      outCSP.mFrame_ancestors.Value() = std::move(srcs);
1180
0
      return;
1181
0
1182
0
    case nsIContentSecurityPolicy::WEB_MANIFEST_SRC_DIRECTIVE:
1183
0
      outCSP.mManifest_src.Construct();
1184
0
      outCSP.mManifest_src.Value() = std::move(srcs);
1185
0
      return;
1186
0
    // not supporting REFLECTED_XSS_DIRECTIVE
1187
0
1188
0
    case nsIContentSecurityPolicy::BASE_URI_DIRECTIVE:
1189
0
      outCSP.mBase_uri.Construct();
1190
0
      outCSP.mBase_uri.Value() = std::move(srcs);
1191
0
      return;
1192
0
1193
0
    case nsIContentSecurityPolicy::FORM_ACTION_DIRECTIVE:
1194
0
      outCSP.mForm_action.Construct();
1195
0
      outCSP.mForm_action.Value() = std::move(srcs);
1196
0
      return;
1197
0
1198
0
    case nsIContentSecurityPolicy::BLOCK_ALL_MIXED_CONTENT:
1199
0
      outCSP.mBlock_all_mixed_content.Construct();
1200
0
      // does not have any srcs
1201
0
      return;
1202
0
1203
0
    case nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE:
1204
0
      outCSP.mUpgrade_insecure_requests.Construct();
1205
0
      // does not have any srcs
1206
0
      return;
1207
0
1208
0
    case nsIContentSecurityPolicy::CHILD_SRC_DIRECTIVE:
1209
0
      outCSP.mChild_src.Construct();
1210
0
      outCSP.mChild_src.Value() = std::move(srcs);
1211
0
      return;
1212
0
1213
0
    case nsIContentSecurityPolicy::SANDBOX_DIRECTIVE:
1214
0
      outCSP.mSandbox.Construct();
1215
0
      outCSP.mSandbox.Value() = std::move(srcs);
1216
0
      return;
1217
0
1218
0
    case nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE:
1219
0
      outCSP.mWorker_src.Construct();
1220
0
      outCSP.mWorker_src.Value() = std::move(srcs);
1221
0
      return;
1222
0
1223
0
    // REQUIRE_SRI_FOR is handled in nsCSPPolicy::toDomCSPStruct()
1224
0
1225
0
    default:
1226
0
      NS_ASSERTION(false, "cannot find directive to convert CSP to JSON");
1227
0
  }
1228
0
}
1229
1230
1231
bool
1232
nsCSPDirective::restrictsContentType(nsContentPolicyType aContentType) const
1233
0
{
1234
0
  // make sure we do not check for the default src before any other sources
1235
0
  if (isDefaultDirective()) {
1236
0
    return false;
1237
0
  }
1238
0
  return mDirective == CSP_ContentTypeToDirective(aContentType);
1239
0
}
1240
1241
void
1242
nsCSPDirective::getReportURIs(nsTArray<nsString> &outReportURIs) const
1243
0
{
1244
0
  NS_ASSERTION((mDirective == nsIContentSecurityPolicy::REPORT_URI_DIRECTIVE), "not a report-uri directive");
1245
0
1246
0
  // append uris
1247
0
  nsString tmpReportURI;
1248
0
  for (uint32_t i = 0; i < mSrcs.Length(); i++) {
1249
0
    tmpReportURI.Truncate();
1250
0
    mSrcs[i]->toString(tmpReportURI);
1251
0
    outReportURIs.AppendElement(tmpReportURI);
1252
0
  }
1253
0
}
1254
1255
bool
1256
nsCSPDirective::visitSrcs(nsCSPSrcVisitor* aVisitor) const
1257
0
{
1258
0
  for (uint32_t i = 0; i < mSrcs.Length(); i++) {
1259
0
    if (!mSrcs[i]->visit(aVisitor)) {
1260
0
      return false;
1261
0
    }
1262
0
  }
1263
0
  return true;
1264
0
}
1265
1266
bool nsCSPDirective::equals(CSPDirective aDirective) const
1267
39.6k
{
1268
39.6k
  return (mDirective == aDirective);
1269
39.6k
}
1270
1271
void
1272
nsCSPDirective::getDirName(nsAString& outStr) const
1273
0
{
1274
0
  outStr.AppendASCII(CSP_CSPDirectiveToString(mDirective));
1275
0
}
1276
1277
bool
1278
nsCSPDirective::hasReportSampleKeyword() const
1279
0
{
1280
0
  for (nsCSPBaseSrc* src : mSrcs) {
1281
0
    if (src->isReportSample()) {
1282
0
      return true;
1283
0
    }
1284
0
  }
1285
0
1286
0
  return false;
1287
0
}
1288
1289
/* =============== nsCSPChildSrcDirective ============= */
1290
1291
nsCSPChildSrcDirective::nsCSPChildSrcDirective(CSPDirective aDirective)
1292
  : nsCSPDirective(aDirective)
1293
  , mRestrictFrames(false)
1294
  , mRestrictWorkers(false)
1295
44
{
1296
44
}
1297
1298
nsCSPChildSrcDirective::~nsCSPChildSrcDirective()
1299
{
1300
}
1301
1302
bool nsCSPChildSrcDirective::restrictsContentType(nsContentPolicyType aContentType) const
1303
0
{
1304
0
  if (aContentType == nsIContentPolicy::TYPE_SUBDOCUMENT) {
1305
0
    return mRestrictFrames;
1306
0
  }
1307
0
  if (aContentType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
1308
0
      aContentType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER ||
1309
0
      aContentType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER) {
1310
0
    return mRestrictWorkers;
1311
0
  }
1312
0
  return false;
1313
0
}
1314
1315
bool nsCSPChildSrcDirective::equals(CSPDirective aDirective) const
1316
3.11k
{
1317
3.11k
  if (aDirective == nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE) {
1318
501
    return mRestrictFrames;
1319
501
  }
1320
2.61k
  if (aDirective == nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE) {
1321
1.07k
    return mRestrictWorkers;
1322
1.07k
  }
1323
1.54k
  return (mDirective == aDirective);
1324
1.54k
}
1325
1326
/* =============== nsCSPScriptSrcDirective ============= */
1327
1328
nsCSPScriptSrcDirective::nsCSPScriptSrcDirective(CSPDirective aDirective)
1329
  : nsCSPDirective(aDirective)
1330
  , mRestrictWorkers(false)
1331
89
{
1332
89
}
1333
1334
nsCSPScriptSrcDirective::~nsCSPScriptSrcDirective()
1335
{
1336
}
1337
1338
bool nsCSPScriptSrcDirective::restrictsContentType(nsContentPolicyType aContentType) const
1339
0
{
1340
0
  if (aContentType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
1341
0
      aContentType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER ||
1342
0
      aContentType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER) {
1343
0
    return mRestrictWorkers;
1344
0
  }
1345
0
  return mDirective == CSP_ContentTypeToDirective(aContentType);
1346
0
}
1347
1348
bool nsCSPScriptSrcDirective::equals(CSPDirective aDirective) const
1349
1.28k
{
1350
1.28k
  if (aDirective == nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE) {
1351
560
    return mRestrictWorkers;
1352
560
  }
1353
728
  return (mDirective == aDirective);
1354
728
}
1355
1356
/* =============== nsBlockAllMixedContentDirective ============= */
1357
1358
nsBlockAllMixedContentDirective::nsBlockAllMixedContentDirective(CSPDirective aDirective)
1359
: nsCSPDirective(aDirective)
1360
3
{
1361
3
}
1362
1363
nsBlockAllMixedContentDirective::~nsBlockAllMixedContentDirective()
1364
{
1365
}
1366
1367
void
1368
nsBlockAllMixedContentDirective::toString(nsAString& outStr) const
1369
0
{
1370
0
  outStr.AppendASCII(CSP_CSPDirectiveToString(
1371
0
    nsIContentSecurityPolicy::BLOCK_ALL_MIXED_CONTENT));
1372
0
}
1373
1374
void
1375
nsBlockAllMixedContentDirective::getDirName(nsAString& outStr) const
1376
0
{
1377
0
  outStr.AppendASCII(CSP_CSPDirectiveToString(
1378
0
    nsIContentSecurityPolicy::BLOCK_ALL_MIXED_CONTENT));
1379
0
}
1380
1381
/* =============== nsUpgradeInsecureDirective ============= */
1382
1383
nsUpgradeInsecureDirective::nsUpgradeInsecureDirective(CSPDirective aDirective)
1384
: nsCSPDirective(aDirective)
1385
5
{
1386
5
}
1387
1388
nsUpgradeInsecureDirective::~nsUpgradeInsecureDirective()
1389
{
1390
}
1391
1392
void
1393
nsUpgradeInsecureDirective::toString(nsAString& outStr) const
1394
0
{
1395
0
  outStr.AppendASCII(CSP_CSPDirectiveToString(
1396
0
    nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE));
1397
0
}
1398
1399
void
1400
nsUpgradeInsecureDirective::getDirName(nsAString& outStr) const
1401
0
{
1402
0
  outStr.AppendASCII(CSP_CSPDirectiveToString(
1403
0
    nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE));
1404
0
}
1405
1406
/* ===== nsRequireSRIForDirective ========================= */
1407
1408
nsRequireSRIForDirective::nsRequireSRIForDirective(CSPDirective aDirective)
1409
: nsCSPDirective(aDirective)
1410
0
{
1411
0
}
1412
1413
nsRequireSRIForDirective::~nsRequireSRIForDirective()
1414
0
{
1415
0
}
1416
1417
void
1418
nsRequireSRIForDirective::toString(nsAString &outStr) const
1419
0
{
1420
0
  outStr.AppendASCII(CSP_CSPDirectiveToString(
1421
0
    nsIContentSecurityPolicy::REQUIRE_SRI_FOR));
1422
0
  for (uint32_t i = 0; i < mTypes.Length(); i++) {
1423
0
    if (mTypes[i] == nsIContentPolicy::TYPE_SCRIPT) {
1424
0
      outStr.AppendLiteral(" script");
1425
0
    }
1426
0
    else if (mTypes[i] == nsIContentPolicy::TYPE_STYLESHEET) {
1427
0
      outStr.AppendLiteral(" style");
1428
0
    }
1429
0
  }
1430
0
}
1431
1432
bool
1433
nsRequireSRIForDirective::hasType(nsContentPolicyType aType) const
1434
0
{
1435
0
  for (uint32_t i = 0; i < mTypes.Length(); i++) {
1436
0
    if (mTypes[i] == aType) {
1437
0
      return true;
1438
0
    }
1439
0
  }
1440
0
  return false;
1441
0
}
1442
1443
bool
1444
nsRequireSRIForDirective::restrictsContentType(const nsContentPolicyType aType) const
1445
0
{
1446
0
  return this->hasType(aType);
1447
0
}
1448
1449
bool
1450
nsRequireSRIForDirective::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
1451
                                 bool aParserCreated) const
1452
0
{
1453
0
  // can only disallow CSP_REQUIRE_SRI_FOR.
1454
0
  return (aKeyword != CSP_REQUIRE_SRI_FOR);
1455
0
}
1456
1457
void
1458
nsRequireSRIForDirective::getDirName(nsAString& outStr) const
1459
0
{
1460
0
  outStr.AppendASCII(CSP_CSPDirectiveToString(
1461
0
    nsIContentSecurityPolicy::REQUIRE_SRI_FOR));
1462
0
}
1463
1464
/* ===== nsCSPPolicy ========================= */
1465
1466
nsCSPPolicy::nsCSPPolicy()
1467
  : mUpgradeInsecDir(nullptr)
1468
  , mReportOnly(false)
1469
5.77k
{
1470
5.77k
  CSPUTILSLOG(("nsCSPPolicy::nsCSPPolicy"));
1471
5.77k
}
1472
1473
nsCSPPolicy::~nsCSPPolicy()
1474
5.77k
{
1475
5.77k
  CSPUTILSLOG(("nsCSPPolicy::~nsCSPPolicy"));
1476
5.77k
1477
11.0k
  for (uint32_t i = 0; i < mDirectives.Length(); i++) {
1478
5.27k
    delete mDirectives[i];
1479
5.27k
  }
1480
5.77k
}
1481
1482
bool
1483
nsCSPPolicy::permits(CSPDirective aDir,
1484
                     nsIURI* aUri,
1485
                     bool aSpecific) const
1486
0
{
1487
0
  nsString outp;
1488
0
  return this->permits(aDir, aUri, EmptyString(), false, aSpecific, false, outp);
1489
0
}
1490
1491
bool
1492
nsCSPPolicy::permits(CSPDirective aDir,
1493
                     nsIURI* aUri,
1494
                     const nsAString& aNonce,
1495
                     bool aWasRedirected,
1496
                     bool aSpecific,
1497
                     bool aParserCreated,
1498
                     nsAString& outViolatedDirective) const
1499
0
{
1500
0
  if (CSPUTILSLOGENABLED()) {
1501
0
    CSPUTILSLOG(("nsCSPPolicy::permits, aUri: %s, aDir: %d, aSpecific: %s",
1502
0
                 aUri->GetSpecOrDefault().get(), aDir,
1503
0
                 aSpecific ? "true" : "false"));
1504
0
  }
1505
0
1506
0
  NS_ASSERTION(aUri, "permits needs an uri to perform the check!");
1507
0
  outViolatedDirective.Truncate();
1508
0
1509
0
  nsCSPDirective* defaultDir = nullptr;
1510
0
1511
0
  // Try to find a relevant directive
1512
0
  // These directive arrays are short (1-5 elements), not worth using a hashtable.
1513
0
  for (uint32_t i = 0; i < mDirectives.Length(); i++) {
1514
0
    if (mDirectives[i]->equals(aDir)) {
1515
0
      if (!mDirectives[i]->permits(aUri, aNonce, aWasRedirected, mReportOnly,
1516
0
                                   mUpgradeInsecDir, aParserCreated)) {
1517
0
        mDirectives[i]->getDirName(outViolatedDirective);
1518
0
        return false;
1519
0
      }
1520
0
      return true;
1521
0
    }
1522
0
    if (mDirectives[i]->isDefaultDirective()) {
1523
0
      defaultDir = mDirectives[i];
1524
0
    }
1525
0
  }
1526
0
1527
0
  // If the above loop runs through, we haven't found a matching directive.
1528
0
  // Avoid relooping, just store the result of default-src while looping.
1529
0
  if (!aSpecific && defaultDir) {
1530
0
    if (!defaultDir->permits(aUri, aNonce, aWasRedirected, mReportOnly,
1531
0
                             mUpgradeInsecDir, aParserCreated)) {
1532
0
      defaultDir->getDirName(outViolatedDirective);
1533
0
      return false;
1534
0
    }
1535
0
    return true;
1536
0
  }
1537
0
1538
0
  // Nothing restricts this, so we're allowing the load
1539
0
  // See bug 764937
1540
0
  return true;
1541
0
}
1542
1543
bool
1544
nsCSPPolicy::allows(nsContentPolicyType aContentType,
1545
                    enum CSPKeyword aKeyword,
1546
                    const nsAString& aHashOrNonce,
1547
                    bool aParserCreated) const
1548
0
{
1549
0
  CSPUTILSLOG(("nsCSPPolicy::allows, aKeyWord: %s, a HashOrNonce: %s",
1550
0
              CSP_EnumToUTF8Keyword(aKeyword),
1551
0
              NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
1552
0
1553
0
  nsCSPDirective* defaultDir = nullptr;
1554
0
1555
0
  // Try to find a matching directive
1556
0
  for (uint32_t i = 0; i < mDirectives.Length(); i++) {
1557
0
    if (mDirectives[i]->restrictsContentType(aContentType)) {
1558
0
      if (mDirectives[i]->allows(aKeyword, aHashOrNonce, aParserCreated)) {
1559
0
        return true;
1560
0
      }
1561
0
      return false;
1562
0
    }
1563
0
    if (mDirectives[i]->isDefaultDirective()) {
1564
0
      defaultDir = mDirectives[i];
1565
0
    }
1566
0
  }
1567
0
1568
0
  // {nonce,hash}-source should not consult default-src:
1569
0
  //   * return false if default-src is specified
1570
0
  //   * but allow the load if default-src is *not* specified (Bug 1198422)
1571
0
  if (aKeyword == CSP_NONCE || aKeyword == CSP_HASH) {
1572
0
     if (!defaultDir) {
1573
0
       return true;
1574
0
     }
1575
0
    return false;
1576
0
  }
1577
0
1578
0
  // If the above loop runs through, we haven't found a matching directive.
1579
0
  // Avoid relooping, just store the result of default-src while looping.
1580
0
  if (defaultDir) {
1581
0
    return defaultDir->allows(aKeyword, aHashOrNonce, aParserCreated);
1582
0
  }
1583
0
1584
0
  // Allowing the load; see Bug 885433
1585
0
  // a) inline scripts (also unsafe eval) should only be blocked
1586
0
  //    if there is a [script-src] or [default-src]
1587
0
  // b) inline styles should only be blocked
1588
0
  //    if there is a [style-src] or [default-src]
1589
0
  return true;
1590
0
}
1591
1592
bool
1593
nsCSPPolicy::allows(nsContentPolicyType aContentType,
1594
                    enum CSPKeyword aKeyword) const
1595
0
{
1596
0
  return allows(aContentType, aKeyword, NS_LITERAL_STRING(""), false);
1597
0
}
1598
1599
void
1600
nsCSPPolicy::toString(nsAString& outStr) const
1601
0
{
1602
0
  uint32_t length = mDirectives.Length();
1603
0
  for (uint32_t i = 0; i < length; ++i) {
1604
0
    mDirectives[i]->toString(outStr);
1605
0
    if (i != (length - 1)) {
1606
0
      outStr.AppendLiteral("; ");
1607
0
    }
1608
0
  }
1609
0
}
1610
1611
void
1612
nsCSPPolicy::toDomCSPStruct(mozilla::dom::CSP& outCSP) const
1613
0
{
1614
0
  outCSP.mReport_only = mReportOnly;
1615
0
1616
0
  for (uint32_t i = 0; i < mDirectives.Length(); ++i) {
1617
0
    mDirectives[i]->toDomCSPStruct(outCSP);
1618
0
  }
1619
0
}
1620
1621
bool
1622
nsCSPPolicy::hasDirective(CSPDirective aDir) const
1623
17.3k
{
1624
31.6k
  for (uint32_t i = 0; i < mDirectives.Length(); i++) {
1625
17.8k
    if (mDirectives[i]->equals(aDir)) {
1626
3.57k
      return true;
1627
3.57k
    }
1628
17.8k
  }
1629
17.3k
  return false;
1630
17.3k
}
1631
1632
/*
1633
 * Use this function only after ::allows() returned 'false'. Most and
1634
 * foremost it's used to get the violated directive before sending reports.
1635
 * The parameter outDirective is the equivalent of 'outViolatedDirective'
1636
 * for the ::permits() function family.
1637
 */
1638
void
1639
nsCSPPolicy::getDirectiveStringAndReportSampleForContentType(nsContentPolicyType aContentType,
1640
                                                             nsAString& outDirective,
1641
                                                             bool* aReportSample) const
1642
0
{
1643
0
  MOZ_ASSERT(aReportSample);
1644
0
  *aReportSample = false;
1645
0
1646
0
  nsCSPDirective* defaultDir = nullptr;
1647
0
  for (uint32_t i = 0; i < mDirectives.Length(); i++) {
1648
0
    if (mDirectives[i]->restrictsContentType(aContentType)) {
1649
0
      mDirectives[i]->getDirName(outDirective);
1650
0
      *aReportSample = mDirectives[i]->hasReportSampleKeyword();
1651
0
      return;
1652
0
    }
1653
0
    if (mDirectives[i]->isDefaultDirective()) {
1654
0
      defaultDir = mDirectives[i];
1655
0
    }
1656
0
  }
1657
0
  // if we haven't found a matching directive yet,
1658
0
  // the contentType must be restricted by the default directive
1659
0
  if (defaultDir) {
1660
0
    defaultDir->getDirName(outDirective);
1661
0
    *aReportSample = defaultDir->hasReportSampleKeyword();
1662
0
    return;
1663
0
  }
1664
0
  NS_ASSERTION(false, "Can not query directive string for contentType!");
1665
0
  outDirective.AppendLiteral("couldNotQueryViolatedDirective");
1666
0
}
1667
1668
void
1669
nsCSPPolicy::getDirectiveAsString(CSPDirective aDir, nsAString& outDirective) const
1670
0
{
1671
0
  for (uint32_t i = 0; i < mDirectives.Length(); i++) {
1672
0
    if (mDirectives[i]->equals(aDir)) {
1673
0
      mDirectives[i]->toString(outDirective);
1674
0
      return;
1675
0
    }
1676
0
  }
1677
0
}
1678
1679
/*
1680
 * Helper function that returns the underlying bit representation of sandbox
1681
 * flags. The function returns SANDBOXED_NONE if there are no sandbox
1682
 * directives.
1683
 */
1684
uint32_t
1685
nsCSPPolicy::getSandboxFlags() const
1686
0
{
1687
0
  for (uint32_t i = 0; i < mDirectives.Length(); i++) {
1688
0
    if (mDirectives[i]->equals(nsIContentSecurityPolicy::SANDBOX_DIRECTIVE)) {
1689
0
      nsAutoString flags;
1690
0
      mDirectives[i]->toString(flags);
1691
0
1692
0
      if (flags.IsEmpty()) {
1693
0
        return SANDBOX_ALL_FLAGS;
1694
0
      }
1695
0
1696
0
      nsAttrValue attr;
1697
0
      attr.ParseAtomArray(flags);
1698
0
1699
0
      return nsContentUtils::ParseSandboxAttributeToFlags(&attr);
1700
0
    }
1701
0
  }
1702
0
1703
0
  return SANDBOXED_NONE;
1704
0
}
1705
1706
void
1707
nsCSPPolicy::getReportURIs(nsTArray<nsString>& outReportURIs) const
1708
0
{
1709
0
  for (uint32_t i = 0; i < mDirectives.Length(); i++) {
1710
0
    if (mDirectives[i]->equals(nsIContentSecurityPolicy::REPORT_URI_DIRECTIVE)) {
1711
0
      mDirectives[i]->getReportURIs(outReportURIs);
1712
0
      return;
1713
0
    }
1714
0
  }
1715
0
}
1716
1717
bool
1718
nsCSPPolicy::visitDirectiveSrcs(CSPDirective aDir, nsCSPSrcVisitor* aVisitor) const
1719
0
{
1720
0
  for (uint32_t i = 0; i < mDirectives.Length(); i++) {
1721
0
    if (mDirectives[i]->equals(aDir)) {
1722
0
      return mDirectives[i]->visitSrcs(aVisitor);
1723
0
    }
1724
0
  }
1725
0
  return false;
1726
0
}
1727
1728
bool
1729
nsCSPPolicy::requireSRIForType(nsContentPolicyType aContentType)
1730
0
{
1731
0
  for (uint32_t i = 0; i < mDirectives.Length(); i++) {
1732
0
    if (mDirectives[i]->equals(nsIContentSecurityPolicy::REQUIRE_SRI_FOR)) {
1733
0
      return static_cast<nsRequireSRIForDirective*>(mDirectives[i])->hasType(aContentType);
1734
0
    }
1735
0
  }
1736
0
  return false;
1737
0
}