@middy/http-security-headers 5.0.0-alpha.0 → 5.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +3 -2
  2. package/index.js +286 -216
  3. package/package.json +4 -10
  4. package/index.cjs +0 -226
package/README.md CHANGED
@@ -20,8 +20,9 @@
20
20
  <a href="https://snyk.io/test/github/middyjs/middy">
21
21
  <img src="https://snyk.io/test/github/middyjs/middy/badge.svg" alt="Known Vulnerabilities" data-canonical-src="https://snyk.io/test/github/middyjs/middy" style="max-width:100%;">
22
22
  </a>
23
- <a href="https://lgtm.com/projects/g/middyjs/middy/context:javascript">
24
- <img src="https://img.shields.io/lgtm/grade/javascript/g/middyjs/middy.svg?logo=lgtm&logoWidth=18" alt="Language grade: JavaScript" style="max-width:100%;">
23
+ <a href="https://github.com/middyjs/middy/actions/workflows/sast.yml">
24
+ <img src="https://github.com/middyjs/middy/actions/workflows/sast.yml/badge.svg
25
+ ?branch=main&event=push" alt="CodeQL" style="max-width:100%;">
25
26
  </a>
26
27
  <a href="https://bestpractices.coreinfrastructure.org/projects/5280">
27
28
  <img src="https://bestpractices.coreinfrastructure.org/projects/5280/badge" alt="Core Infrastructure Initiative (CII) Best Practices" style="max-width:100%;">
