passport-local with mysql not working - mysql

I am using node.js and passport and mysql for a userlogin.
I the main source is from https://github.com/manjeshpv/node-express-passport-mysql/issues
I want to add more columns in the table. I started with emailfield and change the code like below. I simply added the email variable at the needed places I think. I cannot find the bug where its crashing. without modifying anything, the code does work.
passport.js:
passport.use(
'local-signup',
new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'username',
passwordField : 'password',
//emailField : 'email',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, email, done) {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
connection.query("SELECT * FROM users WHERE username = ?",[username], function(err, rows) {
if (err)
log.info(err);
//return done(err);
if (rows.length) {
return done(null, false, req.flash('signupMessage', 'That username is already taken.'));
} else {
// if there is no user with that username
// create the user
var newUserMysql = {
username: username,
email: email,
password: bcrypt.hashSync(password, null, null) // use the generateHash function in our user model
};
var insertQuery = "INSERT INTO users ( username, password, email ) values (?,?,?)";
connection.query(insertQuery,[newUserMysql.username, newUserMysql.password, newUserMysql.email],function(err, rows) {
newUserMysql.id = rows.insertId;
return done(null, newUserMysql);
});
}
});
})
);
and here the log:
The magic happens on port 8080
GET /signup 200 20ms - 1.21kb
D:\node-express-passport-mysql\node_modules\mysql\lib\protocol\Parser.js:82
throw err;
^
TypeError: undefined is not a function
at Object.SqlString.escape (D:\node-express-passport-mysql\node_modules\mysq
l\lib\protocol\SqlString.js:46:13)
at D:\node-express-passport-mysql\node_modules\mysql\lib\protocol\SqlString.
js:80:19
at String.replace (native)
at Object.SqlString.format (D:\node-express-passport-mysql\node_modules\mysq
l\lib\protocol\SqlString.js:71:14)
at Connection.format (D:\node-express-passport-mysql\node_modules\mysql\lib\
Connection.js:263:20)
at Connection.query (D:\node-express-passport-mysql\node_modules\mysql\lib\C
onnection.js:196:22)
at Query._callback (D:\node-express-passport-mysql\config\passport.js:71:32)
at Query.Sequence.end (D:\node-express-passport-mysql\node_modules\mysql\lib
\protocol\sequences\Sequence.js:96:24)
at Query._handleFinalResultPacket (D:\node-express-passport-mysql\node_modul
es\mysql\lib\protocol\sequences\Query.js:144:8)
at Query.EofPacket (D:\node-express-passport-mysql\node_modules\mysql\lib\pr
otocol\sequences\Query.js:128:8)
28 Jun 21:03:58 - [nodemon] app crashed - waiting for file changes before starti
ng...

This looks to be the problem:
function(req, username, password, email, done) {
You added an extra argument email which shouldn't be there. Since it clobbers the done callback, when your code tries to call it it will cause an "undefined is not a function" error.
If you're passing an extra email property, you can access it through req.body.email (assuming that you're using a POST route to log in).

Related

Mysql JWT reporting fails always

i am trying to simulate login using Node.Js , JWT and mysql
i am always getting invalid user and pass, i started to wonder what i was not doing correctly.
My code:
app.post('/api/v1/user/login', async function(req,res){
var email = req.body.email;
var password = req.body.password;
var hashPass = await bcrypt.hashSync(password,12);
const bycryptPass = bcrypt.compareSync(password,hashPass);
dbConn.query('select * from xxxx_users where email =? and password =?',[email,bycryptPass],function(error,results,fields){
if(results.length > 0){
const token = jwt.sign({id:row[0].id},'the-super-strong-secrect',{ expiresIn: '1h' });
res.send({error: false, message: 'OK', token: token})
}else{
res.send({error: true, message: 'Invalid User or Pass'})
}
})
})
what am i not doing correctly? Why does it report that the login user and pass is always failed?
Compare hash would give you a boolean result based on the 2 values that you passed into it.
First, you have to get the user record based on the username and then check the password or pass hashed password to the query itself.
const hashPass = await bcrypt.hashSync(password,12);
//const bycryptPass = bcrypt.compareSync(password,hashPass);
dbConn.query('select * from xxxx_users where email =? and password =?',[email,hashPass],function(error,results,fields){
if(results.length > 0){
const token = jwt.sign({id:row[0].id},'the-super-strong-secrect',{ expiresIn: '1h' });
res.send({error: false, message: 'OK', token: token})
}else{
res.send({error: true, message: 'Invalid User or Pass'})
}
})
I prefer the following
const user = await getUserByUsername(loginRequest.userName);
if (user && compareHash(user.password, loginRequest.password)) {
//login success access
}
bcrypt will never produce the same hash for the same password. It's one of its design features.
Your general flow would work for older ways to hash passwords, like md5, sha256, but these are no longer recommended.
The general correct flow for implementing login works roughly like this:
Given that you have a username and password
Pull out the user record from the database based on the username alone (not the password)
Then use the compare function to see if the password the user supplied is comparable to the hash in the database.
It's impossible to select on the password hash, it will always be wrong.

