https://project.mdnd-it.cc/work_packages/94
This commit is contained in:
2025-08-23 04:25:28 +02:00
parent 725516ad6c
commit 19cfa031d0
25823 changed files with 1095587 additions and 2801760 deletions
+34 -40
View File
@@ -1,5 +1,6 @@
const dangerouslyDisableDefaultSrc = Symbol("dangerouslyDisableDefaultSrc")
const DEFAULT_DIRECTIVES = {
const SHOULD_BE_QUOTED = new Set(["none", "self", "strict-dynamic", "report-sample", "inline-speculation-rules", "unsafe-inline", "unsafe-eval", "unsafe-hashes", "wasm-unsafe-eval"])
const getDefaultDirectives = () => ({
"default-src": ["'self'"],
"base-uri": ["'self'"],
"font-src": ["'self'", "https:", "data:"],
@@ -11,18 +12,18 @@ const DEFAULT_DIRECTIVES = {
"script-src-attr": ["'none'"],
"style-src": ["'self'", "https:", "'unsafe-inline'"],
"upgrade-insecure-requests": []
}
const SHOULD_BE_QUOTED = new Set(["none", "self", "strict-dynamic", "report-sample", "inline-speculation-rules", "unsafe-inline", "unsafe-eval", "unsafe-hashes", "wasm-unsafe-eval"])
const getDefaultDirectives = () => Object.assign({}, DEFAULT_DIRECTIVES)
})
const dashify = str => str.replace(/[A-Z]/g, capitalLetter => "-" + capitalLetter.toLowerCase())
const isDirectiveValueInvalid = directiveValue => /;|,/.test(directiveValue)
const shouldDirectiveValueEntryBeQuoted = directiveValueEntry => SHOULD_BE_QUOTED.has(directiveValueEntry) || directiveValueEntry.startsWith("nonce-") || directiveValueEntry.startsWith("sha256-") || directiveValueEntry.startsWith("sha384-") || directiveValueEntry.startsWith("sha512-")
const warnIfDirectiveValueEntryShouldBeQuoted = value => {
if (shouldDirectiveValueEntryBeQuoted(value)) {
console.warn(`Content-Security-Policy got directive value \`${value}\` which should be single-quoted and changed to \`'${value}'\`. This will be an error in future versions of Helmet.`)
const assertDirectiveValueIsValid = (directiveName, directiveValue) => {
if (/;|,/.test(directiveValue)) {
throw new Error(`Content-Security-Policy received an invalid directive value for ${JSON.stringify(directiveName)}`)
}
}
const assertDirectiveValueEntryIsValid = (directiveName, directiveValueEntry) => {
if (SHOULD_BE_QUOTED.has(directiveValueEntry) || directiveValueEntry.startsWith("nonce-") || directiveValueEntry.startsWith("sha256-") || directiveValueEntry.startsWith("sha384-") || directiveValueEntry.startsWith("sha512-")) {
throw new Error(`Content-Security-Policy received an invalid directive value for ${JSON.stringify(directiveName)}. ${JSON.stringify(directiveValueEntry)} should be quoted`)
}
}
const has = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key)
function normalizeDirectives(options) {
const defaultDirectives = getDefaultDirectives()
const {useDefaults = true, directives: rawDirectives = defaultDirectives} = options
@@ -30,7 +31,7 @@ function normalizeDirectives(options) {
const directiveNamesSeen = new Set()
const directivesExplicitlyDisabled = new Set()
for (const rawDirectiveName in rawDirectives) {
if (!has(rawDirectives, rawDirectiveName)) {
if (!Object.hasOwn(rawDirectives, rawDirectiveName)) {
continue
}
if (rawDirectiveName.length === 0 || /[^a-zA-Z0-9-]/.test(rawDirectiveName)) {
@@ -64,12 +65,9 @@ function normalizeDirectives(options) {
directiveValue = rawDirectiveValue
}
for (const element of directiveValue) {
if (typeof element === "string") {
if (isDirectiveValueInvalid(element)) {
throw new Error(`Content-Security-Policy received an invalid directive value for ${JSON.stringify(directiveName)}`)
}
warnIfDirectiveValueEntryShouldBeQuoted(element)
}
if (typeof element !== "string") continue
assertDirectiveValueIsValid(directiveName, element)
assertDirectiveValueEntryIsValid(directiveName, element)
}
result.set(directiveName, directiveValue)
}
@@ -89,28 +87,26 @@ function normalizeDirectives(options) {
return result
}
function getHeaderValue(req, res, normalizedDirectives) {
let err
const result = []
normalizedDirectives.forEach((rawDirectiveValue, directiveName) => {
for (const [directiveName, rawDirectiveValue] of normalizedDirectives) {
let directiveValue = ""
for (const element of rawDirectiveValue) {
if (typeof element === "function") {
const newElement = element(req, res)
warnIfDirectiveValueEntryShouldBeQuoted(newElement)
assertDirectiveValueEntryIsValid(directiveName, newElement)
directiveValue += " " + newElement
} else {
directiveValue += " " + element
}
}
if (!directiveValue) {
result.push(directiveName)
} else if (isDirectiveValueInvalid(directiveValue)) {
err = new Error(`Content-Security-Policy received an invalid directive value for ${JSON.stringify(directiveName)}`)
} else {
if (directiveValue) {
assertDirectiveValueIsValid(directiveName, directiveValue)
result.push(`${directiveName}${directiveValue}`)
} else {
result.push(directiveName)
}
})
return err ? err : result.join(";")
}
return result.join(";")
}
const contentSecurityPolicy = function contentSecurityPolicy(options = {}) {
const headerName = options.reportOnly ? "Content-Security-Policy-Report-Only" : "Content-Security-Policy"
@@ -208,7 +204,7 @@ function referrerPolicy(options = {}) {
}
}
const DEFAULT_MAX_AGE = 180 * 24 * 60 * 60
const DEFAULT_MAX_AGE = 365 * 24 * 60 * 60
function parseMaxAge(value = DEFAULT_MAX_AGE) {
if (value >= 0 && Number.isFinite(value)) {
return Math.floor(value)
@@ -221,7 +217,7 @@ function getHeaderValueFromOptions$2(options) {
throw new Error("Strict-Transport-Security received an unsupported property, `maxage`. Did you mean to pass `maxAge`?")
}
if ("includeSubdomains" in options) {
console.warn('Strict-Transport-Security middleware should use `includeSubDomains` instead of `includeSubdomains`. (The correct one has an uppercase "D".)')
throw new Error('Strict-Transport-Security middleware should use `includeSubDomains` instead of `includeSubdomains`. (The correct one has an uppercase "D".)')
}
const directives = [`max-age=${parseMaxAge(options.maxAge)}`]
if (options.includeSubDomains === undefined || options.includeSubDomains) {
@@ -313,7 +309,6 @@ function xXssProtection() {
}
function getMiddlewareFunctionsFromOptions(options) {
var _a, _b, _c, _d, _e, _f, _g, _h
const result = []
switch (options.contentSecurityPolicy) {
case undefined:
@@ -385,7 +380,7 @@ function getMiddlewareFunctionsFromOptions(options) {
if ("strictTransportSecurity" in options && "hsts" in options) {
throw new Error("Strict-Transport-Security option was specified twice. Remove `hsts` to silence this warning.")
}
const strictTransportSecurityOption = (_a = options.strictTransportSecurity) !== null && _a !== void 0 ? _a : options.hsts
const strictTransportSecurityOption = options.strictTransportSecurity ?? options.hsts
switch (strictTransportSecurityOption) {
case undefined:
case true:
@@ -400,7 +395,7 @@ function getMiddlewareFunctionsFromOptions(options) {
if ("xContentTypeOptions" in options && "noSniff" in options) {
throw new Error("X-Content-Type-Options option was specified twice. Remove `noSniff` to silence this warning.")
}
const xContentTypeOptionsOption = (_b = options.xContentTypeOptions) !== null && _b !== void 0 ? _b : options.noSniff
const xContentTypeOptionsOption = options.xContentTypeOptions ?? options.noSniff
switch (xContentTypeOptionsOption) {
case undefined:
case true:
@@ -416,7 +411,7 @@ function getMiddlewareFunctionsFromOptions(options) {
if ("xDnsPrefetchControl" in options && "dnsPrefetchControl" in options) {
throw new Error("X-DNS-Prefetch-Control option was specified twice. Remove `dnsPrefetchControl` to silence this warning.")
}
const xDnsPrefetchControlOption = (_c = options.xDnsPrefetchControl) !== null && _c !== void 0 ? _c : options.dnsPrefetchControl
const xDnsPrefetchControlOption = options.xDnsPrefetchControl ?? options.dnsPrefetchControl
switch (xDnsPrefetchControlOption) {
case undefined:
case true:
@@ -431,7 +426,7 @@ function getMiddlewareFunctionsFromOptions(options) {
if ("xDownloadOptions" in options && "ieNoOpen" in options) {
throw new Error("X-Download-Options option was specified twice. Remove `ieNoOpen` to silence this warning.")
}
const xDownloadOptionsOption = (_d = options.xDownloadOptions) !== null && _d !== void 0 ? _d : options.ieNoOpen
const xDownloadOptionsOption = options.xDownloadOptions ?? options.ieNoOpen
switch (xDownloadOptionsOption) {
case undefined:
case true:
@@ -447,7 +442,7 @@ function getMiddlewareFunctionsFromOptions(options) {
if ("xFrameOptions" in options && "frameguard" in options) {
throw new Error("X-Frame-Options option was specified twice. Remove `frameguard` to silence this warning.")
}
const xFrameOptionsOption = (_e = options.xFrameOptions) !== null && _e !== void 0 ? _e : options.frameguard
const xFrameOptionsOption = options.xFrameOptions ?? options.frameguard
switch (xFrameOptionsOption) {
case undefined:
case true:
@@ -462,7 +457,7 @@ function getMiddlewareFunctionsFromOptions(options) {
if ("xPermittedCrossDomainPolicies" in options && "permittedCrossDomainPolicies" in options) {
throw new Error("X-Permitted-Cross-Domain-Policies option was specified twice. Remove `permittedCrossDomainPolicies` to silence this warning.")
}
const xPermittedCrossDomainPoliciesOption = (_f = options.xPermittedCrossDomainPolicies) !== null && _f !== void 0 ? _f : options.permittedCrossDomainPolicies
const xPermittedCrossDomainPoliciesOption = options.xPermittedCrossDomainPolicies ?? options.permittedCrossDomainPolicies
switch (xPermittedCrossDomainPoliciesOption) {
case undefined:
case true:
@@ -477,7 +472,7 @@ function getMiddlewareFunctionsFromOptions(options) {
if ("xPoweredBy" in options && "hidePoweredBy" in options) {
throw new Error("X-Powered-By option was specified twice. Remove `hidePoweredBy` to silence this warning.")
}
const xPoweredByOption = (_g = options.xPoweredBy) !== null && _g !== void 0 ? _g : options.hidePoweredBy
const xPoweredByOption = options.xPoweredBy ?? options.hidePoweredBy
switch (xPoweredByOption) {
case undefined:
case true:
@@ -493,7 +488,7 @@ function getMiddlewareFunctionsFromOptions(options) {
if ("xXssProtection" in options && "xssFilter" in options) {
throw new Error("X-XSS-Protection option was specified twice. Remove `xssFilter` to silence this warning.")
}
const xXssProtectionOption = (_h = options.xXssProtection) !== null && _h !== void 0 ? _h : options.xssFilter
const xXssProtectionOption = options.xXssProtection ?? options.xssFilter
switch (xXssProtectionOption) {
case undefined:
case true:
@@ -510,11 +505,10 @@ function getMiddlewareFunctionsFromOptions(options) {
}
const helmet = Object.assign(
function helmet(options = {}) {
var _a
// People should be able to pass an options object with no prototype,
// so we want this optional chaining.
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (((_a = options.constructor) === null || _a === void 0 ? void 0 : _a.name) === "IncomingMessage") {
if (options.constructor?.name === "IncomingMessage") {
throw new Error("It appears you have done something like `app.use(helmet)`, but it should be `app.use(helmet())`.")
}
const middlewareFunctions = getMiddlewareFunctionsFromOptions(options)