fix: edge case during email change
Docker Image CI / build-and-push-image (push) Has been cancelled
Maintain Release Merge PR / update-release-pr (push) Has been cancelled
release-please / release-please (push) Has been cancelled
test / test (18.x) (push) Has been cancelled
test / test (20.x) (push) Has been cancelled
test / test (22.x) (push) Has been cancelled

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
This commit is contained in:
KernelDeimos
2025-04-01 12:41:49 -04:00
parent 7a3365a25c
commit fb01bb474a
@@ -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');