This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import type { NextRequest } from 'next/server';
|
||||
import { jwtVerify } from 'jose';
|
||||
|
||||
// 🌍 1. Importamos el motor de idiomas
|
||||
import createIntlMiddleware from 'next-intl/middleware';
|
||||
import { routing } from './i18n/routing';
|
||||
|
||||
// Configuramos el proxy de next-intl
|
||||
const handleI18nRouting = createIntlMiddleware(routing);
|
||||
|
||||
// 🔒 2. Llave de seguridad del CMS
|
||||
const secretKey = process.env.SESSION_SECRET || "FLUX_SUPER_SECRET_KEY_2026_ARCHITECTURE";
|
||||
const encodedKey = new TextEncoder().encode(secretKey);
|
||||
|
||||
// 🔥 AHORA SE LLAMA "proxy" EN LUGAR DE "middleware" 🔥
|
||||
export async function proxy(request: NextRequest) {
|
||||
const path = request.nextUrl.pathname;
|
||||
|
||||
// --------------------------------------------------------
|
||||
// ZONA ROJA: CENTRO DE MANDO (Seguridad estricta, sin idiomas)
|
||||
// --------------------------------------------------------
|
||||
if (path.startsWith('/hq-command')) {
|
||||
const isPublicHQRoute = path === '/hq-command/login' || path === '/hq-command/setup';
|
||||
const cookie = request.cookies.get('flux_session')?.value;
|
||||
|
||||
// Si intenta entrar al dashboard sin pase
|
||||
if (!isPublicHQRoute && !cookie) {
|
||||
return NextResponse.redirect(new URL('/hq-command/login', request.url));
|
||||
}
|
||||
|
||||
// Verificamos el pase
|
||||
if (cookie) {
|
||||
try {
|
||||
await jwtVerify(cookie, encodedKey);
|
||||
// Si tiene pase y está en el login, lo mandamos al dashboard
|
||||
if (isPublicHQRoute) {
|
||||
return NextResponse.redirect(new URL('/hq-command/dashboard', request.url));
|
||||
}
|
||||
return NextResponse.next(); // Pasa al CMS tranquilamente
|
||||
} catch (error) {
|
||||
// Pase falso o expirado
|
||||
if (!isPublicHQRoute) {
|
||||
return NextResponse.redirect(new URL('/hq-command/login', request.url));
|
||||
}
|
||||
}
|
||||
}
|
||||
return NextResponse.next(); // Pasa a login/setup si no hay cookie
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
// ZONA VERDE: WEB PÚBLICA (Motor de Traducciones i18n)
|
||||
// --------------------------------------------------------
|
||||
// Si el usuario no va al CMS, le pasamos el control a next-intl
|
||||
// para que gestione los prefijos /en/, /it/, /vec/, etc.
|
||||
return handleI18nRouting(request);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
// OPTIMIZACIÓN EXTREMA DEL MATCHER
|
||||
// --------------------------------------------------------
|
||||
export const config = {
|
||||
// Coincide con TODAS las rutas de la aplicación EXCEPTO:
|
||||
// - /api (nuestras rutas backend)
|
||||
// - /_next/static y /_next/image (archivos internos de React/Next)
|
||||
// - Archivos estáticos como .jpg, .png, .mp4, .glb, .svg (.*\\..*)
|
||||
// IMPORTANTE: Al ignorar los estáticos, las fotos y videos del CMS cargarán rapidísimo.
|
||||
matcher: ['/((?!api|_next/static|_next/image|.*\\..*).*)'],
|
||||
};
|
||||
Reference in New Issue
Block a user