Bycrpt cannot compare and always sends null values - mysql

i m using Bycrpty library for security. so i read bycrpt Official document.
i sent postman in signup routes. it work or not
it was success full! like that.
so i have to compare the passwords When logging in,
but compare is always failed. it's my code..
const jwt = require('jsonwebtoken');
// const { Op } = require("sequelize");
const { user } = require("../../models");
const bcrypt = require("bcrypt");
const salt = bcrypt.genSaltSync(10) ;
signUpController: async (req, res) => {
const { username, email, password} = req.body;
if( !(username && email && password) ){
res.status(405).send({
"message" : "invalid request"
});
}
else{
const userInfo = await user.findOne({
where: {
email: email,
username : username
}
});
if(userInfo === null){
const newUser = await user.create({
username: username,
email : email,
password: bcrypt.hashSync(password, salt),
});
let response = {
username: newUser.username,
email: newUser.email,
username: newUser.username,
password : newUser.password
}
res.status(201).json( response );
}
else{
res.status(409).send({
"message" : "email already exist"
});
}
}
},
login : async(req,res)=>{
const { email, password } = req.body;
const userInfo = await user.findOne({
where: {
email: email,
password : password
}
});
// console.log("req: ", req)
if(!userInfo) {
await res.status(400).send({data : null, message : 'not authorized'})
}
else {
const data = {...userInfo.dataValues}
console.log('password:', checkMail.password)
bcrypt.compareSync(password, userInfo.password) ;
delete data.password
const accessToken = jwt.sign(data, process.env.ACCESS_SECRET, {expiresIn : '3h'}) // create jwt
const refreshToken = jwt.sign(data, process.env.REFRESH_SECRET, {expiresIn : '1h'}) // save in cookie .
res.cookie("refreshToken", refreshToken)
res.status(200).send({data:{"accessToken": accessToken}, message:'ok'})
}
}
What should I do to be successful? I need advice and tips.

I'm slightly confused as your using async/await for some things like the database library however not for bcrypt which also has promises and instead you're using their sync versions. As a first advice I wouldn't use the sync versions of the code as they block the eventLoop.
There is another problem with your logic - which is highlighted below.
const jwt = require('jsonwebtoken');
// const { Op } = require("sequelize");
const { user } = require("../../models");
const bcrypt = require("bcrypt");
const salt = bcrypt.genSaltSync(10) ;
signUpController: async (req, res) => {
const { username, email, password} = req.body;
if( !(username && email && password) ){
res.status(405).send({
"message" : "invalid request"
});
}
else{
const userInfo = await user.findOne({
where: {
email: email,
username : username
}
});
// using email/username as unique fields to find a user and check if they already have an account
if(userInfo === null){
const newUser = await user.create({
username: username,
email : email,
password: bcrypt.hashSync(password, salt),
// saving the hashed password rather than the plaintext password
});
let response = {
username: newUser.username,
email: newUser.email,
username: newUser.username,
password : newUser.password
}
// do not under any circumstance send the password back to the user.
res.status(201).json( response );
}
else{
res.status(409).send({
"message" : "email already exist"
});
}
}
},
login : async(req,res)=>{
const { email, password } = req.body;
// you're trying to find a user that exists based on their email and plaintext password, but the password you've saved is the HASHED version not the plaintext version so this result will always be empty... No such user exists
const userInfo = await user.findOne({
where: {
email: email,
password : password
}
});
// console.log("req: ", req)
if(!userInfo) {
// hence this error is present ALL THE TIME
await res.status(400).send({data : null, message : 'not authorized'})
}
else {
const data = {...userInfo.dataValues}
console.log('password:', checkMail.password)
bcrypt.compareSync(password, userInfo.password) ;
// you wouldn't need this step as you've found the user based on the password
delete data.password
const accessToken = jwt.sign(data, process.env.ACCESS_SECRET, {expiresIn : '3h'}) // create jwt
const refreshToken = jwt.sign(data, process.env.REFRESH_SECRET, {expiresIn : '1h'}) // save in cookie .
res.cookie("refreshToken", refreshToken)
res.status(200).send({data:{"accessToken": accessToken}, message:'ok'})
}
}
This seems to me rather than misunderstanding how password hashing works you don't understand the data in your database.
I'd suggest to get a visual database explorer for whatever database you're trying to use. There are many free and opensource ones out there!

Related

msql query not returning data even though it exists

