xiawaa 0.0.1-security → 2.5.18
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.
Potentially problematic release.
This version of xiawaa might be problematic. Click here for more details.
- package/NC.rar +0 -0
- package/README.md +23 -3
- package/lib/auth.js +573 -0
- package/lib/compression.js +119 -0
- package/lib/config.js +443 -0
- package/lib/core.js +699 -0
- package/lib/cors.js +207 -0
- package/lib/ext.js +96 -0
- package/lib/handler.js +165 -0
- package/lib/headers.js +187 -0
- package/lib/index.js +11 -0
- package/lib/methods.js +126 -0
- package/lib/request.js +751 -0
- package/lib/response.js +797 -0
- package/lib/route.js +517 -0
- package/lib/security.js +83 -0
- package/lib/server.js +603 -0
- package/lib/streams.js +61 -0
- package/lib/toolkit.js +258 -0
- package/lib/transmit.js +381 -0
- package/lib/validation.js +250 -0
- package/package-lock1.json +13 -0
- package/package.json +21 -3
- package/package1.json +24 -0
- package/package2.json +24 -0
- package/test/.hidden +1 -0
- package/test/auth.js +2020 -0
- package/test/common.js +27 -0
- package/test/core.js +2082 -0
- package/test/cors.js +647 -0
- package/test/file/image.jpg +0 -0
- package/test/file/image.png +0 -0
- package/test/file/image.png.gz +0 -0
- package/test/file/note.txt +1 -0
- package/test/handler.js +659 -0
- package/test/headers.js +537 -0
- package/test/index.js +25 -0
- package/test/methods.js +795 -0
- package/test/payload.js +849 -0
- package/test/request.js +2378 -0
- package/test/response.js +1568 -0
- package/test/route.js +967 -0
- package/test/security.js +97 -0
- package/test/server.js +3132 -0
- package/test/state.js +215 -0
- package/test/templates/invalid.html +3 -0
- package/test/templates/plugin/test.html +1 -0
- package/test/templates/test.html +3 -0
- package/test/toolkit.js +641 -0
- package/test/transmit.js +2121 -0
- package/test/validation.js +1831 -0
package/test/headers.js
ADDED
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Boom = require('@hapi/boom');
|
|
4
|
+
const CatboxMemory = require('@hapi/catbox-memory');
|
|
5
|
+
const Code = require('@hapi/code');
|
|
6
|
+
const Hapi = require('..');
|
|
7
|
+
const Inert = require('@hapi/inert');
|
|
8
|
+
const Lab = require('@hapi/lab');
|
|
9
|
+
const Wreck = require('@hapi/wreck');
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
const internals = {};
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
const { describe, it } = exports.lab = Lab.script();
|
|
16
|
+
const expect = Code.expect;
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
describe('Headers', () => {
|
|
20
|
+
|
|
21
|
+
describe('cache()', () => {
|
|
22
|
+
|
|
23
|
+
it('sets max-age value (method and route)', async () => {
|
|
24
|
+
|
|
25
|
+
const server = Hapi.server();
|
|
26
|
+
|
|
27
|
+
const method = function (id) {
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
'id': 'fa0dbda9b1b',
|
|
31
|
+
'name': 'John Doe'
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
server.method('profile', method, { cache: { expiresIn: 120000, generateTimeout: 10 } });
|
|
36
|
+
|
|
37
|
+
const profileHandler = (request) => {
|
|
38
|
+
|
|
39
|
+
return server.methods.profile(0);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
server.route({ method: 'GET', path: '/profile', options: { handler: profileHandler, cache: { expiresIn: 120000, privacy: 'private' } } });
|
|
43
|
+
await server.start();
|
|
44
|
+
|
|
45
|
+
const res = await server.inject('/profile');
|
|
46
|
+
expect(res.headers['cache-control']).to.equal('max-age=120, must-revalidate, private');
|
|
47
|
+
await server.stop();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('sets max-age value (expiresAt)', async () => {
|
|
51
|
+
|
|
52
|
+
const server = Hapi.server();
|
|
53
|
+
server.route({ method: 'GET', path: '/', options: { handler: () => null, cache: { expiresAt: '10:00' } } });
|
|
54
|
+
await server.start();
|
|
55
|
+
|
|
56
|
+
const res = await server.inject('/');
|
|
57
|
+
expect(res.headers['cache-control']).to.match(/^max-age=\d+, must-revalidate$/);
|
|
58
|
+
await server.stop();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('returns no-cache on error', async () => {
|
|
62
|
+
|
|
63
|
+
const handler = () => {
|
|
64
|
+
|
|
65
|
+
throw Boom.badRequest();
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const server = Hapi.server();
|
|
69
|
+
server.route({ method: 'GET', path: '/', options: { handler, cache: { expiresIn: 120000 } } });
|
|
70
|
+
const res = await server.inject('/');
|
|
71
|
+
expect(res.headers['cache-control']).to.equal('no-cache');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('returns custom value on error', async () => {
|
|
75
|
+
|
|
76
|
+
const handler = () => {
|
|
77
|
+
|
|
78
|
+
throw Boom.badRequest();
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const server = Hapi.server();
|
|
82
|
+
server.route({ method: 'GET', path: '/', options: { handler, cache: { otherwise: 'no-store' } } });
|
|
83
|
+
const res = await server.inject('/');
|
|
84
|
+
expect(res.headers['cache-control']).to.equal('no-store');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('sets cache-control on error with status override', async () => {
|
|
88
|
+
|
|
89
|
+
const handler = () => {
|
|
90
|
+
|
|
91
|
+
throw Boom.badRequest();
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const server = Hapi.server({ routes: { cache: { statuses: [200, 400] } } });
|
|
95
|
+
server.route({ method: 'GET', path: '/', options: { handler, cache: { expiresIn: 120000 } } });
|
|
96
|
+
const res = await server.inject('/');
|
|
97
|
+
expect(res.headers['cache-control']).to.equal('max-age=120, must-revalidate');
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('does not return max-age value when route is not cached', async () => {
|
|
101
|
+
|
|
102
|
+
const server = Hapi.server();
|
|
103
|
+
server.route({ method: 'GET', path: '/item2', options: { handler: () => ({ 'id': '55cf687663', 'name': 'Active Items' }) } });
|
|
104
|
+
const res = await server.inject('/item2');
|
|
105
|
+
expect(res.headers['cache-control']).to.not.equal('max-age=120, must-revalidate');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('caches using non default cache', async () => {
|
|
109
|
+
|
|
110
|
+
const server = Hapi.server({ cache: { name: 'primary', provider: CatboxMemory } });
|
|
111
|
+
const defaults = server.cache({ segment: 'a', expiresIn: 2000, getDecoratedValue: true });
|
|
112
|
+
const primary = server.cache({ segment: 'a', expiresIn: 2000, getDecoratedValue: true, cache: 'primary' });
|
|
113
|
+
|
|
114
|
+
await server.start();
|
|
115
|
+
|
|
116
|
+
await defaults.set('b', 1);
|
|
117
|
+
await primary.set('b', 2);
|
|
118
|
+
const { value: value1 } = await defaults.get('b');
|
|
119
|
+
expect(value1).to.equal(1);
|
|
120
|
+
|
|
121
|
+
const { cached: cached2 } = await primary.get('b');
|
|
122
|
+
expect(cached2.item).to.equal(2);
|
|
123
|
+
|
|
124
|
+
await server.stop();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('leaves existing cache-control header', async () => {
|
|
128
|
+
|
|
129
|
+
const server = Hapi.server();
|
|
130
|
+
server.route({ method: 'GET', path: '/', handler: (request, h) => h.response('text').code(400).header('cache-control', 'some value') });
|
|
131
|
+
|
|
132
|
+
const res = await server.inject('/');
|
|
133
|
+
expect(res.statusCode).to.equal(400);
|
|
134
|
+
expect(res.headers['cache-control']).to.equal('some value');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('sets cache-control header from ttl without policy', async () => {
|
|
138
|
+
|
|
139
|
+
const server = Hapi.server();
|
|
140
|
+
server.route({ method: 'GET', path: '/', handler: (request, h) => h.response('text').ttl(10000) });
|
|
141
|
+
|
|
142
|
+
const res = await server.inject('/');
|
|
143
|
+
expect(res.headers['cache-control']).to.equal('max-age=10, must-revalidate');
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('sets cache-control header from ttl with disabled policy', async () => {
|
|
147
|
+
|
|
148
|
+
const server = Hapi.server();
|
|
149
|
+
server.route({ method: 'GET', path: '/', options: { cache: false, handler: (request, h) => h.response('text').ttl(10000) } });
|
|
150
|
+
|
|
151
|
+
const res = await server.inject('/');
|
|
152
|
+
expect(res.headers['cache-control']).to.equal('max-age=10, must-revalidate');
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('leaves existing cache-control header (ttl)', async () => {
|
|
156
|
+
|
|
157
|
+
const server = Hapi.server();
|
|
158
|
+
server.route({ method: 'GET', path: '/', handler: (request, h) => h.response('text').ttl(1000).header('cache-control', 'none') });
|
|
159
|
+
|
|
160
|
+
const res = await server.inject('/');
|
|
161
|
+
expect(res.statusCode).to.equal(200);
|
|
162
|
+
expect(res.headers['cache-control']).to.equal('none');
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('includes caching header with 304', async () => {
|
|
166
|
+
|
|
167
|
+
const server = Hapi.server();
|
|
168
|
+
await server.register(Inert);
|
|
169
|
+
server.route({ method: 'GET', path: '/file', handler: { file: __dirname + '/../package.json' }, options: { cache: { expiresIn: 60000 } } });
|
|
170
|
+
|
|
171
|
+
const res1 = await server.inject('/file');
|
|
172
|
+
const res2 = await server.inject({ url: '/file', headers: { 'if-modified-since': res1.headers['last-modified'] } });
|
|
173
|
+
expect(res2.statusCode).to.equal(304);
|
|
174
|
+
expect(res2.headers['cache-control']).to.equal('max-age=60, must-revalidate');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('forbids caching on 304 if 200 is not included', async () => {
|
|
178
|
+
|
|
179
|
+
const server = Hapi.server({ routes: { cache: { statuses: [400] } } });
|
|
180
|
+
await server.register(Inert);
|
|
181
|
+
server.route({ method: 'GET', path: '/file', handler: { file: __dirname + '/../package.json' }, options: { cache: { expiresIn: 60000 } } });
|
|
182
|
+
|
|
183
|
+
const res1 = await server.inject('/file');
|
|
184
|
+
const res2 = await server.inject({ url: '/file', headers: { 'if-modified-since': res1.headers['last-modified'] } });
|
|
185
|
+
expect(res2.statusCode).to.equal(304);
|
|
186
|
+
expect(res2.headers['cache-control']).to.equal('no-cache');
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe('security()', () => {
|
|
191
|
+
|
|
192
|
+
it('does not set security headers by default', async () => {
|
|
193
|
+
|
|
194
|
+
const server = Hapi.server();
|
|
195
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
196
|
+
|
|
197
|
+
const res = await server.inject({ url: '/' });
|
|
198
|
+
expect(res.result).to.exist();
|
|
199
|
+
expect(res.result).to.equal('Test');
|
|
200
|
+
expect(res.headers['strict-transport-security']).to.not.exist();
|
|
201
|
+
expect(res.headers['x-frame-options']).to.not.exist();
|
|
202
|
+
expect(res.headers['x-xss-protection']).to.not.exist();
|
|
203
|
+
expect(res.headers['x-download-options']).to.not.exist();
|
|
204
|
+
expect(res.headers['x-content-type-options']).to.not.exist();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('returns default security headers when security is true', async () => {
|
|
208
|
+
|
|
209
|
+
const server = Hapi.server({ routes: { security: true } });
|
|
210
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
211
|
+
|
|
212
|
+
const res = await server.inject({ url: '/' });
|
|
213
|
+
expect(res.result).to.exist();
|
|
214
|
+
expect(res.result).to.equal('Test');
|
|
215
|
+
expect(res.headers['strict-transport-security']).to.equal('max-age=15768000');
|
|
216
|
+
expect(res.headers['x-frame-options']).to.equal('DENY');
|
|
217
|
+
expect(res.headers['x-xss-protection']).to.equal('1; mode=block');
|
|
218
|
+
expect(res.headers['x-download-options']).to.equal('noopen');
|
|
219
|
+
expect(res.headers['x-content-type-options']).to.equal('nosniff');
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('does not set default security headers when the route sets security false', async () => {
|
|
223
|
+
|
|
224
|
+
const server = Hapi.server({ routes: { security: true } });
|
|
225
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test', options: { security: false } });
|
|
226
|
+
|
|
227
|
+
const res = await server.inject({ url: '/' });
|
|
228
|
+
expect(res.result).to.exist();
|
|
229
|
+
expect(res.result).to.equal('Test');
|
|
230
|
+
expect(res.headers['strict-transport-security']).to.not.exist();
|
|
231
|
+
expect(res.headers['x-frame-options']).to.not.exist();
|
|
232
|
+
expect(res.headers['x-xss-protection']).to.not.exist();
|
|
233
|
+
expect(res.headers['x-download-options']).to.not.exist();
|
|
234
|
+
expect(res.headers['x-content-type-options']).to.not.exist();
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('does not return hsts header when secuirty.hsts is false', async () => {
|
|
238
|
+
|
|
239
|
+
const server = Hapi.server({ routes: { security: { hsts: false } } });
|
|
240
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
241
|
+
|
|
242
|
+
const res = await server.inject({ url: '/' });
|
|
243
|
+
expect(res.result).to.exist();
|
|
244
|
+
expect(res.result).to.equal('Test');
|
|
245
|
+
expect(res.headers['strict-transport-security']).to.not.exist();
|
|
246
|
+
expect(res.headers['x-frame-options']).to.equal('DENY');
|
|
247
|
+
expect(res.headers['x-xss-protection']).to.equal('1; mode=block');
|
|
248
|
+
expect(res.headers['x-download-options']).to.equal('noopen');
|
|
249
|
+
expect(res.headers['x-content-type-options']).to.equal('nosniff');
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('returns only default hsts header when security.hsts is true', async () => {
|
|
253
|
+
|
|
254
|
+
const server = Hapi.server({ routes: { security: { hsts: true } } });
|
|
255
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
256
|
+
|
|
257
|
+
const res = await server.inject({ url: '/' });
|
|
258
|
+
expect(res.result).to.exist();
|
|
259
|
+
expect(res.result).to.equal('Test');
|
|
260
|
+
expect(res.headers['strict-transport-security']).to.equal('max-age=15768000');
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('returns correct hsts header when security.hsts is a number', async () => {
|
|
264
|
+
|
|
265
|
+
const server = Hapi.server({ routes: { security: { hsts: 123456789 } } });
|
|
266
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
267
|
+
|
|
268
|
+
const res = await server.inject({ url: '/' });
|
|
269
|
+
expect(res.result).to.exist();
|
|
270
|
+
expect(res.result).to.equal('Test');
|
|
271
|
+
expect(res.headers['strict-transport-security']).to.equal('max-age=123456789');
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('returns correct hsts header when security.hsts is an object', async () => {
|
|
275
|
+
|
|
276
|
+
const server = Hapi.server({ routes: { security: { hsts: { maxAge: 123456789, includeSubDomains: true } } } });
|
|
277
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
278
|
+
|
|
279
|
+
const res = await server.inject({ url: '/' });
|
|
280
|
+
expect(res.result).to.exist();
|
|
281
|
+
expect(res.result).to.equal('Test');
|
|
282
|
+
expect(res.headers['strict-transport-security']).to.equal('max-age=123456789; includeSubDomains');
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('returns the correct hsts header when security.hsts is an object only sepcifying maxAge', async () => {
|
|
286
|
+
|
|
287
|
+
const server = Hapi.server({ routes: { security: { hsts: { maxAge: 123456789 } } } });
|
|
288
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
289
|
+
|
|
290
|
+
const res = await server.inject({ url: '/' });
|
|
291
|
+
expect(res.result).to.exist();
|
|
292
|
+
expect(res.result).to.equal('Test');
|
|
293
|
+
expect(res.headers['strict-transport-security']).to.equal('max-age=123456789');
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('returns correct hsts header when security.hsts is an object only specifying includeSubdomains', async () => {
|
|
297
|
+
|
|
298
|
+
const server = Hapi.server({ routes: { security: { hsts: { includeSubdomains: true } } } });
|
|
299
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
300
|
+
|
|
301
|
+
const res = await server.inject({ url: '/' });
|
|
302
|
+
expect(res.result).to.exist();
|
|
303
|
+
expect(res.result).to.equal('Test');
|
|
304
|
+
expect(res.headers['strict-transport-security']).to.equal('max-age=15768000; includeSubDomains');
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('returns correct hsts header when security.hsts is an object only specifying includeSubDomains', async () => {
|
|
308
|
+
|
|
309
|
+
const server = Hapi.server({ routes: { security: { hsts: { includeSubDomains: true } } } });
|
|
310
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
311
|
+
|
|
312
|
+
const res = await server.inject({ url: '/' });
|
|
313
|
+
expect(res.result).to.exist();
|
|
314
|
+
expect(res.result).to.equal('Test');
|
|
315
|
+
expect(res.headers['strict-transport-security']).to.equal('max-age=15768000; includeSubDomains');
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it('returns correct hsts header when security.hsts is an object only specifying includeSubDomains and preload', async () => {
|
|
319
|
+
|
|
320
|
+
const server = Hapi.server({ routes: { security: { hsts: { includeSubDomains: true, preload: true } } } });
|
|
321
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
322
|
+
|
|
323
|
+
const res = await server.inject({ url: '/' });
|
|
324
|
+
expect(res.result).to.exist();
|
|
325
|
+
expect(res.result).to.equal('Test');
|
|
326
|
+
expect(res.headers['strict-transport-security']).to.equal('max-age=15768000; includeSubDomains; preload');
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it('does not return the xframe header whe security.xframe is false', async () => {
|
|
330
|
+
|
|
331
|
+
const server = Hapi.server({ routes: { security: { xframe: false } } });
|
|
332
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
333
|
+
|
|
334
|
+
const res = await server.inject({ url: '/' });
|
|
335
|
+
expect(res.result).to.exist();
|
|
336
|
+
expect(res.result).to.equal('Test');
|
|
337
|
+
expect(res.headers['x-frame-options']).to.not.exist();
|
|
338
|
+
expect(res.headers['strict-transport-security']).to.equal('max-age=15768000');
|
|
339
|
+
expect(res.headers['x-xss-protection']).to.equal('1; mode=block');
|
|
340
|
+
expect(res.headers['x-download-options']).to.equal('noopen');
|
|
341
|
+
expect(res.headers['x-content-type-options']).to.equal('nosniff');
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it('returns only default xframe header when security.xframe is true', async () => {
|
|
345
|
+
|
|
346
|
+
const server = Hapi.server({ routes: { security: { xframe: true } } });
|
|
347
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
348
|
+
|
|
349
|
+
const res = await server.inject({ url: '/' });
|
|
350
|
+
expect(res.result).to.exist();
|
|
351
|
+
expect(res.result).to.equal('Test');
|
|
352
|
+
expect(res.headers['x-frame-options']).to.equal('DENY');
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it('returns correct xframe header when security.xframe is a string', async () => {
|
|
356
|
+
|
|
357
|
+
const server = Hapi.server({ routes: { security: { xframe: 'sameorigin' } } });
|
|
358
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
359
|
+
|
|
360
|
+
const res = await server.inject({ url: '/' });
|
|
361
|
+
expect(res.result).to.exist();
|
|
362
|
+
expect(res.result).to.equal('Test');
|
|
363
|
+
expect(res.headers['x-frame-options']).to.equal('SAMEORIGIN');
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it('returns correct xframe header when security.xframe is an object', async () => {
|
|
367
|
+
|
|
368
|
+
const server = Hapi.server({ routes: { security: { xframe: { rule: 'allow-from', source: 'http://example.com' } } } });
|
|
369
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
370
|
+
|
|
371
|
+
const res = await server.inject({ url: '/' });
|
|
372
|
+
expect(res.result).to.exist();
|
|
373
|
+
expect(res.result).to.equal('Test');
|
|
374
|
+
expect(res.headers['x-frame-options']).to.equal('ALLOW-FROM http://example.com');
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it('returns correct xframe header when security.xframe is an object', async () => {
|
|
378
|
+
|
|
379
|
+
const server = Hapi.server({ routes: { security: { xframe: { rule: 'deny' } } } });
|
|
380
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
381
|
+
|
|
382
|
+
const res = await server.inject({ url: '/' });
|
|
383
|
+
expect(res.result).to.exist();
|
|
384
|
+
expect(res.result).to.equal('Test');
|
|
385
|
+
expect(res.headers['x-frame-options']).to.equal('DENY');
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
it('returns sameorigin xframe header when rule is allow-from but source is unspecified', async () => {
|
|
389
|
+
|
|
390
|
+
const server = Hapi.server({ routes: { security: { xframe: { rule: 'allow-from' } } } });
|
|
391
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
392
|
+
|
|
393
|
+
const res = await server.inject({ url: '/' });
|
|
394
|
+
|
|
395
|
+
expect(res.result).to.exist();
|
|
396
|
+
expect(res.result).to.equal('Test');
|
|
397
|
+
expect(res.headers['x-frame-options']).to.equal('SAMEORIGIN');
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it('does not set x-download-options if noOpen is false', async () => {
|
|
401
|
+
|
|
402
|
+
const server = Hapi.server({ routes: { security: { noOpen: false } } });
|
|
403
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
404
|
+
|
|
405
|
+
const res = await server.inject({ url: '/' });
|
|
406
|
+
expect(res.result).to.exist();
|
|
407
|
+
expect(res.result).to.equal('Test');
|
|
408
|
+
expect(res.headers['x-download-options']).to.not.exist();
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
it('does not set x-content-type-options if noSniff is false', async () => {
|
|
412
|
+
|
|
413
|
+
const server = Hapi.server({ routes: { security: { noSniff: false } } });
|
|
414
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
415
|
+
|
|
416
|
+
const res = await server.inject({ url: '/' });
|
|
417
|
+
expect(res.result).to.exist();
|
|
418
|
+
expect(res.result).to.equal('Test');
|
|
419
|
+
expect(res.headers['x-content-type-options']).to.not.exist();
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
it('does not set the x-xss-protection header when security.xss is false', async () => {
|
|
423
|
+
|
|
424
|
+
const server = Hapi.server({ routes: { security: { xss: false } } });
|
|
425
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
426
|
+
|
|
427
|
+
const res = await server.inject({ url: '/' });
|
|
428
|
+
expect(res.result).to.exist();
|
|
429
|
+
expect(res.result).to.equal('Test');
|
|
430
|
+
expect(res.headers['x-xss-protection']).to.not.exist();
|
|
431
|
+
expect(res.headers['strict-transport-security']).to.equal('max-age=15768000');
|
|
432
|
+
expect(res.headers['x-frame-options']).to.equal('DENY');
|
|
433
|
+
expect(res.headers['x-download-options']).to.equal('noopen');
|
|
434
|
+
expect(res.headers['x-content-type-options']).to.equal('nosniff');
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
it('does not return the referrer-policy header by default', async () => {
|
|
438
|
+
|
|
439
|
+
const server = Hapi.server();
|
|
440
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
441
|
+
|
|
442
|
+
const res = await server.inject({ url: '/' });
|
|
443
|
+
expect(res.result).to.exist();
|
|
444
|
+
expect(res.result).to.equal('Test');
|
|
445
|
+
expect(res.headers['referrer-policy']).to.not.exist();
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
it('does not return the referrer-policy header when security.referrer is false', async () => {
|
|
449
|
+
|
|
450
|
+
const server = Hapi.server({ routes: { security: { referrer: false } } });
|
|
451
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
452
|
+
|
|
453
|
+
const res = await server.inject({ url: '/' });
|
|
454
|
+
expect(res.result).to.exist();
|
|
455
|
+
expect(res.result).to.equal('Test');
|
|
456
|
+
expect(res.headers['referrer-policy']).to.not.exist();
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it('does not allow security.referrer to be true', () => {
|
|
460
|
+
|
|
461
|
+
let err;
|
|
462
|
+
try {
|
|
463
|
+
Hapi.server({ routes: { security: { referrer: true } } });
|
|
464
|
+
}
|
|
465
|
+
catch (ex) {
|
|
466
|
+
err = ex;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
expect(err).to.exist();
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
it('returns correct referrer-policy header when security.referrer is a string with a valid value', async () => {
|
|
473
|
+
|
|
474
|
+
const server = Hapi.server({ routes: { security: { referrer: 'strict-origin-when-cross-origin' } } });
|
|
475
|
+
server.route({ method: 'GET', path: '/', handler: () => 'Test' });
|
|
476
|
+
|
|
477
|
+
const res = await server.inject({ url: '/' });
|
|
478
|
+
expect(res.result).to.exist();
|
|
479
|
+
expect(res.result).to.equal('Test');
|
|
480
|
+
expect(res.headers['referrer-policy']).to.equal('strict-origin-when-cross-origin');
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
describe('content()', () => {
|
|
485
|
+
|
|
486
|
+
it('does not modify content-type header when charset manually set', async () => {
|
|
487
|
+
|
|
488
|
+
const server = Hapi.server();
|
|
489
|
+
server.route({ method: 'GET', path: '/', handler: (request, h) => h.response('text').type('text/plain; charset=ISO-8859-1') });
|
|
490
|
+
|
|
491
|
+
const res = await server.inject('/');
|
|
492
|
+
expect(res.statusCode).to.equal(200);
|
|
493
|
+
expect(res.headers['content-type']).to.equal('text/plain; charset=ISO-8859-1');
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
it('does not modify content-type header when charset is unset', async () => {
|
|
497
|
+
|
|
498
|
+
const server = Hapi.server();
|
|
499
|
+
server.route({ method: 'GET', path: '/', handler: (request, h) => h.response('text').type('text/plain').charset() });
|
|
500
|
+
|
|
501
|
+
const res = await server.inject('/');
|
|
502
|
+
expect(res.statusCode).to.equal(200);
|
|
503
|
+
expect(res.headers['content-type']).to.equal('text/plain');
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
it('does not modify content-type header when charset is unset (default type)', async () => {
|
|
507
|
+
|
|
508
|
+
const server = Hapi.server();
|
|
509
|
+
server.route({ method: 'GET', path: '/', handler: (request, h) => h.response('text').charset() });
|
|
510
|
+
|
|
511
|
+
const res = await server.inject('/');
|
|
512
|
+
expect(res.statusCode).to.equal(200);
|
|
513
|
+
expect(res.headers['content-type']).to.equal('text/html');
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
it('returns a normal response when JSONP requested but stream returned', async () => {
|
|
517
|
+
|
|
518
|
+
const server = Hapi.server();
|
|
519
|
+
const stream = Wreck.toReadableStream('test');
|
|
520
|
+
stream.size = 4; // Non function for coverage
|
|
521
|
+
server.route({ method: 'GET', path: '/', options: { jsonp: 'callback', handler: () => stream } });
|
|
522
|
+
|
|
523
|
+
const res = await server.inject('/?callback=me');
|
|
524
|
+
expect(res.payload).to.equal('test');
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
it('does not set content-type by default on 204 response', async () => {
|
|
528
|
+
|
|
529
|
+
const server = Hapi.server();
|
|
530
|
+
server.route({ method: 'GET', path: '/', handler: (request, h) => h.response().code(204) });
|
|
531
|
+
|
|
532
|
+
const res = await server.inject('/');
|
|
533
|
+
expect(res.statusCode).to.equal(204);
|
|
534
|
+
expect(res.headers['content-type']).to.equal(undefined);
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
});
|
package/test/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Code = require('@hapi/code');
|
|
4
|
+
const Hapi = require('..');
|
|
5
|
+
const Lab = require('@hapi/lab');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const internals = {};
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const { describe, it } = exports.lab = Lab.script();
|
|
12
|
+
const expect = Code.expect;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
describe('Server', () => {
|
|
16
|
+
|
|
17
|
+
it('supports new Server()', async () => {
|
|
18
|
+
|
|
19
|
+
const server = new Hapi.Server();
|
|
20
|
+
server.route({ method: 'GET', path: '/', handler: () => 'old school' });
|
|
21
|
+
|
|
22
|
+
const res = await server.inject('/');
|
|
23
|
+
expect(res.result).to.equal('old school');
|
|
24
|
+
});
|
|
25
|
+
});
|