BCRYPT issue pulling from MySQL - javascript

Novice in my programming endeavors, but I am stuck and cannot find any help. I am able to register users into my db and hash the password. I am trying to be able to login with that user. I am able to check for required field in email and password, but when I enter a user in the db with the correct password the page hangs.
'''
exports.login = (req,res) =>{
try {
const {email, password} = req.body;
if (!email || !password){
return res.status(400).render('login', {
message: 'Email and password required.'
})
}
db.query ('SELECT * FROM users WHERE email = ?', [email], async (error, results)=> {
if(error)
console.log(error)
if(!results){
res.status(401).render('login', {
message: 'Invalid email or password.'
})
}else{
await bcrypt.compare(req.body.password, results.password)
if(bool == false){
res.status(401).render('login', {
message: 'Invalid password.'
})
}else{
res.status(401).render('index', {
message: 'User Logged in'
});
}
}
})
} catch (error) {
console.log(error);
}
}'''

Try this function : (bcryptCompare.js)
const checkBcrypt = async function(pass, hash) {
const bcrypt = require('bcrypt');
return new Promise(resolve => {
bcrypt.compare(pass, hash, function(bcryptErr, bcryptRes) {
if (bcryptErr) {
console.log('ERROR -> BCRYPT');
return resolve(false);
} else {
if (!bcryptRes) {
return resolve(false);
} else {
return resolve(true);
}
}
});
});
}
module.exports = checkBcrypt;
You can use it like this:
const checkBcrypt = require('./bcryptCompare');
const checkPass = await checkBcrypt(req.body.password, results.password);
if(checkPass){
//
} else {
//invalid password
}

Related

Login system wrong username error handling with MySql / NodeJs

