Files
LingvAI/utils/admin-auth.ts

56 lines
1.5 KiB
TypeScript
Raw Permalink Normal View History

import { SignJWT, jwtVerify } from "jose";
import { NextApiRequest, NextApiResponse } from "next";
import { readSettings } from "./settings-store";
const JWT_COOKIE = "lingva_admin";
const JWT_EXPIRY = "8h";
function getSecret(): Uint8Array {
const secret = process.env["ADMIN_JWT_SECRET"] ?? "lingva-admin-secret-change-me";
return new TextEncoder().encode(secret);
}
export async function signAdminToken(): Promise<string> {
return new SignJWT({ role: "admin" })
.setProtectedHeader({ alg: "HS256" })
.setIssuedAt()
.setExpirationTime(JWT_EXPIRY)
.sign(getSecret());
}
export async function verifyAdminToken(token: string): Promise<boolean> {
try {
await jwtVerify(token, getSecret());
return true;
} catch {
return false;
}
}
export function getTokenFromRequest(req: NextApiRequest): string | null {
const cookie = req.cookies[JWT_COOKIE];
if (cookie) return cookie;
const auth = req.headers.authorization;
if (auth?.startsWith("Bearer ")) return auth.slice(7);
return null;
}
export async function requireAdmin(
req: NextApiRequest,
res: NextApiResponse
): Promise<boolean> {
const token = getTokenFromRequest(req);
if (!token || !(await verifyAdminToken(token))) {
res.status(401).json({ error: "Unauthorized" });
return false;
}
return true;
}
export function checkPassword(password: string): boolean {
const settings = readSettings();
return password === settings.adminPasswordHash;
}
export const COOKIE_NAME = JWT_COOKIE;