simpleadmin-web/README.md
Astra dc7a1e42bd Offer the @zio/... flags in the rank editor
The rank editor only listed @css/... flags, so a @zio/ flag showed up only on a rank that
already held it and couldn't be added to others. List the flags admin_overrides.json uses, plus
@zio/penalties from our SimpleAdmin fork.
2026-09-29 17:58:27 +01:00

132 lines
7.4 KiB
Markdown

# simpleadmin-web
A SourceBans-style web panel for [CS2-SimpleAdmin](https://github.com/daffyyyy/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, the staff list and its rank changes (promotions, demotions, who made them).
Read-only. It never shows who issued a penalty, 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_groups` and 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. The rank editor offers the
`@css/...` flags and our `@zio/...` ones (from the server's `admin_overrides.json` and our
SimpleAdmin fork); a new `@zio/` flag needs adding to `knownFlags` in `internal/web/admin.go`.
- **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/generic` |
| Ban | `@css/ban`; permanent or longer than `MaxBanDuration` also `@css/permban` |
| Unban | `@css/unban` |
| Gag, mute, silence, lift them | `@css/chat`; permanent or longer than `MaxMuteDuration` also `@css/permmute` |
| Kick, warn | `@css/kick` |
| See IP addresses | `@css/showip` |
| Change map | `@css/changemap` |
| Server cvars | `@css/cvar` |
| Ranks, staff, SimpleAdmin settings, reload admins | `@css/root` |
`@css/root` grants 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
1. Install WebPanelBridge on the game server (see its README).
2. Make sure RCON works: `rcon_password` set, and the panel can reach the game port over TCP.
SimpleAdmin stores the server's address and RCON password in `sa_servers`, and the panel uses
those unless `SAW_RCON_ADDR` / `SAW_RCON_PASSWORD` are set.
3. Copy `example.env` to `simpleadmin-web.env` and fill it in. `SAW_BASE_URL` must be the exact
public address; Steam returns signed-in users there.
4. Put the panel behind HTTPS (a reverse proxy). Session cookies are marked Secure when
`SAW_BASE_URL` is 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` (VIPs) are listed apart from staff and don't count as staff online. Ranks
marked `"inactive": true` (Guardian: staff who are stepping back) are listed with the staff; they
only change how the rank log reads (see below). Nobody can sign in without `@css/generic`.
### Rank changes
Every change to a player's rank (their highest-immunity group) is recorded in `sa_rank_log` and
listed under the public Staff page: who, from which rank to which, who changed it and when. A
change is a promotion or demotion by the ranks' immunity, except for inactive ranks: moving
between an inactive rank and any other rank is a promotion either way, and losing an inactive rank
is a demotion. The
panel creates the table at startup (`sql/rank-log.sql`, embedded; run it by hand if the database
user can't create tables). It logs changes made in the panel (giving, moving or removing a rank,
and deleting a rank that people hold). Our SimpleAdmin fork (1.8.2b-zio10+) logs `css_addadmin`,
`css_deladmin` and the in-game admin menu to the same table, marked "in game". Not logged: ranks
that lapse when their expiry passes, `css_delgroup`, and edits made straight in the database.
History starts when the table is created.
### Name history (optional)
SimpleAdmin keeps one row per SteamID + IP in `sa_players_ips` and overwrites its name on each
connect, so a rename on the same IP loses the old name. `sql/players-ips-name-history.sql` adds
`name` to that table's primary key, so every name a SteamID has joined with is kept and shows up
on its player page and in name search. SimpleAdmin needs no changes. Run it once against the
SimpleAdmin database; the file has the revert. Names are still only recorded at connect.
## 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`, like `css 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_ID` if `sa_servers` lists 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.