9router / src /lib /auth /dashboardSession.js
2api
feat: configurable stream stall timeout + per-provider UI
88c4c60
Raw
History Blame Contribute Delete
2.49 kB
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");
}
// Verify the current dashboard password (re-auth for sensitive actions).
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;
}