API inicial

This commit is contained in:
2021-03-25 17:23:36 +01:00
commit 218326c402
1878 changed files with 274122 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
/// <reference types="node" />
import { IncomingMessage, ServerResponse } from "http"
interface ContentSecurityPolicyDirectiveValueFunction {
(req: IncomingMessage, res: ServerResponse): string
}
declare type ContentSecurityPolicyDirectiveValue = string | ContentSecurityPolicyDirectiveValueFunction
export interface ContentSecurityPolicyOptions {
directives?: Record<string, Iterable<ContentSecurityPolicyDirectiveValue> | typeof dangerouslyDisableDefaultSrc>
reportOnly?: boolean
}
interface ContentSecurityPolicy {
(options?: Readonly<ContentSecurityPolicyOptions>): (req: IncomingMessage, res: ServerResponse, next: (err?: Error) => void) => void
getDefaultDirectives: typeof getDefaultDirectives
dangerouslyDisableDefaultSrc: typeof dangerouslyDisableDefaultSrc
}
declare const dangerouslyDisableDefaultSrc: unique symbol
declare const getDefaultDirectives: () => {
[x: string]: Iterable<ContentSecurityPolicyDirectiveValue>
}
declare const contentSecurityPolicy: ContentSecurityPolicy
export default contentSecurityPolicy
export { getDefaultDirectives, dangerouslyDisableDefaultSrc }

View File

