From fb01bb474aecb4625fbd840436ae4781f86b4cf6 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 1 Apr 2025 12:41:49 -0400 Subject: [PATCH] fix: edge case during email change Previous logic was: - on email change, update temporary value - send email to confirm new email - temporary value is moved to real email This doesn't work when an account has not yet confirmed their email after signup (i.e. user's email_confirmed is still 0). Well, it actually does work, but the user is only able to confirm the change to their email and not set their account as having a confirmed email. New logic has a branch for this case; IFF email_confirmed=0: - change account confirm code - send new account confirm email --- .../routers/user-protected/change-email.js | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/backend/src/routers/user-protected/change-email.js b/src/backend/src/routers/user-protected/change-email.js index 8dc09c554..a782888f0 100644 --- a/src/backend/src/routers/user-protected/change-email.js +++ b/src/backend/src/routers/user-protected/change-email.js @@ -22,6 +22,9 @@ const jwt = require('jsonwebtoken'); const validator = require('validator'); const crypto = require('crypto'); const config = require("../../config"); +const { send_email_verification_token } = require("../../helpers"); +const { Context } = require("../../util/context"); +const { v4: uuidv4 } = require('uuid'); module.exports = { route: '/change-email', @@ -66,6 +69,23 @@ module.exports = { if ( rows[0].count > 0 ) { throw APIError.create('email_already_in_use', null, { email: new_email }); } + + // If user does not have a confirmed email, then update `email` directly + // and send a new confirmation email for their account instead. + if ( ! user.email_confirmed ) { + const email_confirm_token = uuidv4(); + await db.write( + 'UPDATE `user` SET `email` = ?, `email_confirm_token` = ? WHERE `id` = ?', + [new_email, email_confirm_token, user.id], + ); + + const svc_email = Context.get('services').get('email'); + const link = `${config.origin}/confirm-email-by-token?user_uuid=${user.uuid}&token=${email_confirm_token}`; + svc_email.send_email({ email: new_email }, 'email_verification_link', { link }); + + res.send({ success: true }); + return; + } // generate confirmation token const token = crypto.randomBytes(4).toString('hex');