2026-03-06 20:50:02 -06: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-06 20:50:02 -06:00
< title > Settings - Overlord</ title >
< link rel = "icon" type = "image/x-icon" href = "/assets/favicon.ico" />
< link rel = "stylesheet" href = "/assets/tailwind.css" />
2026-04-18 21:16:29 -05:00
< link rel = "stylesheet" href = "/vendor/fontawesome/css/all.min.css" />
2026-03-06 20:50:02 -06:00
< link rel = "stylesheet" href = "/assets/main.css" />
2026-04-01 13:49:41 -05:00
< link rel = "stylesheet" href = "/assets/custom.css" />
2026-04-29 00:22:37 -05:00
< style >
. settings-nav-link {
display : flex ;
align-items : center ;
gap : 0.625 rem ;
padding : 0.5 rem 0.75 rem ;
border-radius : 0.5 rem ;
color : rgb ( 203 213 225 ); /* slate-300 */
cursor : pointer ;
transition : background-color 120 ms , color 120 ms ;
}
. settings-nav-link : hover {
background-color : rgb ( 30 41 59 / 0.7 ); /* slate-800/70 */
color : rgb ( 241 245 249 ); /* slate-100 */
}
/* Active state pulls its color from --accent (set inline per link to
match the link's icon). Falls back to sky-400 if not set. */
. settings-nav-link . active {
background-color : rgb ( var ( -- accent , 56 189 248 ) / 0.18 );
color : rgb ( 241 245 249 );
box-shadow :
inset 2 px 0 0 0 rgb ( var ( -- accent , 56 189 248 )),
0 0 14 px -2 px rgb ( var ( -- accent , 56 189 248 ) / 0.45 );
}
. settings-nav-group-label {
display : block ;
padding : 0.5 rem 0.75 rem 0.25 rem ;
font-size : 0.625 rem ;
font-weight : 600 ;
text-transform : uppercase ;
letter-spacing : 0.08 em ;
color : rgb ( 100 116 139 ); /* slate-500 */
}
/* Scroll offset for #section anchors. In topbar nav mode this is set to
the topbar's actual rendered height + a small buffer at runtime; in
sidebar mode it's just a small visual margin. The settings-section
class applies scroll-margin-top, which both `scrollIntoView` and
browser hash navigation honor. */
: root { --settings-scroll-mt : 1 rem ; }
. settings-section { scroll-margin-top : var ( -- settings - scroll - mt ); }
/* Also pin the sticky sidebar below the topbar so it doesn't slide
under the nav when the page is scrolled. */
# settings-sidebar { top : var ( -- settings - scroll - mt ); }
</ style >
2026-03-06 20:50:02 -06:00
</ head >
< body class = "min-h-screen bg-slate-950 text-slate-100" >
< header id = "top-nav" ></ header >
2026-04-29 00:22:37 -05:00
< main class = "max-w-7xl w-full mx-auto px-4 py-8" >
< div class = "mb-6" >
2026-03-06 20:50:02 -06:00
< h1 class = "text-2xl font-bold text-slate-100" > Settings</ h1 >
< p class = "text-slate-400 text-sm" >
2026-04-29 00:22:37 -05:00
Manage your account preferences, operational tools, and admin configuration.
2026-03-06 20:50:02 -06:00
</ p >
</ div >
2026-04-29 00:22:37 -05:00
< div class = "flex flex-col lg:flex-row gap-6" >
<!-- Sidebar nav -->
< aside class = "lg:w-56 lg:flex-shrink-0" >
< nav id = "settings-sidebar"
class = "lg:sticky bg-slate-900/60 border border-slate-800 rounded-xl p-2 space-y-0.5 text-sm" >
< span class = "settings-nav-group-label" > Personal</ span >
< a data-target = "section-account" class = "settings-nav-link" style = "--accent: 56 189 248" >< i class = "fa-solid fa-user w-4 text-sky-400" ></ i >< span > Account</ span ></ a >
< a data-target = "section-sessions" class = "settings-nav-link" style = "--accent: 52 211 153" >< i class = "fa-solid fa-desktop w-4 text-emerald-400" ></ i >< span > Active Sessions</ span ></ a >
< a data-target = "section-prefs" class = "settings-nav-link" style = "--accent: 167 139 250" >< i class = "fa-solid fa-sliders w-4 text-violet-400" ></ i >< span > Dashboard Preferences</ span ></ a >
< a data-target = "telegram-settings" class = "settings-nav-link" style = "--accent: 52 211 153" >< i class = "fa-solid fa-bell w-4 text-emerald-400" ></ i >< span > Notification Delivery</ span ></ a >
< a data-target = "section-news" class = "settings-nav-link" style = "--accent: 56 189 248" >< i class = "fa-brands fa-telegram w-4 text-sky-400" ></ i >< span > News & Updates</ span ></ a >
2026-05-19 00:46:30 -05:00
< span class = "settings-nav-group-label" > Operations</ span >
< a data-target = "section-bans" class = "settings-nav-link" data-permission = "network:manage-bans" style = "--accent: 248 113 113" >< i class = "fa-solid fa-ban w-4 text-red-400" ></ i >< span > Banned IPs</ span ></ a >
< a data-target = "section-builds" class = "settings-nav-link" data-permission = "clients:build" style = "--accent: 251 146 60" >< i class = "fa-solid fa-hammer w-4 text-orange-400" ></ i >< span > Build IDs</ span ></ a >
< a data-target = "wipe-offline-section" class = "settings-nav-link" data-permission = "clients:control" style = "--accent: 248 113 113" >< i class = "fa-solid fa-circle-minus w-4 text-red-400" ></ i >< span > Wipe Offline Clients</ span ></ a >
2026-04-29 00:22:37 -05:00
2026-05-19 00:46:30 -05:00
< span class = "settings-nav-group-label" > Admin</ span >
2026-06-04 19:44:36 -05:00
< a data-target = "section-permissions-overview" class = "settings-nav-link" data-permission = "users:manage" style = "--accent: 167 139 250" >< i class = "fa-solid fa-user-shield w-4 text-violet-400" ></ i >< span > Access Overview</ span ></ a >
< a data-target = "section-security" class = "settings-nav-link" data-permission = "system:security" style = "--accent: 129 140 248" >< i class = "fa-solid fa-shield-halved w-4 text-indigo-400" ></ i >< span > Security Policy</ span ></ a >
< a data-target = "section-tls" class = "settings-nav-link" data-permission = "system:tls" style = "--accent: 34 211 238" >< i class = "fa-solid fa-certificate w-4 text-cyan-400" ></ i >< span > TLS Certificates</ span ></ a >
< a data-target = "chat-settings-section" class = "settings-nav-link" data-permission = "system:chat" style = "--accent: 56 189 248" >< i class = "fa-solid fa-comments w-4 text-sky-400" ></ i >< span > Team Chat</ span ></ a >
< a data-target = "registration-section" class = "settings-nav-link" data-permission = "system:registration" style = "--accent: 52 211 153" >< i class = "fa-solid fa-user-plus w-4 text-emerald-400" ></ i >< span > Registration</ span ></ a >
< a data-target = "thumbnails-section" class = "settings-nav-link" data-permission = "system:thumbnails" style = "--accent: 56 189 248" >< i class = "fa-solid fa-images w-4 text-sky-400" ></ i >< span > Screenshot Thumbnails</ span ></ a >
< a data-target = "build-rate-limit-section" class = "settings-nav-link" data-permission = "system:build-limits" style = "--accent: 251 146 60" >< i class = "fa-solid fa-gauge-high w-4 text-orange-400" ></ i >< span > Build Rate Limit</ span ></ a >
< a data-target = "section-appearance" class = "settings-nav-link" data-permission = "system:appearance" style = "--accent: 232 121 249" >< i class = "fa-solid fa-paintbrush w-4 text-fuchsia-400" ></ i >< span > Custom CSS</ span ></ a >
< a data-target = "export-import-section" class = "settings-nav-link" data-permission = "system:export-import" style = "--accent: 251 191 36" >< i class = "fa-solid fa-file-export w-4 text-amber-400" ></ i >< span > Export / Import</ span ></ a >
< a data-target = "section-health" class = "settings-nav-link" data-permission = "system:health" style = "--accent: 34 211 238" >< i class = "fa-solid fa-heart-pulse w-4 text-cyan-400" ></ i >< span > Server Health</ span ></ a >
2026-04-29 00:22:37 -05:00
</ nav >
</ aside >
<!-- Sections -->
< div class = "flex-1 min-w-0 space-y-6" >
<!-- ========== PERSONAL ========== -->
<!-- Account -->
< section id = "section-account" class = "bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
2026-03-24 20:42:54 -05:00
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-sky-500/10 border border-sky-500/30" >
2026-04-29 00:22:37 -05:00
< i class = "fa-solid fa-user text-sky-400" ></ i >
2026-03-24 20:42:54 -05:00
</ div >
< div >
2026-04-29 00:22:37 -05:00
< h2 class = "text-lg font-semibold" > Account</ h2 >
< p class = "text-sm text-slate-400" > View your account info and update your password.</ p >
2026-03-25 10:18:22 -05:00
</ div >
</ div >
2026-04-29 00:22:37 -05:00
< div class = "grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm" >
< div class = "rounded-lg bg-slate-900 border border-slate-800 px-3 py-2" >
< div class = "text-slate-400" > Username</ div >
< div id = "settings-username" class = "font-medium" > -</ div >
</ div >
< div class = "rounded-lg bg-slate-900 border border-slate-800 px-3 py-2" >
< div class = "text-slate-400" > Role</ div >
< div id = "settings-role" class = "font-medium" > -</ div >
</ div >
</ div >
< form id = "password-form" class = "space-y-3 mt-2 pt-4 border-t border-slate-800" >
< p class = "text-xs font-semibold uppercase tracking-wider text-slate-500 pb-1" > Change Password</ p >
< input
id = "current-password"
type = "password"
autocomplete = "current-password"
placeholder = "Current password"
class = "w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
required
/>
< input
id = "new-password"
type = "password"
autocomplete = "new-password"
minlength = "6"
placeholder = "New password (min 6 chars)"
class = "w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
required
/>
< input
id = "confirm-password"
type = "password"
autocomplete = "new-password"
minlength = "6"
placeholder = "Confirm new password"
class = "w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
required
/>
< div class = "pt-1" >
< p id = "password-policy-hint" class = "text-xs text-slate-400 mb-3" ></ p >
2026-03-25 10:18:22 -05:00
</ div >
< button
2026-04-29 00:22:37 -05:00
type = "submit"
class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-sky-600 hover:bg-sky-500 transition-colors text-white text-sm font-medium"
2026-03-25 10:18:22 -05:00
>
2026-04-29 00:22:37 -05:00
< i class = "fa-solid fa-key" ></ i > Update Password
2026-03-25 10:18:22 -05:00
</ button >
2026-04-29 00:22:37 -05:00
</ form >
2026-03-25 10:18:22 -05:00
2026-06-01 16:37:23 -05:00
< div id = "mfa-settings" class = "space-y-3 mt-2 pt-4 border-t border-slate-800" >
< div class = "flex items-center justify-between gap-3 flex-wrap" >
< div >
< p class = "text-xs font-semibold uppercase tracking-wider text-slate-500 pb-1" > Multi-Factor Authentication</ p >
< p id = "mfa-status-text" class = "text-sm text-slate-400" > Loading MFA status...</ p >
</ div >
< button
id = "mfa-start-btn"
type = "button"
class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-emerald-700 hover:bg-emerald-600 transition-colors text-white text-sm font-medium"
>
< i class = "fa-solid fa-shield-halved" ></ i > Set Up MFA
</ button >
</ div >
< div id = "mfa-setup-panel" class = "hidden rounded-lg border border-slate-700 bg-slate-900 px-4 py-4 space-y-4" >
< p class = "text-sm text-slate-300 pb-1" > Add this manual key to your authenticator app, then enter the 6-digit code.</ p >
< div class = "grid grid-cols-1 md:grid-cols-[20rem_minmax(0,1fr)] gap-5 items-start" >
< div class = "w-80 max-w-full" >
< div id = "mfa-qr-code" class = "aspect-square w-full rounded-lg bg-white p-1 border border-slate-700 overflow-hidden" ></ div >
</ div >
< div class = "min-w-0 space-y-3" >
< p class = "text-xs font-semibold uppercase tracking-wider text-slate-500" > Manual Key</ p >
< div class = "rounded bg-slate-950 border border-slate-800 px-3 py-2 font-mono text-sm text-sky-300 break-all" id = "mfa-secret-text" ></ div >
< input
id = "mfa-enable-code"
type = "text"
inputmode = "numeric"
maxlength = "6"
placeholder = "6-digit code"
class = "w-full px-3 py-2 rounded-lg bg-slate-950 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-emerald-500"
/>
< div class = "flex gap-2 flex-wrap" >
< button id = "mfa-enable-btn" type = "button" class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-emerald-700 hover:bg-emerald-600 transition-colors text-white text-sm font-medium" >
< i class = "fa-solid fa-check" ></ i > Enable MFA
</ button >
< a id = "mfa-otpauth-link" href = "#" class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-sm transition-colors" >
< i class = "fa-solid fa-mobile-screen" ></ i > Open App Link
</ a >
</ div >
</ div >
</ div >
</ div >
< div id = "mfa-disable-panel" class = "hidden rounded-lg border border-slate-700 bg-slate-900 px-4 py-4 space-y-3" >
< div class = "grid grid-cols-1 sm:grid-cols-2 gap-3" >
< input
id = "mfa-disable-password"
type = "password"
autocomplete = "current-password"
placeholder = "Current password"
class = "w-full px-3 py-2 rounded-lg bg-slate-950 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-rose-500"
/>
< input
id = "mfa-disable-code"
type = "text"
inputmode = "numeric"
maxlength = "6"
placeholder = "6-digit code"
class = "w-full px-3 py-2 rounded-lg bg-slate-950 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-rose-500"
/>
</ div >
< button id = "mfa-disable-btn" type = "button" class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-rose-800/70 hover:bg-rose-700 transition-colors text-rose-100 border border-rose-700 text-sm font-medium" >
< i class = "fa-solid fa-lock-open" ></ i > Disable MFA
</ button >
</ div >
< p id = "mfa-message" class = "hidden text-sm rounded-lg px-3 py-2 border" ></ p >
</ div >
2026-04-29 00:22:37 -05:00
< p id = "settings-message" class = "hidden text-sm rounded-lg px-3 py-2 border" ></ p >
2026-03-06 20:50:02 -06:00
</ section >
2026-04-13 17:15:06 -05:00
<!-- Active Sessions -->
2026-04-29 00:22:37 -05:00
< section id = "section-sessions" class = "bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
2026-04-13 17:15:06 -05:00
< div class = "flex items-center justify-between gap-3" >
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-emerald-500/10 border border-emerald-500/30" >
< i class = "fa-solid fa-desktop text-emerald-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > Active Sessions</ h2 >
< p class = "text-sm text-slate-400" > View and manage your active login sessions.</ p >
</ div >
</ div >
< button
id = "refresh-sessions-btn"
class = "inline-flex items-center gap-2 px-3 py-2 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-sm transition-colors"
type = "button"
>
< i class = "fa-solid fa-rotate" ></ i > Refresh
</ button >
2026-04-14 10:23:59 -05:00
< button
id = "remove-inactive-sessions-btn"
class = "inline-flex items-center gap-2 px-3 py-2 rounded-lg bg-red-900/40 hover:bg-red-800/60 text-red-100 border border-red-700/60 text-sm transition-colors"
type = "button"
>
< i class = "fa-solid fa-broom" ></ i > Remove Inactive
</ button >
2026-04-13 17:15:06 -05:00
</ div >
< div class = "overflow-x-auto border border-slate-800 rounded-lg" >
< table class = "w-full text-sm" >
< thead class = "bg-slate-800/60 text-slate-300" >
< tr >
< th class = "text-left px-3 py-2" > IP</ th >
< th class = "text-left px-3 py-2" > Browser / Client</ th >
< th class = "text-left px-3 py-2" > Created</ th >
< th class = "text-left px-3 py-2" > Last Active</ th >
< th class = "text-left px-3 py-2" > Status</ th >
< th class = "text-right px-3 py-2" > Action</ th >
</ tr >
</ thead >
< tbody id = "sessions-table-body" class = "divide-y divide-slate-800" >
< tr >
< td colspan = "6" class = "px-3 py-6 text-center text-slate-400" > Loading...</ td >
</ tr >
</ tbody >
</ table >
</ div >
< p id = "sessions-message" class = "hidden text-sm rounded-lg px-3 py-2 border" ></ p >
</ section >
2026-03-24 20:42:54 -05:00
2026-04-05 21:39:22 -05:00
<!-- Dashboard Preferences -->
2026-04-29 00:22:37 -05:00
< section id = "section-prefs" class = "bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
2026-04-05 21:39:22 -05:00
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-violet-500/10 border border-violet-500/30" >
< i class = "fa-solid fa-sliders text-violet-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > Dashboard Preferences</ h2 >
< p class = "text-sm text-slate-400" > Configure notifications, client refresh rate, and navigation layout.</ p >
</ div >
</ div >
2026-03-06 20:50:02 -06:00
2026-04-05 21:39:22 -05:00
< form id = "prefs-form" class = "space-y-4" >
< div class = "grid grid-cols-1 sm:grid-cols-2 gap-4" >
< div class = "space-y-2" >
< p class = "text-xs font-semibold uppercase tracking-wider text-slate-500" > Notifications</ p >
< label class = "flex items-center gap-2 text-sm" >
< input id = "pref-notifications" type = "checkbox" class = "h-4 w-4" />
< span > Enable notification badge updates</ span >
</ label >
< label class = "flex items-center gap-2 text-sm" >
< input id = "pref-desktop-notifications" type = "checkbox" class = "h-4 w-4 accent-emerald-500" />
< span > Enable desktop (OS) notifications</ span >
</ label >
< p id = "pref-desktop-notifications-hint" class = "hidden text-xs text-amber-400" >
< i class = "fa-solid fa-triangle-exclamation mr-1" ></ i >
Browser permission was denied. Reset notification permissions for this site in your browser settings, then try again.
</ p >
</ div >
< div class = "space-y-2" >
< p class = "text-xs font-semibold uppercase tracking-wider text-slate-500" > Refresh Interval</ p >
< label class = "block" >
< span class = "text-sm text-slate-300" > Client refresh interval (seconds)</ span >
< input
id = "pref-refresh-seconds"
type = "number"
min = "3"
max = "120"
class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</ label >
</ div >
</ div >
< div >
< p class = "text-xs font-semibold uppercase tracking-wider text-slate-500 mb-2" > Navigation Layout</ p >
< div class = "flex gap-2" >
< button type = "button" id = "pref-nav-sidebar"
class = "nav-layout-btn flex-1 flex items-center justify-center gap-2 px-3 py-2 rounded-lg border text-sm font-medium transition-colors" >
< i class = "fa-solid fa-table-columns" ></ i > Sidebar
</ button >
< button type = "button" id = "pref-nav-topbar"
class = "nav-layout-btn flex-1 flex items-center justify-center gap-2 px-3 py-2 rounded-lg border text-sm font-medium transition-colors" >
< i class = "fa-solid fa-bars" ></ i > Top Bar
</ button >
</ div >
< p class = "text-xs text-slate-500 mt-1" > Changes apply immediately on save.</ p >
</ div >
2026-04-17 18:43:16 -05:00
< div class = "space-y-2" >
< p class = "text-xs font-semibold uppercase tracking-wider text-slate-500" > Visibility</ p >
< label class = "flex items-center gap-2 text-sm" >
< input id = "pref-nav-hidden" type = "checkbox" class = "h-4 w-4 accent-indigo-500" />
< span > Hide navigation bar</ span >
</ label >
< p class = "text-xs text-slate-500" > Press < kbd class = "px-1 py-0.5 rounded bg-slate-800 border border-slate-700 text-slate-400 text-[10px]" > Ctrl+\</ kbd > to toggle anytime.</ p >
</ div >
2026-04-05 21:39:22 -05:00
< button
type = "submit"
class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-violet-700 hover:bg-violet-600 transition-colors text-white text-sm font-medium"
>
< i class = "fa-solid fa-floppy-disk" ></ i > Save Preferences
</ button >
</ form >
</ section >
<!-- Notification Delivery -->
2026-04-29 00:22:37 -05:00
< section id = "telegram-settings" class = "bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
2026-04-05 21:39:22 -05:00
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-emerald-500/10 border border-emerald-500/30" >
< i class = "fa-solid fa-bell text-emerald-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > Notification Delivery</ h2 >
< p class = "text-sm text-slate-400" > Configure where alerts and notifications are sent.</ p >
</ div >
</ div >
< div class = "rounded-lg border border-slate-700 bg-slate-900 px-4 py-4" >
< p class = "text-sm text-slate-300" >
Webhook and Telegram Bot settings have moved to the
< a href = "/notifications" class = "text-sky-400 hover:underline font-medium" > Notifications page</ a > .
Configure your personal webhook and Telegram bot there.
</ p >
</ div >
</ section >
2026-04-29 00:22:37 -05:00
<!-- News & Updates -->
< section id = "section-news" class = "bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-sky-500/10 border border-sky-500/30" >
< i class = "fa-brands fa-telegram text-sky-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > News & Updates</ h2 >
< p class = "text-sm text-slate-400" > Stay up to date with the newest features, releases, and announcements.</ p >
</ div >
</ div >
< div class = "rounded-lg border border-slate-700 bg-slate-900 px-4 py-4 flex flex-col sm:flex-row sm:items-center gap-4" >
< div class = "flex-1" >
< p class = "text-sm text-slate-300" >
Follow the official Overlord Telegram channel for the latest updates, changelogs, and feature announcements.
</ p >
< p class = "text-xs text-slate-500 mt-1" > Channel: < span class = "text-slate-400 font-mono" > @kunta</ span ></ p >
</ div >
< a
href = "https://t.me/kunta"
target = "_blank"
rel = "noopener noreferrer"
class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-sky-600 hover:bg-sky-500 transition-colors text-white text-sm font-medium whitespace-nowrap"
>
< i class = "fa-brands fa-telegram" ></ i >
Open on Telegram
</ a >
</ div >
</ section >
<!-- ========== OPERATIONS ========== -->
<!-- Banned IPs -->
2026-05-19 00:46:30 -05:00
< section id = "section-bans" data-permission = "network:manage-bans" class = "hidden bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
2026-04-29 00:22:37 -05:00
< div class = "flex items-center justify-between gap-3" >
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-red-500/10 border border-red-500/30" >
< i class = "fa-solid fa-ban text-red-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > Banned IPs</ h2 >
< p class = "text-sm text-slate-400" > Unban blocked agent source IPs.</ p >
</ div >
</ div >
< button
id = "refresh-bans-btn"
class = "inline-flex items-center gap-2 px-3 py-2 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-sm transition-colors"
type = "button"
>
< i class = "fa-solid fa-rotate" ></ i > Refresh
</ button >
</ div >
< div id = "bans-permission-note" class = "hidden rounded-lg border border-amber-800 bg-amber-900/20 text-amber-200 px-3 py-2 text-sm" >
Your role does not allow IP unban actions.
</ div >
< div class = "overflow-x-auto border border-slate-800 rounded-lg" >
< table class = "w-full text-sm" >
< thead class = "bg-slate-800/60 text-slate-300" >
< tr >
< th class = "text-left px-3 py-2" > IP</ th >
< th class = "text-left px-3 py-2" > Reason</ th >
< th class = "text-left px-3 py-2" > Banned At</ th >
< th class = "text-right px-3 py-2" > Action</ th >
</ tr >
</ thead >
< tbody id = "bans-table-body" class = "divide-y divide-slate-800" >
< tr >
< td colspan = "4" class = "px-3 py-6 text-center text-slate-400" > Loading...</ td >
</ tr >
</ tbody >
</ table >
</ div >
</ section >
<!-- Build IDs (operator/admin) -->
2026-05-19 00:46:30 -05:00
< section id = "section-builds" data-permission = "clients:build" class = "hidden bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
2026-04-29 00:22:37 -05:00
< div class = "flex items-center justify-between gap-3" >
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-orange-500/10 border border-orange-500/30" >
< i class = "fa-solid fa-hammer text-orange-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > Build IDs</ h2 >
< p class = "text-sm text-slate-400" > Review your builds, see how many agents have claimed each, and block a build to immediately disconnect any agent that connects with its tag.</ p >
</ div >
</ div >
< div class = "flex items-center gap-2" >
< label class = "hidden lg:flex items-center gap-2 text-xs text-slate-400" id = "builds-show-all-wrap" >
< input id = "builds-show-all" type = "checkbox" class = "h-3.5 w-3.5" />
< span > Show all users' builds</ span >
</ label >
< button
id = "refresh-builds-btn"
class = "inline-flex items-center gap-2 px-3 py-2 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-sm transition-colors"
type = "button"
>
< i class = "fa-solid fa-rotate" ></ i > Refresh
</ button >
</ div >
</ div >
< p class = "text-xs text-slate-500" >
< strong > Claim count</ strong > is the number of unique agent fingerprints that have ever connected using a build's tag. Each unique host produces one claim. A claim count higher than the number of machines you actually deployed to suggests the build tag may have leaked.
</ p >
< div class = "overflow-x-auto border border-slate-800 rounded-lg" >
< table class = "w-full text-sm" >
< thead class = "bg-slate-800/60 text-slate-300" >
< tr >
< th class = "text-left px-3 py-2" > Build ID</ th >
< th class = "text-left px-3 py-2" > Tag</ th >
< th class = "text-left px-3 py-2" > Status</ th >
< th class = "text-left px-3 py-2" > Created</ th >
< th class = "text-right px-3 py-2" > Claims</ th >
< th class = "text-right px-3 py-2" > Action</ th >
</ tr >
</ thead >
< tbody id = "builds-table-body" class = "divide-y divide-slate-800" >
< tr >
< td colspan = "6" class = "px-3 py-6 text-center text-slate-400" > Loading...</ td >
</ tr >
</ tbody >
</ table >
</ div >
< p id = "builds-message" class = "hidden text-sm rounded-lg px-3 py-2 border" ></ p >
</ section >
<!-- Wipe Offline Clients -->
2026-05-19 00:46:30 -05:00
< section id = "wipe-offline-section" data-permission = "clients:control" class = "hidden bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
2026-04-29 00:22:37 -05:00
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-red-500/10 border border-red-500/30" >
< i class = "fa-solid fa-circle-minus text-red-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > Wipe Offline Clients</ h2 >
< p class = "text-sm text-slate-400" > Permanently remove all offline clients from the dashboard in one click.</ p >
</ div >
</ div >
< div class = "rounded-lg border border-slate-700 bg-slate-900 px-4 py-4 flex flex-col sm:flex-row sm:items-center gap-4" >
< div class = "flex-1" >
< p class = "text-sm text-slate-300" >
Deletes every client currently marked as offline. If any of them reconnect later they will reappear automatically.
</ p >
</ div >
< button
id = "wipe-offline-btn"
type = "button"
class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-red-800/70 hover:bg-red-700 transition-colors text-red-100 border border-red-700 text-sm font-medium whitespace-nowrap"
>
< i class = "fa-solid fa-circle-minus" ></ i >
Wipe Offline
</ button >
</ div >
< p id = "wipe-offline-message" class = "hidden text-sm rounded-lg px-3 py-2 border" ></ p >
</ section >
<!-- ========== ADMIN ========== -->
2026-06-04 19:44:36 -05:00
<!-- Access Overview -->
< section id = "section-permissions-overview" data-permission = "users:manage" class = "hidden bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-violet-500/10 border border-violet-500/30" >
< i class = "fa-solid fa-user-shield text-violet-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > Access Overview</ h2 >
< p class = "text-sm text-slate-400" > Review your effective permissions and jump to user access management.</ p >
</ div >
</ div >
< div id = "settings-permissions-summary" class = "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3" ></ div >
< div class = "flex flex-wrap items-center gap-3" >
< a href = "/users" class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-violet-700 hover:bg-violet-600 text-white text-sm font-medium" >
< i class = "fa-solid fa-users-gear" ></ i > Manage Users
</ a >
< span class = "inline-flex items-center gap-2 max-w-full px-3 py-2 rounded-lg bg-slate-900/70 border border-slate-800 text-slate-300 text-sm" >
< i class = "fa-solid fa-desktop text-sky-400" ></ i >
< span class = "min-w-0 leading-snug" > Client access rules are edited from a selected user in Manage Users.</ span >
</ span >
</ div >
</ section >
< section id = "section-security" data-permission = "system:security" class = "hidden bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
2026-04-05 21:39:22 -05:00
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-indigo-500/10 border border-indigo-500/30" >
< i class = "fa-solid fa-shield-halved text-indigo-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > Security Policy</ h2 >
< p class = "text-sm text-slate-400" > Admin-only global security controls.</ p >
</ div >
</ div >
< form id = "security-form" class = "space-y-4" >
< div id = "security-permission-note" class = "hidden rounded-lg border border-amber-800 bg-amber-900/20 text-amber-200 px-3 py-2 text-sm" >
2026-06-04 19:44:36 -05:00
Your permissions do not allow security policy changes.
2026-04-05 21:39:22 -05:00
</ div >
< div class = "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3" >
< label class = "block" >
< span class = "text-sm text-slate-300" > Session TTL (hours)</ span >
< input
id = "security-session-ttl"
type = "number"
min = "1"
max = "720"
class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</ label >
< label class = "block" >
< span class = "text-sm text-slate-300" > Max login attempts</ span >
< input
id = "security-login-max-attempts"
type = "number"
min = "1"
max = "50"
class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</ label >
< label class = "block" >
< span class = "text-sm text-slate-300" > Login window (minutes)</ span >
< input
id = "security-login-window"
type = "number"
min = "1"
max = "1440"
class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</ label >
< label class = "block" >
< span class = "text-sm text-slate-300" > Lockout duration (minutes)</ span >
< input
id = "security-lockout"
type = "number"
min = "1"
max = "1440"
class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</ label >
< label class = "block" >
< span class = "text-sm text-slate-300" > Minimum password length</ span >
< input
id = "security-password-min"
type = "number"
min = "6"
max = "128"
class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</ label >
</ div >
< div >
< p class = "text-xs font-semibold uppercase tracking-wider text-slate-500 mb-2" > Password Requirements</ p >
< div class = "grid grid-cols-2 sm:grid-cols-4 gap-2 text-sm" >
< label class = "flex items-center gap-2" >
< input id = "security-require-uppercase" type = "checkbox" class = "h-4 w-4" />
< span > Uppercase</ span >
</ label >
< label class = "flex items-center gap-2" >
< input id = "security-require-lowercase" type = "checkbox" class = "h-4 w-4" />
< span > Lowercase</ span >
</ label >
< label class = "flex items-center gap-2" >
< input id = "security-require-number" type = "checkbox" class = "h-4 w-4" />
< span > Number</ span >
</ label >
< label class = "flex items-center gap-2" >
< input id = "security-require-symbol" type = "checkbox" class = "h-4 w-4" />
< span > Symbol</ span >
</ label >
</ div >
</ div >
2026-06-01 16:37:23 -05:00
< div >
< p class = "text-xs font-semibold uppercase tracking-wider text-slate-500 mb-2" > MFA Enforcement</ p >
< div class = "grid grid-cols-1 sm:grid-cols-2 gap-2 text-sm" >
< label class = "flex items-start gap-2 rounded-lg border border-slate-700/60 bg-slate-900/40 p-3" >
< input id = "security-mfa-admins" type = "checkbox" class = "mt-1 h-4 w-4 accent-indigo-500" />
< span >
< span class = "block text-slate-200" > Require MFA for admins</ span >
< span class = "block text-xs text-slate-500" > Your admin account must have MFA enabled first.</ span >
</ span >
</ label >
< label class = "flex items-start gap-2 rounded-lg border border-slate-700/60 bg-slate-900/40 p-3" >
< input id = "security-mfa-non-admins" type = "checkbox" class = "mt-1 h-4 w-4 accent-indigo-500" />
< span >
< span class = "block text-slate-200" > Require MFA for non-admins</ span >
< span class = "block text-xs text-slate-500" > Applies to operator and viewer accounts.</ span >
</ span >
</ label >
</ div >
</ div >
2026-04-05 21:39:22 -05:00
< button
type = "submit"
id = "security-save-btn"
class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-indigo-700 hover:bg-indigo-600 transition-colors text-white text-sm font-medium"
>
< i class = "fa-solid fa-shield-halved" ></ i > Save Security Policy
</ button >
</ form >
</ section >
<!-- TLS Certificates -->
2026-06-04 19:44:36 -05:00
< section id = "section-tls" data-permission = "system:tls" class = "hidden bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
2026-04-05 21:39:22 -05:00
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-cyan-500/10 border border-cyan-500/30" >
< i class = "fa-solid fa-certificate text-cyan-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > TLS Certificates</ h2 >
< p class = "text-sm text-slate-400" > Admin-only TLS source configuration. Changes apply after server restart.</ p >
</ div >
</ div >
< form id = "tls-form" class = "space-y-4" >
< div id = "tls-permission-note" class = "hidden rounded-lg border border-amber-800 bg-amber-900/20 text-amber-200 px-3 py-2 text-sm" >
2026-06-04 19:44:36 -05:00
Your permissions do not allow TLS setting changes.
2026-04-05 21:39:22 -05:00
</ div >
< label class = "flex items-center gap-2 text-sm" >
< input id = "tls-certbot-enabled" type = "checkbox" class = "h-4 w-4" />
< span > Use certbot certificates in production runtime (NODE_ENV=production)</ span >
</ label >
< div class = "grid grid-cols-1 sm:grid-cols-2 gap-3" >
< label class = "block" >
< span class = "text-sm text-slate-300" > Let's Encrypt account email</ span >
< input
id = "tls-certbot-email"
type = "email"
placeholder = "admin@example.com"
class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</ label >
< label class = "block" >
< span class = "text-sm text-slate-300" > Certbot live base path</ span >
< input
id = "tls-certbot-live-path"
type = "text"
placeholder = "/etc/letsencrypt/live"
class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</ label >
< label class = "block" >
< span class = "text-sm text-slate-300" > Certbot domain folder</ span >
< input
id = "tls-certbot-domain"
type = "text"
placeholder = "example.com"
class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</ label >
< label class = "block" >
< span class = "text-sm text-slate-300" > Cert file name</ span >
< input
id = "tls-certbot-cert-file"
type = "text"
placeholder = "fullchain.pem"
class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</ label >
< label class = "block" >
< span class = "text-sm text-slate-300" > Key file name</ span >
< input
id = "tls-certbot-key-file"
type = "text"
placeholder = "privkey.pem"
class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</ label >
< label class = "block" >
< span class = "text-sm text-slate-300" > CA chain file name</ span >
< input
id = "tls-certbot-ca-file"
type = "text"
placeholder = "chain.pem"
class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</ label >
</ div >
< div class = "rounded-lg border border-slate-700 bg-slate-900 px-4 py-4 flex flex-col sm:flex-row sm:items-center gap-4" >
< div class = "flex-1" >
< p class = "text-sm text-slate-300" > One-click setup requirements: DNS for the domain must point to this server and inbound port 80 must be reachable.</ p >
</ div >
< button
type = "button"
id = "tls-certbot-auto-btn"
class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-emerald-700 hover:bg-emerald-600 transition-colors text-white text-sm font-medium whitespace-nowrap"
>
< i class = "fa-solid fa-wand-magic-sparkles" ></ i > Auto Setup Free SSL
</ button >
</ div >
< button
type = "submit"
id = "tls-save-btn"
class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-cyan-700 hover:bg-cyan-600 transition-colors text-white text-sm font-medium"
>
< i class = "fa-solid fa-certificate" ></ i > Save TLS Settings
</ button >
</ form >
</ section >
2026-04-14 21:56:18 -05:00
<!-- Team Chat -->
2026-06-04 19:44:36 -05:00
< section id = "chat-settings-section" data-permission = "system:chat" class = "hidden bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
2026-04-14 21:56:18 -05:00
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-sky-500/10 border border-sky-500/30" >
< i class = "fa-solid fa-comments text-sky-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > Team Chat</ h2 >
< p class = "text-sm text-slate-400" > Admin-only. Configure message retention for the team chat.</ p >
</ div >
</ div >
< form id = "chat-settings-form" class = "space-y-4" >
< label class = "block" >
< span class = "text-sm text-slate-300 font-medium" > Message Retention (days)</ span >
< input
type = "number"
id = "chat-retention-days"
min = "0"
max = "365"
step = "1"
class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500 text-sm"
/>
< p class = "text-xs text-slate-500 mt-1" > Messages older than this will be automatically deleted. Set to 0 to keep messages forever. Max 365 days.</ p >
</ label >
< button
type = "submit"
id = "chat-settings-save-btn"
class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-sky-700 hover:bg-sky-600 transition-colors text-white text-sm font-medium"
>
< i class = "fa-solid fa-floppy-disk" ></ i > Save Chat Settings
</ button >
</ form >
</ section >
2026-04-19 18:24:50 -05:00
<!-- Registration Settings (admin only) -->
2026-06-04 19:44:36 -05:00
< section id = "registration-section" data-permission = "system:registration" class = "hidden bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
2026-04-19 18:24:50 -05:00
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-emerald-500/10 border border-emerald-500/30" >
< i class = "fa-solid fa-user-plus text-emerald-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > Registration</ h2 >
< p class = "text-sm text-slate-400" > Admin-only. Control how new users can register.</ p >
</ div >
</ div >
< form id = "registration-form" class = "space-y-4" >
< div class = "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3" >
< label class = "block" >
< span class = "text-sm text-slate-300" > Registration Mode</ span >
< select id = "reg-mode" class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500" >
< option value = "off" > Off</ option >
< option value = "open" > Open</ option >
< option value = "key" > Key Required</ option >
< option value = "approval" > Approval Required</ option >
</ select >
</ label >
< label class = "block" >
< span class = "text-sm text-slate-300" > Default Role</ span >
< select id = "reg-default-role" class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500" >
< option value = "operator" > Operator</ option >
< option value = "viewer" > Viewer</ option >
</ select >
</ label >
< label class = "block" >
< span class = "text-sm text-slate-300" > Max Users (0 = unlimited)</ span >
< input id = "reg-max-users" type = "number" min = "0" max = "10000" class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500" />
</ label >
</ div >
2026-05-19 00:46:30 -05:00
< div >
< span class = "text-sm text-slate-300" > Default permission groups for new users</ span >
< p class = "text-xs text-slate-500 mb-2" > Newly registered users automatically join these groups. Manage groups on the < a href = "/users" class = "text-sky-400 hover:underline" > Users page</ a > .</ p >
< div id = "reg-default-groups-list" class = "space-y-1 max-h-40 overflow-y-auto border border-slate-700 rounded-lg p-2 bg-slate-900/50" >
< p class = "text-slate-500 text-sm" > Loading...</ p >
</ div >
</ div >
2026-04-19 18:24:50 -05:00
< button type = "submit" class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-emerald-700 hover:bg-emerald-600 transition-colors text-white text-sm font-medium" >
< i class = "fa-solid fa-floppy-disk" ></ i > Save Registration Settings
</ button >
</ form >
< p id = "reg-settings-msg" class = "hidden text-sm rounded-lg px-3 py-2 border" ></ p >
<!-- Key Management (visible when mode=key) -->
< div id = "reg-key-section" class = "hidden space-y-3 border-t border-slate-700 pt-4" >
< h3 class = "text-md font-semibold text-slate-200" > Registration Keys</ h3 >
< div class = "flex flex-wrap items-end gap-3" >
< label class = "block" >
< span class = "text-sm text-slate-300" > Count</ span >
< input id = "reg-key-count" type = "number" value = "1" min = "1" max = "100" class = "mt-1 w-24 px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500" />
</ label >
< label class = "block" >
< span class = "text-sm text-slate-300" > Label (optional)</ span >
< input id = "reg-key-label" type = "text" maxlength = "64" placeholder = "e.g. Batch 1" class = "mt-1 w-40 px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500" />
</ label >
< label class = "block" >
< span class = "text-sm text-slate-300" > Expires (hours, 0=never)</ span >
< input id = "reg-key-expires" type = "number" value = "0" min = "0" max = "8760" class = "mt-1 w-28 px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500" />
</ label >
< button id = "reg-key-generate-btn" type = "button" class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-emerald-700 hover:bg-emerald-600 transition-colors text-white text-sm font-medium" >
< i class = "fa-solid fa-plus" ></ i > Generate
</ button >
< a id = "reg-key-export-btn" href = "/api/registration/keys/export" class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-slate-700 hover:bg-slate-600 transition-colors text-white text-sm font-medium" >
< i class = "fa-solid fa-file-export" ></ i > Export
</ a >
</ div >
< div class = "overflow-x-auto" >
< table class = "w-full text-sm text-left text-slate-300" >
< thead class = "text-xs uppercase text-slate-500 border-b border-slate-700" >
< tr >
< th class = "px-3 py-2" > Key</ th >
< th class = "px-3 py-2" > Label</ th >
< th class = "px-3 py-2" > Status</ th >
< th class = "px-3 py-2" > Created</ th >
< th class = "px-3 py-2" > Expires</ th >
< th class = "px-3 py-2" ></ th >
</ tr >
</ thead >
< tbody id = "reg-keys-tbody" ></ tbody >
</ table >
</ div >
</ div >
<!-- Pending Registrations (visible when mode=approval) -->
< div id = "reg-pending-section" class = "hidden space-y-3 border-t border-slate-700 pt-4" >
< h3 class = "text-md font-semibold text-slate-200" > Pending Registrations</ h3 >
< div class = "overflow-x-auto" >
< table class = "w-full text-sm text-left text-slate-300" >
< thead class = "text-xs uppercase text-slate-500 border-b border-slate-700" >
< tr >
< th class = "px-3 py-2" > Username</ th >
< th class = "px-3 py-2" > Requested</ th >
< th class = "px-3 py-2" > Status</ th >
< th class = "px-3 py-2" > Actions</ th >
</ tr >
</ thead >
< tbody id = "reg-pending-tbody" ></ tbody >
</ table >
</ div >
< p id = "reg-pending-empty" class = "text-sm text-slate-500" > No pending registrations.</ p >
</ div >
</ section >
2026-06-04 19:44:36 -05:00
<!-- Screenshot Thumbnails -->
< section id = "thumbnails-section" data-permission = "system:thumbnails" class = "hidden bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
2026-05-17 22:02:23 -05:00
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-sky-500/10 border border-sky-500/30" >
< i class = "fa-solid fa-images text-sky-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > Screenshot Thumbnails</ h2 >
< p class = "text-sm text-slate-400" > Admin-only. Control automatic agent screenshot polling.</ p >
</ div >
</ div >
< div class = "text-xs text-slate-400 bg-slate-800/40 border border-slate-700/60 rounded-lg p-3" >
< p > Each visible card or tile triggers one screenshot request to its agent on a refresh interval. With many concurrent users or thousands of agents, this can add up. Turn either off to reduce load — manual screenshot commands still work either way.</ p >
</ div >
< form id = "thumbnails-form" class = "space-y-4" >
< label class = "flex items-start gap-3 p-3 rounded-lg border border-slate-700/60 bg-slate-900/40 hover:bg-slate-900/70 cursor-pointer transition-colors" >
< input id = "thumb-dashboard-enabled" type = "checkbox" class = "mt-1 h-4 w-4 accent-sky-500" />
< div >
< div class = "text-sm font-medium text-slate-100" > Dashboard live thumbnails</ div >
< div class = "text-xs text-slate-400" > Auto-refresh the thumbnail on each visible client card on the Clients dashboard (~15s per visible tile).</ div >
</ div >
</ label >
< label class = "flex items-start gap-3 p-3 rounded-lg border border-slate-700/60 bg-slate-900/40 hover:bg-slate-900/70 cursor-pointer transition-colors" >
< input id = "thumb-wall-enabled" type = "checkbox" class = "mt-1 h-4 w-4 accent-sky-500" />
< div >
< div class = "text-sm font-medium text-slate-100" > Screenshot Wall page</ div >
< div class = "text-xs text-slate-400" > Enable the < code class = "text-sky-300" > /screenshots</ code > page. When off, the page returns 403 and the nav link is hidden.</ div >
</ div >
</ label >
< button type = "submit" class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-sky-700 hover:bg-sky-600 transition-colors text-white text-sm font-medium" >
< i class = "fa-solid fa-floppy-disk" ></ i > Save
</ button >
</ form >
< p id = "thumbnails-msg" class = "hidden text-sm rounded-lg px-3 py-2 border" ></ p >
</ section >
2026-04-19 18:24:50 -05:00
<!-- Build Rate Limit (admin only) -->
2026-06-04 19:44:36 -05:00
< section id = "build-rate-limit-section" data-permission = "system:build-limits" class = "hidden bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
2026-04-19 18:24:50 -05:00
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-orange-500/10 border border-orange-500/30" >
< i class = "fa-solid fa-gauge-high text-orange-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > Build Rate Limit</ h2 >
< p class = "text-sm text-slate-400" > Admin-only. Prevent abuse by limiting build frequency.</ p >
</ div >
</ div >
< form id = "build-rate-limit-form" class = "space-y-4" >
< div class = "grid grid-cols-1 sm:grid-cols-3 gap-3" >
< label class = "block" >
< span class = "text-sm text-slate-300" > Max Builds per Hour (per user)</ span >
< input id = "brl-max-per-hour" type = "number" min = "1" max = "100" class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500" />
</ label >
< label class = "block" >
< span class = "text-sm text-slate-300" > Max Concurrent (per user)</ span >
< input id = "brl-max-concurrent-user" type = "number" min = "1" max = "10" class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500" />
</ label >
< label class = "block" >
< span class = "text-sm text-slate-300" > Global Max Concurrent</ span >
< input id = "brl-global-concurrent" type = "number" min = "1" max = "50" class = "mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500" />
</ label >
</ div >
< button type = "submit" class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-orange-700 hover:bg-orange-600 transition-colors text-white text-sm font-medium" >
< i class = "fa-solid fa-floppy-disk" ></ i > Save Rate Limit Settings
</ button >
</ form >
< p id = "brl-settings-msg" class = "hidden text-sm rounded-lg px-3 py-2 border" ></ p >
</ section >
2026-04-29 00:22:37 -05:00
<!-- Custom CSS -->
2026-06-04 19:44:36 -05:00
< section id = "section-appearance" data-permission = "system:appearance" class = "hidden bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
2026-04-29 00:22:37 -05:00
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-fuchsia-500/10 border border-fuchsia-500/30" >
< i class = "fa-solid fa-paintbrush text-fuchsia-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > Custom CSS</ h2 >
< p class = "text-sm text-slate-400" > Admin-only. Paste custom CSS to override the default theme across all pages.</ p >
</ div >
</ div >
< form id = "appearance-form" class = "space-y-4" >
< div id = "appearance-permission-note" class = "hidden rounded-lg border border-amber-800 bg-amber-900/20 text-amber-200 px-3 py-2 text-sm" >
2026-06-04 19:44:36 -05:00
Your permissions do not allow custom CSS changes.
2026-04-29 00:22:37 -05:00
</ div >
< label class = "block" >
< textarea
id = "appearance-custom-css"
rows = "12"
spellcheck = "false"
placeholder = "/* Paste your custom CSS here */ :root { --color-primary: #f59e0b; }"
class = "w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500 font-mono text-xs resize-y"
></ textarea >
< p class = "text-xs text-slate-500 mt-1" > Max 50 KB. Reload any open page after saving to see the new styles.</ p >
</ label >
< button
type = "submit"
id = "appearance-save-btn"
class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-fuchsia-700 hover:bg-fuchsia-600 transition-colors text-white text-sm font-medium"
>
< i class = "fa-solid fa-paintbrush" ></ i > Save Custom CSS
</ button >
</ form >
</ section >
<!-- Export & Import -->
2026-06-04 19:44:36 -05:00
< section id = "export-import-section" data-permission = "system:export-import" class = "hidden bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section" >
2026-04-29 00:22:37 -05:00
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-amber-500/10 border border-amber-500/30" >
< i class = "fa-solid fa-file-export text-amber-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > Export & Import Settings</ h2 >
< p class = "text-sm text-slate-400" > Backup or restore your Overlord configuration (notifications, security, TLS, appearance, auth tokens).</ p >
</ div >
</ div >
< div class = "rounded-lg border border-slate-700 bg-slate-900 px-4 py-4 flex flex-col sm:flex-row sm:items-center gap-4" >
< div class = "flex-1 space-y-1" >
< p class = "text-sm text-slate-300" >
< strong > Export</ strong > — Downloads a JSON file with all current settings and auth tokens.
</ p >
< p class = "text-xs text-slate-500" > Keep this file secure — it contains sensitive tokens.</ p >
</ div >
< button
id = "export-settings-btn"
type = "button"
class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-amber-600 hover:bg-amber-500 transition-colors text-white text-sm font-medium whitespace-nowrap"
>
< i class = "fa-solid fa-download" ></ i >
Export Settings
</ button >
</ div >
< div class = "rounded-lg border border-slate-700 bg-slate-900 px-4 py-4 flex flex-col sm:flex-row sm:items-center gap-4" >
< div class = "flex-1 space-y-1" >
< p class = "text-sm text-slate-300" >
< strong > Import</ strong > — Restore settings from a previously exported JSON file.
</ p >
< p class = "text-xs text-slate-500" > Auth token changes require a server restart. Environment variables will still take priority.</ p >
</ div >
< label
class = "inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-slate-700 hover:bg-slate-600 transition-colors text-white text-sm font-medium whitespace-nowrap cursor-pointer"
>
< i class = "fa-solid fa-upload" ></ i >
Import Settings
< input id = "import-settings-file" type = "file" accept = ".json,application/json" class = "hidden" />
</ label >
</ div >
< p id = "export-import-message" class = "hidden text-sm rounded-lg px-3 py-2 border" ></ p >
</ section >
2026-05-22 10:49:29 -05:00
<!-- Server Health -->
2026-06-04 19:44:36 -05:00
< section id = "section-health" class = "bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section hidden" data-permission = "system:health" >
2026-05-22 10:49:29 -05:00
< div class = "flex items-center justify-between gap-3 flex-wrap" >
< div class = "flex items-center gap-3" >
< div class = "flex items-center justify-center w-9 h-9 rounded-lg bg-cyan-500/10 border border-cyan-500/30" >
< i class = "fa-solid fa-heart-pulse text-cyan-400" ></ i >
</ div >
< div >
< h2 class = "text-lg font-semibold" > Server Health</ h2 >
< p class = "text-sm text-slate-400" > Memory usage, per-component breakdown, and process stats.</ p >
</ div >
</ div >
< div class = "flex items-center gap-2" >
< button id = "health-gc-btn" type = "button"
class = "inline-flex items-center gap-2 px-3 py-2 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-sm transition-colors text-slate-300" >
< i class = "fa-solid fa-broom" ></ i > Force GC
</ button >
< button id = "health-refresh-btn" type = "button"
class = "inline-flex items-center gap-2 px-3 py-2 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-sm transition-colors text-slate-300" >
< i class = "fa-solid fa-rotate" ></ i > Refresh
</ button >
</ div >
</ div >
< div id = "health-loading" class = "text-slate-500 text-sm py-4 text-center" >
< i class = "fa-solid fa-spinner fa-spin mr-2" ></ i > Loading...
</ div >
< div id = "health-content" class = "hidden space-y-4" >
<!-- Summary cards -->
< div class = "grid grid-cols-2 sm:grid-cols-4 gap-3 text-sm" >
< div class = "rounded-lg bg-slate-900 border border-slate-800 px-3 py-2" >
< div class = "text-slate-400 text-xs mb-0.5" > Uptime</ div >
< div id = "health-uptime" class = "font-medium font-mono" > -</ div >
</ div >
< div class = "rounded-lg bg-slate-900 border border-slate-800 px-3 py-2" >
< div class = "text-slate-400 text-xs mb-0.5" > RSS (Total)</ div >
< div id = "health-rss" class = "font-medium font-mono" > -</ div >
</ div >
< div class = "rounded-lg bg-slate-900 border border-slate-800 px-3 py-2" >
< div class = "text-slate-400 text-xs mb-0.5" > Heap Used</ div >
< div id = "health-heap-used" class = "font-medium font-mono" > -</ div >
</ div >
< div class = "rounded-lg bg-slate-900 border border-slate-800 px-3 py-2" >
< div class = "text-slate-400 text-xs mb-0.5" > External / Buffers</ div >
< div id = "health-external" class = "font-medium font-mono" > -</ div >
</ div >
</ div >
<!-- Memory bar -->
< div >
< div class = "flex justify-between text-xs mb-1.5" >
< span class = "text-slate-400" > RSS memory breakdown</ span >
< span id = "health-bar-label" class = "font-mono text-slate-300" > -</ span >
</ div >
<!-- Stacked bar: heap | external/buffers | free -->
< div class = "h-5 rounded-lg bg-slate-700 overflow-hidden flex" style = "min-width:0" >
< div id = "health-heap-bar"
class = "h-full bg-sky-500 transition-all duration-700 flex items-center justify-center overflow-hidden"
style = "width:0%" title = "JS Heap" >
< span id = "health-heap-bar-label" class = "text-white text-[10px] font-mono font-semibold leading-none px-1 hidden" ></ span >
</ div >
< div id = "health-ext-bar"
class = "h-full bg-violet-500 transition-all duration-700"
style = "width:0%" title = "External / Buffers" ></ div >
</ div >
<!-- Legend -->
< div class = "flex items-center gap-4 mt-2 text-xs text-slate-400" >
< span class = "flex items-center gap-1.5" >< span class = "inline-block w-2.5 h-2.5 rounded-sm bg-sky-500" ></ span > Heap used</ span >
< span class = "flex items-center gap-1.5" >< span class = "inline-block w-2.5 h-2.5 rounded-sm bg-violet-500" ></ span > External / Buffers</ span >
< span class = "flex items-center gap-1.5" >< span class = "inline-block w-2.5 h-2.5 rounded-sm bg-slate-700" ></ span > Other (native, stack)</ span >
</ div >
</ div >
<!-- Component breakdown -->
< div >
< p class = "text-xs font-semibold uppercase tracking-wider text-slate-500 mb-2" > Components</ p >
< div class = "grid grid-cols-1 sm:grid-cols-3 gap-3" >
<!-- Thumbnails -->
< div class = "rounded-lg bg-slate-900 border border-slate-800 p-3 space-y-2" >
< div class = "flex items-center gap-2 text-sm font-medium text-slate-200" >
< i class = "fa-solid fa-images text-sky-400 text-xs w-3" ></ i > Thumbnail Cache
</ div >
< div class = "space-y-1 text-xs text-slate-400 font-mono" >
< div class = "flex justify-between" >< span > Cached</ span >< span id = "h-thumb-count" class = "text-slate-200" > -</ span ></ div >
< div class = "flex justify-between" >< span > Cache size</ span >< span id = "h-thumb-bytes" class = "text-slate-200" > -</ span ></ div >
< div class = "flex justify-between" >< span > Pending frames</ span >< span id = "h-thumb-frames" class = "text-slate-200" > -</ span ></ div >
< div class = "flex justify-between" >< span > Gen active / queued</ span >< span id = "h-thumb-gen" class = "text-slate-200" > -</ span ></ div >
< div class = "flex justify-between text-slate-500" >< span > Capacity</ span >< span id = "h-thumb-max" > -</ span ></ div >
</ div >
</ div >
<!-- Clients -->
< div class = "rounded-lg bg-slate-900 border border-slate-800 p-3 space-y-2" >
< div class = "flex items-center gap-2 text-sm font-medium text-slate-200" >
< i class = "fa-solid fa-users text-emerald-400 text-xs w-3" ></ i > Connected Clients
</ div >
< div class = "space-y-1 text-xs text-slate-400 font-mono" >
< div class = "flex justify-between" >< span > In memory</ span >< span id = "h-clients-mem" class = "text-slate-200" > -</ span ></ div >
< div class = "flex justify-between" >< span > Online (< 60s)</ span >< span id = "h-clients-online" class = "text-slate-200" > -</ span ></ div >
</ div >
</ div >
<!-- Database -->
< div class = "rounded-lg bg-slate-900 border border-slate-800 p-3 space-y-2" >
< div class = "flex items-center gap-2 text-sm font-medium text-slate-200" >
< i class = "fa-solid fa-database text-amber-400 text-xs w-3" ></ i > Database
</ div >
< div class = "space-y-1 text-xs text-slate-400 font-mono" >
< div class = "flex justify-between" >< span > File size</ span >< span id = "h-db-size" class = "text-slate-200" > -</ span ></ div >
</ div >
</ div >
</ div >
</ div >
2026-06-03 22:31:48 -05:00
<!-- Server profiler -->
< div class = "rounded-lg bg-slate-900 border border-slate-800 p-4 space-y-4" >
< div class = "flex items-center justify-between gap-3 flex-wrap" >
< div >
< p class = "text-xs font-semibold uppercase tracking-wider text-slate-500 mb-1" > Server Profiler</ p >
< p class = "text-sm text-slate-400" > Capture a short CPU sample and memory snapshot to find hot functions and heavy allocations.</ p >
</ div >
< div class = "flex items-center gap-2 flex-wrap" >
< select id = "server-profile-duration"
class = "px-3 py-2 rounded-lg bg-slate-950 border border-slate-700 text-sm text-slate-200 focus:outline-none focus:ring-2 focus:ring-cyan-500" >
< option value = "3000" > 3 seconds</ option >
< option value = "5000" selected > 5 seconds</ option >
< option value = "10000" > 10 seconds</ option >
< option value = "30000" > 30 seconds</ option >
</ select >
< button id = "server-profile-btn" type = "button"
class = "inline-flex items-center gap-2 px-3 py-2 rounded-lg bg-cyan-700 hover:bg-cyan-600 border border-cyan-600 text-sm transition-colors text-white" >
< i class = "fa-solid fa-gauge-high" ></ i > Run Profile
</ button >
< button id = "server-profile-download-btn" type = "button"
class = "hidden inline-flex items-center gap-2 px-3 py-2 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-sm transition-colors text-slate-300" >
< i class = "fa-solid fa-download" ></ i > CPU Profile
</ button >
</ div >
</ div >
< p id = "server-profile-message" class = "hidden text-xs rounded-lg px-3 py-2 border" ></ p >
< div id = "server-profile-results" class = "hidden space-y-4" >
< div class = "grid grid-cols-2 sm:grid-cols-4 gap-3 text-sm" >
< div class = "rounded-lg bg-slate-950 border border-slate-800 px-3 py-2" >
< div class = "text-slate-400 text-xs mb-0.5" > Captured</ div >
< div id = "profile-duration" class = "font-medium font-mono" > -</ div >
</ div >
< div class = "rounded-lg bg-slate-950 border border-slate-800 px-3 py-2" >
< div class = "text-slate-400 text-xs mb-0.5" > Process CPU</ div >
< div id = "profile-cpu-percent" class = "font-medium font-mono" > -</ div >
</ div >
< div class = "rounded-lg bg-slate-950 border border-slate-800 px-3 py-2" >
< div class = "text-slate-400 text-xs mb-0.5" > Samples</ div >
< div id = "profile-samples" class = "font-medium font-mono" > -</ div >
</ div >
< div class = "rounded-lg bg-slate-950 border border-slate-800 px-3 py-2" >
< div class = "text-slate-400 text-xs mb-0.5" > RSS Delta</ div >
< div id = "profile-rss-delta" class = "font-medium font-mono" > -</ div >
</ div >
</ div >
< div class = "grid grid-cols-1 xl:grid-cols-2 gap-4" >
< div class = "space-y-2" >
< p class = "text-xs font-semibold uppercase tracking-wider text-slate-500" > Hot Functions</ p >
< div class = "overflow-x-auto rounded-lg border border-slate-800" >
< table class = "min-w-full text-xs" >
< thead class = "bg-slate-950 text-slate-400" >
< tr >
< th class = "text-left px-3 py-2 font-medium" > Function</ th >
< th class = "text-right px-3 py-2 font-medium" > Self</ th >
< th class = "text-right px-3 py-2 font-medium" > Samples</ th >
</ tr >
</ thead >
< tbody id = "profile-functions-body" class = "divide-y divide-slate-800" ></ tbody >
</ table >
</ div >
</ div >
< div class = "space-y-2" >
< p class = "text-xs font-semibold uppercase tracking-wider text-slate-500" > Memory Object Types</ p >
< div class = "overflow-x-auto rounded-lg border border-slate-800" >
< table class = "min-w-full text-xs" >
< thead class = "bg-slate-950 text-slate-400" >
< tr >
< th class = "text-left px-3 py-2 font-medium" > Type</ th >
< th class = "text-right px-3 py-2 font-medium" > Count</ th >
</ tr >
</ thead >
< tbody id = "profile-objects-body" class = "divide-y divide-slate-800" ></ tbody >
</ table >
</ div >
</ div >
</ div >
< div class = "space-y-2" >
< p class = "text-xs font-semibold uppercase tracking-wider text-slate-500" > Hottest Stacks</ p >
< div id = "profile-stacks-list" class = "space-y-2" ></ div >
</ div >
</ div >
</ div >
2026-05-22 10:49:29 -05:00
< p id = "health-gc-message" class = "hidden text-xs rounded-lg px-3 py-2 border border-emerald-700 bg-emerald-900/20 text-emerald-300" ></ p >
</ div >
</ section >
2026-04-29 00:22:37 -05:00
</ div >
<!-- /Sections -->
</ div >
<!-- /flex wrapper -->
2026-04-13 13:49:41 -05:00
< footer class = "text-center text-sm text-slate-500 py-4 border-t border-slate-800 mt-4" >
< p > Created by KDot — < a href = "https://t.me/kunta" target = "_blank" rel = "noopener noreferrer" class = "text-sky-400 hover:text-sky-300 transition-colors" >< i class = "fa-brands fa-telegram" ></ i > t.me/kunta</ a ></ p >
</ footer >
2026-03-28 22:18:33 -05:00
</ main >
2026-03-06 20:50:02 -06:00
< script type = "module" src = "/assets/nav.js" ></ script >
< script type = "module" src = "/assets/settings.js" ></ script >
</ body >
</ html >