@@ -6,13 +6,13 @@ const { Buffer } = require('buffer');
66const Boom = require ( '@hapi/boom' ) ;
77const camelCase = require ( 'camelcase' ) ;
88const capitalize = require ( 'capitalize' ) ;
9- const co = require ( 'co' ) ;
109const fastSafeStringify = require ( 'fast-safe-stringify' ) ;
1110const humanize = require ( 'humanize-string' ) ;
1211const statuses = require ( 'statuses' ) ;
1312const toIdentifier = require ( 'toidentifier' ) ;
1413const { RedisError } = require ( 'redis-errors' ) ;
1514const { convert } = require ( 'html-to-text' ) ;
15+ const MongooseError = require ( 'mongoose/lib/error' ) ;
1616
1717// lodash
1818const _isError = require ( 'lodash.iserror' ) ;
@@ -90,7 +90,6 @@ const passportLocalMongooseTooManyRequests = new Set([
9090//
9191
9292function errorHandler (
93- cookiesKey = false ,
9493 _logger = console ,
9594 useCtxLogger = true , // useful if you have ctx.logger (e.g. you're using Cabin's middleware)
9695 stringify = fastSafeStringify // you could alternatively use JSON.stringify
@@ -137,13 +136,27 @@ function errorHandler(
137136 // redis errors (e.g. ioredis' MaxRetriesPerRequestError)
138137 err . status = 408 ;
139138 err . message = translate ( Boom . clientTimeout ( ) . output . payload ) ;
140- } else {
139+ } else if ( passportLocalMongooseErrorNames . has ( err . name ) ) {
140+ // passport-local-mongoose support
141+ if ( ! err . no_translate ) err . message = translate ( err . message ) ;
142+ // this ensures the error shows up client-side
143+ err . status = 400 ;
144+ // 429 = too many requests
145+ if ( passportLocalMongooseTooManyRequests . has ( err . name ) ) err . status = 429 ;
146+ } else if ( err . name === 'ValidationError' ) {
141147 // parse mongoose validation errors
142148 err = parseValidationError ( this , err , translate ) ;
149+ } else if (
150+ err instanceof MongooseError &&
151+ ! ( err instanceof MongooseError . ValidationError ) &&
152+ ! ( err instanceof MongooseError . ValidatorError ) &&
153+ ! ( err instanceof MongooseError . VersionError )
154+ ) {
155+ // parse mongoose (and mongodb connection errors)
156+ err . status = 408 ;
157+ err . message = translate ( Boom . clientTimeout ( ) . output . payload ) ;
143158 }
144159
145- // TODO: mongodb errors that are not Mongoose ValidationError
146-
147160 // check if we have a boom error that specified
148161 // a status code already for us (and then use it)
149162 if ( _isObject ( err . output ) && _isNumber ( err . output . statusCode ) ) {
@@ -163,9 +176,6 @@ function errorHandler(
163176 // check if there is a view rendering engine binding `this.render`
164177 const hasRender = _isFunction ( this . render ) ;
165178
166- // check if we're about to go into a possible endless redirect loop
167- const noReferrer = this . get ( 'Referrer' ) === '' ;
168-
169179 // populate the status and body with `boom` error message payload
170180 // (e.g. you can do `ctx.throw(404)` and it will output a beautiful err obj)
171181 err . status = err . status || 500 ;
@@ -209,11 +219,7 @@ function errorHandler(
209219 } else {
210220 this . body = _404 ;
211221 }
212- } else if ( noReferrer ) {
213- // this prevents a redirect loop by detecting an empty Referrer
214- // ...otherwise it would reach the next conditional block which
215- // would endlessly rediret the user with `this.redirect('back')`
216-
222+ } else {
217223 // flash an error message
218224 if ( hasFlash ) this . flash ( 'error' , err . message ) ;
219225
@@ -228,49 +234,6 @@ function errorHandler(
228234 } else {
229235 this . body = _500 ;
230236 }
231- } else {
232- // flash an error message
233- if ( hasFlash ) this . flash ( 'error' , err . message ) ;
234-
235- // TODO: until the issue is resolved, we need to add this here
236- // <https://github.com/koajs/generic-session/pull/95#issuecomment-246308544>
237- if (
238- this . sessionStore &&
239- this . sessionId &&
240- this . session &&
241- cookiesKey
242- ) {
243- try {
244- await co
245- . wrap ( this . sessionStore . set )
246- . call ( this . sessionStore , this . sessionId , this . session ) ;
247- this . cookies . set ( cookiesKey , this . sessionId , this . session . cookie ) ;
248- } catch ( err ) {
249- logger . error ( err ) ;
250- if ( err . code === 'ERR_HTTP_HEADERS_SENT' ) return ;
251- }
252- }
253-
254- /*
255- // TODO: we need to add support for `koa-session-store` here
256- // <https://github.com/koajs/generic-session/pull/95#issuecomment-246308544>
257- //
258- // these comments may no longer be valid and need reconsidered:
259- //
260- // if we're using `koa-session-store` we need to add
261- // `this._session = new Session()`, and then run this:
262- await co.wrap(this._session._store.save).call(
263- this._session._store,
264- this._session._sid,
265- stringify(this.session)
266- );
267- this.cookies.set(this._session._name, stringify({
268- _sid: this._session._sid
269- }), this._session._cookieOpts);
270- */
271-
272- // redirect the user to the page they were just on
273- this . redirect ( 'back' ) ;
274237 }
275238
276239 break ;
@@ -309,20 +272,8 @@ function makeAPIFriendly(ctx, message) {
309272 : message ;
310273}
311274
275+ // inspired by https://github.com/syntagma/mongoose-error-helper
312276function parseValidationError ( ctx , err , translate ) {
313- // passport-local-mongoose support
314- if ( passportLocalMongooseErrorNames . has ( err . name ) ) {
315- if ( ! err . no_translate ) err . message = translate ( err . message ) ;
316- // this ensures the error shows up client-side
317- err . status = 400 ;
318- // 429 = too many requests
319- if ( passportLocalMongooseTooManyRequests . has ( err . name ) ) err . status = 429 ;
320- return err ;
321- }
322-
323- // inspired by https://github.com/syntagma/mongoose-error-helper
324- if ( err . name !== 'ValidationError' ) return err ;
325-
326277 // transform the error messages to be humanized as adapted from:
327278 // https://github.com/niftylettuce/mongoose-validation-error-transform
328279 err . errors = _map ( err . errors , ( error ) => {
0 commit comments