mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-06 23:32:12 +03:00
fix(auth): redirect active sessions from /login (#9491)
Validated in local merge-train (diegosouzapw batch)
This commit is contained in:
committed by
GitHub
parent
53c8016d53
commit
8fdb67f1d3
1
changelog.d/fixes/9491-port-3005-auth-redirect-login.md
Normal file
1
changelog.d/fixes/9491-port-3005-auth-redirect-login.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(auth):** redirect active sessions from /login by checking the session cookie before showing the login form. (thanks @DaDecky)
|
||||
@@ -1,4 +1,6 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { cookies } from "next/headers";
|
||||
import { jwtVerify } from "jose";
|
||||
import { getSettings, updateSettings } from "@/lib/localDb";
|
||||
import {
|
||||
hasManagementPasswordConfigured,
|
||||
@@ -9,6 +11,24 @@ import { getNodeRuntimeSupport } from "@/shared/utils/nodeRuntimeSupport.ts";
|
||||
import { updateRequireLoginSchema } from "@/shared/validation/schemas";
|
||||
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
|
||||
|
||||
function getJwtSecret(): Uint8Array | null {
|
||||
const secret = process.env.JWT_SECRET?.trim();
|
||||
return secret ? new TextEncoder().encode(secret) : null;
|
||||
}
|
||||
|
||||
async function checkSessionAuthenticated(): Promise<boolean> {
|
||||
try {
|
||||
const cookieStore = await cookies();
|
||||
const token = cookieStore.get("auth_token")?.value;
|
||||
const secret = getJwtSecret();
|
||||
if (!token || !secret) return false;
|
||||
await jwtVerify(token, secret);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Node.js compatibility check — reflect the supported secure runtime floors used by CLI/CI.
|
||||
function getNodeCompatibility() {
|
||||
const { nodeVersion, nodeCompatible } = getNodeRuntimeSupport();
|
||||
@@ -28,10 +48,12 @@ export async function GET() {
|
||||
try {
|
||||
const settings = await getSettings();
|
||||
const requireLogin = settings.requireLogin !== false;
|
||||
const authenticated = await checkSessionAuthenticated();
|
||||
const hasPassword = hasManagementPasswordConfigured(settings);
|
||||
const setupComplete = !!settings.setupComplete;
|
||||
const oidcEnabled = !!settings.oidcEnabled;
|
||||
return NextResponse.json({
|
||||
authenticated,
|
||||
requireLogin,
|
||||
hasPassword,
|
||||
setupComplete,
|
||||
@@ -42,6 +64,7 @@ export async function GET() {
|
||||
console.error("[API] Error fetching require-login settings:", error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
authenticated: false,
|
||||
requireLogin: true,
|
||||
hasPassword: true,
|
||||
setupComplete: true,
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function LoginPage() {
|
||||
const data = await res.json();
|
||||
if (data.nodeVersion) setNodeVersion(data.nodeVersion);
|
||||
if (data.nodeCompatible === false) setNodeCompatible(false);
|
||||
if (data.requireLogin === false) {
|
||||
if (data.authenticated === true || data.requireLogin === false) {
|
||||
router.push("/dashboard");
|
||||
router.refresh();
|
||||
return;
|
||||
|
||||
41
tests/unit/auth-redirect-login.test.ts
Normal file
41
tests/unit/auth-redirect-login.test.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Auth redirect: active sessions are redirected from /login to /dashboard.
|
||||
*
|
||||
* Upstream: decolua/9router#3005 — fix(auth): redirect active sessions from /login
|
||||
* When a user navigates to /login while already authenticated, the login page
|
||||
* fetches /api/settings/require-login and redirects to /dashboard.
|
||||
*/
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
describe("auth redirect login (port from 9router#3005)", () => {
|
||||
it("login page checks data.authenticated === true before showing the form", () => {
|
||||
const source = fs.readFileSync(path.resolve("src/app/login/page.tsx"), "utf-8");
|
||||
// The redirect guard must check both:
|
||||
// - authenticated=true (active session → redirect to dashboard)
|
||||
// - requireLogin=false (no auth configured → allow access)
|
||||
const redirectCheck = source.match(/if\s*\(.*authenticated.*requireLogin.*\)/);
|
||||
assert.ok(redirectCheck, "login page must check both authenticated and requireLogin");
|
||||
assert.ok(
|
||||
source.includes("data.authenticated === true"),
|
||||
"login page must check data.authenticated === true for redirect",
|
||||
);
|
||||
});
|
||||
|
||||
it("require-login API route returns authenticated field", () => {
|
||||
const source = fs.readFileSync(
|
||||
path.resolve("src/app/api/settings/require-login/route.ts"),
|
||||
"utf-8",
|
||||
);
|
||||
assert.ok(
|
||||
source.includes("authenticated:"),
|
||||
"require-login route must include authenticated in the response",
|
||||
);
|
||||
assert.ok(
|
||||
source.includes("authenticated,"),
|
||||
"authenticated must be part of the JSON response object (spread or key)",
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user