import type { Handler } from 'hono'; import { sendMail } from 'emailer'; import { getUserCount, createUser } from 'officerdb'; import { sign, verify } from '@@/jwt'; import argon2 from 'argon2'; import * as errors from '@@/custom-errors'; import { validatePassword } from './validate-password'; export const bootstrapHandler: Handler = async function (ctx) { const body = ctx.get('body'); const origin = ctx.get('origin'); const token = body.token as string; const email = body.email as string; const userCount = await getUserCount(); if (userCount > 0) throw errors.FORBIDDEN('Registration is closed'); if (!token) { if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { throw errors.BAD_REQUEST('Invalid email address'); } const verificationCode = await sign({ email }, '24h'); const url = `${origin}/auth/verify?verificationCode=${verificationCode}`; await sendMail({ template: 'VerifyAdmin', subject: 'Verify your officer.dev account', to: email, data: { name: email, url }, }); return ctx.json({ ok: true }); } const payload = ((await verify(token).catch(() => null)) as { email: string } | null); if (!payload?.email) throw errors.BAD_REQUEST('Invalid or expired token'); const name = body.name as string; const username = body.username as string; const password = body.password as string; const confirmPassword = body.confirmPassword as string; if (!name || !name.trim()) throw errors.BAD_REQUEST('Name is required'); if (!username || !username.trim()) throw errors.BAD_REQUEST('Username is required'); validatePassword(password); if (password !== confirmPassword) throw errors.BAD_REQUEST('Passwords do not match'); const passwordHash = await argon2.hash(password); await createUser({ email: payload.email, password: passwordHash, name: name.trim(), username: username.trim(), role: 'Super Admin', status: 'Active', }); return ctx.json({ ok: true }); };