// [TSM.ID].[11031972] -- All Rights Reserved. Proprietary & Confidential. import { NextRequest, NextResponse } from "next/server"; import crypto from "crypto"; import { promises as fs } from "fs"; import path from "path"; function decryptBuffer(vaultPayload: Buffer): Buffer { const rawKey = process.env.QUANTUM_MASTER_KEY || "JUMPA-XCU-ABSOLUTE-SOVEREIGN-KEY"; const key = crypto.createHash("sha256").update(rawKey).digest(); // Ekstrak komponen dari paket vault: [IV (12 bytes)] + [Auth Tag (16 bytes)] + [Encrypted Data] const iv = vaultPayload.subarray(0, 12); const tag = vaultPayload.subarray(12, 28); const encrypted = vaultPayload.subarray(28); const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv); decipher.setAuthTag(tag); return Buffer.concat([decipher.update(encrypted), decipher.final()]); } export async function GET( req: NextRequest, { params }: { params: Promise<{ filename: string }> } ) { try { const { filename } = await params; // Mencegah eksploitasi Path Traversal if (filename.includes("..") || filename.includes("/")) { return NextResponse.json({ error: "Invalid filename" }, { status: 400 }); } const localDir = process.env.OMNI_LOCAL_DIR || "/var/www/omni-storage"; const filePath = path.join(localDir, filename); // 1. Baca data terenkripsi (Ciphertext) dari brankas baja lokal const vaultPayload = await fs.readFile(filePath); // 2. Dekripsi On-The-Fly (Cleartext) untuk disajikan ke pengguna yang berhak const decryptedBuffer = decryptBuffer(vaultPayload); // Deteksi tipe konten dari nama file asli (membuang .vault) const originalExt = filename.replace(".vault", "").split(".").pop()?.toLowerCase(); let contentType = "application/octet-stream"; if (originalExt === "jpg" || originalExt === "jpeg") contentType = "image/jpeg"; else if (originalExt === "png") contentType = "image/png"; else if (originalExt === "gif") contentType = "image/gif"; else if (originalExt === "webp") contentType = "image/webp"; else if (originalExt === "pdf") contentType = "application/pdf"; else if (originalExt === "mp4") contentType = "video/mp4"; return new NextResponse(new Uint8Array(decryptedBuffer), { status: 200, headers: { "Content-Type": contentType, // Caching agresif karena file objek bersifat immutable "Cache-Control": "public, max-age=31536000, immutable", }, }); } catch (error: unknown) { const msg = error instanceof Error ? error.message : "Unknown error"; console.error("[QUANTUM VAULT] Dekripsi gagal atau file hilang:", msg); return NextResponse.json({ error: "Brankas tidak dapat diakses atau kunci enkripsi salah." }, { status: 404 }); } }