nodester 0.0.1
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.
- package/LICENSE +21 -0
- package/Readme.md +125 -0
- package/docs/App.md +13 -0
- package/docs/Queries.md +61 -0
- package/docs/Readme.md +2 -0
- package/docs/Routing.md +34 -0
- package/examples/goal/index.js +23 -0
- package/examples/rest/index.js +25 -0
- package/examples/rest/node_modules/.package-lock.json +40 -0
- package/examples/rest/package-lock.json +72 -0
- package/examples/rest/package.json +14 -0
- package/lib/application/MiddlewareStack.js +125 -0
- package/lib/application/http/request.js +462 -0
- package/lib/application/http/response.js +1107 -0
- package/lib/application/http/utils.js +254 -0
- package/lib/application/index.js +292 -0
- package/lib/constants/ConstantsEnum.js +13 -0
- package/lib/constants/ResponseFormats.js +7 -0
- package/lib/controllers/Controller.js +474 -0
- package/lib/controllers/JWTController.js +240 -0
- package/lib/controllers/ServiceController.js +109 -0
- package/lib/controllers/WebController.js +75 -0
- package/lib/facades/Facade.js +388 -0
- package/lib/facades/FacadeParams.js +11 -0
- package/lib/facades/ServiceFacade.js +17 -0
- package/lib/facades/jwt.facade.js +273 -0
- package/lib/factories/errors/CustomError.js +22 -0
- package/lib/factories/errors/index.js +9 -0
- package/lib/factories/responses/api.js +90 -0
- package/lib/factories/responses/html.js +55 -0
- package/lib/logger/console.js +24 -0
- package/lib/models/DisabledRefreshToken.js +68 -0
- package/lib/models/Extractor.js +320 -0
- package/lib/models/define.js +62 -0
- package/lib/models/mixins.js +369 -0
- package/lib/policies/Role.js +77 -0
- package/lib/policies/RoleExtracting.js +97 -0
- package/lib/preprocessors/BodyPreprocessor.js +61 -0
- package/lib/preprocessors/IncludesPreprocessor.js +55 -0
- package/lib/preprocessors/QueryPreprocessor.js +64 -0
- package/lib/routers/Default/index.js +143 -0
- package/lib/routers/Default/layer.js +50 -0
- package/lib/routers/Main/index.js +10 -0
- package/lib/routers/Roles/index.js +81 -0
- package/lib/services/includes.service.js +79 -0
- package/lib/services/jwt.service.js +147 -0
- package/lib/tools/sql.tool.js +82 -0
- package/lib/utils/dates.util.js +23 -0
- package/lib/utils/forms.util.js +22 -0
- package/lib/utils/json.util.js +49 -0
- package/lib/utils/mappers/Routes/index.js +100 -0
- package/lib/utils/mappers/Routes/utils.js +20 -0
- package/lib/utils/modelAssociations.util.js +44 -0
- package/lib/utils/objects.util.js +69 -0
- package/lib/utils/params.util.js +19 -0
- package/lib/utils/path.util.js +26 -0
- package/lib/utils/queries.util.js +240 -0
- package/lib/utils/sanitizations.util.js +111 -0
- package/lib/utils/sql.util.js +78 -0
- package/lib/utils/strings.util.js +43 -0
- package/lib/utils/types.util.js +26 -0
- package/package.json +63 -0
- package/tests/index.test.js +35 -0
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* /nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const accepts = require('accepts');
|
|
8
|
+
const isIP = require('net').isIP;
|
|
9
|
+
const typeis = require('type-is');
|
|
10
|
+
const http = require('http');
|
|
11
|
+
const fresh = require('fresh');
|
|
12
|
+
const parseRange = require('range-parser');
|
|
13
|
+
const parse = require('parseurl');
|
|
14
|
+
const proxyaddr = require('proxy-addr');
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
const req = http.IncomingMessage.prototype;
|
|
18
|
+
|
|
19
|
+
module.exports = req;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Return request header.
|
|
23
|
+
*
|
|
24
|
+
* The `Referrer` header field is special-cased,
|
|
25
|
+
* both `Referrer` and `Referer` are interchangeable.
|
|
26
|
+
*
|
|
27
|
+
* Examples:
|
|
28
|
+
*
|
|
29
|
+
* req.get('Content-Type');
|
|
30
|
+
* // => "text/plain"
|
|
31
|
+
*
|
|
32
|
+
* req.get('content-type');
|
|
33
|
+
* // => "text/plain"
|
|
34
|
+
*
|
|
35
|
+
* req.get('Something');
|
|
36
|
+
* // => undefined
|
|
37
|
+
*
|
|
38
|
+
* Aliased as `req.header()`.
|
|
39
|
+
*
|
|
40
|
+
* @param {String} name
|
|
41
|
+
* @return {String}
|
|
42
|
+
* @public
|
|
43
|
+
*/
|
|
44
|
+
req.get =
|
|
45
|
+
req.header = function header(name) {
|
|
46
|
+
if (!name) {
|
|
47
|
+
throw new TypeError('name argument is required to req.get');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (typeof name !== 'string') {
|
|
51
|
+
throw new TypeError('name must be a string to req.get');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const lowerCased = name.toLowerCase();
|
|
55
|
+
|
|
56
|
+
switch (lowerCased) {
|
|
57
|
+
case 'referer':
|
|
58
|
+
case 'referrer':
|
|
59
|
+
return this.headers.referrer || this.headers.referer;
|
|
60
|
+
default:
|
|
61
|
+
return this.headers[lowerCased];
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* To do: update docs.
|
|
68
|
+
*
|
|
69
|
+
* Check if the given `type(s)` is acceptable, returning
|
|
70
|
+
* the best match when true, otherwise `undefined`, in which
|
|
71
|
+
* case you should respond with 406 "Not Acceptable".
|
|
72
|
+
*
|
|
73
|
+
* The `type` value may be a single MIME type string
|
|
74
|
+
* such as "application/json", an extension name
|
|
75
|
+
* such as "json", a comma-delimited list such as "json, html, text/plain",
|
|
76
|
+
* an argument list such as `"json", "html", "text/plain"`,
|
|
77
|
+
* or an array `["json", "html", "text/plain"]`. When a list
|
|
78
|
+
* or array is given, the _best_ match, if any is returned.
|
|
79
|
+
*
|
|
80
|
+
* Examples:
|
|
81
|
+
*
|
|
82
|
+
* // Accept: text/html
|
|
83
|
+
* req.accepts('html');
|
|
84
|
+
* // => "html"
|
|
85
|
+
*
|
|
86
|
+
* // Accept: text/*, application/json
|
|
87
|
+
* req.accepts('html');
|
|
88
|
+
* // => "html"
|
|
89
|
+
* req.accepts('text/html');
|
|
90
|
+
* // => "text/html"
|
|
91
|
+
* req.accepts('json, text');
|
|
92
|
+
* // => "json"
|
|
93
|
+
* req.accepts('application/json');
|
|
94
|
+
* // => "application/json"
|
|
95
|
+
*
|
|
96
|
+
* // Accept: text/*, application/json
|
|
97
|
+
* req.accepts('image/png');
|
|
98
|
+
* req.accepts('png');
|
|
99
|
+
* // => undefined
|
|
100
|
+
*
|
|
101
|
+
* // Accept: text/*;q=.5, application/json
|
|
102
|
+
* req.accepts(['html', 'json']);
|
|
103
|
+
* req.accepts('html', 'json');
|
|
104
|
+
* req.accepts('html, json');
|
|
105
|
+
* // => "json"
|
|
106
|
+
*
|
|
107
|
+
* @param {String|Array} type(s)
|
|
108
|
+
* @return {String|Array|Boolean}
|
|
109
|
+
* @public
|
|
110
|
+
*/
|
|
111
|
+
req.accepts = function() {
|
|
112
|
+
const accept = accepts(this);
|
|
113
|
+
return accept.types.apply(accept, arguments);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Check if the given `encoding`s are accepted.
|
|
119
|
+
*
|
|
120
|
+
* @param {String} ...encoding
|
|
121
|
+
* @return {String|Array}
|
|
122
|
+
* @public
|
|
123
|
+
*/
|
|
124
|
+
req.acceptsEncodings = function() {
|
|
125
|
+
const accept = accepts(this);
|
|
126
|
+
return accept.encodings.apply(accept, arguments);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Check if the given `charset`s are acceptable,
|
|
132
|
+
* otherwise you should respond with 406 "Not Acceptable".
|
|
133
|
+
*
|
|
134
|
+
* @param {String} ...charset
|
|
135
|
+
* @return {String|Array}
|
|
136
|
+
* @public
|
|
137
|
+
*/
|
|
138
|
+
req.acceptsCharsets = function() {
|
|
139
|
+
const accept = accepts(this);
|
|
140
|
+
return accept.charsets.apply(accept, arguments);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Check if the given `lang`s are acceptable,
|
|
146
|
+
* otherwise you should respond with 406 "Not Acceptable".
|
|
147
|
+
*
|
|
148
|
+
* @param {String} ...lang
|
|
149
|
+
* @return {String|Array}
|
|
150
|
+
* @public
|
|
151
|
+
*/
|
|
152
|
+
req.acceptsLanguages = function() {
|
|
153
|
+
const accept = accepts(this);
|
|
154
|
+
return accept.languages.apply(accept, arguments);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Parse Range header field, capping to the given `size`.
|
|
160
|
+
*
|
|
161
|
+
* Unspecified ranges such as "0-" require knowledge of your resource length. In
|
|
162
|
+
* the case of a byte range this is of course the total number of bytes. If the
|
|
163
|
+
* Range header field is not given `undefined` is returned, `-1` when unsatisfiable,
|
|
164
|
+
* and `-2` when syntactically invalid.
|
|
165
|
+
*
|
|
166
|
+
* When ranges are returned, the array has a "type" property which is the type of
|
|
167
|
+
* range that is required (most commonly, "bytes"). Each array element is an object
|
|
168
|
+
* with a "start" and "end" property for the portion of the range.
|
|
169
|
+
*
|
|
170
|
+
* The "combine" option can be set to `true` and overlapping & adjacent ranges
|
|
171
|
+
* will be combined into a single range.
|
|
172
|
+
*
|
|
173
|
+
* NOTE: remember that ranges are inclusive, so for example "Range: users=0-3"
|
|
174
|
+
* should respond with 4 users when available, not 3.
|
|
175
|
+
*
|
|
176
|
+
* @param {number} size
|
|
177
|
+
* @param {object} [options]
|
|
178
|
+
* @param {boolean} [options.combine=false]
|
|
179
|
+
* @return {number|array}
|
|
180
|
+
* @public
|
|
181
|
+
*/
|
|
182
|
+
req.range = function range(size, options) {
|
|
183
|
+
const range = this.get('Range');
|
|
184
|
+
if (!range)
|
|
185
|
+
return;
|
|
186
|
+
|
|
187
|
+
return parseRange(size, range, options);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Check if the incoming request contains the "Content-Type"
|
|
193
|
+
* header field, and it contains the given mime `type`.
|
|
194
|
+
*
|
|
195
|
+
* Examples:
|
|
196
|
+
*
|
|
197
|
+
* // With Content-Type: text/html; charset=utf-8
|
|
198
|
+
* req.is('html');
|
|
199
|
+
* req.is('text/html');
|
|
200
|
+
* req.is('text/*');
|
|
201
|
+
* // => true
|
|
202
|
+
*
|
|
203
|
+
* // When Content-Type is application/json
|
|
204
|
+
* req.is('json');
|
|
205
|
+
* req.is('application/json');
|
|
206
|
+
* req.is('application/*');
|
|
207
|
+
* // => true
|
|
208
|
+
*
|
|
209
|
+
* req.is('html');
|
|
210
|
+
* // => false
|
|
211
|
+
*
|
|
212
|
+
* @param {String|Array} types...
|
|
213
|
+
* @return {String|false|null}
|
|
214
|
+
* @public
|
|
215
|
+
*/
|
|
216
|
+
req.is = function is(types) {
|
|
217
|
+
let arr = types;
|
|
218
|
+
|
|
219
|
+
// support flattened arguments
|
|
220
|
+
if (!Array.isArray(types)) {
|
|
221
|
+
arr = new Array(arguments.length);
|
|
222
|
+
for (let i = 0; i < arr.length; i++) {
|
|
223
|
+
arr[i] = arguments[i];
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return typeis(this, arr);
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Return the protocol string "http" or "https"
|
|
233
|
+
* when requested with TLS. When the "trust proxy"
|
|
234
|
+
* setting trusts the socket address, the
|
|
235
|
+
* "X-Forwarded-Proto" header field will be trusted
|
|
236
|
+
* and used if present.
|
|
237
|
+
*
|
|
238
|
+
* If you're running behind a reverse proxy that
|
|
239
|
+
* supplies https for you this may be enabled.
|
|
240
|
+
*
|
|
241
|
+
* @return {String}
|
|
242
|
+
* @public
|
|
243
|
+
*/
|
|
244
|
+
|
|
245
|
+
defineGetter(req, 'protocol', function protocol() {
|
|
246
|
+
const proto = this.connection.encrypted
|
|
247
|
+
? 'https'
|
|
248
|
+
: 'http';
|
|
249
|
+
const trust = this.app.get('trust proxy fn');
|
|
250
|
+
|
|
251
|
+
if (!trust(this.connection.remoteAddress, 0)) {
|
|
252
|
+
return proto;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Note: X-Forwarded-Proto is normally only ever a
|
|
256
|
+
// single value, but this is to be safe.
|
|
257
|
+
const header = this.get('X-Forwarded-Proto') || proto
|
|
258
|
+
const index = header.indexOf(',')
|
|
259
|
+
|
|
260
|
+
return index !== -1
|
|
261
|
+
? header.substring(0, index).trim()
|
|
262
|
+
: header.trim()
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Short-hand for:
|
|
268
|
+
*
|
|
269
|
+
* req.protocol === 'https'
|
|
270
|
+
*
|
|
271
|
+
* @return {Boolean}
|
|
272
|
+
* @public
|
|
273
|
+
*/
|
|
274
|
+
defineGetter(req, 'secure', function secure() {
|
|
275
|
+
return this.protocol === 'https';
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Return the remote address from the trusted proxy.
|
|
281
|
+
*
|
|
282
|
+
* The is the remote address on the socket unless
|
|
283
|
+
* "trust proxy" is set.
|
|
284
|
+
*
|
|
285
|
+
* @return {String}
|
|
286
|
+
* @public
|
|
287
|
+
*/
|
|
288
|
+
defineGetter(req, 'ip', function ip() {
|
|
289
|
+
const trust = this.app.get('trust proxy fn');
|
|
290
|
+
return proxyaddr(this, trust);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* When "trust proxy" is set, trusted proxy addresses + client.
|
|
296
|
+
*
|
|
297
|
+
* For example if the value were "client, proxy1, proxy2"
|
|
298
|
+
* you would receive the array `["client", "proxy1", "proxy2"]`
|
|
299
|
+
* where "proxy2" is the furthest down-stream and "proxy1" and
|
|
300
|
+
* "proxy2" were trusted.
|
|
301
|
+
*
|
|
302
|
+
* @return {Array}
|
|
303
|
+
* @public
|
|
304
|
+
*/
|
|
305
|
+
defineGetter(req, 'ips', function ips() {
|
|
306
|
+
const trust = this.app.get('trust proxy fn');
|
|
307
|
+
const addrs = proxyaddr.all(this, trust);
|
|
308
|
+
|
|
309
|
+
// reverse the order (to farthest -> closest)
|
|
310
|
+
// and remove socket address
|
|
311
|
+
addrs.reverse().pop()
|
|
312
|
+
|
|
313
|
+
return addrs
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Return subdomains as an array.
|
|
319
|
+
*
|
|
320
|
+
* Subdomains are the dot-separated parts of the host before the main domain of
|
|
321
|
+
* the app. By default, the domain of the app is assumed to be the last two
|
|
322
|
+
* parts of the host. This can be changed by setting "subdomain offset".
|
|
323
|
+
*
|
|
324
|
+
* For example, if the domain is "tobi.ferrets.example.com":
|
|
325
|
+
* If "subdomain offset" is not set, req.subdomains is `["ferrets", "tobi"]`.
|
|
326
|
+
* If "subdomain offset" is 3, req.subdomains is `["tobi"]`.
|
|
327
|
+
*
|
|
328
|
+
* @return {Array}
|
|
329
|
+
* @public
|
|
330
|
+
*/
|
|
331
|
+
defineGetter(req, 'subdomains', function subdomains() {
|
|
332
|
+
const hostname = this.hostname;
|
|
333
|
+
|
|
334
|
+
if (!hostname) return [];
|
|
335
|
+
|
|
336
|
+
const offset = this.app.get('subdomain offset');
|
|
337
|
+
const subdomains = !isIP(hostname)
|
|
338
|
+
? hostname.split('.').reverse()
|
|
339
|
+
: [hostname];
|
|
340
|
+
|
|
341
|
+
return subdomains.slice(offset);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Short-hand for `url.parse(req.url).pathname`.
|
|
347
|
+
*
|
|
348
|
+
* @return {String}
|
|
349
|
+
* @public
|
|
350
|
+
*/
|
|
351
|
+
defineGetter(req, 'path', function path() {
|
|
352
|
+
return parse(this).pathname;
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Parse the "Host" header field to a hostname.
|
|
358
|
+
*
|
|
359
|
+
* When the "trust proxy" setting trusts the socket
|
|
360
|
+
* address, the "X-Forwarded-Host" header field will
|
|
361
|
+
* be trusted.
|
|
362
|
+
*
|
|
363
|
+
* @return {String}
|
|
364
|
+
* @public
|
|
365
|
+
*/
|
|
366
|
+
defineGetter(req, 'hostname', function hostname() {
|
|
367
|
+
const trust = this.app.get('trust proxy fn');
|
|
368
|
+
let host = this.get('X-Forwarded-Host');
|
|
369
|
+
|
|
370
|
+
if (!host || !trust(this.connection.remoteAddress, 0)) {
|
|
371
|
+
host = this.get('Host');
|
|
372
|
+
}
|
|
373
|
+
else if (host.indexOf(',') !== -1) {
|
|
374
|
+
// Note: X-Forwarded-Host is normally only ever a
|
|
375
|
+
// single value, but this is to be safe.
|
|
376
|
+
host = host.substring(0, host.indexOf(',')).trimRight()
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (!host)
|
|
380
|
+
return;
|
|
381
|
+
|
|
382
|
+
// IPv6 literal support
|
|
383
|
+
const offset = host[0] === '['
|
|
384
|
+
? host.indexOf(']') + 1
|
|
385
|
+
: 0;
|
|
386
|
+
const index = host.indexOf(':', offset);
|
|
387
|
+
|
|
388
|
+
return index !== -1
|
|
389
|
+
? host.substring(0, index)
|
|
390
|
+
: host;
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Check if the request is fresh, aka
|
|
396
|
+
* Last-Modified and/or the ETag
|
|
397
|
+
* still match.
|
|
398
|
+
*
|
|
399
|
+
* @return {Boolean}
|
|
400
|
+
* @public
|
|
401
|
+
*/
|
|
402
|
+
defineGetter(req, 'fresh', function() {
|
|
403
|
+
const method = this.method;
|
|
404
|
+
const res = this.res
|
|
405
|
+
const status = res.statusCode
|
|
406
|
+
|
|
407
|
+
// GET or HEAD for weak freshness validation only
|
|
408
|
+
if ('GET' !== method && 'HEAD' !== method)
|
|
409
|
+
return false;
|
|
410
|
+
|
|
411
|
+
// 2xx or 304 as per rfc2616 14.26
|
|
412
|
+
if ((status >= 200 && status < 300) || 304 === status) {
|
|
413
|
+
return fresh(this.headers, {
|
|
414
|
+
'etag': res.get('ETag'),
|
|
415
|
+
'last-modified': res.get('Last-Modified')
|
|
416
|
+
})
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return false;
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Check if the request is stale, aka
|
|
425
|
+
* "Last-Modified" and / or the "ETag" for the
|
|
426
|
+
* resource has changed.
|
|
427
|
+
*
|
|
428
|
+
* @return {Boolean}
|
|
429
|
+
* @public
|
|
430
|
+
*/
|
|
431
|
+
defineGetter(req, 'stale', function stale() {
|
|
432
|
+
return !this.fresh;
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Check if the request was an _XMLHttpRequest_.
|
|
438
|
+
*
|
|
439
|
+
* @return {Boolean}
|
|
440
|
+
* @public
|
|
441
|
+
*/
|
|
442
|
+
defineGetter(req, 'xhr', function xhr() {
|
|
443
|
+
const val = this.get('X-Requested-With') || '';
|
|
444
|
+
return val.toLowerCase() === 'xmlhttprequest';
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Helper function for creating a getter on an object.
|
|
450
|
+
*
|
|
451
|
+
* @param {Object} obj
|
|
452
|
+
* @param {String} name
|
|
453
|
+
* @param {Function} getter
|
|
454
|
+
* @private
|
|
455
|
+
*/
|
|
456
|
+
function defineGetter(obj, name, getter) {
|
|
457
|
+
Object.defineProperty(obj, name, {
|
|
458
|
+
configurable: true,
|
|
459
|
+
enumerable: true,
|
|
460
|
+
get: getter
|
|
461
|
+
});
|
|
462
|
+
}
|