diff --git a/src/backend/controllers/auth/AuthController.ts b/src/backend/controllers/auth/AuthController.ts index bc3d659bf..3149459bc 100644 --- a/src/backend/controllers/auth/AuthController.ts +++ b/src/backend/controllers/auth/AuthController.ts @@ -823,6 +823,16 @@ export class AuthController extends PuterController { email_confirm_token: null, }); + // Revoke confirmation from any other accounts sharing this + // email so only the account whose owner just proved inbox + // access retains verified status. + const canonical = cleanEmail(user.email!); + await this.stores.user.unconfirmOthersByEmail( + user.id, + user.email!, + canonical, + ); + await promoteToVerifiedGroup(this.stores.group, this.config, user); try { diff --git a/src/backend/stores/user/UserStore.ts b/src/backend/stores/user/UserStore.ts index 11c068a65..04d8531c6 100644 --- a/src/backend/stores/user/UserStore.ts +++ b/src/backend/stores/user/UserStore.ts @@ -419,6 +419,25 @@ export class UserStore extends PuterStore { } } + async unconfirmOthersByEmail( + userId: number, + email: string, + cleanEmailValue: string, + ): Promise { + await this.clients.db.write( + `UPDATE \`user\` + SET \`email\` = NULL, + \`clean_email\` = NULL, + \`email_confirmed\` = 0, + \`requires_email_confirmation\` = 0, + \`email_confirm_code\` = NULL, + \`email_confirm_token\` = NULL + WHERE \`id\` != ? + AND (\`email\` = ? OR \`clean_email\` = ?)`, + [userId, email, cleanEmailValue], + ); + } + async invalidate(user: UserRow): Promise { const keys = this.#cacheKeysForUser(user); await this.publishCacheKeys({ keys, broadcast: true });