Bluebird promise resolve is being caught as an error - node.js

I am using promises to return data for a user do authenticate them and my resolve is showing up in my .catch for my call.
Call to the login function;
function(req, username, password, done) {
user.login(username, password).then( function(err, results){
if (err) throw err;
done(null, results.user);
}).catch(
function(err){
console.log("Failed to log in", err);
done(null, false);
}
);
}
Here is the promise code:
exports.login = function(username, password){
return new promise(function(resolve, reject){
var sql = `CALL LOGIN(?)`;
db.conn.query(sql, username, (err, results, fields) => {
if (err) {
reject("SQL ERR:", err);
}
var user = results[0][0];
if (!user.uID) {
reject("Incorrect username");
}
if(bcrypt.compareSync(password, user.pword)){
resolve(user);
} else {
reject('Incorrect password');
}
});
});
}
When this is called, the user objet is being thrown as an error even though its being called on resolve... I am currently stuck, I tried to re-install the bluebird module as well incase something happened with it.

What's going on here is the next thing:
Here you are passing the user object as a param if everything is ok
if (bcrypt.compareSync(password, user.pword)) {
resolve(user);
} else {
reject('Incorrect password');
}
So in this part .then of your code you are receiving a user object as a unique param so there is no necessity to check if there is an error.
function (req, username, password, done) {
user.login(username, password).then(function(user) {
// a good way to see all arguments is
// console.log(arguments);
done(null, user);
}).catch(
function(err) {
console.log("Failed to log in", err);
done(null, false);
}
);
}

Related

MongoDb findOne query results in error - even if data is found

the below is my controller function
exports.validateUsername = async (uName) => {
console.log("inside validate username");
await User.findOne({ username: "sab2" }).then(function (err, user) {
if (err) {
console.log("inside err");
console.log("error");
console.log(err);
return true;
} else {
console.log("inside user found");
console.log("user");
console.log(user);
return false;
}
});
};
I have record in my "user" collection with username ="sab2". But still , the promise function results in err, and goes inside if(err).
But when I do console.log(err) I get the actual user data "sab2" object.
I have a doubt if the function syntax is function(data,err).
Error object printed
Please suggest a solution.
The then() on a findOne does not return a error, I would rewrite like this:
User.findOne({ username: "sab2" }, function(err, user) {
if (err) {
console.log("inside err");
console.log("error");
console.log(err);
return true;
} else {
console.log("inside user found");
console.log("user");
console.log(user);
return false;
}
});
then do not return error. Do something like this to catch error
await User.findOne({ username: "sab2" }).then((user) => {
console.log(user)
}).catch(error=>console.log(error))
or use callback. See here

What is the proper way to handle an error in Node.JS?

