diff --git a/middleware.ts b/middleware.ts index 12bc3de2..0ef18d28 100644 --- a/middleware.ts +++ b/middleware.ts @@ -1,7 +1,4 @@ -import { - handleAuthenticatedRedirectMiddleware, - handleAuthenticationMiddlewareNoRefresh, -} from '@/middlewares/auth/auth'; +import { handleAuthenticatedRedirectMiddleware } from '@/middlewares/auth/auth'; import { handleDomainRouting, analyzeDomain } from '@/middlewares/domain-handling/domainHandler'; import { handleCollectionOwnershipMiddleware } from '@/middlewares/ownership/collectionOwnership'; import { handlePagesOwnershipMiddleware } from '@/middlewares/ownership/pagesOwnership'; @@ -19,8 +16,6 @@ const PROTECTED_ROUTES = { OAUTH_CALLBACK: '/auth/callback', /** Rutas de órdenes */ ORDERS: '/orders', - /** Configuración de cuenta */ - ACCOUNT_SETTINGS: '/account-settings', /** Pasos iniciales de configuración */ FIRST_STEPS: '/first-steps', /** Página de selección de tienda */ @@ -326,23 +321,6 @@ async function handleStoreAccess( return await next(); } -/** - * Handler para proteger rutas de configuración de cuenta - * @param request - Petición entrante - * @param next - Función para continuar con el siguiente handler - * @returns Respuesta del middleware de autenticación o null para continuar - */ -async function handleAccountSettings( - request: NextRequest, - next: () => Promise -): Promise { - if (request.nextUrl.pathname.startsWith(PROTECTED_ROUTES.ACCOUNT_SETTINGS)) { - return await handleAuthenticationMiddlewareNoRefresh(request, NextResponse.next()); - } - - return await next(); -} - /** * Handler para manejar rutas de configuración inicial de tienda * @param request - Petición entrante @@ -425,12 +403,10 @@ export async function middleware(request: NextRequest): Promise { handlePagesOwnership, handleCollectionOwnership, handleStoreAccess, - handleAccountSettings, handleStoreSetup, handleLoginRedirect, ]; - // Ejecutar recursivamente todos los handlers return await executeHandlers(handlers, request); } diff --git a/middlewares/auth/auth.ts b/middlewares/auth/auth.ts index fef39cc5..fc2aadfa 100644 --- a/middlewares/auth/auth.ts +++ b/middlewares/auth/auth.ts @@ -54,22 +54,12 @@ function getCacheKey(request: NextRequest): string { export async function getSession(request: NextRequest, response: NextResponse, forceRefresh = true) { const cacheKey = getCacheKey(request); - // Debug logs temporales - console.log('🔍 [GET SESSION DEBUG]', { - pathname: request.nextUrl.pathname, - forceRefresh, - cacheKey, - hasCached: !forceRefresh ? !!sessionCache.get(cacheKey) : 'N/A', - }); - // Verificar cache si no es forceRefresh if (!forceRefresh) { const cached = sessionCache.get(cacheKey); if (cached) { - console.log('✅ [GET SESSION] Cache hit:', cacheKey); return cached; } - console.log('❌ [GET SESSION] Cache miss:', cacheKey); } return runWithAmplifyServerContext({ @@ -79,21 +69,14 @@ export async function getSession(request: NextRequest, response: NextResponse, f const session = await fetchAuthSession(contextSpec, { forceRefresh }); const result = session.tokens !== undefined ? session : null; - console.log('🔍 [FETCH AUTH SESSION]', { - hasTokens: !!session?.tokens, - result: !!result, - forceRefresh, - }); - // Guardar en cache solo si la sesión es válida if (result && result.tokens) { sessionCache.set(cacheKey, result); - console.log('💾 [GET SESSION] Saved to cache:', cacheKey); } return result; } catch (error) { - console.error('❌ [GET SESSION] Error fetching user session:', error); + console.error('Error fetching user session:', error); return null; } }, @@ -110,30 +93,10 @@ export async function handleAuthenticationMiddleware(request: NextRequest, respo return response; } -export async function handleAuthenticationMiddlewareNoRefresh(request: NextRequest, response: NextResponse) { - const session = await getSession(request, response, false); - - if (!session) { - return NextResponse.redirect(new URL('/login', request.url)); - } - - return response; -} - export async function handleAuthenticatedRedirectMiddleware(request: NextRequest, response: NextResponse) { const session = await getSession(request, response, false); - // Debug logs temporales - console.log('🔍 [LOGIN REDIRECT DEBUG]', { - pathname: request.nextUrl.pathname, - hasSession: !!session, - sessionTokens: !!(session as any)?.tokens, - cookies: request.headers.get('cookie')?.substring(0, 100) + '...', - cacheKey: getCacheKey(request), - }); - if (session) { - console.log('✅ [LOGIN REDIRECT] Usuario autenticado detectado, redirigiendo...'); const lastStoreId = getLastVisitedStore(request); if (lastStoreId) { @@ -141,8 +104,6 @@ export async function handleAuthenticatedRedirectMiddleware(request: NextRequest } else { return NextResponse.redirect(new URL('/my-store', request.url)); } - } else { - console.log('❌ [LOGIN REDIRECT] No hay sesión, permitiendo acceso a /login'); } return response; diff --git a/middlewares/ownership/collectionOwnership.ts b/middlewares/ownership/collectionOwnership.ts index fc64358d..d78df074 100644 --- a/middlewares/ownership/collectionOwnership.ts +++ b/middlewares/ownership/collectionOwnership.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { getSession, type AuthSession } from '@/middlewares/auth/auth'; +import { getSession, handleAuthenticationMiddleware, type AuthSession } from '@/middlewares/auth/auth'; import { cookiesClient } from '@/utils/client/AmplifyUtils'; import { NextRequest, NextResponse } from 'next/server'; @@ -38,14 +38,15 @@ export async function handleCollectionOwnershipMiddleware(request: NextRequest) return NextResponse.next(); } - // Verificar autenticación del usuario - // Usar cache para evitar múltiples forceRefresh en la misma request - const session = await getSession(request, NextResponse.next(), false); - - if (!session) { - return NextResponse.redirect(new URL('/login', request.url)); + // Verificar autenticación usando el middleware centralizado + const authResponse = await handleAuthenticationMiddleware(request, NextResponse.next()); + if (authResponse) { + return authResponse; // Si hay redirección de auth, retornarla } + // Obtener la sesión del usuario (ya validada) + const session = await getSession(request, NextResponse.next(), false); + const userId = (session as AuthSession).tokens?.idToken?.payload?.['cognito:username']; if (!userId || typeof userId !== 'string') { diff --git a/middlewares/ownership/pagesOwnership.ts b/middlewares/ownership/pagesOwnership.ts index 8ff7b391..3e8bff34 100644 --- a/middlewares/ownership/pagesOwnership.ts +++ b/middlewares/ownership/pagesOwnership.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { getSession, type AuthSession } from '@/middlewares/auth/auth'; +import { getSession, handleAuthenticationMiddleware, type AuthSession } from '@/middlewares/auth/auth'; import { cookiesClient } from '@/utils/client/AmplifyUtils'; import { NextRequest, NextResponse } from 'next/server'; @@ -38,14 +38,15 @@ export async function handlePagesOwnershipMiddleware(request: NextRequest) { return NextResponse.next(); } - // Verificar autenticación del usuario - // Usar cache para evitar múltiples forceRefresh en la misma request - const session = await getSession(request, NextResponse.next(), false); - - if (!session) { - return NextResponse.redirect(new URL('/login', request.url)); + // Verificar autenticación usando el middleware centralizado + const authResponse = await handleAuthenticationMiddleware(request, NextResponse.next()); + if (authResponse) { + return authResponse; // Si hay redirección de auth, retornarla } + // Obtener la sesión del usuario (ya validada) + const session = await getSession(request, NextResponse.next(), false); + const userId = (session as AuthSession).tokens?.idToken?.payload?.['cognito:username']; if (!userId || typeof userId !== 'string') { diff --git a/middlewares/ownership/productOwnership.ts b/middlewares/ownership/productOwnership.ts index 89d0ed84..72288ffa 100644 --- a/middlewares/ownership/productOwnership.ts +++ b/middlewares/ownership/productOwnership.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { getSession, type AuthSession } from '@/middlewares/auth/auth'; +import { getSession, handleAuthenticationMiddleware, type AuthSession } from '@/middlewares/auth/auth'; import { cookiesClient } from '@/utils/client/AmplifyUtils'; import { NextRequest, NextResponse } from 'next/server'; @@ -38,14 +38,15 @@ export async function handleProductOwnershipMiddleware(request: NextRequest) { return NextResponse.next(); } - // Verificar autenticación del usuario - // Usar cache para evitar múltiples forceRefresh en la misma request - const session = await getSession(request, NextResponse.next(), false); - - if (!session) { - return NextResponse.redirect(new URL('/login', request.url)); + // Verificar autenticación usando el middleware centralizado + const authResponse = await handleAuthenticationMiddleware(request, NextResponse.next()); + if (authResponse) { + return authResponse; // Si hay redirección de auth, retornarla } + // Obtener la sesión del usuario (ya validada) + const session = await getSession(request, NextResponse.next(), false); + const userId = (session as AuthSession).tokens?.idToken?.payload?.['cognito:username']; if (!userId || typeof userId !== 'string') { diff --git a/middlewares/store-access/store.ts b/middlewares/store-access/store.ts index 73e28a76..770cdf74 100644 --- a/middlewares/store-access/store.ts +++ b/middlewares/store-access/store.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { getSession, type AuthSession } from '@/middlewares/auth/auth'; +import { getSession, handleAuthenticationMiddleware, type AuthSession } from '@/middlewares/auth/auth'; import { cookiesClient } from '@/utils/client/AmplifyUtils'; import { NextRequest, NextResponse } from 'next/server'; @@ -52,16 +52,18 @@ async function checkStoreLimit(userId: string, plan: string) { } export async function handleStoreMiddleware(request: NextRequest, response: NextResponse) { - // Usar cache para evitar múltiples forceRefresh en la misma request - const session = await getSession(request, response, false); - - if (!session) { - return NextResponse.redirect(new URL('/login', request.url)); + // Verificar autenticación usando el middleware centralizado + const authResponse = await handleAuthenticationMiddleware(request, response); + if (authResponse) { + return authResponse; // Si hay redirección de auth, retornarla } + // Obtener la sesión del usuario (ya validada) + const session = await getSession(request, response, false); + const userId = (session as AuthSession).tokens?.idToken?.payload?.['cognito:username']; const userPlan = (session as AuthSession).tokens?.idToken?.payload?.['custom:plan']; - const hasValidSubscription = await hasValidPlan(session); + const hasValidSubscription = await hasValidPlan(session as AuthSession); if (!hasValidSubscription) { return NextResponse.redirect(new URL('/pricing', request.url)); diff --git a/middlewares/store-access/storeAccess.ts b/middlewares/store-access/storeAccess.ts index 09d00c4a..1586ec7b 100644 --- a/middlewares/store-access/storeAccess.ts +++ b/middlewares/store-access/storeAccess.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { getSession, type AuthSession } from '@/middlewares/auth/auth'; +import { getSession, handleAuthenticationMiddleware, type AuthSession } from '@/middlewares/auth/auth'; import { cookiesClient } from '@/utils/client/AmplifyUtils'; import { NextRequest, NextResponse } from 'next/server'; @@ -23,13 +23,15 @@ import { NextRequest, NextResponse } from 'next/server'; * Verifica que el usuario tenga acceso a la tienda solicitada y un plan de suscripción válido */ export async function handleStoreAccessMiddleware(request: NextRequest) { - // Obtener la sesión del usuario - const session = await getSession(request, NextResponse.next(), false); - // Verificar autenticación - if (!session || !(session as AuthSession).tokens) { - return NextResponse.redirect(new URL('/login', request.url)); + // Verificar autenticación usando el middleware centralizado + const authResponse = await handleAuthenticationMiddleware(request, NextResponse.next()); + if (authResponse) { + return authResponse; // Si hay redirección de auth, retornarla } + // Obtener la sesión del usuario (ya validada) + const session = await getSession(request, NextResponse.next(), false); + // Verificar plan de suscripción válido ANTES de verificar acceso a tienda const userPlan: string | undefined = (session as AuthSession).tokens?.idToken?.payload?.['custom:plan'] as | string diff --git a/middlewares/subscription/subscription.ts b/middlewares/subscription/subscription.ts index c8c7b417..f29fcd4e 100644 --- a/middlewares/subscription/subscription.ts +++ b/middlewares/subscription/subscription.ts @@ -15,16 +15,18 @@ */ import { NextRequest, NextResponse } from 'next/server'; -import { getSession, type AuthSession } from '@/middlewares/auth/auth'; +import { getSession, handleAuthenticationMiddleware, type AuthSession } from '@/middlewares/auth/auth'; export async function handleSubscriptionMiddleware(request: NextRequest, response: NextResponse) { - // Usar cache para evitar múltiples forceRefresh en la misma request - const session = await getSession(request, response, false); - - if (!session) { - return NextResponse.redirect(new URL('/pricing', request.url)); + // Verificar autenticación usando el middleware centralizado + const authResponse = await handleAuthenticationMiddleware(request, response); + if (authResponse) { + return authResponse; // Si hay redirección de auth, retornarla } + // Obtener la sesión del usuario (ya validada) + const session = await getSession(request, response, false); + const userPlan: string | undefined = (session as AuthSession).tokens?.idToken?.payload?.['custom:plan'] as | string | undefined; diff --git a/test/unit/middlewares/middleware.test.ts b/test/unit/middlewares/middleware.test.ts index 703c57f7..2cf3bf8b 100644 --- a/test/unit/middlewares/middleware.test.ts +++ b/test/unit/middlewares/middleware.test.ts @@ -4,7 +4,6 @@ import { middleware } from '@/middleware'; // Mock de los middlewares específicos jest.mock('@/middlewares/auth/auth', () => ({ handleAuthenticationMiddleware: jest.fn(), - handleAuthenticationMiddlewareNoRefresh: jest.fn(), handleAuthenticatedRedirectMiddleware: jest.fn(), })); @@ -197,9 +196,9 @@ describe('Main Middleware Security Tests', () => { const mainDomainRequest = { nextUrl: { - pathname: '/account-settings', + pathname: '/my-store', clone: () => ({ - pathname: '/account-settings', + pathname: '/my-store', }), }, headers: { @@ -207,14 +206,14 @@ describe('Main Middleware Security Tests', () => { }, } as unknown as NextRequest; - const { handleAuthenticationMiddlewareNoRefresh } = require('@/middlewares/auth/auth'); - handleAuthenticationMiddlewareNoRefresh.mockReturnValue({ type: 'auth' }); + const { handleStoreMiddleware } = require('@/middlewares/store-access/store'); + handleStoreMiddleware.mockReturnValue({ type: 'store' }); const result = await middleware(mainDomainRequest); - // Debería ejecutar el middleware de autenticación para el dominio principal - expect(handleAuthenticationMiddlewareNoRefresh).toHaveBeenCalled(); - expect(result).toEqual({ type: 'auth' }); + // Debería ejecutar el middleware de store que internamente usa handleAuthenticationMiddleware + expect(handleStoreMiddleware).toHaveBeenCalled(); + expect(result).toEqual({ type: 'store' }); }); it('should handle main domain correctly in development', async () => { @@ -222,9 +221,9 @@ describe('Main Middleware Security Tests', () => { const mainDomainRequest = { nextUrl: { - pathname: '/account-settings', + pathname: '/my-store', clone: () => ({ - pathname: '/account-settings', + pathname: '/my-store', }), }, headers: { @@ -232,14 +231,14 @@ describe('Main Middleware Security Tests', () => { }, } as unknown as NextRequest; - const { handleAuthenticationMiddlewareNoRefresh } = require('@/middlewares/auth/auth'); - handleAuthenticationMiddlewareNoRefresh.mockReturnValue({ type: 'auth' }); + const { handleStoreMiddleware } = require('@/middlewares/store-access/store'); + handleStoreMiddleware.mockReturnValue({ type: 'store' }); const result = await middleware(mainDomainRequest); - // Debería ejecutar el middleware de autenticación para el dominio principal - expect(handleAuthenticationMiddlewareNoRefresh).toHaveBeenCalled(); - expect(result).toEqual({ type: 'auth' }); + // Debería ejecutar el middleware de store que internamente usa handleAuthenticationMiddleware + expect(handleStoreMiddleware).toHaveBeenCalled(); + expect(result).toEqual({ type: 'store' }); }); });