yes-https 3.0.0 → 4.0.3
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.
- package/.github/workflows/ci.yaml +56 -22
- package/.github/workflows/codeql.yml +41 -0
- package/.github/workflows/release.yaml +51 -0
- package/.release-please-manifest.json +3 -0
- package/AGENTS.md +36 -0
- package/CHANGELOG.md +49 -0
- package/README.md +11 -4
- package/SECURITY.md +39 -0
- package/biome.json +30 -0
- package/docs/assets/yes-https.png +0 -0
- package/example/app.js +4 -4
- package/example/package-lock.json +355 -218
- package/example/package.json +1 -1
- package/lib/index.js +33 -30
- package/package.json +12 -24
- package/release-please-config.json +10 -0
- package/renovate.json +12 -4
- package/test/certs/ca.crt +19 -12
- package/test/certs/ca.key +28 -18
- package/test/certs/server.crt +17 -12
- package/test/certs/server.csr +14 -9
- package/test/certs/server.key +28 -15
- package/test/test.js +233 -79
- package/.releaserc.json +0 -3
package/test/test.js
CHANGED
|
@@ -1,90 +1,244 @@
|
|
|
1
|
-
import https from 'node:https';
|
|
2
1
|
import fs from 'node:fs';
|
|
3
|
-
import
|
|
2
|
+
import https from 'node:https';
|
|
3
|
+
import { describe, it } from 'node:test';
|
|
4
4
|
import express from 'express';
|
|
5
5
|
import request from 'supertest';
|
|
6
6
|
import yes from '../lib/index.js';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const TEST_SERVER_CERT = fs.readFileSync('./test/certs/server.crt');
|
|
9
9
|
|
|
10
10
|
describe('yes', () => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
11
|
+
it('should perform the 301 for an http request', async () => {
|
|
12
|
+
// Configure a minimal web server with the defaults
|
|
13
|
+
const app = express();
|
|
14
|
+
app.use(yes());
|
|
15
|
+
app.get('/test', (_request_, response) => {
|
|
16
|
+
response.sendStatus(200);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Verify the request returns a 301
|
|
20
|
+
await request(app).get('/test').expect(301);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should use the correct defaults', { timeout: 60_000 }, async () => {
|
|
24
|
+
// Configure a minimal web server with the defaults
|
|
25
|
+
const app = express();
|
|
26
|
+
app.use(yes());
|
|
27
|
+
app.get('/test', (_request, response) => {
|
|
28
|
+
response.sendStatus(200);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Verify the request returns the right header when using https
|
|
32
|
+
const server = createSecureServer(app);
|
|
33
|
+
await request(server)
|
|
34
|
+
.get('/test')
|
|
35
|
+
.ca(TEST_SERVER_CERT)
|
|
36
|
+
.expect('Strict-Transport-Security', 'max-age=86400; includeSubDomains')
|
|
37
|
+
.expect(200);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should allow disabling includeSubDomains with camel case options', {
|
|
41
|
+
timeout: 60_000,
|
|
42
|
+
}, async () => {
|
|
43
|
+
const app = express();
|
|
44
|
+
app.use(
|
|
45
|
+
yes({
|
|
46
|
+
includeSubDomains: false,
|
|
47
|
+
}),
|
|
48
|
+
);
|
|
49
|
+
app.get('/test', (_request, response) => {
|
|
50
|
+
response.sendStatus(200);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const server = createSecureServer(app);
|
|
54
|
+
await request(server)
|
|
55
|
+
.get('/test')
|
|
56
|
+
.ca(TEST_SERVER_CERT)
|
|
57
|
+
.expect('Strict-Transport-Security', 'max-age=86400')
|
|
58
|
+
.expect(200);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should allow disabling includeSubDomains with the legacy lowercase alias', {
|
|
62
|
+
timeout: 60_000,
|
|
63
|
+
}, async () => {
|
|
64
|
+
const app = express();
|
|
65
|
+
app.use(
|
|
66
|
+
yes({
|
|
67
|
+
includeSubdomains: false,
|
|
68
|
+
}),
|
|
69
|
+
);
|
|
70
|
+
app.get('/test', (_request, response) => {
|
|
71
|
+
response.sendStatus(200);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const server = createSecureServer(app);
|
|
75
|
+
await request(server)
|
|
76
|
+
.get('/test')
|
|
77
|
+
.ca(TEST_SERVER_CERT)
|
|
78
|
+
.expect('Strict-Transport-Security', 'max-age=86400')
|
|
79
|
+
.expect(200);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should ignore filtered requests', async () => {
|
|
83
|
+
// Configure a minimal web server with the defaults
|
|
84
|
+
const app = express();
|
|
85
|
+
app.use(
|
|
86
|
+
yes({
|
|
87
|
+
ignoreFilter: (request_) => request_.url.includes('/_ah/health'),
|
|
88
|
+
}),
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
app.get('/_ah/health', (_request, response) => {
|
|
92
|
+
response.sendStatus(200);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Verify the request returns a 200 for health checks
|
|
96
|
+
await request(app).get('/_ah/health').expect(200);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should include preload when configured', {
|
|
100
|
+
timeout: 60_000,
|
|
101
|
+
}, async () => {
|
|
102
|
+
const app = express();
|
|
103
|
+
app.use(yes({ preload: true }));
|
|
104
|
+
app.get('/test', (_request, response) => {
|
|
105
|
+
response.sendStatus(200);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const server = createSecureServer(app);
|
|
109
|
+
await request(server)
|
|
110
|
+
.get('/test')
|
|
111
|
+
.ca(TEST_SERVER_CERT)
|
|
112
|
+
.expect(
|
|
113
|
+
'Strict-Transport-Security',
|
|
114
|
+
'max-age=86400; includeSubDomains; preload',
|
|
115
|
+
)
|
|
116
|
+
.expect(200);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should omit includeSubDomains when disabled', {
|
|
120
|
+
timeout: 60_000,
|
|
121
|
+
}, async () => {
|
|
122
|
+
const app = express();
|
|
123
|
+
app.use(yes({ includeSubDomains: false }));
|
|
124
|
+
app.get('/test', (_request, response) => {
|
|
125
|
+
response.sendStatus(200);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const server = createSecureServer(app);
|
|
129
|
+
await request(server)
|
|
130
|
+
.get('/test')
|
|
131
|
+
.ca(TEST_SERVER_CERT)
|
|
132
|
+
.expect('Strict-Transport-Security', 'max-age=86400')
|
|
133
|
+
.expect(200);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should include includeSubDomains when explicitly enabled', {
|
|
137
|
+
timeout: 60_000,
|
|
138
|
+
}, async () => {
|
|
139
|
+
const app = express();
|
|
140
|
+
app.use(yes({ includeSubDomains: true }));
|
|
141
|
+
app.get('/test', (_request, response) => {
|
|
142
|
+
response.sendStatus(200);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const server = createSecureServer(app);
|
|
146
|
+
await request(server)
|
|
147
|
+
.get('/test')
|
|
148
|
+
.ca(TEST_SERVER_CERT)
|
|
149
|
+
.expect('Strict-Transport-Security', 'max-age=86400; includeSubDomains')
|
|
150
|
+
.expect(200);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe('includeSubDomains', () => {
|
|
154
|
+
it('should include the directive by default over a secure connection', () => {
|
|
155
|
+
return expectSecureHeader({}, 'max-age=86400; includeSubDomains');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should include the directive when explicitly enabled over a secure connection', () => {
|
|
159
|
+
return expectSecureHeader(
|
|
160
|
+
{ includeSubDomains: true },
|
|
161
|
+
'max-age=86400; includeSubDomains',
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('should omit the directive when disabled over a secure connection', () => {
|
|
166
|
+
return expectSecureHeader({ includeSubDomains: false }, 'max-age=86400');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('should compose correctly with preload and maxAge when enabled', () => {
|
|
170
|
+
return expectSecureHeader(
|
|
171
|
+
{ includeSubDomains: true, preload: true, maxAge: 31_536_000 },
|
|
172
|
+
'max-age=31536000; includeSubDomains; preload',
|
|
173
|
+
);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('should compose correctly with preload and maxAge when disabled', () => {
|
|
177
|
+
return expectSecureHeader(
|
|
178
|
+
{ includeSubDomains: false, preload: true, maxAge: 31_536_000 },
|
|
179
|
+
'max-age=31536000; preload',
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('should include the directive by default for forwarded https requests', () => {
|
|
184
|
+
return expectForwardedSecureHeader(
|
|
185
|
+
{},
|
|
186
|
+
'max-age=86400; includeSubDomains',
|
|
187
|
+
);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('should honor an explicit true value for forwarded https requests', () => {
|
|
191
|
+
return expectForwardedSecureHeader(
|
|
192
|
+
{ includeSubDomains: true },
|
|
193
|
+
'max-age=86400; includeSubDomains',
|
|
194
|
+
);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('should honor an explicit false value for forwarded https requests', () => {
|
|
198
|
+
return expectForwardedSecureHeader(
|
|
199
|
+
{ includeSubDomains: false },
|
|
200
|
+
'max-age=86400',
|
|
201
|
+
);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
79
204
|
});
|
|
80
205
|
|
|
81
206
|
function createSecureServer(app) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
207
|
+
return https.createServer(
|
|
208
|
+
{
|
|
209
|
+
key: fs.readFileSync('./test/certs/server.key'),
|
|
210
|
+
cert: fs.readFileSync('./test/certs/server.crt'),
|
|
211
|
+
},
|
|
212
|
+
app,
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function expectSecureHeader(options, expectedHeader) {
|
|
217
|
+
const app = express();
|
|
218
|
+
app.use(yes(options));
|
|
219
|
+
app.get('/test', (_request, response) => {
|
|
220
|
+
response.sendStatus(200);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const server = createSecureServer(app);
|
|
224
|
+
return request(server)
|
|
225
|
+
.get('/test')
|
|
226
|
+
.ca(TEST_SERVER_CERT)
|
|
227
|
+
.expect('Strict-Transport-Security', expectedHeader)
|
|
228
|
+
.expect(200);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function expectForwardedSecureHeader(options, expectedHeader) {
|
|
232
|
+
const app = express();
|
|
233
|
+
app.use(yes(options));
|
|
234
|
+
app.get('/test', (_request, response) => {
|
|
235
|
+
response.sendStatus(200);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
return request(app)
|
|
239
|
+
.get('/test')
|
|
240
|
+
.set('X-Forwarded-Proto', 'https')
|
|
241
|
+
.set('Host', 'example.com')
|
|
242
|
+
.expect('Strict-Transport-Security', expectedHeader)
|
|
243
|
+
.expect(200);
|
|
90
244
|
}
|
package/.releaserc.json
DELETED