0

I am using sequelize for the first time and trying to use hooks, and additionally I am just learning about promises in JS. I have two methods of implementing a function, but I am wondering if one is asynch and the other is not?

// METHOD 1
User.addHook("beforeCreate", (user) => {
  user.password = bcrypt.hashSync(user.password, bcrypt.genSaltSync(8), null);
});

// METHOD 2
User.addHook("beforeCreate", (user, options) => {     
  return bcrypt.hashSync(user.password, bcrypt.genSaltSync(8), null)
    .then(hashedPw => {
      user.password = hashedPw;
    });
});

Also if anyone knows what the 'options' parameter is for that would be helpful, method 2 is essentially taken from the Sequelize docs and it has the 'options' parameter but I cannot see where it is used...

EDIT

Comments made me understand the above methods aren't asynch as they use hashSync, so I made a new implementation, but this still results in the unhashed password being saved to db...

const saltRounds = 8;
User.addHook("beforeCreate", (user) => {
  bcrypt.genSalt(saltRounds, function(err, salt) {
    bcrypt.hash(user.password, salt, null, function(err, hash) {
        user.password = hash;
    });
  });
});
Will Cowan
  • 81
  • 8
  • Due to the signature: `hashSync`, I guess it's synchronous, hence it should **not** work with `.then`, since it should **not** return a `Promise`. If it does work in method 2, that's bad design. Are you sure the signature is actually the same? the third argument is usually a callback, in bCrypt hashing – briosheje Jun 06 '19 at 10:42
  • @briosheje You are right, they have aysnch versions methods too which I am swapping for. – Will Cowan Jun 06 '19 at 10:49

3 Answers3

1

@WillCowan The method 2 will not work as mentioned in the doc of Bcrypt hasSync() does not return promise.

Options are passed as second parameter which is generally used to change default behaviours of method and passing some extra settings as per the sequelize doc.

Are you facing any problem in implementation?

EDIT

I have written and tested following code can you please check:

const saltRounds = 8;
User.addHook('beforeCreate',(user,options)=>{
 var salt = bcrypt.genSaltSync(saltRounds);
 var hash = bcrypt.hashSync(user.password, salt);
 user.password = hash
 })

  User.create({
    username: "shi",
    birthday: new Date(),
    password:"hello123"
  }).then((user) => {
    console.log("user detail \n", user.userInfo);
  })

It is printing shi_Fri Jun 07 2019 14:05:07 GMT+0530 (IST)_$2b$10$os4R7AALhNfYW2namfw0GOGn0hDd0ugEE2hOuoJVzDxL6qNxnG7G2

dharmendra vaishnav
  • 1,851
  • 2
  • 17
  • 23
  • I started using hashSync from a tutorial and realised from one of the comments that this means it won't be asynchronous. I started an implementation with synchronous functions though, however currently the password still saves as the prior unhashed password... ``` – Will Cowan Jun 07 '19 at 07:58
  • yes that works thank you. However, I am trying to make my code asynchronous so I don't think I can use hashSync. – Will Cowan Jun 07 '19 at 08:51
1

The problem in your code is that, hook in sequelize, is called in asynch manner. Thus, your code should be something like this to make it works

const saltRounds = 8;
User.addHook("beforeCreate", (user, options, callback) => {
  bcrypt.genSalt(saltRounds, function(err, salt) {
    bcrypt.hash(user.password, salt, null, function(err, hash) {
        user.password = hash;

        callback(null, user);
    });
  });
});

on unrelated note, it might be a good idea to promisify those functions using something like bluebird or util package from node

kucing_terbang
  • 4,991
  • 2
  • 22
  • 28
  • What does the callback(null, user) at the end do? (I haven't had experience with async functions until now trying to implement this, so not sure why adding that works) – Will Cowan Jun 07 '19 at 09:05
  • Aa.. it's just a completion callback to notify sequelize that your hook has done the process. If you are not adding the third argument ( the callback ). Sequelize guess your hook is synchronous function. But, in this case, it is not. So sequelize saved the state where the password has not been hashed. – kucing_terbang Jun 07 '19 at 12:07
1

If you want to use sequelize hooks and bcrypt to asynchronously hash a password before creation, you need to do:

beforeCreate: async function(user) {
    const salt = await bcrypt.genSalt(10); 
    user.password = await bcrypt.hash(user.password, salt);
}

Answer found at: Using BCrypt with Sequelize Model

Given by: @user1274820

Will Cowan
  • 81
  • 8