screentinker/server
ScreenTinker 404c3301dd fix(#143): enforceable device block + fix the null-token auth short-circuit
Highest-priority #143 item (operator finding from Bold): nulling a device's token
did NOT lock it out — device 75c2a08a immediately reconnected and saturated the
loop. Two distinct defects:

1. Auth short-circuit (the cause). device:register used
     if (device.device_token && !validateDeviceToken(...)) { reject }
   so a NULL/empty STORED token made the guard falsy -> validation SKIPPED, and the
   next block even MINTED a fresh token and persisted it. Nulling a token thus
   RE-PROVISIONED the device instead of locking it out. Fix: drop the
   `device.device_token &&` guard -> `if (!validateDeviceToken(device_id, device_token))`
   (validateDeviceToken already returns false for null-stored/missing/mismatch), and
   remove the legacy "mint a token for a null-token device" path (the re-provision
   vector). An already-provisioned device (every row, incl. 'provisioning', is created
   WITH a token) presenting null/empty/invalid is now REJECTED + disconnected.
   The first-pairing seam is unaffected: a brand-new device has NO device_id and goes
   through the pairing_code branch (which mints id+token) — a different code path.

2. No server-side kill switch. Added a `blocked` column (devices.blocked INTEGER
   NOT NULL DEFAULT 0; schema.sql + a database.js migration). The block is the FIRST
   gate at the top of device:register — before the fingerprint block, the reconnect
   throttle, any DB writes, or playlist build — so a blocked device's socket is
   refused immediately (auth-error 'Device blocked' + disconnect, zero further work).
   It does NOT rely on null-token (the thing that failed). The row is re-read every
   register, so a DIRECT SQLite edit takes effect on the device's NEXT reconnect with
   NO server restart. Operator statements (dashboard-down, hand-edit):
     block:   UPDATE devices SET blocked = 1 WHERE id = '<device_id>';
     unblock: UPDATE devices SET blocked = 0 WHERE id = '<device_id>';

Tests (port 3987): nulled-token provisioned device is REJECTED (75c2a08a repro);
blocked=1 refused at the first gate (no register/playlist); unblock reconnects;
first-pairing still works; normal valid-token device unaffected. Full suite green
serial AND parallel (213); reconnect-throttle.js + the dbac699 content-ack limiter
untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 22:40:30 -05:00
..
config PiP overlay MVP: push image/web overlays to a device or group (#109) (#127) 2026-06-18 14:54:44 -05:00
db fix(#143): enforceable device block + fix the null-token auth short-circuit 2026-06-27 22:40:30 -05:00
lib fix(#143): content-ack flood control — per-device rate budget + loop-lag valve 2026-06-27 22:21:57 -05:00
middleware feat(api): per-agency-token auto-publish (#73) 2026-06-14 13:48:17 -05:00
player fix(player): composite multi-zone layouts in screenshot/stream capture 2026-06-22 23:22:12 -05:00
routes feat(#142): event-loop lag telemetry (perf_hooks) + bounded storage 2026-06-27 19:01:08 -05:00
scripts feat(scheduling): per-item schedule blocks (#74 dayparting, #75 auto-expire) 2026-06-11 15:46:41 -05:00
services fix(#143): content-ack flood control — per-device rate budget + loop-lag valve 2026-06-27 22:21:57 -05:00
test fix(#143): enforceable device block + fix the null-token auth short-circuit 2026-06-27 22:40:30 -05:00
ws fix(#143): enforceable device block + fix the null-token auth short-circuit 2026-06-27 22:40:30 -05:00
.gitignore feat(email): Microsoft Graph send + alert spam protection + preferences UI 2026-05-12 18:16:40 -05:00
config.js fix(#143): content-ack flood control — per-device rate budget + loop-lag valve 2026-06-27 22:21:57 -05:00
package-lock.json chore(release): v1.9.2-beta1 2026-06-27 19:59:34 -05:00
package.json chore(release): v1.9.2-beta1 2026-06-27 19:59:34 -05:00
server.js feat(#142): event-loop lag telemetry (perf_hooks) + bounded storage 2026-06-27 19:01:08 -05:00
version.js chore(version): single-source VERSION, env-configurable data paths, bump tooling 2026-06-10 12:56:03 -05:00