docs(wiki): booth bring-up fixes — relay password, secret re-merge, lamp concurrency
- dingtian-relay: the "offline despite ping" gotcha (relay_pw in every binary frame, missing form field → Test connection sent 0 → timeout) + the identity-gated secret re-merge that stops a redirected probe exfiltrating the password. - button-light-indicator: serialized desired-state worker (UDP is unordered → the lamp stuck on/off) and hot-reload of the lamp config (no restart). - log entry for the three fixes (commits420542c/fd15988/830993b). Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -157,6 +157,28 @@ On assign the driver runs `harden()` (the [[device-registry|HardenableDevice]] c
|
||||
> drop connections (ECONNRESET), locking out the API the driver depends on — recoverable only by
|
||||
> factory reset. `harden()` deliberately never touches it.
|
||||
|
||||
## `relayPassword` field + the "offline despite ping" gotcha (2026-06-24)
|
||||
|
||||
`relay_pw` is in **every** binary frame — control AND the status read `healthCheck()` uses. With a
|
||||
wrong/missing value the device **silently drops the packet** (no NAK), so the probe **times out →
|
||||
the controller shows "offline" even though it pings** (ping is ICMP and never touches the binary
|
||||
protocol). This bit a real bring-up: the driver read `config.relayPassword` but there was **no form
|
||||
field** for it, so Test connection sent `0` → timeout → "offline", while `relay_pw` was actually a
|
||||
non-zero value the harden flow had set. Diagnostic: a raw UDP status frame
|
||||
(`FF AA <s> 00 <pwLo> <pwHi>`) replies *only* with the right password — `pw=N` → `ffaa…`, `pw=0` →
|
||||
timeout — and binding the WSL socket to the device-facing NIC (`localAddress`) also broke the reply
|
||||
(leave it unbound on WSL). Fix: a **"Relay control password"** config field (a **secret**; blank =
|
||||
keep the stored value).
|
||||
|
||||
> 🔒 **Secret re-merge is identity-gated (don't let a redirected probe exfiltrate it).** Because
|
||||
> `relayPassword`/`pushPassword` are redacted from the client ([[first-run-setup]]), the edit form
|
||||
> can't resend them, so `/api/setup/test` re-merges the stored secret by device **id** — but ONLY
|
||||
> when the submitted config addresses the **same device**: matching `driverId` and every
|
||||
> connection-identity field it sets (`host`/`port`/`binaryPort`/`httpPort`/`serial`). A redirected
|
||||
> host/port or mismatched driver returns NO secret, so an authenticated admin can't point a test at
|
||||
> an attacker host and have the password sent there (the booth operator is the [[threat-model]]
|
||||
> adversary). Save already merged from the stored row; this closes the same gap on test.
|
||||
|
||||
## Status — VERIFIED on hardware (DT-R004, sw V3.1.5461A, 10.0.10.172)
|
||||
|
||||
- ✅ status read (`0000:1111:4`), relay pulse, input press/release events (active-LOW, idle HIGH).
|
||||
|
||||
Reference in New Issue
Block a user