How to hash password with bcryptjs in node? - javascript

I recieve password through req.body and hash it like this :
const { name, email, password, number } = req.body;
let userExist;
userExist = await User.find({ email: email });
if (userExist.length) {
const err = new Error('User already exists');
return next(err);
}
let hashedPass;
try {
hashedPass = await bcrypt(req.body.password, 12);
} catch (e) {
console.log('error here bro');
return next(e);
}
const createdUser = new User({
name,
email,
password: hashedPass,
number,
ads: []
});
It console logs 'error here bro' and I dont know why .
How can I hash password coming from user with bcrypt js ?

You can also add salt to your password in the following way:
const salt = await bcrypt.genSalt(7);
const hashPassword = await bcrypt.hash(req.body.secret, salt);

Solved the problem by adding hash after bcrypt
bcrypt.hash(....)

Related

Bcrypt compare() always return false

I have used this code for comparison.
UserSchema.pre('save', async function() {
const salt = await bcrypt.genSalt(10)
this.password = await bcrypt.hash(this.password, salt)
})
UserSchema.methods.comparePassword = async function(candidatePassword) {
const isMatch = await bcrypt.compare(candidatePassword, this.password)
console.log(this.password);
console.log(candidatePassword);
return isMatch
}
I always get an invalid credentials error from the below login function. I have checked by logging the outputs. The problem lies with the compare password functionality.
const login = async(req, res) => {
const { email, password } = req.body
if (!email || !password) {
throw new CustomError.BadRequestError('Please provide email and password')
}
const user = await User.findOne({ email })
if (!user) {
throw new CustomError.UnauthenticatedError('Invalid Credentials')
}
const isPasswordCorrect = await user.comparePassword(password)
if (!isPasswordCorrect) {
throw new CustomError.UnauthenticatedError('Invalid Credentials')
}
if (!user.isVerified) {
throw new CustomError.UnauthenticatedError('Please Verify Your Email ')
}
const tokenUSer = createTokenUser(user)
attachCookiesToResponse({ res, user: tokenUSer })
res.status(StatusCodes.OK).json({ user: tokenUSer })
}
This might be helpful to someone,
I got the same errror while working with postgresql, I replaced the hash password variable with hardcoded hash string and it worked. So I console logged the user password retrieved from the database and noticed that whitespace was included in the result, the number of whitespace included when summed up with length of the user password gives the exact length precision of the password column, so you can either trim the user.password or redefine your database so that it doesn't include whitespace when queried.

Resolving bcrypt return promise

Im trying to pass the result of the bcrypt hashing function into the user model below.
I can't seem be able to wrap my head around how to efficiently resolve this promise.
Heres the code:
router.post("/", async (req, res) => {
req.body = sanitize(req.body);
// SHA-256
/* const bitArray = sjcl.hash.sha256.hash(req.body.data[2].value);
const passwordHashed = sjcl.codec.hex.fromBits(bitArray); */
const saltRounds = 10;
const password = req.body.data[2].value;
var passwordHashed;
async function hash() {
return await bcrypt.hash(password, saltRounds, function (err, hash) {});
}
const user = new User({
username: req.body.data[0].value,
email: req.body.data[1].value,
password: hash(),
});
try {
await user.save();
res.status(200).json({ msg: "Success" });
} catch (e) {}
});
That is what I have tried so far, which is probably wrong
Don't pass a callback to bcrypt.hash and then you can await it.
const user = new User({
username: req.body.data[0].value,
email: req.body.data[1].value,
password: await bcrypt.hash(password, saltRounds),
});

How do i Validate old password while updating user password?

