Update password in database mongodb, mongoose - node.js

I have this route
router.patch("/me/update-password", authenticate, (req, res) =>{
let newPassword = _.pick(req.body, 'password');
const newP = newPassword.password;
User.findByCredentials(req.user.username, req.user.password).then((user) => {
user.password = newP;
user.save().then(() => {
res.send(user);
}).catch((e) => {
res.status(400).send(e);
});
});
});
/////////////////////////////////////////////////////////////////////////////
UserSchema.statics.findByCredentials = function (username, password) {
var User = this;
return User.findOne({username}).then((user) => {
if (!user) {
return Promise.reject();
}
return new Promise((resolve, reject) => {
// Use bcrypt.compare to compare password and user.password
bcrypt.compare(password, user.password, (err, res) => {
if (res) {
resolve(user);
} else {
reject();
}
});
});
});
};
//////////////////////////////////////////////////////////////////
UserSchema.pre('save', function (next) {
let user = this;
if (user.isModified('password')) {
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(user.password, salt, (err, hash) => {
user.password = hash;
next();
});
});
} else {
next();
}
});
I find the username and password of the authenticated user and then I want to send a new password which I save as newP.
I want to update the password hash and salt it and then save, so I tried with the method user.save() which hashes and salts the password. But when I send a patch request it wont`t finish.
Does anybody know why ?
I tried everything but I am stuck.

Related

Express routes not sending response Heroku-Postgres code H12

I'm having an issue with my routes not sending responses to the frontend. I only have 3 routes so far, only two send responses, but neither are doing so. I am using node-postgres(pg). My register route seems to be working because when I register a user, it is reflected in the database. Here are the two routes in question.
// login
app.post('/api/v1/login', checkInput, async (req, res, next) => {
console.log(req.body)
try {
// find user
db.query(`SELECT * FROM users WHERE username = $1`, [req.body.username], async (err, user) => {
if (err) throw err;
// user not found
if (!user) {
res.send({message: 'error'});
} else {
// compare passwords
const matchedPassword = await bcrypt.compare(req.body.password, user.password);
// password doesn't match
if (!matchedPassword) {
res.send({message: 'error'});
} else {
// user found
req.session.user = user.username;
req.session.auth = true;
res.send({message: 'success'});
}
}
})
} catch (error) {
next(error);
}
});
// register
app.post('/api/v1/register', checkInput, async (req, res, next) => {
console.log(req.body)
try {
// check if user already exists
db.query(`SELECT username FROM users WHERE username = $1`, [req.body.username], (err, user) => {
if (err || user) {
res.send({message: 'error'});
}
});
// user doesn't exist so create user
// encrypt password
const salt = await bcrypt.genSalt(3);
const hashPassword = await bcrypt.hash(req.body.password, salt);
db.query(`INSERT INTO users (username, password) VALUES ($1, $2)`, [req.body.username, hashPassword], (err, user) => {
if (err) {
res.send({message: 'error'});
} else {
res.send({message: 'success'});
}
});
} catch (error) {
next(error);
}
});
Any help would be appreciated!

Hashing password not working after using await

I am trying to hash a password after updating it but I dont understand why it is just working after the await line. In the res.json I get the hashed password, but just there.
I am new to this so I appreciate any help or advice.
router.put('/:id', async (req, res) => {
let { mail, password } = req.body;
bcrypt.genSalt(saltRounds, function (err, salt) {
if (err) return next(err);
bcrypt.hash(password, salt, function (err, hash) {
if (err) return next(err);
password = hash;
});
});
const newUser = { mail, password };
await User.findByIdAndUpdate(req.params.id, newUser);
res.json({ mensaje: `Updated Password ${password}` });
});
As per my comment, you should look into async/await and callbacks more to understand the call order. As it's not running in the sequential fashion you think it is. But you can try the following.
router.put('/:id', async (req, res) => {
let { mail, password } = req.body;
try{
const salt = await bcrypt.genSalt(saltRounds);
const hashedPassword = await bcrypt.hash(password, salt);
const newUser = { mail, password };
await User.findByIdAndUpdate(req.params.id, newUser);
res.json({ mensaje: `Updated Password ${password}` });
} catch(error) {
res.json(error);
}
});

Bcrypts compare and authenticate function authenticate any password

I'm using bcrypt to authenticate the users in my system. When i register an user, with the code:
UserSchema.pre("save", async function(next) {
var user = this;
if (user.isModified('password')) {
var salt = bcrypt.genSaltSync(10);
await bcrypt.hash(user.password, salt, null, function(err, hash) {
if(err){
console.log(err);
}else {
user.password = hash;
}
});
}
next();
});
Ok, the hash is created and save in mongo. My problema is, when i log in with this user, any password works. Here's is my compare function:
UserSchema.methods.authenticate = async function(password) {
var user = this;
var isAuthenticaded = await bcrypt.compare(password, user.password,
function(err, res){
if(res){
return true;
}else{
return false;
}
});
return isAuthenticaded;
};
I call the function 'authenticate' with passport:
if (!user.authenticate(password)) {
return done(null, false, {message: 'Senha inválida.'});
}
Someone could help?
[EDIT] - I think the problem is asynchronous calls. Modified to syncrhonous and it works! I will apreciate if someone discover where is the problem with asyncrhonous calls
About async implementation.
UserSchema.pre('save', async function save(next) {
if (!this.isModified('password')) return next();
try {
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
return next();
} catch (err) {
return next(err);
}
});
UserSchema.methods.authenticate = async function(password) {
return bcrypt.compare(password, this.password);
};
And now, if user using our async authentication method, we have to await for result.
if (!await user.authenticate(password)) {
return done(null, false, {message: 'Senha inválida.'});
}
You can read more about pre.

Bcrypt.compare() returning only false, Used Under Promises

I am using Bcrypt for hashing passwords and storing it in the database,
Bcrypt is returning false, when I retrieve the hashed password from the database, and compare with the typed user password.
I am using it under Promise, but bcrypt is returning false on the correct password
Here is the code:
userSchema.statics.findByCredentials = function(email, password) {
const User = this;
return User.findOne({email}).then((user) => {
if(!user) {
return Promise.reject();
}
// console.log(user.password);
return new Promise((resolve, reject) => {
bcrypt.compare(password, user.password, (err,res) => {
if(res) {
resolve(user);
}
else {
reject("Problem here");
}
console.log(res);
});
});
});
};
I am trying promise chain to the main file i.e server.js and return the details to the user, but it's not working.
Here is the route code of express:
app.post('/users/login', (req, res) => {
const body = _.pick(req.body, ['email', 'password']);
// res.send(body);
User.findByCredentials(body.email, body.password)
.then((user) => {
res.send(user);
}).catch((e) => res.send(e));
});
Thanks
Have you tried using the promise api for bcrypt?
It might look like this:
userSchema.statics.findByCredentials = function(email, password) {
const User = this;
return User.findOne({email}).then((user) => {
if(!user) {
return Promise.reject();
}
// console.log(user.password);
return bcrypt.compare(password, user.password)
.then(res => {
if (res) {
return user;
}
throw new Error('Problem here');
});
});
}
If not, you might be getting an error, so you could check the err argument to see if something came back from there. Other than that, as long as user.password is the hashed version of the original password, then it should be working.

How to use bcrypt.compare in mongoose model?

I am trying to implement the login function in my express API. Below are my controller and the model functions related to the authentication process.
auth.controller
import User from '../models/user.model';
import jwt from 'jsonwebtoken';
import dotenv from 'dotenv';
dotenv.config({path: './src/.env'});
const jwtSecret = process.env.JWT_SECRET;
function login(req, res, next) {
var username = req.body.username;
var password = req.body.password;
User.login(username, password)
.then(user => {
if (user) {
const token = jwt.sign({
userId: user._id
}, jwtSecret);
res.json({
token,
username: user.userName
});
}
res.send('No such user exists!');
})
.catch(e => next(e));
}
export default { login };
user.model
userSchema.statics = {
list() {
return this.find().exec();
},
login(username, password) {
var queryPromise = this.findOne({ "userName": username }).exec();
queryPromise.then(function(user) {
bcrypt.compare(password, user.password, function(err, isMatch){
if (err) throw err;
console.log('Is password match :', isMatch);
if (isMatch) {
return;
}
});
});
}
}
Here's the error I'm getting
TypeError: Cannot read property 'then' of undefined
Can someone tell me what I'm doing wrong here?
The login method should return a Promise if you want to use .then
login(username, password) {
return new Promise((resolve, reject) => {
var queryPromise = this.findOne({ "userName": username }).exec();
queryPromise.then(function(user) {
bcrypt.compare(password, user.password, function(err, isMatch) {
if (err) throw err;
console.log('Is password match :', isMatch);
if (isMatch) {
return resolve(user); // pass the user if you want to access it in the .then statement
} else {
return reject(new Error('Invalid Credentials'));
}
});
});
})
}

Resources