From 03e964bad72f3cc390b50388fd054e3698b36370 Mon Sep 17 00:00:00 2001 From: Kosztyk <36381705+Kosztyk@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:04:49 +0200 Subject: [PATCH] Add files via upload --- src/pages/user.tsx | 122 ++++++++++++++++++++------------------------- 1 file changed, 53 insertions(+), 69 deletions(-) diff --git a/src/pages/user.tsx b/src/pages/user.tsx index abcff49..c133097 100644 --- a/src/pages/user.tsx +++ b/src/pages/user.tsx @@ -13,9 +13,19 @@ import { WEBROOT, } from "../helpers/env"; -export let FIRST_RUN = db.query("SELECT * FROM users").get() === null || false; +function computeFirstRun(): boolean { + // DB-driven, so it stays correct across reloads and multi-process setups. + return db.query("SELECT 1 FROM users LIMIT 1").get() === null; +} + +// Exported for backwards compatibility; refreshed per-request via userService.derive(). +export let FIRST_RUN = computeFirstRun(); export const userService = new Elysia({ name: "user/service" }) + .derive(() => { + FIRST_RUN = computeFirstRun(); + return {}; + }) .use( jwt({ name: "jwt", @@ -67,7 +77,7 @@ export const userService = new Elysia({ name: "user/service" }) export const user = new Elysia() .use(userService) .get("/setup", ({ redirect }) => { - if (!FIRST_RUN) { + if (!computeFirstRun()) { return redirect(`${WEBROOT}/login`, 302); } @@ -182,27 +192,28 @@ export const user = new Elysia() ); }) .post( - "/register", - async ({ body: { email, password }, set, redirect, jwt, cookie: { auth } }) => { - // first user allowed even if ACCOUNT_REGISTRATION=false - const isFirstUser = FIRST_RUN; + "/register", + async ({ body: { email, password }, set, redirect, jwt, cookie: { auth } }) => { + // DB-driven "first user" detection + race-safe creation. + // Hash outside the write-lock to keep the lock window short. + const savedPassword = await Bun.password.hash(password); + db.exec("BEGIN IMMEDIATE"); + try { + const isFirstUser = computeFirstRun(); + + // first user allowed even if ACCOUNT_REGISTRATION=false if (!ACCOUNT_REGISTRATION && !isFirstUser) { + db.exec("ROLLBACK"); return redirect(`${WEBROOT}/login`, 302); } - if (FIRST_RUN) { - FIRST_RUN = false; - } - - const existingUser = await db.query("SELECT * FROM users WHERE email = ?").get(email); + const existingUser = db.query("SELECT 1 FROM users WHERE email = ?").get(email); if (existingUser) { + db.exec("ROLLBACK"); set.status = 400; - return { - message: "Email already in use.", - }; + return { message: "Email already in use." }; } - const savedPassword = await Bun.password.hash(password); const role = isFirstUser ? "admin" : "user"; @@ -213,24 +224,25 @@ export const user = new Elysia() ); const userRow = db.query("SELECT * FROM users WHERE email = ?").as(User).get(email); - if (!userRow) { + db.exec("ROLLBACK"); set.status = 500; - return { - message: "Failed to create user.", - }; + return { message: "Failed to create user." }; } + db.exec("COMMIT"); + + // Refresh after successful creation + FIRST_RUN = computeFirstRun(); + const accessToken = await jwt.sign({ id: String(userRow.id), - role: userRow.role, + role: userRow.role ?? "user", }); if (!auth) { set.status = 500; - return { - message: "No auth cookie, perhaps your browser is blocking cookies.", - }; + return { message: "No auth cookie, perhaps your browser is blocking cookies." }; } // set cookie @@ -243,9 +255,18 @@ export const user = new Elysia() }); return redirect(`${WEBROOT}/`, 302); - }, - { body: "signIn" }, - ) + } catch (e) { + try { + db.exec("ROLLBACK"); + } catch (rollbackErr) { + console.warn("[user/register] ROLLBACK failed:", rollbackErr); + } + throw e; + } + }, + { body: "signIn" }, +) + .get( "/login", async ({ jwt, redirect, cookie: { auth } }) => { @@ -547,35 +568,18 @@ export const user = new Elysia() {u.email} {u.role} -
- {/* Edit / details icon */} +
- {/* Delete icon */}
@@ -817,9 +803,7 @@ export const user = new Elysia()