@middy/http-security-headers
Advanced tools
Comparing version 1.5.2 to 2.0.0-alpha.0
@@ -1,4 +0,4 @@ | ||
const { invoke } = require('../../test-helpers') | ||
const middy = require('../../core') | ||
const httpSecurityHeaders = require('../') | ||
const test = require('ava') | ||
const middy = require('../../core/index.js') | ||
const httpSecurityHeaders = require('../index.js') | ||
@@ -40,6 +40,4 @@ const createDefaultObjectResponse = () => | ||
describe('🔒 Middleware Http Security Headers', () => { | ||
test('It should return default security headers', async () => { | ||
const handler = middy((event, context, cb) => | ||
cb(null, createDefaultObjectResponse()) | ||
test('It should return default security headers', async (t) => { | ||
const handler = middy((event, context) => createDefaultObjectResponse() | ||
) | ||
@@ -53,20 +51,19 @@ | ||
const response = await invoke(handler, event) | ||
const response = await handler(event) | ||
expect(response.statusCode).toEqual(200) | ||
expect(response.headers['X-DNS-Prefetch-Control']).toEqual('off') | ||
expect(response.headers['X-Powered-By']).toEqual(undefined) | ||
expect(response.headers['Strict-Transport-Security']).toEqual('max-age=15552000; includeSubDomains; preload') | ||
expect(response.headers['X-Download-Options']).toEqual('noopen') | ||
expect(response.headers['X-Content-Type-Options']).toEqual('nosniff') | ||
expect(response.headers['Referrer-Policy']).toEqual('no-referrer') | ||
expect(response.headers['X-Permitted-Cross-Domain-Policies']).toEqual('none') | ||
t.is(response.statusCode,200) | ||
t.is(response.headers['X-DNS-Prefetch-Control'],'off') | ||
t.is(response.headers['X-Powered-By'],undefined) | ||
t.is(response.headers['Strict-Transport-Security'],'max-age=15552000; includeSubDomains; preload') | ||
t.is(response.headers['X-Download-Options'],'noopen') | ||
t.is(response.headers['X-Content-Type-Options'],'nosniff') | ||
t.is(response.headers['Referrer-Policy'],'no-referrer') | ||
t.is(response.headers['X-Permitted-Cross-Domain-Policies'],'none') | ||
expect(response.headers['X-Frame-Options']).toEqual(undefined) | ||
expect(response.headers['X-XSS-Protection']).toEqual(undefined) | ||
t.is(response.headers['X-Frame-Options'],undefined) | ||
t.is(response.headers['X-XSS-Protection'],undefined) | ||
}) | ||
test('It should return default security headers when HTML', async () => { | ||
const handler = middy((event, context, cb) => | ||
cb(null, createHtmlObjectResponse()) | ||
test('It should return default security headers when HTML', async (t) => { | ||
const handler = middy((event, context) => createHtmlObjectResponse() | ||
) | ||
@@ -80,19 +77,18 @@ | ||
const response = await invoke(handler, event) | ||
const response = await handler(event) | ||
expect(response.headers['X-DNS-Prefetch-Control']).toEqual('off') | ||
expect(response.headers['X-Powered-By']).toEqual(undefined) | ||
expect(response.headers['Strict-Transport-Security']).toEqual('max-age=15552000; includeSubDomains; preload') | ||
expect(response.headers['X-Download-Options']).toEqual('noopen') | ||
expect(response.headers['X-Content-Type-Options']).toEqual('nosniff') | ||
expect(response.headers['Referrer-Policy']).toEqual('no-referrer') | ||
expect(response.headers['X-Permitted-Cross-Domain-Policies']).toEqual('none') | ||
t.is(response.headers['X-DNS-Prefetch-Control'],'off') | ||
t.is(response.headers['X-Powered-By'],undefined) | ||
t.is(response.headers['Strict-Transport-Security'],'max-age=15552000; includeSubDomains; preload') | ||
t.is(response.headers['X-Download-Options'],'noopen') | ||
t.is(response.headers['X-Content-Type-Options'],'nosniff') | ||
t.is(response.headers['Referrer-Policy'],'no-referrer') | ||
t.is(response.headers['X-Permitted-Cross-Domain-Policies'],'none') | ||
expect(response.headers['X-Frame-Options']).toEqual('DENY') | ||
expect(response.headers['X-XSS-Protection']).toEqual('1; mode=block') | ||
t.is(response.headers['X-Frame-Options'],'DENY') | ||
t.is(response.headers['X-XSS-Protection'],'1; mode=block') | ||
}) | ||
test('It should modify default security headers', async () => { | ||
const handler = middy((event, context, cb) => | ||
cb(null, createHeaderObjectResponse()) | ||
test('It should modify default security headers', async (t) => { | ||
const handler = middy((event, context) => createHeaderObjectResponse() | ||
) | ||
@@ -106,12 +102,11 @@ | ||
const response = await invoke(handler, event) | ||
const response = await handler(event) | ||
expect(response.statusCode).toEqual(200) | ||
expect(response.headers.Server).toEqual(undefined) | ||
expect(response.headers['X-Powered-By']).toEqual(undefined) | ||
t.is(response.statusCode,200) | ||
t.is(response.headers.Server,undefined) | ||
t.is(response.headers['X-Powered-By'],undefined) | ||
}) | ||
test('It should modify default security headers', async () => { | ||
const handler = middy((event, context, cb) => | ||
cb(null, createHtmlObjectResponse()) | ||
test('It should modify default security headers with config set', async (t) => { | ||
const handler = middy((event, context) => createHtmlObjectResponse() | ||
) | ||
@@ -142,13 +137,13 @@ | ||
const response = await invoke(handler, event) | ||
const response = await handler(event) | ||
expect(response.statusCode).toEqual(200) | ||
expect(response.headers['X-Permitted-Cross-Domain-Policies']).toEqual('all') | ||
expect(response.headers['X-DNS-Prefetch-Control']).toEqual('on') | ||
expect(response.headers['X-Powered-By']).toEqual('Other') | ||
expect(response.headers['Strict-Transport-Security']).toEqual('max-age=15552000') | ||
expect(response.headers['X-XSS-Protection']).toEqual('1; mode=block; report=https://example.com/report') | ||
t.is(response.statusCode,200) | ||
t.is(response.headers['X-Permitted-Cross-Domain-Policies'],'all') | ||
t.is(response.headers['X-DNS-Prefetch-Control'],'on') | ||
t.is(response.headers['X-Powered-By'],'Other') | ||
t.is(response.headers['Strict-Transport-Security'],'max-age=15552000') | ||
t.is(response.headers['X-XSS-Protection'],'1; mode=block; report=https://example.com/report') | ||
}) | ||
test('It should catch thrown errors', async () => { | ||
test('It should catch thrown errors', async (t) => { | ||
const handler = middy(async () => { | ||
@@ -164,5 +159,4 @@ throw new Error('This error should not return 200') | ||
const response = await invoke(handler, event) | ||
expect(response.statusCode).toEqual(500) | ||
const response = await handler(event) | ||
t.is(response.statusCode,500) | ||
}) | ||
}) |
179
index.js
// Code and Defaults heavily based off https://helmetjs.github.io/ | ||
const defaults = { | ||
@@ -9,4 +8,4 @@ dnsPrefetchControl: { | ||
enforce: true, | ||
maxAge: 30 | ||
// reportUri: '' | ||
maxAge: 30 // reportUri: '' | ||
}, | ||
@@ -32,2 +31,3 @@ frameguard: { | ||
policy: 'none' // none, master-only, by-content-type, by-ftp-filename, all | ||
}, | ||
@@ -37,117 +37,122 @@ referrerPolicy: { | ||
}, | ||
xssFilter: { | ||
// reportUri: '' | ||
xssFilter: {// reportUri: '' | ||
} | ||
} | ||
const helmet = {} | ||
const helmetHtmlOnly = {} | ||
// contentSecurityPolicy - N/A - no HTML | ||
}; | ||
const helmet = {}; | ||
const helmetHtmlOnly = {}; // contentSecurityPolicy - N/A - no HTML | ||
// featurePolicy - N/A - no HTML | ||
// crossdomain - N/A - For Adobe products | ||
// https://github.com/helmetjs/dns-Prefetch-control | ||
// https://github.com/helmetjs/dns-prefetch-control | ||
helmet.dnsPrefetchControl = (headers, options) => { | ||
headers['X-DNS-Prefetch-Control'] = options.allow ? 'on' : 'off' | ||
return headers | ||
} | ||
helmet.dnsPrefetchControl = (headers, config) => { | ||
headers['X-DNS-Prefetch-Control'] = config.allow ? 'on' : 'off'; | ||
return headers; | ||
}; // expectCt - in-progress spec | ||
// https://github.com/helmetjs/frameguard | ||
// expectCt - in-progress spec | ||
// https://github.com/helmetjs/frameguard | ||
helmetHtmlOnly.frameguard = (headers, options) => { | ||
headers['X-Frame-Options'] = options.action.toUpperCase() | ||
return headers | ||
} | ||
helmetHtmlOnly.frameguard = (headers, config) => { | ||
headers['X-Frame-Options'] = config.action.toUpperCase(); | ||
return headers; | ||
}; // https://github.com/helmetjs/hide-powered-by | ||
// https://github.com/helmetjs/hide-powered-by | ||
helmet.hidePoweredBy = (headers, options) => { | ||
if (options.setTo) { | ||
headers['X-Powered-By'] = options.setTo | ||
helmet.hidePoweredBy = (headers, config) => { | ||
if (config.setTo) { | ||
headers['X-Powered-By'] = config.setTo; | ||
} else { | ||
Reflect.deleteProperty(headers, 'Server') | ||
Reflect.deleteProperty(headers, 'X-Powered-By') | ||
Reflect.deleteProperty(headers, 'Server'); | ||
Reflect.deleteProperty(headers, 'X-Powered-By'); | ||
} | ||
return headers | ||
} | ||
// hpkp - deprecated | ||
return headers; | ||
}; // hpkp - deprecated | ||
// https://github.com/helmetjs/hsts | ||
// https://github.com/helmetjs/hsts | ||
helmet.hsts = (headers, options) => { | ||
let header = 'max-age=' + Math.round(options.maxAge) | ||
if (options.includeSubDomains) { | ||
header += '; includeSubDomains' | ||
helmet.hsts = (headers, config) => { | ||
let header = 'max-age=' + Math.round(config.maxAge); | ||
if (config.includeSubDomains) { | ||
header += '; includeSubDomains'; | ||
} | ||
if (options.preload) { | ||
header += '; preload' | ||
if (config.preload) { | ||
header += '; preload'; | ||
} | ||
headers['Strict-Transport-Security'] = header | ||
return headers | ||
} | ||
// https://github.com/helmetjs/ienoopen | ||
helmet.ieNoOpen = (headers, options) => { | ||
headers['X-Download-Options'] = options.action | ||
return headers | ||
} | ||
headers['Strict-Transport-Security'] = header; | ||
return headers; | ||
}; // https://github.com/helmetjs/ienoopen | ||
// noCache - N/A - separate middleware | ||
helmet.ieNoOpen = (headers, config) => { | ||
headers['X-Download-Options'] = config.action; | ||
return headers; | ||
}; // noCache - N/A - separate middleware | ||
// https://github.com/helmetjs/dont-sniff-mimetype | ||
helmet.noSniff = (headers, options) => { | ||
headers['X-Content-Type-Options'] = options.action | ||
return headers | ||
} | ||
// https://github.com/helmetjs/referrer-policy | ||
helmet.referrerPolicy = (headers, options) => { | ||
headers['Referrer-Policy'] = options.policy | ||
return headers | ||
} | ||
// https://github.com/helmetjs/crossdomain | ||
helmet.permittedCrossDomainPolicies = (headers, options) => { | ||
headers['X-Permitted-Cross-Domain-Policies'] = options.policy | ||
return headers | ||
} | ||
helmet.noSniff = (headers, config) => { | ||
headers['X-Content-Type-Options'] = config.action; | ||
return headers; | ||
}; // https://github.com/helmetjs/referrer-policy | ||
// https://github.com/helmetjs/x-xss-protection | ||
helmetHtmlOnly.xssFilter = (headers, options) => { | ||
let header = '1; mode=block' | ||
if (options.reportUri) { | ||
header += '; report=' + options.reportUri | ||
helmet.referrerPolicy = (headers, config) => { | ||
headers['Referrer-Policy'] = config.policy; | ||
return headers; | ||
}; // https://github.com/helmetjs/crossdomain | ||
helmet.permittedCrossDomainPolicies = (headers, config) => { | ||
headers['X-Permitted-Cross-Domain-Policies'] = config.policy; | ||
return headers; | ||
}; // https://github.com/helmetjs/x-xss-protection | ||
helmetHtmlOnly.xssFilter = (headers, config) => { | ||
let header = '1; mode=block'; | ||
if (config.reportUri) { | ||
header += '; report=' + config.reportUri; | ||
} | ||
headers['X-XSS-Protection'] = header | ||
return headers | ||
} | ||
headers['X-XSS-Protection'] = header; | ||
return headers; | ||
}; | ||
module.exports = (opts = {}) => { | ||
opts = Object.assign({}, defaults, opts) | ||
const options = { ...defaults, | ||
...opts | ||
}; | ||
const response = (handler, next) => { | ||
handler.response = handler.response || { statusCode: 500 } // catch thrown errors, prevent default statusCode | ||
handler.response.headers = handler.response.headers || {} | ||
const httpSecurityHeadersMiddlewareAfter = async handler => { | ||
handler.response = handler.response ?? { | ||
statusCode: 500 | ||
}; // catch thrown errors, prevent default statusCode | ||
handler.response.headers = handler.response?.headers ?? {}; | ||
Object.keys(helmet).forEach(key => { | ||
const options = Object.assign({}, defaults[key], opts[key]) | ||
handler.response.headers = helmet[key](handler.response.headers, options) | ||
}) | ||
const config = { ...defaults[key], | ||
...options[key] | ||
}; | ||
handler.response.headers = helmet[key](handler.response.headers, config); | ||
}); | ||
if (handler.response.headers['Content-Type'] && handler.response.headers['Content-Type'].indexOf('text/html') !== -1) { | ||
Object.keys(helmetHtmlOnly).forEach(key => { | ||
const options = Object.assign({}, defaults[key], opts[key]) | ||
handler.response.headers = helmetHtmlOnly[key](handler.response.headers, options) | ||
}) | ||
const config = { ...defaults[key], | ||
...options[key] | ||
}; | ||
handler.response.headers = helmetHtmlOnly[key](handler.response.headers, config); | ||
}); | ||
} | ||
}; | ||
next() | ||
} | ||
const httpSecurityHeadersMiddlewareOnError = httpSecurityHeadersMiddlewareAfter; | ||
return { | ||
after: response, | ||
onError: response | ||
} | ||
} | ||
after: httpSecurityHeadersMiddlewareAfter, | ||
onError: httpSecurityHeadersMiddlewareOnError | ||
}; | ||
}; |
{ | ||
"name": "@middy/http-security-headers", | ||
"version": "1.5.2", | ||
"version": "2.0.0-alpha.0", | ||
"description": "Applies best practice security headers to responses. It's a simplified port of HelmetJS", | ||
"type": "commonjs", | ||
"engines": { | ||
"node": ">=10" | ||
"node": ">=14" | ||
}, | ||
@@ -12,5 +13,7 @@ "engineStrict": true, | ||
}, | ||
"main": "index.js", | ||
"types": "index.d.ts", | ||
"scripts": { | ||
"test": "npm run test:typings && npm run test:unit", | ||
"test:unit": "jest", | ||
"test:unit": "ava", | ||
"test:typings": "typings-tester --config tsconfig.json index.d.ts" | ||
@@ -40,3 +43,4 @@ }, | ||
"type": "git", | ||
"url": "git+https://github.com/middyjs/middy.git" | ||
"url": "github:middyjs/middy", | ||
"directory": "packages/http-security-headers" | ||
}, | ||
@@ -47,10 +51,3 @@ "bugs": { | ||
"homepage": "https://github.com/middyjs/middy#readme", | ||
"peerDependencies": { | ||
"@middy/core": ">=1.0.0-alpha" | ||
}, | ||
"devDependencies": { | ||
"@middy/core": "^1.5.2", | ||
"es6-promisify": "^6.0.2" | ||
}, | ||
"gitHead": "f77cb5e1fc2c529f4fe74efa8a9fb105373b0723" | ||
"gitHead": "e047c0d3db00aa11b39f2d3e193458ea021a58a0" | ||
} |
# Middy http-security-headers middleware | ||
<div align="center"> | ||
<img alt="Middy logo" src="https://raw.githubusercontent.com/middyjs/middy/master/img/middy-logo.png"/> | ||
<img alt="Middy logo" src="https://raw.githubusercontent.com/middyjs/middy/master/docs/img/middy-logo.png"/> | ||
</div> | ||
@@ -23,5 +23,2 @@ | ||
</a> | ||
<a href="https://greenkeeper.io/"> | ||
<img src="https://badges.greenkeeper.io/middyjs/middy.svg" alt="Greenkeeper badge" style="max-width:100%;"> | ||
</a> | ||
<a href="https://gitter.im/middyjs/Lobby"> | ||
@@ -60,7 +57,7 @@ <img src="https://badges.gitter.im/gitterHQ/gitter.svg" alt="Chat on Gitter" style="max-width:100%;"> | ||
```javascript | ||
const middy = require('@middy/core') | ||
const httpSecurityHeaders = require('@middy/http-security-headers') | ||
import middy from '@middy/core' | ||
import httpSecurityHeaders from '@middy/http-security-headers' | ||
const handler = middy((event, context, cb) => { | ||
cb(null, {}) | ||
const handler = middy((event, context) => { | ||
return {} | ||
}) | ||
@@ -85,3 +82,3 @@ | ||
Licensed under [MIT License](LICENSE). Copyright (c) 2017-2018 Luciano Mammino and the [Middy team](https://github.com/middyjs/middy/graphs/contributors). | ||
Licensed under [MIT License](LICENSE). Copyright (c) 2017-2021 Luciano Mammino, will Farrell, and the [Middy team](https://github.com/middyjs/middy/graphs/contributors). | ||
@@ -88,0 +85,0 @@ <a href="https://app.fossa.io/projects/git%2Bgithub.com%2Fmiddyjs%2Fmiddy?ref=badge_large"> |
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
0
0
14462
6
284
1
85