diff --git a/install/data/defaults.json b/install/data/defaults.json index bfbf6a4b39..f6c31125b2 100644 --- a/install/data/defaults.json +++ b/install/data/defaults.json @@ -65,7 +65,6 @@ "profileImageDimension": 200, "profile:convertProfileImageToPNG": 0, "profile:keepAllUserImages": 0, - "requireEmailConfirmation": 0, "gdpr_enabled": 1, "allowProfileImageUploads": 1, "teaserPost": "last-reply", diff --git a/public/openapi/read/config.yaml b/public/openapi/read/config.yaml index 30455c6e61..2d8d2ff07b 100644 --- a/public/openapi/read/config.yaml +++ b/public/openapi/read/config.yaml @@ -92,8 +92,6 @@ get: description: A user identifier cache-buster: type: string - requireEmailConfirmation: - type: boolean topicPostSort: type: string categoryTopicSort: diff --git a/public/src/app.js b/public/src/app.js index eacfb7e2ee..53d60ffe32 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -719,7 +719,7 @@ app.cacheBuster = null; }; app.showEmailConfirmWarning = function (err) { - if (!config.requireEmailConfirmation || !app.user.uid) { + if (!app.user.uid) { return; } var msg = { diff --git a/src/api/users.js b/src/api/users.js index 2a4c5100d6..b7deaed080 100644 --- a/src/api/users.js +++ b/src/api/users.js @@ -71,10 +71,6 @@ usersAPI.update = async function (caller, data) { await events.log(eventData); } - if (userData.email !== oldUserData.email) { - await log('email-change', { oldEmail: oldUserData.email, newEmail: userData.email }); - } - if (userData.username !== oldUserData.username) { await log('username-change', { oldUsername: oldUserData.username, newUsername: userData.username }); } diff --git a/src/controllers/api.js b/src/controllers/api.js index 5419bbbe01..44f3726f72 100644 --- a/src/controllers/api.js +++ b/src/controllers/api.js @@ -60,7 +60,6 @@ apiController.loadConfig = async function (req) { loggedIn: !!req.user, uid: req.uid, 'cache-buster': meta.config['cache-buster'] || '', - requireEmailConfirmation: meta.config.requireEmailConfirmation === 1, topicPostSort: meta.config.topicPostSort || 'oldest_to_newest', categoryTopicSort: meta.config.categoryTopicSort || 'newest_to_oldest', csrf_token: req.uid >= 0 && req.csrfToken && req.csrfToken(), diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index 3f325f168d..b4bc61d1a4 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -23,8 +23,12 @@ const sockets = require('../socket.io'); const authenticationController = module.exports; async function registerAndLoginUser(req, res, userData) { + if (!userData.email) { + userData.updateEmail = true; + } + const data = await plugins.hooks.fire('filter:register.interstitial', { - userData: userData, + userData, interstitials: [], }); @@ -33,7 +37,6 @@ async function registerAndLoginUser(req, res, userData) { if (deferRegistration) { userData.register = true; - userData.updateEmail = true; req.session.registration = userData; if (req.body.noscript === 'true') { diff --git a/src/emailer.js b/src/emailer.js index 012fed1d4c..c8cfd7cbe8 100644 --- a/src/emailer.js +++ b/src/emailer.js @@ -228,7 +228,7 @@ Emailer.send = async (template, uid, params) => { } const allowedTpls = ['verify_email', 'welcome', 'registration_accepted']; - if (meta.config.requireEmailConfirmation && !userData['email:confirmed'] && !allowedTpls.includes(template)) { + if (!userData['email:confirmed'] && !allowedTpls.includes(template)) { if (process.env.NODE_ENV === 'development') { winston.warn(`uid : ${uid} (${userData.email}) has not confirmed email, not sending "${template}" email.`); } diff --git a/src/events.js b/src/events.js index d781fd851f..69da2ef272 100644 --- a/src/events.js +++ b/src/events.js @@ -40,6 +40,7 @@ events.types = [ 'user-deleteAccount', 'user-deleteContent', 'password-change', + 'email-confirmation-sent', 'email-change', 'username-change', 'ip-blacklist-save', diff --git a/src/middleware/header.js b/src/middleware/header.js index b9e41df5ba..aceb38eef8 100644 --- a/src/middleware/header.js +++ b/src/middleware/header.js @@ -75,7 +75,7 @@ middleware.renderHeader = async function renderHeader(req, res, data) { isModerator: user.isModeratorOfAnyCategory(req.uid), privileges: privileges.global.get(req.uid), user: user.getUserData(req.uid), - isEmailConfirmSent: (!meta.config.requireEmailConfirmation || req.uid <= 0) ? false : await db.get(`uid:${req.uid}:confirm:email:sent`), + isEmailConfirmSent: req.uid <= 0 ? false : await db.get(`uid:${req.uid}:confirm:email:sent`), languageDirection: translator.translate('[[language:dir]]', res.locals.config.userLang), timeagoCode: languages.userTimeagoCode(res.locals.config.userLang), browserTitle: translator.translate(controllers.helpers.buildTitle(translator.unescape(data.title))), diff --git a/src/middleware/user.js b/src/middleware/user.js index cf545ab901..b3a63651af 100644 --- a/src/middleware/user.js +++ b/src/middleware/user.js @@ -264,6 +264,8 @@ module.exports = function (middleware) { return setImmediate(next); } + console.log('middleware hit', req.session); + 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/socket.io/admin/user.js b/src/socket.io/admin/user.js index 5012818dc2..e813053137 100644 --- a/src/socket.io/admin/user.js +++ b/src/socket.io/admin/user.js @@ -8,7 +8,6 @@ const api = require('../../api'); const groups = require('../../groups'); const user = require('../../user'); const events = require('../../events'); -const meta = require('../../meta'); const translator = require('../../translator'); const sockets = require('..'); @@ -81,10 +80,6 @@ User.sendValidationEmail = async function (socket, uids) { throw new Error('[[error:invalid-data]]'); } - if (!meta.config.requireEmailConfirmation) { - throw new Error('[[error:email-confirmations-are-disabled]]'); - } - const failed = []; let errorLogged = false; await async.eachLimit(uids, 50, async (uid) => { diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 3e324a6211..a9f105ef48 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -48,10 +48,6 @@ SocketUser.emailConfirm = async function (socket) { throw new Error('[[error:no-privileges]]'); } - if (!meta.config.requireEmailConfirmation) { - throw new Error('[[error:email-confirmations-are-disabled]]'); - } - return await user.email.sendValidationEmail(socket.uid); }; diff --git a/src/upgrades/1.15.0/verified_users_group.js b/src/upgrades/1.15.0/verified_users_group.js index 0aabdb3224..1488b8b280 100644 --- a/src/upgrades/1.15.0/verified_users_group.js +++ b/src/upgrades/1.15.0/verified_users_group.js @@ -81,6 +81,8 @@ async function updatePrivilges() { // if email confirmation is required // give chat, posting privs to "verified-users" group // remove chat, posting privs from "registered-users" group + + // This config property has been removed from v1.18.0+, but is still present in old datasets if (meta.config.requireEmailConfirmation) { const cids = await db.getSortedSetRevRange('categories:cid', 0, -1); const canChat = await privileges.global.canGroup('chat', 'registered-users'); diff --git a/src/user/digest.js b/src/user/digest.js index dec6a43df3..d9b7e1ef3e 100644 --- a/src/user/digest.js +++ b/src/user/digest.js @@ -103,7 +103,7 @@ Digest.send = async function (data) { let errorLogged = false; await batch.processArray(data.subscribers, async (uids) => { let userData = await user.getUsersFields(uids, ['uid', 'email', 'email:confirmed', 'username', 'userslug', 'lastonline']); - userData = userData.filter(u => u && u.email && (!meta.config.requireEmailConfirmation || u['email:confirmed'])); + userData = userData.filter(u => u && u.email && (meta.config.includeUnverifiedEmails || u['email:confirmed'])); if (!userData.length) { return; } diff --git a/src/user/email.js b/src/user/email.js index 7fd9346ce8..6ed3c9d8a0 100644 --- a/src/user/email.js +++ b/src/user/email.js @@ -10,6 +10,7 @@ const db = require('../database'); const meta = require('../meta'); const emailer = require('../emailer'); const groups = require('../groups'); +const events = require('../events'); const UserEmail = module.exports; @@ -69,6 +70,13 @@ UserEmail.sendValidationEmail = async function (uid, options) { await db.expireAt(`confirm:${confirm_code}`, Math.floor((Date.now() / 1000) + (60 * 60 * 24))); const username = await user.getUserField(uid, 'username'); + events.log({ + type: 'email-confirmation-sent', + uid, + confirm_code, + ...options, + }); + const data = { username: username, confirm_link: confirm_link, @@ -104,6 +112,7 @@ UserEmail.confirmByCode = async function (code) { await db.sortedSetRemove('email:uid', oldEmail.toLowerCase()); await db.sortedSetRemove('email:sorted', `${oldEmail.toLowerCase()}:${confirmObj.uid}`); await user.auth.revokeAllSessions(confirmObj.uid); + await events.log('email-change', { oldEmail, newEmail: confirmObj.email }); } await Promise.all([ diff --git a/src/user/profile.js b/src/user/profile.js index 72148fcf3a..2f19772c33 100644 --- a/src/user/profile.js +++ b/src/user/profile.js @@ -244,6 +244,7 @@ module.exports = function (User) { } if (newEmail) { + await db.delete(`uid:${uid}:confirm:email:sent`); await User.email.sendValidationEmail(uid, { email: newEmail, subject: '[[email:email.verify-your-email.subject]]', diff --git a/src/views/admin/settings/user.tpl b/src/views/admin/settings/user.tpl index fc17a4e2f0..1bfc772737 100644 --- a/src/views/admin/settings/user.tpl +++ b/src/views/admin/settings/user.tpl @@ -4,13 +4,6 @@
[[admin/settings/user:authentication]]
-
- -
-