2026-05-01 13:10:23 +03:00
{{ define "admin/security.html" }}
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
< title > WarpBox Admin Security< / title >
< link rel = "icon" type = "image/png" href = "/static/WarpBoxLogo.png" >
< link rel = "stylesheet" href = "/static/css/app.css" >
< link rel = "stylesheet" href = "/static/css/window.css" >
< link rel = "stylesheet" href = "/static/css/components/buttons.css" >
< link rel = "stylesheet" href = "/static/css/components/toast.css" >
< link rel = "stylesheet" href = "/static/css/admin.css" >
< link rel = "stylesheet" href = "/static/css/security.css" >
< / head >
< body >
< div class = "admin-shell" >
< div class = "admin-frame" >
{{ template "admin/header.html" . }}
< div class = "win98-window admin-workspace-window" role = "main" >
< div class = "win98-titlebar" >
< div class = "win98-titlebar-label" >
< img class = "win98-titlebar-icon" src = "/static/WarpBoxLogo.png" alt = "" aria-hidden = "true" >
< h1 > WarpBox Security< / h1 >
< / div >
< div class = "win98-window-controls" aria-hidden = "true" >
< button class = "win98-control" type = "button" > _< / button >
< button class = "win98-control" type = "button" > □< / button >
< button class = "win98-control" type = "button" > x< / button >
< / div >
< / div >
< nav class = "menu-bar" aria-label = "Security toolbar" >
< div class = "menu-item" >
< button class = "menu-button" type = "button" aria-expanded = "false" > Security< / button >
< div class = "menu-popup" >
< button class = "menu-action" type = "button" data-command = "ban-ip" > < span > B< / span > < span > Ban IP now< / span > < span > < / span > < / button >
< button class = "menu-action" type = "button" data-command = "ban-until" > < span > T< / span > < span > Set ban expiration< / span > < span > < / span > < / button >
< button class = "menu-action" type = "button" data-command = "unban-ip" > < span > U< / span > < span > Unban selected IP< / span > < span > < / span > < / button >
2026-05-03 22:46:54 +03:00
< button class = "menu-action" type = "button" data-command = "bulk-unban" > < span > K< / span > < span > Bulk unban selected< / span > < span > < / span > < / button >
< button class = "menu-action" type = "button" data-command = "unban-all" > < span > A< / span > < span > Unban all< / span > < span > < / span > < / button >
2026-05-01 13:10:23 +03:00
< button class = "menu-action" type = "button" data-command = "refresh" > < span > R< / span > < span > Refresh data< / span > < span > F5< / span > < / button >
< / div >
< / div >
< / nav >
< div class = "admin-workspace-body security-page-body" >
< section class = "security-grid" >
< section class = "security-panel" >
2026-05-03 22:46:54 +03:00
< div class = "security-panel-header" > < strong > Manual controls< / strong > < span > admin actions< / span > < / div >
2026-05-01 13:10:23 +03:00
< div class = "security-panel-body" >
< label class = "security-field" > IP address
< input class = "security-input" id = "security-ip-input" type = "text" placeholder = "203.0.113.12" >
< / label >
< button class = "win98-button security-button" type = "button" data-command = "ban-ip" > Ban IP (temporary)< / button >
< label class = "security-field" > Ban expires (UTC)
< input class = "security-input" id = "security-ban-until" type = "datetime-local" >
< / label >
< button class = "win98-button security-button" type = "button" data-command = "ban-until" > Set ban expiration< / button >
< button class = "win98-button security-button" type = "button" data-command = "unban-ip" > Unban selected IP< / button >
2026-05-03 22:46:54 +03:00
< button class = "win98-button security-button" type = "button" data-command = "bulk-unban" > Bulk unban selected< / button >
< button class = "win98-button security-button security-danger" type = "button" data-command = "unban-all" > Unban all< / button >
< div class = "security-note" > Ban duration, whitelist rules and trusted proxies are managed in Settings - Security.< / div >
2026-05-01 13:10:23 +03:00
< / div >
< / section >
< section class = "security-panel" >
< div class = "security-panel-header" > < strong > Recent alerts< / strong > < span > {{ len .Alerts }} total< / span > < / div >
< div class = "security-panel-body" >
< ul class = "security-list" id = "security-alert-list" > < / ul >
< / div >
< / section >
< / section >
< section class = "security-panel" >
2026-05-03 22:46:54 +03:00
< div class = "security-panel-header" > < strong > Active bans< / strong > < span id = "security-bans-count" > {{ len .Bans }} active bans< / span > < / div >
2026-05-01 13:10:23 +03:00
< div class = "security-panel-body security-ban-grid" >
2026-05-03 22:46:54 +03:00
< div >
< div class = "security-table-toolbar" >
< input id = "security-ban-filter" class = "security-input" type = "text" placeholder = "Filter by IP" >
< select id = "security-ban-sort" class = "security-input" >
< option value = "expiry_asc" > Expiry ↑< / option >
< option value = "expiry_desc" > Expiry ↓< / option >
< option value = "ip_asc" > IP A-Z< / option >
< option value = "ip_desc" > IP Z-A< / option >
< / select >
< / div >
< div class = "security-table-wrap security-bans-wrap" >
< table class = "security-table" >
< thead >
< tr >
< th > < input id = "security-select-all" type = "checkbox" aria-label = "Select all" > < / th >
< th > IP< / th >
< th > Status< / th >
< th > Ban expires (UTC)< / th >
< / tr >
< / thead >
< tbody id = "security-bans-body" > < / tbody >
< / table >
< / div >
2026-05-01 13:10:23 +03:00
< / div >
< div class = "security-ip-detail" >
< h3 id = "security-detail-ip" > No IP selected< / h3 >
< ul >
< li > < strong > Risk:< / strong > < span id = "security-detail-risk" > -< / span > < / li >
< li > < strong > Threat:< / strong > < span id = "security-detail-threat" > -< / span > < / li >
2026-05-03 22:46:54 +03:00
< li > < strong > Geo:< / strong > < span id = "security-detail-geo" > GeoIP not enabled yet< / span > < / li >
< li > < strong > ASN:< / strong > < span id = "security-detail-asn" > GeoIP not enabled yet< / span > < / li >
2026-05-01 13:10:23 +03:00
< li > < strong > Ban until:< / strong > < span id = "security-detail-until" > -< / span > < / li >
2026-05-03 22:46:54 +03:00
< li > < strong > Why banned:< / strong > < span id = "security-detail-why" > -< / span > < / li >
< li > < button id = "security-copy-ip" class = "win98-button security-button" type = "button" > Copy IP< / button > < / li >
< li > < button id = "security-open-activity" class = "win98-button security-button" type = "button" > Search in activity< / button > < / li >
< li > < button id = "security-open-alerts" class = "win98-button security-button" type = "button" > Search in alerts< / button > < / li >
2026-05-01 13:10:23 +03:00
< / ul >
< / div >
< / div >
< / section >
< section class = "security-panel" >
< div class = "security-panel-header" > < strong > Recent security activity< / strong > < span > {{ len .Events }} rows< / span > < / div >
< div class = "security-panel-body" >
< div class = "security-table-wrap" >
< table class = "security-table" >
< thead >
< tr >
< th > Time< / th >
< th > Kind< / th >
< th > Severity< / th >
< th > IP< / th >
< th > Path< / th >
< th > Message< / th >
< / tr >
< / thead >
< tbody id = "security-activity-body" > < / tbody >
< / table >
< / div >
< / div >
< / section >
2026-05-03 22:46:54 +03:00
< section class = "security-panel" >
< div class = "security-panel-header" > < strong > Security Runbook< / strong > < span > ops quick reference< / span > < / div >
< div class = "security-panel-body security-docs" >
< h4 > Reverse Proxy and Trusted CIDRs< / h4 >
< p > Set < code > WARPBOX_TRUSTED_PROXY_CIDRS< / code > to the CIDRs of your proxy nodes only. WarpBox will trust forwarding headers only when the direct remote IP is in this list.< / p >
< pre > Caddyfile
:443 {
reverse_proxy 127.0.0.1:8080 {
header_up X-Forwarded-For {http.request.remote.host}
header_up X-Real-IP {http.request.remote.host}
}
}< / pre >
< h4 > Ban / Unban Safety< / h4 >
< p > Use custom ban durations only for active incidents. Prefer temporary bans. Review the "why banned" detail before unbanning to avoid immediate re-abuse.< / p >
< h4 > Tuning Guidance< / h4 >
< p > Low traffic: lower < code > security_*_max_attempts< / code > . High traffic: increase windows and attempt thresholds gradually, then monitor alerts/activity for false positives.< / p >
< h4 > GeoIP Guide (planned)< / h4 >
< p > For < code > geoip2fast< / code > , keep lookups async-safe with a single loaded database, add a short timeout per lookup, cache by IP with TTL, and degrade gracefully to "unknown" on failures. Start with security detail pane only, then aggregate stats later.< / p >
< / div >
< / section >
2026-05-01 13:10:23 +03:00
< / div >
< footer class = "status-bar admin-dashboard-statusbar" >
< span id = "security-status-left" > Security controls active< / span >
< span id = "security-status-middle" > alerts + activity linked< / span >
< span id = "security-status-right" > admin only< / span >
< / footer >
< / div >
< / div >
< / div >
< div class = "toast" id = "toast" role = "status" aria-live = "polite" > < / div >
< script id = "security-events-data" type = "application/json" > { { toJSON . Events } } < / script >
< script id = "security-alerts-data" type = "application/json" > { { toJSON . Alerts } } < / script >
< script id = "security-bans-data" type = "application/json" > { { toJSON . Bans } } < / script >
< script src = "/static/js/warpbox-ui.js" > < / script >
< script src = "/static/js/admin/security.js" > < / script >
< / body >
< / html >
{{ end }}