| import { SignJWT, jwtVerify } from "jose"; |
| import bcrypt from "bcryptjs"; |
| import fs from "node:fs"; |
| import path from "node:path"; |
| import crypto from "node:crypto"; |
| import { DATA_DIR } from "@/lib/dataDir"; |
| import { getSettings } from "@/lib/localDb"; |
|
|
| const DEFAULT_PASSWORD = "123456"; |
|
|
| function loadJwtSecret() { |
| if (process.env.JWT_SECRET) return process.env.JWT_SECRET; |
| const file = path.join(DATA_DIR, "jwt-secret"); |
| try { |
| return fs.readFileSync(file, "utf8").trim(); |
| } catch {} |
| fs.mkdirSync(DATA_DIR, { recursive: true }); |
| const generated = crypto.randomBytes(32).toString("hex"); |
| fs.writeFileSync(file, generated, { mode: 0o600 }); |
| return generated; |
| } |
|
|
| const SECRET = new TextEncoder().encode(loadJwtSecret()); |
|
|
| export function shouldUseSecureCookie(request) { |
| const forceSecureCookie = process.env.AUTH_COOKIE_SECURE === "true"; |
| const forwardedProto = request?.headers?.get?.("x-forwarded-proto"); |
| const isHttpsRequest = forwardedProto === "https"; |
| return forceSecureCookie || isHttpsRequest; |
| } |
|
|
| export async function createDashboardAuthToken(claims = {}) { |
| return new SignJWT({ authenticated: true, ...claims }) |
| .setProtectedHeader({ alg: "HS256" }) |
| .setIssuedAt() |
| .setExpirationTime("24h") |
| .sign(SECRET); |
| } |
|
|
| export async function verifyDashboardAuthToken(token) { |
| if (!token) return false; |
| try { |
| await jwtVerify(token, SECRET); |
| return true; |
| } catch { |
| return false; |
| } |
| } |
|
|
| export async function getDashboardAuthSession(token) { |
| if (!token) return null; |
| try { |
| const { payload } = await jwtVerify(token, SECRET); |
| return payload; |
| } catch { |
| return null; |
| } |
| } |
|
|
| export async function setDashboardAuthCookie(cookieStore, request, claims = {}) { |
| const token = await createDashboardAuthToken(claims); |
| cookieStore.set("auth_token", token, { |
| httpOnly: true, |
| secure: shouldUseSecureCookie(request), |
| sameSite: "lax", |
| path: "/", |
| }); |
| } |
|
|
| export function clearDashboardAuthCookie(cookieStore) { |
| cookieStore.delete("auth_token"); |
| } |
|
|
| |
| export async function verifyDashboardPassword(password) { |
| if (typeof password !== "string" || !password) return false; |
| const settings = await getSettings(); |
| const storedHash = settings?.password; |
| if (storedHash) return bcrypt.compare(password, storedHash); |
| const initialPassword = process.env.INITIAL_PASSWORD || DEFAULT_PASSWORD; |
| return password === initialPassword; |
| } |
|
|