import "server-only"; import { randomUUID } from "node:crypto"; import bcrypt from "bcryptjs"; import { cache } from "react"; import { cookies } from "next/headers"; import { redirect } from "next/navigation"; import { createSessionRecord, deleteSessionRecord, getSessionUser, getUserByUsername, normalizeUsername, } from "@/lib/db"; import { appConfig } from "@/lib/config"; import type { PublicUser, SessionRecord, UserRecord } from "@/lib/types"; export const SESSION_COOKIE_NAME = "image_prompt_session"; export function toPublicUser(user: UserRecord | null): PublicUser | null { if (!user) { return null; } return { id: user.id, username: user.username, role: user.role, isActive: user.isActive, monthlyQuota: user.monthlyQuota, createdAt: user.createdAt, updatedAt: user.updatedAt, }; } export function hashPassword(password: string): string { return bcrypt.hashSync(String(password), 12); } export function verifyPassword( password: string, passwordHash: string, ): boolean { return bcrypt.compareSync(String(password), passwordHash); } export function authenticateUser( username: string, password: string, ): UserRecord | null { const user = getUserByUsername(normalizeUsername(username)); if (!user || !user.isActive) { return null; } if (!verifyPassword(password, user.passwordHash)) { return null; } return user; } export function createSessionForUser(userId: string): SessionRecord { const sessionId = randomUUID(); const expiresAt = new Date( Date.now() + appConfig.sessionDays * 24 * 60 * 60 * 1000, ).toISOString(); createSessionRecord({ sessionId, userId, expiresAt, }); return { sessionId, userId, expiresAt, }; } export function getSessionCookieOptions(expiresAt: string) { return { httpOnly: true, secure: process.env.NODE_ENV === "production", sameSite: "lax" as const, path: "/", expires: new Date(expiresAt), }; } export function clearSessionById(sessionId: string | undefined): void { if (!sessionId) { return; } deleteSessionRecord(sessionId); } export function getUserFromSessionToken( sessionToken: string | undefined, ): UserRecord | null { if (!sessionToken) { return null; } return getSessionUser(sessionToken); } export async function getCurrentUser(): Promise { const cookieStore = await cookies(); const sessionToken = cookieStore.get(SESSION_COOKIE_NAME)?.value; return getUserFromSessionToken(sessionToken); } export const getCachedCurrentUser = cache(getCurrentUser); export async function requireCurrentUser(): Promise { const user = await getCachedCurrentUser(); if (!user) { redirect("/login"); } if (!user.isActive) { redirect("/login?reason=inactive"); } return user; } export async function requireAdminUser(): Promise { const user = await requireCurrentUser(); if (user.role !== "admin") { redirect("/studio"); } return user; }