What's the proper way to validate old user password while updating new password?
So far i have tried and always get error: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
What i did:
I tried using bcrypt to compare the old password from req.body with user existing password and then hash with bcrypt before saving. Comparing the password using bcrypt gave the error above. Not comparing the old password at all and just saving new password works properly.
My code:
exports.updatePassword = async (req, res) => {
try {
const { oldPassword, password } = req.body;
let updatedPassword = {
password: password,
};
const user = await User.findOneAndUpdate(
{ _id: req.params.userId },
{ $set: updatedPassword },
{ new: true, useFindAndModify: false }
);
// validate old password
bcrypt.compare(oldPassword, user.password, function (err, match) {
if (!match || err)
return res.status(400).send('Please enter correct old password');
});
//hash password and save user
bcrypt.genSalt(12, function (err, salt) {
bcrypt.hash(user.password, salt, (err, hash) => {
user.password = hash;
user.save();
return res.json({user});
});
});
} catch (err) {
console.log(err);
return res.status(400).send('Something went wrong. Try again');
}
};
The issue is that the updatePassword function is ending before you actually process everything. To avoid nested function calls and returns, use the async methods provided by bcrypt (also check their recomendation on using async vs sync).
Regarding the code itself, you are updating the user's password before checking if the password is valid. You should get the user from the db, check if the current password matches, and only then insert the new hashed password into the db.
exports.updatePassword = async (req, res) => {
const { oldPassword, password } = req.body;
try {
// get user
const user = await User.findById(req.params.userId);
if (!user) {
return res.status(400).send('User not found');
}
// validate old password
const isValidPassword = await bcrypt.compare(oldPassword, user.password);
if (!isValidPassword) {
return res.status(400).send('Please enter correct old password');
}
// hash new password
const hashedPassword = await bcrypt.hash(password, 12);
// update user's password
user.password = hashedPassword;
const updatedUser = await user.save();
return res.json({ user: updatedUser });
} catch (err) {
console.log(err);
return res.status(500).send('Something went wrong. Try again');
}
};

cannot compare password with bcrypt compare

Im trying to build a node api for change password,
User must type the currentPassword and the new password
when bcrypt.compare the new currentPassword with the stored on db, i got always false, whatever it's wrong or correct
const changePass = async (req, res, next) => {
//email and password
const CurrentPassword = req.body.currPassword
let password1 = ''+req.body.password1
let password2 = ''+req.body.password2
const hashedPassword = await bcrypt.hash(password1, 10);
let id = "" + req.body.id
User.findById( id )
.then(user => {
bcrypt.compare(CurrentPassword, user.password, (err, data) => {
if (err) throw err
if (data) {
User.findByIdAndUpdate(id, {password : hashedPassword }, {new: false}, (err) => {
if (err) throw err
})
} else {
return res.status(401).json({ msg: "Invalid" })
}
})
})
}
If you want to learn bcrypt I recommend you to visit bcrypt NPM because it will save you too much time later,
in your case I made some modification on your code in order to check for the current password OLD and then compare between the newPassword1 and the confirmation passwordConfirmation
feel free to use console.log('') when you have doubts about anything it will give you a good vision about your code status
const changePassword = async (req, res, next) => {
let id = req.body.nid;
if(id){
console.log('Im here')
const old = req.body.old;
const newP = req.body.newP;
const newP2 = req.body.newP2;
User.findById(id,(err,user)=>{
if(user){
console.log(user)
const hash = user.password;
bcrypt.compare(old,hash,function (err,res){
if(res){
if(newP === newP2){
bcrypt.hash(newP,10, (err,hash)=>{
user.password = hash;
user.save( (err,user) =>{
if(err) return console.error(err);
console.log(user.userName +' your password has been changed');
});
});
};
};
});
}
})
}
}

How do I properly chain Promises when both creating a new user and hashing their password?

