[TSM.ID].[11031972] PXE : Platform X Ecosystem I [118 Module -LIVE-]
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
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<string>();
|
||||
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|.*\\..*).*)', '/']
|
||||
};
|
||||
Reference in New Issue
Block a user