mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-31 07:35:24 +00:00
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:
1 parent
3941dd4ecc
commit
e610aba0e5
19 files changed
+14354
-26
No files matched your search
@@ -1,6 +1,9 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { TestSqliteDatabase } from "./test-support.js";
|
||||
import { UserRepository } from "../../../database/repositories/user-repository.js";
|
||||
import {
|
||||
UserRepository,
|
||||
isUsernameTaken,
|
||||
} from "../../../database/repositories/user-repository.js";
|
||||
|
||||
describe("UserRepository.listPage", () => {
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
@@ -93,3 +96,27 @@ describe("UserRepository.listPage", () => {
|
||||
expect(page.total).toBe(5);
|
||||
});
|
||||
});
|
||||
|
||||
describe("UserRepository.create", () => {
|
||||
let adapter: TestSqliteDatabase | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (adapter) {
|
||||
await adapter.close();
|
||||
adapter = null;
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects a taken username in a way callers can recognise", async () => {
|
||||
adapter = new TestSqliteDatabase();
|
||||
const repo = new UserRepository(await adapter.connect());
|
||||
await repo.create({ id: "u1", username: "alice", passwordHash: "hash" });
|
||||
|
||||
const error = await repo
|
||||
.create({ id: "u2", username: "alice", passwordHash: "hash" })
|
||||
.catch((e: unknown) => e);
|
||||
|
||||
expect(isUsernameTaken(error)).toBe(true);
|
||||
expect(isUsernameTaken(new Error("unrelated"))).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user