screentinker/server/ws
ScreenTinker 97d489223f fix(#146) D: operator block — close the device_id-less gap + dashboard toggle
- Enforcement (deviceSocket): resolve identity ONCE via the SNAT-safe chain and check
  blocked against the RESOLVED device_id (device_id directly OR fingerprint->device_id),
  so a blocked device that reconnects WITHOUT a device_id is still caught — the old
  "if (device_id)" gate let a device_id-less reconnect slip past. Still the first gate,
  before flap/throttle/DB/playlist. Nulling the token still does NOT block (it
  re-provisions) — the blocked column is the lever.
- Dashboard toggle: POST /api/devices/:id/{block,unblock} (write-gated + workspace-scoped
  via checkDeviceOwnership) writes devices.blocked; takes effect on the device's NEXT
  register with no restart. api.js + a Block/Unblock button in device-detail.js.
- Outage procedure documented in-code: direct SQLite
  "UPDATE devices SET blocked = 1 WHERE id = <id>" works with the dashboard down.

Tests: blocked refused at handshake with no playlist build; device_id-less reconnect
with a mapped fingerprint still refused; unblock effective on next register, no restart.
Suite 262/262.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 21:28:04 -05:00
..
dashboardSocket.js fix(#146): crash-hardening — one device's handler throw can't take down the fleet 2026-06-29 23:38:11 -05:00
deviceSocket.js fix(#146) D: operator block — close the device_id-less gap + dashboard toggle 2026-06-30 21:28:04 -05:00
index.js Initial open source release 2026-04-08 12:14:53 -05:00