"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getDefaultDirectives = void 0; 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 isRawPolicyDirectiveNameInvalid = (rawDirectiveName) => rawDirectiveName.length === 0 || /[^a-zA-Z0-9-]/.test(rawDirectiveName); 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 getHeaderName({ reportOnly, }) { if (reportOnly) { return "Content-Security-Policy-Report-Only"; } else { return "Content-Security-Policy"; } } function normalizeDirectives(options) { const result = {}; const { directives: rawDirectives = getDefaultDirectives() } = options; for (const rawDirectiveName in rawDirectives) { if (!has(rawDirectives, rawDirectiveName)) { continue; } if (isRawPolicyDirectiveNameInvalid(rawDirectiveName)) { throw new Error(`Content-Security-Policy received an invalid directive name ${JSON.stringify(rawDirectiveName)}`); } const directiveName = dashify(rawDirectiveName); if (has(result, directiveName)) { throw new Error(`Content-Security-Policy received a duplicate directive ${JSON.stringify(directiveName)}`); } const rawDirectiveValue = rawDirectives[rawDirectiveName]; let directiveValue; if (typeof rawDirectiveValue === "string") { directiveValue = [rawDirectiveValue]; } 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[directiveName] = directiveValue; } if (!("default-src" in result)) { throw new Error("Content-Security-Policy needs a default-src but none was provided"); } return result; } function getHeaderValue(req, res, directives) { const result = []; for (const directiveName in directives) { if (!has(directives, directiveName)) { continue; } const rawDirectiveValue = directives[directiveName]; let directiveValue = ""; for (const element of rawDirectiveValue) { if (element instanceof Function) { directiveValue += " " + element(req, res); } else { directiveValue += " " + element; } } if (!directiveValue) { result.push(directiveName); } else if (isDirectiveValueInvalid(directiveValue)) { return new Error(`Content-Security-Policy received an invalid directive value for ${JSON.stringify(directiveName)}`); } else { result.push(`${directiveName}${directiveValue}`); } } return result.join(";"); } 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 ."); } ["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 for discussion.`); } }); const headerName = getHeaderName(options); const directives = normalizeDirectives(options); return function contentSecurityPolicyMiddleware(req, res, next) { const result = getHeaderValue(req, res, directives); if (result instanceof Error) { next(result); } else { res.setHeader(headerName, result); next(); } }; } contentSecurityPolicy.getDefaultDirectives = getDefaultDirectives; module.exports = contentSecurityPolicy; exports.default = contentSecurityPolicy;