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/toolkit.js ADDED
@@ -0,0 +1,258 @@
1
+ 'use strict';
2
+
3
+ const Boom = require('@hapi/boom');
4
+ const Bounce = require('@hapi/bounce');
5
+ const Hoek = require('@hapi/hoek');
6
+
7
+
8
+ const internals = {};
9
+
10
+
11
+ exports.reserved = [
12
+ 'abandon',
13
+ 'authenticated',
14
+ 'close',
15
+ 'context',
16
+ 'continue',
17
+ 'entity',
18
+ 'redirect',
19
+ 'realm',
20
+ 'request',
21
+ 'response',
22
+ 'state',
23
+ 'unauthenticated',
24
+ 'unstate'
25
+ ];
26
+
27
+
28
+ exports.symbols = {
29
+ abandon: Symbol('abandon'),
30
+ close: Symbol('close'),
31
+ continue: Symbol('continue')
32
+ };
33
+
34
+
35
+ exports.Manager = class {
36
+
37
+ constructor() {
38
+
39
+ this._toolkit = internals.toolkit();
40
+ }
41
+
42
+ async execute(method, request, options) {
43
+
44
+ const h = new this._toolkit(request, options);
45
+ const bind = options.bind || null;
46
+
47
+ try {
48
+ let operation;
49
+
50
+ if (bind) {
51
+ operation = method.call(bind, request, h);
52
+ }
53
+ else if (options.args) {
54
+ operation = method(request, h, ...options.args);
55
+ }
56
+ else {
57
+ operation = method(request, h);
58
+ }
59
+
60
+ var response = await exports.timed(operation, options);
61
+ }
62
+ catch (err) {
63
+ if (Bounce.isSystem(err)) {
64
+ response = Boom.badImplementation(err);
65
+ }
66
+ else if (!Bounce.isError(err)) {
67
+ response = Boom.badImplementation('Cannot throw non-error object', err);
68
+ }
69
+ else {
70
+ response = Boom.boomify(err);
71
+ }
72
+ }
73
+
74
+ // Process response
75
+
76
+ if (options.ignoreResponse) {
77
+ return response;
78
+ }
79
+
80
+ if (response === undefined) {
81
+ response = Boom.badImplementation(`${method.name} method did not return a value, a promise, or throw an error`);
82
+ }
83
+
84
+ if (options.continue &&
85
+ response === exports.symbols.continue) {
86
+
87
+ if (options.continue === 'undefined') {
88
+ return;
89
+ }
90
+
91
+ // 'null'
92
+
93
+ response = null;
94
+ }
95
+
96
+ if (options.auth &&
97
+ response instanceof internals.Auth) {
98
+
99
+ return response;
100
+ }
101
+
102
+ if (typeof response !== 'symbol') {
103
+ response = request._core.Response.wrap(response, request);
104
+ if (!response.isBoom && response._state === 'init') {
105
+ response = await response._prepare();
106
+ }
107
+ }
108
+
109
+ return response;
110
+ }
111
+
112
+ decorate(name, method) {
113
+
114
+ this._toolkit.prototype[name] = method;
115
+ }
116
+
117
+ failAction(request, failAction, err, options) {
118
+
119
+ const retain = options.retain ? err : undefined;
120
+ if (failAction === 'ignore') {
121
+ return retain;
122
+ }
123
+
124
+ if (failAction === 'log') {
125
+ request._log(options.tags, err);
126
+ return retain;
127
+ }
128
+
129
+ if (failAction === 'error') {
130
+ throw err;
131
+ }
132
+
133
+ return this.execute(failAction, request, { realm: request.route.realm, args: [options.details || err] });
134
+ }
135
+ };
136
+
137
+
138
+ exports.timed = function (method, options) {
139
+
140
+ if (!options.timeout) {
141
+ return method;
142
+ }
143
+
144
+ const timer = new Promise((resolve, reject) => {
145
+
146
+ const handler = () => {
147
+
148
+ reject(Boom.internal(`${options.name} timed out`));
149
+ };
150
+
151
+ setTimeout(handler, options.timeout);
152
+ });
153
+
154
+ return Promise.race([timer, method]);
155
+ };
156
+
157
+
158
+ /*
159
+ const handler = function (request, h) {
160
+
161
+ result / h.response(result) -> result // Not allowed before handler
162
+ h.response(result).takeover() -> result (respond)
163
+ h.continue -> null // Defaults to null only in handler and pre, not allowed in auth
164
+
165
+ throw error / h.response(error) -> error (respond) // failAction override in pre
166
+ <undefined> -> badImplementation (respond)
167
+
168
+ // Auth only (scheme.payload and scheme.response use the same interface as pre-handler extension methods)
169
+
170
+ h.unauthenticated(error, data) -> error (respond) + data
171
+ h.authenticated(data ) -> (continue) + data
172
+ };
173
+ */
174
+
175
+ internals.toolkit = function () {
176
+
177
+ const Toolkit = class {
178
+
179
+ constructor(request, options) {
180
+
181
+ this.context = options.bind;
182
+ this.realm = options.realm;
183
+ this.request = request;
184
+
185
+ this._auth = options.auth;
186
+ }
187
+
188
+ response(result) {
189
+
190
+ Hoek.assert(!result || typeof result !== 'object' || typeof result.then !== 'function', 'Cannot wrap a promise');
191
+ Hoek.assert(result instanceof Error === false, 'Cannot wrap an error');
192
+ Hoek.assert(typeof result !== 'symbol', 'Cannot wrap a symbol');
193
+
194
+ return this.request._core.Response.wrap(result, this.request);
195
+ }
196
+
197
+ redirect(location) {
198
+
199
+ return this.response('').redirect(location);
200
+ }
201
+
202
+ entity(options) {
203
+
204
+ Hoek.assert(options, 'Entity method missing required options');
205
+ Hoek.assert(options.etag || options.modified, 'Entity methods missing required options key');
206
+
207
+ this.request._entity = options;
208
+
209
+ const entity = this.request._core.Response.entity(options.etag, options);
210
+ if (this.request._core.Response.unmodified(this.request, entity)) {
211
+ return this.response().code(304).takeover();
212
+ }
213
+ }
214
+
215
+ state(name, value, options) {
216
+
217
+ this.request._setState(name, value, options);
218
+ }
219
+
220
+ unstate(name, options) {
221
+
222
+ this.request._clearState(name, options);
223
+ }
224
+
225
+ authenticated(data) {
226
+
227
+ Hoek.assert(this._auth, 'Method not supported outside of authentication');
228
+ Hoek.assert(data && data.credentials, 'Authentication data missing credentials information');
229
+
230
+ return new internals.Auth(null, data);
231
+ }
232
+
233
+ unauthenticated(error, data) {
234
+
235
+ Hoek.assert(this._auth, 'Method not supported outside of authentication');
236
+ Hoek.assert(!data || data.credentials, 'Authentication data missing credentials information');
237
+
238
+ return new internals.Auth(error, data);
239
+ }
240
+ };
241
+
242
+ Toolkit.prototype.abandon = exports.symbols.abandon;
243
+ Toolkit.prototype.close = exports.symbols.close;
244
+ Toolkit.prototype.continue = exports.symbols.continue;
245
+
246
+ return Toolkit;
247
+ };
248
+
249
+
250
+ internals.Auth = class {
251
+
252
+ constructor(error, data) {
253
+
254
+ this.isAuth = true;
255
+ this.error = error;
256
+ this.data = data;
257
+ }
258
+ };
@@ -0,0 +1,381 @@
1
+ 'use strict';
2
+
3
+ const Http = require('http');
4
+
5
+ const Ammo = require('@hapi/ammo');
6
+ const Boom = require('@hapi/boom');
7
+ const Bounce = require('@hapi/bounce');
8
+ const Hoek = require('@hapi/hoek');
9
+ const Teamwork = require('@hapi/teamwork');
10
+
11
+ const Config = require('./config');
12
+
13
+
14
+ const internals = {};
15
+
16
+
17
+ exports.send = async function (request) {
18
+
19
+ const response = request.response;
20
+
21
+ try {
22
+ if (response.isBoom) {
23
+ await internals.fail(request, response);
24
+ return;
25
+ }
26
+
27
+ await internals.marshal(response);
28
+ await internals.transmit(response);
29
+ }
30
+ catch (err) {
31
+ Bounce.rethrow(err, 'system');
32
+ request._setResponse(err);
33
+ return internals.fail(request, err);
34
+ }
35
+ };
36
+
37
+
38
+ internals.marshal = async function (response) {
39
+
40
+ for (const func of response.request._route._marshalCycle) {
41
+ await func(response);
42
+ }
43
+ };
44
+
45
+
46
+ internals.fail = async function (request, boom) {
47
+
48
+ const response = internals.error(request, boom);
49
+ request.response = response; // Not using request._setResponse() to avoid double log
50
+
51
+ try {
52
+ await internals.marshal(response);
53
+ }
54
+ catch (err) {
55
+ Bounce.rethrow(err, 'system');
56
+
57
+ // Failed to marshal an error - replace with minimal representation of original error
58
+
59
+ const minimal = {
60
+ statusCode: response.statusCode,
61
+ error: Http.STATUS_CODES[response.statusCode],
62
+ message: boom.message
63
+ };
64
+
65
+ response._payload = new request._core.Response.Payload(JSON.stringify(minimal), {});
66
+ }
67
+
68
+ return internals.transmit(response);
69
+ };
70
+
71
+
72
+ internals.error = function (request, boom) {
73
+
74
+ const error = boom.output;
75
+ const response = new request._core.Response(error.payload, request, { error: boom });
76
+ response.code(error.statusCode);
77
+ response.headers = Hoek.clone(error.headers); // Prevent source from being modified
78
+ return response;
79
+ };
80
+
81
+
82
+ internals.transmit = function (response) {
83
+
84
+ const request = response.request;
85
+ const length = internals.length(response);
86
+
87
+ // Pipes
88
+
89
+ const encoding = request._core.compression.encoding(response, length);
90
+ const ranger = encoding ? null : internals.range(response, length);
91
+ const compressor = internals.encoding(response, encoding);
92
+
93
+ // Connection: close
94
+
95
+ const isInjection = request.isInjected;
96
+ if (!(isInjection || request._core.started) ||
97
+ request._isPayloadPending && !request.raw.req._readableState.ended) {
98
+
99
+ response._header('connection', 'close');
100
+ }
101
+
102
+ // Write headers
103
+
104
+ internals.writeHead(response);
105
+
106
+ // Injection
107
+
108
+ if (isInjection) {
109
+ request.raw.res[Config.symbol] = { request };
110
+
111
+ if (response.variety === 'plain') {
112
+ request.raw.res[Config.symbol].result = response._isPayloadSupported() ? response.source : null;
113
+ }
114
+ }
115
+
116
+ // Finalize response stream
117
+
118
+ const stream = internals.chain([response._payload, response._tap(), compressor, ranger]);
119
+ return internals.pipe(request, stream);
120
+ };
121
+
122
+
123
+ internals.length = function (response) {
124
+
125
+ const request = response.request;
126
+
127
+ const header = response.headers['content-length'];
128
+ if (header === undefined) {
129
+ return null;
130
+ }
131
+
132
+ let length = header;
133
+ if (typeof length === 'string') {
134
+ length = parseInt(header, 10);
135
+ if (!isFinite(length)) {
136
+ delete response.headers['content-length'];
137
+ return null;
138
+ }
139
+ }
140
+
141
+ // Empty response
142
+
143
+ if (length === 0 &&
144
+ !response._statusCode &&
145
+ response.statusCode === 200 &&
146
+ request.route.settings.response.emptyStatusCode !== 200) {
147
+
148
+ response.code(204);
149
+ delete response.headers['content-length'];
150
+ }
151
+
152
+ return length;
153
+ };
154
+
155
+
156
+ internals.range = function (response, length) {
157
+
158
+ const request = response.request;
159
+
160
+ if (!length ||
161
+ !request.route.settings.response.ranges ||
162
+ request.method !== 'get' ||
163
+ response.statusCode !== 200) {
164
+
165
+ return null;
166
+ }
167
+
168
+ response._header('accept-ranges', 'bytes');
169
+
170
+ if (!request.headers.range) {
171
+ return null;
172
+ }
173
+
174
+ // Check If-Range
175
+
176
+ if (request.headers['if-range'] &&
177
+ request.headers['if-range'] !== response.headers.etag) { // Ignoring last-modified date (weak)
178
+
179
+ return null;
180
+ }
181
+
182
+ // Parse header
183
+
184
+ const ranges = Ammo.header(request.headers.range, length);
185
+ if (!ranges) {
186
+ const error = Boom.rangeNotSatisfiable();
187
+ error.output.headers['content-range'] = 'bytes */' + length;
188
+ throw error;
189
+ }
190
+
191
+ // Prepare transform
192
+
193
+ if (ranges.length !== 1) { // Ignore requests for multiple ranges
194
+ return null;
195
+ }
196
+
197
+ const range = ranges[0];
198
+ response.code(206);
199
+ response.bytes(range.to - range.from + 1);
200
+ response._header('content-range', 'bytes ' + range.from + '-' + range.to + '/' + length);
201
+
202
+ return new Ammo.Clip(range);
203
+ };
204
+
205
+
206
+ internals.encoding = function (response, encoding) {
207
+
208
+ const request = response.request;
209
+
210
+ const header = response.headers['content-encoding'] || encoding;
211
+ if (header &&
212
+ response.headers.etag &&
213
+ response.settings.varyEtag) {
214
+
215
+ response.headers.etag = response.headers.etag.slice(0, -1) + '-' + header + '"';
216
+ }
217
+
218
+ if (!encoding ||
219
+ response.statusCode === 206 ||
220
+ !response._isPayloadSupported()) {
221
+
222
+ return null;
223
+ }
224
+
225
+ delete response.headers['content-length'];
226
+ response._header('content-encoding', encoding);
227
+ const compressor = request._core.compression.encoder(request, encoding);
228
+ if (response.variety === 'stream' &&
229
+ typeof response._payload.setCompressor === 'function') {
230
+
231
+ response._payload.setCompressor(compressor);
232
+ }
233
+
234
+ return compressor;
235
+ };
236
+
237
+
238
+ internals.pipe = function (request, stream) {
239
+
240
+ const team = new Teamwork.Team();
241
+
242
+ // Write payload
243
+
244
+ const env = { stream, request, team };
245
+
246
+ if (request._closed) {
247
+
248
+ // The request has already been aborted - no need to wait or attempt to write.
249
+
250
+ internals.end(env, 'aborted');
251
+ return team.work;
252
+ }
253
+
254
+ const aborted = internals.end.bind(null, env, 'aborted');
255
+ const close = internals.end.bind(null, env, 'close');
256
+ const end = internals.end.bind(null, env, null);
257
+
258
+ request.raw.req.on('aborted', aborted);
259
+
260
+ request.raw.res.on('close', close);
261
+ request.raw.res.on('error', end);
262
+ request.raw.res.on('finish', end);
263
+
264
+ if (stream.writeToStream) {
265
+ stream.writeToStream(request.raw.res);
266
+ }
267
+ else {
268
+ stream.on('error', end);
269
+ stream.pipe(request.raw.res);
270
+ }
271
+
272
+ return team.work;
273
+ };
274
+
275
+
276
+ internals.end = function (env, event, err) {
277
+
278
+ const { request, stream, team } = env;
279
+
280
+ if (!team) { // Used instead of cleaning up emitter listeners
281
+ return;
282
+ }
283
+
284
+ env.team = null;
285
+
286
+ if (request.raw.res.finished) {
287
+ if (!event) {
288
+ request.info.responded = Date.now();
289
+ }
290
+
291
+ team.attend();
292
+ return;
293
+ }
294
+
295
+ if (err) {
296
+ request.raw.res.destroy();
297
+ request._core.Response.drain(stream);
298
+ }
299
+
300
+ // Update reported response to reflect the error condition
301
+
302
+ const origResponse = request.response;
303
+ const error = err ? Boom.boomify(err) :
304
+ new Boom.Boom(`Request ${event}`, { statusCode: request.route.settings.response.disconnectStatusCode, data: origResponse });
305
+
306
+ request._setResponse(error);
307
+
308
+ // Make inject throw a disconnect error
309
+
310
+ if (request.raw.res[Config.symbol]) {
311
+ request.raw.res[Config.symbol].error = event ? error :
312
+ new Boom.Boom(`Response error`, { statusCode: request.route.settings.response.disconnectStatusCode, data: origResponse });
313
+ }
314
+
315
+ if (event) {
316
+ request._log(['response', 'error', event]);
317
+ }
318
+ else {
319
+ request._log(['response', 'error'], err);
320
+ }
321
+
322
+ request.raw.res.end(); // Triggers injection promise resolve
323
+ team.attend();
324
+ };
325
+
326
+
327
+ internals.writeHead = function (response) {
328
+
329
+ const res = response.request.raw.res;
330
+ const headers = Object.keys(response.headers);
331
+ let i = 0;
332
+
333
+ try {
334
+ for (; i < headers.length; ++i) {
335
+ const header = headers[i];
336
+ const value = response.headers[header];
337
+ if (value !== undefined) {
338
+ res.setHeader(header, value);
339
+ }
340
+ }
341
+ }
342
+ catch (err) {
343
+ for (--i; i >= 0; --i) {
344
+ res.removeHeader(headers[i]); // Undo headers
345
+ }
346
+
347
+ throw Boom.boomify(err);
348
+ }
349
+
350
+ if (response.settings.message) {
351
+ res.statusMessage = response.settings.message;
352
+ }
353
+
354
+ try {
355
+ res.writeHead(response.statusCode);
356
+ }
357
+ catch (err) {
358
+ throw Boom.boomify(err);
359
+ }
360
+ };
361
+
362
+
363
+ internals.chain = function (sources) {
364
+
365
+ let from = sources[0];
366
+ for (let i = 1; i < sources.length; ++i) {
367
+ const to = sources[i];
368
+ if (to) {
369
+ from.on('error', internals.errorPipe.bind(from, to));
370
+ from = from.pipe(to);
371
+ }
372
+ }
373
+
374
+ return from;
375
+ };
376
+
377
+
378
+ internals.errorPipe = function (to, err) {
379
+
380
+ to.emit('error', err);
381
+ };