Files
9router/src/app/api/auth/login/route.js

67 lines
2.3 KiB
JavaScript

import { NextResponse } from "next/server";
import { getSettings } from "@/lib/localDb";
import bcrypt from "bcryptjs";
import { SignJWT } from "jose";
import { cookies } from "next/headers";
const SECRET = new TextEncoder().encode(
process.env.JWT_SECRET || "9router-default-secret-change-me"
);
function isTunnelRequest(request, settings) {
const host = (request.headers.get("host") || "").split(":")[0].toLowerCase();
const tunnelHost = settings.tunnelUrl ? new URL(settings.tunnelUrl).hostname.toLowerCase() : "";
const tailscaleHost = settings.tailscaleUrl ? new URL(settings.tailscaleUrl).hostname.toLowerCase() : "";
return (tunnelHost && host === tunnelHost) || (tailscaleHost && host === tailscaleHost);
}
export async function POST(request) {
try {
const { password } = await request.json();
const settings = await getSettings();
// Block login via tunnel/tailscale if dashboard access is disabled
if (isTunnelRequest(request, settings) && settings.tunnelDashboardAccess !== true) {
return NextResponse.json({ error: "Dashboard access via tunnel is disabled" }, { status: 403 });
}
// Default password is '123456' if not set
const storedHash = settings.password;
let isValid = false;
if (storedHash) {
isValid = await bcrypt.compare(password, storedHash);
} else {
// Use env var or default
const initialPassword = process.env.INITIAL_PASSWORD || "123456";
isValid = password === initialPassword;
}
if (isValid) {
const forceSecureCookie = process.env.AUTH_COOKIE_SECURE === "true";
const forwardedProto = request.headers.get("x-forwarded-proto");
const isHttpsRequest = forwardedProto === "https";
const useSecureCookie = forceSecureCookie || isHttpsRequest;
const token = await new SignJWT({ authenticated: true })
.setProtectedHeader({ alg: "HS256" })
.setExpirationTime("24h")
.sign(SECRET);
const cookieStore = await cookies();
cookieStore.set("auth_token", token, {
httpOnly: true,
secure: useSecureCookie,
sameSite: "lax",
path: "/",
});
return NextResponse.json({ success: true });
}
return NextResponse.json({ error: "Invalid password" }, { status: 401 });
} catch (error) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
}