diff --git a/packages/backend/src/routers/_default.js b/packages/backend/src/routers/_default.js index ebbe2bdf..3579e533 100644 --- a/packages/backend/src/routers/_default.js +++ b/packages/backend/src/routers/_default.js @@ -209,7 +209,7 @@ router.all('*', async function(req, res, next) { const {get_user} = require('../helpers') // get user - const user = await get_user({uuid: req.query.user_uuid}) + const user = await get_user({uuid: req.query.user_uuid, force: true}) // more validation if(user === undefined || user === null || user === false) @@ -220,6 +220,13 @@ router.all('*', async function(req, res, next) { h += '

invalid token.

'; // mark user as confirmed else{ + // If other users have the same unconfirmed email, revoke it + await db.write( + 'UPDATE `user` SET `unconfirmed_change_email` = NULL, `change_email_confirm_token` = NULL WHERE `unconfirmed_change_email` = ?', + [user.email], + ); + + // update user await db.write( "UPDATE `user` SET `email_confirmed` = 1, `requires_email_confirmation` = 0 WHERE id = ?", [user.id] diff --git a/packages/backend/src/routers/change_email.js b/packages/backend/src/routers/change_email.js index 5a6f81ed..9ff54301 100644 --- a/packages/backend/src/routers/change_email.js +++ b/packages/backend/src/routers/change_email.js @@ -53,6 +53,21 @@ const CHANGE_EMAIL_CONFIRM = eggspress('/change_email/confirm', { throw APIError.create('token_invalid'); } + // Scenario: email was confirmed on another account already + const rows2 = await db.read( + 'SELECT `id` FROM `user` WHERE `email` = ?', + [rows[0].unconfirmed_change_email] + ); + if ( rows2.length > 0 ) { + throw APIError.create('email_already_in_use'); + } + + // If other users have the same unconfirmed email, revoke it + await db.write( + 'UPDATE `user` SET `unconfirmed_change_email` = NULL, `change_email_confirm_token` = NULL WHERE `unconfirmed_change_email` = ?', + [rows[0].unconfirmed_change_email] + ); + const new_email = rows[0].unconfirmed_change_email; await db.write( diff --git a/packages/backend/src/routers/confirm-email.js b/packages/backend/src/routers/confirm-email.js index 023205cd..839ebb2e 100644 --- a/packages/backend/src/routers/confirm-email.js +++ b/packages/backend/src/routers/confirm-email.js @@ -22,6 +22,7 @@ const { invalidate_cached_user } = require('../helpers'); const router = new express.Router(); const auth = require('../middleware/auth.js'); const { DB_WRITE } = require('../services/database/consts'); +const APIError = require('../api/APIError.js'); // -----------------------------------------------------------------------// // POST /confirm-email @@ -48,6 +49,22 @@ router.post('/confirm-email', auth, express.json(), async (req, res, next)=>{ // Set expiry for rate limit kv.expire(`confirm-email|${req.ip}|${req.body.email ?? req.body.username}`, 60 * 10, 'NX') + // Scenario: email was confirmed on another account already + const rows = await db.read( + 'SELECT `id` FROM `user` WHERE `email` = ? AND `email_confirmed` = 1', + [req.body.email], + ); + if ( rows.length > 0 ) { + APIError.create('email_already_in_use').write(res); + return; + } + + // If other users have the same unconfirmed email, revoke it + await db.write( + 'UPDATE `user` SET `unconfirmed_change_email` = NULL, `change_email_confirm_token` = NULL WHERE `unconfirmed_change_email` = ?', + [req.user.email], + ); + if(req.body.code === req.user.email_confirm_code) { await db.write( "UPDATE `user` SET `email_confirmed` = 1, `requires_email_confirmation` = 0 WHERE id = ? LIMIT 1",