[web] When switching primary email, delete the old primary if it's unconfirmed (#23688)
* Add note to ConfirmModal: unconfirmed primary will be deleted * Change confirm button copy * Promisify `UserEmailsController.setDefault` * Update tests after promisification * Delete unconfirmed primary when swapped * Fixup apostrophe in translation * `npm run extract-translations` * Add unit tests * Add acceptance tests * Fix frontend tests * Make email address bold * Add "We removed the previous primary..." to the email GitOrigin-RevId: c971e219e36e509f9963e1720acdd44f562a05b5
This commit is contained in:
@@ -544,6 +544,73 @@ async function remove(req, res) {
|
||||
res.sendStatus(200)
|
||||
}
|
||||
|
||||
async function setDefault(req, res, next) {
|
||||
const userId = SessionManager.getLoggedInUserId(req.session)
|
||||
const email = EmailHelper.parseEmail(req.body.email)
|
||||
|
||||
if (!email) {
|
||||
return res.sendStatus(422)
|
||||
}
|
||||
|
||||
const { emails, email: oldDefault } = await UserGetter.promises.getUser(
|
||||
userId,
|
||||
{ email: 1, emails: 1 }
|
||||
)
|
||||
const primaryEmailData = emails?.find(email => email.email === oldDefault)
|
||||
const deleteOldEmail =
|
||||
req.query['delete-unconfirmed-primary'] !== undefined &&
|
||||
primaryEmailData &&
|
||||
!primaryEmailData.confirmedAt
|
||||
|
||||
const auditLog = {
|
||||
initiatorId: userId,
|
||||
ipAddress: req.ip,
|
||||
}
|
||||
try {
|
||||
await UserUpdater.promises.setDefaultEmailAddress(
|
||||
userId,
|
||||
email,
|
||||
false,
|
||||
auditLog,
|
||||
true,
|
||||
deleteOldEmail
|
||||
)
|
||||
} catch (err) {
|
||||
return UserEmailsController._handleEmailError(err, req, res, next)
|
||||
}
|
||||
SessionManager.setInSessionUser(req.session, { email })
|
||||
const user = SessionManager.getSessionUser(req.session)
|
||||
try {
|
||||
await UserSessionsManager.promises.removeSessionsFromRedis(
|
||||
user,
|
||||
req.sessionID // remove all sessions except the current session
|
||||
)
|
||||
} catch (err) {
|
||||
logger.warn(
|
||||
{ err },
|
||||
'failed revoking secondary sessions after changing default email'
|
||||
)
|
||||
}
|
||||
if (
|
||||
req.query['delete-unconfirmed-primary'] !== undefined &&
|
||||
primaryEmailData &&
|
||||
!primaryEmailData.confirmedAt
|
||||
) {
|
||||
await UserUpdater.promises.removeEmailAddress(
|
||||
userId,
|
||||
primaryEmailData.email,
|
||||
{
|
||||
initiatorId: userId,
|
||||
ipAddress: req.ip,
|
||||
extraInfo: {
|
||||
info: 'removed unconfirmed email after setting new primary',
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
res.sendStatus(200)
|
||||
}
|
||||
|
||||
const UserEmailsController = {
|
||||
list(req, res, next) {
|
||||
const userId = SessionManager.getLoggedInUserId(req.session)
|
||||
@@ -566,43 +633,7 @@ const UserEmailsController = {
|
||||
|
||||
remove: expressify(remove),
|
||||
|
||||
setDefault(req, res, next) {
|
||||
const userId = SessionManager.getLoggedInUserId(req.session)
|
||||
const email = EmailHelper.parseEmail(req.body.email)
|
||||
if (!email) {
|
||||
return res.sendStatus(422)
|
||||
}
|
||||
const auditLog = {
|
||||
initiatorId: userId,
|
||||
ipAddress: req.ip,
|
||||
}
|
||||
UserUpdater.setDefaultEmailAddress(
|
||||
userId,
|
||||
email,
|
||||
false,
|
||||
auditLog,
|
||||
true,
|
||||
err => {
|
||||
if (err) {
|
||||
return UserEmailsController._handleEmailError(err, req, res, next)
|
||||
}
|
||||
SessionManager.setInSessionUser(req.session, { email })
|
||||
const user = SessionManager.getSessionUser(req.session)
|
||||
UserSessionsManager.removeSessionsFromRedis(
|
||||
user,
|
||||
req.sessionID, // remove all sessions except the current session
|
||||
err => {
|
||||
if (err)
|
||||
logger.warn(
|
||||
{ err },
|
||||
'failed revoking secondary sessions after changing default email'
|
||||
)
|
||||
}
|
||||
)
|
||||
res.sendStatus(200)
|
||||
}
|
||||
)
|
||||
},
|
||||
setDefault: expressify(setDefault),
|
||||
|
||||
endorse(req, res, next) {
|
||||
const userId = SessionManager.getLoggedInUserId(req.session)
|
||||
|
||||
@@ -20,7 +20,13 @@ const _ = require('lodash')
|
||||
const Modules = require('../../infrastructure/Modules')
|
||||
const UserSessionsManager = require('./UserSessionsManager')
|
||||
|
||||
async function _sendSecurityAlertPrimaryEmailChanged(userId, oldEmail, email) {
|
||||
async function _sendSecurityAlertPrimaryEmailChanged(
|
||||
userId,
|
||||
oldEmail,
|
||||
email,
|
||||
deleteOldEmail
|
||||
) {
|
||||
// here
|
||||
// Send email to the following:
|
||||
// - the old primary
|
||||
// - the new primary
|
||||
@@ -31,6 +37,11 @@ async function _sendSecurityAlertPrimaryEmailChanged(userId, oldEmail, email) {
|
||||
const emailOptions = {
|
||||
actionDescribed: `the primary email address on your account was changed to ${email}`,
|
||||
action: 'change of primary email address',
|
||||
message: deleteOldEmail
|
||||
? [
|
||||
`We also removed the previous primary email ${oldEmail} from the account.`,
|
||||
]
|
||||
: [],
|
||||
}
|
||||
|
||||
async function sendToRecipients(recipients) {
|
||||
@@ -161,7 +172,8 @@ async function setDefaultEmailAddress(
|
||||
email,
|
||||
allowUnconfirmed,
|
||||
auditLog,
|
||||
sendSecurityAlert
|
||||
sendSecurityAlert,
|
||||
deleteOldEmail = false
|
||||
) {
|
||||
email = EmailHelper.parseEmail(email)
|
||||
if (email == null) {
|
||||
@@ -212,11 +224,14 @@ async function setDefaultEmailAddress(
|
||||
|
||||
if (sendSecurityAlert) {
|
||||
// no need to wait, errors are logged and not passed back
|
||||
_sendSecurityAlertPrimaryEmailChanged(userId, oldEmail, email).catch(
|
||||
err => {
|
||||
logger.error({ err }, 'failed to send security alert email')
|
||||
}
|
||||
)
|
||||
_sendSecurityAlertPrimaryEmailChanged(
|
||||
userId,
|
||||
oldEmail,
|
||||
email,
|
||||
deleteOldEmail
|
||||
).catch(err => {
|
||||
logger.error({ err }, 'failed to send security alert email')
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user