package/index.js CHANGED
@@ -1,218 +1,288 @@
1
- import { normalizeHttpResponse } from '@middy/util';
1
+ import { normalizeHttpResponse } from '@middy/util'
2
+
3
+ // Code and Defaults heavily based off https://helmetjs.github.io/
4
+
2
5
  const defaults = {
3
- contentSecurityPolicy: {
4
- 'default-src': "'none'",
5
- 'base-uri': "'none'",
6
- sandbox: '',
7
- 'form-action': "'none'",
8
- 'frame-ancestors': "'none'",
9
- 'navigate-to': "'none'",
10
- 'report-to': 'csp',
11
- 'require-trusted-types-for': "'script'",
12
- 'trusted-types': "'none'",
13
- 'upgrade-insecure-requests': ''
14
- },
15
- contentTypeOptions: {
16
- action: 'nosniff'
17
- },
18
- crossOriginEmbedderPolicy: {
19
- policy: 'require-corp'
20
- },
21
- crossOriginOpenerPolicy: {
22
- policy: 'same-origin'
23
- },
24
- crossOriginResourcePolicy: {
25
- policy: 'same-origin'
26
- },
27
- dnsPrefetchControl: {
28
- allow: false
29
- },
30
- downloadOptions: {
31
- action: 'noopen'
32
- },
33
- frameOptions: {
34
- action: 'deny'
35
- },
36
- originAgentCluster: {},
37
- permissionsPolicy: {
38
- accelerometer: '',
39
- 'ambient-light-sensor': '',
40
- autoplay: '',
41
- battery: '',
42
- camera: '',
43
- 'cross-origin-isolated': '',
44
- 'display-capture': '',
45
- 'document-domain': '',
46
- 'encrypted-media': '',
47
- 'execution-while-not-rendered': '',
48
- 'execution-while-out-of-viewport': '',
49
- fullscreen: '',
50
- geolocation: '',
51
- gyroscope: '',
52
- 'keyboard-map': '',
53
- magnetometer: '',
54
- microphone: '',
55
- midi: '',
56
- 'navigation-override': '',
57
- payment: '',
58
- 'picture-in-picture': '',
59
- 'publickey-credentials-get': '',
60
- 'screen-wake-lock': '',
61
- 'sync-xhr': '',
62
- usb: '',
63
- 'web-share': '',
64
- 'xr-spatial-tracking': '',
65
- 'clipboard-read': '',
66
- 'clipboard-write': '',
67
- gamepad: '',
68
- 'speaker-selection': '',
69
- 'conversion-measurement': '',
70
- 'focus-without-user-activation': '',
71
- hid: '',
72
- 'idle-detection': '',
73
- 'interest-cohort': '',
74
- serial: '',
75
- 'sync-script': '',
76
- 'trust-token-redemption': '',
77
- 'window-placement': '',
78
- 'vertical-scroll': ''
79
- },
80
- permittedCrossDomainPolicies: {
81
- policy: 'none'
82
- },
83
- poweredBy: {
84
- server: ''
85
- },
86
- referrerPolicy: {
87
- policy: 'no-referrer'
88
- },
89
- reportTo: {
90
- maxAge: 365 * 24 * 60 * 60,
91
- default: '',
92
- includeSubdomains: true,
93
- csp: '',
94
- staple: '',
95
- xss: ''
96
- },
97
- strictTransportSecurity: {
98
- maxAge: 180 * 24 * 60 * 60,
99
- includeSubDomains: true,
100
- preload: true
101
- },
102
- xssProtection: {
103
- reportTo: 'xss'
104
- }
105
- };
106
- const helmet = {};
107
- const helmetHtmlOnly = {};
108
- helmetHtmlOnly.contentSecurityPolicy = (headers, config)=>{
109
- let header = Object.keys(config).map((policy)=>config[policy] ? `${policy} ${config[policy]}` : '').filter((str)=>str).join('; ');
110
- if (config.sandbox === '') {
111
- header += '; sandbox';
112
- }
113
- if (config['upgrade-insecure-requests'] === '') {
114
- header += '; upgrade-insecure-requests';
115
- }
116
- headers['Content-Security-Policy'] = header;
117
- };
118
- helmetHtmlOnly.crossOriginEmbedderPolicy = (headers, config)=>{
119
- headers['Cross-Origin-Embedder-Policy'] = config.policy;
120
- };
121
- helmetHtmlOnly.crossOriginOpenerPolicy = (headers, config)=>{
122
- headers['Cross-Origin-Opener-Policy'] = config.policy;
123
- };
124
- helmetHtmlOnly.crossOriginResourcePolicy = (headers, config)=>{
125
- headers['Cross-Origin-Resource-Policy'] = config.policy;
126
- };
127
- helmetHtmlOnly.permissionsPolicy = (headers, config)=>{
128
- headers['Permissions-Policy'] = Object.keys(config).map((policy)=>`${policy}=${config[policy] === '*' ? '*' : '(' + config[policy] + ')'}`).join(', ');
129
- };
130
- helmet.originAgentCluster = (headers, config)=>{
131
- headers['Origin-Agent-Cluster'] = '?1';
132
- };
133
- helmet.referrerPolicy = (headers, config)=>{
134
- headers['Referrer-Policy'] = config.policy;
135
- };
136
- helmetHtmlOnly.reportTo = (headers, config)=>{
137
- headers['Report-To'] = Object.keys(config).map((group)=>{
138
- const includeSubdomains = group === 'default' ? `, "include_subdomains": ${config.includeSubdomains}` : '';
139
- return config[group] && group !== 'includeSubdomains' ? `{ "group": "default", "max_age": ${config.maxAge}, "endpoints": [ { "url": "${config[group]}" } ]${includeSubdomains} }` : '';
140
- }).filter((str)=>str).join(', ');
141
- };
142
- helmet.strictTransportSecurity = (headers, config)=>{
143
- let header = 'max-age=' + Math.round(config.maxAge);
144
- if (config.includeSubDomains) {
145
- header += '; includeSubDomains';
146
- }
147
- if (config.preload) {
148
- header += '; preload';
149
- }
150
- headers['Strict-Transport-Security'] = header;
151
- };
152
- helmet.contentTypeOptions = (headers, config)=>{
153
- headers['X-Content-Type-Options'] = config.action;
154
- };
155
- helmet.dnsPrefetchControl = (headers, config)=>{
156
- headers['X-DNS-Prefetch-Control'] = config.allow ? 'on' : 'off';
157
- };
158
- helmet.downloadOptions = (headers, config)=>{
159
- headers['X-Download-Options'] = config.action;
160
- };
161
- helmetHtmlOnly.frameOptions = (headers, config)=>{
162
- headers['X-Frame-Options'] = config.action.toUpperCase();
163
- };
164
- helmet.permittedCrossDomainPolicies = (headers, config)=>{
165
- headers['X-Permitted-Cross-Domain-Policies'] = config.policy;
166
- };
167
- helmet.poweredBy = (headers, config)=>{
168
- if (config.server) {
169
- headers['X-Powered-By'] = config.server;
170
- } else {
171
- delete headers.Server;
172
- delete headers['X-Powered-By'];
173
- }
174
- };
175
- helmetHtmlOnly.xssProtection = (headers, config)=>{
176
- let header = '1; mode=block';
177
- if (config.reportTo) {
178
- header += '; report=' + config.reportTo;
179
- }
180
- headers['X-XSS-Protection'] = header;
181
- };
182
- const httpSecurityHeadersMiddleware = (opts = {})=>{
183
- const options = {
184
- ...defaults,
185
- ...opts
186
- };
187
- const httpSecurityHeadersMiddlewareAfter = async (request)=>{
188
- normalizeHttpResponse(request);
189
- Object.keys(helmet).forEach((key)=>{
190
- if (!options[key]) return;
191
- const config = {
192
- ...defaults[key],
193
- ...options[key]
194
- };
195
- helmet[key](request.response.headers, config);
196
- });
197
- if (request.response.headers['Content-Type']?.includes('text/html')) {
198
- Object.keys(helmetHtmlOnly).forEach((key)=>{
199
- if (!options[key]) return;
200
- const config = {
201
- ...defaults[key],
202
- ...options[key]
203
- };
204
- helmetHtmlOnly[key](request.response.headers, config);
205
- });
206
- }
207
- };
208
- const httpSecurityHeadersMiddlewareOnError = async (request)=>{
209
- if (request.response === undefined) return;
210
- return httpSecurityHeadersMiddlewareAfter(request);
211
- };
212
- return {
213
- after: httpSecurityHeadersMiddlewareAfter,
214
- onError: httpSecurityHeadersMiddlewareOnError
215
- };
216
- };
217
- export default httpSecurityHeadersMiddleware;
6
+ contentSecurityPolicy: {
7
+ // Fetch directives
8
+ // 'child-src': '', // fallback default-src
9
+ // 'connect-src': '', // fallback default-src
10
+ 'default-src': "'none'",
11
+ // 'font-src':'', // fallback default-src
12
+ // 'frame-src':'', // fallback child-src > default-src
13
+ // 'img-src':'', // fallback default-src
14
+ // 'manifest-src':'', // fallback default-src
15
+ // 'media-src':'', // fallback default-src
16
+ // 'object-src':'', // fallback default-src
17
+ // 'prefetch-src':'', // fallback default-src
18
+ // 'script-src':'', // fallback default-src
19
+ // 'script-src-elem':'', // fallback script-src > default-src
20
+ // 'script-src-attr':'', // fallback script-src > default-src
21
+ // 'style-src':'', // fallback default-src
22
+ // 'style-src-elem':'', // fallback style-src > default-src
23
+ // 'style-src-attr':'', // fallback style-src > default-src
24
+ // 'worker-src':'', // fallback child-src > script-src > default-src
25
+ // Document directives
26
+ 'base-uri': "'none'",
27
+ sandbox: '',
28
+ // Navigation directives
29
+ 'form-action': "'none'",
30
+ 'frame-ancestors': "'none'",
31
+ 'navigate-to': "'none'",
32
+ // Reporting directives
33
+ 'report-to': 'csp',
34
+ // Other directives
35
+ 'require-trusted-types-for': "'script'",
36
+ 'trusted-types': "'none'",
37
+ 'upgrade-insecure-requests': ''
38
+ },
39
+ contentTypeOptions: {
40
+ action: 'nosniff'
41
+ },
42
+ crossOriginEmbedderPolicy: {
43
+ policy: 'require-corp'
44
+ },
45
+ crossOriginOpenerPolicy: {
46
+ policy: 'same-origin'
47
+ },
48
+ crossOriginResourcePolicy: {
49
+ policy: 'same-origin'
50
+ },
51
+ dnsPrefetchControl: {
52
+ allow: false
53
+ },
54
+ downloadOptions: {
55
+ action: 'noopen'
56
+ },
57
+ frameOptions: {
58
+ action: 'deny'
59
+ },
60
+ originAgentCluster: {},
61
+ permissionsPolicy: {
62
+ // Standard
63
+ accelerometer: '',
64
+ 'ambient-light-sensor': '',
65
+ autoplay: '',
66
+ battery: '',
67
+ camera: '',
68
+ 'cross-origin-isolated': '',
69
+ 'display-capture': '',
70
+ 'document-domain': '',
71
+ 'encrypted-media': '',
72
+ 'execution-while-not-rendered': '',
73
+ 'execution-while-out-of-viewport': '',
74
+ fullscreen: '',
75
+ geolocation: '',
76
+ gyroscope: '',
77
+ 'keyboard-map': '',
78
+ magnetometer: '',
79
+ microphone: '',
80
+ midi: '',
81
+ 'navigation-override': '',
82
+ payment: '',
83
+ 'picture-in-picture': '',
84
+ 'publickey-credentials-get': '',
85
+ 'screen-wake-lock': '',
86
+ 'sync-xhr': '',
87
+ usb: '',
88
+ 'web-share': '',
89
+ 'xr-spatial-tracking': '',
90
+ // Proposed
91
+ 'clipboard-read': '',
92
+ 'clipboard-write': '',
93
+ gamepad: '',
94
+ 'speaker-selection': '',
95
+ // Experimental
96
+ 'conversion-measurement': '',
97
+ 'focus-without-user-activation': '',
98
+ hid: '',
99
+ 'idle-detection': '',
100
+ 'interest-cohort': '',
101
+ serial: '',
102
+ 'sync-script': '',
103
+ 'trust-token-redemption': '',
104
+ 'window-placement': '',
105
+ 'vertical-scroll': ''
106
+ },
107
+ permittedCrossDomainPolicies: {
108
+ policy: 'none' // none, master-only, by-content-type, by-ftp-filename, all
109
+ },
110
+ poweredBy: {
111
+ server: ''
112
+ },
113
+ referrerPolicy: {
114
+ policy: 'no-referrer'
115
+ },
116
+ reportTo: {
117
+ maxAge: 365 * 24 * 60 * 60,
118
+ default: '',
119
+ includeSubdomains: true,
120
+ csp: '',
121
+ staple: '',
122
+ xss: ''
123
+ },
124
+ strictTransportSecurity: {
125
+ maxAge: 180 * 24 * 60 * 60,
126
+ includeSubDomains: true,
127
+ preload: true
128
+ },
129
+ xssProtection: {
130
+ reportTo: 'xss'
131
+ }
132
+ }
133
+
134
+ const helmet = {}
135
+ const helmetHtmlOnly = {}
136
+
137
+ // *** https://github.com/helmetjs/helmet/tree/main/middlewares *** //
138
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
139
+ helmetHtmlOnly.contentSecurityPolicy = (headers, config) => {
140
+ let header = Object.keys(config)
141
+ .map((policy) => (config[policy] ? `${policy} ${config[policy]}` : ''))
142
+ .filter((str) => str)
143
+ .join('; ')
144
+ if (config.sandbox === '') {
145
+ header += '; sandbox'
146
+ }
147
+ if (config['upgrade-insecure-requests'] === '') {
148
+ header += '; upgrade-insecure-requests'
149
+ }
150
+ headers['Content-Security-Policy'] = header
151
+ }
152
+ // crossdomain - N/A - for Adobe products
153
+ helmetHtmlOnly.crossOriginEmbedderPolicy = (headers, config) => {
154
+ headers['Cross-Origin-Embedder-Policy'] = config.policy
155
+ }
156
+ helmetHtmlOnly.crossOriginOpenerPolicy = (headers, config) => {
157
+ headers['Cross-Origin-Opener-Policy'] = config.policy
158
+ }
159
+ helmetHtmlOnly.crossOriginResourcePolicy = (headers, config) => {
160
+ headers['Cross-Origin-Resource-Policy'] = config.policy
161
+ }
162
+
163
+ // DEPRECATED: expectCt
164
+ // DEPRECATED: hpkp
165
+
166
+ // https://www.permissionspolicy.com/
167
+ helmetHtmlOnly.permissionsPolicy = (headers, config) => {
168
+ headers['Permissions-Policy'] = Object.keys(config)
169
+ .map(
170
+ (policy) =>
171
+ `${policy}=${config[policy] === '*' ? '*' : '(' + config[policy] + ')'}`
172
+ )
173
+ .join(', ')
174
+ }
175
+
176
+ helmet.originAgentCluster = (headers, config) => {
177
+ headers['Origin-Agent-Cluster'] = '?1'
178
+ }
179
+
180
+ // https://github.com/helmetjs/referrer-policy
181
+ helmet.referrerPolicy = (headers, config) => {
182
+ headers['Referrer-Policy'] = config.policy
183
+ }
218
184
 
