import { NextRequest, NextResponse } from "next/server"; import { readFile } from "fs/promises"; import { join } from "path"; import { existsSync } from "fs"; export async function GET( request: NextRequest, { params }: { params: Promise<{ filename: string }> } ) { try { const { filename } = await params; // Sécuriser le nom de fichier pour éviter les path traversal if ( !filename || filename.includes("..") || filename.includes("/") || filename.includes("\\") ) { return NextResponse.json( { error: "Nom de fichier invalide" }, { status: 400 } ); } // Décoder le nom de fichier (au cas où il contient des caractères encodés) const decodedFilename = decodeURIComponent(filename); // Chemin vers le fichier avatar const avatarsDir = join(process.cwd(), "public", "uploads", "avatars"); const filepath = join(avatarsDir, decodedFilename); // Vérifier que le fichier existe if (!existsSync(filepath)) { return NextResponse.json({ error: "Avatar non trouvé" }, { status: 404 }); } // Lire le fichier const fileBuffer = await readFile(filepath); // Déterminer le type MIME basé sur l'extension const extension = decodedFilename.split(".").pop()?.toLowerCase(); let contentType = "image/jpeg"; // par défaut switch (extension) { case "png": contentType = "image/png"; break; case "gif": contentType = "image/gif"; break; case "webp": contentType = "image/webp"; break; case "svg": contentType = "image/svg+xml"; break; case "jpg": case "jpeg": default: contentType = "image/jpeg"; } // Retourner l'image avec les bons headers return new NextResponse(fileBuffer, { headers: { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable", }, }); } catch (error) { console.error("Error serving avatar:", error); return NextResponse.json( { error: "Erreur lors de la récupération de l'avatar" }, { status: 500 } ); } }