199 lines
12 KiB
Markdown
199 lines
12 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.
|
|
- **Verification** (optional): who our GroupVerify plugin verifies, with overrides to give and
|
|
remove, and its settings. Only appears when GroupVerify is installed (see below).
|
|
|
|
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` |
|
|
| Raw console commands (Server settings > Console; sent without waiting, output only logged) | `@css/rcon` |
|
|
| See the Staff & ranks page | `@zio/webpanel` |
|
|
| Give and remove verification overrides | `@zio/verify` (not on themselves, unless Root) |
|
|
| Ranks, staff, SimpleAdmin settings, reload admins, GroupVerify's group and on/off | `@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.
|
|
|
|
### Verification (GroupVerify, optional)
|
|
|
|
[GroupVerify](https://git.zio.sh/cs2/GroupVerify) (`plugins/GroupVerify` in the cs2 repo) verifies
|
|
players who are in the server's Steam group or have a manual override, and other plugins give
|
|
verified players perks. It keeps everything in SimpleAdmin's database (`gv_verified`,
|
|
`gv_settings`), so the panel needs no setup for it:
|
|
|
|
- **Staff** get a Verification page as soon as GroupVerify's tables are in the database: whether
|
|
it's on, the plugin's state and version, the Steam group, its saved member list, and the
|
|
overrides. The player drawer shows why a player is or isn't verified. With `@zio/verify` (give
|
|
it to the ranks that should have it in the rank editor), staff give overrides for a day up to a
|
|
year or with no expiry, change them and remove them. Root sets the group and turns verification
|
|
on and off.
|
|
- **Everyone** sees a "Verified" tag on the scoreboard and on player pages, but only while
|
|
verification is on (enabled, with a group set) and GroupVerify isn't missing from the server's
|
|
plugin list. The public site never shows why someone is verified, or who gave an override.
|
|
- **Clan tag**: Root can set the scoreboard tag verified players without a rank get (GroupVerify's
|
|
`clan_tag`, at most 12 characters). CS2-Tags (1.0.4c-zio6+) applies it, and gives unverified
|
|
players without a rank no tag at all. Blank turns it off.
|
|
- **Whether it's loaded** comes from `css_plugins list` over RCON, read once a minute alongside
|
|
the live status. While the server is down it's unknown, and that doesn't hide anything.
|
|
- **Changes**: overrides are written to `gv_verified` and GroupVerify picks them up on its next
|
|
reload (`db_reload_seconds`, 60 by default). Settings are written to `gv_settings` and, when
|
|
the plugin is loaded, also sent as its own `css_gv_group`/`css_gv_enable`/`css_gv_disable`, so
|
|
they apply at once.
|
|
- **Times** in its tables are in GroupVerify's own `timezone` setting, which the panel follows.
|
|
Keep it the same as SimpleAdmin's `Timezone`.
|
|
|
|
GroupVerify (0.3.0+) checks each player with the Steam Web API as they join, so "Confirmed group
|
|
members" is everyone Steam has said is in the group when they joined, not the group's full member
|
|
list. The panel never asks Steam itself.
|
|
|
|
### 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.
|
|
|
|
### Installing as an app
|
|
|
|
The site is a PWA, so Chrome on Android (and desktop Chrome or Edge) offers to install it: menu >
|
|
**Add to Home screen** / **Install app**. The public site and the staff panel install as separate
|
|
apps (`/manifest.webmanifest` opens on `/`, `/admin.webmanifest` on `/admin`); install the staff one
|
|
from the staff panel or its sign-in page. Installing needs the site on HTTPS. The service worker
|
|
(`assets/sw.js`, served at `/sw.js`) caches only an offline page, never data.
|
|
|
|
The icons are rendered from `assets/icon.svg` and `assets/icon-maskable.svg` (the brand mark kept
|
|
inside the maskable safe zone). After changing either:
|
|
|
|
```
|
|
cd internal/web/assets
|
|
rsvg-convert -w 192 -h 192 icon.svg -o icon-192.png
|
|
rsvg-convert -w 512 -h 512 icon.svg -o icon-512.png
|
|
rsvg-convert -w 512 -h 512 icon-maskable.svg -o icon-maskable-512.png
|
|
rsvg-convert -w 180 -h 180 icon-maskable.svg -o apple-touch-icon.png
|
|
```
|
|
|
|
## 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 ./...
|
|
```
|
|
|
|
`internal/web/verify_db_test.go` also runs the Verification endpoints against a real MySQL when
|
|
`SAW_TEST_DSN` is set. It empties SimpleAdmin's admin and group tables and GroupVerify's, so give
|
|
it a scratch database holding SimpleAdmin 1.8.2b's migrations and GroupVerify's
|
|
`Migrations/001_CreateTables.sql`:
|
|
|
|
```
|
|
podman run -d --rm --name sa-test -e MYSQL_ROOT_PASSWORD=test -e MYSQL_DATABASE=sa -p 127.0.0.1:33061:3306 mysql:8.4
|
|
# apply the migrations, then:
|
|
SAW_TEST_DSN='root:test@tcp(127.0.0.1:33061)/sa?parseTime=true&loc=UTC' go test ./internal/web -run VerifyDB
|
|
```
|
|
|
|
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.
|