import { auth } from "@/auth"; import { NextRequest, NextResponse } from "next/server"; import fs from "fs/promises"; import path from "path"; const UPLOADS_DIR = path.join(process.cwd(), ".dev-uploads"); function resolveFilePath(keySegments: string[]): string { const relative = path.join(...keySegments); const resolved = path.resolve(UPLOADS_DIR, relative); // Prevent path traversal outside the uploads directory if (!resolved.startsWith(path.resolve(UPLOADS_DIR))) { throw new Error("Invalid path"); } return resolved; } export async function PUT( request: NextRequest, { params }: { params: Promise<{ key: string[] }> } ) { if (process.env.NODE_ENV !== "development") { return NextResponse.json({ error: "Not found" }, { status: 404 }); } const session = await auth(); if (!session?.user) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const { key } = await params; let filePath: string; try { filePath = resolveFilePath(key); } catch { return NextResponse.json({ error: "Invalid path" }, { status: 400 }); } await fs.mkdir(path.dirname(filePath), { recursive: true }); const buffer = await request.arrayBuffer(); await fs.writeFile(filePath, Buffer.from(buffer)); return new NextResponse(null, { status: 200 }); } export async function GET( request: NextRequest, { params }: { params: Promise<{ key: string[] }> } ) { if (process.env.NODE_ENV !== "development") { return NextResponse.json({ error: "Not found" }, { status: 404 }); } const session = await auth(); if (!session?.user) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const { key } = await params; let filePath: string; try { filePath = resolveFilePath(key); } catch { return NextResponse.json({ error: "Invalid path" }, { status: 400 }); } let fileBuffer: Buffer; try { fileBuffer = await fs.readFile(filePath) as Buffer; } catch { return NextResponse.json({ error: "File not found" }, { status: 404 }); } const ext = path.extname(filePath).toLowerCase(); const contentTypeMap: Record = { ".pdf": "application/pdf", ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp", }; const contentType = contentTypeMap[ext] ?? "application/octet-stream"; return new NextResponse(new Uint8Array(fileBuffer), { headers: { "Content-Type": contentType }, }); }