import { NextResponse } from "next/server"; import { readFile } from "fs/promises"; import { existsSync } from "fs"; import path from "path"; export const dynamic = "force-dynamic"; const MEDIA_DIR = "public/assets/images/media"; const ALLOWED_EXT = [".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".bmp"]; export async function GET(_request: Request, { params }: { params: Promise<{ path: string[] }> }) { const { path: segments } = await params; const name = segments.join("/"); // Prevent path traversal if (name.includes("..") || name.includes("\\")) { return new NextResponse("Forbidden", { status: 403 }); } const ext = path.extname(name).toLowerCase(); if (!ALLOWED_EXT.includes(ext)) { return new NextResponse("Forbidden", { status: 403 }); } const baseDir = path.resolve(process.cwd(), MEDIA_DIR); const filePath = path.resolve(baseDir, name); if (!filePath.startsWith(baseDir + path.sep)) { return new NextResponse("Forbidden", { status: 403 }); } // eslint-disable-next-line security/detect-non-literal-fs-filename if (!existsSync(filePath)) { return new NextResponse("Not found", { status: 404 }); } // eslint-disable-next-line security/detect-non-literal-fs-filename const bytes = await readFile(filePath); const mime: Record = { ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp", ".svg": "image/svg+xml", ".bmp": "image/bmp", }; return new NextResponse(bytes, { headers: { // eslint-disable-next-line security/detect-object-injection -- ext validated against ALLOWED_EXT "Content-Type": mime[ext] ?? "application/octet-stream", "Cache-Control": "public, max-age=86400", }, }); }