From 84313712a29a3a79eb57c72a1f2a5d9bda05e39e Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 3 May 2023 13:42:28 -0400 Subject: [PATCH] fix: add an additional check on page load to enforce `requireEmailAddress` setting The old behaviour would require that an email be entered, but did not block access to the forum (nor did it ensure that the email was verified). The new behaviour (if the setting is enabled) will ensure that only those users with a confirmed email can continue through. The only exceptions are super admins (so they don't get locked out). --- public/language/en-GB/user.json | 3 ++- src/middleware/user.js | 20 ++++++++++++++++++-- src/user/interstitials.js | 4 +++- src/views/partials/email_update.tpl | 5 +++++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/public/language/en-GB/user.json b/public/language/en-GB/user.json index 31df96fb8c..6fd7f11675 100644 --- a/public/language/en-GB/user.json +++ b/public/language/en-GB/user.json @@ -223,5 +223,6 @@ "emailUpdate.optional": "This field is optional. You are not obligated to provide your email address, but without a validated email you will not be able to recover your account or login with your email.", "emailUpdate.required": "This field is required.", "emailUpdate.change-instructions": "A confirmation email will be sent to the entered email address with a unique link. Accessing that link will confirm your ownership of the email address and it will become active on your account. At any time, you are able to update your email on file from within your account page.", - "emailUpdate.password-challenge": "Please enter your password in order to verify account ownership." + "emailUpdate.password-challenge": "Please enter your password in order to verify account ownership.", + "emailUpdate.pending": "Your email address has not yet been confirmed, but an email has been sent out requesting confirmation. If you wish to invalidate that request and send a new confirmation request, please fill in the form below." } diff --git a/src/middleware/user.js b/src/middleware/user.js index fb3e5ed84f..57c1db8296 100644 --- a/src/middleware/user.js +++ b/src/middleware/user.js @@ -6,6 +6,7 @@ const nconf = require('nconf'); const path = require('path'); const util = require('util'); +const meta = require('../meta'); const user = require('../user'); const privileges = require('../privileges'); const plugins = require('../plugins'); @@ -231,12 +232,27 @@ module.exports = function (middleware) { }; middleware.registrationComplete = async function registrationComplete(req, res, next) { - // If the user's session contains registration data, redirect the user to complete registration + /** + * Redirect the user to complete registration if: + * * user's session contains registration data + * * email is required and they have no confirmed email (pending doesn't count, but admins are OK) + */ + const path = req.path.startsWith('/api/') ? req.path.replace('/api', '') : req.path; + if (!req.session.hasOwnProperty('registration')) { + if (req.uid && !path.endsWith('/edit/email')) { + const [confirmed, isAdmin] = await Promise.all([ + user.getUserField(req.uid, 'email:confirmed'), + user.isAdministrator(req.uid), + ]); + if (meta.config.requireEmailAddress && !confirmed && !isAdmin) { + controllers.helpers.redirect(res, '/me/edit/email'); + } + } + return setImmediate(next); } - const path = req.path.startsWith('/api/') ? req.path.replace('/api', '') : req.path; const { allowed } = await plugins.hooks.fire('filter:middleware.registrationComplete', { allowed: ['/register/complete'], }); diff --git a/src/user/interstitials.js b/src/user/interstitials.js index 9a0e96f6db..b87877b53e 100644 --- a/src/user/interstitials.js +++ b/src/user/interstitials.js @@ -28,9 +28,10 @@ Interstitials.email = async (data) => { return data; } - const [isAdminOrGlobalMod, hasPassword] = await Promise.all([ + const [isAdminOrGlobalMod, hasPassword, hasPending] = await Promise.all([ user.isAdminOrGlobalMod(data.req.uid), user.hasPassword(data.userData.uid), + user.email.isValidationPending(data.userData.uid), ]); let email; @@ -44,6 +45,7 @@ Interstitials.email = async (data) => { email, requireEmailAddress: meta.config.requireEmailAddress, issuePasswordChallenge: !!data.userData.uid && hasPassword, + hasPending, }, callback: async (userData, formData) => { // Validate and send email confirmation diff --git a/src/views/partials/email_update.tpl b/src/views/partials/email_update.tpl index ccadc6226b..788c49942f 100644 --- a/src/views/partials/email_update.tpl +++ b/src/views/partials/email_update.tpl @@ -1,4 +1,9 @@
+ {{{ if hasPending }}} +
+

[[user:emailUpdate.pending]]

+
+ {{{ end }}}

[[user:emailUpdate.intro]]

{{{ if requireEmailAddress }}}

[[user:emailUpdate.required]]