I am using a password verification based on this demo http://devsmash.com/blog/password-authentication-with-mongoose-and-bcrypt and for some reason the method is not attaching to my 'user' return, resulting in an error
Here is my code...
module.exports = function (app, mongoose, config, passport) {
var bcrypt = require('bcrypt')
var SALT_WORK_FACTOR = 10;
var UserSchema = new mongoose.Schema({
name: { type: String },
password: { type: String, required: true },
email: {
type:String,
lowercase: true,
required: true,
unique: true
}
});
var _User = mongoose.model('user', UserSchema);
// 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);
});
};
return {
User : _User,
isValidUserPassword : function(auth, done) {
_User.findOne({email : auth.body.username}, function(err, user){
// if(err) throw err;
if(err) return done(err);
if(!user) return done(null, false, { message : 'Incorrect email.' });
user.comparePassword(auth.body.password, function(err, isMatch) {
if (err) throw err;
console.log('Password123:', isMatch); // -> Password123: true
});
});
}
}
}
The problem with your code is that it calls
var _User = mongoose.model('user', UserSchema);
before defining the UserSchema.pre hook and UserSchema.methods.comparePassword method.
Call mongoose.model after defining your schema and things will work:
// 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);
});
};
var _User = mongoose.model('user', UserSchema);
Related
I've been starting to add user authentication into my app and when adding the login route, i've been getting the error "TypeError: cb is not a function". I know it is coming from my login route as all my other routes work fine.
I have tried researching the issue and trying a few fixes that i've found but none have worked. So i'm starting to believe i've messed up somewhere and I can't find where.
Login Route:
router.post('/login', function (req, res) {
User.findOne({ username: req.body.username }, function (err, user) {
if (err || user == null) {
console.log(err);
res.redirect('/login');
}
if (!user.comparePassword(req.body.password)) {
req.flash('invalidDetails', 'Wrong username or password!');
res.redirect('/login');
} else {
req.session.userId = user._id;
req.flash('loggedIn', 'User ' + req.body.username + ' has been logged in!');
return res.redirect('/');
}
});
});
User Model:
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
bcrypt = require('bcrypt'),
SALT_WORK_FACTOR = 10;
var UserSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true,
trim: true
},
username: {
type: String,
unique: true,
required: true,
trim: true
},
password: {
type: String,
required: true
}
});
UserSchema.statics.authenticate = function (email, password, callback) {
User.findOne({ email: email }).exec(function (err, user) {
if (err) {
return callback(err);
} else if (!user) {
var err = new Error('User not found.');
err.status = 401;
return callback(err);
}
bcrypt.compare(password, hash, function (err, result) {
if (result === true) {
return callback(null, user);
} else {
return callback();
}
});
});
};
UserSchema.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();
// generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function (err, salt) {
if (err) return next(err);
// hash the password along with 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();
});
});
});
UserSchema.methods.comparePassword = function comparePassword(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function (err, isMatch) {
if (err) {
return cb(err);
}
cb(null, isMatch);
});
};
var User = mongoose.model('User', UserSchema);
module.exports = User;
I'm expecting it to compare the password with the password that has been entered into the login form with the password that is stored in the database and log in the user if the password is correct or redirect back to the login page with the invalidDetails flash message if the password is incorrect.
But what i'm actually getting is the "TypeError: cb is not a function" error when trying to login.
You are not passing a callback that's why.
If you want a promise based method you can write something like this
AuthSchema.methods.comparePassword = function(candidatePassword) {
const currentPassword = this.password;
return new Promise((resolve, reject) => {
bcrypt.compare(candidatePassword, currentPassword, function(err, isMatch) {
if (err) return reject(err);
resolve(isMatch);
});
})
};
And now you can call that with await
as a starting copypasteprogrammer I started to add some salting and hashing to my app. The creation of a new User works fine. But the authentication of a user/password in Postman gives me a hard time. I keep getting errors. Now a 500 internal service error. Who can give me a little advice?
Here the schema:
const userSchema = new Schema({
userName: { //email
type: String,
required: true,
unique: true,
trim: true
},
password: {
type: String,
required: true
}
});
// hashing and salting before saving
userSchema.pre('save', function (next) {
let user = this;
// only hash the password if it has been modified (or is new)
if (!user.isModified('password')) return next();
//generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function (err, salt) {
if (err) return next(err);
// 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();
});
});
});
mongoose.model('User', userSchema);
Here the routes:
const express = require('express');
const router = express.Router();
const ctrlAuthFiles = require('../controllers/authFiles');
router
.route('/login')
.post(ctrlAuthFiles.userLogin);
module.exports = router;
Here the controller:
const mongoose = require('mongoose'),
Schema = mongoose.Schema;
const User1 = mongoose.model('User');
//fetch user and test password verification
const userLogin = function (req, res) {
if (req.body) {
User1
.findOne({ userName: req.body.username })
.exec((err, user) => {
if (!user) {
res
.status(404)
.json({
"message": "username or password not found"
});
return;
} else if (err) {
res
.status(404)
.json(err);
return;
}
});
User1.comparePassword(req.body.password, function (err, isMatch) {
if (err) throw err;
console.log(isMatch);
});
User1.methods.comparePassword = function (candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function (err, isMatch) {
if (err)
return cb(err);
cb(null, isMatch);
});
}
} else {
res
.status(404)
.json({
"message": "no username or password"
});
}
};
I have mongoose schema like so
var mongoose = require ('mongoose');
var bcrypt = require('bcryptjs');
var Schema = mongoose.Schema;
var SALT_WORK_FACTOR = 10;
var touristSchema = new Schema ({
local: {
email: String,
password: String
},
facebook: {
id: String,
token: String,
email: String,
name: String,
}
});
touristSchema.pre('save', function(next) {
var user = this;
console.log('bcrypt called by strategy', user);
// if user is facebook user skip the pasword thing.
if (user.facebook.token) {
next();
}
// only hash the password if it has been modified (or is new)
if (!user.isModified('password') && !user.isNew){
console.log('I am in here', user.isNew);
return next();
}
// generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
console.log('I am in genSalt');
if (err) return next(err);
// hash the password using our new salt
bcrypt.hash(user.local.password, salt, function(err, hash) {
if (err) return next(err);
// override the cleartext password with the hashed one
user.local.password = hash;
next();
});
});
});
touristSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.local.password, function(err, isMatch) {
// console.log(this.local.password);
if (err) return cb(err);
cb(null, isMatch);
});
};
module.exports = mongoose.model('users', touristSchema);
and login strategy like this
passport.use('local-login', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
},
function(req, email, password, done) {
process.nextTick(function() {
User.findOne({ 'local.email': email }, function(err, user) {
if(err)
return done(err);
if(!user)
return done(null, false, req.flash('loginMessage', 'No User Found'));
user.comparePassword(password, function(err, isMatch) {
if (err) throw err;
if (isMatch) {
done(null, user);
}
else
done(null, false, req.flash('loginMessage', 'Incorrect password'));
});
});
});
}
));
everything is working as expected but when I try to log in it gives me error:
TypeError: Cannot read property 'password' of undefined.
Turns out that this.local is undefined.
This is very strange as in touristSchema.pre hook we assigned var user = this and on logging this returned user document. When in compare method we are using touristSchema.methods.compare then this should must refer to the document as written in mongoose middleware docs too. I am beating my head over it for a couple of days now and have consumed every available help I could. Any help is greatly appreciated in advance. Thanks
and yes my
mongnodb version is v3.2.15
mongoose version is 4.9.7
which looks compatible to me according to mongoose docs
I am trying to encrypt password on registration using mongoose and mongodb but pre function is not called at all.
var mongoose = require('mongoose');
var Schema = mongoose.Schema,
bcrypt = require('bcrypt'),
SALT_WORK_FACTOR = 10;
var patientSchema = new Schema({
username: {type: String, trim: true, index: { unique: true }},
password: {type: String, required: true}
});
//====================== Middleware:Start==========================//
patientSchema.pre('save', function(next) {
console.log('pre called'); //This is not printed at all
var user = this;
// only hash the password if it has been modified (or is new)
if (!user.isModified('password')) return next();
// generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if (err) return next(err);
// hash the password along with 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();
});
});
});
//======================Middleware:End===========================//
//======================API Routes:Start===========================//
router.route('/signup')
.post(function (req, res) {
console.log('post signup called', req.body);
var patients = new Patients({
username: req.body.username,
password: req.body.password
});
Patients.findOne({username: req.body.username}, function (err, user) {
if (err) {
console.log('user not found');
}
if (user) {
console.log("patient already exists");
res.json({message: 'patient already exists'});
} else {
//Saving the model instance to the DB
patients.save(function (err) {
if (err)
throw err;
console.log("user Saved Successfully");
res.json({message: 'user Saved Successfully'});
});
}
});
});
module.exports = router;
//======================API Routes:End===========================//
Inside the pre function, console.log('pre called'); is not printed at all. What am I missing here?
it might be solve your error.
const patients = new Patients({
username: req.body.username,
password: req.body.password
})
if(!patients) return res.json(patients)
patients.save((err,patients) => {
if(err) return res.json({status: 500, message: err})
return res.json({status: 200, user: patients})
})
Thank you.
i got a problem with bcrypt on node.js -> the bcrypt compare method returns false while comparing the passwords from a mongoDB and a user entry. I have no idea why and i tried to debug it since 3 days but i really need some extern help...
UserShema:
var userSchema = new Schema({
name: {
type: String,
required: true
},
password: {
type: String,
required: true
}
});
hash and salt:
userSchema.pre('save', function (next) {
var user = this;
if (this.isModified('password') || this.isNew) {
bcrypt.genSalt(10, 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();
});
});
} else {
return next();
}
});
and finally: the compare method:
userSchema.methods.comparePassword = function (passw, cb) {
bcrypt.compare(passw, this.password, function (err, isMatch) {
if (err) {
return cb(err);
}
cb(null, isMatch);
});
};
module.exports = mongoose.model('User', userSchema);
Thx alot!