I am trying to make a POST request that creates a new account. It first checks if there is already an account using that email. If there isn't, it then creates a new account and stores it in a user collection. It also does two things, it hashes the person's password and generates a token for that user when the account is created. Here is my code for my first attempt:
const bcrypt = require('bcryptjs');
const authentication = require('../controllers/authentication');
const express = require('express');
const passport = require('passport');
const passportService =require('../services/passport');
const config = require('../config/config');
const User = require('../model/user');
const router = express.Router();
const mongodb = require('mongodb');
const mongoose = require('mongoose');
mongoose.Promise = Promise;
router.post('/register', (req, res, next) => {
// I guess I will have to use this, and set this to true or false within findOne
let doesExist_ = undefined;
function generateUserToken(user){
return jwt.encode({sub: user._id, iat: timeStamp}, config.secretKey);
}
if (!req.body.email || !req.body.password) {
return res.status(442).send({error: 'Make sure that you entered your email and password'});
}
/// this doesn't return a boolean
User.findOne({email: req.body.email})
.then((err, user) => {
if (user !== null || user !== undefined){
doesExist_ = true;
console.log('in first Then, doesExist_ is ' + doesExist_);
}
else {
doesExist_ = false;
console.log('in first Then, doesExist_ is ' + doesExist_);
}
})
.then(() => {
console.log('in second Then, doesExist_ is ' + doesExist_);
if (!doesExist_){
let password = req.body.password;
bcrypt.genSalt(10, function(err, salt){
bcrypt.hash(password, salt, function(err, hash){
if (err) throw err;
password = hash;
})
}).then(() => {
User.create({
username: req.body.username,
password: password,
name: req.body.name,
email: req.body.email,
profilePic: req.body.profilePic,
/// userId: userid
}).then((user) => {
res.json({token: generateUserToken(user)});
})
});
}
else {
return res.status(422).send({error: "Email is already in use"});
}
})
.catch((err) => {
console.log(err);
});
});
However, it isn't working, every time I try to create a new User, it fails to do so. Postman takes three minutes to process the request and when I check Robomongo afterwards, the user I just created is not in the collection.
I also wrote a second version of this making use of promises. I thought maybe the problem was that I needed to make my code wait for bcrypt to hash the password, then I could create and save the entry to the database:
const bcrypt = require('bcryptjs');
const authentication = require('../controllers/authentication');
const express = require('express');
const passport = require('passport');
const passportService =require('../services/passport');
const config = require('../config/config');
const User = require('../model/user');
const router = express.Router();
const mongodb = require('mongodb');
const mongoose = require('mongoose');
mongoose.Promise = Promise;
router.post('/register', (req, res, next) => {
// I guess I will have to use this, and set this to true or false within findOne
let doesExist_ = undefined;
function generateUserToken(user){
return jwt.encode({sub: user._id, iat: timeStamp}, config.secretKey);
}
if (!req.body.email || !req.body.password) {
return res.status(442).send({error: 'Make sure that you entered your email and password'});
}
/// this doesn't return a boolean
User.findOne({email: req.body.email})
.then((user) => {
/// this should be null if it doesn't exist
if (user !== null){
doesExist_ = true;
console.log('in first Then, user is...' + user);
console.log('in first Then, doesExist_ is...' + doesExist_);
}
else {
doesExist_ = false;
console.log('in first Then, doesExist_ is ' + doesExist_);
}
})
.then(() => {
console.log('in second Then, doesExist_ is ' + doesExist_);
if (!doesExist_){
let password = req.body.password;
let hashedPassword;
bcrypt.genSalt(10, function(err, salt){
bcrypt.hash(password, salt, function(err, hash){
if (err) throw err;
hashedPassword = hash;
console.log('hashedPassword is now...' + hashedPassword + ' and the hash is...' + hash);
})
});
let hashPromise = () => {
return new Promise ((resolve, reject) => {
if (hashedPassword !== undefined && hashedPassword !== null){
console.log('Within hashPromise, hashedPassword is...' + hashedPassword);
resolve();
}
else {
console.log('Within hashPromise, hashedPassword is...' + hashedPassword);
reject('hashedPassword is still undefined');
}
});
};
hashPromise().then(() => {
User.create({
username: req.body.username,
password: hashedPassword,
name: req.body.name,
email: req.body.email,
profilePic: req.body.profilePic,
/// userId: userid
}).then((user) => {
res.json({token: generateUserToken(user)});
})
});
}
else {
return res.status(422).send({error: "Email is already in use"});
}
})
.catch((err) => {
console.log(err);
});
However, I am still running into the same problems with this version. It is running for a long ass time in Postman, and when the server times out, I still don't have the entry added to the collection. Am I chaining the promises correctly in this approach?
When I run this version I get this console log:
in first Then, doesExist_ is false
in second Then, doesExist_ is false
Within hashPromise, hashedPassword is...undefined
(node:8684) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): hashedPassword is still
undefined
hashedPassword is now...$2a$10$2VQ6AlaEgnrCvt8udshnZe/auswqawe8eZ1f5IXESmKmQVEI7nYNa and the hash is...$2a$10$2VQ6Al
aEgnrCvt8udshnZe/auswqawe8eZ1f5IXESmKmQVEI7nYNa
Before Bcrypt finishes hashing the password, I get the console.log from my Promise. Is the console.log an indicator that the Promise is not working? The Promise is supposed to be resolved once the variable hashedPassword is no longer undefined after bcrypt finishes hashing it. But it doesn't appear to be running as I intended.
Any tips as to how I can fix either versions? Am I doing too much in a single request given that I am also generating a token as well?
Any help would be greatly appreciated.
The standard bcrypt library does not return a promise - if you want to work with promises, you could use bcrypt-promise.
If you want to use the standard bcrypt lib, you'll have to work in the callback:
User.findOne({email: req.body.email})
.then((user) => {
if (user !== null){
bcrypt.genSalt(10, function(err, salt){
bcrypt.hash(password, salt, function(err, hash) {
// this is the function bcrypt calls when it's done
if (err) throw err;
User.create({
username: req.body.username,
password: hashedPassword,
name: req.body.name,
email: req.body.email,
profilePic: req.body.profilePic,
/// userId: userid
}).then((user) => {
res.json({token: generateUserToken(user)});
});
});
});
}
});
(reduced example to show nesting - you'll still need to handle your errors and stuff)
alternatively - because callbacks get nested deep really quickly, you can of course create an extra function and give that to bcrypt as a callback:
var afterHash = function(err, hash){
if (err) throw err;
User.create({
username: req.body.username,
password: hashedPassword,
name: req.body.name,
email: req.body.email,
profilePic: req.body.profilePic,
/// userId: userid
}).then((user) => {
res.json({token: generateUserToken(user)});
});
};
User.findOne({email: req.body.email})
.then((user) => {
if (user !== null){
bcrypt.genSalt(10, function(err, salt){
bcrypt.hash(password, salt, afterHash);
});
}
});
I am currently learning how to use mongoose and I did not get to learning about hashes yet but I glimpsed at the docs and I think you are not using the methods correctly ...
first of all mongo docs say that findone (queries) don't return a promise but have a then() function
I would try something like :
User.findOne({email: req.body.email}).exec()
.then((user) => {
/// this should be null if it doesn't exist
if (user !== null){
doesExist_ = true;
console.log('in first Then, user is...' + user);
console.log('in first Then, doesExist_ is...' + doesExist_);
}
else {
doesExist_ = false;
console.log('in first Then, doesExist_ is ' + doesExist_);
}
})
or:
User.findOne({email: req.body.email})
.then((user) => {
doesExist_ = true;
console.log(user);
console.log('in first Then, doesExist_ is...' + doesExist_);
},(err) =>
{
doesExist_ = false;
console.log(err);
console.log('in first Then, doesExist_ is ' + doesExist_);
}
)
second of all bcrypt's genSalt() and hash() return a promise If the callbacks are omitted ...
Hope I was of help ...

Categories

Resources