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
@@ -0,0 +1,797 @@
1
+ 'use strict';
2
+
3
+ const Stream = require('stream');
4
+
5
+ const Boom = require('@hapi/boom');
6
+ const Bounce = require('@hapi/bounce');
7
+ const Hoek = require('@hapi/hoek');
8
+ const Podium = require('@hapi/podium');
9
+
10
+ const Streams = require('./streams');
11
+
12
+
13
+ const internals = {
14
+ events: Podium.validate(['finish', { name: 'peek', spread: true }]),
15
+ hopByHop: {
16
+ connection: true,
17
+ 'keep-alive': true,
18
+ 'proxy-authenticate': true,
19
+ 'proxy-authorization': true,
20
+ 'te': true,
21
+ 'trailer': true,
22
+ 'transfer-encoding': true,
23
+ 'upgrade': true
24
+ },
25
+ reserved: ['app', 'headers', 'plugins', 'request', 'source', 'statusCode', 'variety',
26
+ 'settings', 'events', 'code', 'message', 'header', 'vary', 'etag', 'type', 'contentType',
27
+ 'bytes', 'location', 'created', 'compressed', 'replacer', 'space', 'suffix', 'escape',
28
+ 'passThrough', 'redirect', 'temporary', 'permanent', 'rewritable', 'encoding', 'charset',
29
+ 'ttl', 'state', 'unstate', 'takeover']
30
+ };
31
+
32
+
33
+ exports = module.exports = internals.Response = class {
34
+
35
+ constructor(source, request, options = {}) {
36
+
37
+ this.app = {};
38
+ this.headers = {}; // Incomplete as some headers are stored in flags
39
+ this.plugins = {};
40
+ this.request = request;
41
+ this.source = null;
42
+ this.statusCode = null;
43
+ this.variety = null;
44
+
45
+ this.settings = {
46
+ charset: 'utf-8', // '-' required by IANA
47
+ compressed: null,
48
+ encoding: 'utf8',
49
+ message: null,
50
+ passThrough: true,
51
+ stringify: null, // JSON.stringify options
52
+ ttl: null,
53
+ varyEtag: false
54
+ };
55
+
56
+ this._events = null;
57
+ this._payload = null; // Readable stream
58
+ this._error = options.error || null; // The boom object when created from an error (used for logging)
59
+ this._contentType = null; // Used if no explicit content-type is set and type is known
60
+ this._takeover = false;
61
+ this._statusCode = false; // true when code() called
62
+ this._state = this._error ? 'prepare' : 'init'; // One of 'init', 'prepare', 'marshall', 'close'
63
+
64
+ this._processors = {
65
+ marshal: options.marshal,
66
+ prepare: options.prepare,
67
+ close: options.close
68
+ };
69
+
70
+ this._setSource(source, options.variety);
71
+ }
72
+
73
+ static wrap(result, request) {
74
+
75
+ if (result instanceof request._core.Response ||
76
+ typeof result === 'symbol') {
77
+
78
+ return result;
79
+ }
80
+
81
+ if (result instanceof Error) {
82
+ return Boom.boomify(result);
83
+ }
84
+
85
+ return new request._core.Response(result, request);
86
+ }
87
+
88
+ _setSource(source, variety) {
89
+
90
+ // Method must not set any headers or other properties as source can change later
91
+
92
+ this.variety = variety || 'plain';
93
+
94
+ if (source === null ||
95
+ source === undefined) {
96
+
97
+ source = null;
98
+ }
99
+ else if (Buffer.isBuffer(source)) {
100
+ this.variety = 'buffer';
101
+ this._contentType = 'application/octet-stream';
102
+ }
103
+ else if (Streams.isStream(source)) {
104
+ this.variety = 'stream';
105
+ this._contentType = 'application/octet-stream';
106
+ }
107
+
108
+ this.source = source;
109
+
110
+ if (this.variety === 'plain' &&
111
+ this.source !== null) {
112
+
113
+ this._contentType = typeof this.source === 'string' ? 'text/html' : 'application/json';
114
+ }
115
+ }
116
+
117
+ get events() {
118
+
119
+ if (!this._events) {
120
+ this._events = new Podium(internals.events);
121
+ }
122
+
123
+ return this._events;
124
+ }
125
+
126
+ code(statusCode) {
127
+
128
+ Hoek.assert(Number.isSafeInteger(statusCode), 'Status code must be an integer');
129
+
130
+ this.statusCode = statusCode;
131
+ this._statusCode = true;
132
+
133
+ return this;
134
+ }
135
+
136
+ message(httpMessage) {
137
+
138
+ this.settings.message = httpMessage;
139
+ return this;
140
+ }
141
+
142
+ header(key, value, options) {
143
+
144
+ key = key.toLowerCase();
145
+ if (key === 'vary') {
146
+ return this.vary(value);
147
+ }
148
+
149
+ return this._header(key, value, options);
150
+ }
151
+
152
+ _header(key, value, options = {}) {
153
+
154
+ const append = options.append || false;
155
+ const separator = options.separator || ',';
156
+ const override = options.override !== false;
157
+ const duplicate = options.duplicate !== false;
158
+
159
+ if (!append && override ||
160
+ !this.headers[key]) {
161
+
162
+ this.headers[key] = value;
163
+ }
164
+ else if (override) {
165
+ if (key === 'set-cookie') {
166
+ this.headers[key] = [].concat(this.headers[key], value);
167
+ }
168
+ else {
169
+ const existing = this.headers[key];
170
+ if (!duplicate) {
171
+ const values = existing.split(separator);
172
+ for (const v of values) {
173
+ if (v === value) {
174
+ return this;
175
+ }
176
+ }
177
+ }
178
+
179
+ this.headers[key] = existing + separator + value;
180
+ }
181
+ }
182
+
183
+ return this;
184
+ }
185
+
186
+ vary(value) {
187
+
188
+ if (value === '*') {
189
+ this.headers.vary = '*';
190
+ }
191
+ else if (!this.headers.vary) {
192
+ this.headers.vary = value;
193
+ }
194
+ else if (this.headers.vary !== '*') {
195
+ this._header('vary', value, { append: true, duplicate: false });
196
+ }
197
+
198
+ return this;
199
+ }
200
+
201
+ etag(tag, options) {
202
+
203
+ const entity = this.request._core.Response.entity(tag, options);
204
+ this._header('etag', entity.etag);
205
+ this.settings.varyEtag = entity.vary;
206
+ return this;
207
+ }
208
+
209
+ static entity(tag, options = {}) {
210
+
211
+ Hoek.assert(tag !== '*', 'ETag cannot be *');
212
+
213
+ return {
214
+ etag: (options.weak ? 'W/' : '') + '"' + tag + '"',
215
+ vary: options.vary !== false && !options.weak, // vary defaults to true
216
+ modified: options.modified
217
+ };
218
+ }
219
+
220
+ static unmodified(request, entity) {
221
+
222
+ if (request.method !== 'get' &&
223
+ request.method !== 'head') {
224
+
225
+ return false;
226
+ }
227
+
228
+ // Strong verifier
229
+
230
+ if (entity.etag &&
231
+ request.headers['if-none-match']) {
232
+
233
+ const ifNoneMatch = request.headers['if-none-match'].split(/\s*,\s*/);
234
+ for (const etag of ifNoneMatch) {
235
+
236
+ // Compare tags (https://tools.ietf.org/html/rfc7232#section-2.3.2)
237
+
238
+ if (etag === entity.etag) { // Strong comparison
239
+ return true;
240
+ }
241
+
242
+ if (!entity.vary) {
243
+ continue;
244
+ }
245
+
246
+ if (etag === `W/${entity.etag}`) { // Weak comparison
247
+ return etag;
248
+ }
249
+
250
+ const etagBase = entity.etag.slice(0, -1);
251
+ const encoders = request._core.compression.encodings;
252
+ for (const encoder of encoders) {
253
+ if (etag === etagBase + `-${encoder}"`) {
254
+ return true;
255
+ }
256
+ }
257
+ }
258
+
259
+ return false;
260
+ }
261
+
262
+ // Weak verifier
263
+
264
+ if (!entity.modified) {
265
+ return false;
266
+ }
267
+
268
+ const ifModifiedSinceHeader = request.headers['if-modified-since'];
269
+ if (!ifModifiedSinceHeader) {
270
+ return false;
271
+ }
272
+
273
+ const ifModifiedSince = internals.parseDate(ifModifiedSinceHeader);
274
+ if (!ifModifiedSince) {
275
+ return false;
276
+ }
277
+
278
+ const lastModified = internals.parseDate(entity.modified);
279
+ if (!lastModified) {
280
+ return false;
281
+ }
282
+
283
+ return ifModifiedSince >= lastModified;
284
+ }
285
+
286
+ type(type) {
287
+
288
+ this._header('content-type', type);
289
+ return this;
290
+ }
291
+
292
+ get contentType() {
293
+
294
+ let type = this.headers['content-type'];
295
+ if (type) {
296
+ type = type.trim();
297
+ if (this.settings.charset &&
298
+ type.match(/^(?:text\/)|(?:application\/(?:json)|(?:javascript))/) &&
299
+ !type.match(/; *charset=/)) {
300
+
301
+ const semi = type[type.length - 1] === ';';
302
+ return type + (semi ? ' ' : '; ') + 'charset=' + this.settings.charset;
303
+ }
304
+
305
+ return type;
306
+ }
307
+
308
+ if (this._contentType) {
309
+ const charset = this.settings.charset && this._contentType !== 'application/octet-stream' ? '; charset=' + this.settings.charset : '';
310
+ return this._contentType + charset;
311
+ }
312
+
313
+ return null;
314
+ }
315
+
316
+ bytes(bytes) {
317
+
318
+ this._header('content-length', bytes);
319
+ return this;
320
+ }
321
+
322
+ location(uri) {
323
+
324
+ this._header('location', uri);
325
+ return this;
326
+ }
327
+
328
+ created(location) {
329
+
330
+ Hoek.assert(this.request.method === 'post' ||
331
+ this.request.method === 'put' ||
332
+ this.request.method === 'patch', 'Cannot return 201 status codes for ' + this.request.method.toUpperCase());
333
+
334
+ this.statusCode = 201;
335
+ this.location(location);
336
+ return this;
337
+ }
338
+
339
+ compressed(encoding) {
340
+
341
+ Hoek.assert(encoding && typeof encoding === 'string', 'Invalid content-encoding');
342
+ this.settings.compressed = encoding;
343
+ return this;
344
+ }
345
+
346
+ replacer(method) {
347
+
348
+ this.settings.stringify = this.settings.stringify || {};
349
+ this.settings.stringify.replacer = method;
350
+ return this;
351
+ }
352
+
353
+ spaces(count) {
354
+
355
+ this.settings.stringify = this.settings.stringify || {};
356
+ this.settings.stringify.space = count;
357
+ return this;
358
+ }
359
+
360
+ suffix(suffix) {
361
+
362
+ this.settings.stringify = this.settings.stringify || {};
363
+ this.settings.stringify.suffix = suffix;
364
+ return this;
365
+ }
366
+
367
+ escape(escape) {
368
+
369
+ this.settings.stringify = this.settings.stringify || {};
370
+ this.settings.stringify.escape = escape;
371
+ return this;
372
+ }
373
+
374
+ passThrough(enabled) {
375
+
376
+ this.settings.passThrough = enabled !== false; // Defaults to true
377
+ return this;
378
+ }
379
+
380
+ redirect(location) {
381
+
382
+ this.statusCode = 302;
383
+ this.location(location);
384
+ return this;
385
+ }
386
+
387
+ temporary(isTemporary) {
388
+
389
+ Hoek.assert(this.headers.location, 'Cannot set redirection mode without first setting a location');
390
+
391
+ this._setTemporary(isTemporary !== false); // Defaults to true
392
+ return this;
393
+ }
394
+
395
+ permanent(isPermanent) {
396
+
397
+ Hoek.assert(this.headers.location, 'Cannot set redirection mode without first setting a location');
398
+
399
+ this._setTemporary(isPermanent === false); // Defaults to true
400
+ return this;
401
+ }
402
+
403
+ rewritable(isRewritable) {
404
+
405
+ Hoek.assert(this.headers.location, 'Cannot set redirection mode without first setting a location');
406
+
407
+ this._setRewritable(isRewritable !== false); // Defaults to true
408
+ return this;
409
+ }
410
+
411
+ _isTemporary() {
412
+
413
+ return this.statusCode === 302 || this.statusCode === 307;
414
+ }
415
+
416
+ _isRewritable() {
417
+
418
+ return this.statusCode === 301 || this.statusCode === 302;
419
+ }
420
+
421
+ _setTemporary(isTemporary) {
422
+
423
+ if (isTemporary) {
424
+ if (this._isRewritable()) {
425
+ this.statusCode = 302;
426
+ }
427
+ else {
428
+ this.statusCode = 307;
429
+ }
430
+ }
431
+ else {
432
+ if (this._isRewritable()) {
433
+ this.statusCode = 301;
434
+ }
435
+ else {
436
+ this.statusCode = 308;
437
+ }
438
+ }
439
+ }
440
+
441
+ _setRewritable(isRewritable) {
442
+
443
+ if (isRewritable) {
444
+ if (this._isTemporary()) {
445
+ this.statusCode = 302;
446
+ }
447
+ else {
448
+ this.statusCode = 301;
449
+ }
450
+ }
451
+ else {
452
+ if (this._isTemporary()) {
453
+ this.statusCode = 307;
454
+ }
455
+ else {
456
+ this.statusCode = 308;
457
+ }
458
+ }
459
+ }
460
+
461
+ encoding(encoding) {
462
+
463
+ this.settings.encoding = encoding;
464
+ return this;
465
+ }
466
+
467
+ charset(charset) {
468
+
469
+ this.settings.charset = charset || null;
470
+ return this;
471
+ }
472
+
473
+ ttl(ttl) {
474
+
475
+ this.settings.ttl = ttl;
476
+ return this;
477
+ }
478
+
479
+ state(name, value, options) {
480
+
481
+ this.request._setState(name, value, options);
482
+ return this;
483
+ }
484
+
485
+ unstate(name, options) {
486
+
487
+ this.request._clearState(name, options);
488
+ return this;
489
+ }
490
+
491
+ takeover() {
492
+
493
+ this._takeover = true;
494
+ return this;
495
+ }
496
+
497
+ _prepare() {
498
+
499
+ Hoek.assert(this._state === 'init');
500
+
501
+ this._state = 'prepare';
502
+
503
+ this._passThrough();
504
+
505
+ if (!this._processors.prepare) {
506
+ return this;
507
+ }
508
+
509
+ try {
510
+ return this._processors.prepare(this);
511
+ }
512
+ catch (err) {
513
+ throw Boom.boomify(err);
514
+ }
515
+ }
516
+
517
+ _passThrough() {
518
+
519
+ if (this.variety === 'stream' &&
520
+ this.settings.passThrough) {
521
+
522
+ if (this.source.statusCode &&
523
+ !this.statusCode) {
524
+
525
+ this.statusCode = this.source.statusCode; // Stream is an HTTP response
526
+ }
527
+
528
+ if (this.source.headers) {
529
+ let headerKeys = Object.keys(this.source.headers);
530
+
531
+ if (headerKeys.length) {
532
+ const localHeaders = this.headers;
533
+ this.headers = {};
534
+
535
+ const connection = this.source.headers.connection;
536
+ const byHop = {};
537
+ if (connection) {
538
+ connection.split(/\s*,\s*/).forEach((header) => {
539
+
540
+ byHop[header] = true;
541
+ });
542
+ }
543
+
544
+ for (const key of headerKeys) {
545
+ const lower = key.toLowerCase();
546
+ if (!internals.hopByHop[lower] &&
547
+ !byHop[lower]) {
548
+
549
+ this.header(lower, Hoek.clone(this.source.headers[key])); // Clone arrays
550
+ }
551
+ }
552
+
553
+ headerKeys = Object.keys(localHeaders);
554
+ for (const key of headerKeys) {
555
+ this.header(key, localHeaders[key], { append: key === 'set-cookie' });
556
+ }
557
+ }
558
+ }
559
+ }
560
+
561
+ this.statusCode = this.statusCode || 200;
562
+ }
563
+
564
+ async _marshal() {
565
+
566
+ Hoek.assert(this._state === 'prepare');
567
+
568
+ this._state = 'marshall';
569
+
570
+ // Processor marshal
571
+
572
+ let source = this.source;
573
+
574
+ if (this._processors.marshal) {
575
+ try {
576
+ source = await this._processors.marshal(this);
577
+ }
578
+ catch (err) {
579
+ throw Boom.boomify(err);
580
+ }
581
+ }
582
+
583
+ // Stream source
584
+
585
+ if (Streams.isStream(source)) {
586
+ this._payload = source;
587
+ return;
588
+ }
589
+
590
+ // Plain source (non string or null)
591
+
592
+ const jsonify = this.variety === 'plain' && source !== null && typeof source !== 'string';
593
+
594
+ if (!jsonify &&
595
+ this.settings.stringify) {
596
+
597
+ throw Boom.badImplementation('Cannot set formatting options on non object response');
598
+ }
599
+
600
+ let payload = source;
601
+
602
+ if (jsonify) {
603
+ const options = this.settings.stringify || {};
604
+ const space = options.space || this.request.route.settings.json.space;
605
+ const replacer = options.replacer || this.request.route.settings.json.replacer;
606
+ const suffix = options.suffix || this.request.route.settings.json.suffix || '';
607
+ const escape = this.request.route.settings.json.escape || false;
608
+
609
+ try {
610
+ if (replacer || space) {
611
+ payload = JSON.stringify(payload, replacer, space);
612
+ }
613
+ else {
614
+ payload = JSON.stringify(payload);
615
+ }
616
+ }
617
+ catch (err) {
618
+ throw Boom.boomify(err);
619
+ }
620
+
621
+ if (suffix) {
622
+ payload = payload + suffix;
623
+ }
624
+
625
+ if (escape) {
626
+ payload = Hoek.escapeJson(payload);
627
+ }
628
+ }
629
+
630
+ this._payload = new internals.Response.Payload(payload, this.settings);
631
+ }
632
+
633
+ _tap() {
634
+
635
+ if (!this._events) {
636
+ return null;
637
+ }
638
+
639
+ if (this._events.hasListeners('peek') ||
640
+ this._events.hasListeners('finish')) {
641
+
642
+ return new internals.Response.Peek(this._events);
643
+ }
644
+
645
+ return null;
646
+ }
647
+
648
+ _close() {
649
+
650
+ if (this._state === 'close') {
651
+ return;
652
+ }
653
+
654
+ this._state = 'close';
655
+
656
+ if (this._processors.close) {
657
+ try {
658
+ this._processors.close(this);
659
+ }
660
+ catch (err) {
661
+ Bounce.rethrow(err, 'system');
662
+ this.request._log(['response', 'cleanup', 'error'], err);
663
+ }
664
+ }
665
+
666
+ const stream = this._payload || this.source;
667
+ if (Streams.isStream(stream)) {
668
+ internals.Response.drain(stream);
669
+ }
670
+ }
671
+
672
+ _isPayloadSupported() {
673
+
674
+ return this.request.method !== 'head' && this.statusCode !== 304 && this.statusCode !== 204;
675
+ }
676
+
677
+ static drain(stream) {
678
+
679
+ if (stream.destroy) {
680
+ stream.destroy();
681
+ return;
682
+ }
683
+
684
+ // Fallback for old-style streams
685
+
686
+ stream.unpipe();
687
+
688
+ if (stream.close) {
689
+ stream.close();
690
+ }
691
+ }
692
+ };
693
+
694
+
695
+ internals.Response.reserved = internals.reserved;
696
+
697
+
698
+ internals.parseDate = function (string) {
699
+
700
+ try {
701
+ return Date.parse(string);
702
+ }
703
+ catch (errIgnore) { }
704
+ };
705
+
706
+
707
+ internals.Response.Payload = class extends Stream.Readable {
708
+
709
+ constructor(payload, options) {
710
+
711
+ super();
712
+
713
+ this._data = payload;
714
+ this._prefix = null;
715
+ this._suffix = null;
716
+ this._sizeOffset = 0;
717
+ this._encoding = options.encoding;
718
+ }
719
+
720
+ _read(size) {
721
+
722
+ if (this._prefix) {
723
+ this.push(this._prefix, this._encoding);
724
+ }
725
+
726
+ if (this._data) {
727
+ this.push(this._data, this._encoding);
728
+ }
729
+
730
+ if (this._suffix) {
731
+ this.push(this._suffix, this._encoding);
732
+ }
733
+
734
+ this.push(null);
735
+ }
736
+
737
+ size() {
738
+
739
+ if (!this._data) {
740
+ return this._sizeOffset;
741
+ }
742
+
743
+ return (Buffer.isBuffer(this._data) ? this._data.length : Buffer.byteLength(this._data, this._encoding)) + this._sizeOffset;
744
+ }
745
+
746
+ jsonp(variable) {
747
+
748
+ this._sizeOffset = this._sizeOffset + variable.length + 7;
749
+ this._prefix = '/**/' + variable + '('; // '/**/' prefix prevents CVE-2014-4671 security exploit
750
+
751
+ if (this._data !== null &&
752
+ !Buffer.isBuffer(this._data)) {
753
+
754
+ this._data = this._data
755
+ .replace(/\u2028/g, '\\u2028')
756
+ .replace(/\u2029/g, '\\u2029');
757
+ }
758
+
759
+ this._suffix = ');';
760
+ }
761
+
762
+ writeToStream(stream) {
763
+
764
+ if (this._prefix) {
765
+ stream.write(this._prefix, this._encoding);
766
+ }
767
+
768
+ if (this._data) {
769
+ stream.write(this._data, this._encoding);
770
+ }
771
+
772
+ if (this._suffix) {
773
+ stream.write(this._suffix, this._encoding);
774
+ }
775
+
776
+ stream.end();
777
+ }
778
+ };
779
+
780
+
781
+ internals.Response.Peek = class extends Stream.Transform {
782
+
783
+ constructor(podium) {
784
+
785
+ super();
786
+
787
+ this._podium = podium;
788
+ this.on('finish', () => podium.emit('finish'));
789
+ }
790
+
791
+ _transform(chunk, encoding, callback) {
792
+
793
+ this._podium.emit('peek', [chunk, encoding]);
794
+ this.push(chunk, encoding);
795
+ callback();
796
+ }
797
+ };