From bcd6e12a6c789fa425e05e4dda6eb42d7bd06828 Mon Sep 17 00:00:00 2001 From: larssand Date: Sat, 12 Sep 2026 20:28:07 +0200 Subject: [PATCH] Document a concrete auth design for the deferred permissions work Planning only, no code yet. Per-role PIN codes (not named accounts - a shared trackside laptop doesn't want individual logins), an optional IP/host allowlist as a separate complementary layer, and 2FA deliberately left out unless a club actually exposes the server past their own LAN. Flags one open question for the user to decide before implementation starts: auth off by default vs. on by default with an auto-generated Admin PIN on first run. Co-Authored-By: Claude Sonnet 5 --- CHANGELOG.md | 6 ++++++ ROADMAP.md | 11 +++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d2d550..dec7912 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ The application version is maintained in `package.json` and displayed in the adm No changes recorded yet. +## 1.21.2 - 2026-09-12 + +### Changed + +- Documented a concrete auth design in ROADMAP.md ("Permissions and mobile Race Control"): per-role PIN codes rather than named accounts, an optional IP/host allowlist as a separate complementary layer, and 2FA deliberately left out unless a club actually exposes the server past their own LAN. Planning only - no auth code shipped yet. + ## 1.21.1 - 2026-09-12 ### Changed diff --git a/ROADMAP.md b/ROADMAP.md index e838bdd..36767eb 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -155,6 +155,17 @@ Deferred 2026-09-09 at the user's request - requires a paid third-party neural T Deferred 2026-09-09 at the user's request - the largest remaining item, on par with or bigger than the full optimistic-locking rework already deferred under section 2. Today there is no login or authorization at all: anyone reaching the server on the network has full admin access. Building this needs an identity system that doesn't exist yet (no user accounts, no sessions), server-side authorization on every mutating endpoint (not just hiding UI controls), and a genuinely new "compact mobile Race Control" surface (start/stop, track call, flags, next heat) - plus a real decision on how login should work in practice on a shared trackside laptop (PIN codes per role? named accounts? offline/LAN-only requirement?) before any of it can be designed, let alone built. Revisit as its own dedicated design conversation. +### Recommended auth design (discussed 2026-09-12, not yet built) + +The user framed the actual threat model clearly: this normally runs on a trusted local race-day LAN, so a random internet attacker isn't the realistic concern - but someone else on that same LAN/venue WiFi being able to open the admin UI and interfere with a live race (stop a session, change results, trigger the unauthenticated `/api/update/run` restart from the audit follow-up above) is a real, low-effort risk worth closing. That framing should drive the design: **simple enough for volunteers on a shared trackside laptop, not an internet-grade identity system.** + +- **PIN codes per role, not named accounts.** One shared PIN each for Admin, Race Director, Speaker, and Read-only (matching the capabilities list below) - a race club hands a laptop between whoever's running the desk that night; individual logins would just add friction nobody wants. Entering a PIN issues a signed, long-lived token (HMAC'd server-side, no session store needed - a secret already has to live somewhere, e.g. a value in `data/`, generated on first run) stored as a cookie, so it survives normal use for weeks and specifically **survives the server restarting** (relevant since the update checker and a power blip both restart the process mid-event). +- **IP/host allowlist as a separate, complementary layer**, per the user's own question - not instead of the PIN, in addition to it: an optional `RC_ADMIN_ALLOWED_CIDRS` env var (same shape as the existing `RC_ALLOWED_ORIGINS`) that, when set, rejects admin requests from outside the listed ranges before the PIN even matters. Left unset by default - forcing IP configuration would break the simple "clone it and it just works" flow this app has always had, but a club that wants belt-and-suspenders on their venue's fixed subnet can turn it on. +- **2FA: explicitly not part of this.** Only relevant if a club deliberately exposes the server past their own LAN (port-forwarded for a remote stream day, say) - a real but separate scenario from "someone else at the track." If that ever comes up, the natural shape is requiring a TOTP code on top of the PIN specifically for requests arriving from outside the allowlisted ranges, not a blanket requirement that would slow down the normal trackside case for no benefit. Not planned unless a club actually asks for internet-facing access. +- **Server-side enforcement on every mutating endpoint**, not just hiding buttons (this was already the plan below) - a small role-to-endpoint capability map, in the same spirit as the `MANAGE_TAB_TARGETS`-style lookup tables already used elsewhere in this codebase rather than scattering checks ad hoc through `server.js`. +- **Public overlays and training links are unaffected** - they're already gated per-share-token independently of admin auth (see the security audit's scope notes) and are meant to be shared outside the operator group; nothing about this design changes that. +- **Open question needing the user's decision before building:** auth off by default (today's zero-friction behavior, but does nothing until someone remembers to turn it on) vs. on by default with an auto-generated Admin PIN printed once to the console/log on first run (safer out of the box, closer to how other self-hosted tools like this one already print startup info to logs, but a new "one more thing to notice" step during setup). Leaning toward on-by-default given the whole point is closing a real live-race risk, but this is exactly the kind of call that should be confirmed, not assumed, before implementation starts. + - [ ] Define Admin, Race Director, Speaker and Read-only capabilities. - [ ] Enforce permissions on server endpoints, not only in the UI. - [ ] Keep public overlays and training links restricted. diff --git a/package-lock.json b/package-lock.json index 8c8cae8..d8a693c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rc-racecore", - "version": "1.21.1", + "version": "1.21.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rc-racecore", - "version": "1.21.1", + "version": "1.21.2", "hasInstallScript": true, "dependencies": { "better-sqlite3": "^12.11.1", diff --git a/package.json b/package.json index 6eb7623..7400e99 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-racecore", - "version": "1.21.1", + "version": "1.21.2", "private": true, "description": "RC RaceCore live timing and race control with AMMC ingest and SQLite persistence", "engines": {