Files
worst-scan-web/src/middleware.ts
T

78 lines
2.6 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server"
import { verifySession } from "@/lib/auth"
// Rutas públicas EXACTAS (coincidencia por segmento, no por prefijo).
const publicExact = new Set([
"/login",
"/api/auth/login",
"/api/auth/logout",
"/api/health",
"/api/proxy/health",
"/setup",
])
// Prefijos públicos: /api/cover (imágenes de portada para el sitio público),
// assets de Next y fuentes. Coinciden a nivel de segmento: "/api/cover" NO
// destapa "/api/cover/evil" ni otras rutas.
const publicPrefixes = [
"/api/cover/",
"/_next/",
"/fonts/",
]
// Páginas públicas del sitio (server-side, sin login).
// "/" es MATCH EXACTO (startsWith("/") matchearía TODO).
// "/gallery/" incluye el lector: cualquiera puede LEER (GET); las acciones
// del panel (eliminar, etc.) quedan protegidas por el middleware vía método.
const publicPages = ["/p/", "/tag/", "/gallery/", "/buscar"]
// GET de lectura del proxy hacia el pipeline: solo las rutas que el LECTOR
// público necesita (páginas, summary, artifacts, cover). /status y /queue
// exponen info operativa interna -> requieren sesión.
function isPublicProxyRead(pathname: string, method: string): boolean {
if (method !== "GET" && method !== "HEAD") return false
return pathname.startsWith("/api/proxy/galleries/")
}
function isPublicPath(pathname: string, method: string): boolean {
if (pathname === "/") return true
if (publicExact.has(pathname)) return true
if (publicPrefixes.some((p) => pathname.startsWith(p))) return true
if (publicPages.some((p) => pathname.startsWith(p))) return true
if (isPublicProxyRead(pathname, method)) return true
// /api/posts: GET de listado público; mutaciones requieren sesión.
if (pathname === "/api/posts" && method === "GET") return true
// /api/setup: GET (chequeo de config) público; POST (cambiar secrets) NO.
if (pathname === "/api/setup" && method === "GET") return true
return false
}
export async function middleware(req: NextRequest) {
const { pathname } = req.nextUrl
const method = req.method
if (isPublicPath(pathname, method)) return NextResponse.next()
const webPassword = process.env.WEB_PASSWORD
if (!webPassword) return NextResponse.next()
const session = req.cookies.get("session")?.value
if (!session) {
return NextResponse.redirect(new URL("/login", req.url))
}
const payload = await verifySession(session)
if (!payload || !payload.authenticated) {
return NextResponse.redirect(new URL("/login", req.url))
}
return NextResponse.next()
}
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
}