Search code examples
javascriptnode.jsmongoosemongoose-schema

Mongoose changes password every time I save with pre-save hook


I'm using a pre-save hook with bcrypt to encrypt passwords on the system. It works fine when creating or changing a password. The problem is that it seems to re-encrypt the password every time I change and save a different field, for example e-mail.

Probably easier to explain with code. Here's the model:

const UserSchema = new Schema({
    email: {
        type: String,
        required: true,
        lowercase: true,
        unique: true,
        trim: true
    },
    password: {
        type: String,
        required: true
    }
})

And the hook:

UserSchema.pre('save', function(next){
    const user = this;
    console.log(user);
    bcrypt.genSalt(10, function(err, salt){
        if (err){ return next(err) }

        bcrypt.hash(user.password, salt, null, function(err, hash){
            if(err){return next(err)}

            user.password = hash;
            next();
        })
    })
});

And here's my code to update the e-mail address:

module.exports = function(req, res){
    User.findOne({ _id: req.body.user}, function(err, doc){
        if(err){
            console.log(err);
            return;
        }

        doc.email = req.body.data;
        doc.save(function(err, returnData){
            if (err){
                console.log(err);
                return;
            }
            res.send(returnData);
        })

    })
}

So when I call doc.save in the final example, it updates the e-mail address as intended but it also re-encrypts the password, meaning if the user then logs out, they can't log back in again.

Can anyone help with how to get around this?


Solution

  • Try this:

    UserSchema.pre('save', function(next){
        if (!this.isModified('password')) return next();
    
        const user = this;
        
        bcrypt.genSalt(10, function(err, salt){
            if (err){ return next(err) }
    
            bcrypt.hash(user.password, salt, null, function(err, hash){
                if(err){return next(err)}
    
                user.password = hash;
                next();
            })
       })
    });