import { createHash, randomBytes } from "node:crypto"; import { cookies } from "next/headers"; import { redirect } from "next/navigation"; import { db } from "./db"; const COOKIE = "kibu_session"; export const tokenHash = (token: string) => createHash("sha256").update(token).digest("hex"); export type Staff = { id: string; email: string; name: string }; export async function currentStaff(): Promise { const token = (await cookies()).get(COOKIE)?.value; if (!token || !/^[a-f0-9]{64}$/.test(token)) return null; const result = await db.query( `SELECT s.id, s.email, s.name FROM sessions t JOIN staff s ON s.id = t.staff_id WHERE t.token_hash = $1 AND t.expires_at > now()`, [tokenHash(token)], ); return result.rows[0] ?? null; } export async function requireStaff() { const staff = await currentStaff(); if (!staff) redirect("/login"); return staff; } export async function createSession(staffId: string) { const token = randomBytes(32).toString("hex"); const expires = new Date(Date.now() + 12 * 60 * 60 * 1000); await db.query("DELETE FROM sessions WHERE expires_at <= now()"); await db.query("INSERT INTO sessions(token_hash, staff_id, expires_at) VALUES ($1, $2, $3)", [tokenHash(token), staffId, expires]); (await cookies()).set(COOKIE, token, { httpOnly: true, sameSite: "lax", secure: process.env.SESSION_SECURE === "true", path: "/", expires, }); } export async function deleteSession() { const jar = await cookies(); const token = jar.get(COOKIE)?.value; if (token) await db.query("DELETE FROM sessions WHERE token_hash = $1", [tokenHash(token)]); jar.delete(COOKIE); }