1

I wrote a node.js module. My module has an isValid method which reads data from a database using a giving token as a lookup value. If the data is valid setData method is called, then return true if the data is valid or false otherwise.

Based on some messages I logged to the console, the function should return true but when I do `if...else...`` check, it always returns false.

Here is my module

var db = require('./dbconnect');

var PHPUnserialize = require('php-unserialize');


function validator (){
  this.icws = null;
};


/**
* @setData
*
* Set the value of the icwsData
*
* @return void
*/
validator.prototype.setData = function (icws){
  this.icws = icws;
};


/**
* @getData
*
* Get the value of the icwsData
*
* @return object
*/
validator.prototype.getData = function (){
  return this.icws;
};


/**
* @isValid
*
* Checks if a token is valid or not
*
* @params (string) tokenId: the PHP sessionId
* @params (string) myIP: the user IP address
* @params (integer) duration: the duration to keep the session good for in microseconds
*
* @return bool
*/
validator.prototype.isValid = function (tokenId, myIP, duration){

  if(!tokenId || !myIP){
    console.log('Missing TokenID or IP Address');
    return false;
  }

  if(!duration){
    duration = 3600;
  }

  var self = this;
  db.sqlConnection('SELECT ' +
                   '  su.icws_username AS username ' +
                   ', su.icws_password AS password ' +
                   ', su.icws_workstation AS workstation ' +
                   ', icws.host ' +
                   ', icws.port ' +
                   ', s.data ' +
                   'FROM sessions AS s ' +
                   'INNER JOIN view_users AS su ON su.user_id = s.user_id ' +
                   'INNER JOIN icws_servers AS icws ON icws.server_id = su.icws_server_id ' +
                   'WHERE s.session_id = ? '
                   , [tokenId] , function(err, rows){


    if(err){ 
      console.log(err);
      return false;
    }

    if(!rows[0] || !rows[0].data){
      console.log('No match found for this token!');
      return true;
    }

    var data = PHPUnserialize.unserializeSession(rows[0].data);
    var now = Math.floor(new Date() / 1000);

    if(!data.MA_IDLE_TIMEOUT || (data.MA_IDLE_TIMEOUT + duration) < now){
      console.log('The session Times out!');
      return false;
    }

    if(!data.MA_IP_ADDRESS || myIP != data.MA_IP_ADDRESS){
      console.log('This session have been hijacked!');
      return false;
    }

    self.setData(rows[0]);
    console.log('Good - return true!');
    return true;
  });

};


module.exports = validator;

Here is how I call the module

var sessionValidator = require('./modules/validator.js');
var sessionChecker = new sessionValidator();
var boo = sessionChecker.isValid(decodedToken, myIP, env.session.duration);
if(boo){
    console.log('Worked!');
} else {
    console.log('No Go!');
}

return;

The console prints

Good - return true!
No Go!

I am expecting this for my output

Good - return true!
Worked!

Why this function is always returning false?

If you need to see my dbconnect module, here is it's code

// Dependencies
var mysql   = require('mysql'),
    env  = require('./config');

/**
 * @sqlConnection
* Creates the connection, makes the query and close it to avoid concurrency conflicts.
*
* @param (string) sql: the sql query
* @param (array) values: contains values to sanitize for the query
* @param (function) next: call back function that will have data set if a select query is passed
*
* @return void
*/  

exports.sqlConnection = function (sql, values, next) {

    // It means that the values hasnt been passed
    if (arguments.length === 2) {
        next = values;
        values = null;
    }

    var connection = mysql.createConnection({
          host: env.mysql.host,
          user: env.mysql.user,
          password: env.mysql.password,
          database: env.mysql.database
    });

    connection.connect(function(err) {
        if (err !== null) {
            console.log("[MYSQL] Error connecting to mysql:" + err );
        }
    });

    connection.query(sql, values, function(err) {

        connection.end(); // close the connection

        if (err) {
            throw err;
        }

        // Execute the callback
        next.apply(this, arguments);
    });
}

EDITED

the current output is actually

No Go!
Good - return true!
Junior
  • 11,602
  • 27
  • 106
  • 212
  • @JamesThorpe I forgot to copy that line, I just updated my question. this is how I declare it `var boo = sessionChecker.isValid(decodedToken, myIP, env.session.duration); – Junior Sep 21 '15 at 16:10
  • @Dave If it were async, you'd expect the `No Go` output before `Good - return true` etc? – James Thorpe Sep 21 '15 at 16:11
  • do you get different results if you do if(boo == true) ? – spectacularbob Sep 21 '15 at 16:12
  • 1
    Ah - there's an inner function in there you're returning from - it's that that has "return true" in it, not your outer `isValid` function. – James Thorpe Sep 21 '15 at 16:12
  • 1
    With the final edit showing the actual current output, I agree with @Dave. So it's a probable duplicate of [How to return the response from an asynchronous call?](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call) – James Thorpe Sep 21 '15 at 16:13
  • @DaveNewton I think you are right there. How can I fix that? the function should return whatever the inner function return – Junior Sep 21 '15 at 16:14
  • @MikeA that isn't possible. Welcome to the wonderful world of asynchronous javascript. – Kevin B Sep 21 '15 at 16:20
  • @KevinB so what would be my workaround to validate a user? – Junior Sep 21 '15 at 16:21
  • 1
    Use a callback or a promise (which will also have a callback) – Kevin B Sep 21 '15 at 16:21
  • 1
    @MikeA work with callback functions and passing them around when the async work is done. – Thomas Stringer Sep 21 '15 at 16:21
  • Wonderful! The call back did the trick! – Junior Sep 21 '15 at 16:27
  • 1
    @JamesThorpe When it's async I don't expect much of anything except it often won't work like one expects. Console output can be misleading, too. Regardless of the reported output (which was edited), most DB work in Node is async (clue #1), I didn't see anything that took that into account (clue #2), and it exhibited all the hallmarks of typical async misunderstanding, e.g., "I know I'm returning the right thing but the calling code gets something else" (clue #3). – Dave Newton Sep 21 '15 at 16:39
  • @DaveNewton if you post an answer I will gladly accept it. – Junior Sep 21 '15 at 16:40

1 Answers1

2

The DB access itself is asynchronous.

What actually happens is that isValid returns undefined (falsey, but not explicitly false) so the conditional indicates invalidity.

It often makes sense to use === and check for type as well as truthy/falsey: it might have helped indicate why/where the code wasn't doing what you expected.

As indicated in the comments, using callbacks or promises is the canonical approach.

Dave Newton
  • 158,873
  • 26
  • 254
  • 302