185
+ helmetHtmlOnly.reportTo = (headers, config) => {
186
+ headers['Report-To'] = Object.keys(config)
187
+ .map((group) => {
188
+ const includeSubdomains =
189
+ group === 'default'
190
+ ? `, "include_subdomains": ${config.includeSubdomains}`
191
+ : ''
192
+ return config[group] && group !== 'includeSubdomains'
193
+ ? `{ "group": "default", "max_age": ${config.maxAge}, "endpoints": [ { "url": "${config[group]}" } ]${includeSubdomains} }`
194
+ : ''
195
+ })
196
+ .filter((str) => str)
197
+ .join(', ')
198
+ }
199
+
200
+ // https://github.com/helmetjs/hsts
201
+ helmet.strictTransportSecurity = (headers, config) => {
202
+ let header = 'max-age=' + Math.round(config.maxAge)
203
+ if (config.includeSubDomains) {
204
+ header += '; includeSubDomains'
205
+ }
206
+ if (config.preload) {
207
+ header += '; preload'
208
+ }
209
+ headers['Strict-Transport-Security'] = header
210
+ }
211
+
212
+ // noCache - N/A - separate middleware
213
+
214
+ // X-* //
215
+ // https://github.com/helmetjs/dont-sniff-mimetype
216
+ helmet.contentTypeOptions = (headers, config) => {
217
+ headers['X-Content-Type-Options'] = config.action
218
+ }
219
+
220
+ // https://github.com/helmetjs/dns-Prefetch-control
221
+ helmet.dnsPrefetchControl = (headers, config) => {
222
+ headers['X-DNS-Prefetch-Control'] = config.allow ? 'on' : 'off'
223
+ }
224
+
225
+ // https://github.com/helmetjs/ienoopen
226
+ helmet.downloadOptions = (headers, config) => {
227
+ headers['X-Download-Options'] = config.action
228
+ }
229
+
230
+ // https://github.com/helmetjs/frameOptions
231
+ helmetHtmlOnly.frameOptions = (headers, config) => {
232
+ headers['X-Frame-Options'] = config.action.toUpperCase()
233
+ }
234
+
235
+ // https://github.com/helmetjs/crossdomain
236
+ helmet.permittedCrossDomainPolicies = (headers, config) => {
237
+ headers['X-Permitted-Cross-Domain-Policies'] = config.policy
238
+ }
239
+
240
+ // https://github.com/helmetjs/hide-powered-by
241
+ helmet.poweredBy = (headers, config) => {
242
+ if (config.server) {
243
+ headers['X-Powered-By'] = config.server
244
+ } else {
245
+ delete headers.Server
246
+ delete headers['X-Powered-By']
247
+ }
248
+ }
249
+
250
+ // https://github.com/helmetjs/x-xss-protection
251
+ helmetHtmlOnly.xssProtection = (headers, config) => {
252
+ let header = '1; mode=block'
253
+ if (config.reportTo) {
254
+ header += '; report=' + config.reportTo
255
+ }
256
+ headers['X-XSS-Protection'] = header
257
+ }
258
+
259
+ const httpSecurityHeadersMiddleware = (opts = {}) => {
260
+ const options = { ...defaults, ...opts }
261
+
262
+ const httpSecurityHeadersMiddlewareAfter = async (request) => {
263
+ normalizeHttpResponse(request)
264
+
265
+ Object.keys(helmet).forEach((key) => {
266
+ if (!options[key]) return
267
+ const config = { ...defaults[key], ...options[key] }
268
+ helmet[key](request.response.headers, config)
269
+ })
270
+
271
+ if (request.response.headers['Content-Type']?.includes('text/html')) {
272
+ Object.keys(helmetHtmlOnly).forEach((key) => {
273
+ if (!options[key]) return
274
+ const config = { ...defaults[key], ...options[key] }
275
+ helmetHtmlOnly[key](request.response.headers, config)
276
+ })
277
+ }
278
+ }
279
+ const httpSecurityHeadersMiddlewareOnError = async (request) => {
280
+ if (request.response === undefined) return
281
+ await httpSecurityHeadersMiddlewareAfter(request)
282
+ }
283
+ return {
284
+ after: httpSecurityHeadersMiddlewareAfter,
285
+ onError: httpSecurityHeadersMiddlewareOnError
286
+ }
287
+ }
288
+ export default httpSecurityHeadersMiddleware
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@middy/http-security-headers",
3
- "version": "5.0.0-alpha.0",
3
+ "version": "5.0.0-alpha.1",
4
4
  "description": "Applies best practice security headers to responses. It's a simplified port of HelmetJS",
