Seguridad y docs: fix SQLi en updatePost, middleware por segmentos exactos, cover-cache directo al upstream, JWT sin fallback hardcodeado, password sudo fuera de deploy/setup.sh; reescritura AGENTS.md y CLAUDE.md
This commit is contained in:
+30
-13
@@ -1,30 +1,47 @@
|
||||
import { NextRequest, NextResponse } from "next/server"
|
||||
import { verifySession } from "@/lib/auth"
|
||||
|
||||
const publicPaths = [
|
||||
// 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",
|
||||
"/api/posts",
|
||||
"/api/cover",
|
||||
"/api/cron",
|
||||
"/api/setup",
|
||||
"/setup",
|
||||
"/_next",
|
||||
"/favicon.ico",
|
||||
"/fonts",
|
||||
])
|
||||
|
||||
// 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).
|
||||
const publicPages = ["/", "/p/", "/tag/"]
|
||||
|
||||
function isPublicPath(pathname: string, method: string): boolean {
|
||||
if (publicExact.has(pathname)) return true
|
||||
if (publicPrefixes.some((p) => pathname.startsWith(p))) return true
|
||||
if (publicPages.some((p) => pathname.startsWith(p))) 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
|
||||
|
||||
const isPublic = publicPaths.some((p) => pathname.startsWith(p))
|
||||
if (isPublic) return NextResponse.next()
|
||||
|
||||
const isPublicPage = pathname === "/" || pathname.startsWith("/p/") || pathname.startsWith("/tag/")
|
||||
if (isPublicPage) return NextResponse.next()
|
||||
if (isPublicPath(pathname, method)) return NextResponse.next()
|
||||
|
||||
const webPassword = process.env.WEB_PASSWORD
|
||||
if (!webPassword) return NextResponse.next()
|
||||
|
||||
Reference in New Issue
Block a user