Tom Oakley
Tom Oakley

Reputation: 6403

node.bcrypt.js not updating the password in object

I'm using bcrypt for Node.js to encrypt a password. I'm also using Mongoose to create a MongoDB database and user model.

However, the plaintext password is not being updated to the password hash when I GET the data (using Postman). Here is my code:

User.js:

const userSchema = new mongoose.Schema({
  "email": { type: String, required: true, unique: true, trim: true },
  "username": { type: String, required: true, unique: true },
  "name": {
    "first": String,
    "last": String
  },
  "password": { type: String, required: true },
  "created_at": { type: Date, default: Date.now },
  "updated_at": { type: String }
})

userSchema.pre("save", function(next) {
  var user = this
  if (!user.isModified('password')) return callback()
  bcrypt.genSalt(10, function(err, salt) {
    if (err) return next(err)
    bcrypt.hash(user.password, salt, function(err, hash) {
      if (err) return next(err)
      user.password = hash
      console.log(user.password)
    })
  })
  const currentDate = new Date
  user.updated_at = currentDate
  next()
})

const User = mongoose.model("users", userSchema)
export default User

Posting the user data:

router.route("/users").post((req, res) => {
  let json = {}
  const newUser = new User({
    username: req.body.username,
    email: req.body.email,
    name: {
      first: req.body.firstName,
      last: req.body.lastName
    },
    password: req.body.password
  })
  newUser.save((err) => {
    if (err) {
      json.error = err.message
    } else {
      json.id = newUser._id
    }
    res.json(json)
  })
})

As I said above, there are no errors when I GET the data the password is still just the simple plaintext, rather than the hash. When I use console.log(user.password) inside the function, it gives me back the hash.

I've just started learning backend stuff (I'm a front-end dev) so would also be grateful for any advice you may have - thanks!

Upvotes: 1

Views: 2185

Answers (1)

Robert Moskal
Robert Moskal

Reputation: 22553

Classic node callback screwup. The next() callback is called before the hash is generated!

The presave function needs to be something like this:

userSchema.pre("save", function(next) {
  var user = this
  if (!user.isModified('password')) return callback()
  bcrypt.genSalt(10, function(err, salt) {
    if (err) return next(err)
    bcrypt.hash(user.password, salt, function(err, hash) {
      if (err) return next(err)
      user.password = hash
        const currentDate = new Date
        user.updated_at = currentDate
        next()
    })
  })

})

Upvotes: 2

Related Questions