fix: enforce unique usernames (#1628)

* fix: enforce unique usernames

Registration checked for a taken name, hashed the password, then
inserted, with nothing in the schema enforcing uniqueness. Concurrent
sign-ups could create two accounts with one name, after which login,
password reset, proxy login and admin lookups by username picked
between them arbitrarily.

Add a unique index on users.username for every dialect. Existing
duplicates are renamed (later rows get a -<id> suffix, the oldest keeps
the name) rather than deleted. Registration and admin user creation now
return the same 409 when the insert loses the race.

* fix: avoid username collisions during migration
This commit is contained in:
ZacharyZcR authored and GitHub committed 2026-10-14 08:17:47 +08:00
1 parent 3941dd4ecc
commit e610aba0e5
19 files changed
+14354 -26

No files matched your search

+13 -7
View File
@@ -21,13 +21,19 @@ import {
} from "drizzle-orm/mysql-core";
import { sql } from "drizzle-orm";
export const users = mysqlTable("users", {
id: varchar("id", { length: 255 }).primaryKey(),
username: text("username").notNull(),
passwordHash: text("password_hash").notNull(),
isAdmin: boolean("is_admin").notNull().default(false),
registeredAt: text("registered_at").notNull().default(sql`(CURRENT_TIMESTAMP)`),
});
export const users = mysqlTable(
"users",
{
id: varchar("id", { length: 255 }).primaryKey(),
username: varchar("username", { length: 255 }).notNull(),
passwordHash: text("password_hash").notNull(),
isAdmin: boolean("is_admin").notNull().default(false),
registeredAt: text("registered_at")
.notNull()
.default(sql`(CURRENT_TIMESTAMP)`),
},
(table) => [uniqueIndex("idx_users_username").on(table.username)],
);
export const settings = mysqlTable("settings", {
key: varchar("key", { length: 255 }).primaryKey(),