import { NextResponse } from 'next/server'; import jwt from 'jsonwebtoken'; // Konfigurasi CORS agar JUMPA.ID VC (atau subdomain lain) bisa mengakses endpoint ini function applyCorsHeaders(res: NextResponse, req: Request) { const origin = req.headers.get('origin'); // Di sistem produksi, pastikan hanya mengizinkan origin yang valid (misal: *.ultramodul.xyz) if (origin && (origin.includes('ultramodul.xyz') || origin.includes('localhost'))) { res.headers.set('Access-Control-Allow-Origin', origin); } res.headers.set('Access-Control-Allow-Credentials', 'true'); res.headers.set('Access-Control-Allow-Methods', 'GET, OPTIONS'); res.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization'); return res; } export async function OPTIONS(req: Request) { const res = new NextResponse(null, { status: 204 }); return applyCorsHeaders(res, req); } export async function GET(req: Request) { try { // 1. Ekstrak Session Token JUMPA.ID (Authentication) const cookieHeader = req.headers.get('cookie') || ''; const cookies = Object.fromEntries(cookieHeader.split('; ').map(c => c.split('='))); const sessionToken = cookies['jumpa_token']; if (!sessionToken) { const res = NextResponse.json({ error: 'Unauthorized: No session token found' }, { status: 401 }); return applyCorsHeaders(res, req); } // 2. Dekripsi Session Token const jwtSecret = process.env.JWT_SECRET; if (!jwtSecret) { throw new Error('JWT_SECRET is not configured'); } let decodedSession: { licenses?: Record; tenantName?: string }; try { decodedSession = jwt.verify(sessionToken, jwtSecret) as { licenses?: Record; tenantName?: string }; } catch (_e) { const res = NextResponse.json({ error: 'Unauthorized: Invalid session token' }, { status: 401 }); return applyCorsHeaders(res, req); } // 3. Ekstrak hak akses (licenses) dari Token Session // Format licenses: { "chat": "GRANTED", "vc": "GRANTED", "recording": "GRANTED", "pulsar_codec": "GRANTED" } const licenses = decodedSession.licenses || {}; const tenantName = decodedSession.tenantName || 'UNKNOWN_TENANT'; // 4. Translasi fitur IAM ke Module ID XCU Core (Ala Carte Modules) const allowedModules: number[] = []; // Pengecualian Khusus VIP TELAH DIHAPUS (No more hardcoded bypass) // Auto-Pilot & JVC Package Logic if (licenses['pulsar_codec'] === 'GRANTED' || licenses['recording'] === 'GRANTED' || licenses['JVC'] === 'GRANTED') { allowedModules.push(43); // Modul 43: PulsarCodec / Recording / Hot-Swap HD } if (licenses['crdt_chat'] === 'GRANTED' || licenses['x_ray_log'] === 'GRANTED' || licenses['JC'] === 'GRANTED' || licenses['JVC'] === 'GRANTED') { allowedModules.push(72); // Modul 72: Neural CRDT Chat / X-Ray Diagnostic } if (licenses['ebpf_shield'] === 'GRANTED' || licenses['JVC'] === 'GRANTED') { allowedModules.push(88); // Modul 88: The eBPF Shield (Ring-0 DDoS) } if (licenses['ouroboros_sla'] === 'GRANTED' || licenses['JVC'] === 'GRANTED') { allowedModules.push(99); // Modul 99: Ouroboros Automation (Self-Healing SLA) } // 5. Generate The Quantum Entitlement Token (JWS murni) // Ditandatangani menggunakan kunci simetris yang hanya diketahui oleh IAM dan XCU Core const quantumSecret = process.env.XCU_TOKEN_SECRET || "UltR4S3cr3T_XCU_Key_2026!"; // Sinkron dengan Rust xcu-core const quantumToken = jwt.sign( { tenant: tenantName, allowed_modules: allowedModules, }, quantumSecret, { expiresIn: '8h' } ); const res = NextResponse.json({ success: true, token: quantumToken, modules: allowedModules, }, { status: 200 }); return applyCorsHeaders(res, req); } catch (error: unknown) { console.error('[QUANTUM TOKEN ERROR]', error); const res = NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }); return applyCorsHeaders(res, req); } }