import bcrypt from "bcryptjs"; import { createCookieSessionStorage, redirect } from "@remix-run/node"; import { prisma } from "./db.server"; import type { User } from "@prisma/client"; // Session configuration const sessionSecret = process.env.SESSION_SECRET; if (!sessionSecret) { throw new Error("SESSION_SECRET must be set"); } // Create session storage const storage = createCookieSessionStorage({ cookie: { name: "car_maintenance_session", secure: process.env.NODE_ENV === "production", secrets: [sessionSecret], sameSite: "lax", path: "/", maxAge: 60 * 60 * 24 * 30, // 30 days httpOnly: true, }, }); // Password hashing utilities export async function hashPassword(password: string): Promise { return bcrypt.hash(password, 12); } export async function verifyPassword( password: string, hashedPassword: string ): Promise { return bcrypt.compare(password, hashedPassword); } // Session management functions export async function createUserSession( userId: number, redirectTo: string = "/dashboard" ) { const session = await storage.getSession(); session.set("userId", userId); return redirect(redirectTo, { headers: { "Set-Cookie": await storage.commitSession(session), }, }); } export async function getUserSession(request: Request) { return storage.getSession(request.headers.get("Cookie")); } export async function getUserId(request: Request): Promise { 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 = new URL(request.url).pathname ) { const userId = await getUserId(request); if (!userId) { const searchParams = new URLSearchParams([["redirectTo", redirectTo]]); throw redirect(`/signin?${searchParams}`); } return userId; } export async function getUser(request: Request): Promise | null> { const userId = await getUserId(request); if (!userId) return null; try { const user = await prisma.user.findUnique({ where: { id: userId }, select: { id: true, name: true, username: true, email: true, status: true, authLevel: true, createdDate: true, editDate: true, }, }); return user; } catch { throw logout(request); } } export async function requireUser(request: Request) { const user = await getUser(request); if (!user) { throw logout(request); } return user; } export async function logout(request: Request) { const session = await getUserSession(request); return redirect("/signin", { headers: { "Set-Cookie": await storage.destroySession(session), }, }); }