diff --git a/app/server/cli/commands/change-email.test.ts b/app/server/cli/commands/change-email.test.ts index fa94f403..93fd172c 100644 --- a/app/server/cli/commands/change-email.test.ts +++ b/app/server/cli/commands/change-email.test.ts @@ -130,4 +130,22 @@ describe("changeEmailForUser", () => { expect(impact.ssoAccounts).toEqual([]); }); + + test("rejects changing to the same email and leaves SSO accounts and sessions unchanged", async () => { + const user = await insertUser("grace", "grace@example.com"); + await insertCredentialAccount(user.id); + await insertSsoAccount(user.id, "oidc-google", "google-grace"); + await insertSession(user.id); + + await expect(changeEmailForUser("grace", "grace@example.com")).rejects.toThrow("already has email"); + + const impact = await getEmailChangeImpact("grace", "grace-different@example.com"); + expect(impact.ssoAccounts).toEqual([{ providerId: "oidc-google", accountId: "google-grace" }]); + + const sessions = await db + .select({ id: sessionsTable.id }) + .from(sessionsTable) + .where(eq(sessionsTable.userId, user.id)); + expect(sessions).toHaveLength(1); + }); }); diff --git a/app/server/cli/commands/change-email.ts b/app/server/cli/commands/change-email.ts index bf17a8ea..a1b2e8ac 100644 --- a/app/server/cli/commands/change-email.ts +++ b/app/server/cli/commands/change-email.ts @@ -52,6 +52,10 @@ export const getEmailChangeImpact = async (username: string, newEmail: string): throw new Error(`User "${username}" not found`); } + if (user.email.trim().toLowerCase() === normalizedEmail) { + throw new Error(`User "${username}" already has email "${normalizedEmail}"`); + } + const [existingUser] = await db .select({ id: usersTable.id }) .from(usersTable)