52 lines
1.5 KiB
TypeScript
52 lines
1.5 KiB
TypeScript
import { NextRequest } from 'next/server';
|
|
import { eq } from 'drizzle-orm';
|
|
import crypto from 'crypto';
|
|
import { db, guests, type Guest } from '@/lib/db';
|
|
import { ADM_COOKIE, USR_COOKIE } from './cookies';
|
|
|
|
function constantTimeEquals(a: string, b: string): boolean {
|
|
const ab = Buffer.from(a);
|
|
const bb = Buffer.from(b);
|
|
if (ab.length !== bb.length) return false;
|
|
return crypto.timingSafeEqual(ab, bb);
|
|
}
|
|
|
|
export function getAdminToken(): string {
|
|
const t = process.env.ADMIN_TOKEN;
|
|
if (!t || t.length < 16) {
|
|
throw new Error('ADMIN_TOKEN env var must be set and at least 16 chars');
|
|
}
|
|
return t;
|
|
}
|
|
|
|
export function verifyAdminToken(req: NextRequest): boolean {
|
|
const cookie = req.cookies.get(ADM_COOKIE)?.value;
|
|
if (!cookie) return false;
|
|
try {
|
|
return constantTimeEquals(cookie, getAdminToken());
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export async function getGuestFromRequest(req: NextRequest): Promise<Guest | null> {
|
|
const cookie = req.cookies.get(USR_COOKIE)?.value;
|
|
if (!cookie) return null;
|
|
const rows = await db.select().from(guests).where(eq(guests.id, cookie)).limit(1);
|
|
return rows[0] ?? null;
|
|
}
|
|
|
|
export function isAdminTokenValue(token: string): boolean {
|
|
try {
|
|
return constantTimeEquals(token, getAdminToken());
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export async function isGuestTokenValue(token: string): Promise<Guest | null> {
|
|
if (!token) return null;
|
|
const rows = await db.select().from(guests).where(eq(guests.id, token)).limit(1);
|
|
return rows[0] ?? null;
|
|
}
|