CS2 tags a command's output with the id of the empty end packet when both arrive together, and replies to the end packet with a bare \x00\x01. The client dropped the output as stale, so the panel reported WebPanelBridge as missing. Also log each new kind of poll failure once, and recovery. |
||
|---|---|---|
| internal | ||
| .gitignore | ||
| Containerfile | ||
| example.env | ||
| go.mod | ||
| go.sum | ||
| main.go | ||
| README.md | ||
| site.example.json | ||
simpleadmin-web
A SourceBans-style web panel for CS2-SimpleAdmin (built against 1.8.2b's MySQL schema).
- Public site (
/): the live server (name, map, players, team score and a scoreboard), bans, gags and mutes, and the staff list. Read-only. It never shows admin names, IP addresses or internal immunity values. - Staff panel (
/admin): sign in through Steam. Ban, gag, mute, silence, warn and kick; lift bans and blocks; manage ranks, permissions and staff; change server cvars and SimpleAdmin's punishment settings.
Live data comes from the WebPanelBridge plugin (plugins/WebPanelBridge in this repo) over
RCON. Without it the panel still works, but shows the server as offline and can't kick or warn.
How it works
-
Reading: straight from SimpleAdmin's MySQL tables (
sa_bans,sa_mutes,sa_warns,sa_admins,sa_groupsand their flag, unban and unmute tables,sa_players_ips). -
Penalties: sent over RCON as SimpleAdmin's own commands (
css_addban,css_addgag,css_unban,css_warn, …), so they take effect in game at once, with SimpleAdmin's usual announcements, Discord messages and IP handling. SimpleAdmin records console commands as "Console", so the panel then rewrites that row to credit the staff member who did it. -
Game server unreachable: bans and blocks are written to the database directly, the way SimpleAdmin writes them. They apply when the player next joins (bans are also picked up by SimpleAdmin within about a minute). Kicks and warnings need the server.
-
Ranks and staff: written to the database, then
css_reloadadmins. A rank is a SimpleAdmin group (#rank/mod); staff are admins holding exactly one such group. -
Permissions: commands sent over RCON run as Console, which skips all of SimpleAdmin's own checks, so the panel enforces them itself with the same flags:
Action Needs Use the panel @css/genericBan @css/ban; permanent or longer thanMaxBanDurationalso@css/permbanUnban @css/unbanGag, mute, silence, lift them @css/chat; permanent or longer thanMaxMuteDurationalso@css/permmuteKick, warn @css/kickSee IP addresses @css/showipChange map @css/changemapServer cvars @css/cvarRanks, staff, SimpleAdmin settings, reload admins @css/root@css/rootgrants everything. Nobody can act on a player whose immunity is higher than theirs, or on themselves, or give a rank with more immunity than their own.
Setup
- Install WebPanelBridge on the game server (see its README).
- Make sure RCON works:
rcon_passwordset, and the panel can reach the game port over TCP. SimpleAdmin stores the server's address and RCON password insa_servers, and the panel uses those unlessSAW_RCON_ADDR/SAW_RCON_PASSWORDare set. - Copy
example.envtosimpleadmin-web.envand fill it in.SAW_BASE_URLmust be the exact public address; Steam returns signed-in users there. - Put the panel behind HTTPS (a reverse proxy). Session cookies are marked Secure when
SAW_BASE_URLis https.
Run it with podman:
podman build -t simpleadmin-web .
podman run -d --name simpleadmin-web --env-file simpleadmin-web.env \
--user 1000:1000 \
-v /srv/cs2/game/csgo/addons/counterstrikesharp/configs/plugins/CS2-SimpleAdmin:/data:Z \
-p 127.0.0.1:8080:8080 simpleadmin-web
--user 1000:1000 matches the game container's user, which owns CS2-SimpleAdmin.json, so the
panel can edit it. Mount it with :ro instead to make those settings read-only. Changes to that
file apply the next time SimpleAdmin loads (a server restart). The panel keeps the previous
version as CS2-SimpleAdmin.json.bak. It writes keys in alphabetical order, so expect a reordered
file after the first save.
Or build and run it directly: go build && ./simpleadmin-web (Go 1.25, settings from the
environment).
Rank names and colours
SimpleAdmin groups have no display name or colour, so those come from a site config
(SAW_SITE_CONFIG, see site.example.json). The built-in defaults cover #rank/owner,
senioradmin, admin, trialadmin, mod, trialmod, helper and guardian. Ranks marked
"supporter": true are listed apart from staff and can't sign in unless they hold
@css/generic.
Limitations and caveats
- Tested against a real MySQL 8.4 with SimpleAdmin 1.8.2b's migrations applied, and a fake game
server that speaks Source RCON and imitates SimpleAdmin's console commands. Not yet tested
against a live CS2 server or live Steam sign-in. Things to check on first run: that RCON
returns WebPanelBridge's output (it prints through
Server.PrintToConsole, likecss version), and that the cvar values on the settings page read correctly. - In-game announcements for panel actions name "Console", because that's who SimpleAdmin sees. The database records the real staff member.
- Unban and lift act on the player:
css_unban <steamid>lifts every active ban on that SteamID, as it does in game. - Bans without a SteamID (IP-only bans from
css_banip) are listed but can only be lifted in game. - One server per panel. Set
SAW_SERVER_IDifsa_serverslists several. - Times are read in SimpleAdmin's
Timezone(UTC by default), matching how it writes them.
Development
go vet ./... && go test ./...
The pages are plain HTML, CSS and JS in internal/web/assets, embedded into the binary. The
design mockup they came from is in docs/mockup at the repo root.