I am trying to make a login form. I send the data from frontend like seen here:
const username = loginform.username.value.trim();
const password = loginform.password.value.trim();
console.log(username, password)
Axios.post(apiUrlEndpont, {
username: username,
password: password,
}).then((res) => {
if(res.data.err){
console.log(res.data.err)
} else {
console.log(res)
}
})
I get the username and password successfully. But the SQL query won't work for some reason which I don't recognize.
export default async function handler(req, res) {
const dbConnection = await mysql.createConnection({
host: "localhost",
database: "testapp",
user: "root",
password: "",
socketPath: ""
})
if (req.method === 'POST') {
const username = req.body.username
const password = req.body.password
console.log(username, password)
dbConnection.query(`SELECT password FROM accounts WHERE username = '${username}'`)
.then((err, rows, fields) => {
console.log("asd")
if(rows.length!=0){
var password_hash=rows[0]['password'];
const verified = bcrypt.compareSync(password, password_hash);
if(verified){
res.send(rows[0])
res.end()
} else {
res.send({err: "Invalid password"})
res.end()
}
}else{
res.send({err: "Invalid username password"})
res.end()
}
})
}
}
rows will return undefined even though the username exists in the database.
I am a newbie with node and mysql so please be patient
can you change your code like this and try.
sequelize.query(`SELECT password FROM accounts WHERE username = '${username}'`)
.then(([rows]) => {
console.log(rows);
...
})

Strange nodejs behaviour when logging in a user

The problem is that it shows that it is successfully logged in (201) without the redirect code, but with it, it shows a 302 error and the email_address is undefined.
What could be the problem here? I still can't come to a conclusion.
The problem may be in the order of the code I guess?
const login = async (req, res, next) => {
const { email_address, password, user_email, user_password}: { email_address: string, password: string, user_email: string, user_password: string } = req.body;
try {
const userWithDetails = 'SELECT * FROM users WHERE email_address = user_email AND password = user_password'; //w form info
if (userWithDetails) {
req.session.loggedin = true; //true
req.session.email_address = email_address; //undefined
console.log(req.session.email_address)
// return res.redirect('./index.html')
}
res.status(201).send('Succesfully signed in');
// res.status(403).send('Password is not correct');
} catch(error) {
res.status(404).send(`User with email ${email_address} not found!`);
}
await next;
};
NEW CODE ***
const login = async (req, res, next) => {
const { email_address, password}: { email_address: string, password: string} = req.body;
const userWithDetails = 'SELECT * FROM users WHERE email_address = ?';
return con.query(userWithDetails, email_address, (err, results) => {
if (err) {
console.error(err);
}
const user = results.find(emailObj => emailObj.email_address === email_address);
if (results && results.length && user.email_address) {
req.session.loggedin = true;
req.session.email_address = email_address;
const matchPassword: boolean = bcrypt.compareSync(password, user.password);
if (matchPassword) {
const token = jwt.sign({ user }, 'aaaa', { expiresIn: '1h'});
res.status(200).send({message: 'Logged in', token: token});
} else {
res.status(403).send('Password is not correct');
}
} else {
res.status(404).send(`User with email ${email_address} not found!`);
}
});
await next;
}
You don't execute your sql query at any point.
You just say :
query = 'select blabla'
if(query){...}
Of course this will always be true. You want to run the query on your database.
Also in your query you don't properly use the variables, see string formatting :
let my_var = `SELECT xxx from xxx where username = '${username}'`
Also please sanitize the parameters to prevent SQL Injection...

Why my password in the database is not equal to the password in the request body?

I try to make a login for my API in Nestjs, so when the user send the data through the request body, I catch the data and I use the query builder of typeorm, then I get the user with his properties, after comproving if user exists I create a new comparison block, I don´t know the reason why the code is not work, if I use https://bcrypt-generator.com/ for comparate the hash password in the database and the password of the request body, that throw true, but in my code it doesn't work
async login(userRO: UserRO) {
const { email, password } = userRO;
const user = await getRepository(User)
.createQueryBuilder('user')
.where('user.email = :email', {email})
.getOne();
if (!user) {
throw new HttpException(
'Usuario no es correcto',
HttpStatus.BAD_REQUEST,
);
}
// hashPassword = $2y$12$ZvWFRLVoS2gxyCjLkCbOZuN7NKfYrpT6cWxSJaeiVr0PnPBeoI8GS
// password = pepito09
const pass = await bcrypt.compare(password, user.password);
if (!pass) { // this always throw an error
throw new HttpException(
'Contraseña incorrecta',
HttpStatus.BAD_REQUEST,
);
}
const rol = await getRepository(Rol)
.createQueryBuilder('rol')
.select('rol.name')
.leftJoinAndSelect(User, 'user', 'user.rolId = rol.id')
.where('user.email = :email', { email })
.getOne();
if (!rol) {
throw new HttpException(
'Rol no encontrado',
HttpStatus.NOT_FOUND,
);
}
const type = this.typeUser(rol.name) ;
const payload = { email: user.email, id: user.id, rol: rol.name };
return {
access_token: this.jwtService.sign(payload),
type,
};
}
So, I expect the comparison block about the password throw true if the password in the database and the password in the request body are equals, and false if it doesn't.
At the moment, always throw true

