Bcrypt Not Saving? - PassportJS - node.js

For some reason the code below does not save to the database? Can anyone tell me why this will not work to save a user's new password using PassportJS?
UserSchema.pre('save', function(next) {
var user = this;
var SALT_FACTOR = 5;
if (!user.isModified('password')) return next();
bcrypt.genSalt(SALT_FACTOR, function(err, salt) {
if (err) return next(err);
bcrypt.hash(user.password, salt, null, function(err, hash) {
if (err) return next(err);
user.password = hash;
next();
});
});
});

Related

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.

Node.js hash updated password

Well, i have simple user edit in node,express,mongodb. But i am unable to hash password to bcrypt. In registration works everything allright but that was tutorial...
Here is part of my routes/users.js
Everything is updated but password is not hashed and i dont know what to do.
router.post("/profile", function (req, res) {
let user = {};
user.firstname = req.body.firstname;
user.lastname = req.body.lastname;
user.email = req.body.email;
user.password = req.body.password;
user.password2 = req.body.password2;
req.checkBody("firstname", "Firstname is required").notEmpty();
req.checkBody("lastname", "Lastname is required").notEmpty();
req.checkBody("email", "Email is required").notEmpty();
req.checkBody("email", "Email is not valid").isEmail();
req.checkBody("password", "Password is required").notEmpty();
req
.checkBody("password", "Password must be longer then 8 chars bitch")
.len(8, 64);
req
.checkBody("password2", "Passwords do not match")
.equals(req.body.password);
var errors = req.validationErrors();
if (errors) {
res.render("profile", {
errors: errors
});
} else {
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(user.password, salt, function(err, hash) {
user.password = hash;
});
});
let query = {_id:req.user.id}
User.update(query, user, function(err){
if(err){
console.log(err);
return;
} else {
res.redirect('/');
}
});
}});
Here is my hasing for registration in models/users.js that i was inspired by.
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);
});
});
};
I will be thankfull for any help.
Well after hous its solved.
I just changed it to.
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(user.password, salt, function(err, hash) {
user.password = hash;
let query = {_id:req.user.id}
User.update(query, user, function(err){
if(err){
console.log(err);
return;
} else {
res.redirect('/');
}
});
});
});
}});

How can I use or create an onupdate middleware using mongoose schema?

With mongoose we can use some middlewares when we manipulate data. For example, this is a famous use of the save middleware:
Schema.pre('save', function(next){
const user = this;
if (!user.isModified('password')) {
return next();
}
bcrypt.genSalt(10, (err, salt) => {
if (err) {
next(err);
}
bcrypt.hash(user.password, salt, null, (err, hash) => {
if (err) {
next(err);
}
user.password = hash;
next();
});
});
});
I would like to know how to do the same when you try to update some records. I read in several forums that can use: Schema.pre('update'), I've tried but it doesn't work for me. The idea is to re-encrypt the new password when the user wants to change it. I know than I could do this in the controller, but I would like to take away that responsibility and do it from the schema.
The result must be something like:
Schema.pre('onUpdate', function(next){
const user = this;
if (!user.isModified('password')) {
return next();
}
bcrypt.genSalt(10, (err, salt) => {
if (err) {
next(err);
}
bcrypt.hash(user.password, salt, null, (err, hash) => {
if (err) {
next(err);
}
user.password = hash;
next();
});
});
});
I know this doesn't actually answer the question but if your use-case is to update the password only, you can use the following:
let userDetails = await User.findOne({ userID: userIDFromRequest });
userDetails.password = request.newPasswordFromRequest;
await userDetails.save();
Without having to worry about the hashing.
Also, if you really need the update hook try the code below (Not tested):
UserSchema.pre('update', function(next) {
let update = this._update;
if (update.$set && update.$set.password) {
this.update({}, { password: generateHash(update.$set.password) });
}
next();
});
You can read more here: http://mongoosejs.com/docs/middleware.html#notes

mongoose password gets hashed twice

I am new to Mongoose and Node JS, and have this problem with password being hashed again after a user is updated.
Here is the code for hashing:
UserSchema.pre('save', function (next) {
var user = this;
bcrypt.hash(user.password, 10, function (err, hash) {
if (err) {
return next(err);
}
user.password = hash;
next();
})
});
and this is for updating the user
router.post('/insert', function (req, res) {
User.findById(req.session.userId, function (err, user) {
if (err) { throw err; }
if (user) {
user.patients = req.body.patients
user.diagnosis_list = req.body.diagnosis_list
user.medicine_dose_list = req.body.medicine_dose_list
user.medicine_list = req.body.medicine_list
user.save(function (err) {
if (err) throw err;
res.send(user.toJSON());
})
}
})
})
I understand that presave has to be prevented to be called on updating the user, I just have no clue how to do that. Is there some other way I can update the user without having presave being called maybe?
if (!user.isModified('password')) {
return next();
}
bcrypt.hash(user.password, 10, function (err, hash) {
if (err) {
return next(err);
}
user.password = hash;
next();
})
http://mongoosejs.com/docs/api.html#document_Document-isModified

Save password hash only when password is present

I have a form where users can create a room with an optional password field. I want to save the password only if the password field contains something ( is not empty). I have hash middleware that hash the password before saving it to mongodb. Even if the password field is empty it is saving a hash value. I tried to add a condition to check if there is a value only then to proceed with the hashing but this does not seem to work.
Here is my post :
exports.postCreateRooms = function(req, res, next) {
req.assert('workspace', 'Please enter a board name').notEmpty();
var errors = req.validationErrors();
var enableVideo;
if (errors) {
req.flash('errors', errors);
return res.redirect('/dashboard');
}
var url = uuid.v4();
var room = new Room({
roomUrl: url,
roomName: req.body.workspace,
owner:req.user._id,
ownerEmail:req.user.email,
dateCreated: Date(),
lastUpdated: Date(),
users: [req.user._id]
});
if (req.body.password != ''){
room.password = req.body.password;
}
room.save(function(err) {
if (err) {
return next(err);
}
res.redirect('/board='+room.roomUrl);
});
};
here is my hash middleware :
roomSchema.pre('save', function(next) {
var room = this;
if(room.password){
bcrypt.genSalt(10, function(err, salt) {
if (err) {
return next(err);
}
bcrypt.hash(room.password, salt, null, function(err, hash) {
if (err) {
return next(err);
}
room.password = hash;
next();
});
});
}
});
What happens when you have the check in place?
From what I can see, you need a next() call outside of your if block in the middleware, so it knows to proceed even if there isn't a password specified.
It would look like
roomSchema.pre('save', function(next) {
var room = this;
if(room.password){
return bcrypt.genSalt(10, function(err, salt) {
if (err) {
return next(err);
}
bcrypt.hash(room.password, salt, null, function(err, hash) {
if (err) {
return next(err);
}
room.password = hash;
next();
});
});
}
next();
});

Resources