@ladjs/web 12.0.0 → 13.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.
Files changed (2) hide show
  1. package/index.js +61 -34
  2. package/package.json +12 -11
package/index.js CHANGED
@@ -12,6 +12,7 @@ const CacheResponses = require('@ladjs/koa-cache-responses');
12
12
  const I18N = require('@ladjs/i18n');
13
13
  const Koa = require('koa');
14
14
  const Meta = require('koa-meta');
15
+ const Passport = require('@ladjs/passport');
15
16
  const RedirectLoop = require('koa-redirect-loop');
16
17
  const Redis = require('@ladjs/redis');
17
18
  const StateHelper = require('@ladjs/state-helper');
@@ -38,6 +39,7 @@ const koaConnect = require('koa-connect');
38
39
  const methodOverride = require('koa-methodoverride');
39
40
  const ms = require('ms');
40
41
  const multimatch = require('multimatch');
42
+ const ratelimit = require('@ladjs/koa-simple-ratelimit');
41
43
  const redisStore = require('koa-redis');
42
44
  const removeTrailingSlashes = require('koa-no-trailing-slash');
43
45
  const requestId = require('express-request-id');
@@ -48,7 +50,6 @@ const session = require('koa-generic-session');
48
50
  const sharedConfig = require('@ladjs/shared-config');
49
51
  const views = require('koa-views');
50
52
  const { boolean } = require('boolean');
51
- const { ratelimit } = require('koa-simple-ratelimit');
52
53
 
53
54
  const defaultSrc = isSANB(process.env.WEB_HOST)
54
55
  ? [
@@ -60,13 +61,17 @@ const defaultSrc = isSANB(process.env.WEB_HOST)
60
61
  `${process.env.WEB_HOST}:*`
61
62
  ]
62
63
  : null;
64
+
63
65
  const reportUri = isSANB(process.env.WEB_URL)
64
66
  ? `${process.env.WEB_URL}/report`
65
67
  : null;
66
68
 
