mirror of
https://codeberg.org/teddit/teddit.git
synced 2026-04-21 22:15:04 -04:00
initial commit
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
||||
/// <reference types="node" />
|
||||
import { IncomingMessage, ServerResponse } from "http";
|
||||
interface ContentSecurityPolicyDirectiveValueFunction {
|
||||
(req: IncomingMessage, res: ServerResponse): string;
|
||||
}
|
||||
declare type ContentSecurityPolicyDirectiveValue = string | ContentSecurityPolicyDirectiveValueFunction;
|
||||
interface ContentSecurityPolicyDirectives {
|
||||
[directiveName: string]: Iterable<ContentSecurityPolicyDirectiveValue>;
|
||||
}
|
||||
export interface ContentSecurityPolicyOptions {
|
||||
directives?: ContentSecurityPolicyDirectives;
|
||||
reportOnly?: boolean;
|
||||
}
|
||||
declare const getDefaultDirectives: () => {
|
||||
[x: string]: Iterable<ContentSecurityPolicyDirectiveValue>;
|
||||
};
|
||||
declare function contentSecurityPolicy(options?: Readonly<ContentSecurityPolicyOptions>): (req: IncomingMessage, res: ServerResponse, next: (err?: Error) => void) => void;
|
||||
declare namespace contentSecurityPolicy {
|
||||
var getDefaultDirectives: () => {
|
||||
[x: string]: Iterable<ContentSecurityPolicyDirectiveValue>;
|
||||
};
|
||||
}
|
||||
export default contentSecurityPolicy;
|
||||
export { getDefaultDirectives };
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
"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 <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 = 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;
|
||||
Reference in New Issue
Block a user