import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; import { ERROR_CODES } from "./constants/errorCodes"; import { UserData } from "./lib/services/auth-server.service"; import { getErrorMessage } from "./utils/errors"; // Routes qui ne nécessitent pas d'authentification const publicRoutes = ["/login", "/register", "/images"]; // Routes d'API qui ne nécessitent pas d'authentification const publicApiRoutes = ["/api/auth/login", "/api/auth/register", "/api/komga/test"]; // Langues supportées const locales = ["fr", "en"]; const defaultLocale = "fr"; export function middleware(request: NextRequest) { const { pathname } = request.nextUrl; // Gestion de la langue let locale = request.cookies.get("NEXT_LOCALE")?.value; // Si pas de cookie de langue ou langue non supportée, on utilise la langue par défaut if (!locale || !locales.includes(locale)) { locale = defaultLocale; // On crée une nouvelle réponse avec le cookie de langue const response = NextResponse.next(); response.cookies.set("NEXT_LOCALE", locale, { path: "/", maxAge: 365 * 24 * 60 * 60, // 1 an }); return response; } // Gestion de l'authentification const user = request.cookies.get("stripUser"); // Si l'utilisateur est connecté et essaie d'accéder à la page de login ou register if (user?.value && (pathname === "/login" || pathname === "/register")) { return NextResponse.redirect(new URL("/", request.url)); } // Vérifier si c'est une route publique ou commence par certains préfixes if ( publicRoutes.includes(pathname) || publicApiRoutes.includes(pathname) || pathname.startsWith("/images/") || pathname.startsWith("/_next/") || pathname.startsWith("/fonts/") ) { return NextResponse.next(); } // Pour toutes les routes protégées, vérifier la présence de l'utilisateur if (!user || !user.value) { if (pathname.startsWith("/api/")) { return NextResponse.json( { error: { code: ERROR_CODES.MIDDLEWARE.UNAUTHORIZED, message: getErrorMessage(ERROR_CODES.MIDDLEWARE.UNAUTHORIZED), name: "Unauthorized", }, }, { status: 401 } ); } const loginUrl = new URL("/login", request.url); loginUrl.searchParams.set("from", pathname); return NextResponse.redirect(loginUrl); } try { const userData: UserData = JSON.parse(atob(user.value)); if (!userData || !userData.authenticated || !userData.id || !userData.email) { throw new Error(getErrorMessage(ERROR_CODES.MIDDLEWARE.INVALID_SESSION)); } } catch (error) { console.error("Erreur de validation du cookie:", error); if (pathname.startsWith("/api/")) { return NextResponse.json( { error: { code: ERROR_CODES.MIDDLEWARE.INVALID_TOKEN, message: getErrorMessage(ERROR_CODES.MIDDLEWARE.INVALID_TOKEN), name: "Invalid token", }, }, { status: 401 } ); } const loginUrl = new URL("/login", request.url); loginUrl.searchParams.set("from", pathname); return NextResponse.redirect(loginUrl); } return NextResponse.next(); } // Configuration des routes à protéger export const config = { matcher: [ /* * Match all request paths except: * 1. /api/auth/* (authentication routes) * 2. /_next/* (Next.js internals) * 3. /fonts/* (inside public directory) * 4. /images/* (inside public directory) * 5. Static files (manifest.json, favicon.ico, etc.) */ "/((?!api/auth|_next/static|_next/image|fonts|images|manifest.json|favicon.ico|sitemap.xml|sw.js|offline.html).*)", ], };