From bf99c600f18a06f3a8cec8e635d3c3599482de78 Mon Sep 17 00:00:00 2001 From: decolua Date: Fri, 27 Mar 2026 11:45:54 +0700 Subject: [PATCH] Fix Bug --- package.json | 2 +- .../dashboard/providers/[id]/page.js | 7 +++ .../(dashboard)/dashboard/providers/page.js | 7 --- src/dashboardGuard.js | 61 +++++++++++++++++++ src/proxy.js | 11 +++- 5 files changed, 79 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 6849f7a..7955492 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "9router-app", - "version": "0.3.62", + "version": "0.3.64", "description": "9Router web dashboard", "private": true, "scripts": { diff --git a/src/app/(dashboard)/dashboard/providers/[id]/page.js b/src/app/(dashboard)/dashboard/providers/[id]/page.js index 00f45ed..7cb9eff 100644 --- a/src/app/(dashboard)/dashboard/providers/[id]/page.js +++ b/src/app/(dashboard)/dashboard/providers/[id]/page.js @@ -682,6 +682,13 @@ export default function ProviderDetailPage() { + {providerInfo.deprecated && ( +
+ info +

{providerInfo.deprecationNotice}

+
+ )} + {isCompatible && providerNode && (
diff --git a/src/app/(dashboard)/dashboard/providers/page.js b/src/app/(dashboard)/dashboard/providers/page.js index 219ccdd..f23edea 100644 --- a/src/app/(dashboard)/dashboard/providers/page.js +++ b/src/app/(dashboard)/dashboard/providers/page.js @@ -489,7 +489,6 @@ export default function ProvidersPage() { function ProviderCard({ providerId, provider, stats, authType, onToggle }) { const { connected, error, errorCode, errorTime, allDisabled } = stats; - const isDeprecated = !!provider.deprecated; const dotColors = { free: "bg-green-500", @@ -572,12 +571,6 @@ function ProviderCard({ providerId, provider, stats, authType, onToggle }) { )}
- {isDeprecated && ( -
- warning -

{provider.deprecationNotice}

-
- )}
); diff --git a/src/dashboardGuard.js b/src/dashboardGuard.js index a683a6c..bff3b23 100644 --- a/src/dashboardGuard.js +++ b/src/dashboardGuard.js @@ -5,9 +5,70 @@ const SECRET = new TextEncoder().encode( process.env.JWT_SECRET || "9router-default-secret-change-me" ); +// Always require JWT token regardless of requireLogin setting +const ALWAYS_PROTECTED = [ + "/api/shutdown", + "/api/settings/database", +]; + +// Require auth, but allow through if requireLogin is disabled +const PROTECTED_API_PATHS = [ + "/api/settings", + "/api/keys", + "/api/providers/client", + "/api/provider-nodes/validate", +]; + +function isLocalRequest(request) { + const host = request.headers.get("host") || ""; + const hostname = host.split(":")[0]; + return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1"; +} + +async function hasValidToken(request) { + const token = request.cookies.get("auth_token")?.value; + if (!token) return false; + try { + await jwtVerify(token, SECRET); + return true; + } catch { + return false; + } +} + +async function isAuthenticated(request) { + if (await hasValidToken(request)) return true; + // Allow if requireLogin is disabled + const origin = request.nextUrl.origin; + try { + const res = await fetch(`${origin}/api/settings/require-login`); + const data = await res.json(); + if (data.requireLogin === false) return true; + } catch { + // On error, require login + } + return false; +} + export async function proxy(request) { const { pathname } = request.nextUrl; + // Always protected - allow localhost or valid JWT only + if (ALWAYS_PROTECTED.some((p) => pathname.startsWith(p))) { + if (isLocalRequest(request) || await hasValidToken(request)) + return NextResponse.next(); + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + // Protect sensitive API endpoints (bypass if localhost or requireLogin = false) + if (PROTECTED_API_PATHS.some((p) => pathname.startsWith(p))) { + if (pathname === "/api/settings/require-login") return NextResponse.next(); + if (isLocalRequest(request) || await isAuthenticated(request)) + return NextResponse.next(); + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + // Protect all dashboard routes if (pathname.startsWith("/dashboard")) { const token = request.cookies.get("auth_token")?.value; diff --git a/src/proxy.js b/src/proxy.js index 0ea6605..e91fd54 100644 --- a/src/proxy.js +++ b/src/proxy.js @@ -1,5 +1,14 @@ export { proxy } from "./dashboardGuard"; export const config = { - matcher: ["/", "/dashboard/:path*"], + matcher: [ + "/", + "/dashboard/:path*", + "/api/shutdown", + "/api/settings/:path*", + "/api/keys", + "/api/keys/:path*", + "/api/providers/client", + "/api/provider-nodes/validate", + ], };