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/cors.js
ADDED
|
@@ -0,0 +1,647 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Boom = require('@hapi/boom');
|
|
4
|
+
const Code = require('@hapi/code');
|
|
5
|
+
const Hapi = require('..');
|
|
6
|
+
const Lab = require('@hapi/lab');
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
const internals = {};
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
const { describe, it } = exports.lab = Lab.script();
|
|
13
|
+
const expect = Code.expect;
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
describe('CORS', () => {
|
|
17
|
+
|
|
18
|
+
it('returns 404 on OPTIONS when cors disabled', async () => {
|
|
19
|
+
|
|
20
|
+
const server = Hapi.server({ routes: { cors: false } });
|
|
21
|
+
server.route({ method: 'GET', path: '/', handler: () => null });
|
|
22
|
+
|
|
23
|
+
const res = await server.inject({ method: 'OPTIONS', url: '/', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
24
|
+
expect(res.statusCode).to.equal(404);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('returns OPTIONS response', async () => {
|
|
28
|
+
|
|
29
|
+
const handler = function () {
|
|
30
|
+
|
|
31
|
+
throw Boom.badRequest();
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const server = Hapi.server({ routes: { cors: true } });
|
|
35
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
36
|
+
|
|
37
|
+
const res = await server.inject({ method: 'OPTIONS', url: '/', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
38
|
+
expect(res.headers['access-control-allow-origin']).to.equal('http://example.com/');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('returns OPTIONS response (server config)', async () => {
|
|
42
|
+
|
|
43
|
+
const handler = function () {
|
|
44
|
+
|
|
45
|
+
throw Boom.badRequest();
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const server = Hapi.server({ routes: { cors: true } });
|
|
49
|
+
server.route({ method: 'GET', path: '/x', handler });
|
|
50
|
+
|
|
51
|
+
const res = await server.inject({ method: 'OPTIONS', url: '/x', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
52
|
+
expect(res.headers['access-control-allow-origin']).to.equal('http://example.com/');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('returns headers on single route', async () => {
|
|
56
|
+
|
|
57
|
+
const server = Hapi.server();
|
|
58
|
+
server.route({ method: 'GET', path: '/a', handler: () => 'ok', options: { cors: true } });
|
|
59
|
+
server.route({ method: 'GET', path: '/b', handler: () => 'ok' });
|
|
60
|
+
|
|
61
|
+
const res1 = await server.inject({ method: 'OPTIONS', url: '/a', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
62
|
+
expect(res1.statusCode).to.equal(204);
|
|
63
|
+
expect(res1.result).to.be.null();
|
|
64
|
+
expect(res1.headers['access-control-allow-origin']).to.equal('http://example.com/');
|
|
65
|
+
|
|
66
|
+
const res2 = await server.inject({ method: 'OPTIONS', url: '/b', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
67
|
+
expect(res2.statusCode).to.equal(200);
|
|
68
|
+
expect(res2.result.message).to.equal('CORS is disabled for this route');
|
|
69
|
+
expect(res2.headers['access-control-allow-origin']).to.not.exist();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('allows headers on multiple routes but not all', async () => {
|
|
73
|
+
|
|
74
|
+
const server = Hapi.server();
|
|
75
|
+
server.route({ method: 'GET', path: '/a', handler: () => 'ok', options: { cors: true } });
|
|
76
|
+
server.route({ method: 'GET', path: '/b', handler: () => 'ok', options: { cors: true } });
|
|
77
|
+
server.route({ method: 'GET', path: '/c', handler: () => 'ok' });
|
|
78
|
+
|
|
79
|
+
const res1 = await server.inject({ method: 'OPTIONS', url: '/a', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
80
|
+
expect(res1.statusCode).to.equal(204);
|
|
81
|
+
expect(res1.result).to.be.null();
|
|
82
|
+
expect(res1.headers['access-control-allow-origin']).to.equal('http://example.com/');
|
|
83
|
+
|
|
84
|
+
const res2 = await server.inject({ method: 'OPTIONS', url: '/b', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
85
|
+
expect(res2.statusCode).to.equal(204);
|
|
86
|
+
expect(res2.result).to.be.null();
|
|
87
|
+
expect(res2.headers['access-control-allow-origin']).to.equal('http://example.com/');
|
|
88
|
+
|
|
89
|
+
const res3 = await server.inject({ method: 'OPTIONS', url: '/c', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
90
|
+
expect(res3.statusCode).to.equal(200);
|
|
91
|
+
expect(res3.result.message).to.equal('CORS is disabled for this route');
|
|
92
|
+
expect(res3.headers['access-control-allow-origin']).to.not.exist();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('allows same headers on multiple routes with same path', async () => {
|
|
96
|
+
|
|
97
|
+
const server = Hapi.server();
|
|
98
|
+
server.route({ method: 'GET', path: '/a', handler: () => 'ok', options: { cors: true } });
|
|
99
|
+
server.route({ method: 'POST', path: '/a', handler: () => 'ok', options: { cors: true } });
|
|
100
|
+
|
|
101
|
+
const res = await server.inject({ method: 'OPTIONS', url: '/a', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
102
|
+
expect(res.statusCode).to.equal(204);
|
|
103
|
+
expect(res.result).to.be.null();
|
|
104
|
+
expect(res.headers['access-control-allow-origin']).to.equal('http://example.com/');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('returns headers on single route (overrides defaults)', async () => {
|
|
108
|
+
|
|
109
|
+
const server = Hapi.server({ routes: { cors: { origin: ['b'] } } });
|
|
110
|
+
server.route({ method: 'GET', path: '/a', handler: () => 'ok', options: { cors: { origin: ['a'] } } });
|
|
111
|
+
server.route({ method: 'GET', path: '/b', handler: () => 'ok' });
|
|
112
|
+
|
|
113
|
+
const res1 = await server.inject({ method: 'OPTIONS', url: '/a', headers: { origin: 'a', 'access-control-request-method': 'GET' } });
|
|
114
|
+
expect(res1.statusCode).to.equal(204);
|
|
115
|
+
expect(res1.result).to.be.null();
|
|
116
|
+
expect(res1.headers['access-control-allow-origin']).to.equal('a');
|
|
117
|
+
|
|
118
|
+
const res2 = await server.inject({ method: 'OPTIONS', url: '/b', headers: { origin: 'b', 'access-control-request-method': 'GET' } });
|
|
119
|
+
expect(res2.statusCode).to.equal(204);
|
|
120
|
+
expect(res2.result).to.be.null();
|
|
121
|
+
expect(res2.headers['access-control-allow-origin']).to.equal('b');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('sets access-control-allow-credentials header', async () => {
|
|
125
|
+
|
|
126
|
+
const server = Hapi.server({ routes: { cors: { credentials: true } } });
|
|
127
|
+
server.route({ method: 'GET', path: '/', handler: () => null });
|
|
128
|
+
|
|
129
|
+
const res = await server.inject({ url: '/', headers: { origin: 'http://example.com/' } });
|
|
130
|
+
expect(res.statusCode).to.equal(204);
|
|
131
|
+
expect(res.result).to.equal(null);
|
|
132
|
+
expect(res.headers['access-control-allow-credentials']).to.equal('true');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('combines server defaults with route config', async () => {
|
|
136
|
+
|
|
137
|
+
const server = Hapi.server({ routes: { cors: { origin: ['http://example.com/'] } } });
|
|
138
|
+
server.route({ method: 'GET', path: '/', handler: () => null, options: { cors: { credentials: true } } });
|
|
139
|
+
|
|
140
|
+
const res1 = await server.inject({ url: '/', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
141
|
+
expect(res1.statusCode).to.equal(204);
|
|
142
|
+
expect(res1.result).to.equal(null);
|
|
143
|
+
expect(res1.headers['access-control-allow-credentials']).to.equal('true');
|
|
144
|
+
|
|
145
|
+
const res2 = await server.inject({ method: 'OPTIONS', url: '/', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
146
|
+
expect(res2.statusCode).to.equal(204);
|
|
147
|
+
expect(res2.result).to.equal(null);
|
|
148
|
+
expect(res2.headers['access-control-allow-credentials']).to.equal('true');
|
|
149
|
+
|
|
150
|
+
const res3 = await server.inject({ url: '/', headers: { origin: 'http://example.org/', 'access-control-request-method': 'GET' } });
|
|
151
|
+
expect(res3.statusCode).to.equal(204);
|
|
152
|
+
expect(res3.result).to.equal(null);
|
|
153
|
+
expect(res3.headers['access-control-allow-credentials']).to.not.exist();
|
|
154
|
+
|
|
155
|
+
const res4 = await server.inject({ method: 'OPTIONS', url: '/', headers: { origin: 'http://example.org/', 'access-control-request-method': 'GET' } });
|
|
156
|
+
expect(res4.statusCode).to.equal(200);
|
|
157
|
+
expect(res4.result).to.equal({ message: 'CORS error: Origin not allowed' });
|
|
158
|
+
expect(res4.headers['access-control-allow-credentials']).to.not.exist();
|
|
159
|
+
expect(res4.headers['access-control-allow-origin']).to.not.exist();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('handles request without origin header', async () => {
|
|
163
|
+
|
|
164
|
+
const server = Hapi.server({ port: 8080, routes: { cors: { origin: ['http://*.domain.com'] } } });
|
|
165
|
+
server.route({ method: 'GET', path: '/test', handler: () => null });
|
|
166
|
+
|
|
167
|
+
const res1 = await server.inject('/');
|
|
168
|
+
expect(res1.statusCode).to.equal(404);
|
|
169
|
+
expect(res1.headers['access-control-allow-origin']).to.not.exist();
|
|
170
|
+
|
|
171
|
+
const res2 = await server.inject('/test');
|
|
172
|
+
expect(res2.statusCode).to.equal(204);
|
|
173
|
+
expect(res2.headers['access-control-allow-origin']).to.not.exist();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('handles missing routes', async () => {
|
|
177
|
+
|
|
178
|
+
const server = Hapi.server({ port: 8080, routes: { cors: { origin: ['http://*.domain.com'] } } });
|
|
179
|
+
|
|
180
|
+
const res1 = await server.inject('/');
|
|
181
|
+
expect(res1.statusCode).to.equal(404);
|
|
182
|
+
expect(res1.headers['access-control-allow-origin']).to.not.exist();
|
|
183
|
+
|
|
184
|
+
const res2 = await server.inject({ url: '/', headers: { origin: 'http://example.domain.com' } });
|
|
185
|
+
expect(res2.statusCode).to.equal(404);
|
|
186
|
+
expect(res2.headers['access-control-allow-origin']).to.exist();
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('uses server defaults in onRequest', async () => {
|
|
190
|
+
|
|
191
|
+
const server = Hapi.server({ port: 8080, routes: { cors: { origin: ['http://*.domain.com'] } } });
|
|
192
|
+
|
|
193
|
+
server.ext('onRequest', (request, h) => {
|
|
194
|
+
|
|
195
|
+
expect(request.info.cors).to.be.null(); // Do not set potentially incorrect information
|
|
196
|
+
return h.response('skip').takeover();
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const res1 = await server.inject({ url: '/', headers: { origin: 'http://example.domain.com' } });
|
|
200
|
+
expect(res1.statusCode).to.equal(200);
|
|
201
|
+
expect(res1.headers['access-control-allow-origin']).to.exist();
|
|
202
|
+
|
|
203
|
+
const res2 = await server.inject({ url: '/', headers: { origin: 'http://example.domain.net' } });
|
|
204
|
+
expect(res2.statusCode).to.equal(200);
|
|
205
|
+
expect(res2.headers['access-control-allow-origin']).to.not.exist();
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
describe('headers()', () => {
|
|
209
|
+
|
|
210
|
+
it('returns CORS origin (route level)', async () => {
|
|
211
|
+
|
|
212
|
+
const server = Hapi.server();
|
|
213
|
+
server.route({ method: 'GET', path: '/', handler: () => 'ok', options: { cors: true } });
|
|
214
|
+
|
|
215
|
+
const res1 = await server.inject({ url: '/', headers: { origin: 'http://example.com/' } });
|
|
216
|
+
expect(res1.statusCode).to.equal(200);
|
|
217
|
+
expect(res1.result).to.exist();
|
|
218
|
+
expect(res1.result).to.equal('ok');
|
|
219
|
+
expect(res1.headers['access-control-allow-origin']).to.equal('http://example.com/');
|
|
220
|
+
|
|
221
|
+
const res2 = await server.inject({ method: 'OPTIONS', url: '/', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
222
|
+
expect(res2.statusCode).to.equal(204);
|
|
223
|
+
expect(res2.result).to.be.null();
|
|
224
|
+
expect(res2.headers['access-control-allow-origin']).to.equal('http://example.com/');
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('returns CORS origin (GET)', async () => {
|
|
228
|
+
|
|
229
|
+
const server = Hapi.server({ routes: { cors: { origin: ['http://x.example.com', 'http://www.example.com'] } } });
|
|
230
|
+
server.route({ method: 'GET', path: '/', handler: () => 'ok' });
|
|
231
|
+
|
|
232
|
+
const res = await server.inject({ url: '/', headers: { origin: 'http://x.example.com' } });
|
|
233
|
+
expect(res.statusCode).to.equal(200);
|
|
234
|
+
expect(res.result).to.exist();
|
|
235
|
+
expect(res.result).to.equal('ok');
|
|
236
|
+
expect(res.headers['access-control-allow-origin']).to.equal('http://x.example.com');
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('returns CORS origin (OPTIONS)', async () => {
|
|
240
|
+
|
|
241
|
+
const server = Hapi.server({ routes: { cors: { origin: ['http://test.example.com', 'http://www.example.com'] } } });
|
|
242
|
+
server.route({ method: 'GET', path: '/', handler: () => 'ok' });
|
|
243
|
+
|
|
244
|
+
const res = await server.inject({ method: 'OPTIONS', url: '/', headers: { origin: 'http://test.example.com', 'access-control-request-method': 'GET' } });
|
|
245
|
+
expect(res.statusCode).to.equal(204);
|
|
246
|
+
expect(res.payload.length).to.equal(0);
|
|
247
|
+
expect(res.headers['access-control-allow-origin']).to.equal('http://test.example.com');
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('merges CORS access-control-expose-headers header', async () => {
|
|
251
|
+
|
|
252
|
+
const handler = (request, h) => {
|
|
253
|
+
|
|
254
|
+
return h.response('ok').header('access-control-expose-headers', 'something');
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
const server = Hapi.server({ routes: { cors: { additionalExposedHeaders: ['xyz'] } } });
|
|
258
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
259
|
+
|
|
260
|
+
const res = await server.inject({ url: '/', headers: { origin: 'http://example.com/' } });
|
|
261
|
+
expect(res.statusCode).to.equal(200);
|
|
262
|
+
expect(res.result).to.exist();
|
|
263
|
+
expect(res.result).to.equal('ok');
|
|
264
|
+
expect(res.headers['access-control-expose-headers']).to.equal('something,WWW-Authenticate,Server-Authorization,xyz');
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('returns no CORS headers when route CORS disabled', async () => {
|
|
268
|
+
|
|
269
|
+
const server = Hapi.server({ routes: { cors: { origin: ['http://test.example.com', 'http://www.example.com'] } } });
|
|
270
|
+
server.route({ method: 'GET', path: '/', handler: () => 'ok', options: { cors: false } });
|
|
271
|
+
|
|
272
|
+
const res = await server.inject({ url: '/', headers: { origin: 'http://x.example.com' } });
|
|
273
|
+
expect(res.statusCode).to.equal(200);
|
|
274
|
+
expect(res.result).to.exist();
|
|
275
|
+
expect(res.result).to.equal('ok');
|
|
276
|
+
expect(res.headers['access-control-allow-origin']).to.not.exist();
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('returns matching CORS origin', async () => {
|
|
280
|
+
|
|
281
|
+
const handler = (request, h) => {
|
|
282
|
+
|
|
283
|
+
return h.response('Tada').header('vary', 'x-test');
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const server = Hapi.server({ compression: { minBytes: 1 }, routes: { cors: { origin: ['http://test.example.com', 'http://www.example.com', 'http://*.a.com'] } } });
|
|
287
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
288
|
+
|
|
289
|
+
const res = await server.inject({ url: '/', headers: { origin: 'http://www.example.com' } });
|
|
290
|
+
expect(res.statusCode).to.equal(200);
|
|
291
|
+
expect(res.result).to.exist();
|
|
292
|
+
expect(res.result).to.equal('Tada');
|
|
293
|
+
expect(res.headers['access-control-allow-origin']).to.equal('http://www.example.com');
|
|
294
|
+
expect(res.headers.vary).to.equal('x-test,origin,accept-encoding');
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('returns origin header when matching against *', async () => {
|
|
298
|
+
|
|
299
|
+
const handler = (request, h) => {
|
|
300
|
+
|
|
301
|
+
return h.response('Tada').header('vary', 'x-test');
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
const server = Hapi.server({ compression: { minBytes: 1 }, routes: { cors: { origin: ['*'] } } });
|
|
305
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
306
|
+
|
|
307
|
+
const res = await server.inject({ url: '/', headers: { origin: 'http://www.example.com' } });
|
|
308
|
+
expect(res.statusCode).to.equal(200);
|
|
309
|
+
expect(res.result).to.exist();
|
|
310
|
+
expect(res.result).to.equal('Tada');
|
|
311
|
+
expect(res.headers['access-control-allow-origin']).to.equal('http://www.example.com');
|
|
312
|
+
expect(res.headers.vary).to.equal('x-test,origin,accept-encoding');
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('returns * origin header when matching against * and origin is ignored', async () => {
|
|
316
|
+
|
|
317
|
+
const handler = (request, h) => {
|
|
318
|
+
|
|
319
|
+
return h.response('Tada').header('vary', 'x-test');
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const server = Hapi.server({ compression: { minBytes: 1 }, routes: { cors: { origin: 'ignore' } } });
|
|
323
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
324
|
+
|
|
325
|
+
const res = await server.inject({ url: '/', headers: { origin: 'http://www.example.com' } });
|
|
326
|
+
expect(res.statusCode).to.equal(200);
|
|
327
|
+
expect(res.result).to.exist();
|
|
328
|
+
expect(res.result).to.equal('Tada');
|
|
329
|
+
expect(res.headers['access-control-allow-origin']).to.equal('*');
|
|
330
|
+
expect(res.headers.vary).to.equal('x-test,accept-encoding');
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('returns matching CORS origin wildcard', async () => {
|
|
334
|
+
|
|
335
|
+
const handler = (request, h) => {
|
|
336
|
+
|
|
337
|
+
return h.response('Tada').header('vary', 'x-test');
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
const server = Hapi.server({ compression: { minBytes: 1 }, routes: { cors: { origin: ['http://test.example.com', 'http://www.example.com', 'http://*.a.com'] } } });
|
|
341
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
342
|
+
|
|
343
|
+
const res = await server.inject({ url: '/', headers: { origin: 'http://www.a.com' } });
|
|
344
|
+
expect(res.statusCode).to.equal(200);
|
|
345
|
+
expect(res.result).to.exist();
|
|
346
|
+
expect(res.result).to.equal('Tada');
|
|
347
|
+
expect(res.headers['access-control-allow-origin']).to.equal('http://www.a.com');
|
|
348
|
+
expect(res.headers.vary).to.equal('x-test,origin,accept-encoding');
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it('returns matching CORS origin wildcard when more than one wildcard', async () => {
|
|
352
|
+
|
|
353
|
+
const handler = (request, h) => {
|
|
354
|
+
|
|
355
|
+
return h.response('Tada').header('vary', 'x-test', true);
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
const server = Hapi.server({ compression: { minBytes: 1 }, routes: { cors: { origin: ['http://test.example.com', 'http://www.example.com', 'http://*.b.com', 'http://*.a.com'] } } });
|
|
359
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
360
|
+
|
|
361
|
+
const res = await server.inject({ url: '/', headers: { origin: 'http://www.a.com' } });
|
|
362
|
+
expect(res.statusCode).to.equal(200);
|
|
363
|
+
expect(res.result).to.exist();
|
|
364
|
+
expect(res.result).to.equal('Tada');
|
|
365
|
+
expect(res.headers['access-control-allow-origin']).to.equal('http://www.a.com');
|
|
366
|
+
expect(res.headers.vary).to.equal('x-test,origin,accept-encoding');
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
it('does not set empty CORS expose headers', async () => {
|
|
370
|
+
|
|
371
|
+
const server = Hapi.server({ routes: { cors: { exposedHeaders: [] } } });
|
|
372
|
+
server.route({ method: 'GET', path: '/', handler: () => 'ok' });
|
|
373
|
+
|
|
374
|
+
const res1 = await server.inject({ url: '/', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
375
|
+
expect(res1.statusCode).to.equal(200);
|
|
376
|
+
expect(res1.headers['access-control-allow-origin']).to.equal('http://example.com/');
|
|
377
|
+
expect(res1.headers['access-control-expose-headers']).to.not.exist();
|
|
378
|
+
|
|
379
|
+
const res2 = await server.inject({ method: 'OPTIONS', url: '/', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
380
|
+
expect(res2.statusCode).to.equal(204);
|
|
381
|
+
expect(res2.headers['access-control-allow-origin']).to.equal('http://example.com/');
|
|
382
|
+
expect(res2.headers['access-control-expose-headers']).to.not.exist();
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
describe('options()', () => {
|
|
387
|
+
|
|
388
|
+
it('ignores OPTIONS route', () => {
|
|
389
|
+
|
|
390
|
+
const server = Hapi.server();
|
|
391
|
+
server.route({
|
|
392
|
+
method: 'OPTIONS',
|
|
393
|
+
path: '/',
|
|
394
|
+
handler: () => null
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
expect(server._core.router.special.options).to.not.exist();
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
describe('handler()', () => {
|
|
402
|
+
|
|
403
|
+
it('errors on missing origin header', async () => {
|
|
404
|
+
|
|
405
|
+
const server = Hapi.server({ routes: { cors: true } });
|
|
406
|
+
server.route({
|
|
407
|
+
method: 'GET',
|
|
408
|
+
path: '/',
|
|
409
|
+
handler: () => null
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
const res = await server.inject({ method: 'OPTIONS', url: '/', headers: { 'access-control-request-method': 'GET' } });
|
|
413
|
+
expect(res.statusCode).to.equal(404);
|
|
414
|
+
expect(res.result.message).to.equal('CORS error: Missing Origin header');
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it('errors on missing access-control-request-method header', async () => {
|
|
418
|
+
|
|
419
|
+
const server = Hapi.server({ routes: { cors: true } });
|
|
420
|
+
server.route({
|
|
421
|
+
method: 'GET',
|
|
422
|
+
path: '/',
|
|
423
|
+
handler: () => null
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
const res = await server.inject({ method: 'OPTIONS', url: '/', headers: { origin: 'http://example.com/' } });
|
|
427
|
+
expect(res.statusCode).to.equal(404);
|
|
428
|
+
expect(res.result.message).to.equal('CORS error: Missing Access-Control-Request-Method header');
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it('errors on missing route', async () => {
|
|
432
|
+
|
|
433
|
+
const server = Hapi.server({ routes: { cors: true } });
|
|
434
|
+
|
|
435
|
+
const res = await server.inject({ method: 'OPTIONS', url: '/', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
436
|
+
expect(res.statusCode).to.equal(404);
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
it('errors on mismatching origin header', async () => {
|
|
440
|
+
|
|
441
|
+
const server = Hapi.server({ routes: { cors: { origin: ['a'] } } });
|
|
442
|
+
server.route({
|
|
443
|
+
method: 'GET',
|
|
444
|
+
path: '/',
|
|
445
|
+
handler: () => null
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
const res = await server.inject({ method: 'OPTIONS', url: '/', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
449
|
+
expect(res.statusCode).to.equal(200);
|
|
450
|
+
expect(res.result.message).to.equal('CORS error: Origin not allowed');
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
it('matches a wildcard origin if origin is ignored and present', async () => {
|
|
454
|
+
|
|
455
|
+
const server = Hapi.server({ routes: { cors: { origin: 'ignore' } } });
|
|
456
|
+
server.route({ method: 'GET', path: '/', handler: () => 'ok' });
|
|
457
|
+
|
|
458
|
+
const res = await server.inject({
|
|
459
|
+
method: 'OPTIONS',
|
|
460
|
+
url: '/',
|
|
461
|
+
headers: {
|
|
462
|
+
origin: 'http://test.example.com',
|
|
463
|
+
'access-control-request-method': 'GET',
|
|
464
|
+
'access-control-request-headers': 'Authorization'
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
expect(res.statusCode).to.equal(204);
|
|
469
|
+
expect(res.headers['access-control-allow-origin']).to.equal('*');
|
|
470
|
+
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
it('matches a wildcard origin if origin is ignored and missing', async () => {
|
|
474
|
+
|
|
475
|
+
const server = Hapi.server({ routes: { cors: { origin: 'ignore' } } });
|
|
476
|
+
server.route({ method: 'GET', path: '/', handler: () => 'ok' });
|
|
477
|
+
|
|
478
|
+
const res = await server.inject({
|
|
479
|
+
method: 'OPTIONS',
|
|
480
|
+
url: '/',
|
|
481
|
+
headers: {
|
|
482
|
+
'access-control-request-method': 'GET',
|
|
483
|
+
'access-control-request-headers': 'Authorization'
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
expect(res.statusCode).to.equal(204);
|
|
488
|
+
expect(res.headers['access-control-allow-origin']).to.equal('*');
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
it('matches allowed headers', async () => {
|
|
492
|
+
|
|
493
|
+
const server = Hapi.server({ routes: { cors: true } });
|
|
494
|
+
server.route({ method: 'GET', path: '/', handler: () => 'ok' });
|
|
495
|
+
|
|
496
|
+
const res = await server.inject({
|
|
497
|
+
method: 'OPTIONS',
|
|
498
|
+
url: '/',
|
|
499
|
+
headers: {
|
|
500
|
+
origin: 'http://test.example.com',
|
|
501
|
+
'access-control-request-method': 'GET',
|
|
502
|
+
'access-control-request-headers': 'Authorization'
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
expect(res.statusCode).to.equal(204);
|
|
507
|
+
expect(res.headers['access-control-allow-headers']).to.equal('Accept,Authorization,Content-Type,If-None-Match');
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
it('matches allowed headers (case insensitive)', async () => {
|
|
511
|
+
|
|
512
|
+
const server = Hapi.server({ routes: { cors: true } });
|
|
513
|
+
server.route({ method: 'GET', path: '/', handler: () => 'ok' });
|
|
514
|
+
|
|
515
|
+
const res = await server.inject({
|
|
516
|
+
method: 'OPTIONS',
|
|
517
|
+
url: '/',
|
|
518
|
+
headers: {
|
|
519
|
+
origin: 'http://test.example.com',
|
|
520
|
+
'access-control-request-method': 'GET',
|
|
521
|
+
'access-control-request-headers': 'authorization'
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
expect(res.statusCode).to.equal(204);
|
|
526
|
+
expect(res.headers['access-control-allow-headers']).to.equal('Accept,Authorization,Content-Type,If-None-Match');
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
it('matches allowed headers (Origin explicit)', async () => {
|
|
530
|
+
|
|
531
|
+
const server = Hapi.server({ routes: { cors: { additionalHeaders: ['Origin'] } } });
|
|
532
|
+
server.route({ method: 'GET', path: '/', handler: () => 'ok' });
|
|
533
|
+
|
|
534
|
+
const res = await server.inject({
|
|
535
|
+
method: 'OPTIONS',
|
|
536
|
+
url: '/',
|
|
537
|
+
headers: {
|
|
538
|
+
origin: 'http://test.example.com',
|
|
539
|
+
'access-control-request-method': 'GET',
|
|
540
|
+
'access-control-request-headers': 'Origin'
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
expect(res.statusCode).to.equal(204);
|
|
545
|
+
expect(res.headers['access-control-allow-headers']).to.equal('Accept,Authorization,Content-Type,If-None-Match,Origin');
|
|
546
|
+
expect(res.headers['access-control-expose-headers']).to.equal('WWW-Authenticate,Server-Authorization');
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
it('matches allowed headers (Origin implicit)', async () => {
|
|
550
|
+
|
|
551
|
+
const server = Hapi.server({ routes: { cors: true } });
|
|
552
|
+
server.route({ method: 'GET', path: '/', handler: () => 'ok' });
|
|
553
|
+
|
|
554
|
+
const res = await server.inject({
|
|
555
|
+
method: 'OPTIONS',
|
|
556
|
+
url: '/',
|
|
557
|
+
headers: {
|
|
558
|
+
origin: 'http://test.example.com',
|
|
559
|
+
'access-control-request-method': 'GET',
|
|
560
|
+
'access-control-request-headers': 'Origin'
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
expect(res.statusCode).to.equal(204);
|
|
565
|
+
expect(res.headers['access-control-allow-headers']).to.equal('Accept,Authorization,Content-Type,If-None-Match');
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
it('errors on disallowed headers', async () => {
|
|
569
|
+
|
|
570
|
+
const server = Hapi.server({ routes: { cors: true } });
|
|
571
|
+
server.route({ method: 'GET', path: '/', handler: () => 'ok' });
|
|
572
|
+
|
|
573
|
+
const res = await server.inject({
|
|
574
|
+
method: 'OPTIONS',
|
|
575
|
+
url: '/',
|
|
576
|
+
headers: {
|
|
577
|
+
origin: 'http://test.example.com',
|
|
578
|
+
'access-control-request-method': 'GET',
|
|
579
|
+
'access-control-request-headers': 'X'
|
|
580
|
+
}
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
expect(res.statusCode).to.equal(200);
|
|
584
|
+
expect(res.result.message).to.equal('CORS error: Some headers are not allowed');
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
it('allows credentials', async () => {
|
|
588
|
+
|
|
589
|
+
const server = Hapi.server({ routes: { cors: { credentials: true } } });
|
|
590
|
+
server.route({
|
|
591
|
+
method: 'GET',
|
|
592
|
+
path: '/',
|
|
593
|
+
handler: () => null
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
const res = await server.inject({ method: 'OPTIONS', url: '/', headers: { origin: 'http://example.com/', 'access-control-request-method': 'GET' } });
|
|
597
|
+
expect(res.statusCode).to.equal(204);
|
|
598
|
+
expect(res.headers['access-control-allow-credentials']).to.equal('true');
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
it('correctly finds route when using vhost setting', async () => {
|
|
602
|
+
|
|
603
|
+
const server = Hapi.server({ routes: { cors: true } });
|
|
604
|
+
server.route({
|
|
605
|
+
method: 'POST',
|
|
606
|
+
vhost: 'example.com',
|
|
607
|
+
path: '/',
|
|
608
|
+
handler: () => null
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
const res = await server.inject({ method: 'OPTIONS', url: 'http://example.com:4000/', headers: { origin: 'http://localhost', 'access-control-request-method': 'POST' } });
|
|
612
|
+
expect(res.statusCode).to.equal(204);
|
|
613
|
+
expect(res.headers['access-control-allow-methods']).to.equal('POST');
|
|
614
|
+
});
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
describe('headers()', () => {
|
|
618
|
+
|
|
619
|
+
it('skips CORS when missing origin header and wildcard does not ignore origin', async () => {
|
|
620
|
+
|
|
621
|
+
const server = Hapi.server({ routes: { cors: { origin: ['*'] } } });
|
|
622
|
+
server.route({
|
|
623
|
+
method: 'GET',
|
|
624
|
+
path: '/',
|
|
625
|
+
handler: () => 'ok'
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
const res = await server.inject('/');
|
|
629
|
+
expect(res.statusCode).to.equal(200);
|
|
630
|
+
expect(res.headers['access-control-allow-origin']).to.not.exist();
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
it('uses CORS when missing origin header and wildcard ignores origin', async () => {
|
|
634
|
+
|
|
635
|
+
const server = Hapi.server({ routes: { cors: { origin: 'ignore' } } });
|
|
636
|
+
server.route({
|
|
637
|
+
method: 'GET',
|
|
638
|
+
path: '/',
|
|
639
|
+
handler: () => 'ok'
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
const res = await server.inject('/');
|
|
643
|
+
expect(res.statusCode).to.equal(200);
|
|
644
|
+
expect(res.headers['access-control-allow-origin']).to.equal('*');
|
|
645
|
+
});
|
|
646
|
+
});
|
|
647
|
+
});
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Test
|