35 lines
1.1 KiB
TypeScript
35 lines
1.1 KiB
TypeScript
import { NextRequest } from "next/server";
|
|
import { db } from "@/lib/db";
|
|
import crypto from "crypto";
|
|
import type { ReviewSession } from "@prisma/client";
|
|
|
|
export type TokenValidation =
|
|
| { type: "ok"; session: ReviewSession }
|
|
| { type: "invalid" }
|
|
| { type: "requiresPassword" };
|
|
|
|
export function makeUnlockCookieValue(token: string): string {
|
|
const secret = process.env.AUTH_SECRET ?? "fallback-secret";
|
|
return crypto.createHmac("sha256", secret).update(token).digest("hex");
|
|
}
|
|
|
|
export async function validateReviewToken(
|
|
token: string,
|
|
req: NextRequest
|
|
): Promise<TokenValidation> {
|
|
const session = await db.reviewSession.findUnique({ where: { token } });
|
|
if (!session || !session.isActive) return { type: "invalid" };
|
|
if (session.expiresAt && session.expiresAt < new Date()) return { type: "invalid" };
|
|
|
|
if (session.passwordHash) {
|
|
const cookieName = `rsauth_${token}`;
|
|
const cookieValue = req.cookies.get(cookieName)?.value;
|
|
const expected = makeUnlockCookieValue(token);
|
|
if (!cookieValue || cookieValue !== expected) {
|
|
return { type: "requiresPassword" };
|
|
}
|
|
}
|
|
|
|
return { type: "ok", session };
|
|
}
|