I have made a set up to update a user's password using NodeJS/Passport. I followed this great guide: http://sahatyalkabov.com/how-to-implement-password-reset-in-nodejs/.
99% of this is working. I had to modify it a bit to include some stripe functionality. I am afraid however I have a critical error somewhere and I cannot find it. The user is currently able to go all the way through the process of having an email sent to them, enter a new password, and be logged in. Another email follows saying their password was successfully updated. All perfect. However. For some reason. The new password is not being SAVED. the user can only sign in with their old password. I have tried everything I can think of to fix this.
I have had several other programmers look at this and none of them have been able to figure out how in the world its not working.
Current thought is that the session might not be ending correctly but we tried destroying the session and it still did not work.
Any help greatly appreciated.
Full set up:
User Model:
var UserSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
password: String,
datapoint: String,
email: { type: String, required: true, unique: true },
resetPasswordToken: String,
resetPasswordExpires: Date
});
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();
});
});
});
Register New Account (This also has stripe info in it unrelated but could cause the problem.)
var newUser = new User({username: req.body.username, email: req.body.email, datapoint: req.body.datapoint});
User.register(newUser, req.body.password, function(err, user){
if(err){
console.log('Looks like there was an error:' + ' ' + err)
res.redirect('/login')
} else {
passport.authenticate("local")(req, res, function(){
var user = new User({
username: req.body.username,
email: req.body.email,
password: req.body.password
})
console.log('creating new account')
console.log('prepping charge')
var token = req.body.stripeToken; // Using Express
var charge = stripe.charges.create({
amount: 749,
currency: "usd",
description: "Example charge",
source: token,
}, function(err, charge) {
// asynchronously called
console.log('charged')
});
res.redirect('/jobquiz')
console.log(req.body.datapoint)
console.log(req.body.email)
});
}
});
});
Set up forgot password posting
app.post('/forgot', function(req, res, next) {
async.waterfall([
function(done) {
crypto.randomBytes(20, function(err, buf) {
var token = buf.toString('hex');
done(err, token);
});
},
function(token, done) {
User.findOne({ email: req.body.email }, function(err, user) {
if (!user) {
// console.log('error', 'No account with that email address exists.');
req.flash('error', 'No account with that email address exists.');
return res.redirect('/forgot');
}
console.log('step 1')
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err) {
done(err, token, user);
});
});
},
function(token, user, done) {
console.log('step 2')
var smtpTrans = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'myemail',
pass: 'mypassword'
}
});
var mailOptions = {
to: user.email,
from: 'myemail',
subject: 'Node.js Password Reset',
text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
'http://' + req.headers.host + '/reset/' + token + '\n\n' +
'If you did not request this, please ignore this email and your password will remain unchanged.\n'
};
console.log('step 3')
smtpTrans.sendMail(mailOptions, function(err) {
req.flash('success', 'An e-mail has been sent to ' + user.email + ' with further instructions.');
console.log('sent')
res.redirect('/forgot');
});
}
], function(err) {
console.log('this err' + ' ' + err)
res.redirect('/');
});
});
app.get('/forgot', function(req, res) {
res.render('forgot', {
User: req.user
});
});
Set up changing password post
app.get('/reset/:token', function(req, res) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
console.log(user);
if (!user) {
req.flash('error', 'Password reset token is invalid or has expired.');
return res.redirect('/forgot');
}
res.render('reset', {
User: req.user
});
});
});
app.post('/reset/:token', function(req, res) {
async.waterfall([
function(done) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user, next) {
if (!user) {
req.flash('error', 'Password reset token is invalid or has expired.');
return res.redirect('back');
}
user.password = req.body.password;
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
console.log('password' + user.password + 'and the user is' + user)
user.save(function(err) {
if (err) {
console.log('here')
return res.redirect('back');
} else {
console.log('here2')
req.logIn(user, function(err) {
done(err, user);
});
}
});
});
},
function(user, done) {
// console.log('got this far 4')
var smtpTrans = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'myemail',
pass: 'mypass'
}
});
var mailOptions = {
to: user.email,
from: 'myemail',
subject: 'Your password has been changed',
text: 'Hello,\n\n' +
' - This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n'
};
smtpTrans.sendMail(mailOptions, function(err) {
// req.flash('success', 'Success! Your password has been changed.');
done(err);
});
}
], function(err) {
res.redirect('/');
});
});