phosphat-report-app/app/utils/auth.server.ts
2025-07-24 12:39:15 +03:00

129 lines
3.8 KiB
TypeScript

import { createCookieSessionStorage, redirect } from "@remix-run/node";
import { PrismaClient } from "@prisma/client";
import bcrypt from "bcryptjs";
const prisma = new PrismaClient();
// Session storage
const sessionSecret = process.env.SESSION_SECRET || "default-secret";
const { getSession, commitSession, destroySession } = createCookieSessionStorage({
cookie: {
name: "__session",
httpOnly: true,
maxAge: 60 * 60 * 24 * 7, // 7 days
path: "/",
sameSite: "lax",
secrets: [sessionSecret],
secure: process.env.NODE_ENV === "production",
},
});
export { getSession, commitSession, destroySession };
// Auth functions
export async function createUserSession(userId: number, redirectTo: string) {
const session = await getSession();
session.set("userId", userId);
return redirect(redirectTo, {
headers: {
"Set-Cookie": await commitSession(session),
},
});
}
export async function getUserSession(request: Request) {
return getSession(request.headers.get("Cookie"));
}
export async function getUserId(request: Request) {
const session = await getUserSession(request);
const userId = session.get("userId");
if (!userId || typeof userId !== "number") return null;
return userId;
}
export async function requireUserId(request: Request, redirectTo: string = "/signin") {
const userId = await getUserId(request);
if (!userId) {
const searchParams = new URLSearchParams([["redirectTo", new URL(request.url).pathname]]);
throw redirect(`${redirectTo}?${searchParams}`);
}
return userId;
}
export async function getUser(request: Request) {
const userId = await getUserId(request);
if (!userId) return null;
try {
const user = await prisma.employee.findUnique({
where: { id: userId },
select: { id: true, name: true, username: true, email: true, authLevel: true },
});
return user;
} catch {
throw logout(request);
}
}
export async function requireUser(request: Request) {
const user = await getUser(request);
if (!user) {
throw redirect("/signin");
}
return user;
}
export async function requireAuthLevel(request: Request, minLevel: number = 2) {
const user = await requireUser(request);
if (user.authLevel < minLevel) {
throw redirect("/signin");
//throw new Response("Unauthorized", { status: 403 });
// redirect to dashboard page
//redirect("/dashboard");
}
return user;
}
export async function logout(request: Request) {
const session = await getUserSession(request);
return redirect("/signin", {
headers: {
"Set-Cookie": await destroySession(session),
},
});
}
export async function verifyLogin(usernameOrEmail: string, password: string) {
// Try to find user by username first, then by email
const user = await prisma.employee.findFirst({
where: {
OR: [
{ username: usernameOrEmail },
{ email: usernameOrEmail }
]
}
});
if (!user || !bcrypt.compareSync(password, user.password)) {
return null;
}
return { id: user.id, username: user.username, email: user.email, name: user.name, authLevel: user.authLevel };
}
export async function createUser(name: string, username: string, email: string, password: string, authLevel: number = 1) {
const hashedPassword = bcrypt.hashSync(password, 10);
const user = await prisma.employee.create({
data: {
name,
username,
email,
password: hashedPassword,
authLevel,
},
});
return { id: user.id, username: user.username, email: user.email, name: user.name, authLevel: user.authLevel };
}