This repository has been archived by the owner on Aug 30, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented password reset core feature
- Loading branch information
Showing
10 changed files
with
268 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,12 @@ var mongoose = require('mongoose'), | |
passport = require('passport'), | ||
User = mongoose.model('User'), | ||
_ = require('lodash'); | ||
/* Requires for reset password */ | ||
var nodemailer = require('nodemailer'); | ||
var LocalStrategy = require('passport-local').Strategy; | ||
var bcrypt = require('bcrypt-nodejs'); | ||
var async = require('async'); | ||
var crypto = require('crypto'); | ||
|
||
/** | ||
* Get the error message from error object | ||
|
@@ -92,6 +98,160 @@ exports.signin = function(req, res, next) { | |
})(req, res, next); | ||
}; | ||
|
||
/** | ||
* Forgot for reset password (forgot POST) | ||
*/ | ||
exports.forgot = function(req, res, next) { | ||
async.waterfall([ | ||
// Generate random token | ||
function(done) { | ||
crypto.randomBytes(20, function(err, buf) { | ||
var token = buf.toString('hex'); | ||
done(err, token); | ||
}); | ||
}, | ||
// Lookup user by email address | ||
function(token, done) { | ||
if (req.body.email) { | ||
User.findOne({ email: req.body.email }, function(err, user) { | ||
if (!user) { | ||
return res.send(400, { | ||
message: 'No account with that email address exists' | ||
}); | ||
} | ||
|
||
user.resetPasswordToken = token; | ||
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour | ||
|
||
user.save(function(err) { | ||
done(err, token, user); | ||
}); | ||
}); | ||
} else { | ||
return res.send(400, { | ||
message: 'Email field must not be blank' | ||
}); | ||
} | ||
|
||
}, | ||
// If valid email, send reset email using service | ||
function(token, user, done) { | ||
var smtpTransport = nodemailer.createTransport('SMTP', { | ||
service: 'SendGrid', // Choose email service, default SendGrid | ||
auth: { | ||
user: '[email protected]', | ||
pass: 'your_sendgrid_password' | ||
} | ||
}); | ||
var mailOptions = { | ||
to: user.email, | ||
from: '[email protected]', | ||
subject: '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 + '/auth/reset/' + token + '\n\n' + | ||
'If you did not request this, please ignore this email and your password will remain unchanged.\n' | ||
}; | ||
smtpTransport.sendMail(mailOptions, function(err) { | ||
res.send(200, { | ||
message: 'An email has been sent to ' + user.email + ' with further instructions.' | ||
}); | ||
done(err, 'done'); | ||
}); | ||
} | ||
], function(err) { | ||
if (err) return next(err); | ||
}); | ||
}; | ||
|
||
/** | ||
* Reset password GET from email token | ||
*/ | ||
exports.resetGet = function(req, res) { | ||
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) { | ||
if (!user) { | ||
// res.render('404'); | ||
res.send(400, { | ||
message: 'Password reset token is invalid or has expired.' | ||
}); | ||
return res.redirect('/#!/forgot'); | ||
} | ||
|
||
res.redirect('/#!/reset/' + req.params.token); | ||
|
||
}); | ||
}; | ||
|
||
/** | ||
* Reset password POST from email token | ||
*/ | ||
exports.resetPost = function(req, res) { | ||
// Init Variables | ||
var passwordDetails = req.body; | ||
var message = null; | ||
|
||
async.waterfall([ | ||
function(done) { | ||
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) { | ||
if (!err && user) { | ||
if (passwordDetails.newPassword === passwordDetails.verifyPassword) { | ||
user.password = passwordDetails.newPassword; | ||
user.resetPasswordToken = undefined; | ||
user.resetPasswordExpires = undefined; | ||
|
||
user.save(function(err) { | ||
if (err) { | ||
return res.send(400, { | ||
message: getErrorMessage(err) | ||
}); | ||
} else { | ||
req.login(user, function(err) { | ||
if (err) { | ||
res.send(400, err); | ||
} else { | ||
done(err, user); | ||
} | ||
}); | ||
} | ||
}); | ||
} else { | ||
return res.send(400, { | ||
message: 'Passwords do not match' | ||
}); | ||
} | ||
} else { | ||
return res.send(400, { | ||
message: 'Password reset token is invalid or has expired.' | ||
}); | ||
} | ||
}); | ||
}, | ||
function(user, done) { | ||
var smtpTransport = nodemailer.createTransport('SMTP', { | ||
service: 'SendGrid', | ||
auth: { | ||
user: '[email protected]', | ||
pass: 'your_sendgrid_password' | ||
} | ||
}); | ||
var mailOptions = { | ||
to: user.email, | ||
from: '[email protected]', | ||
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' | ||
}; | ||
smtpTransport.sendMail(mailOptions, function(err) { | ||
res.send(200, { | ||
message: 'Password changed successfully' | ||
}); | ||
}); | ||
} | ||
], function(err) { | ||
res.redirect('/'); | ||
}); | ||
}; | ||
|
||
/** | ||
* Update user details | ||
*/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<section class="row" data-ng-controller="AuthenticationController"> | ||
<h3 class="col-md-12 text-center">Forgot your password?</h3> | ||
<div class="col-xs-offset-2 col-xs-8 col-md-offset-5 col-md-2"> | ||
<form data-ng-submit="forgot()" class="signin form-horizontal" autocomplete="off"> | ||
<fieldset> | ||
<div class="form-group"> | ||
<input type="text" id="email" name="email" class="form-control" data-ng-model="credentials.email" placeholder="Account Email"> | ||
</div> | ||
<div class="text-center form-group"> | ||
<button type="submit" class="btn btn-primary">Submit</button> | ||
</div> | ||
<div data-ng-show="error" class="text-center text-danger"> | ||
<strong>{{error}}</strong> | ||
</div> | ||
<div data-ng-show="success" class="text-center text-success"> | ||
<strong>{{success}}</strong> | ||
</div> | ||
</fieldset> | ||
</form> | ||
</div> | ||
</section> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<section class="row" data-ng-controller="AuthenticationController"> | ||
<h3 class="col-md-12 text-center">Reset your password</h3> | ||
<div class="col-xs-offset-2 col-xs-8 col-md-offset-5 col-md-2"> | ||
<form data-ng-submit="reset()" class="signin form-horizontal" autocomplete="off"> | ||
<fieldset> | ||
<div class="form-group"> | ||
<label for="newPassword">New Password</label> | ||
<input type="password" id="newPassword" name="newPassword" class="form-control" data-ng-model="passwordDetails.newPassword" placeholder="New Password"> | ||
</div> | ||
<div class="form-group"> | ||
<label for="verifyPassword">Verify Password</label> | ||
<input type="password" id="verifyPassword" name="verifyPassword" class="form-control" data-ng-model="passwordDetails.verifyPassword" placeholder="Verify Password"> | ||
</div> | ||
<div class="text-center form-group"> | ||
<button type="submit" class="btn btn-large btn-primary">Update Password</button> | ||
</div> | ||
<div data-ng-show="error" class="text-center text-danger"> | ||
<strong>{{error}}</strong> | ||
</div> | ||
<div data-ng-show="success" class="text-center text-success"> | ||
<strong>{{success}}</strong> | ||
</div> | ||
</fieldset> | ||
</form> | ||
</div> | ||
</section> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters