@ladjs/web 16.0.2 → 17.0.0
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/index.js +36 -68
- package/package.json +6 -7
package/index.js
CHANGED
|
@@ -38,7 +38,6 @@ const koaCash = require('koa-cash');
|
|
|
38
38
|
const koaConnect = require('koa-connect');
|
|
39
39
|
const methodOverride = require('koa-methodoverride');
|
|
40
40
|
const ms = require('ms');
|
|
41
|
-
const multimatch = require('multimatch');
|
|
42
41
|
const ratelimit = require('@ladjs/koa-simple-ratelimit');
|
|
43
42
|
const redisStore = require('koa-redis');
|
|
44
43
|
const removeTrailingSlashes = require('koa-no-trailing-slash');
|
|
@@ -67,13 +66,13 @@ const reportUri = isSANB(process.env.WEB_URL)
|
|
|
67
66
|
: null;
|
|
68
67
|
|
|
69
68
|
const INVALID_TOKEN_MESSAGE = 'Invalid CSRF token.';
|
|
70
|
-
const RATE_LIMIT_EXCEEDED = `Rate limit exceeded, retry in %s.`;
|
|
71
69
|
|
|
72
70
|
class Web {
|
|
73
71
|
// eslint-disable-next-line complexity
|
|
74
72
|
constructor(config, Users) {
|
|
73
|
+
const sharedWebConfig = sharedConfig('WEB');
|
|
75
74
|
this.config = {
|
|
76
|
-
...
|
|
75
|
+
...sharedWebConfig,
|
|
77
76
|
meta: {},
|
|
78
77
|
views: {
|
|
79
78
|
root: path.resolve('./app/views'),
|
|
@@ -82,9 +81,23 @@ class Web {
|
|
|
82
81
|
extension: 'pug'
|
|
83
82
|
}
|
|
84
83
|
},
|
|
85
|
-
csrf: {
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
csrf: {
|
|
85
|
+
...sharedWebConfig.csrf,
|
|
86
|
+
ignoredPathGlobs: ['/report'],
|
|
87
|
+
errorHandler(ctx) {
|
|
88
|
+
return ctx.throw(
|
|
89
|
+
Boom.forbidden(
|
|
90
|
+
typeof ctx.request.t === 'function'
|
|
91
|
+
? ctx.request.t(INVALID_TOKEN_MESSAGE)
|
|
92
|
+
: INVALID_TOKEN_MESSAGE
|
|
93
|
+
)
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
rateLimit: {
|
|
98
|
+
...sharedWebConfig.rateLimit,
|
|
99
|
+
ignoredPathGlobs: ['/report']
|
|
100
|
+
},
|
|
88
101
|
sessionKeys: process.env.SESSION_KEYS
|
|
89
102
|
? process.env.SESSION_KEYS.split(',')
|
|
90
103
|
: ['lad'],
|
|
@@ -242,30 +255,14 @@ class Web {
|
|
|
242
255
|
if (this.config.auth) app.use(auth(this.config.auth));
|
|
243
256
|
|
|
244
257
|
// rate limiting
|
|
245
|
-
if (this.config.rateLimit)
|
|
246
|
-
app.use(
|
|
247
|
-
|
|
248
|
-
if (
|
|
249
|
-
Array.isArray(this.config.rateLimitIgnoredGlobs) &&
|
|
250
|
-
this.config.rateLimitIgnoredGlobs.length > 0
|
|
251
|
-
) {
|
|
252
|
-
const match = multimatch(ctx.path, this.config.rateLimitIgnoredGlobs);
|
|
253
|
-
if (Array.isArray(match) && match.length > 0) return next();
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
return ratelimit({
|
|
258
|
+
if (this.config.rateLimit)
|
|
259
|
+
app.use(
|
|
260
|
+
ratelimit({
|
|
257
261
|
...this.config.rateLimit,
|
|
258
262
|
db: this.client,
|
|
259
|
-
logger: this.logger
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
typeof ctx.request.t === 'function' ? ctx.request.t : util.format;
|
|
263
|
-
// NOTE: ms does not support i18n localization
|
|
264
|
-
return fn(RATE_LIMIT_EXCEEDED, ms(exp, { long: true }));
|
|
265
|
-
}
|
|
266
|
-
})(ctx, next);
|
|
267
|
-
});
|
|
268
|
-
}
|
|
263
|
+
logger: this.logger
|
|
264
|
+
})
|
|
265
|
+
);
|
|
269
266
|
|
|
270
267
|
// remove trailing slashes
|
|
271
268
|
app.use(removeTrailingSlashes());
|
|
@@ -364,9 +361,7 @@ class Web {
|
|
|
364
361
|
ctx.state.ctx.path = ctx.path;
|
|
365
362
|
ctx.state.ctx.pathWithoutLocale = ctx.pathWithoutLocale;
|
|
366
363
|
ctx.state.ctx.query = ctx.query;
|
|
367
|
-
ctx.state.ctx.session = ctx.session;
|
|
368
364
|
ctx.state.ctx.sessionId = ctx.sessionId;
|
|
369
|
-
ctx.state.ctx.translate = ctx.translate;
|
|
370
365
|
ctx.state.ctx.url = ctx.url;
|
|
371
366
|
|
|
372
367
|
return next();
|
|
@@ -374,23 +369,15 @@ class Web {
|
|
|
374
369
|
|
|
375
370
|
// session store
|
|
376
371
|
app.keys = this.config.sessionKeys;
|
|
377
|
-
app.use(
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
} catch (err) {
|
|
387
|
-
// this would indicate that redis is down
|
|
388
|
-
ctx.logger.error(err);
|
|
389
|
-
delete ctx.session;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
return next();
|
|
393
|
-
});
|
|
372
|
+
app.use(
|
|
373
|
+
session({
|
|
374
|
+
store: redisStore({ client: this.client }),
|
|
375
|
+
key: this.config.cookiesKey,
|
|
376
|
+
cookie: this.config.cookies,
|
|
377
|
+
genSid: this.config.genSid,
|
|
378
|
+
...this.config.session
|
|
379
|
+
})
|
|
380
|
+
);
|
|
394
381
|
|
|
395
382
|
// redirect loop (must come after sessions added)
|
|
396
383
|
if (this.config.redirectLoop) {
|
|
@@ -415,34 +402,15 @@ class Web {
|
|
|
415
402
|
if (this.config.methodOverride)
|
|
416
403
|
app.use(methodOverride(...this.config.methodOverride));
|
|
417
404
|
|
|
418
|
-
// TODO: move this into `@ladjs/csrf`
|
|
419
405
|
// csrf (with added localization support)
|
|
420
406
|
if (this.config.csrf && process.env.NODE_ENV !== 'test') {
|
|
421
|
-
const csrf = new CSRF(
|
|
422
|
-
...this.config.csrf,
|
|
423
|
-
invalidTokenMessage: (ctx) =>
|
|
424
|
-
typeof ctx.request.t === 'function'
|
|
425
|
-
? ctx.request.t(INVALID_TOKEN_MESSAGE)
|
|
426
|
-
: INVALID_TOKEN_MESSAGE
|
|
427
|
-
});
|
|
407
|
+
const csrf = new CSRF(this.config.csrf);
|
|
428
408
|
app.use(async (ctx, next) => {
|
|
429
|
-
// check against ignored/whitelisted redirect middleware paths
|
|
430
|
-
if (
|
|
431
|
-
Array.isArray(this.config.csrfIgnoredGlobs) &&
|
|
432
|
-
this.config.csrfIgnoredGlobs.length > 0
|
|
433
|
-
) {
|
|
434
|
-
const match = multimatch(ctx.path, this.config.csrfIgnoredGlobs);
|
|
435
|
-
if (Array.isArray(match) && match.length > 0) return next();
|
|
436
|
-
}
|
|
437
|
-
|
|
438
409
|
try {
|
|
439
410
|
await csrf(ctx, next);
|
|
440
411
|
} catch (err) {
|
|
441
|
-
ctx.logger.error(err);
|
|
442
412
|
let error = err;
|
|
443
|
-
|
|
444
|
-
if (!ctx.session) error = Boom.clientTimeout();
|
|
445
|
-
else if (err.name && err.name === 'ForbiddenError')
|
|
413
|
+
if (err.name && err.name === 'ForbiddenError')
|
|
446
414
|
error = Boom.forbidden(err.message);
|
|
447
415
|
|
|
448
416
|
ctx.throw(error);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ladjs/web",
|
|
3
3
|
"description": "Web server for Lad",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "17.0.0",
|
|
5
5
|
"author": "Nick Baugh <niftylettuce@gmail.com> (http://niftylettuce.com/)",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/ladjs/web/issues",
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
"@ladjs/koa-better-static": "^2.0.1",
|
|
18
18
|
"@ladjs/koa-cache-responses": "^0.0.3",
|
|
19
19
|
"@ladjs/koa-isajax": "^2.0.0",
|
|
20
|
-
"@ladjs/koa-simple-ratelimit": "^
|
|
20
|
+
"@ladjs/koa-simple-ratelimit": "^4.0.1",
|
|
21
21
|
"@ladjs/redis": "^1.0.7",
|
|
22
|
-
"@ladjs/shared-config": "^
|
|
23
|
-
"@ladjs/state-helper": "^2.0.
|
|
22
|
+
"@ladjs/shared-config": "^8.0.0",
|
|
23
|
+
"@ladjs/state-helper": "^2.0.2",
|
|
24
24
|
"@ladjs/store-ip-address": "^0.0.7",
|
|
25
25
|
"boolean": "^3.2.0",
|
|
26
26
|
"cabin": "^9.1.2",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"koa-compress": "^5.1.0",
|
|
40
40
|
"koa-conditional-get": "^3.0.0",
|
|
41
41
|
"koa-connect": "^2.1.0",
|
|
42
|
-
"koa-csrf": "^
|
|
42
|
+
"koa-csrf": "^5.0.0",
|
|
43
43
|
"koa-etag": "^4.0.0",
|
|
44
44
|
"koa-favicon": "^2.1.0",
|
|
45
45
|
"koa-generic-session": "^2.3.0",
|
|
@@ -53,7 +53,6 @@
|
|
|
53
53
|
"koa-views": "^8.0.0",
|
|
54
54
|
"lodash": "^4.17.21",
|
|
55
55
|
"ms": "^2.1.3",
|
|
56
|
-
"multimatch": "5",
|
|
57
56
|
"request-received": "^0.0.3",
|
|
58
57
|
"response-time": "^2.3.2"
|
|
59
58
|
},
|
|
@@ -63,7 +62,7 @@
|
|
|
63
62
|
"@ladjs/passport": "^5.0.2",
|
|
64
63
|
"ava": "^4.3.0",
|
|
65
64
|
"cross-env": "^7.0.3",
|
|
66
|
-
"eslint": "^8.
|
|
65
|
+
"eslint": "^8.19.0",
|
|
67
66
|
"eslint-config-xo-lass": "^2.0.1",
|
|
68
67
|
"fixpack": "^4.0.0",
|
|
69
68
|
"husky": "^8.0.1",
|