@@ -0,0 +1,114 @@
"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 { directives: rawDirectives = getDefaultDirectives() } = options
const result = []
const directiveNamesSeen = 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 (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") {
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.push({ directiveName, directiveValue })
}
if (!result.length) {
throw new Error("Content-Security-Policy has no directives. Either set some or disable the header")
}
if (!directiveNamesSeen.has("default-src")) {
throw new Error("Content-Security-Policy needs a default-src but none was provided")
}
return result
}
function getHeaderValue(req, res, normalizedDirectives) {
const result = []
for (const { directiveName, directiveValue: rawDirectiveValue } of normalizedDirectives) {
let directiveValue = ""
for (const element of rawDirectiveValue) {
directiveValue += " " + (element instanceof Function ? element(req, res) : 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(";")
}
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

View File

@@ -0,0 +1,8 @@
import { IncomingMessage, ServerResponse } from "http"
export interface ExpectCtOptions {
maxAge?: number
enforce?: boolean
reportUri?: string
}
declare function expectCt(options?: Readonly<ExpectCtOptions>): (_req: IncomingMessage, res: ServerResponse, next: () => void) => void
export default expectCt

View File

@@ -0,0 +1,28 @@
"use strict"
Object.defineProperty(exports, "__esModule", { value: true })
function parseMaxAge(value = 0) {
if (value >= 0 && Number.isFinite(value)) {
return Math.floor(value)
} else {
throw new Error(`Expect-CT: ${JSON.stringify(value)} is not a valid value for maxAge. Please choose a positive integer.`)
}
}
function getHeaderValueFromOptions(options) {
const directives = [`max-age=${parseMaxAge(options.maxAge)}`]
if (options.enforce) {
directives.push("enforce")
}
if (options.reportUri) {
directives.push(`report-uri="${options.reportUri}"`)
}
return directives.join(", ")
}
function expectCt(options = {}) {
const headerValue = getHeaderValueFromOptions(options)
return function expectCtMiddleware(_req, res, next) {
res.setHeader("Expect-CT", headerValue)
next()
}
}
module.exports = expectCt
exports.default = expectCt

View File

@@ -0,0 +1,3 @@
import { IncomingMessage, ServerResponse } from "http"
declare function originAgentCluster(): (_req: IncomingMessage, res: ServerResponse, next: () => void) => void
export default originAgentCluster

View File

@@ -0,0 +1,10 @@
"use strict"
Object.defineProperty(exports, "__esModule", { value: true })
function originAgentCluster() {
return function originAgentClusterMiddleware(_req, res, next) {
res.setHeader("Origin-Agent-Cluster", "?1")
next()
}
}
module.exports = originAgentCluster
exports.default = originAgentCluster

View File

@@ -0,0 +1,6 @@
import { IncomingMessage, ServerResponse } from "http"
export interface ReferrerPolicyOptions {
policy?: string | string[]
}
declare function referrerPolicy(options?: Readonly<ReferrerPolicyOptions>): (_req: IncomingMessage, res: ServerResponse, next: () => void) => void
export default referrerPolicy

View File

@@ -0,0 +1,28 @@
"use strict"
Object.defineProperty(exports, "__esModule", { value: true })
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", ""])
function getHeaderValueFromOptions({ policy = ["no-referrer"] }) {
const tokens = typeof policy === "string" ? [policy] : policy
if (tokens.length === 0) {
throw new Error("Referrer-Policy received no policy tokens")
}
const tokensSeen = new Set()
tokens.forEach(token => {
if (!ALLOWED_TOKENS.has(token)) {
throw new Error(`Referrer-Policy received an unexpected policy token ${JSON.stringify(token)}`)
} else if (tokensSeen.has(token)) {
throw new Error(`Referrer-Policy received a duplicate policy token ${JSON.stringify(token)}`)
}
tokensSeen.add(token)
})
return tokens.join(",")
}
function referrerPolicy(options = {}) {
const headerValue = getHeaderValueFromOptions(options)
return function referrerPolicyMiddleware(_req, res, next) {
res.setHeader("Referrer-Policy", headerValue)
next()
}
}
module.exports = referrerPolicy
exports.default = referrerPolicy

View File

@@ -0,0 +1,8 @@
import { IncomingMessage, ServerResponse } from "http"
export interface StrictTransportSecurityOptions {
maxAge?: number
includeSubDomains?: boolean
preload?: boolean
}
declare function strictTransportSecurity(options?: Readonly<StrictTransportSecurityOptions>): (_req: IncomingMessage, res: ServerResponse, next: () => void) => void
export default strictTransportSecurity

View File

@@ -0,0 +1,38 @@
"use strict"
Object.defineProperty(exports, "__esModule", { value: true })
const DEFAULT_MAX_AGE = 180 * 24 * 60 * 60
function parseMaxAge(value = DEFAULT_MAX_AGE) {
if (value >= 0 && Number.isFinite(value)) {
return Math.floor(value)
} else {
throw new Error(`Strict-Transport-Security: ${JSON.stringify(value)} is not a valid value for maxAge. Please choose a positive integer.`)
}
}
function getHeaderValueFromOptions(options) {
if ("maxage" in 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".)')
}
if ("setIf" in options) {
console.warn("Strict-Transport-Security middleware no longer supports the `setIf` parameter. See the documentation and <https://github.com/helmetjs/helmet/wiki/Conditionally-using-middleware> if you need help replicating this behavior.")
}
const directives = [`max-age=${parseMaxAge(options.maxAge)}`]
if (options.includeSubDomains === undefined || options.includeSubDomains) {
directives.push("includeSubDomains")
}
if (options.preload) {
directives.push("preload")
}
return directives.join("; ")
}
function strictTransportSecurity(options = {}) {
const headerValue = getHeaderValueFromOptions(options)
return function strictTransportSecurityMiddleware(_req, res, next) {
res.setHeader("Strict-Transport-Security", headerValue)
next()
}
}
module.exports = strictTransportSecurity
exports.default = strictTransportSecurity

View File

@@ -0,0 +1,3 @@
import { IncomingMessage, ServerResponse } from "http"
declare function xContentTypeOptions(): (_req: IncomingMessage, res: ServerResponse, next: () => void) => void
export default xContentTypeOptions

View File

@@ -0,0 +1,10 @@
"use strict"
Object.defineProperty(exports, "__esModule", { value: true })
function xContentTypeOptions() {
return function xContentTypeOptionsMiddleware(_req, res, next) {
res.setHeader("X-Content-Type-Options", "nosniff")
next()
}
}
module.exports = xContentTypeOptions
exports.default = xContentTypeOptions

View File

@@ -0,0 +1,6 @@
import { IncomingMessage, ServerResponse } from "http"
export interface XDnsPrefetchControlOptions {
allow?: boolean
}
declare function xDnsPrefetchControl(options?: Readonly<XDnsPrefetchControlOptions>): (_req: IncomingMessage, res: ServerResponse, next: () => void) => void
export default xDnsPrefetchControl

View File

@@ -0,0 +1,11 @@
"use strict"
Object.defineProperty(exports, "__esModule", { value: true })
function xDnsPrefetchControl(options = {}) {
const headerValue = options.allow ? "on" : "off"
return function xDnsPrefetchControlMiddleware(_req, res, next) {
res.setHeader("X-DNS-Prefetch-Control", headerValue)
next()
}
}
module.exports = xDnsPrefetchControl
exports.default = xDnsPrefetchControl

View File

@@ -0,0 +1,3 @@
import { IncomingMessage, ServerResponse } from "http"
declare function xDownloadOptions(): (_req: IncomingMessage, res: ServerResponse, next: () => void) => void
export default xDownloadOptions

View File

@@ -0,0 +1,10 @@
"use strict"
Object.defineProperty(exports, "__esModule", { value: true })
function xDownloadOptions() {
return function xDownloadOptionsMiddleware(_req, res, next) {
res.setHeader("X-Download-Options", "noopen")
next()
}
}
module.exports = xDownloadOptions
exports.default = xDownloadOptions

View File

@@ -0,0 +1,6 @@
import { IncomingMessage, ServerResponse } from "http"
export interface XFrameOptionsOptions {
action?: string
}
declare function xFrameOptions(options?: Readonly<XFrameOptionsOptions>): (_req: IncomingMessage, res: ServerResponse, next: () => void) => void
export default xFrameOptions

View File

@@ -0,0 +1,25 @@
"use strict"
Object.defineProperty(exports, "__esModule", { value: true })
function getHeaderValueFromOptions({ action = "SAMEORIGIN" }) {
const normalizedAction = typeof action === "string" ? action.toUpperCase() : action
switch (normalizedAction) {
case "SAME-ORIGIN":
return "SAMEORIGIN"
case "DENY":
case "SAMEORIGIN":
return normalizedAction
case "ALLOW-FROM":
throw new Error("X-Frame-Options no longer supports `ALLOW-FROM` due to poor browser support. See <https://github.com/helmetjs/helmet/wiki/How-to-use-X%E2%80%93Frame%E2%80%93Options's-%60ALLOW%E2%80%93FROM%60-directive> for more info.")
default:
throw new Error(`X-Frame-Options received an invalid action ${JSON.stringify(action)}`)
}
}
function xFrameOptions(options = {}) {
const headerValue = getHeaderValueFromOptions(options)
return function xFrameOptionsMiddleware(_req, res, next) {
res.setHeader("X-Frame-Options", headerValue)
next()
}
}
module.exports = xFrameOptions
exports.default = xFrameOptions

View File

@@ -0,0 +1,6 @@
import { IncomingMessage, ServerResponse } from "http"
export interface XPermittedCrossDomainPoliciesOptions {
permittedPolicies?: string
}
declare function xPermittedCrossDomainPolicies(options?: Readonly<XPermittedCrossDomainPoliciesOptions>): (_req: IncomingMessage, res: ServerResponse, next: () => void) => void
export default xPermittedCrossDomainPolicies

View File

@@ -0,0 +1,19 @@
"use strict"
Object.defineProperty(exports, "__esModule", { value: true })
const ALLOWED_PERMITTED_POLICIES = new Set(["none", "master-only", "by-content-type", "all"])
function getHeaderValueFromOptions({ permittedPolicies = "none" }) {
if (ALLOWED_PERMITTED_POLICIES.has(permittedPolicies)) {
return permittedPolicies
} else {
throw new Error(`X-Permitted-Cross-Domain-Policies does not support ${JSON.stringify(permittedPolicies)}`)
}
}
function xPermittedCrossDomainPolicies(options = {}) {
const headerValue = getHeaderValueFromOptions(options)
return function xPermittedCrossDomainPoliciesMiddleware(_req, res, next) {
res.setHeader("X-Permitted-Cross-Domain-Policies", headerValue)
next()
}
}
module.exports = xPermittedCrossDomainPolicies
exports.default = xPermittedCrossDomainPolicies

View File

@@ -0,0 +1,3 @@
import { IncomingMessage, ServerResponse } from "http"
declare function xPoweredBy(): (_req: IncomingMessage, res: ServerResponse, next: () => void) => void
export default xPoweredBy

View File

@@ -0,0 +1,10 @@
"use strict"
Object.defineProperty(exports, "__esModule", { value: true })
function xPoweredBy() {
return function xPoweredByMiddleware(_req, res, next) {
res.removeHeader("X-Powered-By")
next()
}
}
module.exports = xPoweredBy
exports.default = xPoweredBy

View File

@@ -0,0 +1,3 @@
import { IncomingMessage, ServerResponse } from "http"
declare function xXssProtection(): (_req: IncomingMessage, res: ServerResponse, next: () => void) => void
export default xXssProtection

View File

@@ -0,0 +1,10 @@
"use strict"
Object.defineProperty(exports, "__esModule", { value: true })
function xXssProtection() {
return function xXssProtectionMiddleware(_req, res, next) {
res.setHeader("X-XSS-Protection", "0")
next()
}
}
module.exports = xXssProtection
exports.default = xXssProtection