React NodeJS mySQL Can't login with password after Hashing - mysql

I've created a salt and a hash function to hash my password.
I'm trying to login with the original password and it won't let me, but if I try to log in with the hashed password from the database it will give me to log in.
const salt = "HashedPasswordCheck";
hash function:
function has(plainText: string):string{
if(!plainText) return null;
const hashedText = crypto.createHmac("sha512", salt).update(plainText).digest("hex");
return hashedText;
}
auth-logic.ts:
async function login(credentials:CredentialsModel):Promise<string>{
const error = credentials.validate();
if(error) throw new ValidationErrorModel(error);
const sql = `SELECT * FROM users WHERE username = ? AND password = ?`;
const users = await dal.execute(sql, [credentials.username, credentials.password]);
credentials.password = cyber.hash(credentials.password);
if (users.length === 0) throw new UnauthorizedErrorModel("Incorrect username or
password");
const user = users[0];
const token = cyber.getNewToken(user);
return token;
}
I tried to more the has before sending the query and still not working.
I checked this before and it was the same and worked but on this new project i'm working on it's not working properly.
credentials-model:
class CredentialsModel {
public username: string;
public password: string;
public constructor(credentials: CredentialsModel) {
this.username = credentials.username;
this.password = credentials.password;
}
public static validationSchema = Joi.object({
username: Joi.string().required().min(4).max(20),
password: Joi.string().required().min(4).max(50)
});
public validate(): string {
const result = CredentialsModel.validationSchema.validate(this);
return result.error?.message;
}
}
export default CredentialsModel;
auth-controller.ts:
// http://localhost:3001/api/auth/login
router.post("/auth/login", async (request: Request, response: Response, next:
NextFunction) => {
try {
const credentials = new CredentialsModel(request.body);
const token = await authLogic.login(credentials);
response.json(token);
}
catch(err:any){
next(err);
}
});
I didn't add a React code because it's a back end problem..
Thank you for any one that can help!

Found the issue.
I had 24 chars in my mySQL db, so it saved only part of the string and that's why I had an issue.
Solved by increasing the varchar amount on mySQL.

Related

Node.js help creating a function

I'm not sure what did i miss in my code.. I'm new on this
I have this code
helpers.encryptPassword = async (password) => {
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash(password, salt);
return hash;
};
module.export = helpers;
But when i execute this code
**newUser.password = await helpers.encryptPassword(password);**
it gives me an error, say "encryptPassword is not a function", but i don't know what am doing wrong
I understand that encryptPassword seems to store the result of a function with no name, but it is not a function. I need to change it, making possible to recive a parameter (the password, so bcrypt could hash it)
If You need all the code, there is it
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const pool = require ('../../database');
const helpers = require('../lib/helpers');
passport.use ('local.signup', new LocalStrategy({
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true
}, async (req, username, password, done) => {
const { fullname } = req.body;
const newUser = {
username,
password,
fullname
};
**newUser.password = await helpers.encryptPassword(password);**
const result = await pool.query('INSERT INTO users SET ?', [newUser]);
console.log(result);
}));

Bycrpt cannot compare and always sends null values

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!

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;