Nodejs, bcrypt , Mongoose - node.js

I'm very new to Nodejs / Mongo (with Mongoose). I'm using the bcrypt module to hash the password from a HTML form. In my db.create function, I'm not able to store the variable storehash in mongodb.
I don't get any errors but its just blank in the database. I have crossed check every other line of the code and it seems to be working. I don't understand why I'm not able to store a variable as "password: storehash" whereas I'm allowed to store something like "password: 'test' "
I'm sure I'm making some noob mistake somewhere. I'd appreciate any help!
var db = require('../models/users.js');
var bcrypt = require('bcryptjs');
module.exports.createuser = function(req,res){
var pass = req.body.password;
var storehash;
//passsord hashing
bcrypt.genSalt(10, function(err,salt){
if (err){
return console.log('error in hashing the password');
}
bcrypt.hash(pass, salt, function(err,hash){
if (err){
return console.log('error in hashing #2');
} else {
console.log('hash of the password is ' + hash);
console.log(pass);
storehash = hash;
console.log(storehash);
}
});
});
db.create({
email: req.body.email,
username: req.body.username,
password: storehash,
}, function(err, User){
if (err){
console.log('error in creating user with authentication');
} else {
console.log('user created with authentication');
console.log(User);
}
}); //db.create
};// createuser function

Your db.create should go right below console.log(storehash);, not after the bcrypt.salt.
When you put it after bcrypt.salt, what you do is: while you're generating salt for your password and then hashing the salted password, you're also storing stuff in your database using db.create. They are executed simultaneously, not sequentially. That's why, while you're hashing your password, you're also creating a user with db.create without a password.
In other words, it should be:
bcrypt.genSalt(10, function(err,salt){
if (err){
return console.log('error in hashing the password');
}
bcrypt.hash(pass, salt, function(err,hash){
if (err){
return console.log('error in hashing #2');
} else {
console.log('hash of the password is ' + hash);
console.log(pass);
storehash = hash;
console.log(storehash);
db.create({
email: req.body.email,
username: req.body.username,
password: storehash,
}, function(err, User){
if (err){
console.log('error in creating user with authentication');
} else {
console.log('user created with authentication');
console.log(User);
}
}); //db.create
}
});
});

Related

How to compare salted/hashed passwords from database correctly?

I've seen this asked before but in other languages (C# and PHP) but I am working through Javascript. I am storing a username and password onto my database but the password is being hashed via bcrypt.
I can store it correctly but I cannot pull it from my database and compare it correctly. It always console logs my 'password does not match' message.
This is my registration code that stores the username and password onto my database.
app.post('/register', function (req, res) {
var usernameCollection = mongoDBDatabase.collection('accounts');
username = req.body.username;
bcrypt.hash(req.body.password, saltRounds, function (err, hash) {
usernameCollection.insertOne({
personId: req.body.username,
username: req.body.username,
password: hash
}).then(function(data) {
if (data) {
//res.redirect('/' + username);
//window.location.href = "/" + username;
}
});
});
});
And here is my code where I am searching my database for the username and trying to compare the password to no avail.
//login page: storing and comparing email and password,and redirecting to home page after login
app.post('/login', function (req, res) {
var usernameCollection = mongoDBDatabase.collection('accounts');
var username = req.body.username;
var enteredPassword = req.body.password;
usernameCollection.findOne({
$or:[
{ username: username}
]
}).then(function(user){
if (user) {
console.log('That username was found in the database');
bcrypt.compare(enteredPassword, user.password, function(err, result){
if(result == true){
console.log('Password matches!');
res.redirect('/' + username);
}
else{
console.log('Password did not match');
res.redirect('/');
}
});
}
else{
console.log('The username ' + username + ' was NOT found in the database');
}
});
});
I just want to compare the stored password to the entered password and confirm they are the same to log the user in.

bcryptjs comparePassword always returns false - NodeJS

I have looked at the other answers to the question on here but still not getting anywhere. I cannot get the comparePassword function to return true
module.exports.createUser = function(newUser, callback) {
bcrypt.genSalt(10, function(err, salt){
bcrypt.hash(newUser.password, salt, function(err, hash){
newUser.password = salt;
newUser.save(callback);
});
});
};
module.exports.comparePassword = function(candidatePassword, hash, callback){
console.log("Provided password is " + candidatePassword);
console.log("Provided hash is " + hash);
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
if(err) throw err;
console.log(isMatch);
callback(null, isMatch);
});
}
So if we take the user in test at this stage you can see their data
{ _id: 5aec6f702a4a181f261a43fe,
full_name: 'Its me',
username: 'myusername',
email: 'myemail#gmail.com',
tel_number: '12345678',
password: '$2a$10$6GCgZDt.FL/eeZ1NsDASe.', // text version = test
__v: 0
}
When comparePassword is run the console logs return
Provided password is test
Provided hash is $2a$10$6GCgZDt.FL/eeZ1NsDASe.
So to me they match right?
Not sure what is going on here.
Could you try replacing the line newUser.password = salt; with newUser.password = hash; ?
And let us know if that works.
I have an example in my github repo, it might help
https://github.com/shirshendubhowmick/jwt-demo
Here is a snippet of the code from the repo
bcrypt.genSalt(10, (error, salt) => {
bcrypt.hash(user.password, salt, (error, hash) => {
user.password = hash;
next();
});
});

Prevent updating user's password if the input was left empty?

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!

How to validate password in passport-local-mongoose

