From 5521f4ea43765bb0543b2f7771f9cfe5c991269b Mon Sep 17 00:00:00 2001 From: Josh Wright Date: Mon, 5 Oct 2026 22:24:14 -0400 Subject: [PATCH] Authenticate T5 and T6 telemetry over HTTPS --- README.md | 31 +++++++++++++++++++++++++++++++ t5/README.md | 13 +++++++++---- t5/tws_telemetry.gsc | 18 +++++++++++++++++- t6/README.md | 27 +++++++++++++++++++-------- t6/tws_t6_telemetry.gsc | 18 +++++++++++++++++- 5 files changed, 93 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 0001ce1..b6e2ca3 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,37 @@ and telemetry still work. Open `.help` during a record page and check that the record resumes afterwards without overlapping it. Runtime linking and client readiness require Plutonium. +## Telemetry authentication (T5 and T6) + +Both reporters default to `https://ec.thewrightserver.net/api/telemetry` and send +`Authorization: Bearer ` plus `Content-Type: application/json` on every +POST. Existing event fields and queue behavior are unchanged. An explicit +`tws_telemetry_url` override must also use HTTPS; remove any old HTTP override. + +Before upgrading the API or loading these reporters: + +1. Set the Electric Cherry service's **environment variable** + `EC_TELEMETRY_TOKEN` to a separate shared secret of at least 32 characters. + A missing service token disables ingestion. +2. Both telemetry scripts embed the matching reporter secret in + `level.telemetry_token`. No game-server token dvar or private config is needed. +3. Keep `tws_server_id` set to the exact registered server name, then restart + the map. Both reporters refuse to start with a short embedded token or a + non-HTTPS URL. Rotating the service token requires editing the token in both + scripts, deploying them to every game server, and restarting the maps. + +The API also accepts `X-EC-Telemetry-Token`; these reporters use Bearer auth. +Cookies, query parameters, and JSON fields cannot authenticate telemetry. +Missing or incorrect request tokens are rejected before payload parsing or +recording. Reporters that cannot set headers need a trusted relay with an HTTPS +reporter-facing endpoint. The plugins used here accept a headers array. + +After deployment, verify all four event types reach Electric Cherry. On a test +server, also verify that a short embedded token and an HTTP URL prevent startup, +that a wrong token is rejected without recording an event, and that deploying +the correct token restores ingestion. Plugin transport completion alone does +not prove API acceptance; inspect the API response or ingestion records. + ## Validating T6 ```powershell diff --git a/t5/README.md b/t5/README.md index e00ea24..ddba5cf 100644 --- a/t5/README.md +++ b/t5/README.md @@ -354,7 +354,7 @@ and [spawn entry point](https://github.com/plutoniummod/t5-scripts/blob/main/ZM/ | `tws_lock_round` | `tws_lock` | `20` | Round at which the lobby locks | | `tws_server_id` | `tws_bank`, `tws_telemetry` | Required for telemetry | Exact registered Electric Cherry server name; also used as the bank label | | `tws_telemetry_enabled` | `tws_telemetry` | `1` | Set to `0` to disable telemetry at init | -| `tws_telemetry_url` | `tws_telemetry` | `http://192.168.1.199:3000/api/telemetry` | Electric Cherry telemetry endpoint for JSON POSTs | +| `tws_telemetry_url` | `tws_telemetry` | `https://ec.thewrightserver.net/api/telemetry` | Electric Cherry telemetry endpoint for JSON POSTs | | `tws_telemetry_log_level` | `tws_telemetry` | `1` | Read live: `0` warnings/errors/recovery only, `1` lifecycle/request/health logs, `2` also capture/queue logs and response previews | ## tws_telemetry.gsc @@ -362,13 +362,17 @@ and [spawn entry point](https://github.com/plutoniummod/t5-scripts/blob/main/ZM/ Uses `t5-gsc-utils` HTTP/JSON components to POST directly to Electric Cherry's `/api/telemetry`. Install alongside `tws_common.gsc` in `storage/t5/scripts/sp/`. No HUD or database dependency. Reports run whether or not a beta is active. +Follow the shared [authentication setup](../README.md#telemetry-authentication-t5-and-t6) +to configure the service before upgrading. The reporter token is embedded in +`level.telemetry_token`; it must match the service's `EC_TELEMETRY_TOKEN`. Short +embedded tokens and non-HTTPS URLs disable reporting at init. Example server config (except log level, read at script init; restart the map after changes): ```cfg set tws_server_id "t5_zombie_prototype_1" set tws_telemetry_enabled "1" -set tws_telemetry_url "http://192.168.1.199:3000/api/telemetry" +set tws_telemetry_url "https://ec.thewrightserver.net/api/telemetry" set tws_telemetry_log_level "1" ``` @@ -410,8 +414,9 @@ use `jsonSerialize` for escaping. Events are captured immediately into an in-memory queue. One HTTP worker POSTs each snapshot once, in gameplay order, with `Content-Type: -application/json`, waiting for completion before sending the next. Gameplay -and round detection continue while requests are pending. Repeated joins or +application/json` and `Authorization: Bearer `, waiting for completion +before sending the next. Gameplay and round detection continue while requests +are pending. Repeated joins or end notifications do not duplicate start/end reports. At game over, the reporter captures any round change since the last poll, stops detection, and lets the sender drain through `game_end`. diff --git a/t5/tws_telemetry.gsc b/t5/tws_telemetry.gsc index 86e7e38..3f41312 100644 --- a/t5/tws_telemetry.gsc +++ b/t5/tws_telemetry.gsc @@ -21,7 +21,22 @@ init() level.telemetry_url = GetDvar("tws_telemetry_url"); if (level.telemetry_url == "") - level.telemetry_url = "http://192.168.1.199:3000/api/telemetry"; + level.telemetry_url = "https://ec.thewrightserver.net/api/telemetry"; + + if (getSubStr(toLower(level.telemetry_url), 0, 8) != "https://") + { + print("^1[tws_telemetry] Telemetry disabled: tws_telemetry_url must use HTTPS"); + return; + } + + // Shared reporter secret; update both scripts when rotating it. + // This must match Electric Cherry's EC_TELEMETRY_TOKEN environment variable. + level.telemetry_token = "e03a03f7d22418f0c062b0b2a7317fd91b1194c4400e84b469866de501180dc2"; + if (level.telemetry_token.size < 32) + { + print("^1[tws_telemetry] Telemetry disabled: embedded telemetry token must be at least 32 characters"); + return; + } level.telemetry_server = GetDvar("tws_server_id"); if (level.telemetry_server == "") @@ -273,6 +288,7 @@ telemetry_send(entry) headers = []; headers["Content-Type"] = "application/json"; + headers["Authorization"] = "Bearer " + level.telemetry_token; options = []; options["method"] = "POST"; diff --git a/t6/README.md b/t6/README.md index 4a12d0c..53b0f9a 100644 --- a/t6/README.md +++ b/t6/README.md @@ -1,7 +1,8 @@ # TWS T6 Zombies scripts Plutonium T6 versions of the T5 server scripts. Defaults live in the scripts, -just like T5. There is no separate TWS config file or database setup. +just like T5. The telemetry token is embedded in the reporter script; no +separate token config or database setup is required. | File | Role | Dependencies | | --- | --- | --- | @@ -20,7 +21,9 @@ just like T5. There is no separate TWS config file or database setup. 2. For telemetry or leaderboard, install [t6-gsc-utils v3.1.1](https://github.com/alicealys/t6-gsc-utils/releases/tag/v3.1.1) in `Plutonium/plugins/` and restart the server process. The other five scripts do not require that plugin. -3. Restart the map to load script updates. +3. Ensure the API service's `EC_TELEMETRY_TOKEN` matches the token embedded in + the reporter; see [authentication setup](../README.md#telemetry-authentication-t5-and-t6). +4. Restart the map to load script updates. If upgrading from the earlier leaderboard filename, **remove `tws_leaderboard.gsc` from the T6 server script directory** before installing @@ -86,14 +89,15 @@ their module's initialization so the list stays current. - Lock uses T5's HUD round/game-over notifications. Default threshold is 20. As in T5, it clears `g_password` at startup and game over. - Telemetry is enabled by default and posts to - `http://192.168.1.199:3000/api/telemetry`. Set `tws_server_id` to the exact, + `https://ec.thewrightserver.net/api/telemetry`. Set `tws_server_id` to the exact, case-sensitive Electric Cherry registry name; missing or overlong names - disable reporting with a console diagnostic. + disable reporting with a console diagnostic. An embedded token matching the service's + `EC_TELEMETRY_TOKEN` (at least 32 characters) and an HTTPS URL are required as well. -The optional dvars already present in T5 are still supported: `tws_lock_round`, +The dvars already present in T5 are still supported: `tws_lock_round`, `tws_server_id`, `tws_telemetry_url`, and `tws_telemetry_enabled` (`0` disables -telemetry). None require a separate config file. If earlier settings are already -set on the server, they still override these defaults. +telemetry). Earlier settings still override defaults; remove any old HTTP URL +override when upgrading. The reporter token lives in `level.telemetry_token`. ## Round telemetry @@ -102,9 +106,16 @@ Cherry registry name and full endpoint in your existing server configuration: ```cfg set tws_server_id "t6_zombie_town_1" -set tws_telemetry_url "http://192.168.1.199:3000/api/telemetry" +set tws_telemetry_url "https://ec.thewrightserver.net/api/telemetry" ``` +The script embeds the reporter token in `level.telemetry_token`; it must match +the API service's `EC_TELEMETRY_TOKEN` environment variable. Follow the shared +[authentication setup](../README.md#telemetry-authentication-t5-and-t6). Every +request includes `Authorization: Bearer ` and `Content-Type: +application/json`. Token rotation requires updating and redeploying both reporter +scripts. Token and endpoint changes require a map restart. + It sends four event types over the life of a match, mirroring the T5 script: | Event | When | Round in payload | diff --git a/t6/tws_t6_telemetry.gsc b/t6/tws_t6_telemetry.gsc index 4e5864c..94d1135 100644 --- a/t6/tws_t6_telemetry.gsc +++ b/t6/tws_t6_telemetry.gsc @@ -26,7 +26,22 @@ init() level.telemetry_url = GetDvar("tws_telemetry_url"); if (level.telemetry_url == "") - level.telemetry_url = "http://192.168.1.199:3000/api/telemetry"; + level.telemetry_url = "https://ec.thewrightserver.net/api/telemetry"; + + if (getSubStr(toLower(level.telemetry_url), 0, 8) != "https://") + { + println("^1[tws_t6_telemetry] Telemetry disabled: tws_telemetry_url must use HTTPS"); + return; + } + + // Shared reporter secret; update both scripts when rotating it. + // This must match Electric Cherry's EC_TELEMETRY_TOKEN environment variable. + level.telemetry_token = "e03a03f7d22418f0c062b0b2a7317fd91b1194c4400e84b469866de501180dc2"; + if (level.telemetry_token.size < 32) + { + println("^1[tws_t6_telemetry] Telemetry disabled: embedded telemetry token must be at least 32 characters"); + return; + } level.telemetry_server = GetDvar("tws_server_id"); if (level.telemetry_server == "" || level.telemetry_server.size > 255) @@ -292,6 +307,7 @@ telemetry_send(entry) headers = []; headers["Content-Type"] = "application/json"; + headers["Authorization"] = "Bearer " + level.telemetry_token; options = []; options["method"] = "POST";