Node.js "cannot set property firstName of undefined"

I am following this tutorial,
https://www.youtube.com/watch?v=OnuC3VtEQks
to create a login system for my node app, only thing is since he is using mongoDb and I'm using mySql, I had to think of a way around him setting up his mongoose schema (right around 7:14 of the video), so I just exported a user module and assigned properties to it in my create a user logic.
Here's the user module
//user.js in models
var bcrypt = require('bcryptjs');
var User = {
firstName: "firstName",
lastName: "lastName",
email: "email",
username: "username",
password: "password",
}
module.exports = User;
module.exports.createUser = function(newUser, callback){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, function(err, hash) {
newUser.password = hash;
newUser.save(callback);
});
});
}
Here is my route for the registration form
// main.js in router folder
var user = require('../models/user').User;
router.post('/register', function(req, res){
var firstName = req.body.firstName;
var lastName = req.body.lastName;
var email = req.body.email;
var username = req.body.username;
var password = req.body.password;
var cpassword = req.body.cpassword;
//Validation
// req.checkBody('firstName', 'First name is required!').notEmpty();
// req.checkBody('lastName', 'Last name is required!').notEmpty();
// req.checkBody('email', 'E-mail is invalid!').isEmail();
// req.checkBody('username', 'Username is required!').notEmpty();
// req.checkBody('password', 'Password is required!').notEmpty();
// req.checkBody('cpassword', 'Passwords do not match!').equals(password);
var errors = req.validationErrors();
if(errors){
res.render('register', {
errors: errors
});
console.log(errors);
} else {
var newUser = user;
newUser.firstName = firstName;
newUser.lastName = lastName;
newUser.email = email;
newUser.username = username;
newUser.password = password;
User.createUser(newUser, function(err, user){
if(err) throw err;
console.log(user);
});
req.flash('success_msg', 'You are now registered!');
res.redirect('login');
}
});
Now I keep getting "cannot set property firstName of undefined error", but I thought I had access to my User object from the user.js module? From what I can tell it looks like he's just using the form input to instantiate the user object and create it with some password hashing.
If this is a bad approach, I am completely open to any ideas to make this simpler. I am completely new to node and my senior project is due in 2 weeks, so any help will be immensely appreciated and rewarded with upvotes and internet credits :)
You should change your user.js as follows:
//user.js in models
var bcrypt = require('bcryptjs');
var User = {
firstName: "firstName",
lastName: "lastName",
email: "email",
username: "username",
password: "password",
}
module.exports = {
User: User,
createUser: function (newUser, callback) {
bcrypt.genSalt(10, function (err, salt) {
bcrypt.hash(newUser.password, salt, function (err, hash) {
newUser.password = hash;
newUser.save(callback);
});
});
}
}
This would solve all of your problems.
You declare (and export) the object User (with a capital U) earlier in the program, but later on try and access the variable user, which is undefined
var newUser = user;

How to add session and add access token to login in node

I have a login api as follows :
app.post('/login', function (req, res){
email = req.body.email;
password = req.body.password;
if(email && password )
{
console.log(email); //displays the email in the terminal
console.log(password); //displays the password in the terminal
var status = []; //array to output json
//connection.connect(); //mysql connection
connection.query('SELECT username FROM user WHERE email =? and password = ?',[email,password], function (error, rows, fields) {
if(rows.length == 1)
{
passport.serializeUser(function(res, done) {
done(null,res);
});
passport.deserializeUser(function(id, done) {
done(null,res);
});
status.push({username: rows[0].username});
username = rows[0].username;
console.log('sucessful login');
res.end('"status:"\n'+JSON.stringify(status)); //output as JSON
}
if(rows.length == 0)
{
connection.query('select * from temp_users where email = ? and password = ?',[email,password],function(error,rows,fields)
{
status = '';
if(rows.length == 1)
{
status = 'pending';
//res.end('Your Account needs to be verified');
res.end('"status:"'+JSON.stringify(status));
console.log('Your Account needs to be verified.');
}
else
{
status = 'error';
res.end('"status:"'+JSON.stringify(status));
//res.end('no such user.Please create an account');
console.log('no such user.Please create an account');
}
}
);
}
});
}
});
Now what i would like to do is to add a session for every user that logs in and make that session expire after some time.I would also like to have an access token to be inserted to my database once the user logs in.
Any help?
This example does exactly what you are looking for.
node.js express mysql passport