From 59f700b11025fc2754d44a475c4a85924abeb003 Mon Sep 17 00:00:00 2001 From: Mrugesh Mohapatra Date: Fri, 25 May 2018 23:14:09 +0530 Subject: [PATCH] fix(auth): Add verification route for email --- .../Settings/components/Email-Settings.jsx | 6 +- server/boot/authentication.js | 26 ++++++++- server/boot/user.js | 18 +++--- server/middleware.json | 1 + .../middlewares/email-not-verified-notice.js | 32 +++++++++++ server/utils/middleware.js | 2 +- server/views/account/update-email.jade | 57 +++++++++++++++++++ server/views/partials/navbar.jade | 2 +- 8 files changed, 131 insertions(+), 13 deletions(-) create mode 100644 server/middlewares/email-not-verified-notice.js create mode 100644 server/views/account/update-email.jade diff --git a/common/app/routes/Settings/components/Email-Settings.jsx b/common/app/routes/Settings/components/Email-Settings.jsx index d9f1aac76b..7544f15512 100644 --- a/common/app/routes/Settings/components/Email-Settings.jsx +++ b/common/app/routes/Settings/components/Email-Settings.jsx @@ -132,9 +132,9 @@ class EmailSettings extends PureComponent { - A change of email address has not been verified. - To use your new email, you must verify it first using the link - we sent you. + Your email has not been verified. + To use your email, you must + verify it here first. diff --git a/server/boot/authentication.js b/server/boot/authentication.js index 1a95cb2e40..cf108fa3ba 100644 --- a/server/boot/authentication.js +++ b/server/boot/authentication.js @@ -38,9 +38,33 @@ module.exports = function enableAuthentication(app) { ifUserRedirect, (req, res) => res.redirect(301, '/auth/auth0')); + router.get( + '/update-email', + ifNoUserRedirectHome, + (req, res) => res.render('account/update-email', { + title: 'Update your email' + }) + ); + router.get('/signout', (req, res) => { req.logout(); - res.redirect('/'); + req.session.destroy( (err) => { + if (err) { + throw wrapHandledError( + new Error('could not destroy session'), + { + type: 'info', + message: 'Oops, something is not right.', + redirectTo: '/' + } + ); + } + res.clearCookie('jwt_access_token'); + res.clearCookie('access_token'); + res.clearCookie('userId'); + res.clearCookie('_csrf'); + res.redirect('/'); + }); }); router.get( diff --git a/server/boot/user.js b/server/boot/user.js index 6788e4e7e4..bc05d88470 100644 --- a/server/boot/user.js +++ b/server/boot/user.js @@ -5,12 +5,12 @@ import { curry } from 'lodash'; import { ifNoUser401, ifNoUserRedirectTo, - ifNotVerifiedRedirectToSettings + ifNotVerifiedRedirectToUpdateEmail } from '../utils/middleware'; const debug = debugFactory('fcc:boot:user'); -const sendNonUserToMap = ifNoUserRedirectTo('/map'); -const sendNonUserToMapWithMessage = curry(ifNoUserRedirectTo, 2)('/map'); +const sendNonUserToHome = ifNoUserRedirectTo('/'); +const sendNonUserToHomeWithMessage = curry(ifNoUserRedirectTo, 2)('/'); module.exports = function(app) { const router = app.loopback.Router(); @@ -24,7 +24,7 @@ module.exports = function(app) { ); api.get( '/account', - sendNonUserToMap, + sendNonUserToHome, getAccount ); api.post( @@ -34,15 +34,15 @@ module.exports = function(app) { ); api.get( '/account/unlink/:social', - sendNonUserToMap, + sendNonUserToHome, getUnlinkSocial ); // Ensure these are the last routes! router.get( '/user/:username/report-user/', - sendNonUserToMapWithMessage('You must be signed in to report a user'), - ifNotVerifiedRedirectToSettings, + sendNonUserToHomeWithMessage('You must be signed in to report a user'), + ifNotVerifiedRedirectToUpdateEmail, getReportUserProfile ); @@ -119,6 +119,10 @@ module.exports = function(app) { if (err) { return next(err); } req.logout(); req.flash('success', 'You have successfully deleted your account.'); + res.clearCookie('jwt_access_token'); + res.clearCookie('access_token'); + res.clearCookie('userId'); + res.clearCookie('_csrf'); return res.status(200).end(); }); } diff --git a/server/middleware.json b/server/middleware.json index f6ce16ed6f..c664ae1b0f 100644 --- a/server/middleware.json +++ b/server/middleware.json @@ -58,6 +58,7 @@ "./middlewares/jade-helpers": {}, "./middlewares/flash-cheaters": {}, "./middlewares/passport-login": {}, + "./middlewares/email-not-verified-notice": {}, "./middlewares/privacy-terms-notice": {} }, "files": {}, diff --git a/server/middlewares/email-not-verified-notice.js b/server/middlewares/email-not-verified-notice.js new file mode 100644 index 0000000000..d674c0acfd --- /dev/null +++ b/server/middlewares/email-not-verified-notice.js @@ -0,0 +1,32 @@ +import dedent from 'dedent'; + +const ALLOWED_METHODS = ['GET']; +const EXCLUDED_PATHS = [ + '/api/flyers/findOne', + '/signout', + '/update-email' +]; + +export default function emailNotVerifiedNotice() { + return function(req, res, next) { + if ( + ALLOWED_METHODS.indexOf(req.method) !== -1 && + EXCLUDED_PATHS.indexOf(req.path) === -1 + ) { + const { user } = req; + if (user && (!user.email || user.email === '' || !user.emailVerified)) { + req.flash( + 'danger', + dedent` + New privacy laws now require that we have an email address where we can reach + you. Please verify your email address below and click the link we send you to + confirm. + ` + ); + res.redirect('/update-email'); + return next; + } + } + return next(); + }; +} diff --git a/server/utils/middleware.js b/server/utils/middleware.js index f38afbdb37..7371824190 100644 --- a/server/utils/middleware.js +++ b/server/utils/middleware.js @@ -32,7 +32,7 @@ export function ifNoUser401(req, res, next) { return res.status(401).end(); } -export function ifNotVerifiedRedirectToSettings(req, res, next) { +export function ifNotVerifiedRedirectToUpdateEmail(req, res, next) { const { user } = req; if (!user) { return next(); diff --git a/server/views/account/update-email.jade b/server/views/account/update-email.jade new file mode 100644 index 0000000000..53071a0747 --- /dev/null +++ b/server/views/account/update-email.jade @@ -0,0 +1,57 @@ +extends ../layout +block content + .container + .row.flashMessage.negative-30 + .col-xs-12 + #flash-board.alert.fade.in(style='display: none;') + button.close(type='button', data-dismiss='alert') + span.ion-close-circled#flash-close + #flash-content + h2.text-center Update your email address here: + form.form-horizontal.update-email(method='POST', action='/api/users/#{user.id}/update-email', name="updateEmailForm") + .row + .col-sm-6.col-sm-offset-3 + input(type='hidden', name='_csrf', value=_csrf) + .form-group + input.input-lg.form-control(type='email', name='email', id='email', value=user.email || '', placeholder=user.email || 'Enter your new email', autofocus, required, autocomplete="off") + .form-group + button.btn.btn-lg.btn-primary.btn-block(type='submit')= !user.email || user.emailVerified ? 'Update my Email' : 'Verify Email' + a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='/signout') + | Sign out + + script. + $(document).ready(function() { + $('form').submit(function(event){ + event.preventDefault(); + $('#flash-board').hide(); + var $form = $(event.target); + $.ajax({ + type : 'POST', + url : $form.attr('action'), + data : $form.serialize(), + dataType : 'json', + encode : true, + xhrFields : { withCredentials: true } + }) + .fail(error => { + if (error.responseText){ + var data = JSON.parse(error.responseText); + if(data.message) + $('#flash-content').html(data.message); + $('#flash-board') + .removeClass('alert-success') + .addClass('alert-info') + .fadeIn(); + } + }) + .done(data =>{ + if(data && data.message){ + $('#flash-content').html(data.message); + $('#flash-board') + .removeClass('alert-info') + .addClass('alert-success') + .fadeIn(); + } + }); + }); + }); diff --git a/server/views/partials/navbar.jade b/server/views/partials/navbar.jade index a866c4ee57..062d2369d0 100644 --- a/server/views/partials/navbar.jade +++ b/server/views/partials/navbar.jade @@ -14,7 +14,7 @@ nav.navbar.navbar-default.navbar-static-top.nav-height a(href='https://forum.freecodecamp.org', target='_blank' rel='noopener') Forum if !user li - a(href='/signin') Start Coding + a(href='/signin') Sign in else li a(href='/settings') Settings