82 lines
3.0 KiB
TypeScript
82 lines
3.0 KiB
TypeScript
import { NextResponse } from 'next/server';
|
|
import { db, writerDb } from "@/drizzle/db";
|
|
import { liveKillSwitches, quantumLogs } from "@/drizzle/schema";
|
|
import { cookies } from 'next/headers';
|
|
import jwt from 'jsonwebtoken';
|
|
|
|
// PANOPTICON: Live Kill Endpoint
|
|
export async function POST(req: Request) {
|
|
try {
|
|
const cookieStore = await cookies();
|
|
const token = cookieStore.get('jumpa_token')?.value;
|
|
|
|
if (!token) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
|
|
const decoded = jwt.verify(token, process.env.JWT_SECRET as string) as any;
|
|
|
|
// Only superadmin or admin can execute Live Kill
|
|
if (decoded.role !== 'superadmin' && decoded.role !== 'admin') {
|
|
return NextResponse.json({ error: 'Quantum Jurisdiction Denied' }, { status: 403 });
|
|
}
|
|
|
|
const { targetType, targetId, reason } = await req.json();
|
|
|
|
if (!targetType || !targetId) {
|
|
return NextResponse.json({ error: 'Target not specified' }, { status: 400 });
|
|
}
|
|
|
|
// Insert into Live Kill Registry using writerDb (Alpha Node)
|
|
await writerDb.insert(liveKillSwitches).values({
|
|
tenantId: decoded.tenantId,
|
|
targetType,
|
|
targetId,
|
|
reason: reason || 'Violation of Quantum Directives',
|
|
issuedBy: decoded.email,
|
|
});
|
|
|
|
// Log the execution
|
|
await writerDb.insert(quantumLogs).values({
|
|
tenantId: decoded.tenantId,
|
|
actor: decoded.email,
|
|
action: 'LIVE_KILL_EXECUTION',
|
|
targetId: `${targetType}:${targetId}`,
|
|
ipAddress: req.headers.get('x-forwarded-for') || '127.0.0.1',
|
|
userAgent: req.headers.get('user-agent'),
|
|
});
|
|
|
|
// PANOPTICON → XCU RPC Bridge: Kirim sinyal KILL ke mesin Rust
|
|
// XCU akan memutus QUIC stream secara fisik dalam <0.05ms
|
|
const XCU_RPC_PORT = parseInt(process.env.XCU_RPC_PORT || '9090');
|
|
try {
|
|
const net = await import('net');
|
|
const rpcPayload = JSON.stringify({
|
|
action: 'KILL_SESSION',
|
|
target_id: targetId,
|
|
reason: reason || 'Otoritas Puncak',
|
|
issued_by: decoded.email,
|
|
});
|
|
|
|
await new Promise<void>((resolve, reject) => {
|
|
const client = new net.Socket();
|
|
client.connect(XCU_RPC_PORT, '127.0.0.1', () => {
|
|
client.write(rpcPayload);
|
|
client.on('data', () => { client.destroy(); resolve(); });
|
|
setTimeout(() => { client.destroy(); resolve(); }, 2000);
|
|
});
|
|
client.on('error', (err: Error) => {
|
|
console.warn('[XCU RPC] Engine tidak tersedia, kill hanya tercatat di DB:', err.message);
|
|
resolve(); // Non-blocking: kill tetap berhasil di DB meskipun engine offline
|
|
});
|
|
});
|
|
} catch (rpcErr: any) {
|
|
console.warn('[XCU RPC] Bridge error (non-fatal):', rpcErr.message);
|
|
}
|
|
|
|
return NextResponse.json({ success: true, message: 'Target Successfully Terminated via PANOPTICON + XCU RPC' });
|
|
|
|
} catch (error: any) {
|
|
console.error('[LIVE KILL ERROR]', error);
|
|
return NextResponse.json({ error: 'Execution Failed' }, { status: 500 });
|
|
}
|
|
}
|