|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- "use strict"
- Object.defineProperty(exports, "__esModule", { value: true })
- exports.dangerouslyDisableDefaultSrc = exports.getDefaultDirectives = void 0
- const dangerouslyDisableDefaultSrc = Symbol("dangerouslyDisableDefaultSrc")
- exports.dangerouslyDisableDefaultSrc = dangerouslyDisableDefaultSrc
- const DEFAULT_DIRECTIVES = {
- "default-src": ["'self'"],
- "base-uri": ["'self'"],
- "block-all-mixed-content": [],
- "font-src": ["'self'", "https:", "data:"],
- "frame-ancestors": ["'self'"],
- "img-src": ["'self'", "data:"],
- "object-src": ["'none'"],
- "script-src": ["'self'"],
- "script-src-attr": ["'none'"],
- "style-src": ["'self'", "https:", "'unsafe-inline'"],
- "upgrade-insecure-requests": []
- }
- const getDefaultDirectives = () => Object.assign({}, DEFAULT_DIRECTIVES)
- exports.getDefaultDirectives = getDefaultDirectives
- const dashify = str => str.replace(/[A-Z]/g, capitalLetter => "-" + capitalLetter.toLowerCase())
- const isDirectiveValueInvalid = directiveValue => /;|,/.test(directiveValue)
- const has = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key)
- function normalizeDirectives(options) {
- const defaultDirectives = getDefaultDirectives()
- const { useDefaults = false, directives: rawDirectives = defaultDirectives } = options
- const result = new Map()
- const directiveNamesSeen = new Set()
- const directivesExplicitlyDisabled = new Set()
- for (const rawDirectiveName in rawDirectives) {
- if (!has(rawDirectives, rawDirectiveName)) {
- continue
- }
- if (rawDirectiveName.length === 0 || /[^a-zA-Z0-9-]/.test(rawDirectiveName)) {
- throw new Error(`Content-Security-Policy received an invalid directive name ${JSON.stringify(rawDirectiveName)}`)
- }
- const directiveName = dashify(rawDirectiveName)
- if (directiveNamesSeen.has(directiveName)) {
- throw new Error(`Content-Security-Policy received a duplicate directive ${JSON.stringify(directiveName)}`)
- }
- directiveNamesSeen.add(directiveName)
- const rawDirectiveValue = rawDirectives[rawDirectiveName]
- let directiveValue
- if (rawDirectiveValue === null) {
- if (directiveName === "default-src") {
- 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`.")
- }
- directivesExplicitlyDisabled.add(directiveName)
- continue
- } else if (typeof rawDirectiveValue === "string") {
- directiveValue = [rawDirectiveValue]
- } else if (!rawDirectiveValue) {
- throw new Error(`Content-Security-Policy received an invalid directive value for ${JSON.stringify(directiveName)}`)
- } else if (rawDirectiveValue === dangerouslyDisableDefaultSrc) {
- if (directiveName === "default-src") {
- directivesExplicitlyDisabled.add("default-src")
- continue
- } else {
- throw new Error(`Content-Security-Policy: tried to disable ${JSON.stringify(directiveName)} as if it were default-src; simply omit the key`)
- }
- } else {
- directiveValue = rawDirectiveValue
- }
- for (const element of directiveValue) {
- if (typeof element === "string" && isDirectiveValueInvalid(element)) {
- throw new Error(`Content-Security-Policy received an invalid directive value for ${JSON.stringify(directiveName)}`)
- }
- }
- result.set(directiveName, directiveValue)
- }
- if (useDefaults) {
- Object.entries(defaultDirectives).forEach(([defaultDirectiveName, defaultDirectiveValue]) => {
- if (!result.has(defaultDirectiveName) && !directivesExplicitlyDisabled.has(defaultDirectiveName)) {
- result.set(defaultDirectiveName, defaultDirectiveValue)
- }
- })
- }
- if (!result.size) {
- throw new Error("Content-Security-Policy has no directives. Either set some or disable the header")
- }
- if (!result.has("default-src") && !directivesExplicitlyDisabled.has("default-src")) {
- 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`.")
- }
- return result
- }
- function getHeaderValue(req, res, normalizedDirectives) {
- let err
- const result = []
- normalizedDirectives.forEach((rawDirectiveValue, directiveName) => {
- let directiveValue = ""
- for (const element of rawDirectiveValue) {
- directiveValue += " " + (element instanceof Function ? element(req, res) : 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 {
- result.push(`${directiveName}${directiveValue}`)
- }
- })
- return err ? err : result.join(";")
- }
- const contentSecurityPolicy = function contentSecurityPolicy(options = {}) {
- if ("loose" in options) {
- console.warn("Content-Security-Policy middleware no longer needs the `loose` parameter. You should remove it.")
- }
- if ("setAllHeaders" in options) {
- console.warn("Content-Security-Policy middleware no longer supports the `setAllHeaders` parameter. See <https://github.com/helmetjs/helmet/wiki/Setting-legacy-Content-Security-Policy-headers-in-Helmet-4>.")
- }
- ;["disableAndroid", "browserSniff"].forEach(deprecatedOption => {
- if (deprecatedOption in options) {
- console.warn(`Content-Security-Policy middleware no longer does browser sniffing, so you can remove the \`${deprecatedOption}\` option. See <https://github.com/helmetjs/csp/issues/97> for discussion.`)
- }
- })
- const headerName = options.reportOnly ? "Content-Security-Policy-Report-Only" : "Content-Security-Policy"
- const normalizedDirectives = normalizeDirectives(options)
- return function contentSecurityPolicyMiddleware(req, res, next) {
- const result = getHeaderValue(req, res, normalizedDirectives)
- if (result instanceof Error) {
- next(result)
- } else {
- res.setHeader(headerName, result)
- next()
- }
- }
- }
- contentSecurityPolicy.getDefaultDirectives = getDefaultDirectives
- contentSecurityPolicy.dangerouslyDisableDefaultSrc = dangerouslyDisableDefaultSrc
- module.exports = contentSecurityPolicy
- exports.default = contentSecurityPolicy
|