Files
multiverse/jumpa-chat/app/api/vault/[filename]/route.ts
T

69 lines
2.7 KiB
TypeScript

// [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 });
}
}