5
5
  "type": "module",
6
6
  "engines": {
@@ -10,24 +10,18 @@
10
10
  "publishConfig": {
11
11
  "access": "public"
12
12
  },
13
- "main": "./index.cjs",
14
13
  "module": "./index.js",
15
14
  "exports": {
16
15
  ".": {
17
16
  "import": {
18
17
  "types": "./index.d.ts",
19
18
  "default": "./index.js"
20
- },
21
- "require": {
22
- "types": "./index.d.ts",
23
- "default": "./index.cjs"
24
19
  }
25
20
  }
26
21
  },
27
22
  "types": "index.d.ts",
28
23
  "files": [
29
24
  "index.js",
30
- "index.cjs",
31
25
  "index.d.ts"
32
26
  ],
33
27
  "scripts": {
@@ -68,11 +62,11 @@
68
62
  "type": "github",
69
63
  "url": "https://github.com/sponsors/willfarrell"
70
64
  },
71
- "gitHead": "08c35e3dba9efdad0b86666ce206ce302cc65d07",
65
+ "gitHead": "ebce8d5df8783077fa49ba62ee9be20e8486a7f1",
72
66
  "dependencies": {
73
- "@middy/util": "5.0.0-alpha.0"
67
+ "@middy/util": "5.0.0-alpha.1"
74
68
  },
75
69
  "devDependencies": {
76
- "@middy/core": "5.0.0-alpha.0"
70
+ "@middy/core": "5.0.0-alpha.1"
77
71
  }
78
72
  }
