1

Duplicate key E11000 is the expected behavior but crashing the server is not. The duplicate key error comes from my unique index on email.

controller method:

   exports.saveOAuthUserProfile = function(req, profile, done) {

  User.findOne({
    provider: profile.provider,
    providerId: profile.providerId
  }, function(err, user) {
    if (err) {
      return done(err);
    } else {
      if (!user) {
        var possibleUsername = profile.username || ((profile.email) ? profile.email.split('@')[0] : '');

        User.findUniqueUsername(possibleUsername, null, function(availableUsername) {
          profile.username = availableUsername;

          user = new User(profile);

          user.save(function(err) {
            if (err) {
              var message = getErrorMessage(err);
console.log(message);
              //req.flash('error', message);
              return res.redirect('/signup');
            }

            return done(err, user);
          });
        });
      } else {
        return done(err, user);
      }
    }
  });
};

getErrorMessage method:

var getErrorMessage = function(err) {

    var message = '';

    // If an internal MongoDB error occurs get the error message
    if (err.code) {
        switch (err.code) {
            // If a unique index error occurs set the message error
            case 11000:
                message = 'Duplicate Key';
                break;
            case 11001:
                message = 'Username already exists';
                break;
            // If a general error occurs set the message error
            default:
                message = 'Something went wrong';
        }
    } else {
        // Grab the first error message from a list of possible errors
        for (var errName in err.errors) {
            if (err.errors[errName].message) message = err.errors[errName].message;
        }
    }

    return message;
};

email in UserSchema:

email: {
        type: String,
        unique: 'That email is already taken',
        match: [/.+\@.+\..+/, 'Please use a valid e-mail address']
},

cli output:

λ node server
Server running at http://localhost:3000/
GET / 200 26.879 ms - 1347
GET /lib/angular-route/angular-route.min.js 200 12.790 ms - 4408
GET /lib/angular-resource/angular-resource.min.js 200 13.863 ms - 3598
GET /modules/example/example.client.module.js 200 14.557 ms - 30
GET /modules/example/controllers/example.client.controller.js 200 12.595 ms - 240
GET /modules/example/config/example.client.routes.js 200 12.024 ms - 547
GET /lib/angular/angular.min.js 200 77.183 ms - 145234
GET /modules/users/users.client.module.js 200 24.306 ms - 28
GET /modules/users/services/authentication.client.service.js 200 25.467 ms - 168
GET /application.js 200 23.834 ms - 536
GET /modules/articles/articles.client.module.js 200 27.471 ms - 31
GET /modules/articles/services/articles.client.service.js 200 28.066 ms - 234
GET /modules/example/views/example.client.view.html 200 1.968 ms - 83
GET /lib/angular/angular.min.js.map 304 10.579 ms - -
GET /lib/angular-route/angular-route.min.js.map 304 17.932 ms - -
GET /lib/angular-resource/angular-resource.min.js.map 304 31.510 ms - -
GET /signin 200 5.881 ms - 606
GET /oauth/google 302 2.573 ms - 0
Duplicate Key
C:\Users\lotus\Desktop\mastering_mean\application\node_modules\mongoose\node_modules\mpromise\lib\promise.js:108
  if (this.ended && !this.hasRejectListeners()) throw reason;
                                                      ^
ReferenceError: res is not defined
    at EventEmitter.<anonymous> (C:\Users\lotus\Desktop\mastering_mean\application\app\controllers\users.server.controller.js:107:22)
    at EventEmitter.<anonymous> (C:\Users\lotus\Desktop\mastering_mean\application\node_modules\mongoose\node_modules\mpromise\lib\promise.js:174:48)
    at EventEmitter.emit (events.js:107:17)
    at Promise.safeEmit (C:\Users\lotus\Desktop\mastering_mean\application\node_modules\mongoose\node_modules\mpromise\lib\promise.js:81:21)
    at Promise.reject (C:\Users\lotus\Desktop\mastering_mean\application\node_modules\mongoose\node_modules\mpromise\lib\promise.js:109:15)
    at Promise.error (C:\Users\lotus\Desktop\mastering_mean\application\node_modules\mongoose\lib\promise.js:94:15)
    at Promise.resolve (C:\Users\lotus\Desktop\mastering_mean\application\node_modules\mongoose\lib\promise.js:112:24)
    at C:\Users\lotus\Desktop\mastering_mean\application\node_modules\mongoose\lib\document.js:1578:39
    at handleError (C:\Users\lotus\Desktop\mastering_mean\application\node_modules\mongoose\node_modules\hooks-fixed\hooks.js:40:22)
    at next_ (C:\Users\lotus\Desktop\mastering_mean\application\node_modules\mongoose\node_modules\hooks-fixed\hooks.js:75:26)
    at EventEmitter.fnWrapper (C:\Users\lotus\Desktop\mastering_mean\application\node_modules\mongoose\node_modules\hooks-fixed\hooks.js:171:15)
    at EventEmitter.<anonymous> (C:\Users\lotus\Desktop\mastering_mean\application\node_modules\mongoose\node_modules\mpromise\lib\promise.js:174:48)
    at EventEmitter.emit (events.js:107:17)
    at Promise.safeEmit (C:\Users\lotus\Desktop\mastering_mean\application\node_modules\mongoose\node_modules\mpromise\lib\promise.js:81:21)
    at Promise.reject (C:\Users\lotus\Desktop\mastering_mean\application\node_modules\mongoose\node_modules\mpromise\lib\promise.js:109:15)
    at C:\Users\lotus\Desktop\mastering_mean\application\node_modules\mongoose\lib\model.js:263:20

As you can see in the cli output my getErrorMessage function is correctly retrieving the error and I can console.log(message) but at this point node server crashes resulting in the error message that res is not defined.

node version: 0.12.4 MongoDB shell version: 3.0.3 express 4.12.4 mongoose 4.0.5 Win 7 Pro x64

Any more information I can provide?

UPDATE: Adding the passport strategy that calls the controller method

   module.exports = function() {
  passport.use(new GoogleStrategy({
    clientID: config.google.clientID,
    clientSecret: config.google.clientSecret,
    callbackURL: config.google.callbackURL,
    passReqToCallback: true
  },
  function(req, accessToken, refreshToken, profile, done) {
    var providerData = profile._json;
    providerData.accessToken = accessToken;
    providerData.refreshToken = refreshToken;

    var providerUserProfile = {
      firstName: profile.name.givenName,
      lastName: profile.name.familyName,
      fullName: profile.displayName,
      email: profile.emails[0].value,
      username: profile.emails[0].value.replace(/@.*$/,""),
      provider: 'google',
      providerId: profile.id,
      providerData: providerData
    };

    users.saveOAuthUserProfile(req, providerUserProfile, done);
  }));
isimmons
  • 2,016
  • 2
  • 20
  • 32

1 Answers1

1

Passport strategy handlers have an option to get passed req (by setting passReqToCallback), but not res. So if you need the response object in the strategy handler, or any functions called from it (like your users.saveOAuthUserProfile), you need to use the fact that Express adds the response object to the request object, which you can access through req.res.

So this:

return res.redirect('/signup');

Needs to be this:

return req.res.redirect('/signup');
robertklep
  • 198,204
  • 35
  • 394
  • 381