I will post both of the modules, some of the code in them may be "irrelevant" for the main concern here, which is Security.prototype.authenticate(). Nevertheless, comments are welcome about all of the code.
Security.prototype.authenticate() is a controller for a /login API-endpoint.
security.js
'use strict';
var crypto = require('crypto');
var jwt = require('jsonwebtoken');
var Promise = require('bluebird');
var config = require('./config');
var db = require('./db');
function Security() {}
function _verifyPassword(password, hash, salt) {
var newHash = crypto.createHash('sha512').update(password).update(salt).digest("hex");
return newHash === hash;
}
function _generateToken(username, secret, expiration) {
var token = jwt.sign(username, secret, { expiresInMinutes: expiration });
return { token: token };
}
Security.prototype = {
tokenCheck: function(req, res) {
jwt.verify(req.body.token, config.security.secret, function (err, decoded) {
if (err) {
return res.status(400).send("Token invalid or expired");
}
res.json({ username: decoded });
});
},
authenticate: function(req, res) {
if (!req.body.username || !req.body.password) {
return res.status(400).send("Username and/or password field empty");
}
Promise.using(db.getConnection(), function(connection) {
return connection.queryAsync("SELECT password_hash, password_salt FROM users WHERE email = ? AND admin = 1", req.body.username)
.then(function(rows) {
connection.release();
if ( rows[0].length === 1 ) {
return rows[0][0];
} else {
throw new Error("Username not found");
}
}).then(function(user) {
if ( !_verifyPassword(req.body.password, user.password_hash, user.password_salt) ) {
throw new Error("Incorrect password");
}
res.json({
token: _generateToken(req.body.username, config.security.secret, config.security.expiration),
username: req.body.username
});
});
}).error(function(e) {
res.status(400).send("Database error");
}).catch(Error, function(e) {
res.status(400).send(e.message);
});
}
};
module.exports = new Security();
db.js
'use strict';
var config = require('./config');
var Promise = require("bluebird");
var mysql = require('mysql');
Promise.promisifyAll(require("mysql/lib/Connection").prototype);
Promise.promisifyAll(require("mysql/lib/Pool").prototype);
function DB() {
this._pool = _createPool();
}
function _createPool() {
return mysql.createPool({
connectionLimit: config.database.connectionLimit,
host: config.database.host,
user: config.database.username,
password: config.database.password,
database: config.database.database,
debug: config.database.debug
});
}
DB.prototype = {
getConnection: function() {
return this._pool.getConnectionAsync();
}
};
module.exports = new DB();
My concerns are any possible anti-patterns that are visible here. I just got rid of one problem with this function, which was nested callbacks, by implementing promises. However, my knowledge of Bluebird is limited to the last ~12 hours. I have used promises before, but not a lot. Also, as I said, comments on the rest of the code are also welcome.