I'm using NodeJS, with bcrypt-nodejs () and Bluebird for promises. Came up with this code and been wondering if there is better way to do the same thing. I have module with:
var Promise = require("bluebird"),
bcrypt = Promise.promisifyAll(require('bcrypt-nodejs'));
// ....[some othe code here]
Users.prototype.setPassword = function(user) {
return bcrypt.genSaltAsync(10).then(function(result) {
return bcrypt.hashAsync(user.password, result);
});
};
then from another module I call users.setPassword
as below:
app.post('/api/v1/users/set-password', function(req, res, next) {
users.setPassword(req.body).then(function(result) {
// Store hash in your password DB.
console.log(result[1]);
res.json({
success: true
})
})
.catch(function(err) {
console.log(err);
});
});
It always ends up with "[Error: No callback function was given.]" message as bcrypt.hashAsync
seems to require 4 parameters. Original, non-promisified hash
method requires 3 only though. When I add empty callback to hashAsync
, it works fine:
Users.prototype.setPassword = function(user) {
return bcrypt.genSaltAsync(10).then(function(result) {
return bcrypt.hashAsync(user.password, result,function() {});
});
};
Is there any better way to do this, without providing empty callback as above?
EDIT:
In response to Bergi's ment.. the function will set password eventually, I just didn't get that far when posted the question. Now got this far, please let me know if something is not quite right though:
Users.prototype.setPassword = function(user) {
return bcrypt.genSaltAsync(10).then(function(result) {
return bcrypt.hashAsync(user.password, result, null);
})
.then(function(result) {
// store in database
console.log("stored in database!");
return result;
});
};
I'm using NodeJS, with bcrypt-nodejs (https://github./shaneGirish/bcrypt-nodejs) and Bluebird for promises. Came up with this code and been wondering if there is better way to do the same thing. I have module with:
var Promise = require("bluebird"),
bcrypt = Promise.promisifyAll(require('bcrypt-nodejs'));
// ....[some othe code here]
Users.prototype.setPassword = function(user) {
return bcrypt.genSaltAsync(10).then(function(result) {
return bcrypt.hashAsync(user.password, result);
});
};
then from another module I call users.setPassword
as below:
app.post('/api/v1/users/set-password', function(req, res, next) {
users.setPassword(req.body).then(function(result) {
// Store hash in your password DB.
console.log(result[1]);
res.json({
success: true
})
})
.catch(function(err) {
console.log(err);
});
});
It always ends up with "[Error: No callback function was given.]" message as bcrypt.hashAsync
seems to require 4 parameters. Original, non-promisified hash
method requires 3 only though. When I add empty callback to hashAsync
, it works fine:
Users.prototype.setPassword = function(user) {
return bcrypt.genSaltAsync(10).then(function(result) {
return bcrypt.hashAsync(user.password, result,function() {});
});
};
Is there any better way to do this, without providing empty callback as above?
EDIT:
In response to Bergi's ment.. the function will set password eventually, I just didn't get that far when posted the question. Now got this far, please let me know if something is not quite right though:
Users.prototype.setPassword = function(user) {
return bcrypt.genSaltAsync(10).then(function(result) {
return bcrypt.hashAsync(user.password, result, null);
})
.then(function(result) {
// store in database
console.log("stored in database!");
return result;
});
};
Share
Improve this question
edited Jul 18, 2014 at 10:47
spirytus
asked Jul 18, 2014 at 6:04
spirytusspirytus
10.9k14 gold badges63 silver badges77 bronze badges
1
-
I would use a different method name for sure.
users.setPassword
doesn't seem to set a password, but just putes a hash for a given one. – Bergi Commented Jul 18, 2014 at 8:04
3 Answers
Reset to default 9bcrypt.hashAsync seems to require 4 parameters. Original, non-promisified hash method requires 3 only though.
It's the other way round rather. From the docs:
hash(data, salt, progress, cb)
data
- [REQUIRED] - the data to be encrypted.salt
- [REQUIRED] - the salt to be used to hash the password.progress
- a callback to be called during the hash calculation to signify progresscallback
- [REQUIRED] - a callback to be fired once the data has been encrypted.
The original method took 4 arguments, hashAsync
will take 3 and return a promise.
However, in your code you were only passing two. You don't need to pass an empty function though, that the parameter is not [REQUIRED] means you can pass null
(or any other falsy value) for it. bcrypt will create such an empty function itself. So use
function (data) {
return bcrypt.genSaltAsync(10).then(function(result) {
return bcrypt.hashAsync(data.password, result, null);
});
}
This is my promisified bcrypt from a project I did a while back. Bluebird isn't really necessary for such a small, simple library.
module.exports = {
makeUser: function(username, password){
return new Promise(function(resolve, reject) {
bcrypt.genSalt(10, function(err, salt){
bcrypt.hash(password, salt, null, function(err, hash) {
if (err) {
console.log("hashing the password failed, see user.js " + err);
reject(err);
}
else {
console.log("hash was successful.");
resolve(hash);
}
})
})
})
.then(function(hash){
return db.createUser(username, hash)
})
},
login: function(username, password){
return db.userFind(username)
.then(function(userObj){
if(!userObj){
console.log("did not find " + username + " in database.");
return new Promise(function(resolve, reject){
resolve({login:false, message:"Your username and/or password are incorrect."})
}
}
else {
console.log("found user: " + userObj._id, userObj);
return new Promise(function(resolve, reject){
bcrypt.pare(password, userObj.hashword, function(err, bool) {
resolve({bool:bool,
user:userObj._id,
mindSeal: userObj
})
})
})
}
})
}
}
Example Usage:
app.post('/signup', function(req, res) {
var username = req.body.username;
var password = req.body.password;
var user = handler.userExists(username)
.then(function(answer){
if (answer !== null){
console.log(req.body.username + " was taken")
res.send({login: false, message: req.body.username + " is taken"});
return null;
} else if (answer === null) {
console.log("username not taken")
return handler.makeUser(username, password);
}
})
.catch(function(err){
console.log("error during user lookup:", err);
res.status(404).send({message:"database error:", error:err});
})
if (user !== null){
user
.then(function(x){
console.log("this is returned from handler.makeUser: ", x)
console.log(x.ops[0]._id)
req.session.user = x.ops[0]._id;
var mindSeal = {
userSettings: {
username: x.ops[0]._id,
newCardLimit: null,
tValDefault: 128000000,
lastEdit: req.body.time,
todayCounter: 0,
allTimeCounter: 0,
cScaleDefault: {0: 0.9, 1: 1.2, 2: 1.8, 3: 2.5},
accountMade: req.body.time
},
decks: {}
};
handler.setMindSeal(req.session.user, mindSeal, req.body.time);
res.send({
login: true,
mindSeal: mindSeal
});
})
.catch(function(error){
console.log("make user error: " + error);
res.status(401).send({message:"failed.",error:error,login:false});
})
}
});
app.post('/login', function(req, res) {
var username = req.body.username;
var password = req.body.password;
handler.login(username, password)
.then(function(obj){
if (obj.bool){
console.log("username and password are valid. login granted.");
req.session.user = obj.user;
console.log("obj is:", obj)
var mindSeal = {decks:obj.mindSeal.decks, userSettings:obj.mindSeal.userSettings};
console.log("mindSeal sending:", mindSeal);
res.status(200).send({
login: true,
message:"Login Successful",
mindSeal: obj.mindSeal
});
}
else {
console.log("password invalid")
res.status(401).send({login: false, message:"Your username and/or password are incorrect."})
}
})
.catch(function(error){
console.log(error);
res.status(404).send({message:"database error:", error:err});
})
});
conceptual example only; borrowed and slightly modified some old code of mine on the fly. Working code (I see things I'd like to improve in it now, but it works) here: https://github./finetype/mindseal/blob/master/server.js
Maybe you could use another bcrypt library, with a better API which removes the need for promises.
Users.prototype.setPassword = function(user) {
return TwinBcrypt.hashSync(user.password, 10);
};
Or, with progress tracking :
Users.prototype.setPassword = function(user) {
function progress(p) {
console.log( Math.floor(p*100) + '%' );
}
TwinBcrypt.hash(user.password, 10, progress, function(result) {
// store in database
console.log("stored in database!");
return result;
});
};