2026-07-13 15:32:53 +03:00
<!doctype html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
< title > Steam Auth Admin</ title >
< link rel = "stylesheet" href = "/styles.css" >
</ head >
< body >
< header class = "topbar" >
< div class = "title" >
< h1 > Steam auth admin</ h1 >
< div class = "subline" >
< span id = "adminStatus" class = "badge badge-muted" > locked</ span >
< a class = "admin-link" href = "/" > Lobby list</ a >
</ div >
</ div >
< div class = "metrics" aria-label = "Auth status" >
< div class = "metric wide" >
< span class = "metric-label" > credentials</ span >
< strong id = "credentialsSource" > -</ strong >
</ div >
< div class = "metric wide" >
< span class = "metric-label" > refresh token</ span >
< strong id = "tokenStatus" > -</ strong >
</ div >
< div class = "metric wide" >
< span class = "metric-label" > steam</ span >
< strong id = "steamStatus" > -</ strong >
</ div >
< div class = "metric wide" >
< span class = "metric-label" > game coordinator</ span >
< strong id = "gcStatus" > -</ strong >
</ div >
</ div >
</ header >
< main class = "admin-main" >
< section id = "loginPanel" class = "auth-panel" >
< h2 > Admin password</ h2 >
< div class = "admin-grid" >
< label >
< span > password</ span >
< input id = "adminPassword" type = "password" autocomplete = "current-password" >
</ label >
< div class = "actions" >
< button id = "unlockBtn" class = "primary" type = "button" > Unlock</ button >
</ div >
</ div >
</ section >
< p id = "adminError" class = "error" hidden ></ p >
< p id = "adminMessage" class = "notice" hidden ></ p >
2026-08-06 20:33:27 +01:00
< section id = "notificationPanel" class = "auth-panel" hidden >
< h2 > Browser notifications</ h2 >
< p class = "panel-copy" > Push notifications work in the background. Production deployments must use HTTPS.</ p >
< div class = "actions left" >
< button id = "enableNotificationsBtn" class = "primary" type = "button" > Enable on this browser</ button >
< button id = "disableNotificationsBtn" type = "button" > Disable on this browser</ button >
< button id = "testNotificationBtn" type = "button" > Send test</ button >
< span id = "notificationStatus" class = "inline-status" > checking</ span >
</ div >
</ section >
< section id = "telegramPanel" class = "auth-panel" hidden >
< h2 > Telegram notifications</ h2 >
< p class = "panel-copy" > Create a bot with @BotFather. Each recipient must open the bot and send it a message before the bot can write to that numeric Telegram user ID. The token is stored only on the server and is never returned to this page.</ p >
< div class = "admin-grid" >
< label >
< span > bot token</ span >
< input id = "telegramToken" type = "password" autocomplete = "off" placeholder = "paste token or leave blank to keep saved token" >
</ label >
< label >
< span > Telegram user IDs, comma-separated</ span >
< input id = "telegramRecipientIds" type = "text" inputmode = "numeric" placeholder = "123456789, 987654321" >
</ label >
</ div >
< div class = "actions left panel-actions" >
< button id = "saveTelegramBtn" class = "primary" type = "button" > Save Telegram</ button >
< button id = "testTelegramBtn" type = "button" > Send test</ button >
< button id = "disableTelegramBtn" class = "danger" type = "button" > Disable Telegram</ button >
< span id = "telegramStatus" class = "inline-status" > not configured</ span >
</ div >
</ section >
< section id = "lobbyPanel" class = "auth-panel" hidden >
< h2 > Lobby automation</ h2 >
< p class = "panel-copy" > Player thresholds count real users only; the Steam bot itself is excluded. To avoid protocol-specific IDs, click < strong > Create template</ strong > on a lobby in the lobby list and this form will be prefilled after admin authorization.</ p >
< div class = "lobby-grid" >
< label >
< span > lobby name</ span >
< input id = "lobbyName" type = "text" maxlength = "100" placeholder = "Long queue lobby" >
</ label >
< label >
< span > region</ span >
< select id = "lobbyRegion" ></ select >
</ label >
< label >
< span > workshop ID</ span >
< input id = "customGameId" type = "text" inputmode = "numeric" placeholder = "1234567890" >
</ label >
< label >
< span > internal addon name</ span >
< input id = "customGameMode" type = "text" placeholder = "copied by Create template" >
</ label >
< label >
< span > map name</ span >
< input id = "customMapName" type = "text" placeholder = "map_name" >
</ label >
< label >
< span > lobby password</ span >
< input id = "lobbyPassKey" type = "text" autocomplete = "off" >
</ label >
< label >
< span > custom min players</ span >
< input id = "customMinPlayers" type = "number" min = "1" max = "64" >
</ label >
< label >
< span > custom max players</ span >
< input id = "customMaxPlayers" type = "number" min = "2" max = "64" >
</ label >
< label >
< span > notify at real players</ span >
< input id = "notifyAtPlayers" type = "number" min = "1" max = "64" >
</ label >
< label >
< span > bot leaves at real players</ span >
< input id = "leaveAtPlayers" type = "number" min = "1" max = "64" >
</ label >
< label class = "span-2" >
< span > admin persona names or SteamID64, comma-separated</ span >
< input id = "adminNames" type = "text" placeholder = "Alice, Bob, 7656119..." >
</ label >
< label >
< span > custom game CRC (optional)</ span >
< input id = "customGameCrc" type = "text" inputmode = "numeric" >
</ label >
< label >
< span > workshop timestamp (optional)</ span >
< input id = "customGameTimestamp" type = "text" inputmode = "numeric" >
</ label >
< label class = "check" >
< input id = "allowSpectating" type = "checkbox" checked >
< span > allow spectating</ span >
</ label >
</ div >
< div class = "actions left panel-actions" >
< button id = "saveLobbySettingsBtn" type = "button" > Save settings</ button >
< button id = "createLobbyBtn" class = "primary" type = "button" > Create lobby</ button >
< button id = "stopLobbyBtn" class = "danger" type = "button" > Leave lobby</ button >
</ div >
< dl class = "details lobby-details" >
< div >
< dt > automation</ dt >
< dd id = "automationPhase" > -</ dd >
</ div >
< div >
< dt > lobby ID</ dt >
< dd id = "activeLobbyId" > -</ dd >
</ div >
< div >
< dt > real players</ dt >
< dd id = "activePlayerCount" > 0</ dd >
</ div >
< div >
< dt > lobby browser / password</ dt >
< dd id = "publicationStatus" > -</ dd >
</ div >
< div >
< dt > arcade Play queue</ dt >
< dd id = "arcadePublicationStatus" > -</ dd >
</ div >
< div >
< dt > GC lobby flags</ dt >
< dd id = "lobbyProtocolStatus" > -</ dd >
</ div >
< div >
< dt > Dota client version</ dt >
< dd id = "dotaClientVersion" > -</ dd >
</ div >
< div >
< dt > leave reason</ dt >
< dd id = "leaveReason" > -</ dd >
</ div >
</ dl >
< div id = "lobbyMembers" class = "member-list muted" > No active lobby members.</ div >
</ section >
2026-07-13 15:32:53 +03:00
< section id = "credentialsPanel" class = "auth-panel" hidden >
< h2 > Steam credentials</ h2 >
2026-08-06 20:33:27 +01:00
< p class = "panel-copy" > Passwords, per-account refresh tokens, and Steam Guard machine authorization are stored on the server. Switching accounts reconnects Steam and Dota without restarting this process; leave an active lobby first.</ p >
2026-07-13 15:32:53 +03:00
< div class = "admin-grid" >
2026-08-06 20:33:27 +01:00
< label >
< span > saved accounts</ span >
< select id = "savedSteamAccount" ></ select >
</ label >
< div class = "actions" >
< button id = "activateAccountBtn" type = "button" > Activate selected</ button >
</ div >
2026-07-13 15:32:53 +03:00
< label >
< span > account</ span >
< input id = "steamAccount" type = "text" autocomplete = "username" >
</ label >
< label >
< span > password</ span >
2026-08-06 20:33:27 +01:00
< input id = "steamPassword" type = "password" autocomplete = "current-password" placeholder = "leave blank to keep the saved password" >
2026-07-13 15:32:53 +03:00
</ label >
< label class = "check" >
2026-08-06 20:33:27 +01:00
< input id = "clearToken" type = "checkbox" >
< span > forget cached refresh token for this account</ span >
2026-07-13 15:32:53 +03:00
</ label >
< div class = "actions" >
< button id = "reloadBtn" type = "button" > Reload</ button >
2026-08-06 20:33:27 +01:00
< button id = "saveBtn" class = "primary" type = "button" > Save and activate</ button >
2026-07-13 15:32:53 +03:00
</ div >
</ div >
</ section >
< section id = "guardPanel" class = "auth-panel" hidden >
< h2 > Steam Guard</ h2 >
< div class = "admin-grid" >
< label >
< span > code</ span >
< input id = "steamGuardCode" type = "text" autocomplete = "one-time-code" inputmode = "numeric" >
</ label >
< div class = "actions" >
< button id = "submitGuardBtn" class = "primary" type = "button" > Submit code</ button >
</ div >
</ div >
< p id = "guardHint" class = "hint" ></ p >
</ section >
< section id = "tokenPanel" class = "auth-panel" hidden >
< h2 > Saved token</ h2 >
< dl class = "details" >
< div >
< dt > SteamID</ dt >
< dd id = "tokenSteamId" > -</ dd >
</ div >
< div >
< dt > Account</ dt >
< dd id = "tokenAccount" > -</ dd >
</ div >
< div >
< dt > Updated</ dt >
< dd id = "tokenUpdated" > -</ dd >
</ div >
< div >
< dt > Expires</ dt >
< dd id = "tokenExpires" > -</ dd >
</ div >
</ dl >
< div class = "actions left" >
< button id = "clearTokenBtn" type = "button" > Clear refresh token</ button >
</ div >
</ section >
</ main >
< script src = "/admin.js" ></ script >
</ body >
</ html >