question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Need to check if password field has been modified in pre findOneAndUpdate

See original GitHub issue

I ran into a problem last night and still haven’t been able to figure out a solution so hopefully someone can offer some advice. I am allowing users to update their username and password, and whenever the password field has been modified I need to hash it before storing it in mongo.

So far I had been using this code to hash the user’s password:

UserSchema.pre('save', function(next) {
    if (this.isModified('password')) // If the pw has been modified, then encrypt it again
    this.password = this.encryptPassword(this.password);

    next();
});

The encryptPassword function is a custom one I added to my User Schema:

// Add custom methods to our User schema
UserSchema.methods = {
    // Hash the password
    encryptPassword: function(plainTextPassword) {
        if (!plainTextPassword) {
            return ''
        } else {
            var salt = bcrypt.genSaltSync(10);
            return bcrypt.hashSync(plainTextPassword, salt);
        }
    }
};

This only works though when the user first signs up and I create a new user instance and then save it. I need the same functionality when updating the user as well.

I was doing research in past issues here and came across this one: pre, post middleware are not executed on findByIdAndUpdate, and came across a comment where another dev was trying to do something very similar to what I am taking about: https://github.com/Automattic/mongoose/issues/964#issuecomment-154332797

@vkarpov15 responded to his question with the following code suggestion:

TodoSchema.pre('findOneAndUpdate', function() {
  this.findOneAndUpdate({}, { password: hashPassword(this.getUpdate().$set.password) });
});

The only problem is, that this will cause us to rehash the password every time you update a user, which is wrong. You should only be hashing the password when the user initially signs up, and whenever they send a request up to change their password. If you run the above code every single time the user is updated, you will just end up rehashing the old hash, so when the user enters in their password next time on the client, it wont match with the hash stored in mongo anymore…

Is there any way I can use something like this.isModified('password') inside of the .pre('findOneAndUpdate', so that I only hash the password when the user has updated it?

At this point I’m open to any and all suggestions thanks.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:7
  • Comments:24

github_iconTop GitHub Comments

34reactions
ezamelczykcommented, Aug 12, 2017

I’m currently using this solution and it works. You don’t need to execute another query.

schema.pre("update", function(next) {
            const password = this.getUpdate().$set.password;
            if (!password) {
                return next();
            }
            try {
                const salt = Bcrypt.genSaltSync();
                const hash = Bcrypt.hashSync(password, salt);
                this.getUpdate().$set.password = hash;
                next();
            } catch (error) {
                return next(error);
            }
        });
3reactions
vkarpov15commented, Jul 12, 2017

@NicolasBlois that works. There’s a potential race condition there but it’ll work for most cases.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Mongoose: findOneAndUpdate pre hook not working
I'm currently using this function to encrypt the password before storing in the database but even though the values are being changed when...
Read more >
Mongoose v6.8.1: Middleware
The save() function triggers validate() hooks, because mongoose has a built-in pre('save') hook that calls validate() . This means that all pre('validate') and ......
Read more >
delete all user references on other schema when ... - You.com
I have a field in my Ticket model that references a User id and an array field ... to check if password field...
Read more >
Password Authentication with Mongoose Part 1 - MongoDB
pre ('save', { var user = this; // only hash the password if it has been modified (or is new) if (!user.isModified('password')) return...
Read more >
Mongoose query findOneAndUpdate() doesn't update ...
Because Mongoose by default creates a new MongoDB ObjectId ( this hidden _id field) every time you pass it a Javascript Object to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found