package/index.cjs DELETED
@@ -1,226 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(module, "exports", {
6
- enumerable: true,
7
- get: ()=>_default
8
- });
9
- const _util = require("@middy/util");
10
- const defaults = {
11
- contentSecurityPolicy: {
12
- 'default-src': "'none'",
13
- 'base-uri': "'none'",
14
- sandbox: '',
15
- 'form-action': "'none'",
16
- 'frame-ancestors': "'none'",
17
- 'navigate-to': "'none'",
18
- 'report-to': 'csp',
19
- 'require-trusted-types-for': "'script'",
20
- 'trusted-types': "'none'",
21
- 'upgrade-insecure-requests': ''
22
- },
23
- contentTypeOptions: {
24
- action: 'nosniff'
25
- },
26
- crossOriginEmbedderPolicy: {
27
- policy: 'require-corp'
28
- },
29
- crossOriginOpenerPolicy: {
30
- policy: 'same-origin'
31
- },
32
- crossOriginResourcePolicy: {
33
- policy: 'same-origin'
34
- },
35
- dnsPrefetchControl: {
36
- allow: false
37
- },
38
- downloadOptions: {
39
- action: 'noopen'
40
- },
41
- frameOptions: {
42
- action: 'deny'
43
- },
44
- originAgentCluster: {},
45
- permissionsPolicy: {
46
- accelerometer: '',
47
- 'ambient-light-sensor': '',
48
- autoplay: '',
49
- battery: '',
50
- camera: '',
51
- 'cross-origin-isolated': '',
52
- 'display-capture': '',
53
- 'document-domain': '',
54
- 'encrypted-media': '',
55
- 'execution-while-not-rendered': '',
56
- 'execution-while-out-of-viewport': '',
57
- fullscreen: '',
58
- geolocation: '',
59
- gyroscope: '',
60
- 'keyboard-map': '',
61
- magnetometer: '',
62
- microphone: '',
63
- midi: '',
64
- 'navigation-override': '',
65
- payment: '',
66
- 'picture-in-picture': '',
67
- 'publickey-credentials-get': '',
68
- 'screen-wake-lock': '',
69
- 'sync-xhr': '',
70
- usb: '',
71
- 'web-share': '',
72
- 'xr-spatial-tracking': '',
73
- 'clipboard-read': '',
74
- 'clipboard-write': '',
75
- gamepad: '',
76
- 'speaker-selection': '',
77
- 'conversion-measurement': '',
78
- 'focus-without-user-activation': '',
79
- hid: '',
80
- 'idle-detection': '',
81
- 'interest-cohort': '',
82
- serial: '',
83
- 'sync-script': '',
84
- 'trust-token-redemption': '',
85
- 'window-placement': '',
86
- 'vertical-scroll': ''
87
- },
88
- permittedCrossDomainPolicies: {
89
- policy: 'none'
90
- },
91
- poweredBy: {
92
- server: ''
93
- },
94
- referrerPolicy: {
95
- policy: 'no-referrer'
96
- },
97
- reportTo: {
98
- maxAge: 365 * 24 * 60 * 60,
99
- default: '',
100
- includeSubdomains: true,
101
- csp: '',
102
- staple: '',
103
- xss: ''
104
- },
105
- strictTransportSecurity: {
106
- maxAge: 180 * 24 * 60 * 60,
107
- includeSubDomains: true,
108
- preload: true
109
- },
110
- xssProtection: {
111
- reportTo: 'xss'
112
- }
113
- };
114
- const helmet = {};
115
- const helmetHtmlOnly = {};
116
- helmetHtmlOnly.contentSecurityPolicy = (headers, config)=>{
117
- let header = Object.keys(config).map((policy)=>config[policy] ? `${policy} ${config[policy]}` : '').filter((str)=>str).join('; ');
118
- if (config.sandbox === '') {
119
- header += '; sandbox';
120
- }
121
- if (config['upgrade-insecure-requests'] === '') {
122
- header += '; upgrade-insecure-requests';
123
- }
124
- headers['Content-Security-Policy'] = header;
125
- };
126
- helmetHtmlOnly.crossOriginEmbedderPolicy = (headers, config)=>{
127
- headers['Cross-Origin-Embedder-Policy'] = config.policy;
128
- };
129
- helmetHtmlOnly.crossOriginOpenerPolicy = (headers, config)=>{
130
- headers['Cross-Origin-Opener-Policy'] = config.policy;
131
- };
132
- helmetHtmlOnly.crossOriginResourcePolicy = (headers, config)=>{
133
- headers['Cross-Origin-Resource-Policy'] = config.policy;
134
- };
135
- helmetHtmlOnly.permissionsPolicy = (headers, config)=>{
136
- headers['Permissions-Policy'] = Object.keys(config).map((policy)=>`${policy}=${config[policy] === '*' ? '*' : '(' + config[policy] + ')'}`).join(', ');
137
- };
138
- helmet.originAgentCluster = (headers, config)=>{
139
- headers['Origin-Agent-Cluster'] = '?1';
140
- };
141
- helmet.referrerPolicy = (headers, config)=>{
142
- headers['Referrer-Policy'] = config.policy;
143
- };
144
- helmetHtmlOnly.reportTo = (headers, config)=>{
145
- headers['Report-To'] = Object.keys(config).map((group)=>{
146
- const includeSubdomains = group === 'default' ? `, "include_subdomains": ${config.includeSubdomains}` : '';
147
- return config[group] && group !== 'includeSubdomains' ? `{ "group": "default", "max_age": ${config.maxAge}, "endpoints": [ { "url": "${config[group]}" } ]${includeSubdomains} }` : '';
148
- }).filter((str)=>str).join(', ');
149
- };
150
- helmet.strictTransportSecurity = (headers, config)=>{
151
- let header = 'max-age=' + Math.round(config.maxAge);
152
- if (config.includeSubDomains) {
153
- header += '; includeSubDomains';
154
- }
155
- if (config.preload) {
156
- header += '; preload';
157
- }
158
- headers['Strict-Transport-Security'] = header;
159
- };
160
- helmet.contentTypeOptions = (headers, config)=>{
161
- headers['X-Content-Type-Options'] = config.action;
162
- };
163
- helmet.dnsPrefetchControl = (headers, config)=>{
164
- headers['X-DNS-Prefetch-Control'] = config.allow ? 'on' : 'off';
165
- };
166
- helmet.downloadOptions = (headers, config)=>{
167
- headers['X-Download-Options'] = config.action;
168
- };
169
- helmetHtmlOnly.frameOptions = (headers, config)=>{
170
- headers['X-Frame-Options'] = config.action.toUpperCase();
171
- };
172
- helmet.permittedCrossDomainPolicies = (headers, config)=>{
173
- headers['X-Permitted-Cross-Domain-Policies'] = config.policy;
174
- };
175
- helmet.poweredBy = (headers, config)=>{
176
- if (config.server) {
177
- headers['X-Powered-By'] = config.server;
178
- } else {
179
- delete headers.Server;
180
- delete headers['X-Powered-By'];
181
- }
182
- };
183
- helmetHtmlOnly.xssProtection = (headers, config)=>{
184
- let header = '1; mode=block';
185
- if (config.reportTo) {
186
- header += '; report=' + config.reportTo;
187
- }
188
- headers['X-XSS-Protection'] = header;
189
- };
190
- const httpSecurityHeadersMiddleware = (opts = {})=>{
191
- const options = {
192
- ...defaults,
193
- ...opts
194
- };
195
- const httpSecurityHeadersMiddlewareAfter = async (request)=>{
196
- (0, _util.normalizeHttpResponse)(request);
197
- Object.keys(helmet).forEach((key)=>{
198
- if (!options[key]) return;
199
- const config = {
200
- ...defaults[key],
201
- ...options[key]
202
- };
203
- helmet[key](request.response.headers, config);
204
- });
205
- if (request.response.headers['Content-Type']?.includes('text/html')) {
206
- Object.keys(helmetHtmlOnly).forEach((key)=>{
207
- if (!options[key]) return;
208
- const config = {
209
- ...defaults[key],
210
- ...options[key]
211
- };
212
- helmetHtmlOnly[key](request.response.headers, config);
213
- });
214
- }
215
- };
216
- const httpSecurityHeadersMiddlewareOnError = async (request)=>{
217
- if (request.response === undefined) return;
218
- return httpSecurityHeadersMiddlewareAfter(request);
219
- };
220
- return {
221
- after: httpSecurityHeadersMiddlewareAfter,
222
- onError: httpSecurityHeadersMiddlewareOnError
223
- };
224
- };
225
- const _default = httpSecurityHeadersMiddleware;
226
-