Server side checking of user input before allowing signup.

This commit is contained in:
Nathan Leniz
2015-03-09 18:35:56 +09:00
parent 3bfad2e272
commit 64d1c4a908

View File

@ -7,10 +7,10 @@ var _ = require('lodash'),
secrets = require('../config/secrets'), secrets = require('../config/secrets'),
moment = require('moment'), moment = require('moment'),
Challenge = require('./../models/Challenge'), Challenge = require('./../models/Challenge'),
debug = require('debug')('freecc:cntr:challenges') debug = require('debug')('freecc:cntr:challenges'),
resources = require('./resources'); resources = require('./resources');
//TODO(Berks): Refactor to use module.exports = {} pattern.
/** /**
* GET /signin * GET /signin
@ -18,10 +18,10 @@ var _ = require('lodash'),
*/ */
exports.getSignin = function(req, res) { exports.getSignin = function(req, res) {
if (req.user) return res.redirect('/'); if (req.user) return res.redirect('/');
res.render('account/signin', { res.render('account/signin', {
title: 'Free Code Camp Login' title: 'Free Code Camp Login'
}); });
}; };
/** /**
@ -30,28 +30,28 @@ exports.getSignin = function(req, res) {
*/ */
exports.postSignin = function(req, res, next) { exports.postSignin = function(req, res, next) {
req.assert('email', 'Email is not valid').isEmail(); req.assert('email', 'Email is not valid').isEmail();
req.assert('password', 'Password cannot be blank').notEmpty(); req.assert('password', 'Password cannot be blank').notEmpty();
var errors = req.validationErrors(); var errors = req.validationErrors();
if (errors) { if (errors) {
req.flash('errors', errors); req.flash('errors', errors);
return res.redirect('/signin'); return res.redirect('/signin');
}
passport.authenticate('local', function(err, user, info) {
if (err) return next(err);
if (!user) {
req.flash('errors', { msg: info.message });
return res.redirect('/signin');
} }
req.logIn(user, function(err) {
if (err) return next(err); passport.authenticate('local', function(err, user, info) {
req.flash('success', { msg: 'Success! You are logged in.' }); if (err) return next(err);
res.redirect(req.session.returnTo || '/'); if (!user) {
}); req.flash('errors', { msg: info.message });
})(req, res, next); return res.redirect('/signin');
}
req.logIn(user, function(err) {
if (err) return next(err);
req.flash('success', { msg: 'Success! You are logged in.' });
res.redirect(req.session.returnTo || '/');
});
})(req, res, next);
}; };
/** /**
@ -60,8 +60,8 @@ exports.postSignin = function(req, res, next) {
*/ */
exports.signout = function(req, res) { exports.signout = function(req, res) {
req.logout(); req.logout();
res.redirect('/'); res.redirect('/');
}; };
/** /**
@ -70,10 +70,10 @@ exports.signout = function(req, res) {
*/ */
exports.getEmailSignin = function(req, res) { exports.getEmailSignin = function(req, res) {
if (req.user) return res.redirect('/'); if (req.user) return res.redirect('/');
res.render('account/email-signin', { res.render('account/email-signin', {
title: 'Sign in to your Free Code Camp Account' title: 'Sign in to your Free Code Camp Account'
}); });
}; };
/** /**
@ -82,10 +82,10 @@ exports.getEmailSignin = function(req, res) {
*/ */
exports.getEmailSignup = function(req, res) { exports.getEmailSignup = function(req, res) {
if (req.user) return res.redirect('/'); if (req.user) return res.redirect('/');
res.render('account/email-signup', { res.render('account/email-signup', {
title: 'Create Your Free Code Camp Account' title: 'Create Your Free Code Camp Account'
}); });
}; };
/** /**
@ -94,64 +94,93 @@ exports.getEmailSignup = function(req, res) {
*/ */
exports.postEmailSignup = function(req, res, next) { exports.postEmailSignup = function(req, res, next) {
var errors = req.validationErrors(); var errors = req.validationErrors();
if (errors) { if (errors) {
req.flash('errors', errors); req.flash('errors', errors);
return res.redirect('/email-signup'); return res.redirect('/email-signup');
debug(errors);
}
var user = new User({
email: req.body.email.trim(),
password: req.body.password,
profile : {
username: req.body.username.trim(),
picture: 'https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-180x180.png'
} }
});
User.findOne({ email: req.body.email }, function(err, existingUser) { var possibleUserData = req.body;
if (err) { return next(err); }
if (existingUser) { if (possibleUserData.password.length < 5) {
req.flash('errors', { req.flash('errors', {
msg: 'Account with that email address already exists.' msg: 'Your password is too short'
}); });
return res.redirect('/email-signup'); return res.redirect('email-signup');
} }
user.save(function(err) {
if (err) { return next(err); }
req.logIn(user, function(err) { if (possibleUserData.username.length < 8 || possibleUserData.length > 20) {
if (err) { return next(err); } req.flash('errors', {
res.redirect('/email-signup'); msg: 'Your username must be between 5 and 20 characters'
}); });
return res.redirect('email-signup');
}
var user = new User({
email: req.body.email.trim(),
password: req.body.password,
profile : {
username: req.body.username.trim(),
picture: 'https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-180x180.png'
}
}); });
var transporter = nodemailer.createTransport({
service: 'Mandrill', User.findOne({ email: req.body.email }, function(err, existingEmail) {
auth: { if (err) {
user: secrets.mandrill.user, return next(err);
pass: secrets.mandrill.password }
}
if (existingEmail) {
req.flash('errors', {
msg: 'Account with that email address already exists.'
});
return res.redirect('/email-signup');
}
User.findOne({'profile.username': req.body.username }, function(err, existingUsername) {
if (err) {
return next(err);
}
if (existingUsername) {
req.flash('errors', {
msg: 'Account with that username already exists.'
});
return res.redirect('/email-signup');
}
user.save(function(err) {
if (err) { return next(err); }
req.logIn(user, function(err) {
if (err) { return next(err); }
res.redirect('/email-signup');
});
});
var transporter = nodemailer.createTransport({
service: 'Mandrill',
auth: {
user: secrets.mandrill.user,
pass: secrets.mandrill.password
}
});
var mailOptions = {
to: user.email,
from: 'Team@freecodecamp.com',
subject: 'Welcome to Free Code Camp!',
text: [
'Greetings from San Francisco!\n\n',
'Thank you for joining our community.\n',
'Feel free to email us at this address if you have any questions about Free Code Camp.\n',
"And if you have a moment, check out our blog: blog.freecodecamp.com.\n",
'Good luck with the challenges!\n\n',
'- the Volunteer Camp Counselor Team'
].join('')
};
transporter.sendMail(mailOptions, function(err) {
if (err) { return err; }
});
});
}); });
var mailOptions = {
to: user.email,
from: 'Team@freecodecamp.com',
subject: 'Welcome to Free Code Camp!',
text: [
'Greetings from San Francisco!\n\n',
'Thank you for joining our community.\n',
'Feel free to email us at this address if you have any questions about Free Code Camp.\n',
"And if you have a moment, check out our blog: blog.freecodecamp.com.\n",
'Good luck with the challenges!\n\n',
'- the Volunteer Camp Counselor Team'
].join('')
};
transporter.sendMail(mailOptions, function(err) {
if (err) { return err; }
});
});
}; };
/** /**
@ -161,7 +190,7 @@ exports.postEmailSignup = function(req, res, next) {
exports.getAccount = function(req, res) { exports.getAccount = function(req, res) {
res.render('account/account', { res.render('account/account', {
title: 'Manage your Free Code Camp Account' title: 'Manage your Free Code Camp Account'
}); });
}; };
@ -169,9 +198,9 @@ exports.getAccount = function(req, res) {
* Angular API Call * Angular API Call
*/ */
exports.getAccountAngular = function(req, res) { exports.getAccountAngular = function(req, res) {
res.json({ res.json({
user: req.user user: req.user
}); });
}; };
@ -180,13 +209,13 @@ exports.getAccount = function(req, res) {
*/ */
exports.checkUniqueUsername = function(req, res) { exports.checkUniqueUsername = function(req, res) {
User.count({'profile.username': req.params.username.toLowerCase()}, function (err, data) { User.count({'profile.username': req.params.username.toLowerCase()}, function (err, data) {
if (data == 1) { if (data == 1) {
return res.send(true); return res.send(true);
} else { } else {
return res.send(false); return res.send(false);
} }
}); });
}; };
/** /**
@ -207,13 +236,13 @@ exports.checkExistingUsername = function(req, res) {
*/ */
exports.checkUniqueEmail = function(req, res) { exports.checkUniqueEmail = function(req, res) {
User.count({'email': decodeURIComponent(req.params.email).toLowerCase()}, function (err, data) { User.count({'email': decodeURIComponent(req.params.email).toLowerCase()}, function (err, data) {
if (data == 1) { if (data == 1) {
return res.send(true); return res.send(true);
} else { } else {
return res.send(false); return res.send(false);
} }
}); });
}; };
@ -223,44 +252,44 @@ exports.checkUniqueEmail = function(req, res) {
*/ */
exports.returnUser = function(req, res, next) { exports.returnUser = function(req, res, next) {
User.find({'profile.username': req.params.username.toLowerCase()}, function(err, user) { User.find({'profile.username': req.params.username.toLowerCase()}, function(err, user) {
if (err) { debug('Username err: ', err); next(err); } if (err) { debug('Username err: ', err); next(err); }
if (user[0]) { if (user[0]) {
var user = user[0]; var user = user[0];
Challenge.find({}, null, {sort: {challengeNumber: 1}}, function (err, c) { Challenge.find({}, null, {sort: {challengeNumber: 1}}, function (err, c) {
res.render('account/show', { res.render('account/show', {
title: 'Camper: ', title: 'Camper: ',
username: user.profile.username, username: user.profile.username,
name: user.profile.name, name: user.profile.name,
location: user.profile.location, location: user.profile.location,
githubProfile: user.profile.githubProfile, githubProfile: user.profile.githubProfile,
linkedinProfile: user.profile.linkedinProfile, linkedinProfile: user.profile.linkedinProfile,
codepenProfile: user.profile.codepenProfile, codepenProfile: user.profile.codepenProfile,
twitterHandle: user.profile.twitterHandle, twitterHandle: user.profile.twitterHandle,
bio: user.profile.bio, bio: user.profile.bio,
picture: user.profile.picture, picture: user.profile.picture,
points: user.points, points: user.points,
website1Link: user.portfolio.website1Link, website1Link: user.portfolio.website1Link,
website1Title: user.portfolio.website1Title, website1Title: user.portfolio.website1Title,
website1Image: user.portfolio.website1Image, website1Image: user.portfolio.website1Image,
website2Link: user.portfolio.website2Link, website2Link: user.portfolio.website2Link,
website2Title: user.portfolio.website2Title, website2Title: user.portfolio.website2Title,
website2Image: user.portfolio.website2Image, website2Image: user.portfolio.website2Image,
website3Link: user.portfolio.website3Link, website3Link: user.portfolio.website3Link,
website3Title: user.portfolio.website3Title, website3Title: user.portfolio.website3Title,
website3Image: user.portfolio.website3Image, website3Image: user.portfolio.website3Image,
challenges: c, challenges: c,
ch: user.challengesHash, ch: user.challengesHash,
moment: moment moment: moment
}); });
}); });
} else { } else {
req.flash('errors', { req.flash('errors', {
msg: "404: We couldn't find a page with that url. Please double check the link." msg: "404: We couldn't find a page with that url. Please double check the link."
}); });
return res.redirect('/'); return res.redirect('/');
} }
}); });
}; };
@ -292,69 +321,70 @@ exports.updateProgress = function(req, res) {
*/ */
exports.postUpdateProfile = function(req, res, next) { exports.postUpdateProfile = function(req, res, next) {
User.findById(req.user.id, function(err, user) {
if (err) return next(err);
var errors = req.validationErrors();
if (errors) {
req.flash('errors', errors);
return res.redirect('/account');
}
User.findOne({ email: req.body.email }, function(err, existingEmail) { // What does this do?
if (err) { User.findById(req.user.id, function(err, user) {
return next(err); if (err) return next(err);
} var errors = req.validationErrors();
var user = req.user; if (errors) {
if (existingEmail && existingEmail.email != user.email) { req.flash('errors', errors);
req.flash('errors', { return res.redirect('/account');
msg: "An account with that email address already exists."
});
return res.redirect('/account');
}
User.findOne({ username: req.body.username }, function(err, existingUsername) {
if (err) {
return next(err);
} }
var user = req.user;
if (existingUsername && existingUsername.profile.username !== user.profile.username) {
req.flash('errors', {
msg: 'An account with that username already exists.'
});
return res.redirect('/account');
}
var user = req.user;
user.email = req.body.email.trim() || '';
user.profile.name = req.body.name.trim() || '';
user.profile.username = req.body.username.trim() || '';
user.profile.location = req.body.location.trim() || '';
user.profile.githubProfile = req.body.githubProfile.trim() || '';
user.profile.linkedinProfile = req.body.linkedinProfile.trim() || '';
user.profile.codepenProfile = req.body.codepenProfile.trim() || '';
user.profile.twitterHandle = req.body.twitterHandle.trim() || '';
user.profile.bio = req.body.bio.trim() || '';
user.profile.picture = req.body.picture.trim() || 'https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-180x180.png';
user.portfolio.website1Title = req.body.website1Title.trim() || '';
user.portfolio.website1Link = req.body.website1Link.trim() || '';
user.portfolio.website1Image = req.body.website1Image.trim() || '';
user.portfolio.website2Title = req.body.website2Title.trim() || '';
user.portfolio.website2Link = req.body.website2Link.trim() || '';
user.portfolio.website2Image = req.body.website2Image.trim() || '';
user.portfolio.website3Title = req.body.website3Title.trim() || '';
user.portfolio.website3Link = req.body.website3Link.trim() || '';
user.portfolio.website3Image = req.body.website3Image.trim() || '';
User.findOne({ email: req.body.email }, function(err, existingEmail) {
user.save(function (err) {
if (err) { if (err) {
return next(err); return next(err);
} }
req.flash('success', {msg: 'Profile information updated.'}); var user = req.user;
res.redirect('/account'); if (existingEmail && existingEmail.email != user.email) {
resources.updateUserStoryPictures(user._id.toString(), user.profile.picture, user.profile.username); req.flash('errors', {
msg: "An account with that email address already exists."
});
return res.redirect('/account');
}
User.findOne({ username: req.body.username }, function(err, existingUsername) {
if (err) {
return next(err);
}
var user = req.user;
if (existingUsername && existingUsername.profile.username !== user.profile.username) {
req.flash('errors', {
msg: 'An account with that username already exists.'
});
return res.redirect('/account');
}
user.email = req.body.email.trim() || '';
user.profile.name = req.body.name.trim() || '';
user.profile.username = req.body.username.trim() || '';
user.profile.location = req.body.location.trim() || '';
user.profile.githubProfile = req.body.githubProfile.trim() || '';
user.profile.linkedinProfile = req.body.linkedinProfile.trim() || '';
user.profile.codepenProfile = req.body.codepenProfile.trim() || '';
user.profile.twitterHandle = req.body.twitterHandle.trim() || '';
user.profile.bio = req.body.bio.trim() || '';
user.profile.picture = req.body.picture.trim() || 'https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-180x180.png';
user.portfolio.website1Title = req.body.website1Title.trim() || '';
user.portfolio.website1Link = req.body.website1Link.trim() || '';
user.portfolio.website1Image = req.body.website1Image.trim() || '';
user.portfolio.website2Title = req.body.website2Title.trim() || '';
user.portfolio.website2Link = req.body.website2Link.trim() || '';
user.portfolio.website2Image = req.body.website2Image.trim() || '';
user.portfolio.website3Title = req.body.website3Title.trim() || '';
user.portfolio.website3Link = req.body.website3Link.trim() || '';
user.portfolio.website3Image = req.body.website3Image.trim() || '';
user.save(function (err) {
if (err) {
return next(err);
}
req.flash('success', {msg: 'Profile information updated.'});
res.redirect('/account');
resources.updateUserStoryPictures(user._id.toString(), user.profile.picture, user.profile.username);
});
});
}); });
});
}); });
});
}; };
/** /**
@ -363,29 +393,29 @@ exports.postUpdateProfile = function(req, res, next) {
*/ */
exports.postUpdatePassword = function(req, res, next) { exports.postUpdatePassword = function(req, res, next) {
req.assert('password', 'Password must be at least 4 characters long').len(4); req.assert('password', 'Password must be at least 4 characters long').len(4);
req.assert('confirmPassword', 'Passwords do not match') req.assert('confirmPassword', 'Passwords do not match')
.equals(req.body.password); .equals(req.body.password);
var errors = req.validationErrors(); var errors = req.validationErrors();
if (errors) { if (errors) {
req.flash('errors', errors); req.flash('errors', errors);
return res.redirect('/account'); return res.redirect('/account');
} }
User.findById(req.user.id, function(err, user) { User.findById(req.user.id, function(err, user) {
if (err) { return next(err); } if (err) { return next(err); }
user.password = req.body.password; user.password = req.body.password;
user.save(function(err) { user.save(function(err) {
if (err) { return next(err); } if (err) { return next(err); }
req.flash('success', { msg: 'Password has been changed.' }); req.flash('success', { msg: 'Password has been changed.' });
res.redirect('/account'); res.redirect('/account');
});
}); });
});
}; };
/** /**
@ -394,12 +424,12 @@ exports.postUpdatePassword = function(req, res, next) {
*/ */
exports.postDeleteAccount = function(req, res, next) { exports.postDeleteAccount = function(req, res, next) {
User.remove({ _id: req.user.id }, function(err) { User.remove({ _id: req.user.id }, function(err) {
if (err) { return next(err); } if (err) { return next(err); }
req.logout(); req.logout();
req.flash('info', { msg: 'Your account has been deleted.' }); req.flash('info', { msg: 'Your account has been deleted.' });
res.redirect('/'); res.redirect('/');
}); });
}; };
/** /**
@ -408,22 +438,22 @@ exports.postDeleteAccount = function(req, res, next) {
*/ */
exports.getOauthUnlink = function(req, res, next) { exports.getOauthUnlink = function(req, res, next) {
var provider = req.params.provider; var provider = req.params.provider;
User.findById(req.user.id, function(err, user) { User.findById(req.user.id, function(err, user) {
if (err) { return next(err); } if (err) { return next(err); }
user[provider] = undefined; user[provider] = undefined;
user.tokens = user.tokens =
_.reject(user.tokens, function(token) { _.reject(user.tokens, function(token) {
return token.kind === provider; return token.kind === provider;
}); });
user.save(function(err) { user.save(function(err) {
if (err) { return next(err); } if (err) { return next(err); }
req.flash('info', { msg: provider + ' account has been unlinked.' }); req.flash('info', { msg: provider + ' account has been unlinked.' });
res.redirect('/account'); res.redirect('/account');
});
}); });
});
}; };
/** /**
@ -432,25 +462,25 @@ exports.getOauthUnlink = function(req, res, next) {
*/ */
exports.getReset = function(req, res) { exports.getReset = function(req, res) {
if (req.isAuthenticated()) { if (req.isAuthenticated()) {
return res.redirect('/'); return res.redirect('/');
} }
User User
.findOne({ resetPasswordToken: req.params.token }) .findOne({ resetPasswordToken: req.params.token })
.where('resetPasswordExpires').gt(Date.now()) .where('resetPasswordExpires').gt(Date.now())
.exec(function(err, user) { .exec(function(err, user) {
if (err) { return next(err); } if (err) { return next(err); }
if (!user) { if (!user) {
req.flash('errors', { req.flash('errors', {
msg: 'Password reset token is invalid or has expired.' msg: 'Password reset token is invalid or has expired.'
});
return res.redirect('/forgot');
}
res.render('account/reset', {
title: 'Password Reset',
token: req.params.token
});
}); });
return res.redirect('/forgot');
}
res.render('account/reset', {
title: 'Password Reset',
token: req.params.token
});
});
}; };
/** /**
@ -459,72 +489,72 @@ exports.getReset = function(req, res) {
*/ */
exports.postReset = function(req, res, next) { exports.postReset = function(req, res, next) {
var errors = req.validationErrors(); var errors = req.validationErrors();
if (errors) { if (errors) {
req.flash('errors', errors); req.flash('errors', errors);
return res.redirect('back'); return res.redirect('back');
}
async.waterfall([
function(done) {
User
.findOne({ resetPasswordToken: req.params.token })
.where('resetPasswordExpires').gt(Date.now())
.exec(function(err, user) {
if (err) { return next(err); }
if (!user) {
req.flash('errors', {
msg: 'Password reset token is invalid or has expired.'
});
return res.redirect('back');
}
user.password = req.body.password;
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
user.save(function(err) {
if (err) { return done(err); }
req.logIn(user, function(err) {
done(err, user);
});
});
});
},
function(user, done) {
var transporter = nodemailer.createTransport({
service: 'Mandrill',
auth: {
user: secrets.mandrill.user,
pass: secrets.mandrill.password
}
});
var mailOptions = {
to: user.email,
from: 'Team@freecodecamp.com',
subject: 'Your Free Code Camp password has been changed',
text: [
'Hello,\n\n',
'This email is confirming that you requested to',
'reset your password for your Free Code Camp account.',
'This is your email:',
user.email,
'\n'
].join(' ')
};
transporter.sendMail(mailOptions, function(err) {
if (err) { return done(err); }
req.flash('success', {
msg: 'Success! Your password has been changed.'
});
done();
});
} }
], function(err) {
if (err) { return next(err); } async.waterfall([
res.redirect('/'); function(done) {
}); User
.findOne({ resetPasswordToken: req.params.token })
.where('resetPasswordExpires').gt(Date.now())
.exec(function(err, user) {
if (err) { return next(err); }
if (!user) {
req.flash('errors', {
msg: 'Password reset token is invalid or has expired.'
});
return res.redirect('back');
}
user.password = req.body.password;
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
user.save(function(err) {
if (err) { return done(err); }
req.logIn(user, function(err) {
done(err, user);
});
});
});
},
function(user, done) {
var transporter = nodemailer.createTransport({
service: 'Mandrill',
auth: {
user: secrets.mandrill.user,
pass: secrets.mandrill.password
}
});
var mailOptions = {
to: user.email,
from: 'Team@freecodecamp.com',
subject: 'Your Free Code Camp password has been changed',
text: [
'Hello,\n\n',
'This email is confirming that you requested to',
'reset your password for your Free Code Camp account.',
'This is your email:',
user.email,
'\n'
].join(' ')
};
transporter.sendMail(mailOptions, function(err) {
if (err) { return done(err); }
req.flash('success', {
msg: 'Success! Your password has been changed.'
});
done();
});
}
], function(err) {
if (err) { return next(err); }
res.redirect('/');
});
}; };
/** /**
@ -533,12 +563,12 @@ exports.postReset = function(req, res, next) {
*/ */
exports.getForgot = function(req, res) { exports.getForgot = function(req, res) {
if (req.isAuthenticated()) { if (req.isAuthenticated()) {
return res.redirect('/'); return res.redirect('/');
} }
res.render('account/forgot', { res.render('account/forgot', {
title: 'Forgot Password' title: 'Forgot Password'
}); });
}; };
/** /**
@ -547,80 +577,80 @@ exports.getForgot = function(req, res) {
*/ */
exports.postForgot = function(req, res, next) { exports.postForgot = function(req, res, next) {
var errors = req.validationErrors(); var errors = req.validationErrors();
if (errors) { if (errors) {
req.flash('errors', errors); req.flash('errors', errors);
return res.redirect('/forgot'); return res.redirect('/forgot');
}
async.waterfall([
function(done) {
crypto.randomBytes(16, function(err, buf) {
if (err) { return done(err); }
var token = buf.toString('hex');
done(null, token);
});
},
function(token, done) {
User.findOne({
email: req.body.email.toLowerCase()
}, function(err, user) {
if (err) { return done(err); }
if (!user) {
req.flash('errors', {
msg: 'No account with that email address exists.'
});
return res.redirect('/forgot');
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err) {
if (err) { return done(err); }
done(null, token, user);
});
});
},
function(token, user, done) {
var transporter = nodemailer.createTransport({
service: 'Mandrill',
auth: {
user: secrets.mandrill.user,
pass: secrets.mandrill.password
}
});
var mailOptions = {
to: user.email,
from: 'Team@freecodecamp.com',
subject: 'Reset your Free Code Camp password',
text: [
'You are receiving this email because you (or someone else)\n',
'requested we reset your Free Code Camp account\'s password.\n\n',
'Please click on the following link, or paste this into your\n',
'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\n',
'your password will remain unchanged.\n'
].join('')
};
transporter.sendMail(mailOptions, function(err) {
if (err) { return done(err); }
req.flash('info', {
msg: 'An e-mail has been sent to ' +
user.email +
' with further instructions.'
});
done(null, 'done');
});
} }
], function(err) {
if (err) { return next(err); } async.waterfall([
res.redirect('/forgot'); function(done) {
}); crypto.randomBytes(16, function(err, buf) {
if (err) { return done(err); }
var token = buf.toString('hex');
done(null, token);
});
},
function(token, done) {
User.findOne({
email: req.body.email.toLowerCase()
}, function(err, user) {
if (err) { return done(err); }
if (!user) {
req.flash('errors', {
msg: 'No account with that email address exists.'
});
return res.redirect('/forgot');
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err) {
if (err) { return done(err); }
done(null, token, user);
});
});
},
function(token, user, done) {
var transporter = nodemailer.createTransport({
service: 'Mandrill',
auth: {
user: secrets.mandrill.user,
pass: secrets.mandrill.password
}
});
var mailOptions = {
to: user.email,
from: 'Team@freecodecamp.com',
subject: 'Reset your Free Code Camp password',
text: [
'You are receiving this email because you (or someone else)\n',
'requested we reset your Free Code Camp account\'s password.\n\n',
'Please click on the following link, or paste this into your\n',
'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\n',
'your password will remain unchanged.\n'
].join('')
};
transporter.sendMail(mailOptions, function(err) {
if (err) { return done(err); }
req.flash('info', {
msg: 'An e-mail has been sent to ' +
user.email +
' with further instructions.'
});
done(null, 'done');
});
}
], function(err) {
if (err) { return next(err); }
res.redirect('/forgot');
});
}; };