import crypto from "node:crypto"; import type { User } from "@prisma/client"; import { cookies } from "next/headers"; import { redirect } from "next/navigation"; import { SESSION_COOKIE_NAME, SESSION_TTL_DAYS } from "@/lib/constants"; import { db } from "@/server/db"; import { AppError } from "@/server/errors"; const sessionTtlMs = SESSION_TTL_DAYS * 24 * 60 * 60 * 1000; function hashSessionToken(token: string) { return crypto.createHash("sha256").update(token).digest("hex"); } function createSessionToken() { return crypto.randomBytes(32).toString("hex"); } export async function createSession(userId: string) { const token = createSessionToken(); const expiresAt = new Date(Date.now() + sessionTtlMs); await db.session.create({ data: { userId, tokenHash: hashSessionToken(token), expiresAt, }, }); return { token, expiresAt }; } export async function setSessionCookie(token: string, expiresAt: Date) { const cookieStore = await cookies(); cookieStore.set(SESSION_COOKIE_NAME, token, { httpOnly: true, sameSite: "lax", secure: process.env.NODE_ENV === "production", path: "/", expires: expiresAt, }); } export async function clearSessionCookie() { const cookieStore = await cookies(); cookieStore.set(SESSION_COOKIE_NAME, "", { httpOnly: true, sameSite: "lax", secure: process.env.NODE_ENV === "production", path: "/", expires: new Date(0), }); } export async function getSessionToken() { const cookieStore = await cookies(); return cookieStore.get(SESSION_COOKIE_NAME)?.value; } export async function getCurrentSession() { const token = await getSessionToken(); if (!token) { return null; } const session = await db.session.findUnique({ where: { tokenHash: hashSessionToken(token), }, include: { user: true, }, }); if (!session) { return null; } if (session.expiresAt <= new Date()) { await db.session.delete({ where: { id: session.id, }, }); return null; } return session; } export async function getCurrentUser(): Promise { const session = await getCurrentSession(); return session?.user ?? null; } export async function requireCurrentUser() { const user = await getCurrentUser(); if (!user) { redirect("/login"); } return user; } export async function requireApiUser() { const user = await getCurrentUser(); if (!user) { throw new AppError("أنت محتاج تسجل الدخول الأول.", 401); } return user; } export async function redirectIfAuthenticated() { const user = await getCurrentUser(); if (user) { redirect("/dashboard/customers"); } } export async function destroyCurrentSession() { const token = await getSessionToken(); if (token) { const tokenHash = hashSessionToken(token); await db.session.deleteMany({ where: { tokenHash, }, }); } await clearSessionCookie(); }