Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass value from internal to external function - Cannot save password

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

like image 810
slevin Avatar asked Dec 24 '15 22:12

slevin


2 Answers

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");
})
like image 162
Ash Avatar answered Oct 21 '22 09:10

Ash


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.

like image 37
Justin Heath Avatar answered Oct 21 '22 10:10

Justin Heath