MEAN Stack app - Can't set headers after they are sent

I'm basically trying to create a register page using MEAN and I want to check against the database (Mongo using Mongoose) if the user and email already exists, if one of them is true, send a res.json fail.
And if the username and email are not already in the database, continue to add the user.
I'm getting an error "Can't set headers after they are sent." On the Node console and I'm trying to figure out why.
Once User.getUsername() returns a user in the callback (if the username passed exists in the db), shouldn't it return the json and end the request there? Why is it continuing to the User.adduser() function and trying to set the header there too?
Any help is appreciated, thank you.
router.post('/register', (req, res, next) =>{
let newUser = new User({ // Collect body info
name: req.body.name,
email: req.body.email,
username: req.body.username,
password: req.body.password
});
// Check if username is available
User.getUserByUsername(newUser.username, (err, user) => {
if(err) throw err;
if(user){
return res.json({success: false, msg: 'User already exists'});
// I want to end here if there's a user
}
});
//Continue to add user if getUserByUsername() returns false for user
// Add user
User.addUser(newUser, (err, user) => { // Add user
if(err){
return res.json({success: false, msg: 'Failed to register'});
} else {
return res.json({success: true, msg: 'You have been successfully registered!'});
}
});
});
The logic you have doesn't work for as expected because of how asynchronous methods work. The current logic is do User.getUserByUsername then do User.addUser and if either method calls back, handle it. I'm pretty sure you want, do User.getUserByUsername, wait for it's callback, then call User.addUser if necessary. Here's a crude implementation, you could use promises or define the methods outside of the logic to clean it up. Also, make sure you are calling res.end() at some point in your code.
router.post('/register', (req, res, next) =>{
let newUser = new User({ // Collect body info
name: req.body.name,
email: req.body.email,
username: req.body.username,
password: req.body.password
});
// Check if username is available
User.getUserByUsername(newUser.username, (err, user) => {
if(err) throw err;
if(user){
return res.json({success: false, msg: 'User already exists'});
// I want to end here if there's a user
}else{
//Continue to add user if getUserByUsername() returns false for user
// Add user
User.addUser(newUser, (err, user) => { // Add user
if(err){
return res.json({success: false, msg: 'Failed to register'});
} else {
return res.json({success: true, msg: 'You have been successfully registered!'});
}
});
}
});
});

Error function not returning JSON format

I'm trying to pass a JSON error object into my code using the error function in two cases. Once in the email and password check statement and again in the if existingUser statement. I think it's just that time of the night.
const User = require('../models/user');
exports.signup = function(req, res, next) {
const email = req.body.email;
const password = req.body.password;
if (!email || !password) {
return res.err("Please enter in email and password");
}
//See if a user with the given email exists
User.findOne({ email: email }, function(err, existingUser) {
if (err) { return next(err); }
//If a user with email does exist, return an Error
if (existingUser) {
//the status sets the status of the http code 422 means couldn't process this
return res.err( 'Email is in use' );
}
//If a user with email does NOT exist, create and save user record
const user = new User({
email: email,
password: password
});
user.save(function(err) {
if (err) { return next(err); }
//Respond to request indicating the user was created
res.json({ success: true });
});
});
}
At the moment you are not returning the right status code in your response, you could try this:
Replace:
return res.err("Please enter in email and password");
With
return res.status(422).send({error: "Please enter in email and password"})
And replace:
return res.err( 'Email is in use' );
With:
return res.status(422).send({ error: "Email is in use" });
This will send back the required status code in the http response.
Also consider only using single or double quotes in your code for consistency.

Create user with Passport & mysql

