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.

Files changed (51) hide show
  1. package/NC.rar +0 -0
  2. package/README.md +23 -3
  3. package/lib/auth.js +573 -0
  4. package/lib/compression.js +119 -0
  5. package/lib/config.js +443 -0
  6. package/lib/core.js +699 -0
  7. package/lib/cors.js +207 -0
  8. package/lib/ext.js +96 -0
  9. package/lib/handler.js +165 -0
  10. package/lib/headers.js +187 -0
  11. package/lib/index.js +11 -0
  12. package/lib/methods.js +126 -0
  13. package/lib/request.js +751 -0
  14. package/lib/response.js +797 -0
  15. package/lib/route.js +517 -0
  16. package/lib/security.js +83 -0
  17. package/lib/server.js +603 -0
  18. package/lib/streams.js +61 -0
  19. package/lib/toolkit.js +258 -0
  20. package/lib/transmit.js +381 -0
  21. package/lib/validation.js +250 -0
  22. package/package-lock1.json +13 -0
  23. package/package.json +21 -3
  24. package/package1.json +24 -0
  25. package/package2.json +24 -0
  26. package/test/.hidden +1 -0
  27. package/test/auth.js +2020 -0
  28. package/test/common.js +27 -0
  29. package/test/core.js +2082 -0
  30. package/test/cors.js +647 -0
  31. package/test/file/image.jpg +0 -0
  32. package/test/file/image.png +0 -0
  33. package/test/file/image.png.gz +0 -0
  34. package/test/file/note.txt +1 -0
  35. package/test/handler.js +659 -0
  36. package/test/headers.js +537 -0
  37. package/test/index.js +25 -0
  38. package/test/methods.js +795 -0
  39. package/test/payload.js +849 -0
  40. package/test/request.js +2378 -0
  41. package/test/response.js +1568 -0
  42. package/test/route.js +967 -0
  43. package/test/security.js +97 -0
  44. package/test/server.js +3132 -0
  45. package/test/state.js +215 -0
  46. package/test/templates/invalid.html +3 -0
  47. package/test/templates/plugin/test.html +1 -0
  48. package/test/templates/test.html +3 -0
  49. package/test/toolkit.js +641 -0
  50. package/test/transmit.js +2121 -0
  51. package/test/validation.js +1831 -0