This post request creates a new user account and saves a test score data point for a user.
~1/20 users or so run into an error and are redirected back to the previous page thus losing their results.
I have been unable to replicate the error or see any errors in the logs.
Looking for advice on how to change my error handling and or any insight to why this may be occurring.
Thank you!
router.post("/test", function(req, res){
User.findOne({username: req.body.username}, function(err, existingUser) {
console.log('user exists:' + existingUser)
if (err) {
return done(err);
}
if (!existingUser) {
var newUser = new User({username: req.body.username});
User.register(newUser, req.body.password, function(err, user){
user.testscore = req.body.testscore;
user.save()
if(err){
req.flash("error", err.message);
console.log(err)
res.redirect('back')
return res.render("register");
}
passport.authenticate("local")(req, res, function(){
res.redirect("/thank-you");
});
});
You can use try-catch along with async-await for error handling. I would write the code like this.
router.post('/test', async (req, res) => {
try {
const user = await User.findOne({username: req.body.username})
if (!user) {
let newUser = new User({username: req.body.username});
// If User.register returns promise then here also you can use await like above.
// If any error occurs catch block will catch it and show the error.
User.register(newUser, req.body.password, function(err, user) {
user.testscore = req.body.testscore;
user.save()
if(err) {
req.flash("error", err.message);
console.log(err)
res.redirect('back')
return res.render("register");
}
passport.authenticate("local")(req, res, function() {
res.redirect("/thank-you");
});
});
}
} catch (err) {
console.error(err.message)
}
})
Hope it helps to solve your problem.

Setting a function callback fram an async request

Good Morning All,
I have been looking for an answer to this on the boards, but my noob brain just can't make sense of it.
i have this function in models/user.js
module.exports.getUserByUsername = function(username, callback){
var retUser = new User;
sql.connect(dbConfig, function(err) {
if (err) {
console.log(err);
callback();
}
// create Request object
var request = new sql.Request();
request.input('ip_username', sql.NVarChar, username)
// query to the database and get the records
request.query('select * from [portal_users] where username = #ip_username', function(err, recordset) {
if (err) {
console.log(err);
return;
} else {
var user = new User(recordset.recordset[0].username,recordset.recordset[0].password,recordset.recordset[0].email,recordset.recordset[0].name);
user.addID(recordset.recordset[0].id);
retUser = user;
}
callback();
// send records as a response
//res.send(recordset);
});
});
function callback() {
sql.close();
return retUser;
};
}
and this code in my routes/user.js
passport.use(new LocalStrategy(
function(username, password, done) {
User.getUserByUsername(username, function(err, user){
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown User'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
});
}));
I have been modifying an example from GITHUB that uses mongoDB for the DB connection, but I would like to use MS SQL. The function is successfully calling the database and returning the correct values. However I don't know how to initiate the callback so I can pass the retUser object back to the original function for processing and logging in.
I did for a moment try to do this by not using the callback and using a standard return type of function, however I quickly realised that given the async nature this wouldn't work.
any help here would be greatly appreciated.
Thanks
OK I managed to figure it out using this post:
Node.js npm mssql function returning undefined
my new code is:
module.exports.getUserByUsername = function(username, callback){
var connection = new sql.ConnectionPool(dbConfig, function(err) {
if (err) {
console.log(err);
callback(err);
return
}
// create Request object
var request = new sql.Request(connection);
request.input('ip_username', sql.NVarChar, username)
// query to the database and get the records
request.query('select * from [portal_users] where username = #ip_username', function(err, recordset) {
if (err) {
console.log(err);
callback(err,recordset);
return;
} else {
var user = new User(recordset.recordset[0].username,recordset.recordset[0].password.replace(/ /g,''),recordset.recordset[0].email,recordset.recordset[0].name);
user.addID(recordset.recordset[0].id);
callback(err,user);
}
sql.close();
// send records as a response
//res.send(recordset);
});
});
}

I keep getting 401 Unauthorized whenever I try to login an existing user with JWT, Passport, and Express

Whenever I try to login a user through a post request in Postman, I keep getting this error:
Here is the localStrategy I made for checking if a user's email and password can be verified:
passport.use(new LocalStrategy({usernameField: 'email', passwordField: 'password'}, function(email, password, done){
User.findOne({email: email}, (err, user) => {
if (err) return done(err);
if (!user){
return done(null, false, {message: "User is not registered"});
}
else {
const realPassword = String(user.password);
bcrypt.compare(password, realPassword, (err, result) => {
if (err) throw err;
if (result){
console.log('result is...' + result);
done(null, user)
}
else {
console.log('result is...' + result);
return done(null, false, {message: 'Invalid Password'});
}
}
});
}));
And here is the post request method in my router file:
router.post('/login', passport.authenticate('local', {session: false}), (req, res, next) => {
function generateUserToken(user){
return jwt.sign({sub: user._id, creationDate: user.creationDate}, config.secretKey);
}
if (err) throw err;
res.send({token: generateUserToken(user)})
});
UPDATE: I changed some of my code now to address issues raised. However, now instead of getting unauthorized, I keep getting a 404 not found error
In my case there where dismatch in findOne(), User schema has local.email, so I needed to search for findOne({'local.email': email}, ...).
Seems the value of doesMatch is always false.
I believe you're missing the bcrypt.compare doesn't return anything.
It is asynchronous, so, you can't get the result using the return statement.
You have to put everygint inside of the callback function from bcrypt.compare
bcrypt.compare(password, realPassword, (err, result) => {
if (err) throw err;
// NOW YOU HAVE THE VALUE FORM THE COMPARISON
if (result){
done(null, user)
}
else {
return done(null, false, {message: 'Invalid Password'});
}
});
Let me know if it works.
Hope it helps you.

Passport Authentication: chaining strategies

How do I run two or more passport strategies sequentially, meaning if one strategy comes up empty then run another one?
I tried doing this:
app.post('/', function (req,res,next){
passport.authenticate('strategy1', function (err, result1) {
if (err) { return next(err); }
if (!result1) {
passport.authenticate('strategy2', function (err,result2){
if (err) { return next(err); }
if(!result2){
return res.redirect('/');}
req.login(result2, function (err){
if(err){return next(err)}
res.render('result2');
})
});
}
req.login(result1, function (err){
if (err){return next(err)}
console.log('admin login found');
res.render('result');
});
})(req, res, next);
});
But am getting this error:
Error: Failed to serialize user into session
I have implemented:
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
I suspect the user was serialised in the first passport.authentication call and then it tried to serialise it again with the second one, and what I need to do is deserialise it again before running the second strategy.
Appreciate the help!
I ended up sticking to just one strategy but added logic to allow it to check several collections, as recommended in this answer.
passport.use('local', new LocalStrategy({
passReqToCallback : true
}, function(req, username, password, done) {
process.nextTick(function() {
collection1.findOne({'username': username}, function(err, collectionresult) {
if (err) {
return done(err);
}
if (!collectionresult) {
collection2.findOne({'username': username}, function(err, collection2result){
if (err) {
return done(err);
}
if (!collection2result) {
return done(null, false,req.flash('adminmessage','Invalid username or password'));
}
if (!collection2.validPassword(password)) {
return done(null, false,req.flash('adminmessage','Invalid username or password'));
}
console.log('local strategy has authenticated employee username and password! Returning employee');
return done(null, employee);
})
}
if (collection2result){
if (collection2result.password!=password) {
return done(null, false, req.flash('adminmessage','Invalid username or password' ));
}
else{
console.log('Local strategy has found an admin. Returning admin');
return done(null, collection2result)
}
}
});
}
);
}));

Resources