Files

256 lines
11 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useEffect, useState } from "react";
export default function SovereignSetup() {
const [os, setOs] = useState<string>("unknown");
const [certStatus, setCertStatus] = useState<"idle" | "testing" | "ok" | "fail">("idle");
const [tenantName, setTenantName] = useState("SOVEREIGN TENANT");
useEffect(() => {
const ua = navigator.userAgent.toLowerCase();
if (ua.includes("android")) setOs("android");
else if (ua.includes("iphone") || ua.includes("ipad")) setOs("ios");
else if (ua.includes("mac")) setOs("macos");
else if (ua.includes("windows")) setOs("windows");
else if (ua.includes("linux")) setOs("linux");
else setOs("unknown");
// Fetch tenant info
fetch("/api/auth/me").then(r => r.json()).then(d => {
if (d.tenantName) setTenantName(d.tenantName);
}).catch(() => {});
}, []);
const testConnection = async () => {
setCertStatus("testing");
try {
const resp = await fetch("/api/superadmin/xcu-tls-switch");
if (resp.ok) {
const data = await resp.json();
const onlineNodes = data.nodes?.filter((n: any) => n.online) || [];
setCertStatus(onlineNodes.length > 0 ? "ok" : "fail");
} else {
setCertStatus("fail");
}
} catch {
setCertStatus("fail");
}
};
const instructions: Record<string, { title: string; icon: string; steps: string[] }> = {
android: {
title: "Android",
icon: "📱",
steps: [
"Tap tombol \"Download CA Certificate\" di bawah",
"Buka Settings → Security → Encryption & Credentials",
"Tap \"Install a certificate\" → \"CA certificate\"",
"Pilih file xcu-sovereign-ca.crt yang baru di-download",
"Konfirmasi dengan PIN/Fingerprint",
"Selesai! Certificate berlaku 30 tahun"
]
},
ios: {
title: "iPhone / iPad",
icon: "🍎",
steps: [
"Tap tombol \"Download CA Certificate\" di bawah",
"iOS akan menampilkan \"Profile Downloaded\"",
"Buka Settings → General → VPN & Device Management",
"Tap profile \"XCU Sovereign CA\" → Install",
"Buka Settings → General → About → Certificate Trust Settings",
"Enable trust untuk \"XCU Sovereign CA\"",
"Selesai! Certificate berlaku 30 tahun"
]
},
windows: {
title: "Windows",
icon: "🖥️",
steps: [
"Klik tombol \"Download CA Certificate\" di bawah",
"Double-click file xcu-sovereign-ca.crt",
"Klik \"Install Certificate...\"",
"Pilih \"Local Machine\" → Next",
"Pilih \"Place all certificates in the following store\"",
"Klik Browse → pilih \"Trusted Root Certification Authorities\"",
"Klik Finish → Yes",
"Restart browser. Selesai!"
]
},
macos: {
title: "macOS",
icon: "💻",
steps: [
"Klik tombol \"Download CA Certificate\" di bawah",
"Double-click file xcu-sovereign-ca.crt → Keychain Access terbuka",
"Certificate muncul di login keychain",
"Double-click certificate → Trust → \"Always Trust\"",
"Tutup dialog, masukkan password Mac",
"Restart browser. Selesai!"
]
},
linux: {
title: "Linux",
icon: "🐧",
steps: [
"Download CA Certificate",
"sudo cp xcu-sovereign-ca.crt /usr/local/share/ca-certificates/",
"sudo update-ca-certificates",
"Restart browser. Selesai!"
]
},
unknown: {
title: "Device",
icon: "🔧",
steps: ["Download CA Certificate dan install sesuai OS Anda"]
}
};
const currentOs = instructions[os] || instructions.unknown;
return (
<div className="min-h-screen bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950 text-white">
{/* Header */}
<header className="border-b border-slate-800 px-6 py-4">
<div className="max-w-4xl mx-auto flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-amber-500 to-orange-600 flex items-center justify-center shadow-lg">
<svg className="w-5 h-5 text-white" fill="currentColor" viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
</div>
<div>
<h1 className="text-lg font-bold tracking-tight">Sovereign Security Setup</h1>
<p className="text-xs text-slate-400">{tenantName} Private CA Installation</p>
</div>
</div>
<a href="/supreme-admin" className="text-xs text-slate-400 hover:text-white transition-colors"> Back to Dashboard</a>
</div>
</header>
<main className="max-w-4xl mx-auto px-6 py-10 space-y-8">
{/* Hero Card */}
<div className="bg-gradient-to-r from-amber-500/10 via-orange-500/5 to-transparent border border-amber-500/20 rounded-2xl p-8">
<div className="flex items-start gap-4">
<div className="text-4xl">🛡</div>
<div>
<h2 className="text-2xl font-bold mb-2">Mode Sovereign Aktif</h2>
<p className="text-slate-300 text-sm leading-relaxed">
Tenant ini beroperasi dalam <strong className="text-amber-400">Security Tier SOVEREIGN</strong>.
Semua koneksi QUIC/WebTransport menggunakan Private CA yang tidak bergantung pada internet global.
Setiap device perlu install sertifikat CA <strong>1× saja</strong>, berlaku <strong>30 tahun</strong>.
</p>
</div>
</div>
</div>
{/* Download Section */}
<div className="bg-slate-800/50 border border-slate-700 rounded-2xl p-8">
<h3 className="text-lg font-bold mb-4 flex items-center gap-2">
<span className="w-8 h-8 rounded-lg bg-emerald-500/20 flex items-center justify-center text-emerald-400 text-sm font-bold">1</span>
Download Certificate
</h3>
<div className="flex flex-wrap gap-4">
<a
href="/api/superadmin/sovereign-ca/download"
download="xcu-sovereign-ca.crt"
className="inline-flex items-center gap-3 px-6 py-3 bg-gradient-to-r from-emerald-600 to-emerald-500 hover:from-emerald-500 hover:to-emerald-400 text-white font-bold rounded-xl transition-all duration-300 shadow-lg shadow-emerald-500/20 hover:shadow-emerald-500/40 hover:scale-105"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /></svg>
Download CA Certificate
</a>
<div className="flex items-center gap-2 text-xs text-slate-500">
<span>Format: X.509 PEM</span>
<span></span>
<span>Validitas: 30 tahun</span>
<span></span>
<span>Algorithm: RSA-4096 + SHA-256</span>
</div>
</div>
</div>
{/* OS-Specific Instructions */}
<div className="bg-slate-800/50 border border-slate-700 rounded-2xl p-8">
<h3 className="text-lg font-bold mb-1 flex items-center gap-2">
<span className="w-8 h-8 rounded-lg bg-blue-500/20 flex items-center justify-center text-blue-400 text-sm font-bold">2</span>
Install Certificate
</h3>
<p className="text-xs text-slate-400 mb-6">
Terdeteksi: <strong className="text-cyan-400">{currentOs.icon} {currentOs.title}</strong>
</p>
{/* OS Tabs */}
<div className="flex flex-wrap gap-2 mb-6">
{Object.entries(instructions).filter(([k]) => k !== 'unknown').map(([key, val]) => (
<button
key={key}
onClick={() => setOs(key)}
className={`px-4 py-2 rounded-lg text-xs font-bold uppercase tracking-wider transition-all ${
os === key
? 'bg-cyan-500 text-white shadow-lg shadow-cyan-500/30'
: 'bg-slate-700 text-slate-400 hover:bg-slate-600 hover:text-white'
}`}
>
{val.icon} {val.title}
</button>
))}
</div>
{/* Steps */}
<div className="space-y-3">
{currentOs.steps.map((step, idx) => (
<div key={idx} className="flex gap-3 items-start">
<div className="w-6 h-6 rounded-full bg-slate-700 flex items-center justify-center text-[10px] font-bold text-cyan-400 flex-shrink-0 mt-0.5">
{idx + 1}
</div>
<p className="text-sm text-slate-300">{step}</p>
</div>
))}
</div>
</div>
{/* Connection Test */}
<div className="bg-slate-800/50 border border-slate-700 rounded-2xl p-8">
<h3 className="text-lg font-bold mb-4 flex items-center gap-2">
<span className="w-8 h-8 rounded-lg bg-purple-500/20 flex items-center justify-center text-purple-400 text-sm font-bold">3</span>
Verify Connection
</h3>
<div className="flex items-center gap-4">
<button
onClick={testConnection}
disabled={certStatus === "testing"}
className="inline-flex items-center gap-2 px-6 py-3 bg-gradient-to-r from-purple-600 to-purple-500 hover:from-purple-500 hover:to-purple-400 text-white font-bold rounded-xl transition-all duration-300 shadow-lg shadow-purple-500/20 disabled:opacity-50"
>
{certStatus === "testing" ? (
<div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"></div>
) : (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
)}
Test Connection
</button>
{certStatus === "ok" && (
<div className="flex items-center gap-2 px-4 py-2 bg-emerald-500/10 border border-emerald-500/20 rounded-xl">
<span className="relative flex h-3 w-3">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-3 w-3 bg-emerald-400"></span>
</span>
<span className="text-sm font-bold text-emerald-400">Koneksi Aman XCU Engine Online</span>
</div>
)}
{certStatus === "fail" && (
<div className="flex items-center gap-2 px-4 py-2 bg-red-500/10 border border-red-500/20 rounded-xl">
<span className="w-3 h-3 rounded-full bg-red-500"></span>
<span className="text-sm font-bold text-red-400">Koneksi Gagal Pastikan certificate sudah terinstall</span>
</div>
)}
</div>
</div>
{/* Info */}
<div className="text-center text-xs text-slate-600 py-4">
XCom ULTRA Sovereign Security Infrastructure Private CA Zero Internet Dependency
</div>
</main>
</div>
);
}