this is my code for hashing password and for compare existing password into existing module with a password that has been sended on body request:
//hash password of document that use this schema
bcrypt.hash(user.password, null, null, function (err, hashed) {
if (err) {
throw err;
} else {
user.password = hashed;
//next api
next();
}
})
});
userSchema.methods.comparePassword = function (password) {
//refer at userSchema
var user = this;
//return method of bcryot library that compare two string: original password and password hashed
return bcrypt.compareSync(password, user.password);
};
But compare this error message:
Uncaught, unspecified "error" event. (Not a valid BCrypt hash.)
Resolved !!! Into the database i have a lot of user's password not hashed and when i try to login, with bcrypt.compareSync (password, user.password); it expected that has been hashed password.
You're using null twice. I'd wager that you've wrapped this function inside the bcrypt.genSalt function(if you haven't , do so). You need to pass it the bcrypt salt where the first null is written.
Here's a full example:
userSchema.pre('save', function (next) {
const SALTROUNDS = 10; // or another integer in that ballpark
const user = this;
if(!user.isModified('password')) {
return next();
}
bcrypt.genSalt(SALTROUNDS, (err, salt) => {
if (err) { return next(err); }
bcrypt.hash(user.password, salt, null, (error, hash) => {
if (error) { return next(error); }
user.password = hash;
next();
});
});
});
Related
I do not know if the exact request in title is possible, but if not; i would really appreciate an alternate solution.
I have this pre save method of mongoose
ownerSchema.pre("save", function(next) {
const owner = this;
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(owner.password, salt, function(err, hash) {
// Store hash in your password DB.
owner.password = hash;
next();
});
});
});
When i save new user(owner) a hash is created successfully and all is good>
The problem occurs when i login. when i login i generate jwt with a mongoose custom method as below
ownerSchema.methods.generateToken = function(cb) {
var owner = this;
var token = jwt.sign(
{
_id: owner._id,
username: owner.username,
email: owner.email,
category: owner.category === 0 ? false : true,
phones: owner.phones,
address: owner.address
},
config.SECRET,
{ expiresIn: "1h" }
);
owner.token= token;
owner.save(function(err,owner){
if(err) return cb(err);
cb(null,owner);
})
};
as you see i generate token to send it in "res" and at the same time i add the new token to the record in the data base. all working fine till now and the response is returned successfully>
BUT!! while i performed save() in the generate token function to save the token>> the previous pre(save) function ran again, so that a new hash is generated for the password feild.
when i try to login again, the password had already changed from calling the pre save hashing function when generating the token in the first login.
Any workaround for solving this issue?
You could use isModified method on your 'password' field.
I use it in this way, only run bcrypt if the password property was changed:
UserSchema.pre('save', function (next) {
var 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 do not know if the exact request in title is possible, but if not; i would really appreciate an alternate solution.
I have this pre save method of mongoose
ownerSchema.pre("save", function(next) {
const owner = this;
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(owner.password, salt, function(err, hash) {
// Store hash in your password DB.
owner.password = hash;
next();
});
});
});
When i save new user(owner) a hash is created successfully and all is good>
The problem occurs when i login. when i login i generate jwt with a mongoose custom method as below
ownerSchema.methods.generateToken = function(cb) {
var owner = this;
var token = jwt.sign(
{
_id: owner._id,
username: owner.username,
email: owner.email,
category: owner.category === 0 ? false : true,
phones: owner.phones,
address: owner.address
},
config.SECRET,
{ expiresIn: "1h" }
);
owner.token= token;
owner.save(function(err,owner){
if(err) return cb(err);
cb(null,owner);
})
};
as you see i generate token to send it in "res" and at the same time i add the new token to the record in the data base. all working fine till now and the response is returned successfully>
BUT!! while i performed save() in the generate token function to save the token>> the previous pre(save) function ran again, so that a new hash is generated for the password feild.
when i try to login again, the password had already changed from calling the pre save hashing function when generating the token in the first login.
Any workaround for solving this issue?
You could use isModified method on your 'password' field.
I use it in this way, only run bcrypt if the password property was changed:
UserSchema.pre('save', function (next) {
var 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'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.
I'm struggling to prevent updating user's password in database if the password input was left empty.
Here is the route responsible for updating user data:
router.put('/update', passport.authenticate('jwt', {session: false}), (req, res) => {
let user = req.user;
user.firstname = req.body.firstname;
user.lastname = req.body.lastname;
user.username = req.body.username;
user.email = req.body.email;
user.password = req.body.password || null;
User.updateUser(user, (err) => {
if (err) {
res.json({
success: false,
message: 'User details couldn\'t be updated.'
});
} else {
res.json({
success: true,
message: 'User updated'
});
}
});
});
And here is the User model method which generates a hash of a password and saves the new data in the database:
module.exports.updateUser = function (user, callback) {
if (user.password) {
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(user.password, salt, (err, hash) => {
if (err) throw err;
user.password = hash;
});
});
}
user.save(callback);
};
I check if the password value was given but I don't know how to keep the old encrypted password in the database if there is no new value given for the password. If user doesn't fill the password input, it is being saved as null, as expected though...
I hope there is an approach to achieve this, I just can't figure out at the moment as I'm a beginner.
Thank you in advance!
I guess that you are using Mongoose to communicate with the Database.
Change this Line of your code :
user.password = req.body.password || null;
with this :
if(req.body.password != null) {
user.password = req.body.password
}else{
/* find each user with a last name matching 'user.userame', selecting
/*the `password` field and returning the result in 'usr'
*/
User.find({'username' : user.username}, 'password', function (err, usr) {
if (err) return handleError(err);
user.password = usr.password;
})
}
Based on #Neil Lunn's suggestion about checking the documentation, I came up with a solution. I changed the updateUser method to this:
module.exports.updateUser = function (user, callback) {
if (user.password) {
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(user.password, salt, (err, hash) => {
if (err) throw err;
user.password = hash;
user.save(callback);
});
});
} else {
User.findById(user.id).update({
username: user.username,
email: user.email,
firstname: user.firstname,
lastname: user.lastname
}, callback);
}
};
If the password is present, then update everything as is, if no password provided, then update only the needed fields except the password.
Maybe this is not the best solution, but it works for now.
Thank you!
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();
});