69
+ const INVALID_TOKEN_MESSAGE = 'Invalid CSRF token.';
70
+ const RATE_LIMIT_EXCEEDED = `Rate limit exceeded, retry in %s.`;
71
+
67
72
  class Web {
68
73
  // eslint-disable-next-line complexity
69
- constructor(config, client) {
74
+ constructor(config, Users) {
70
75
  this.config = {
71
76
  ...sharedConfig('WEB'),
72
77
  meta: {},
@@ -165,38 +170,50 @@ class Web {
165
170
  ...config
166
171
  };
167
172
 
168
- const cabin = new Cabin({
169
- logger: this.config.logger,
170
- ...this.config.cabin
171
- });
172
-
173
- // initialize redis
174
- this.client = client
175
- ? client
176
- : new Redis(this.config.redis, cabin, this.config.redisMonitor);
177
-
178
173
  // initialize the app
179
174
  const app = new Koa();
180
175
 
181
- // allow middleware to access redis client
176
+ // only trust proxy if enabled
177
+ app.proxy = boolean(process.env.TRUST_PROXY);
178
+
179
+ // inherit cache variable for cache-pug-templates
180
+ app.cache = boolean(this.config.views.locals.cache);
181
+
182
+ // initialize cabin
183
+ this.logger = _.isPlainObject(this.config.logger)
184
+ ? new Cabin(this.config.logger)
185
+ : this.config.logger instanceof Cabin
186
+ ? this.config.logger
187
+ : new Cabin({
188
+ logger: this.config.logger ? this.config.logger : console
189
+ });
190
+ app.context.logger = this.logger;
191
+
192
+ // initialize redis
193
+ this.client =
194
+ this.config.redis === false
195
+ ? false
196
+ : _.isPlainObject(this.config.redis)
197
+ ? new Redis(this.config.redis, this.logger, this.config.redisMonitor)
198
+ : this.config.redis;
182
199
  app.context.client = this.client;
183
200
 
184
- // listen for error and log events emitted by app
201
+ // expose passport
202
+ this.passport =
203
+ this.config.passport === false
204
+ ? false
205
+ : _.isPlainObject(this.config.passport)
206
+ ? new Passport(this.config.passport, Users)
207
+ : this.config.passport;
208
+ app.context.passport = this.passport;
209
+
210
+ // listen for errors emitted by app
185
211
  app.on('error', (err, ctx) => {
186
- const level = err.status && err.status < 500 ? 'warn' : 'error';
187
- if (ctx.logger) ctx.logger[level](err);
188
- else cabin[level](err);
212
+ ctx.logger[err.status && err.status < 500 ? 'warn' : 'error'](err);
189
213
  });
190
- app.on('log', cabin.log);
191
214
 
192
215
  // override koa's undocumented error handler
193
- app.context.onerror = errorHandler(this.config.cookiesKey, cabin);
194
-
195
- // only trust proxy if enabled
196
- app.proxy = boolean(process.env.TRUST_PROXY);
197
-
198
- // inherit cache variable for cache-pug-templates
199
- app.cache = boolean(this.config.views.locals.cache);
216
+ app.context.onerror = errorHandler(this.config.cookiesKey);
200
217
 
201
218
  // adds request received hrtime and date symbols to request object
202
219
  // (which is used by Cabin internally to add `request.timestamp` to logs
@@ -215,7 +232,7 @@ class Web {
215
232
  app.use(koaConnect(requestId()));
216
233
 
217
234
  // add cabin middleware
218
- app.use(cabin.middleware);
235
+ app.use(this.logger.middleware);
219
236
 
220
237
  // allow before hooks to get setup
221
238
  if (_.isFunction(this.config.hookBeforeSetup))
@@ -238,7 +255,14 @@ class Web {
238
255
 
239
256
  return ratelimit({
240
257
  ...this.config.rateLimit,
241
- db: this.client
258
+ db: this.client,
259
+ logger: this.logger,
260
+ errorMessage(exp) {
261
+ const fn =
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
+ }
242
266
  })(ctx, next);
243
267
  });
244
268
  }
@@ -255,7 +279,7 @@ class Web {
255
279
  // create new @ladjs/i18n instance
256
280
  const i18n = this.config.i18n.config
257
281
  ? this.config.i18n
258
- : new I18N({ ...this.config.i18n, logger: cabin });
282
+ : new I18N({ ...this.config.i18n, logger: this.logger });
259
283
 
260
284
  // setup localization (must come before `i18n.redirect`)
261
285
  app.use(i18n.middleware);
@@ -310,7 +334,7 @@ class Web {
310
334
  // NOTE: this must come after ctx.render is added (via koa-views)
311
335
  //
312
336
  if (this.config.meta) {
313
- const meta = new Meta(this.config.meta, cabin);
337
+ const meta = new Meta(this.config.meta, this.logger);
314
338
  app.use(meta.middleware);
315
339
  }
316
340
 
@@ -355,7 +379,10 @@ class Web {
355
379
  if (this.config.csrf && process.env.NODE_ENV !== 'test') {
356
380
  const csrf = new CSRF({
357
381
  ...this.config.csrf,
358
- invalidTokenMessage: (ctx) => ctx.request.t('Invalid CSRF token')
382
+ invalidTokenMessage: (ctx) =>
383
+ typeof ctx.request.t === 'function'
384
+ ? ctx.request.t(INVALID_TOKEN_MESSAGE)
385
+ : INVALID_TOKEN_MESSAGE
359
386
  });
360
387
  app.use(async (ctx, next) => {
361
388
  // check against ignored/whitelisted redirect middleware paths
@@ -382,15 +409,15 @@ class Web {
382
409
  }
383
410
 
384
411
  // passport
385
- if (this.config.passport) {
386
- app.use(this.config.passport.initialize());
387
- app.use(this.config.passport.session());
412
+ if (this.passport) {
413
+ app.use(this.passport.initialize());
414
+ app.use(this.passport.session());
388
415
  }
389
416
 
390
417
  // store the user's last ip address in the background
391
418
  if (this.config.storeIPAddress) {
392
419
  const storeIPAddress = new StoreIPAddress({
393
- logger: cabin,
420
+ logger: this.logger,
394
421
  ...this.config.storeIPAddress
395
422
  });
396
423
  app.use(storeIPAddress.middleware);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ladjs/web",
3
3
  "description": "Web server for Lad",
4
- "version": "12.0.0",
4
+ "version": "13.0.0",
5
5
  "author": "Nick Baugh <niftylettuce@gmail.com> (http://niftylettuce.com/)",
6
6
  "ava": {
7
7
  "failFast": true,
@@ -26,8 +26,9 @@
26
26
  "@ladjs/koa-better-static": "^2.0.1",
27
27
  "@ladjs/koa-cache-responses": "^0.0.3",
28
28
  "@ladjs/koa-isajax": "^2.0.0",
29
+ "@ladjs/koa-simple-ratelimit": "^3.0.0",
29
30
  "@ladjs/redis": "^1.0.7",
30
- "@ladjs/shared-config": "^6.0.0",
31
+ "@ladjs/shared-config": "^7.0.3",
31
32
  "@ladjs/state-helper": "^1.0.0",
32
33
  "@ladjs/store-ip-address": "^0.0.7",
33
34
  "boolean": "^3.2.0",
@@ -58,7 +59,6 @@
58
59
  "koa-no-trailing-slash": "^2.1.0",
59
60
  "koa-redirect-loop": "^1.0.2",
60
61
  "koa-redis": "^4.0.1",
61
- "koa-simple-ratelimit": "^5.1.1",
62
62
  "koa-views": "^8.0.0",
63
63
  "lodash": "^4.17.21",
64
64
  "ms": "^2.1.3",
@@ -67,22 +67,23 @@
67
67
  "response-time": "^2.3.2"
68
68
  },
69
69
  "devDependencies": {
70
- "@commitlint/cli": "^16.2.4",
71
- "@commitlint/config-conventional": "^16.2.4",
72
- "ava": "^4.2.0",
70
+ "@commitlint/cli": "^17.0.2",
71
+ "@commitlint/config-conventional": "^17.0.2",
72
+ "@ladjs/passport": "^5.0.0",
73
+ "ava": "^4.3.0",
73
74
  "codecov": "^3.8.3",
74
75
  "cross-env": "^7.0.3",
75
- "eslint": "^8.14.0",
76
+ "eslint": "^8.16.0",
76
77
  "eslint-config-xo-lass": "^1.0.6",
77
78
  "fixpack": "^4.0.0",
78
- "husky": "^7.0.4",
79
- "lint-staged": "^12.4.1",
79
+ "husky": "^8.0.1",
80
+ "lint-staged": "^13.0.0",
80
81
  "nyc": "^15.1.0",
81
82
  "pug": "^3.0.2",
82
83
  "remark-cli": "^10.0.1",
83
- "remark-preset-github": "^4.0.1",
84
+ "remark-preset-github": "^4.0.2",
84
85
  "supertest": "^6.2.3",
85
- "xo": "^0.48.0"
86
+ "xo": "^0.49.0"
86
87
  },
87
88
  "engines": {
88
89
  "node": ">=10.10.0"