import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; const LOCALES = ['id', 'en']; // ===================================================================== // PANOPTICON LIVE KILL ENFORCEMENT (In-Memory LRU Cache) // Pengguna yang sudah di-kill akan langsung ditolak di middleware layer // tanpa menyentuh database (zero-latency 403). // ===================================================================== const killCache = new Set(); let lastKillSync = 0; const KILL_SYNC_INTERVAL_MS = 10_000; // Sinkronisasi tiap 10 detik async function syncKillList() { const now = Date.now(); if (now - lastKillSync < KILL_SYNC_INTERVAL_MS) return; lastKillSync = now; try { // Fetch kill list from internal API (server-side only) const baseUrl = `http://127.0.0.1:${process.env.PORT || 3005}`; const resp = await fetch(`${baseUrl}/api/telemetry/kill-list`, { headers: { 'x-internal-secret': process.env.JWT_SECRET || '' }, signal: AbortSignal.timeout(3000), }); if (resp.ok) { const data = await resp.json(); killCache.clear(); if (Array.isArray(data.targets)) { data.targets.forEach((id: string) => killCache.add(id)); } } } catch (_e) { // Gagal sinkronisasi = tetap gunakan cache lama. Zero-Downtime. } } function extractUserFromJWT(token: string): string | null { try { // Decode payload tanpa verifikasi (hanya untuk baca email di middleware) const parts = token.split('.'); if (parts.length !== 3) return null; const payload = JSON.parse(atob(parts[1])); return payload.email || payload.userId || null; } catch (_e) { return null; } } export async function middleware(request: NextRequest) { const pathname = request.nextUrl.pathname; // ---- PANOPTICON KILL CHECK ---- await syncKillList(); const token = request.cookies.get('jumpa_token')?.value; if (token && killCache.size > 0) { const userIdentity = extractUserFromJWT(token); if (userIdentity && killCache.has(userIdentity)) { return new NextResponse( JSON.stringify({ error: 'Akses Dihanguskan oleh Otoritas Puncak. Sesi Anda telah dimusnahkan.' }), { status: 403, headers: { 'Content-Type': 'application/json' } } ); } } // ---- NO MORE LOCALE REWRITE ---- return NextResponse.next(); } export default middleware; export const config = { matcher: ['/((?!api|_next|_vercel|.*\\..*).*)', '/'] };