From ccf004f1f4d3a3990e48ea83c5608195a0812e30 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 28 Jul 2021 11:41:55 -0400 Subject: [PATCH] refactor: added user.email.remove method, updated email interstitial to handle email removal --- src/user/email.js | 32 +++++++++++++++++++++++--------- src/user/index.js | 28 +++++++++++++++------------- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/user/email.js b/src/user/email.js index c7779dbc53..f9a3a675b2 100644 --- a/src/user/email.js +++ b/src/user/email.js @@ -24,6 +24,25 @@ UserEmail.available = async function (email) { return !exists; }; +UserEmail.remove = async function (uid) { + const email = await user.getUserField(uid, 'email'); + if (!email) { + return; + } + + await Promise.all([ + user.setUserFields(uid, { + email: '', + 'email:confirmed': 0, + }), + db.sortedSetRemove('email:uid', email.toLowerCase()), + db.sortedSetRemove('email:sorted', `${email.toLowerCase()}:${uid}`), + user.email.expireValidation(uid), + user.auth.revokeAllSessions(uid), + events.log({ type: 'email-change', email, newEmail: '' }), + ]); +}; + UserEmail.isValidationPending = async (uid, email) => { const code = await db.get(`confirm:byUid:${uid}`); @@ -124,21 +143,16 @@ UserEmail.confirmByCode = async function (code) { throw new Error('[[error:invalid-data]]'); } - let oldEmail = await user.getUserField(confirmObj.uid, 'email'); - if (oldEmail) { - oldEmail = oldEmail || ''; - if (oldEmail !== confirmObj.email) { - 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 }); - } + const oldEmail = await user.getUserField(confirmObj.uid, 'email'); + if (oldEmail && confirmObj.email !== oldEmail) { + UserEmail.remove(confirmObj.uid); } await user.setUserField(confirmObj.uid, 'email', confirmObj.email); await Promise.all([ UserEmail.confirmByUid(confirmObj.uid), db.delete(`confirm:${code}`), + events.log({ type: 'email-change', oldEmail, newEmail: confirmObj.email }), ]); }; diff --git a/src/user/index.js b/src/user/index.js index b6698e95a0..c6d097d0cd 100644 --- a/src/user/index.js +++ b/src/user/index.js @@ -248,23 +248,22 @@ User.addInterstitials = function (callback) { data: { email }, callback: async (userData, formData) => { // Validate and send email confirmation - if (formData.email && formData.email.length) { - if (!utils.isEmailValid(formData.email)) { - throw new Error('[[error:invalid-email]]'); - } + if (userData.uid) { + const [isAdminOrGlobalMod, canEdit] = await Promise.all([ + User.isAdminOrGlobalMod(data.req.uid), + privileges.users.canEdit(data.req.uid, userData.uid), + ]); + + if (formData.email && formData.email.length) { + if (!utils.isEmailValid(formData.email)) { + throw new Error('[[error:invalid-email]]'); + } - if (userData.uid) { const current = await User.getUserField(userData.uid, 'email'); if (formData.email === current) { throw new Error('[[error:email-nochange]]'); } - const [isAdminOrGlobalMod, canEdit] = await Promise.all([ - User.isAdminOrGlobalMod(data.req.uid), - privileges.users.canEdit(data.req.uid, userData.uid), - - ]); - // Admins editing will auto-confirm, unless editing their own email if (isAdminOrGlobalMod && userData.uid !== data.req.uid) { await User.setUserField(userData.uid, 'email', formData.email); @@ -279,9 +278,12 @@ User.addInterstitials = function (callback) { throw new Error('[[error:no-privileges]]'); } } else { - // New registrants have the confirm email sent from user.create() - userData.email = formData.email; + // User explicitly clearing their email + await User.email.remove(userData.uid); } + } else { + // New registrants have the confirm email sent from user.create() + userData.email = formData.email; } delete userData.updateEmail;