helmet-core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SECURITY.md ADDED
@@ -0,0 +1,11 @@
1
+ # Security issue reporting & disclosure process
2
+
3
+ Please reach out if you think you've found a security issue.
4
+
5
+ Email Evan Hahn at <me@evanhahn.com>, on Signal at [EvanHahn.64](https://signal.me/#eu/vDide_HmUgHnNa0usMXq8oHAA0gnl5dzCqDeHyXhkeIbIiOcPVhCZKXIZteSqoc8), or [in other ways](https://evanhahn.com/contact).
6
+
7
+ My playbook for security issues:
8
+
9
+ - Acknowledge and address the concern as soon as possible
10
+ - Issue advisories (CVEs, for example) as needed. Public disclosure may be embargoed to give people time to update
11
+ - Consider patching non-current major versions depending on popularity and severity
package/index.cjs ADDED
@@ -0,0 +1,615 @@
1
+ "use strict"
2
+
3
+ Object.defineProperties(exports, {__esModule: {value: true}, [Symbol.toStringTag]: {value: "Module"}})
4
+
5
+ const dashify = str => str.replace(/[A-Z]/g, capitalLetter => "-" + capitalLetter.toLowerCase())
6
+ const errify = err => (err instanceof Error ? err : new Error(String(err)))
7
+ const isString = value => typeof value === "string"
8
+ const throwErrorIfExists = err => {
9
+ if (err) throw err
10
+ }
11
+
12
+ const dangerouslyDisableDefaultSrc = Symbol("dangerouslyDisableDefaultSrc")
13
+ const SHOULD_BE_QUOTED = new Set(["none", "self", "strict-dynamic", "report-sample", "inline-speculation-rules", "unsafe-inline", "unsafe-eval", "unsafe-hashes", "wasm-unsafe-eval"])
14
+ const getDefaultDirectives = () => ({
15
+ "default-src": ["'self'"],
16
+ "base-uri": ["'self'"],
17
+ "font-src": ["'self'", "https:", "data:"],
18
+ "form-action": ["'self'"],
19
+ "frame-ancestors": ["'self'"],
20
+ "img-src": ["'self'", "data:"],
21
+ "object-src": ["'none'"],
22
+ "script-src": ["'self'"],
23
+ "script-src-attr": ["'none'"],
24
+ "style-src": ["'self'", "https:", "'unsafe-inline'"],
25
+ "upgrade-insecure-requests": []
26
+ })
27
+ const parseDirectiveName = rawDirectiveName => {
28
+ if (rawDirectiveName.length === 0 || !/^[a-z](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/.test(rawDirectiveName)) {
29
+ throw new Error(`Content-Security-Policy received an invalid directive name ${JSON.stringify(rawDirectiveName)}`)
30
+ }
31
+ return dashify(rawDirectiveName)
32
+ }
33
+ const getDirectiveValueValidationError = (directiveName, directiveValue) => (/;|,/.test(directiveValue) ? new Error(`Content-Security-Policy received an invalid directive value for ${JSON.stringify(directiveName)}`) : null)
34
+ const getDirectiveValueEntryValidationError = (directiveName, directiveValueEntry) => (SHOULD_BE_QUOTED.has(directiveValueEntry) || directiveValueEntry.startsWith("nonce-") || directiveValueEntry.startsWith("sha256-") || directiveValueEntry.startsWith("sha384-") || directiveValueEntry.startsWith("sha512-") ? new Error(`Content-Security-Policy received an invalid directive value for ${JSON.stringify(directiveName)}. ${JSON.stringify(directiveValueEntry)} should be quoted`) : null)
35
+ const stringifyDirectiveValue = directiveValue => {
36
+ if (Array.isArray(directiveValue)) {
37
+ return directiveValue.every(isString) ? directiveValue.join(" ") : null
38
+ }
39
+ if (directiveValue instanceof Set) {
40
+ return stringifyDirectiveValue(Array.from(directiveValue))
41
+ }
42
+ return null
43
+ }
44
+ const parseDirectives = ({useDefaults = true, directives: rawDirectives = {}}) => {
45
+ const result = new Map(useDefaults ? Object.entries(getDefaultDirectives()) : [])
46
+ let hasDisabledDefaultSrc = false
47
+ const directiveNamesSeen = new Set()
48
+ for (const rawDirectiveName in rawDirectives) {
49
+ if (!Object.hasOwn(rawDirectives, rawDirectiveName)) {
50
+ continue
51
+ }
52
+ const directiveName = parseDirectiveName(rawDirectiveName)
53
+ if (directiveNamesSeen.has(directiveName)) {
54
+ throw new Error(`Content-Security-Policy received a duplicate directive ${JSON.stringify(directiveName)}`)
55
+ }
56
+ directiveNamesSeen.add(directiveName)
57
+ const rawDirectiveValue = rawDirectives[rawDirectiveName]
58
+ let directiveValue
59
+ if (rawDirectiveValue === null) {
60
+ if (directiveName === "default-src") {
61
+ throw new Error("Content-Security-Policy needs a default-src but it was set to `null`. If you really want to disable it, set it to `contentSecurityPolicy.dangerouslyDisableDefaultSrc`.")
62
+ }
63
+ result.delete(directiveName)
64
+ continue
65
+ } else if (typeof rawDirectiveValue === "string") {
66
+ directiveValue = [rawDirectiveValue]
67
+ } else if (rawDirectiveValue === dangerouslyDisableDefaultSrc) {
68
+ if (directiveName === "default-src") {
69
+ hasDisabledDefaultSrc = true
70
+ result.delete(directiveName)
71
+ continue
72
+ } else {
73
+ throw new Error(`Content-Security-Policy: tried to disable ${JSON.stringify(directiveName)} as if it were default-src; simply omit the key`)
74
+ }
75
+ } else if (rawDirectiveValue) {
76
+ directiveValue = rawDirectiveValue
77
+ } else {
78
+ throw new Error(`Content-Security-Policy received an invalid directive value for ${JSON.stringify(directiveName)}`)
79
+ }
80
+ for (const element of directiveValue) {
81
+ if (typeof element !== "string") continue
82
+ throwErrorIfExists(getDirectiveValueValidationError(directiveName, element) ?? getDirectiveValueEntryValidationError(directiveName, element))
83
+ }
84
+ result.set(directiveName, directiveValue)
85
+ }
86
+ if (!result.size) {
87
+ throw new Error("Content-Security-Policy has no directives. Either set some or disable the header")
88
+ }
89
+ if (!result.has("default-src") && !hasDisabledDefaultSrc) {
90
+ throw new Error("Content-Security-Policy needs a default-src but none was provided. If you really want to disable it, set it to `contentSecurityPolicy.dangerouslyDisableDefaultSrc`.")
91
+ }
92
+ let stringResult = ""
93
+ let shouldUseStringResult = true
94
+ for (const [directiveName, directiveValue] of result) {
95
+ const directiveValueString = stringifyDirectiveValue(directiveValue)
96
+ if (directiveValueString === null) {
97
+ shouldUseStringResult = false
98
+ break
99
+ } else {
100
+ if (stringResult) stringResult += ";"
101
+ stringResult += directiveValueString ? `${directiveName} ${directiveValueString}` : directiveName
102
+ }
103
+ }
104
+ return shouldUseStringResult ? stringResult : result
105
+ }
106
+ function getHeaderValue(req, res, normalizedDirectives) {
107
+ const result = []
108
+ for (const [directiveName, rawDirectiveValue] of normalizedDirectives) {
109
+ let directiveValue = ""
110
+ for (const element of rawDirectiveValue) {
111
+ if (typeof element === "function") {
112
+ let newElement
113
+ try {
114
+ newElement = element(req, res)
115
+ } catch (err) {
116
+ return errify(err)
117
+ }
118
+ const err = getDirectiveValueEntryValidationError(directiveName, newElement)
119
+ if (err) return err
120
+ directiveValue += " " + newElement
121
+ } else {
122
+ directiveValue += " " + element
123
+ }
124
+ }
125
+ if (directiveValue) {
126
+ const err = getDirectiveValueValidationError(directiveName, directiveValue)
127
+ if (err) return err
128
+ result.push(`${directiveName}${directiveValue}`)
129
+ } else {
130
+ result.push(directiveName)
131
+ }
132
+ }
133
+ return result.join(";")
134
+ }
135
+ const contentSecurityPolicy = function contentSecurityPolicy(options = {}) {
136
+ const headerName = options.reportOnly ? "Content-Security-Policy-Report-Only" : "Content-Security-Policy"
137
+ const parsedDirectives = parseDirectives(options)
138
+ // A special case for performance.
139
+ if (typeof parsedDirectives === "string") {
140
+ return function contentSecurityPolicyMiddleware(_req, res, next) {
141
+ res.setHeader(headerName, parsedDirectives)
142
+ next()
143
+ }
144
+ }
145
+ return function contentSecurityPolicyMiddleware(req, res, next) {
146
+ const result = getHeaderValue(req, res, parsedDirectives)
147
+ if (result instanceof Error) {
148
+ next(result)
149
+ } else {
150
+ res.setHeader(headerName, result)
151
+ next()
152
+ }
153
+ }
154
+ }
155
+ contentSecurityPolicy.getDefaultDirectives = getDefaultDirectives
156
+ contentSecurityPolicy.dangerouslyDisableDefaultSrc = dangerouslyDisableDefaultSrc
157
+
158
+ const ALLOWED_POLICIES$2 = new Set(["require-corp", "credentialless", "unsafe-none"])
159
+ function getHeaderValueFromOptions$6({policy = "require-corp"}) {
160
+ if (ALLOWED_POLICIES$2.has(policy)) {
161
+ return policy
162
+ } else {
163
+ throw new Error(`Cross-Origin-Embedder-Policy does not support the ${JSON.stringify(policy)} policy`)
164
+ }
165
+ }
166
+ function crossOriginEmbedderPolicy(options = {}) {
167
+ const headerValue = getHeaderValueFromOptions$6(options)
168
+ return function crossOriginEmbedderPolicyMiddleware(_req, res, next) {
169
+ res.setHeader("Cross-Origin-Embedder-Policy", headerValue)
170
+ next()
171
+ }
172
+ }
173
+
174
+ const ALLOWED_POLICIES$1 = new Set(["same-origin", "same-origin-allow-popups", "noopener-allow-popups", "unsafe-none"])
175
+ function getHeaderValueFromOptions$5({policy = "same-origin"}) {
176
+ if (ALLOWED_POLICIES$1.has(policy)) {
177
+ return policy
178
+ } else {
179
+ throw new Error(`Cross-Origin-Opener-Policy does not support the ${JSON.stringify(policy)} policy`)
180
+ }
181
+ }
182
+ function crossOriginOpenerPolicy(options = {}) {
183
+ const headerValue = getHeaderValueFromOptions$5(options)
184
+ return function crossOriginOpenerPolicyMiddleware(_req, res, next) {
185
+ res.setHeader("Cross-Origin-Opener-Policy", headerValue)
186
+ next()
187
+ }
188
+ }
189
+
190
+ const ALLOWED_POLICIES = new Set(["same-origin", "same-site", "cross-origin"])
191
+ function getHeaderValueFromOptions$4({policy = "same-origin"}) {
192
+ if (ALLOWED_POLICIES.has(policy)) {
193
+ return policy
194
+ } else {
195
+ throw new Error(`Cross-Origin-Resource-Policy does not support the ${JSON.stringify(policy)} policy`)
196
+ }
197
+ }
198
+ function crossOriginResourcePolicy(options = {}) {
199
+ const headerValue = getHeaderValueFromOptions$4(options)
200
+ return function crossOriginResourcePolicyMiddleware(_req, res, next) {
201
+ res.setHeader("Cross-Origin-Resource-Policy", headerValue)
202
+ next()
203
+ }
204
+ }
205
+
206
+ function originAgentCluster() {
207
+ return function originAgentClusterMiddleware(_req, res, next) {
208
+ res.setHeader("Origin-Agent-Cluster", "?1")
209
+ next()
210
+ }
211
+ }
212
+
213
+ const ALLOWED_TOKENS = new Set(["no-referrer", "no-referrer-when-downgrade", "same-origin", "origin", "strict-origin", "origin-when-cross-origin", "strict-origin-when-cross-origin", "unsafe-url", ""])
214
+ function getHeaderValueFromOptions$3({policy = ["no-referrer"]}) {
215
+ const tokens = typeof policy === "string" ? [policy] : policy
216
+ if (tokens.length === 0) {
217
+ throw new Error("Referrer-Policy received no policy tokens")
218
+ }
219
+ const tokensSeen = new Set()
220
+ tokens.forEach(token => {
221
+ if (!ALLOWED_TOKENS.has(token)) {
222
+ throw new Error(`Referrer-Policy received an unexpected policy token ${JSON.stringify(token)}`)
223
+ } else if (tokensSeen.has(token)) {
224
+ throw new Error(`Referrer-Policy received a duplicate policy token ${JSON.stringify(token)}`)
225
+ }
226
+ tokensSeen.add(token)
227
+ })
228
+ return tokens.join(",")
229
+ }
230
+ function referrerPolicy(options = {}) {
231
+ const headerValue = getHeaderValueFromOptions$3(options)
232
+ return function referrerPolicyMiddleware(_req, res, next) {
233
+ res.setHeader("Referrer-Policy", headerValue)
234
+ next()
235
+ }
236
+ }
237
+
238
+ const DEFAULT_MAX_AGE = 365 * 24 * 60 * 60
239
+ function parseMaxAge(value = DEFAULT_MAX_AGE) {
240
+ if (value >= 0 && Number.isFinite(value)) {
241
+ return Math.floor(value)
242
+ } else {
243
+ throw new Error(`Strict-Transport-Security: ${JSON.stringify(value)} is not a valid value for maxAge. Please choose a positive integer.`)
244
+ }
245
+ }
246
+ function getHeaderValueFromOptions$2(options) {
247
+ if ("maxage" in options) {
248
+ throw new Error("Strict-Transport-Security received an unsupported property, `maxage`. Did you mean to pass `maxAge`?")
249
+ }
250
+ if ("includeSubdomains" in options) {
251
+ throw new Error('Strict-Transport-Security middleware should use `includeSubDomains` instead of `includeSubdomains`. (The correct one has an uppercase "D".)')
252
+ }
253
+ const directives = [`max-age=${parseMaxAge(options.maxAge)}`]
254
+ if (options.includeSubDomains === undefined || options.includeSubDomains) {
255
+ directives.push("includeSubDomains")
256
+ }
257
+ if (options.preload) {
258
+ directives.push("preload")
259
+ }
260
+ return directives.join("; ")
261
+ }
262
+ function strictTransportSecurity(options = {}) {
263
+ const headerValue = getHeaderValueFromOptions$2(options)
264
+ return function strictTransportSecurityMiddleware(_req, res, next) {
265
+ res.setHeader("Strict-Transport-Security", headerValue)
266
+ next()
267
+ }
268
+ }
269
+
270
+ function xContentTypeOptions() {
271
+ return function xContentTypeOptionsMiddleware(_req, res, next) {
272
+ res.setHeader("X-Content-Type-Options", "nosniff")
273
+ next()
274
+ }
275
+ }
276
+
277
+ function xDnsPrefetchControl(options = {}) {
278
+ const headerValue = options.allow ? "on" : "off"
279
+ return function xDnsPrefetchControlMiddleware(_req, res, next) {
280
+ res.setHeader("X-DNS-Prefetch-Control", headerValue)
281
+ next()
282
+ }
283
+ }
284
+
285
+ function xDownloadOptions() {
286
+ return function xDownloadOptionsMiddleware(_req, res, next) {
287
+ res.setHeader("X-Download-Options", "noopen")
288
+ next()
289
+ }
290
+ }
291
+
292
+ function getHeaderValueFromOptions$1({action = "sameorigin"}) {
293
+ const normalizedAction = typeof action === "string" ? action.toUpperCase() : action
294
+ switch (normalizedAction) {
295
+ case "SAME-ORIGIN":
296
+ return "SAMEORIGIN"
297
+ case "DENY":
298
+ case "SAMEORIGIN":
299
+ return normalizedAction
300
+ default:
301
+ throw new Error(`X-Frame-Options received an invalid action ${JSON.stringify(action)}`)
302
+ }
303
+ }
304
+ function xFrameOptions(options = {}) {
305
+ const headerValue = getHeaderValueFromOptions$1(options)
306
+ return function xFrameOptionsMiddleware(_req, res, next) {
307
+ res.setHeader("X-Frame-Options", headerValue)
308
+ next()
309
+ }
310
+ }
311
+
312
+ const ALLOWED_PERMITTED_POLICIES = new Set(["none", "master-only", "by-content-type", "all"])
313
+ function getHeaderValueFromOptions({permittedPolicies = "none"}) {
314
+ if (ALLOWED_PERMITTED_POLICIES.has(permittedPolicies)) {
315
+ return permittedPolicies
316
+ } else {
317
+ throw new Error(`X-Permitted-Cross-Domain-Policies does not support ${JSON.stringify(permittedPolicies)}`)
318
+ }
319
+ }
320
+ function xPermittedCrossDomainPolicies(options = {}) {
321
+ const headerValue = getHeaderValueFromOptions(options)
322
+ return function xPermittedCrossDomainPoliciesMiddleware(_req, res, next) {
323
+ res.setHeader("X-Permitted-Cross-Domain-Policies", headerValue)
324
+ next()
325
+ }
326
+ }
327
+
328
+ function xPoweredBy() {
329
+ return function xPoweredByMiddleware(_req, res, next) {
330
+ res.removeHeader("X-Powered-By")
331
+ next()
332
+ }
333
+ }
334
+
335
+ function xXssProtection() {
336
+ return function xXssProtectionMiddleware(_req, res, next) {
337
+ res.setHeader("X-XSS-Protection", "0")
338
+ next()
339
+ }
340
+ }
341
+
342
+ function getMiddlewareFunctionsFromOptions(options) {
343
+ const result = []
344
+ switch (options.contentSecurityPolicy) {
345
+ case undefined:
346
+ case true:
347
+ result.push(contentSecurityPolicy())
348
+ break
349
+ case false:
350
+ break
351
+ default:
352
+ result.push(contentSecurityPolicy(options.contentSecurityPolicy))
353
+ break
354
+ }
355
+ switch (options.crossOriginEmbedderPolicy) {
356
+ case undefined:
357
+ case false:
358
+ break
359
+ case true:
360
+ result.push(crossOriginEmbedderPolicy())
361
+ break
362
+ default:
363
+ result.push(crossOriginEmbedderPolicy(options.crossOriginEmbedderPolicy))
364
+ break
365
+ }
366
+ switch (options.crossOriginOpenerPolicy) {
367
+ case undefined:
368
+ case true:
369
+ result.push(crossOriginOpenerPolicy())
370
+ break
371
+ case false:
372
+ break
373
+ default:
374
+ result.push(crossOriginOpenerPolicy(options.crossOriginOpenerPolicy))
375
+ break
376
+ }
377
+ switch (options.crossOriginResourcePolicy) {
378
+ case undefined:
379
+ case true:
380
+ result.push(crossOriginResourcePolicy())
381
+ break
382
+ case false:
383
+ break
384
+ default:
385
+ result.push(crossOriginResourcePolicy(options.crossOriginResourcePolicy))
386
+ break
387
+ }
388
+ switch (options.originAgentCluster) {
389
+ case undefined:
390
+ case true:
391
+ result.push(originAgentCluster())
392
+ break
393
+ case false:
394
+ break
395
+ default:
396
+ console.warn("Origin-Agent-Cluster does not take options. Remove the property to silence this warning.")
397
+ result.push(originAgentCluster())
398
+ break
399
+ }
400
+ switch (options.referrerPolicy) {
401
+ case undefined:
402
+ case true:
403
+ result.push(referrerPolicy())
404
+ break
405
+ case false:
406
+ break
407
+ default:
408
+ result.push(referrerPolicy(options.referrerPolicy))
409
+ break
410
+ }
411
+ if ("strictTransportSecurity" in options && "hsts" in options) {
412
+ throw new Error("Strict-Transport-Security option was specified twice. Remove the `hsts` option to fix this error.")
413
+ }
414
+ const strictTransportSecurityOption = options.strictTransportSecurity ?? options.hsts
415
+ switch (strictTransportSecurityOption) {
416
+ case undefined:
417
+ case true:
418
+ result.push(strictTransportSecurity())
419
+ break
420
+ case false:
421
+ break
422
+ default:
423
+ result.push(strictTransportSecurity(strictTransportSecurityOption))
424
+ break
425
+ }
426
+ if ("xContentTypeOptions" in options && "noSniff" in options) {
427
+ throw new Error("X-Content-Type-Options option was specified twice. Remove the `noSniff` option to fix this error.")
428
+ }
429
+ const xContentTypeOptionsOption = options.xContentTypeOptions ?? options.noSniff
430
+ switch (xContentTypeOptionsOption) {
431
+ case undefined:
432
+ case true:
433
+ result.push(xContentTypeOptions())
434
+ break
435
+ case false:
436
+ break
437
+ default:
438
+ console.warn("X-Content-Type-Options does not take options. Remove the property to silence this warning.")
439
+ result.push(xContentTypeOptions())
440
+ break
441
+ }
442
+ if ("xDnsPrefetchControl" in options && "dnsPrefetchControl" in options) {
443
+ throw new Error("X-DNS-Prefetch-Control option was specified twice. Remove the `dnsPrefetchControl` option to fix this error.")
444
+ }
445
+ const xDnsPrefetchControlOption = options.xDnsPrefetchControl ?? options.dnsPrefetchControl
446
+ switch (xDnsPrefetchControlOption) {
447
+ case undefined:
448
+ case true:
449
+ result.push(xDnsPrefetchControl())
450
+ break
451
+ case false:
452
+ break
453
+ default:
454
+ result.push(xDnsPrefetchControl(xDnsPrefetchControlOption))
455
+ break
456
+ }
457
+ if ("xDownloadOptions" in options && "ieNoOpen" in options) {
458
+ throw new Error("X-Download-Options option was specified twice. Remove the `ieNoOpen` option to fix this error.")
459
+ }
460
+ const xDownloadOptionsOption = options.xDownloadOptions ?? options.ieNoOpen
461
+ switch (xDownloadOptionsOption) {
462
+ case undefined:
463
+ case true:
464
+ result.push(xDownloadOptions())
465
+ break
466
+ case false:
467
+ break
468
+ default:
469
+ console.warn("X-Download-Options does not take options. Remove the property to silence this warning.")
470
+ result.push(xDownloadOptions())
471
+ break
472
+ }
473
+ if ("xFrameOptions" in options && "frameguard" in options) {
474
+ throw new Error("X-Frame-Options option was specified twice. Remove the `frameguard` option to fix this error.")
475
+ }
476
+ const xFrameOptionsOption = options.xFrameOptions ?? options.frameguard
477
+ switch (xFrameOptionsOption) {
478
+ case undefined:
479
+ case true:
480
+ result.push(xFrameOptions())
481
+ break
482
+ case false:
483
+ break
484
+ default:
485
+ result.push(xFrameOptions(xFrameOptionsOption))
486
+ break
487
+ }
488
+ if ("xPermittedCrossDomainPolicies" in options && "permittedCrossDomainPolicies" in options) {
489
+ throw new Error("X-Permitted-Cross-Domain-Policies option was specified twice. Remove the `permittedCrossDomainPolicies` option to fix this error.")
490
+ }
491
+ const xPermittedCrossDomainPoliciesOption = options.xPermittedCrossDomainPolicies ?? options.permittedCrossDomainPolicies
492
+ switch (xPermittedCrossDomainPoliciesOption) {
493
+ case undefined:
494
+ case true:
495
+ result.push(xPermittedCrossDomainPolicies())
496
+ break
497
+ case false:
498
+ break
499
+ default:
500
+ result.push(xPermittedCrossDomainPolicies(xPermittedCrossDomainPoliciesOption))
501
+ break
502
+ }
503
+ if ("xPoweredBy" in options && "hidePoweredBy" in options) {
504
+ throw new Error("X-Powered-By option was specified twice. Remove the `hidePoweredBy` option to fix this error.")
505
+ }
506
+ const xPoweredByOption = options.xPoweredBy ?? options.hidePoweredBy
507
+ switch (xPoweredByOption) {
508
+ case undefined:
509
+ case true:
510
+ result.push(xPoweredBy())
511
+ break
512
+ case false:
513
+ break
514
+ default:
515
+ console.warn("X-Powered-By does not take options. Remove the property to silence this warning.")
516
+ result.push(xPoweredBy())
517
+ break
518
+ }
519
+ if ("xXssProtection" in options && "xssFilter" in options) {
520
+ throw new Error("X-XSS-Protection option was specified twice. Remove the `xssFilter` option to fix this error.")
521
+ }
522
+ const xXssProtectionOption = options.xXssProtection ?? options.xssFilter
523
+ switch (xXssProtectionOption) {
524
+ case undefined:
525
+ case true:
526
+ result.push(xXssProtection())
527
+ break
528
+ case false:
529
+ break
530
+ default:
531
+ console.warn("X-XSS-Protection does not take options. Remove the property to silence this warning.")
532
+ result.push(xXssProtection())
533
+ break
534
+ }
535
+ return result
536
+ }
537
+ const helmet = Object.assign(
538
+ function helmet(options = {}) {
539
+ // People should be able to pass an options object with no prototype,
540
+ // so we want this optional chaining.
541
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
542
+ if (options.constructor?.name === "IncomingMessage") {
543
+ throw new Error("It appears you have done something like `app.use(helmet)`, but it should be `app.use(helmet())`.")
544
+ }
545
+ const middlewareFunctions = getMiddlewareFunctionsFromOptions(options)
546
+ return function helmetMiddleware(req, res, next) {
547
+ let middlewareIndex = 0
548
+ ;(function internalNext(err) {
549
+ if (err) {
550
+ next(err)
551
+ return
552
+ }
553
+ const middlewareFunction = middlewareFunctions[middlewareIndex]
554
+ if (middlewareFunction) {
555
+ middlewareIndex++
556
+ middlewareFunction(req, res, internalNext)
557
+ } else {
558
+ next()
559
+ }
560
+ })()
561
+ }
562
+ },
563
+ {
564
+ contentSecurityPolicy,
565
+ crossOriginEmbedderPolicy,
566
+ crossOriginOpenerPolicy,
567
+ crossOriginResourcePolicy,
568
+ originAgentCluster,
569
+ referrerPolicy,
570
+ strictTransportSecurity,
571
+ xContentTypeOptions,
572
+ xDnsPrefetchControl,
573
+ xDownloadOptions,
574
+ xFrameOptions,
575
+ xPermittedCrossDomainPolicies,
576
+ xPoweredBy,
577
+ xXssProtection,
578
+ // Legacy aliases
579
+ dnsPrefetchControl: xDnsPrefetchControl,
580
+ xssFilter: xXssProtection,
581
+ permittedCrossDomainPolicies: xPermittedCrossDomainPolicies,
582
+ ieNoOpen: xDownloadOptions,
583
+ noSniff: xContentTypeOptions,
584
+ frameguard: xFrameOptions,
585
+ hidePoweredBy: xPoweredBy,
586
+ hsts: strictTransportSecurity
587
+ }
588
+ )
589
+
590
+ exports.contentSecurityPolicy = contentSecurityPolicy
591
+ exports.crossOriginEmbedderPolicy = crossOriginEmbedderPolicy
592
+ exports.crossOriginOpenerPolicy = crossOriginOpenerPolicy
593
+ exports.crossOriginResourcePolicy = crossOriginResourcePolicy
594
+ exports.default = helmet
595
+ exports.dnsPrefetchControl = xDnsPrefetchControl
596
+ exports.frameguard = xFrameOptions
597
+ exports.hidePoweredBy = xPoweredBy
598
+ exports.hsts = strictTransportSecurity
599
+ exports.ieNoOpen = xDownloadOptions
600
+ exports.noSniff = xContentTypeOptions
601
+ exports.originAgentCluster = originAgentCluster
602
+ exports.permittedCrossDomainPolicies = xPermittedCrossDomainPolicies
603
+ exports.referrerPolicy = referrerPolicy
604
+ exports.strictTransportSecurity = strictTransportSecurity
605
+ exports.xContentTypeOptions = xContentTypeOptions
606
+ exports.xDnsPrefetchControl = xDnsPrefetchControl
607
+ exports.xDownloadOptions = xDownloadOptions
608
+ exports.xFrameOptions = xFrameOptions
609
+ exports.xPermittedCrossDomainPolicies = xPermittedCrossDomainPolicies
610
+ exports.xPoweredBy = xPoweredBy
611
+ exports.xXssProtection = xXssProtection
612
+ exports.xssFilter = xXssProtection
613
+
614
+ module.exports = exports.default
615
+ module.exports.default = module.exports