I am using passport with passport-local-mongoose for register and login users.
This is the code I use to login users:
passport.use(new localStrategy({ usernameField: 'email' }, function(email, password, done) {
User.findOne({ email: email }, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username or password.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect username or password.' });
}
return done(null, user);
});
}));
Everything works fun but user.validPassword.
I define it in user model:
userSchema.methods.validPassword = function(password) {
// What should I write here?
};
Since hash password will be saved into database I do not know how to validate password.
For example this is one user saved into database{
"_id" : ObjectId("5901d55c30967512407cdcd0"),
"salt" : "7e76e1de50856c0a0e219c48609e0c86e8036bd4aa48e5161635f88dd19b695b",
"hash" : "eb78dcb7109454457b0709b6b49f322c69454930e3a6ca90621b1f38d4a068c46a34d0af8ba4f3cb3c3f9c8a30889f54028f182e1a038ab5d642e408117a93b34a519e594f62ea2209ef350f17d388e07476c021fdd66979e5752305b2f41571c830c4e03300cfbddce70443debee06d921900e1f7b9f024ea8d875553f01989e9267b01cc7e9da70f5ee39085527a55c8b6a9f5c7f21e07166797d5446322f52ec79c8e6bfd3e31d5f3953d86a13775da09f7ac3a5a85e5342cd35324bc66055030ca738fa657c50ec4368fe1fd4a26448b460996dc85ddebf90f92796f2b1adf9b905e0590efcadd8326053e354afcc144a155ca7ba1a0f1269cd2c5edec9ef4c643e5ca58310bf3283ed21bb94da6b22c113d19baf091f62bf1776fdcd4bca572cc114ec991d780c18524aad34988d0045f9a1d35e6cda4a6be337d7c8dce8256a240ecac9c7f4ac6c231a3c258f3660b5dd6daf4e67f878fbd9af9e52f9d36266828f564e6ac86f3aed98f7af0bb39017f6080e41cb49237bec6eae77253200750be14e53e79e3fc8d29a3a5cc774905e47bc8df6e5ae9f1b38d9ef738a7cc7890aba4bbea757c694df5faaeed2c692adcc9d8bb0242a5ced98c6a015f5b0b3b475b4a78767a1e9e3c6c9f1bc1be42a835f9e54de3ce223f6190ed457ea972ee4be6f506fd3995411d05247b7102c396c3a16b0d4c26664833d2224191cc",
"username" : "stve45",
"email" : "stebe#companycom",
"name" : "Steve",
"__v" : 0
}
I also use simple passport-local-authenticate.
Any help will be appreciate, thanks a lot.
If you are using passport-local-mongoose, it will create a salt and hash itself by taking your password. So that's why in your user schema you don't have to save the password field.
But the local strategy for passport-local-mongoose is quite different from normal passport local strategy. It is like
passport.use(new LocalStrategy(User.authenticate()));
This will check the entered password and will check it with the salt and hash.
The code you wrote is for normal local strategy. That should not use if you are using passport-local-mongoose.
This is how you should srialize and desirialize passport-local-mongoose:
passport.serializeUser(User.serializeUser());passport.deserializeUser(User.deserializeUser());
I assume you have a method for generating the salt and hash before saving.
In your validPassword method, you call the same method and compare the result from the user's password inout and compare it to what you have in the DB/ If it matches, then you are good.
As an alternative, there are libraries to manage this. I use bcrypt. See a sample here:
adminSchema.pre('save', function(next) {
var user = this;
// only hash the password if it has been modified (or is new)
if (!user.isModified('password')) {
return next();
}
// password changed so we need to hash it (generate a salt)
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if (err) {
return next(err);
}else{
// hash the password using our new salt
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) { return next(err); }
// override the cleartext password with the hashed one
user.password = hash;
next();
});
}
});
});
adminSchema.methods.comparePassword = function(password, cb) {
console.log('comparing password');
bcrypt.compare(password, this.password, function(err, isMatch) {
cb(err, isMatch);
});
};
Here is an example code.Please note that the User.findOne() function is far from being complete.It's there just for you to see where this code stands with respect to yours and to give you an idea of what changes should be made.
passport.use('local.signup', new LocalStrategy({
usernameField:'email', //it can be email or whatever one chooses
passwordField:'password',
confirmField:'password',
passReqToCallback:true//here is the trick.u pass everything you want to do to a callback
},function (req,email, password, done) {
req.checkBody('email','Invalid e-mail address...').notEmpty().isEmail().normalizeEmail();//validate email
req.checkBody('password','Invalid password...').notEmpty().isLength({min:8});//validate pass to be min 8 chars but you can provide it with checking for capital letters and so on and so forth
var errors = req.validationErrors();
if(errors){
var messages = [];
errors.forEach(function (error) {
messages.push(error.msg)
});
return done(null, false, req.flash('error', messages))
}
User.findOne({ email: req.body.email }, function (err, user) {
// Make sure user doesn't already exist
if (user) return done(null, false, {message:'The email address you have
entered is already associated with another account.'
});

NodeJS LDAP authentication using Passport and password encryption

I'm looking at PassportJS for authentication and have a login form with username and password. But if I look at the documentation, I see that the password is passed in clear text. Which means if anyone does a console.log(password), the password will be visible. How do I ensure the password submitted by login form is encrypted?
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
1) From the client to server
Use SSL.
2) From the server to disk / database
When creating the password, hash it first and save the hash to disk.
Later, when validating a user, compare the hash of the submitted password against the hash on disk.
From the passport-local examples it would look something like this if using bcrypt:
// Bcrypt middleware
userSchema.pre('save', function(next) {
var user = this;
if(!user.isModified('password')) return next();
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if(err) return next(err);
bcrypt.hash(user.password, salt, function(err, hash) {
if(err) return next(err);
user.password = hash;
next();
});
});
});
// Password verification
userSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if(err) return cb(err);
cb(null, isMatch);
});
};
Note: you'll need to use bcrypt or some other encryption module in addition to passport-local...but that's not super complicated and the example from the passport-local repo provides pretty much all you'll need to get started.

Resources