diff --git a/common/models/user.js b/common/models/user.js index 0ced33a968..a9584b4447 100644 --- a/common/models/user.js +++ b/common/models/user.js @@ -3,6 +3,7 @@ import uuid from 'node-uuid'; import moment from 'moment'; import dedent from 'dedent'; import debugFactory from 'debug'; +import { isEmail } from 'validator'; import { saveUser, observeMethod } from '../../server/utils/rx'; import { blacklistedUsernames } from '../../server/utils/constants'; @@ -62,6 +63,9 @@ module.exports = function(User) { User.observe('before save', function({ instance: user }, next) { if (user) { + if (user.email && !isEmail(user.email)) { + return next(new Error('Email format is not valid')); + } user.username = user.username.trim().toLowerCase(); user.email = typeof user.email === 'string' ? user.email.trim().toLowerCase() : @@ -75,7 +79,7 @@ module.exports = function(User) { user.progressTimestamps.push({ timestamp: Date.now() }); } } - next(); + return next(); }); debug('setting up user hooks'); @@ -93,6 +97,9 @@ module.exports = function(User) { if (!req.body.email) { return next(); } + if (!isEmail(req.body.email)) { + return next(new Error('Email format is not valid')); + } return User.doesExist(null, req.body.email) .then(exists => { if (!exists) { @@ -118,6 +125,10 @@ module.exports = function(User) { }); User.on('resetPasswordRequest', function(info) { + if (!isEmail(info.email)) { + console.error(new Error('Email format is not valid')); + return null; + } let url; const host = User.app.get('host'); const { id: token } = info.accessToken; @@ -150,7 +161,7 @@ module.exports = function(User) { ` }; - User.app.models.Email.send(mailOptions, function(err) { + return User.app.models.Email.send(mailOptions, function(err) { if (err) { console.error(err); } debug('email reset sent'); }); @@ -159,9 +170,12 @@ module.exports = function(User) { User.beforeRemote('login', function(ctx, notUsed, next) { const { body } = ctx.req; if (body && typeof body.email === 'string') { + if (!isEmail(body.email)) { + return next(new Error('Email format is not valid')); + } body.email = body.email.toLowerCase(); } - next(); + return next(); }); User.afterRemote('login', function(ctx, accessToken, next) { @@ -216,7 +230,7 @@ module.exports = function(User) { }); User.doesExist = function doesExist(username, email) { - if (!username && !email) { + if (!username && (!email || !isEmail(email))) { return Promise.resolve(false); } debug('checking existence'); @@ -309,6 +323,11 @@ module.exports = function(User) { ); User.prototype.updateEmail = function updateEmail(email) { + if (!isEmail(email)) { + return Promise.reject( + new Error('The submitted email not valid') + ); + } if (this.email && this.email === email) { return Promise.reject(new Error( `${email} is already associated with this account.` diff --git a/server/boot/a-extendUser.js b/server/boot/a-extendUser.js index e43cdeff2b..932bd7dcdb 100644 --- a/server/boot/a-extendUser.js +++ b/server/boot/a-extendUser.js @@ -1,5 +1,6 @@ import { Observable } from 'rx'; import debugFactory from 'debug'; +import { isEmail } from 'validator'; const debug = debugFactory('fcc:user:remote'); @@ -59,7 +60,7 @@ module.exports = function(app) { // send welcome email to new camper User.afterRemote('create', function({ req, res }, user, next) { debug('user created, sending email'); - if (!user.email) { return next(); } + if (!user.email || !isEmail(user.email)) { return next(); } const redirect = req.session && req.session.returnTo ? req.session.returnTo : '/'; diff --git a/server/boot/user.js b/server/boot/user.js index 989a37edd6..685a2aed5c 100644 --- a/server/boot/user.js +++ b/server/boot/user.js @@ -550,6 +550,7 @@ module.exports = function(app) { } function postForgot(req, res) { + req.validate('email', 'Email format is not valid').isEmail(); const errors = req.validationErrors(); const email = req.body.email.toLowerCase();