"use server"; import { compare, hash } from "bcryptjs"; import { redirect } from "next/navigation"; import { Prisma, type User } from "@prisma/client"; import { prisma } from "./prisma"; import { clearSession, setSession } from "./session"; import { getAppSettings } from "./settings"; function normalizeUsername(value: FormDataEntryValue | null) { return String(value || "") .trim() .toLowerCase() .replace(/[^a-z0-9_-]/g, ""); } export async function registerUser(formData: FormData) { const settings = await getAppSettings(); if (settings.registrationMode !== "OPEN") { redirect("/register?error=closed"); } const username = normalizeUsername(formData.get("username")); const password = String(formData.get("password") || ""); if (!username || password.length < 10) { redirect("/register?error=invalid"); } const passwordHash = await hash(password, 12); let user: User; try { user = await prisma.user.create({ data: { username, displayName: username, passwordHash, ownedRooms: { create: { slug: `@${username}`, name: `${username}'s room`, visibility: "FRIENDS" } } } }); } catch (error) { if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2002") { redirect("/register?error=username"); } throw error; } await setSession(user.id); redirect("/dashboard"); } export async function loginUser(formData: FormData) { const username = normalizeUsername(formData.get("username")); const password = String(formData.get("password") || ""); const user = await prisma.user.findUnique({ where: { username } }); if (!user) { redirect("/login?error=credentials"); } const ok = await compare(password, user.passwordHash); if (!ok) { redirect("/login?error=credentials"); } await setSession(user.id); redirect("/dashboard"); } export async function logoutUser() { await clearSession(); redirect("/login"); }