I have the below controller which I use to manage the login system on my app. Is working in all cases except the one when I insert the wrong username.
I have inserted the below conditional statement to handle the error:
if (error === null) {
res.status(401).render('login', {
message: 'Email or Password is incorrect'
})
}
But when I insert it, I receive the following message on the terminal:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
const jwt = require('jsonwebtoken');
const mysql = require('mysql');
const bcrypt = require('bcryptjs');
const { promisify } = require('util');
var db_config = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME
};
var connection;
function handleDisconnect() {
connection = mysql.createConnection(db_config); // Recreate the connection, since
// the old one cannot be reused.
connection.connect(function (err) { // The server is either down
if (err) { // or restarting (takes a while sometimes).
console.log('error when connecting to db:', err);
setTimeout(handleDisconnect, 2000); // We introduce a delay before attempting to reconnect,
} // to avoid a hot loop, and to allow our node script to
}); // process asynchronous requests in the meantime.
// If you're also serving http, display a 503 error.
connection.on('error', function (err) {
console.log('db error', err);
if (err.code === 'PROTOCOL_CONNECTION_LOST') { // Connection to the MySQL server is usually
handleDisconnect(); // lost due to either server restart, or a
} else { // connnection idle timeout (the wait_timeout
throw err; // server variable configures this)
}
});
}
handleDisconnect();
// code in case the user leave the login space empty
exports.login = async (req, res) => {
try {
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).render('login', {
message: 'Please provide an email and password'
})
}
connection.query('SELECT * FROM login WHERE email=?', [email], async (error, results) => {
// conditional statement to handle the wrong username error
if (error === null) {
res.status(401).render('login', {
message: 'Email or Password is incorrect'
})
}
//conditional if statement to compare password in database and password inserted by the client
if (!results || !(await bcrypt.compare(password, results[0].password))) {
res.status(401).render('login', {
message: 'Email or Password is incorrect'
}) //conditional statement to fetch the id of the client and signign in with sign() function
} else {
const id = results[0].id;
const token = jwt.sign({ id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN
});
// console.log('the token is:' + token);
const cookieOptions = {
expires: new Date(
Date.now() + process.env.JWT_COOKIE_EXPIRES * 24 * 60 * 60 * 1000 // 24 hours converted in milliseconds to set the expiration cookies to 24 hours
),
httpOnly: true
}//setting of cookies on the browser and redirecting to the user interface page
res.cookie('jwt', token, cookieOptions);
res.status(200).redirect('/ui');
}
});
} catch (error) {
console.log("this is the error:", error)
}
}
exports.register = (req, res) => {
// Destructor
const { name, email, password, passwordConfirm } = req.body;
//query that order to MySQL to get the user email only once
connection.query('SELECT email FROM login WHERE email = ?', [email], async (error, results) => {
if (error) {
console.log(error);
}
if (results.length > 0) {
return res.render('register', {
message: 'That email is already in use'
})
} else if (password !== passwordConfirm) {
return res.render('register', {
message: 'Password do not match'
});
}
let hashedPassword = await bcrypt.hash(password, 8);
// console.log(hashedPassword);
connection.query('INSERT INTO login SET ?', { name: name, email: email, password: hashedPassword }, (error, results) => {
if (error) {
console.log(error);
} else {
// console.log(results);
return res.render('register', {
message: 'User registered'
});
}
})
});
}
exports.isLoggedIn = async (req, res, next) => {
// console.log(req.cookies);
if (req.cookies.jwt) {
try {
//1)verify the token
decoded = await promisify(jwt.verify)(req.cookies.jwt,
process.env.JWT_SECRET
);
//2) Check if the user still exists
connection.query('SELECT * FROM login WHERE id = ?', [decoded.id], (error, result) => {
// console.log(result);
if (!result) {
return next();
}
req.user = result[0];
return next();
});
} catch (error) {
console.log(error);
return next();
}
} else {
next();
}
}
exports.logout = async (req, res) => {
res.clearCookie('jwt');
res.status(200).redirect('/');
}
Thanks in advance for suggestions or correction to the right path.
Do not forget to return the response or the function will continue.
return res.status(401).render('login', {
message: 'Email or Password is incorrect'
});
You need to halt the execution of the function by putting the return keyword or the code will run through the other statements.
if (error === null) {
return res.status(401).render('login', {
message: 'Email or Password is incorrect'
})
}
Or
if (error === null) {
res.status(401).render('login', {
message: 'Email or Password is incorrect'
})
return
}
I got it, or at least is working. I deleted the first if statement and modify the remain one as below. instead of !results I edited it to results == "" . So if results is empty it will render the login with te alert message.
if (results == "" || !(await bcrypt.compare(password, results[0].password))) {
res.status(401).render('login', {
message: 'Email or Password is incorrect'
}) //conditio

UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'password' of undefined

This is my login code. Unhandledpromises occour while comparing Users input password and stored password.
exports.login = (req, res) => {
try {
const {email, password} = req.body
console.log(req.body)
if(!email || !password) {
return res.status(400).render('login', {
message: 'Please Provide an email and password'
})
}
db.query('SELECT * FROM users WHERE email = ? ',{email}, async (error, results) => {
console.log(error)
console.log(results)
if( !results || !(await bcrypt.compare(password, results[0].password)) ) {
res.status(401).render('login', {
message: 'Email or Password is Incorrect'
})
}
})
} catch (error) {
console.log(error)
}
}
Console.log(error) is null..
Updated
I'd suggest you to promisify db.query so you can await it, the errors will then be properly caught in the catch block, and your code will be flattened.
Your error is caused by results[0] which is undefined when trying to access its password property, which means that results is an empty array.
The second argument of query should not be an Object but an Array, so replace { email } with [email]:
const {
promisify
} = require('util');
const query = promisify(db.query.bind(db));
exports.login = async (req, res) => {
try {
const {
email,
password
} = req.body;
if (!email || !password) {
return res.status(400).render('login', {
message: 'Please Provide an email and password'
});
}
const results = await query('SELECT * FROM users WHERE email = ? ', [email]); // problem occur due to usage of curly brackets.
if (!results || !(await bcrypt.compare(password, results[0].password))) {
res.status(401).render('login', {
message: 'Email or Password is Incorrect'
});
}
} catch (error) {
console.log(error);
}
}

How to catch wrong username or password on Expressjs?

I have a POST route that takes an username and password and returns a token on successful login. If either username or password are blank, it returns an error. However, if I provide a wrong username or password, I'm still getting a token generated from the provided information. How can I check the information returned from the database to return the same wrong username or password error? This is my route:
router.post('/login', (req, res) => {
if (req.body.username == '' || req.body.password == '') {
res.status(401).send({ error: "Wrong username or password" });
} else {
queries.login(req.body.username, req.body.password).then((user) => {
if (res.error) {
res.status(401).send({ error: 'Wrong username or password' });
}
res.json(auth.getToken(user.id, user.username));
});
}
});
And this is my query:
async login(username, password) {
let getUser = await knex('users').where('username', username);
let user = getUser[0];
try {
if (await argon.verify(user.password_hash, password)) {
return user;
}
} catch (e) {
return e;
}
}
In your login query you need to throw an error for the error case, like:
async login(username, password) {
try {
let getUser = await knex('users').where('username', username);
let user = getUser[0];
if (await argon.verify(user.password_hash, password)) {
return user;
}
throw Error('User not verified');
} catch (e) {
throw Error(e.message);
}
}
Then in your route you can handle the error case by using .catch():
router.post('/login', (req, res) => {
if (req.body.username == '' || req.body.password == '') {
res.status(401).send({ error: "Wrong username or password" });
} else {
queries.login(req.body.username, req.body.password)
.then((user) => {
res.json(auth.getToken(user.id, user.username));
});
.catch((error) => {
res.status(401).send({ error: 'Wrong username or password' });
});
}
});

I am not getting the mongoose queried user as the returned value

This is my apollo resolver and I want to return the user but it does not return anything and if I return the query itself then I cannot do the password checking
my code:
login: (parent, { email, password }, context, info) => {
User.findOne({ email }, function(err, user) {
if (user.length) {
bcrypt.compare(password, user[0].password, function(err, res) {
if (res) {
console.log(user[0]); // this has the user
return user[0]; // but this does not return anything
} else {
throw new ApolloError("failed");
}
});
} else {
throw new ApolloError("failed");
}
});
}
I have done this solution and it is working perfectly
login: async (parent, { email, password }, context, info) => {
const user = await attemptSignIn(email, password);
return user;
}
const attemptSignIn = async (email, password) => {
const message = "Incorrect email or password. Please try again.";
const user = await User.findOne({ email });
if (!user || !(await matchesPassword(user, password))) {
throw new AuthenticationError(message);
}
return user;
};
matchesPassword = (user, password) => {
return compare(password, user.password);
};

Throw errors outside of promise

I have a function to log in a user which should return JSON.
const username = req.body.username;
const password = req.body.password;
if (!username) {
throw new Error('Missing username');
}
if (!password) {
throw new Error('Missing password');
}
User.findOne({ username, password }).then(user => {
res.json({ user });
}).catch(err => {
res.json({ err });
});
but then the errors for missing username or missing password are not returned in JSON.
I could change it to
const username = req.body.username;
const password = req.body.password;
if (!username) {
res.json({ err: 'Missing username' });
}
if (!password) {
res.json({ err: 'Missing password' });
}
User.findOne({ username, password }).then(user => {
res.json({ user });
}).catch(err => {
res.json({ err });
});
but it seems a little redundant.
Is the correct way to do it to encapsulate it in a promise?
In your first solution, the thrown errors won't be handled, because you throw them outside of promise chain and without try/catch block. In your second solution you can get cannot send headers after they sent error, because the response can be sent twice (username is missing and password is missing).
So the one of the possible solutions here, is to create a promise chain (using Promise.resolve()) and validate parameters here:
function validateParams() {
const username = req.body.username;
const password = req.body.password;
if (!username) {
throw new Error('Missing username');
}
if (!password) {
throw new Error('Missing password');
}
return { username, password };
}
Promise
.resolve()
.then(validateParams)
.then(filter => User.findOne(filter))
.then(user => res.json(user))
.catch(err => res.json(err));
The obvious way would indeed be to encapsulate them in a promise to start your promise chain (with the User.findOne being inside the first then-block) - that way your current error handler catches them just fine.
I'm taking the example from #alexmac and use es6 async feature:
function validateParams() {
const username = req.body.username;
const password = req.body.password;
if (!username) {
throw new Error('Missing username');
}
if (!password) {
throw new Error('Missing password');
}
return { username, password };
}
async function resolver() {
try {
await resolve()
let filter = validateParams()
let user = await User.findOne(filter)
await res.json(user)
} catch (e) {
await res.json(e)
}
}
and that would look more elegant by using an if instead of a throw:
async function(req, res) {
const password = req.body.password
const username = req.body.username
let c = !password ? 'missing password' :
!username ? 'missing username' : null
if (!c) {
c = await User.findOne({ username, password })
}
await res.json(c)
}
you can wrap your functions in a promise and handle it efficiently
function getRes(){
return new Promise(function(resolve, reject){
const username = req.body.username;
const password = req.body.password;
if (!username) {
reject(new Error('Missing username'));
}
if (!password) {
reject(new Error('Missing password'));
}
resolve(User.findOne({ username, password }));
});
}
getRes().then(function(result){
res.json(result);
}).catch(function(err){
res.json(err);
})

Categories

Resources