Files
overlord/Overlord-Server/public/purgatory.html
T

338 lines
20 KiB
HTML
Raw Normal View History

2026-03-20 22:38:17 -05:00
<!doctype html>
<html lang="en" class="h-full">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
2026-05-08 15:36:24 -05:00
<script src="/assets/nav-prelude.js"></script>
<link rel="modulepreload" href="/assets/nav.js" />
<link rel="stylesheet" href="/vendor/inter/400.css" />
<link rel="stylesheet" href="/vendor/inter/600.css" />
<link rel="stylesheet" href="/vendor/inter/700.css" />
2026-03-20 22:38:17 -05:00
<title>Purgatory - Overlord</title>
<link rel="icon" type="image/x-icon" href="/assets/favicon.ico" />
<link rel="stylesheet" href="/assets/tailwind.css" />
<link rel="stylesheet" href="/vendor/fontawesome/css/all.min.css" />
2026-03-20 22:38:17 -05:00
<link rel="stylesheet" href="/assets/main.css" />
<link rel="stylesheet" href="/assets/custom.css" />
2026-04-08 14:37:03 -05:00
<script defer src="/assets/toast.js"></script>
2026-03-20 22:38:17 -05:00
</head>
<body class="min-h-screen bg-slate-950 text-slate-100">
<header id="top-nav"></header>
<div class="min-h-full flex flex-col">
2026-06-30 13:36:27 -05:00
<main class="flex-1 max-w-[1500px] w-full mx-auto px-4 sm:px-6 py-6">
2026-03-20 22:38:17 -05:00
<!-- Header -->
2026-06-30 13:36:27 -05:00
<div class="mb-5 rounded-lg border border-slate-800 bg-slate-900/60 px-5 py-4 shadow-[0_18px_55px_rgba(2,6,23,0.22)]">
<div class="flex flex-col xl:flex-row xl:items-center xl:justify-between gap-5">
<div class="flex items-center gap-3">
<div class="grid h-11 w-11 place-items-center rounded-lg border border-amber-400/30 bg-amber-400/10 text-amber-300">
<i class="fa-solid fa-user-clock"></i>
2026-03-20 22:38:17 -05:00
</div>
2026-06-30 13:36:27 -05:00
<div>
<h2 class="text-2xl font-bold text-slate-100 leading-tight">Purgatory</h2>
<p class="text-slate-400 text-sm">
Approve or deny clients before they can connect to the server.
</p>
</div>
</div>
<div class="flex items-stretch gap-3 flex-wrap justify-start xl:justify-end">
<div id="stats-bar" class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-2 text-sm">
<span class="min-w-[120px] rounded-lg border border-amber-400/20 bg-amber-400/5 px-3 py-2 text-amber-300">
<span class="flex items-center gap-2">
<i class="fa-solid fa-clock text-amber-400"></i>
<span class="text-lg font-semibold leading-none" id="stat-pending">0</span>
</span>
<span class="mt-1 block text-xs text-slate-400">pending</span>
</span>
<span class="min-w-[120px] rounded-lg border border-emerald-400/20 bg-emerald-400/5 px-3 py-2 text-emerald-300">
<span class="flex items-center gap-2">
<i class="fa-solid fa-check text-emerald-400"></i>
<span class="text-lg font-semibold leading-none" id="stat-approved">0</span>
</span>
<span class="mt-1 block text-xs text-slate-400">approved</span>
</span>
<span class="min-w-[120px] rounded-lg border border-red-400/20 bg-red-400/5 px-3 py-2 text-red-300">
<span class="flex items-center gap-2">
<i class="fa-solid fa-ban text-red-400"></i>
<span class="text-lg font-semibold leading-none" id="stat-denied">0</span>
</span>
<span class="mt-1 block text-xs text-slate-400">denied</span>
</span>
<span class="min-w-[120px] rounded-lg border border-orange-400/20 bg-orange-400/5 px-3 py-2 text-orange-300">
<span class="flex items-center gap-2">
<i class="fa-solid fa-triangle-exclamation text-orange-400"></i>
<span class="text-lg font-semibold leading-none" id="stat-suspicious">0</span>
</span>
<span class="mt-1 block text-xs text-slate-400">suspicious</span>
</span>
<span class="min-w-[120px] rounded-lg border border-rose-400/20 bg-rose-400/5 px-3 py-2 text-rose-300">
<span class="flex items-center gap-2">
<i class="fa-solid fa-shield-halved text-rose-400"></i>
<span class="text-lg font-semibold leading-none" id="stat-banned-ips">0</span>
</span>
<span class="mt-1 block text-xs text-slate-400">banned IPs</span>
</span>
</div>
<div class="flex flex-col justify-center gap-1 border border-amber-500/30 rounded-lg px-3 py-2 bg-slate-950/50 text-sm shadow-inner shadow-amber-950/10">
2026-05-22 10:12:40 -05:00
<div class="flex items-center gap-2" title="When enabled, all connecting agents are approved automatically without review">
<i class="fa-solid fa-door-open text-amber-400"></i>
<span class="text-slate-300 font-medium">Always Allow</span>
<label class="relative inline-flex items-center cursor-pointer ml-1">
<input type="checkbox" id="auto-accept-toggle" class="sr-only peer" />
<div class="w-9 h-5 bg-slate-700 peer-checked:bg-amber-500 rounded-full transition-colors"></div>
<div class="absolute left-0.5 top-0.5 w-4 h-4 bg-white rounded-full transition-transform peer-checked:translate-x-4"></div>
</label>
</div>
<div id="unless-suspicious-row" class="hidden flex items-center gap-2 pl-1" title="Still quarantine agents that look suspicious (HWID flood, IP flood, no hostname, etc.)">
<i class="fa-solid fa-shield-halved text-slate-500 text-xs"></i>
<span class="text-slate-400 text-xs">Unless suspicious</span>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" id="unless-suspicious-toggle" class="sr-only peer" />
<div class="w-7 h-4 bg-slate-700 peer-checked:bg-emerald-600 rounded-full transition-colors"></div>
<div class="absolute left-0.5 top-0.5 w-3 h-3 bg-white rounded-full transition-transform peer-checked:translate-x-3"></div>
</label>
</div>
</div>
2026-03-20 22:38:17 -05:00
</div>
2026-06-30 13:36:27 -05:00
</div>
2026-03-20 22:38:17 -05:00
</div>
<!-- Filter Tabs -->
2026-06-30 13:36:27 -05:00
<div class="mb-4 flex items-center gap-2 flex-wrap rounded-lg border border-slate-800 bg-slate-900/45 p-2">
2026-03-20 22:38:17 -05:00
<button data-filter="pending"
2026-06-30 13:36:27 -05:00
class="enrollment-tab px-4 py-2 rounded-md text-sm font-medium bg-amber-500/20 text-amber-300 border border-amber-500/40">
2026-03-20 22:38:17 -05:00
Pending
</button>
<button data-filter="denied"
2026-06-30 13:36:27 -05:00
class="enrollment-tab px-4 py-2 rounded-md text-sm font-medium bg-slate-800 text-slate-400 border border-slate-700 hover:bg-slate-700">
2026-03-20 22:38:17 -05:00
Denied
</button>
<button data-filter="approved"
2026-06-30 13:36:27 -05:00
class="enrollment-tab px-4 py-2 rounded-md text-sm font-medium bg-slate-800 text-slate-400 border border-slate-700 hover:bg-slate-700">
2026-03-20 22:38:17 -05:00
Approved
</button>
<button data-filter="banned-ips"
2026-06-30 13:36:27 -05:00
class="enrollment-tab px-4 py-2 rounded-md text-sm font-medium bg-slate-800 text-slate-400 border border-slate-700 hover:bg-slate-700">
2026-03-20 22:38:17 -05:00
<i class="fa-solid fa-shield-halved mr-1"></i>Banned IPs
</button>
2026-05-22 10:12:40 -05:00
<button data-filter="suspicious"
2026-06-30 13:36:27 -05:00
class="enrollment-tab px-4 py-2 rounded-md text-sm font-medium bg-slate-800 text-slate-400 border border-slate-700 hover:bg-slate-700">
2026-05-22 10:12:40 -05:00
<i class="fa-solid fa-triangle-exclamation mr-1"></i>Suspicious
</button>
2026-03-20 22:38:17 -05:00
<div class="flex-1"></div>
<button id="approve-all-btn"
class="hidden px-3 py-2 rounded-lg text-sm font-medium bg-emerald-700 hover:bg-emerald-800 text-white transition-colors">
2026-05-22 10:12:40 -05:00
<i class="fa-solid fa-check-double mr-1"></i>Approve All
</button>
<button id="deny-all-btn"
class="hidden px-3 py-2 rounded-lg text-sm font-medium bg-red-700 hover:bg-red-800 text-white transition-colors">
<i class="fa-solid fa-ban mr-1"></i>Deny All
</button>
2026-03-20 22:38:17 -05:00
<div class="relative">
<i class="fa-solid fa-search absolute left-3 top-1/2 -translate-y-1/2 text-slate-500 text-sm pointer-events-none"></i>
<input type="text" id="search-input" placeholder="Search host, user, IP..."
2026-06-30 13:36:27 -05:00
class="w-56 pl-9 pr-3 py-2 rounded-md text-sm bg-slate-950/70 border border-slate-700 text-slate-200 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:border-transparent" />
2026-03-20 22:38:17 -05:00
</div>
<button id="bulk-approve-btn"
class="hidden px-3 py-2 rounded-lg text-sm font-medium bg-emerald-600 hover:bg-emerald-700 text-white transition-colors">
<i class="fa-solid fa-check mr-1"></i>Approve Selected
</button>
<button id="bulk-deny-btn"
class="hidden px-3 py-2 rounded-lg text-sm font-medium bg-red-600 hover:bg-red-700 text-white transition-colors">
<i class="fa-solid fa-ban mr-1"></i>Deny Selected
</button>
<button id="bulk-ban-btn"
class="hidden px-3 py-2 rounded-lg text-sm font-medium bg-rose-700 hover:bg-rose-800 text-white transition-colors">
<i class="fa-solid fa-shield-halved mr-1"></i>Ban Selected IPs
</button>
</div>
<!-- Clients Table -->
2026-06-30 13:36:27 -05:00
<div id="clients-table-panel" class="bg-slate-900/55 border border-slate-800 rounded-lg overflow-x-auto shadow-[0_18px_55px_rgba(2,6,23,0.18)]">
2026-05-30 22:44:55 -05:00
<table class="w-full min-w-[1200px]" id="enrollment-table">
2026-06-30 13:36:27 -05:00
<thead class="bg-slate-950/55 border-b border-slate-700">
2026-05-30 22:44:55 -05:00
<tr>
<th class="w-10 px-4 py-3">
<input type="checkbox" id="select-all" class="h-4 w-4 rounded border-slate-600" />
</th>
<th class="text-left px-4 py-3 text-sm font-semibold text-slate-300">Host</th>
<th class="text-left px-4 py-3 text-sm font-semibold text-slate-300">User</th>
<th class="text-left px-4 py-3 text-sm font-semibold text-slate-300">OS</th>
<th class="text-left px-4 py-3 text-sm font-semibold text-slate-300">CPU</th>
<th class="text-left px-4 py-3 text-sm font-semibold text-slate-300">GPU</th>
<th class="text-left px-4 py-3 text-sm font-semibold text-slate-300">RAM</th>
<th class="text-left px-4 py-3 text-sm font-semibold text-slate-300">IP</th>
<th class="text-left px-4 py-3 text-sm font-semibold text-slate-300">Country</th>
<th class="text-left px-4 py-3 text-sm font-semibold text-slate-300">Key Fingerprint</th>
<th class="text-left px-4 py-3 text-sm font-semibold text-slate-300">Last Seen</th>
<th class="text-left px-4 py-3 text-sm font-semibold text-slate-300">Status</th>
<th class="text-right px-4 py-3 text-sm font-semibold text-slate-300">Actions</th>
</tr>
</thead>
<tbody id="enrollment-body" class="divide-y divide-slate-800">
<tr id="enrollment-loading">
<td colspan="13" class="px-6 py-12 text-center text-slate-500">
<i class="fa-solid fa-spinner fa-spin mr-2"></i>Loading...
</td>
</tr>
</tbody>
</table>
2026-03-20 22:38:17 -05:00
<div id="enrollment-empty" class="hidden px-6 py-12 text-center text-slate-500">
<i class="fa-solid fa-inbox text-3xl mb-3 block"></i>
<p>No clients in this category.</p>
</div>
</div>
<!-- Banned IPs Table (hidden by default, shown on Banned IPs tab) -->
<div id="banned-ips-section" class="hidden">
<div class="mb-4 flex items-center justify-between">
<h3 class="text-lg font-semibold text-slate-100">
<i class="fa-solid fa-shield-halved text-rose-400 mr-2"></i>Banned IPs
</h3>
<button id="add-ban-btn"
class="px-3 py-2 rounded-lg text-sm font-medium bg-red-600 hover:bg-red-700 text-white transition-colors">
<i class="fa-solid fa-plus mr-1"></i>Ban IP
</button>
</div>
<!-- Manual ban form (hidden by default) -->
<div id="manual-ban-form" class="hidden mb-4 bg-slate-900/60 border border-slate-800 rounded-xl p-4">
<div class="flex items-end gap-3">
<div class="flex-1">
<label class="block text-sm font-medium text-slate-300 mb-1">IP Address</label>
<input type="text" id="ban-ip-input" placeholder="e.g. 192.168.1.100"
class="w-full px-3 py-2 rounded-lg text-sm bg-slate-800 border border-slate-700 text-slate-200 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-red-500 focus:border-transparent" />
</div>
<div class="flex-1">
<label class="block text-sm font-medium text-slate-300 mb-1">Reason (optional)</label>
<input type="text" id="ban-reason-input" placeholder="Reason for ban"
class="w-full px-3 py-2 rounded-lg text-sm bg-slate-800 border border-slate-700 text-slate-200 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-red-500 focus:border-transparent" />
</div>
<button id="confirm-ban-btn"
class="px-4 py-2 rounded-lg text-sm font-medium bg-red-600 hover:bg-red-700 text-white transition-colors">
Ban
</button>
<button id="cancel-ban-btn"
class="px-4 py-2 rounded-lg text-sm font-medium bg-slate-700 hover:bg-slate-600 text-white transition-colors">
Cancel
</button>
</div>
</div>
<div class="bg-slate-900/50 border border-slate-800 rounded-xl overflow-hidden">
2026-05-30 22:44:55 -05:00
<table class="w-full">
<thead class="bg-slate-800/50 border-b border-slate-700">
<tr>
<th class="text-left px-4 py-3 text-sm font-semibold text-slate-300">IP Address</th>
<th class="text-left px-4 py-3 text-sm font-semibold text-slate-300">Reason</th>
<th class="text-left px-4 py-3 text-sm font-semibold text-slate-300">Banned At</th>
<th class="text-right px-4 py-3 text-sm font-semibold text-slate-300">Actions</th>
</tr>
</thead>
<tbody id="banned-ips-body" class="divide-y divide-slate-800"></tbody>
</table>
2026-03-20 22:38:17 -05:00
<div id="banned-ips-empty" class="hidden px-6 py-12 text-center text-slate-500">
<i class="fa-solid fa-shield-halved text-3xl mb-3 block"></i>
<p>No banned IPs.</p>
</div>
</div>
</div>
</main>
</div>
<!-- Ban Confirmation Modal -->
<div id="ban-confirm-modal" class="hidden fixed inset-0 z-50 flex items-center justify-center">
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" id="ban-modal-backdrop"></div>
<div class="relative bg-slate-900 border border-slate-700 rounded-2xl shadow-2xl max-w-md w-full mx-4 p-6">
<div class="flex items-center gap-3 mb-4">
<div class="flex-shrink-0 w-12 h-12 rounded-full bg-rose-500/20 flex items-center justify-center">
<i class="fa-solid fa-shield-halved text-rose-400 text-xl"></i>
</div>
<div>
<h3 class="text-lg font-bold text-slate-100">Confirm IP Ban</h3>
<p class="text-sm text-slate-400">This action cannot be easily undone.</p>
</div>
</div>
<div id="ban-modal-body" class="mb-5 text-sm text-slate-300">
<!-- Filled dynamically -->
</div>
<div class="flex items-center justify-end gap-3">
<button id="ban-modal-cancel"
class="px-4 py-2 rounded-lg text-sm font-medium bg-slate-700 hover:bg-slate-600 text-white transition-colors">
Cancel
</button>
<button id="ban-modal-confirm"
class="px-4 py-2 rounded-lg text-sm font-medium bg-rose-600 hover:bg-rose-700 text-white transition-colors">
<i class="fa-solid fa-shield-halved mr-1"></i>Ban
</button>
</div>
</div>
</div>
2026-05-22 10:12:40 -05:00
<!-- Deny Reason Modal -->
<div id="deny-reason-modal" class="hidden fixed inset-0 z-50 flex items-center justify-center">
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" id="deny-reason-modal-backdrop"></div>
<div class="relative bg-slate-900 border border-red-500/40 rounded-2xl shadow-2xl max-w-md w-full mx-4 p-6">
<div class="flex items-center gap-3 mb-4">
<div class="flex-shrink-0 w-12 h-12 rounded-full bg-red-500/20 flex items-center justify-center">
<i class="fa-solid fa-ban text-red-400 text-xl"></i>
</div>
<div>
<h3 class="text-lg font-bold text-slate-100">Deny Client</h3>
<p class="text-sm text-slate-400">Optionally record a reason for audit purposes.</p>
</div>
</div>
<div class="mb-5">
<label class="block text-sm font-medium text-slate-300 mb-1">Reason <span class="text-slate-500 font-normal">(optional)</span></label>
<input type="text" id="deny-reason-input" maxlength="200" placeholder="Suspicious activity, unauthorized machine..."
class="w-full px-3 py-2 rounded-lg text-sm bg-slate-800 border border-slate-700 text-slate-200 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-red-500 focus:border-transparent" />
</div>
<div class="flex items-center justify-end gap-3">
<button id="deny-reason-modal-cancel"
class="px-4 py-2 rounded-lg text-sm font-medium bg-slate-700 hover:bg-slate-600 text-white transition-colors">
Cancel
</button>
<button id="deny-reason-modal-confirm"
class="px-4 py-2 rounded-lg text-sm font-medium bg-red-600 hover:bg-red-700 text-white transition-colors">
<i class="fa-solid fa-ban mr-1"></i>Deny
</button>
</div>
</div>
</div>
<!-- Always Allow Warning Modal -->
<div id="auto-accept-modal" class="hidden fixed inset-0 z-50 flex items-center justify-center">
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" id="auto-accept-modal-backdrop"></div>
<div class="relative bg-slate-900 border border-amber-500/40 rounded-2xl shadow-2xl max-w-md w-full mx-4 p-6">
<div class="flex items-center gap-3 mb-4">
<div class="flex-shrink-0 w-12 h-12 rounded-full bg-amber-500/20 flex items-center justify-center">
<i class="fa-solid fa-triangle-exclamation text-amber-400 text-xl"></i>
</div>
<div>
<h3 class="text-lg font-bold text-slate-100">Disable Approval Requirement?</h3>
<p class="text-sm text-amber-400">This disables all enrollment security.</p>
</div>
</div>
<div class="mb-5 text-sm text-slate-300 space-y-2">
<p>With <strong class="text-amber-300">Always Allow</strong> enabled, <strong>any agent that connects will be automatically approved</strong> without manual review.</p>
<p class="bg-amber-500/10 border border-amber-500/30 rounded-lg px-3 py-2 text-amber-200">
<i class="fa-solid fa-triangle-exclamation mr-1"></i>
This effectively disables all enrollment security. Any machine running your agent binary will gain immediate access to the server.
</p>
</div>
<div class="flex items-center justify-end gap-3">
<button id="auto-accept-modal-cancel"
class="px-4 py-2 rounded-lg text-sm font-medium bg-slate-700 hover:bg-slate-600 text-white transition-colors">
Cancel
</button>
<button id="auto-accept-modal-confirm"
class="px-4 py-2 rounded-lg text-sm font-medium bg-amber-600 hover:bg-amber-700 text-white transition-colors">
<i class="fa-solid fa-door-open mr-1"></i>Enable Always Allow
</button>
</div>
</div>
</div>
2026-03-20 22:38:17 -05:00
<script type="module" src="/assets/nav.js"></script>
<script type="module" src="/assets/purgatory-ui.js"></script>
</body>
</html>