package/lib/route.js ADDED
@@ -0,0 +1,517 @@
1
+ 'use strict';
2
+
3
+ const Assert = require('assert');
4
+
5
+ const Boom = require('@hapi/boom');
6
+ const Bounce = require('@hapi/bounce');
7
+ const Catbox = require('@hapi/catbox');
8
+ const Hoek = require('@hapi/hoek');
9
+ const Subtext = require('@hapi/subtext');
10
+ const Validate = require('@hapi/validate');
11
+
12
+ const Auth = require('./auth');
13
+ const Config = require('./config');
14
+ const Cors = require('./cors');
15
+ const Ext = require('./ext');
16
+ const Handler = require('./handler');
17
+ const Headers = require('./headers');
18
+ const Security = require('./security');
19
+ const Streams = require('./streams');
20
+ const Validation = require('./validation');
21
+
22
+
23
+ const internals = {};
24
+
25
+
26
+ exports = module.exports = internals.Route = class {
27
+
28
+ constructor(route, server, options = {}) {
29
+
30
+ const core = server._core;
31
+ const realm = server.realm;
32
+
33
+ // Routing information
34
+
35
+ Config.apply('route', route, route.method, route.path);
36
+
37
+ const method = route.method.toLowerCase();
38
+ Hoek.assert(method !== 'head', 'Cannot set HEAD route:', route.path);
39
+
40
+ const path = realm.modifiers.route.prefix ? realm.modifiers.route.prefix + (route.path !== '/' ? route.path : '') : route.path;
41
+ Hoek.assert(path === '/' || path[path.length - 1] !== '/' || !core.settings.router.stripTrailingSlash, 'Path cannot end with a trailing slash when configured to strip:', route.method, route.path);
42
+
43
+ const vhost = realm.modifiers.route.vhost || route.vhost;
44
+
45
+ // Set identifying members (assert)
46
+
47
+ this.method = method;
48
+ this.path = path;
49
+
50
+ // Prepare configuration
51
+
52
+ let config = route.options || route.config || {};
53
+ if (typeof config === 'function') {
54
+ config = config.call(realm.settings.bind, server);
55
+ }
56
+
57
+ config = Config.enable(config); // Shallow clone
58
+
59
+ // Verify route level config (as opposed to the merged settings)
60
+
61
+ this._assert(method !== 'get' || !config.payload, 'Cannot set payload settings on HEAD or GET request');
62
+ this._assert(method !== 'get' || !config.validate || !config.validate.payload, 'Cannot validate HEAD or GET request payload');
63
+
64
+ // Rules
65
+
66
+ this._assert(!route.rules || !config.rules, 'Route rules can only appear once'); // XOR
67
+ const rules = route.rules || config.rules;
68
+ const rulesConfig = internals.rules(rules, { method, path, vhost }, server);
69
+ delete config.rules;
70
+
71
+ // Handler
72
+
73
+ this._assert(route.handler || config.handler, 'Missing or undefined handler');
74
+ this._assert(!!route.handler ^ !!config.handler, 'Handler must only appear once'); // XOR
75
+
76
+ const handler = Config.apply('handler', route.handler || config.handler);
77
+ delete config.handler;
78
+
79
+ const handlerDefaults = Handler.defaults(method, handler, core);
80
+
81
+ // Apply settings in order: server <- handler <- realm <- route
82
+
83
+ const settings = internals.config([core.settings.routes, handlerDefaults, realm.settings, rulesConfig, config]);
84
+ this.settings = Config.apply('routeConfig', settings, method, path);
85
+
86
+
87
+ // Route members
88
+
89
+ this._core = core;
90
+ this.realm = realm;
91
+
92
+ this.settings.vhost = vhost;
93
+ this.settings.plugins = this.settings.plugins || {}; // Route-specific plugins settings, namespaced using plugin name
94
+ this.settings.app = this.settings.app || {}; // Route-specific application settings
95
+
96
+ // Path parsing
97
+
98
+ this._special = !!options.special;
99
+ this._analysis = this._core.router.analyze(this.path);
100
+ this.params = this._analysis.params;
101
+ this.fingerprint = this._analysis.fingerprint;
102
+
103
+ this.public = {
104
+ method: this.method,
105
+ path: this.path,
106
+ vhost,
107
+ realm,
108
+ settings: this.settings,
109
+ fingerprint: this.fingerprint,
110
+ auth: {
111
+ access: (request) => Auth.testAccess(request, this.public)
112
+ }
113
+ };
114
+
115
+ // Validation
116
+
117
+ this._setupValidation();
118
+
119
+ // Payload parsing
120
+
121
+ if (this.method === 'get') {
122
+ this.settings.payload = null;
123
+ }
124
+ else {
125
+ this.settings.payload.decoders = this._core.compression.decoders; // Reference the shared object to keep up to date
126
+ }
127
+
128
+ this._assert(!this.settings.validate.payload || this.settings.payload.parse, 'Route payload must be set to \'parse\' when payload validation enabled');
129
+ this._assert(!this.settings.validate.state || this.settings.state.parse, 'Route state must be set to \'parse\' when state validation enabled');
130
+ this._assert(!this.settings.jsonp || typeof this.settings.jsonp === 'string', 'Bad route JSONP parameter name');
131
+
132
+ // Authentication configuration
133
+
134
+ this.settings.auth = this._special ? false : this._core.auth._setupRoute(this.settings.auth, path);
135
+
136
+ // Cache
137
+
138
+ if (this.method === 'get' &&
139
+ typeof this.settings.cache === 'object' &&
140
+ (this.settings.cache.expiresIn || this.settings.cache.expiresAt)) {
141
+
142
+ this.settings.cache._statuses = new Set(this.settings.cache.statuses);
143
+ this._cache = new Catbox.Policy({ expiresIn: this.settings.cache.expiresIn, expiresAt: this.settings.cache.expiresAt });
144
+ }
145
+
146
+ // CORS
147
+
148
+ this.settings.cors = Cors.route(this.settings.cors);
149
+
150
+ // Security
151
+
152
+ this.settings.security = Security.route(this.settings.security);
153
+
154
+ // Handler
155
+
156
+ this.settings.handler = Handler.configure(handler, this);
157
+ this._prerequisites = Handler.prerequisitesConfig(this.settings.pre);
158
+
159
+ // Route lifecycle
160
+
161
+ this._extensions = {
162
+ onPreResponse: Ext.combine(this, 'onPreResponse'),
163
+ onPostResponse: Ext.combine(this, 'onPostResponse')
164
+ };
165
+
166
+ if (this._special) {
167
+ this._cycle = [internals.drain, Handler.execute];
168
+ this.rebuild();
169
+ return;
170
+ }
171
+
172
+ this._extensions.onPreAuth = Ext.combine(this, 'onPreAuth');
173
+ this._extensions.onCredentials = Ext.combine(this, 'onCredentials');
174
+ this._extensions.onPostAuth = Ext.combine(this, 'onPostAuth');
175
+ this._extensions.onPreHandler = Ext.combine(this, 'onPreHandler');
176
+ this._extensions.onPostHandler = Ext.combine(this, 'onPostHandler');
177
+
178
+ this.rebuild();
179
+ }
180
+
181
+ _setupValidation() {
182
+
183
+ const validation = this.settings.validate;
184
+ if (this.method === 'get') {
185
+ validation.payload = null;
186
+ }
187
+
188
+ this._assert(!validation.params || this.params.length, 'Cannot set path parameters validations without path parameters');
189
+
190
+ for (const type of ['headers', 'params', 'query', 'payload', 'state']) {
191
+ validation[type] = Validation.compile(validation[type], this.settings.validate.validator, this.realm, this._core);
192
+ }
193
+
194
+ if (this.settings.response.schema !== undefined ||
195
+ this.settings.response.status) {
196
+
197
+ this.settings.response._validate = true;
198
+
199
+ const rule = this.settings.response.schema;
200
+ this.settings.response.status = this.settings.response.status || {};
201
+ const statuses = Object.keys(this.settings.response.status);
202
+
203
+ if (rule === true &&
204
+ !statuses.length) {
205
+
206
+ this.settings.response._validate = false;
207
+ }
208
+ else {
209
+ this.settings.response.schema = Validation.compile(rule, this.settings.validate.validator, this.realm, this._core);
210
+ for (const code of statuses) {
211
+ this.settings.response.status[code] = Validation.compile(this.settings.response.status[code], this.settings.validate.validator, this.realm, this._core);
212
+ }
213
+ }
214
+ }
215
+ }
216
+
217
+ rebuild(event) {
218
+
219
+ if (event) {
220
+ this._extensions[event.type].add(event);
221
+ }
222
+
223
+ if (this._special) {
224
+ this._postCycle = this._extensions.onPreResponse.nodes ? [this._extensions.onPreResponse] : [];
225
+ this._buildMarshalCycle();
226
+ return;
227
+ }
228
+
229
+ // Build lifecycle array
230
+
231
+ this._cycle = [];
232
+
233
+ // 'onRequest'
234
+
235
+ if (this.settings.jsonp) {
236
+ this._cycle.push(internals.parseJSONP);
237
+ }
238
+
239
+ if (this.settings.state.parse) {
240
+ this._cycle.push(internals.state);
241
+ }
242
+
243
+ if (this._extensions.onPreAuth.nodes) {
244
+ this._cycle.push(this._extensions.onPreAuth);
245
+ }
246
+
247
+ if (this._core.auth._enabled(this, 'authenticate')) {
248
+ this._cycle.push(Auth.authenticate);
249
+ }
250
+
251
+ if (this.method !== 'get') {
252
+ this._cycle.push(internals.payload);
253
+
254
+ if (this._core.auth._enabled(this, 'payload')) {
255
+ this._cycle.push(Auth.payload);
256
+ }
257
+ }
258
+
259
+ if (this._core.auth._enabled(this, 'authenticate') &&
260
+ this._extensions.onCredentials.nodes) {
261
+
262
+ this._cycle.push(this._extensions.onCredentials);
263
+ }
264
+
265
+ if (this._core.auth._enabled(this, 'access')) {
266
+ this._cycle.push(Auth.access);
267
+ }
268
+
269
+ if (this._extensions.onPostAuth.nodes) {
270
+ this._cycle.push(this._extensions.onPostAuth);
271
+ }
272
+
273
+ if (this.settings.validate.headers) {
274
+ this._cycle.push(Validation.headers);
275
+ }
276
+
277
+ if (this.settings.validate.params) {
278
+ this._cycle.push(Validation.params);
279
+ }
280
+
281
+ if (this.settings.jsonp) {
282
+ this._cycle.push(internals.cleanupJSONP);
283
+ }
284
+
285
+ if (this.settings.validate.query) {
286
+ this._cycle.push(Validation.query);
287
+ }
288
+
289
+ if (this.settings.validate.payload) {
290
+ this._cycle.push(Validation.payload);
291
+ }
292
+
293
+ if (this.settings.validate.state) {
294
+ this._cycle.push(Validation.state);
295
+ }
296
+
297
+ if (this._extensions.onPreHandler.nodes) {
298
+ this._cycle.push(this._extensions.onPreHandler);
299
+ }
300
+
301
+ this._cycle.push(Handler.execute);
302
+
303
+ if (this._extensions.onPostHandler.nodes) {
304
+ this._cycle.push(this._extensions.onPostHandler);
305
+ }
306
+
307
+ this._postCycle = [];
308
+
309
+ if (this.settings.response._validate &&
310
+ this.settings.response.sample !== 0) {
311
+
312
+ this._postCycle.push(Validation.response);
313
+ }
314
+
315
+ if (this._extensions.onPreResponse.nodes) {
316
+ this._postCycle.push(this._extensions.onPreResponse);
317
+ }
318
+
319
+ this._buildMarshalCycle();
320
+
321
+ // onPostResponse
322
+ }
323
+
324
+ _buildMarshalCycle() {
325
+
326
+ this._marshalCycle = [Headers.type];
327
+
328
+ if (this.settings.cors) {
329
+ this._marshalCycle.push(Cors.headers);
330
+ }
331
+
332
+ if (this.settings.security) {
333
+ this._marshalCycle.push(Security.headers);
334
+ }
335
+
336
+ this._marshalCycle.push(Headers.entity);
337
+
338
+ if (this.method === 'get' ||
339
+ this.method === '*') {
340
+
341
+ this._marshalCycle.push(Headers.unmodified);
342
+ }
343
+
344
+ this._marshalCycle.push(Headers.cache);
345
+ this._marshalCycle.push(Headers.state);
346
+ this._marshalCycle.push(Headers.content);
347
+
348
+ if (this._core.auth._enabled(this, 'response')) {
349
+ this._marshalCycle.push(Auth.response); // Must be last in case requires access to headers
350
+ }
351
+ }
352
+
353
+ _assert(condition, message) {
354
+
355
+ if (condition) {
356
+ return;
357
+ }
358
+
359
+ if (this.method[0] !== '_') {
360
+ message = `${message}: ${this.method.toUpperCase()} ${this.path}`;
361
+ }
362
+
363
+ throw new Assert.AssertionError({
364
+ message,
365
+ actual: false,
366
+ expected: true,
367
+ operator: '==',
368
+ stackStartFunction: this._assert
369
+ });
370
+ }
371
+ };
372
+
373
+
374
+ internals.state = async function (request) {
375
+
376
+ request.state = {};
377
+
378
+ const req = request.raw.req;
379
+ const cookies = req.headers.cookie;
380
+ if (!cookies) {
381
+ return;
382
+ }
383
+
384
+ try {
385
+ var result = await request._core.states.parse(cookies);
386
+ }
387
+ catch (err) {
388
+ Bounce.rethrow(err, 'system');
389
+ var parseError = err;
390
+ }
391
+
392
+ const { states, failed = [] } = result || parseError;
393
+ request.state = states || {};
394
+
395
+ // Clear cookies
396
+
397
+ for (const item of failed) {
398
+ if (item.settings.clearInvalid) {
399
+ request._clearState(item.name);
400
+ }
401
+ }
402
+
403
+ if (!parseError) {
404
+ return;
405
+ }
406
+
407
+ parseError.header = cookies;
408
+
409
+ return request._core.toolkit.failAction(request, request.route.settings.state.failAction, parseError, { tags: ['state', 'error'] });
410
+ };
411
+
412
+
413
+ internals.payload = async function (request) {
414
+
415
+ if (request.method === 'get' ||
416
+ request.method === 'head') { // When route.method is '*'
417
+
418
+ return;
419
+ }
420
+
421
+ if (request._expectContinue) {
422
+ request.raw.res.writeContinue();
423
+ }
424
+
425
+ if (request.payload !== undefined) {
426
+ return internals.drain(request);
427
+ }
428
+
429
+ try {
430
+ const { payload, mime } = await Subtext.parse(request.raw.req, request._tap(), request.route.settings.payload);
431
+
432
+ request._isPayloadPending = !!(payload && payload._readableState);
433
+ request.mime = mime;
434
+ request.payload = payload;
435
+ }
436
+ catch (err) {
437
+ Bounce.rethrow(err, 'system');
438
+
439
+ if (request._isPayloadPending) {
440
+ await internals.drain(request);
441
+ }
442
+
443
+ request.mime = err.mime;
444
+ request.payload = null;
445
+
446
+ return request._core.toolkit.failAction(request, request.route.settings.payload.failAction, err, { tags: ['payload', 'error'] });
447
+ }
448
+ };
449
+
450
+
451
+ internals.drain = async function (request) {
452
+
453
+ // Flush out any pending request payload not consumed due to errors
454
+
455
+ await Streams.drain(request.raw.req);
456
+ request._isPayloadPending = false;
457
+ };
458
+
459
+
460
+ internals.jsonpRegex = /^[\w\$\[\]\.]+$/;
461
+
462
+
463
+ internals.parseJSONP = function (request) {
464
+
465
+ const jsonp = request.query[request.route.settings.jsonp];
466
+ if (jsonp) {
467
+ if (internals.jsonpRegex.test(jsonp) === false) {
468
+ throw Boom.badRequest('Invalid JSONP parameter value');
469
+ }
470
+
471
+ request.jsonp = jsonp;
472
+ }
473
+ };
474
+
475
+
476
+ internals.cleanupJSONP = function (request) {
477
+
478
+ if (request.jsonp) {
479
+ delete request.query[request.route.settings.jsonp];
480
+ }
481
+ };
482
+
483
+
484
+ internals.config = function (chain) {
485
+
486
+ if (!chain.length) {
487
+ return {};
488
+ }
489
+
490
+ let config = chain[0];
491
+ for (const item of chain) {
492
+ config = Hoek.applyToDefaults(config, item, { shallow: ['bind', 'validate.headers', 'validate.payload', 'validate.params', 'validate.query', 'validate.state'] });
493
+ }
494
+
495
+ return config;
496
+ };
497
+
498
+
499
+ internals.rules = function (rules, info, server) {
500
+
501
+ const configs = [];
502
+
503
+ let realm = server.realm;
504
+ while (realm) {
505
+ if (realm._rules) {
506
+ const source = !realm._rules.settings.validate ? rules : Validate.attempt(rules, realm._rules.settings.validate.schema, realm._rules.settings.validate.options);
507
+ const config = realm._rules.processor(source, info);
508
+ if (config) {
509
+ configs.unshift(config);
510
+ }
511
+ }
512
+
513
+ realm = realm.parent;
514
+ }
515
+
516
+ return internals.config(configs);
517
+ };
@@ -0,0 +1,83 @@
1
+ 'use strict';
2
+
3
+ const internals = {};
4
+
5
+
6
+ exports.route = function (settings) {
7
+
8
+ if (!settings) {
9
+ return null;
10
+ }
11
+
12
+ const security = settings;
13
+ if (security.hsts) {
14
+ if (security.hsts === true) {
15
+ security._hsts = 'max-age=15768000';
16
+ }
17
+ else if (typeof security.hsts === 'number') {
18
+ security._hsts = 'max-age=' + security.hsts;
19
+ }
20
+ else {
21
+ security._hsts = 'max-age=' + (security.hsts.maxAge || 15768000);
22
+ if (security.hsts.includeSubdomains || security.hsts.includeSubDomains) {
23
+ security._hsts = security._hsts + '; includeSubDomains';
24
+ }
25
+
26
+ if (security.hsts.preload) {
27
+ security._hsts = security._hsts + '; preload';
28
+ }
29
+ }
30
+ }
31
+
32
+ if (security.xframe) {
33
+ if (security.xframe === true) {
34
+ security._xframe = 'DENY';
35
+ }
36
+ else if (typeof security.xframe === 'string') {
37
+ security._xframe = security.xframe.toUpperCase();
38
+ }
39
+ else if (security.xframe.rule === 'allow-from') {
40
+ if (!security.xframe.source) {
41
+ security._xframe = 'SAMEORIGIN';
42
+ }
43
+ else {
44
+ security._xframe = 'ALLOW-FROM ' + security.xframe.source;
45
+ }
46
+ }
47
+ else {
48
+ security._xframe = security.xframe.rule.toUpperCase();
49
+ }
50
+ }
51
+
52
+ return security;
53
+ };
54
+
55
+
56
+ exports.headers = function (response) {
57
+
58
+ const security = response.request.route.settings.security;
59
+
60
+ if (security._hsts) {
61
+ response._header('strict-transport-security', security._hsts, { override: false });
62
+ }
63
+
64
+ if (security._xframe) {
65
+ response._header('x-frame-options', security._xframe, { override: false });
66
+ }
67
+
68
+ if (security.xss) {
69
+ response._header('x-xss-protection', '1; mode=block', { override: false });
70
+ }
71
+
72
+ if (security.noOpen) {
73
+ response._header('x-download-options', 'noopen', { override: false });
74
+ }
75
+
76
+ if (security.noSniff) {
77
+ response._header('x-content-type-options', 'nosniff', { override: false });
78
+ }
79
+
80
+ if (security.referrer !== false) {
81
+ response._header('referrer-policy', security.referrer, { override: false });
82
+ }
83
+ };