mirror of
https://github.com/decolua/9router.git
synced 2026-05-08 12:01:28 +00:00
Fix Bug
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "9router-app",
|
"name": "9router-app",
|
||||||
"version": "0.3.62",
|
"version": "0.3.64",
|
||||||
"description": "9Router web dashboard",
|
"description": "9Router web dashboard",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -682,6 +682,13 @@ export default function ProviderDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{providerInfo.deprecated && (
|
||||||
|
<div className="flex items-start gap-2 px-3 py-2 rounded-lg bg-black/[0.02] dark:bg-white/[0.02] border border-black/[0.05] dark:border-white/[0.05]">
|
||||||
|
<span className="material-symbols-outlined text-[16px] text-text-muted mt-0.5 shrink-0">info</span>
|
||||||
|
<p className="text-xs text-text-muted leading-relaxed">{providerInfo.deprecationNotice}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{isCompatible && providerNode && (
|
{isCompatible && providerNode && (
|
||||||
<Card>
|
<Card>
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4">
|
||||||
|
|||||||
@@ -489,7 +489,6 @@ export default function ProvidersPage() {
|
|||||||
|
|
||||||
function ProviderCard({ providerId, provider, stats, authType, onToggle }) {
|
function ProviderCard({ providerId, provider, stats, authType, onToggle }) {
|
||||||
const { connected, error, errorCode, errorTime, allDisabled } = stats;
|
const { connected, error, errorCode, errorTime, allDisabled } = stats;
|
||||||
const isDeprecated = !!provider.deprecated;
|
|
||||||
|
|
||||||
const dotColors = {
|
const dotColors = {
|
||||||
free: "bg-green-500",
|
free: "bg-green-500",
|
||||||
@@ -572,12 +571,6 @@ function ProviderCard({ providerId, provider, stats, authType, onToggle }) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{isDeprecated && (
|
|
||||||
<div className="mt-2 flex items-start gap-1.5 px-2 py-1.5 rounded-md bg-amber-500/10 border border-amber-500/20 text-amber-600 dark:text-amber-400">
|
|
||||||
<span className="material-symbols-outlined text-[14px] mt-0.5 shrink-0">warning</span>
|
|
||||||
<p className="text-[10px] leading-snug">{provider.deprecationNotice}</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Card>
|
</Card>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,9 +5,70 @@ const SECRET = new TextEncoder().encode(
|
|||||||
process.env.JWT_SECRET || "9router-default-secret-change-me"
|
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) {
|
export async function proxy(request) {
|
||||||
const { pathname } = request.nextUrl;
|
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
|
// Protect all dashboard routes
|
||||||
if (pathname.startsWith("/dashboard")) {
|
if (pathname.startsWith("/dashboard")) {
|
||||||
const token = request.cookies.get("auth_token")?.value;
|
const token = request.cookies.get("auth_token")?.value;
|
||||||
|
|||||||
11
src/proxy.js
11
src/proxy.js
@@ -1,5 +1,14 @@
|
|||||||
export { proxy } from "./dashboardGuard";
|
export { proxy } from "./dashboardGuard";
|
||||||
|
|
||||||
export const config = {
|
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",
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user