Repository navigation
Releases: BitaceS/talepanel
Releases · BitaceS/talepanel
Release list
v0.11.0-beta
Off-site backups (OneDrive, Google Drive, Dropbox, S3, B2, SFTP, WebDAV), email setup in the panel, auto restart, CPU limits, and invitation roles that actually apply.
Security
- The raw console now enforces the same roles as the quick commands. Before, anyone with
server.consolecould typestop,opor any other command. Users may sendhelpandworld save, moderators alsokick,ban,unban,whitelist,time,weather,teleportandsay; everything else needs an admin. The server's own owner counts as admin on it. - Custom quick commands can no longer be saved with a lower
min_rolethan the console command they run, and running one checks the resolved command as well, which also covers commands saved before this fix. - Granting or removing op on the Players page needs admin. The route only required
player.ban, which moderators have. - Off-site backup destination credentials are AES-256-GCM encrypted with
TOTP_ENC_KEY, never returned to the browser, and redacted from the audit log. Only a per-provider allowlist of rclone options is accepted; the daemon additionally refuses options that run commands or read local files. rclone gets its credentials from a per-operation 0600 config file, never from its command line. - Accepting a server invitation ignored the invited role: the member fell back to their global role, so an invited viewer could start the server and use the console. Accepting now grants the role's per-server permissions (viewer: view; moderator: power, console, mods, players, backup.create, database.view; admin: everything but delete), capped to what the inviter holds. Creating an invitation for a role with more rights than the inviter has returns 403. Revoking an invitation is limited to the server in the URL.
- The CurseForge
api_keywas written to the audit log in plain text; it is redacted now.
Added
- Quick setup for beginners:
install.sh --quick(also the first menu entry, and the default when the script runs without a terminal) installs panel and game server on one machine with ansslip.iohostname and asks no questions. It prints ahttps://<host>/setuplink and a one-time setup code; the first admin account is created in the browser. Only the code's SHA-256 is stored (SETUP_CODE_HASHin the panel.env). POST /api/v1/setup/complete: creates the first owner with the setup code and signs it in. Works only while no account exists; concurrent attempts create exactly one owner.GET /health/setupreportssetup_code_required.- Setup wizard at
/setup: setup code, admin account, first Hytale server (optional). The login page sends visitors of a fresh install there. tale-cli node enroll: mints a node enrollment token without a user account. Migration 036 makesnode_enrollments.created_byoptional.- Off-site backups: admins add destinations under Backups → Destinations — OneDrive, Google Drive, Dropbox, S3-compatible (AWS, Wasabi, Cloudflare R2, other), Backblaze B2, SFTP and WebDAV/Nextcloud. The node uploads each backup with rclone to
<folder>/<server id>/<backup id>.zip. Per destination: keep a local copy or not, and keep the newest N uploads per server. For OneDrive/Google Drive/Dropbox the panel shows therclone authorizecommand to run on your own computer and takes the pasted token; the OneDrive drive is looked up automatically. Refreshed OAuth tokens are saved back. - Backups and schedules can target a destination. The backup list shows where each backup is stored and its upload status (waiting, uploading, uploaded, upload failed with rclone's error); failed uploads can be retried. Restore and download fetch a backup from the destination when the node has no copy. Deleting a backup deletes its off-site copy.
- "Test connection" for a destination writes and deletes a probe file and shows rclone's error text.
- Daemon routes
POST /servers/:id/backup/upload,/backup/remote-delete,POST /backup/downloadandPOST /rclone/test; admin API/admin/backup-destinations(CRUD,/providers,/:id/test),GET /backup-destinationsfor the picker,POST /backups/:id/uploadto retry. Migration 039. - The daemon image installs rclone 1.75.2 from downloads.rclone.org, checked against its SHA-256.
- Email (SMTP) for alerts can be set up under Admin → Integrations, with a test-email button. Settings are stored encrypted and take effect without a restart; the
SMTP_*env vars stay as fallback. New optionalSMTP_TLS_MODE(starttls,tls,none). - Auto restart: a crashed server is started again after 5 s, 10 s, 20 s, up to 60 s; after 3 crashes in 10 minutes the daemon gives up. No restart after a stop from the panel, exit code 0, or Hytale exit codes 8 and 11.
- CPU limit (% of one core, 0 = unlimited) is enforced with cgroup v2 where the daemon can write its cgroup. In the default Docker install it cannot; the daemon then logs a warning and writes a notice to the server console. Migration 038 resets the old default of 4 to 0.
- A server that exited with Hytale exit code 8 or 11 shows a notice with a Reinstall button (
POST /servers/:id/reinstall, needsserver.manage). Migration 037 stores the last exit code. - The server's network role (none, hub, gamemode) can be set in the server's Settings tab.
Changed
- MinIO is gone from the dev compose file,
setup-dev.shand.env.example. - A server that exits with code 0 without a stop from the panel (e.g.
stoptyped in the console) is marked stopped instead of crashed. - The "Storage" field of the backup and schedule forms (with its fake "S3 (MinIO)" option) is gone;
storagein the API is accepted for compatibility and always stored aslocal. Usedestination_id. - Backup downloads are streamed by the daemon instead of being read into memory first.
- The Backups page no longer offers "All Servers" (the API only lists one server's backups) and preselects the first server.
Fixed
- Email alerts on port 465 never sent (the notifier always tried STARTTLS), relays without a login failed because PLAIN auth was forced, and a send had no overall timeout.
- An empty CPU field was stored as 4, which as a percentage would have throttled the server to 4% of a core.
- Backups were never marked completed on a fresh database: the
backup_statusenum hadcomplete, the code writescompleted. Migration 039 adds the value.
v0.10.1-beta
Installer hotfix.
Fixed
- The installer failed while pulling images: MinIO removed
minio/minioandminio/mcfrom Docker Hub. MinIO was never used (backups stay on the node), so the panel stack no longer includes it. Upgrades remove the old MinIO containers; theminio_datavolume is kept.
v0.10.0-beta
Hytale 0.6 (Update 6) compatibility (verified against HytaleServer 0.6.8), Hytale account link, the network mod, and a full injection-hardening pass across API, daemon, web and installer.
Added
- Per-server launch flags in the panel (Settings → Launch Settings):
--accept-early-plugins,--allow-op,--disable-sentry. Allowlisted in the API and again in the daemon. Migration 033. - RAM limit editable in the panel (admins only, 512 MB up to the node's total).
GET /api/v1/hytale/versions: newest server build per patchline, read from maven.hytale.com. The create-server form now offers Release / Pre-release instead of a free-text version.- Network mod (
mods/talepanel-network): Hytale plugin with/play <gamemode>on hubs (signedreferToServerhandoff) and a referral gate onrequire_referralgamemodes. Builds againstcom.hypixel.hytale:Server:0.6.8. The config now lives at{server}/talepanel/network.jsoninstead of insidemods/, which Hytale mistook for an asset pack. - Hytale account link (Admin → Integrations → Hytale Account): sign in once with the OAuth device flow and each opted-in server start gets its own game session, so servers boot authenticated without
/auth login. Admins enable it per server (Settings → Launch Settings, migration 035), because every plugin on a server can read its session. The refresh token is stored encrypted and rotated safely; tokens reach the server via environment variables.
Changed
- Daemon sets
HYTALE_DISABLE_UPDATESand explains exit codes 8 (self-update staged) and 11 (data inside the launcher install folder). - Daemon provides a persistent machine-id so Hytale's encrypted auth store (
auth.enc) works in containers. - Dependencies: Go 1.26, gin 1.12, pgx 5.11; Rust 1.98 builder; Nuxt 4.5 (Pinia 3, VueUse 14,
@lucide/vue), Node 22. - CI: daemon passes
cargo clippy -D warningsagain (dead code removed); web runsnuxt typecheck(0 errors).
Fixed
- Whitelist toggle now sends
whitelist add/remove(Hytale 0.6 moved the whitelist to thehytale.server.joinpermission). - Kick no longer appends a reason, which Hytale rejects; the reason stays in the audit log.
- Default commands:
giveuses--quantity, weather usesZone1_Sunny --world {world}(there is noclearweather). Migration 032. - Default game commands were listed twice, and the global copy failed with "command not found".
- Invalid server settings return 400 instead of 500.
- Daemon logs reach stdout again: the bootstrap log subscriber blocked the configured one, so only errors were printed.
/playreports a gamemode as unavailable instead of throwing on a bad address or empty secret.
Security
- Game-command parameters containing control characters are rejected; a newline smuggled a second console command past
min_role. DELETE /servers/:id/game-commands/:cmdIdonly deletes that server's own commands. Before, it could delete any server's commands and the global defaults.- Game-command parameters other than
message/reasonmust be a single word without a leading--, so they cannot append arguments or flags. - Global built-in commands get the same
min_roleas the per-server defaults (they wereuser, so any console user could runstop/op/give). Migration 034. - Hytale game sessions are minted at most once per server every 10 s, and each mint is logged with the node.
- Game server processes no longer inherit the daemon's environment secrets (
TALEDAEMON_NODE_TOKENetc.), which any plugin could read. - The web panel keeps the access token in memory only (it was in
localStorage); a reload restores the session from the httpOnly refresh cookie. - The Hytale device-login link is only rendered if it is
https://. - Network handoff tickets use a per-server key derived from the master secret (mod config version 2). A gamemode's
network.jsonno longer holds a secret that is valid for every other gamemode. The hub still holds its gamemodes' keys, so give the hub role only to a trusted server. Upgrade: update the mod on all networked servers; the API rewrites their configs on start. --allow-opcan only be added or removed by admins.- Refresh tokens get a 30 s grace period after rotation, so parallel tabs or a reload during a refresh no longer log the user out.
Security — injection hardening
API:
- Alert webhooks:
- Must be https on port 443 and point to a public host.
- Calls go through a client that refuses private addresses after DNS (no rebinding), ignores proxies and never follows redirects.
- Webhook URLs are no longer logged.
- Alert rules are scoped:
- Non-admins can only create rules for servers they can view.
- Global and node-level rules (CPU/RAM/disk, node offline, DDoS) are admin-only.
- Events can only be resolved by their owner.
- Audit log:
- The client IP comes from the trusted proxy chain, not a raw header.
- NUL bytes and invalid UTF-8 are stripped, and secrets are redacted at any depth.
- A failed insert is retried instead of being dropped.
- Server migration is admin-only and checks that the target node is online and has room.
- Admins can no longer demote, disable or delete owners, and the last owner cannot be removed.
- Request bodies are limited per route: 1 MiB by default, with larger limits for daemon callbacks, file edits and mod uploads.
- Daemon client:
- URLs are built with proper escaping.
- Node addresses (fqdn, public address, port) are validated on register, enrollment and update.
- Download filenames are encoded safely.
- The client pool is now mutex-guarded (concurrent map access).
- Console commands containing any control character, including line breaks, are rejected for every caller.
- Game-command templates are substituted in a single pass. World names must match
[A-Za-z0-9_-]{1,64}. - Player names must match
[A-Za-z0-9_]{1,32}before they reach a console command (kick, ban, op, mute, network unban). - Mod install URLs must be https. Non-admins are limited to the CurseForge CDN.
- MariaDB databases:
- Names are derived from the server id (
tp_<hex>), so they cannot collide. - DDL values are checked strictly, and SQL text no longer appears in error messages.
- Names are derived from the server id (
- Log pushes are capped at 5000 lines and inserted in chunks.
Daemon:
- File operations:
- Every file operation stays inside the server directory and never follows a symlink planted by a tenant.
- Config writes are atomic.
- Commands are bound to
{servers_dir}/{server_id}.
- Mod downloads:
- Only public addresses on https/443.
- The address is pinned per hop, redirects are re-validated, and proxies are ignored.
- Downloads are capped at 512 MiB and streamed to a temp file.
- Archive extraction:
- Limited to 200k entries / 20 GiB.
- Symlinks are skipped.
- The downloader only extracts its own archive.
- Node token comparison is constant-time, and an empty token never matches.
- Console input with control characters is rejected.
- Offline Hytale binaries are copied per server instead of hardlinked, so one server cannot modify another server's jar.
- Plugin metadata parsing reads at most 64 KiB.
Web and installer:
- The panel sends CSP,
X-Frame-Options: DENY,nosniff, Referrer-Policy and Permissions-Policy on every page. - External links taken from CurseForge or GitHub data must be https.
- The device-login prompt only reads log lines written by the server during installation, so a chat message cannot inject a phishing link.
- The alerts page only offers rule types the user's role may create.
install.shandcommon.sh:- Domains, URLs, ports, UUIDs and tokens are validated.
- Env files are written without
sed. - JSON is built with
jq. - The login password goes over stdin instead of argv.