I try to hash passwords with crypto
and I cannot save them in the database.
I have node.js 4.2.3 express 4.13.3, and my database is PostgreSQL 9.1. The field is character varying (255)
and is named pswrd
.
This is my code:
var tobi = new User({
usrnm:'sp',
pswrd:'an'
});
module.exports = User;
function User(obj){
for(var key in obj){
this[key] = obj[key];
}
}
User.prototype.save = function (fn){
var user=this;
//EDIT, added this :
var psw ;
var salt = crypto.randomBytes(50).toString('base64');
crypto.pbkdf2(user.pswrd, salt, 10000, 150, 'sha512',function(err, derivedKey) {
//user.pswrd = derivedKey.toString('hex');
//EDIT, added this:
var justCrypted = derivedKey.toString('hex');
});
var query=client.query('INSERT INTO mytable(usrnm,pswrd)VALUES($1,$2) RETURNING mytable_id',[user.usrnm,user.pswrd], function(err, result) {
if(err) {console.log(err)}
else {
var newlyCreatedId = result.rows[0].mytable_id;
}
});
query.on("end", function (result) {console.log(result);client.end();});
}
tobi.save(function (err){
if (err)throw error;
console.log("yo");
})
To run this, I type node lib/user
. I get no errors, but the password is not saved properly. The first value gets saved, the an
, not the hashed one. What am I missing here?
EDIT
AshleyB answer is good, but, please help me understand how to pass data from an internal function (crypto.pbkdf2
) to its external (User.prototype.save = function (fn)
) , when the internal has predifined, fixed syntax (crypto.pbkdf2
) , so I dont know if or how I can edit it.
How can I leave code as is and still pass the justCrypted
back to psw
(see edits on code) ? If it was a function that I wrote, I could use apply
I guess, but, crypto.pbkdf2
is predifined and I dont know if can add stuff to it.
Thanks
The problem is with the scope, currently the query the altered user.pswrd is outside of the scope of the query so it falls back to the value assigned at the top.
By moving the query inside the 'crypto.pbkdf2'
... block the user.pswrd value will work as intended. I've updated your code (and made the salt generation asynchronous, as you have used the async version of pbkdf2 anyway).
var tobi = new User({
usrnm: 'sp',
pswrd: 'an'
});
module.exports = User;
function User(obj) {
for (var key in obj) {
this[key] = obj[key];
}
}
User.prototype.save = function(fn) {
var user = this;
// Changed salt generation to async version
// See: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
crypto.randomBytes(50, function(ex, buf) {
if (ex) throw ex;
salt = buf.toString('base64');
// password, salt, iterations, keylen[, digest], callback
crypto.pbkdf2(user.pswrd, salt, 10000, 150, 'sha512', function(err, derivedKey) {
user.pswrd = derivedKey.toString('hex');
// Moved the query within the hash function
var query = client.query('INSERT INTO mytable(usrnm,pswrd)VALUES($1,$2) RETURNING mytable_id', [user.usrnm, user.pswrd], function(err, result) {
if (err) {
console.log(err)
} else {
var newlyCreatedId = result.rows[0].mytable_id;
}
});
query.on("end", function(result) {
console.log(result);
client.end();
});
});
});
}
tobi.save(function(err) {
if (err) throw error;
console.log("yo");
})
To answer your edit, I think you just need to understand that crypto.pbkdf2
is an asynchronous function that has a callback function as it's last parameter.
So within that callback function, you can access the psw
variable, and you are able to do something like psw = newlyCreatedId
. However, in your code the query is most likely called before the callback is. Therefore, you cannot make use of the psw
variable in the query as your code stands.
What Ashley B did is to put your query
function within the callback, to ensure that the query is not called until after the crypto function. You could also structure your code to use events, or promises if you didn't wish to nest the functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With