fix env and middleware
CI / test (push) Successful in 5s

This commit is contained in:
2026-01-27 13:40:49 -05:00
parent b45493f5bd
commit c2600b6a68
2 changed files with 57 additions and 16 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
NEXT_PUBLIC_API_BASE_URL=http://battlbuilder-api:8080 NEXT_PUBLIC_API_BASE_URL=http://battlbuilder-api:8080
# Middleware to limited site to only root page # Middleware to limited site to only root page
NEXT_PUBLIC_LAUNCH_ONLY_ROOT=true LAUNCH_ONLY_ROOT=true
NEXT_PUBLIC_SHORTLINK_BASE_URL=https://battl.build NEXT_PUBLIC_SHORTLINK_BASE_URL=https://battl.build
+56 -15
View File
@@ -2,42 +2,83 @@
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import type { NextRequest } from "next/server"; import type { NextRequest } from "next/server";
function redirectToLogin(req: NextRequest) {
const url = req.nextUrl.clone();
url.pathname = "/login";
url.searchParams.set("next", req.nextUrl.pathname);
return NextResponse.redirect(url);
}
function isPublicPath(pathname: string) {
// Public pages
if (pathname === "/") return true;
if (pathname === "/login") return true;
if (pathname.startsWith("/auth")) return true;
// Static / framework assets
if (pathname.startsWith("/_next")) return true;
if (pathname === "/favicon.ico") return true;
if (pathname === "/robots.txt") return true;
if (pathname === "/sitemap.xml") return true;
// Health / misc APIs you may want public
if (pathname === "/api/health") return true;
return false;
}
export function middleware(req: NextRequest) { export function middleware(req: NextRequest) {
const { pathname } = req.nextUrl; const { pathname } = req.nextUrl;
const token = req.cookies.get("session_token")?.value; const token = req.cookies.get("session_token")?.value;
const isLoggedIn = Boolean(token);
// Protect admin API routes // IMPORTANT: Use a server-only env var for middleware behavior.
// Set LAUNCH_ONLY_ROOT=true in your Docker compose.
const launchOnlyRoot = process.env.LAUNCH_ONLY_ROOT === "true";
// If we're in "launch only" mode, anonymous users can ONLY see public paths.
// Everything else (including /builder) gets bounced.
if (launchOnlyRoot && !isLoggedIn && !isPublicPath(pathname)) {
// For API requests, return 401 instead of redirecting
if (pathname.startsWith("/api/")) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
// For pages, redirect to home (keeps the landing page experience)
const url = req.nextUrl.clone();
url.pathname = "/";
return NextResponse.redirect(url);
}
// --- Protected API routes ---
if (pathname.startsWith("/api/admin")) { if (pathname.startsWith("/api/admin")) {
if (!token) { if (!isLoggedIn) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
} }
} }
// Protect builds API routes
if (pathname.startsWith("/api/builds")) { if (pathname.startsWith("/api/builds")) {
if (!token) { if (!isLoggedIn) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
} }
} }
// Protect admin pages // --- Protected pages ---
if (pathname.startsWith("/admin")) { if (pathname.startsWith("/admin")) {
if (!token) { if (!isLoggedIn) return redirectToLogin(req);
const url = req.nextUrl.clone(); }
url.pathname = "/login";
url.searchParams.set("next", pathname); // Protect the builder UI
return NextResponse.redirect(url); if (pathname === "/builder" || pathname.startsWith("/builder/")) {
} if (!isLoggedIn) return redirectToLogin(req);
} }
return NextResponse.next(); return NextResponse.next();
} }
export const config = { export const config = {
// Run middleware for all application routes, but avoid static assets.
matcher: [ matcher: [
"/api/admin/:path*", "/((?!_next/static|_next/image|favicon.ico|robots.txt|sitemap.xml).*)",
"/api/builds",
"/api/builds/:path+",
"/admin/:path*",
], ],
}; };