diff --git a/src/app/(dashboard)/dashboard/profile/page.js b/src/app/(dashboard)/dashboard/profile/page.js index 9acdbf8..fa6387c 100644 --- a/src/app/(dashboard)/dashboard/profile/page.js +++ b/src/app/(dashboard)/dashboard/profile/page.js @@ -95,6 +95,21 @@ export default function ProfilePage() { } }; + const updateRequireLogin = async (requireLogin) => { + try { + const res = await fetch("/api/settings", { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ requireLogin }), + }); + if (res.ok) { + setSettings(prev => ({ ...prev, requireLogin })); + } + } catch (err) { + console.error("Failed to update require login:", err); + } + }; + return (
@@ -116,7 +131,7 @@ export default function ProfilePage() {
- {/* Routing Preferences */} + {/* Security */}
@@ -124,52 +139,78 @@ export default function ProfilePage() {

Security

-
-
- - setPasswords({ ...passwords, current: e.target.value })} - required +
+
+
+

Require login

+

+ When ON, dashboard requires password. When OFF, access without login. +

+
+ updateRequireLogin(!settings.requireLogin)} + disabled={loading} />
-
-
- - setPasswords({ ...passwords, new: e.target.value })} - required - /> -
-
- - setPasswords({ ...passwords, confirm: e.target.value })} - required - /> -
-
+ {settings.requireLogin === true && ( + + {settings.hasPassword && ( +
+ + setPasswords({ ...passwords, current: e.target.value })} + required + /> +
+ )} + {/* {!settings.hasPassword && ( +
+

+ Setting password for the first time. Leave current password empty or use default: 123456 +

+
+ )} */} +
+
+ + setPasswords({ ...passwords, new: e.target.value })} + required + /> +
+
+ + setPasswords({ ...passwords, confirm: e.target.value })} + required + /> +
+
- {passStatus.message && ( -

- {passStatus.message} -

+ {passStatus.message && ( +

+ {passStatus.message} +

+ )} + +
+ +
+ )} - -
- -
- +
{/* Routing Preferences */} diff --git a/src/app/api/settings/require-login/route.js b/src/app/api/settings/require-login/route.js new file mode 100644 index 0000000..1e1a14d --- /dev/null +++ b/src/app/api/settings/require-login/route.js @@ -0,0 +1,12 @@ +import { NextResponse } from "next/server"; +import { getSettings } from "@/lib/localDb"; + +export async function GET() { + try { + const settings = await getSettings(); + const requireLogin = settings.requireLogin !== false; + return NextResponse.json({ requireLogin }); + } catch (error) { + return NextResponse.json({ requireLogin: true }, { status: 200 }); + } +} diff --git a/src/app/api/settings/route.js b/src/app/api/settings/route.js index a1863a6..fa2332f 100644 --- a/src/app/api/settings/route.js +++ b/src/app/api/settings/route.js @@ -5,13 +5,15 @@ import bcrypt from "bcryptjs"; export async function GET() { try { const settings = await getSettings(); - // Don't return the password hash to the client const { password, ...safeSettings } = settings; - // Add ENABLE_REQUEST_LOGS from env const enableRequestLogs = process.env.ENABLE_REQUEST_LOGS === "true"; - return NextResponse.json({ ...safeSettings, enableRequestLogs }); + return NextResponse.json({ + ...safeSettings, + enableRequestLogs, + hasPassword: !!password + }); } catch (error) { console.log("Error getting settings:", error); return NextResponse.json({ error: error.message }, { status: 500 }); @@ -37,8 +39,9 @@ export async function PATCH(request) { return NextResponse.json({ error: "Invalid current password" }, { status: 401 }); } } else { - // First time setting password, check if it matches default 123456 - if (body.currentPassword !== "123456") { + // First time setting password, no current password needed + // Allow empty currentPassword or default "123456" + if (body.currentPassword && body.currentPassword !== "123456") { return NextResponse.json({ error: "Invalid current password" }, { status: 401 }); } } diff --git a/src/app/login/page.js b/src/app/login/page.js index a8e868e..653c2ef 100644 --- a/src/app/login/page.js +++ b/src/app/login/page.js @@ -11,14 +11,13 @@ export default function LoginPage() { const [hasPassword, setHasPassword] = useState(null); const router = useRouter(); - // Check if password is set on mount useEffect(() => { - async function checkPassword() { + async function checkAuth() { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 5000); + const baseUrl = typeof window !== "undefined" ? window.location.origin : ""; try { - const baseUrl = typeof window !== "undefined" ? window.location.origin : ""; const res = await fetch(`${baseUrl}/api/settings`, { signal: controller.signal, }); @@ -26,8 +25,12 @@ export default function LoginPage() { if (res.ok) { const data = await res.json(); + if (data.requireLogin === false) { + router.push("/dashboard"); + router.refresh(); + return; + } if (!data.password) { - // No password set - auto login const loginRes = await fetch(`${baseUrl}/api/auth/login`, { method: "POST", headers: { "Content-Type": "application/json" }, @@ -43,11 +46,10 @@ export default function LoginPage() { } } catch (err) { clearTimeout(timeoutId); - // Silent fail - default to showing login form setHasPassword(true); } } - checkPassword(); + checkAuth(); }, [router]); const handleLogin = async (e) => { diff --git a/src/lib/localDb.js b/src/lib/localDb.js index 4e2fa6d..6c39b0f 100644 --- a/src/lib/localDb.js +++ b/src/lib/localDb.js @@ -48,7 +48,8 @@ const defaultData = { apiKeys: [], settings: { cloudEnabled: false, - stickyRoundRobinLimit: 3 + stickyRoundRobinLimit: 3, + requireLogin: true }, pricing: {} // NEW: pricing configuration }; diff --git a/src/proxy.js b/src/proxy.js index 4b97c90..a683a6c 100644 --- a/src/proxy.js +++ b/src/proxy.js @@ -12,16 +12,26 @@ export async function proxy(request) { if (pathname.startsWith("/dashboard")) { const token = request.cookies.get("auth_token")?.value; - if (!token) { - return NextResponse.redirect(new URL("/login", request.url)); + if (token) { + try { + await jwtVerify(token, SECRET); + return NextResponse.next(); + } catch (err) { + return NextResponse.redirect(new URL("/login", request.url)); + } } + const origin = request.nextUrl.origin; try { - await jwtVerify(token, SECRET); - return NextResponse.next(); + const res = await fetch(`${origin}/api/settings/require-login`); + const data = await res.json(); + if (data.requireLogin === false) { + return NextResponse.next(); + } } catch (err) { - return NextResponse.redirect(new URL("/login", request.url)); + // On error, require login } + return NextResponse.redirect(new URL("/login", request.url)); } // Redirect / to /dashboard if logged in, or /dashboard if it's the root