import { randomUUID } from "node:crypto"; import { jwt } from "@elysiajs/jwt"; import { Elysia, t } from "elysia"; import { BaseHtml } from "../components/base"; import { Header } from "../components/header"; import db from "../db/db"; import { User } from "../db/types"; import { ACCOUNT_REGISTRATION, ALLOW_UNAUTHENTICATED, HIDE_HISTORY, HTTP_ALLOWED, WEBROOT, } from "../helpers/env"; function computeFirstRun(): boolean { // DB-driven, so it stays correct across reloads and per-request updates. return db.query("SELECT 1 FROM users LIMIT 1").get() === null; } // Kept as an exported boolean for backwards-compatibility (e.g. root.tsx imports FIRST_RUN), // but it is refreshed per-request via userService. Do not rely on it being constant. export let FIRST_RUN = computeFirstRun(); export const userService = new Elysia({ name: "user/service" }) .derive(() => { FIRST_RUN = computeFirstRun(); return {}; }) .use( jwt({ name: "jwt", schema: t.Object({ id: t.String(), role: t.String(), // user role in JWT }), secret: process.env.JWT_SECRET ?? randomUUID(), exp: "7d", }), ) .model({ signIn: t.Object({ email: t.String(), password: t.String(), }), session: t.Cookie({ auth: t.String(), jobId: t.Optional(t.String()), }), optionalSession: t.Cookie({ auth: t.Optional(t.String()), jobId: t.Optional(t.String()), }), }) .macro("auth", { cookie: "session", async resolve({ status, jwt, cookie: { auth } }) { if (!auth.value) { return status(401, { success: false, message: "Unauthorized", }); } const user = await jwt.verify(auth.value); if (!user) { return status(401, { success: false, message: "Unauthorized", }); } return { success: true, user, }; }, }); export const user = new Elysia() .use(userService) .get("/setup", ({ redirect }) => { const isFirstRun = computeFirstRun(); if (!isFirstRun) { return redirect(`${WEBROOT}/login`, 302); } return (

Welcome to ConvertX!

Create your account
); }) .get("/register", ({ redirect }) => { if (!ACCOUNT_REGISTRATION) { return redirect(`${WEBROOT}/login`, 302); } return ( <>
); }) .post( "/register", async ({ body: { email, password }, set, redirect, jwt, cookie: { auth } }) => { // DB-driven "first user" detection (no stale in-memory flag) + race-safe creation. // We hash outside the write-lock to keep the lock window short. const savedPassword = await Bun.password.hash(password); // Acquire a write lock so only one instance can perform "count==0 then insert" at a time. 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); } 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.", }; } const role = isFirstUser ? "admin" : "user"; db.query("INSERT INTO users (email, password, role) VALUES (?, ?, ?)").run( email, savedPassword, role, ); 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.", }; } db.exec("COMMIT"); FIRST_RUN = false; const accessToken = await jwt.sign({ id: String(userRow.id), role: userRow.role ?? "user", }); if (!auth) { set.status = 500; return { message: "No auth cookie, perhaps your browser is blocking cookies.", }; } // set cookie auth.set({ value: accessToken, httpOnly: true, secure: !HTTP_ALLOWED, maxAge: 60 * 60 * 24 * 7, sameSite: "strict", }); return redirect(`${WEBROOT}/`, 302); } catch (e) { try { db.exec("ROLLBACK"); } catch { // ignore rollback errors } throw e; } }, { body: "signIn" }, ) .get( "/login", async ({ jwt, redirect, cookie: { auth } }) => { if (computeFirstRun()) { return redirect(`${WEBROOT}/setup`, 302); } // if already logged in, redirect to home if (auth?.value) { const user = await jwt.verify(auth.value); if (user) { return redirect(`${WEBROOT}/`, 302); } auth.remove(); } return ( <>
{ACCOUNT_REGISTRATION ? ( Register ) : null}
); }, { body: "signIn", cookie: "optionalSession" }, ) .post( "/login", async function handler({ body, set, redirect, jwt, cookie: { auth } }) { const existingUser = db.query("SELECT * FROM users WHERE email = ?").as(User).get( body.email, ); if (!existingUser) { set.status = 403; return { message: "Invalid credentials.", }; } const validPassword = await Bun.password.verify(body.password, existingUser.password); if (!validPassword) { set.status = 403; return { message: "Invalid credentials.", }; } const accessToken = await jwt.sign({ id: String(existingUser.id), role: existingUser.role ?? "user", }); if (!auth) { set.status = 500; return { message: "No auth cookie, perhaps your browser is blocking cookies.", }; } // set cookie auth.set({ value: accessToken, httpOnly: true, secure: !HTTP_ALLOWED, maxAge: 60 * 60 * 24 * 7, sameSite: "strict", }); return redirect(`${WEBROOT}/`, 302); }, { body: "signIn" }, ) .get("/logoff", ({ redirect, cookie: { auth } }) => { if (auth?.value) { auth.remove(); } return redirect(`${WEBROOT}/login`, 302); }) .post("/logoff", ({ redirect, cookie: { auth } }) => { if (auth?.value) { auth.remove(); } return redirect(`${WEBROOT}/login`, 302); }) .get( "/account", async ({ user, redirect }) => { if (!user) { return redirect(`${WEBROOT}/`, 302); } const userData = db.query("SELECT * FROM users WHERE id = ?").as(User).get(user.id); if (!userData) { return redirect(`${WEBROOT}/`, 302); } let otherUsers: { id: number; email: string; role: string }[] = []; if (userData.role === "admin") { otherUsers = db .query("SELECT id, email, role FROM users WHERE id != ? ORDER BY email ASC") .all(userData.id) as { id: number; email: string; role: string }[]; } return ( <>
{userData.role === "admin" && ( <>

Add new user

Create additional users for this ConvertX instance. Admins can create other admins or normal users.

{otherUsers.length > 0 && (

Manage users

Edit or delete users from this instance. You cannot delete yourself or the last remaining admin.

{otherUsers.map((u) => ( ))}
Email Role Actions
{u.email} {u.role}
{/* Edit / details icon */}
{/* Delete icon */}
)} )}
); }, { auth: true, }, ) .post( "/account", async function handler({ body, set, redirect, jwt, cookie: { auth } }) { if (!auth?.value) { return redirect(`${WEBROOT}/login`, 302); } const tokenUser = await jwt.verify(auth.value); if (!tokenUser) { return redirect(`${WEBROOT}/login`, 302); } const existingUser = db.query("SELECT * FROM users WHERE id = ?").as(User).get( tokenUser.id, ); if (!existingUser) { if (auth?.value) { auth.remove(); } return redirect(`${WEBROOT}/login`, 302); } const validPassword = await Bun.password.verify(body.password, existingUser.password); if (!validPassword) { set.status = 403; return { message: "Invalid credentials.", }; } const fields: string[] = []; // eslint-disable-next-line @typescript-eslint/no-explicit-any const values: any[] = []; if (body.email) { const existingUserWithEmail = await db .query("SELECT id FROM users WHERE email = ?") .as(User) .get(body.email); if (existingUserWithEmail && existingUserWithEmail.id.toString() !== tokenUser.id) { set.status = 409; return { message: "Email already in use." }; } fields.push("email"); values.push(body.email); } if (body.newPassword) { fields.push("password"); values.push(await Bun.password.hash(body.newPassword)); } if (fields.length > 0) { db.query( `UPDATE users SET ${fields.map((field) => `${field}=?`).join(", ")} WHERE id=?`, ).run(...values, tokenUser.id); } return redirect(`${WEBROOT}/`, 302); }, { body: t.Object({ email: t.MaybeEmpty(t.String()), newPassword: t.MaybeEmpty(t.String()), password: t.String(), }), cookie: "session", }, ) .post( "/account/add-user", async ({ body, set, redirect, jwt, cookie: { auth } }) => { if (!auth?.value) { return redirect(`${WEBROOT}/login`, 302); } const tokenUser = await jwt.verify(auth.value); if (!tokenUser) { return redirect(`${WEBROOT}/login`, 302); } const actingUser = db.query("SELECT * FROM users WHERE id = ?").as(User).get(tokenUser.id); if (!actingUser) { if (auth?.value) { auth.remove(); } return redirect(`${WEBROOT}/login`, 302); } if (actingUser.role !== "admin") { set.status = 403; return { message: "Only admins can create new users.", }; } const { newUserEmail, newUserPassword, newUserRole } = body as { newUserEmail: string; newUserPassword: string; newUserRole: string; }; if (!newUserEmail || !newUserPassword) { set.status = 400; return { message: "Missing email or password.", }; } const existingNewUser = db.query("SELECT id FROM users WHERE email = ?").get(newUserEmail); if (existingNewUser) { set.status = 400; return { message: "A user with this email already exists.", }; } const hashedPassword = await Bun.password.hash(newUserPassword); const role = newUserRole === "admin" ? "admin" : "user"; db.query("INSERT INTO users (email, password, role) VALUES (?, ?, ?)").run( newUserEmail, hashedPassword, role, ); return redirect(`${WEBROOT}/account`, 302); }, { body: t.Object({ newUserEmail: t.String(), newUserPassword: t.String(), newUserRole: t.String(), }), cookie: "session", }, ) .get( "/account/edit-user", async ({ query, user, redirect }) => { if (!user) { return redirect(`${WEBROOT}/login`, 302); } const actingUser = db.query("SELECT * FROM users WHERE id = ?").as(User).get(user.id); if (!actingUser || actingUser.role !== "admin") { return redirect(`${WEBROOT}/account`, 302); } const targetId = Number.parseInt(query.userId, 10); if (!Number.isFinite(targetId) || targetId === actingUser.id) { return redirect(`${WEBROOT}/account`, 302); } const targetUser = db.query("SELECT * FROM users WHERE id = ?").as(User).get(targetId); if (!targetUser) { return redirect(`${WEBROOT}/account`, 302); } return ( <>

Edit user

Change this user's role or set a new password. Leave password blank to keep it unchanged.

Cancel
); }, { auth: true, query: t.Object({ userId: t.String(), }), }, ) .post( "/account/edit-user", async ({ body, set, redirect, jwt, cookie: { auth } }) => { if (!auth?.value) { return redirect(`${WEBROOT}/login`, 302); } const tokenUser = await jwt.verify(auth.value); if (!tokenUser) { return redirect(`${WEBROOT}/login`, 302); } const actingUser = db.query("SELECT * FROM users WHERE id = ?").as(User).get(tokenUser.id); if (!actingUser || actingUser.role !== "admin") { set.status = 403; return { message: "Only admins can edit users." }; } const { userId, role, newPassword } = body as { userId: string; role: string; newPassword?: string; }; const targetId = Number.parseInt(userId, 10); if (!Number.isFinite(targetId) || targetId === actingUser.id) { return redirect(`${WEBROOT}/account`, 302); } const targetUser = db.query("SELECT * FROM users WHERE id = ?").as(User).get(targetId); if (!targetUser) { return redirect(`${WEBROOT}/account`, 302); } // Prevent demoting the last admin if (targetUser.role === "admin" && role !== "admin") { const adminCountRow = db .query("SELECT COUNT(*) AS cnt FROM users WHERE role = 'admin'") .get() as { cnt: number }; if (adminCountRow.cnt <= 1) { set.status = 400; return { message: "You cannot demote the last remaining admin." }; } } const fields: string[] = []; // eslint-disable-next-line @typescript-eslint/no-explicit-any const values: any[] = []; if (role === "admin" || role === "user") { fields.push("role"); values.push(role); } if (newPassword && newPassword.trim().length > 0) { fields.push("password"); values.push(await Bun.password.hash(newPassword)); } if (fields.length > 0) { db.query( `UPDATE users SET ${fields.map((f) => `${f}=?`).join(", ")} WHERE id=?`, ).run(...values, targetId); } return redirect(`${WEBROOT}/account`, 302); }, { body: t.Object({ userId: t.String(), role: t.String(), newPassword: t.MaybeEmpty(t.String()), }), cookie: "session", }, ) .post( "/account/delete-user", async ({ body, set, redirect, jwt, cookie: { auth } }) => { if (!auth?.value) { return redirect(`${WEBROOT}/login`, 302); } const tokenUser = await jwt.verify(auth.value); if (!tokenUser) { return redirect(`${WEBROOT}/login`, 302); } const actingUser = db.query("SELECT * FROM users WHERE id = ?").as(User).get(tokenUser.id); if (!actingUser) { if (auth?.value) { auth.remove(); } return redirect(`${WEBROOT}/login`, 302); } if (actingUser.role !== "admin") { set.status = 403; return { message: "Only admins can delete users." }; } const { deleteUserId } = body as { deleteUserId: string }; const targetId = Number.parseInt(deleteUserId, 10); if (!Number.isFinite(targetId)) { set.status = 400; return { message: "Invalid user id." }; } if (targetId === actingUser.id) { set.status = 400; return { message: "You cannot delete your own account from here." }; } const targetUser = db .query("SELECT * FROM users WHERE id = ?") .as(User) .get(targetId as unknown as number); if (!targetUser) { return redirect(`${WEBROOT}/account`, 302); } if (targetUser.role === "admin") { const adminCountRow = db .query("SELECT COUNT(*) AS cnt FROM users WHERE role = 'admin'") .get() as { cnt: number }; if (adminCountRow.cnt <= 1) { set.status = 400; return { message: "You cannot delete the last remaining admin." }; } } // delete this user's jobs and files (to avoid FK issues) in a single transaction const deleteUserTx = db.transaction((id: number) => { db.query( "DELETE FROM file_names WHERE job_id IN (SELECT id FROM jobs WHERE user_id = ?)", ).run(id); db.query("DELETE FROM jobs WHERE user_id = ?").run(id); db.query("DELETE FROM users WHERE id = ?").run(id); }); deleteUserTx(targetId); return redirect(`${WEBROOT}/account`, 302); }, { body: t.Object({ deleteUserId: t.String(), }), cookie: "session", }, );