I'm developing a MySql, Express, Angular, NodeJS application and I'm trying to wrap my head around signing up users, I can't find a propper source that provides to information I'm looking for.
I know how to create a user record with a username and password but only how to store the database as text and not hashed/salted.
I'm thinking I just need to find out how to created a hashed password when a user signs up. Then figure out how to place that hashed password in the database and then finally when a user wants to sign in compare the passwords. But it all feels a bit abstract and I can't find any information of passport does any of this.
we are using named strategies since we have one for login and one for signup
by default, if there was no name, it would just be called 'local'
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
connection.query("select * from users where email = '"+email+"'",function(err,rows){
console.log(rows);
console.log("above row object");
if (err)
return done(err);
if (rows.length) {
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else {
// if there is no user with that email
// create the user
var newUserMysql = new Object();
newUserMysql.email = email;
newUserMysql.password = password; // use the generateHash function in our user model
var insertQuery = "INSERT INTO users ( email, password ) values ('" + email +"','"+ password +"')";
console.log(insertQuery);
connection.query(insertQuery,function(err,rows){
newUserMysql.id = rows.insertId;
return done(null, newUserMysql);
});
}
});
}));
For more details plz check this https://gist.github.com/manjeshpv/84446e6aa5b3689e8b84

Rest API - Is it safe to get password in JSON response

I'm writing a Rest API with Node.js and using JWTs.
I have the route below to authenticate users.
I'd like to ask, the user that is returned from the method User.findOne returns the correct password hence I'm able to check if its correct.
However is this safe to do? I did a console.log and it shows the password (albeit encrypted) but still feels unsafe as someone could surely view?
router.post('/authenticate', function(req, res) {
// find the user
User.findOne({
name: req.body.name
}, function(err, user) {
if (err) throw err;
if (!user) {
res.json({ success: false, message: 'Authentication failed. User not found.' });
} else if (user) {
// check if password matches
if (user.password != req.body.password) {
res.json({ success: false, message: 'Authentication failed. Wrong password.' });
} else {
// if user is found and password is right
// create a token
var token = jwt.sign(user, app.get('superSecret'), {
expiresInMinutes: 1440 // expires in 24 hours
});
// return the information including token as JSON
res.json({
success: true,
message: 'Enjoy your token!',
token: token
});
}
}
});
});
No.
Furthermore, passwords shouldn't be saved encrypted in the database, but hashed. The classical environment saves passwords for example as md5 (more common) or bcrypt (more secure) hash.
This ensures that even if your database gets stolen, no one will have the passwords of your users; there is no way to "decrypt" the hashes (not in a hundred million years).
When a user logs in you compare a hash of the entered password with the hash assigned with the user. You can use great modules like bcrypt-nodejs
EDIT
From a technical aspect it wouldn't be dangerous. When you start your server JavaScript compiles your code and executes the result in a V8 engine. There is no way to access whats ever returned by your database as long as the connection between node and MySQL is save.
One could possibly dump the servers memory and hope to find the right bits. But if someone gains the necessary permissions, you'r doomed either way.
I implemented an example for you, it's untested, but should show you how it's meant.
router.post('/register', function(req, res) {
bcrypt.hash(req.body.password, null, null, function(err, hash) {
if (!err) {
var newUser = new User({
name: req.body.name,
password: hash
});
newUser.save(); // ????
}
});
});
router.post('/authenticate', function(req, res) {
User.findOne({
name: req.body.name
}, function(err, user) {
var password = 'GP%Z!zvbk/9>Ss-R';
var passwordHash = '$2a$10$W.zZPCaNOuR152I4qENKH.8h7I6BPcfCYBJqHPNXbVaBz0XWVxnBm'; // bcrypt of string ')RZK&M(QX"k188cw'
if (user) {
password = req.body.password;
passwordHash = user.password;
}
bcrypt.compare(password, passwordHash, function(err, success) {
if (success) {
var token = jwt.sign(user, app.get('superSecret'), {
expiresInMinutes: 1440
});
res.json({
success: true,
message: 'Enjoy your token!',
token: token
});
}
else {
res.status(401).json({
success: false,
message: 'Authentication failed.'
});
}
});
});
});
Note: bcrypt uses random salt by default for each hash operation. This means, whenever you hash a given input, it will produce different hashes each time. The salt is then stored as part of the hash which can be verified then. Please check Wikipedia for further info.