60 lines
1.5 KiB
TypeScript
60 lines
1.5 KiB
TypeScript
|
|
"use server";
|
||
|
|
|
||
|
|
import { compare, hash } from "bcryptjs";
|
||
|
|
import { redirect } from "next/navigation";
|
||
|
|
import { prisma } from "./prisma";
|
||
|
|
import { setSession } from "./session";
|
||
|
|
|
||
|
|
function normalizeUsername(value: FormDataEntryValue | null) {
|
||
|
|
return String(value || "")
|
||
|
|
.trim()
|
||
|
|
.toLowerCase()
|
||
|
|
.replace(/[^a-z0-9_-]/g, "");
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function registerUser(formData: FormData) {
|
||
|
|
const username = normalizeUsername(formData.get("username"));
|
||
|
|
const password = String(formData.get("password") || "");
|
||
|
|
|
||
|
|
if (!username || password.length < 10) {
|
||
|
|
throw new Error("Username is required and password must be at least 10 characters.");
|
||
|
|
}
|
||
|
|
|
||
|
|
const passwordHash = await hash(password, 12);
|
||
|
|
const user = await prisma.user.create({
|
||
|
|
data: {
|
||
|
|
username,
|
||
|
|
displayName: username,
|
||
|
|
passwordHash,
|
||
|
|
ownedRooms: {
|
||
|
|
create: {
|
||
|
|
slug: `@${username}`,
|
||
|
|
name: `${username}'s room`,
|
||
|
|
visibility: "FRIENDS"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
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) {
|
||
|
|
throw new Error("Invalid username or password.");
|
||
|
|
}
|
||
|
|
|
||
|
|
const ok = await compare(password, user.passwordHash);
|
||
|
|
if (!ok) {
|
||
|
|
throw new Error("Invalid username or password.");
|
||
|
|
}
|
||
|
|
|
||
|
|
await setSession(user.id);
|
||
|
|
redirect("/dashboard");
|
||
|
|
}
|