screentinker/server
ScreenTinker 8a28761b12 fix(widgets): bound the unauthenticated telemetry store, and stop it writing rows
The diag widget runs in a null-origin sandboxed iframe, so it cannot carry a session and
its telemetry POST must stay unauthenticated. But the handler stored into a plain Map
keyed on a value taken from the request body, with no cap, no TTL and no eviction — an
unauthenticated caller could add entries until the process died. On this product a dead
server is a fleet-wide reconnect, so a bound here is a fleet-safety control.

Two changes:

- lib/bounded-snapshot-store.js: a "latest snapshot per key" store with a global entry cap
  and a TTL, evicting least-recently-WRITTEN. The cap is GLOBAL rather than per-IP on
  purpose — signage sites egress through one NAT address, so a per-IP limit punishes a
  whole venue for one noisy panel and does nothing about a distributed writer. Same
  reasoning the OTA download guard already documents ("NEVER per-IP (SNAT)"). A live panel
  rewrites its key every 2.5s, so only entries the dashboard already treats as stale
  (>15s) are ever eligible for eviction.

- The POST now answers 204 instead of res.json({ok:true}). The reporting widget ignores
  the response (fetch(...).catch()), and services/activity.js activityLogger wraps
  res.json — so this also stops an anonymous caller from writing one activity_log row, and
  running two synchronous statements, per report.

Read contract unchanged: a live key returns its object, an unknown OR expired key returns
null — the shape frontend/js/views/device-detail.js already handles ("no report yet"), and
it treats anything older than 15s as stale regardless, so the 60s TTL is 4x looser than
what the UI honours. No client change; no rate limiter added.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 10:36:09 -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 feat(content): subtitle/caption support as a content property (#223) 2026-07-23 12:33:35 -05:00
lib fix(widgets): bound the unauthenticated telemetry store, and stop it writing rows 2026-07-26 10:36:09 -05:00
middleware refactor(auth): drop the unused optionalAuth middleware 2026-07-24 21:03:25 -05:00
player fix(widgets): honest webpage-widget note — blocked sites don't work on device (#230) 2026-07-24 19:17:00 -05:00
routes fix(widgets): bound the unauthenticated telemetry store, and stop it writing rows 2026-07-26 10:36:09 -05:00
scripts fix(content+android): rotation-aware media — portrait upright on dashboard AND player (#170) (#172) 2026-07-12 22:05:11 -05:00
services feat(auth,tizen): TOTP 2FA UI, email verification on signup, Tizen SSSP install 2026-07-22 21:08:50 -05:00
test fix(widgets): bound the unauthenticated telemetry store, and stop it writing rows 2026-07-26 10:36:09 -05:00
ws refactor(auth): centralise session token resolution across manual verify sites 2026-07-24 20:58:05 -05:00
.gitignore feat(email): Microsoft Graph send + alert spam protection + preferences UI 2026-05-12 18:16:40 -05:00
config.js feat(email): SMTP transport as an alternative to Microsoft Graph [#173] (#179) 2026-07-13 15:56:22 -05:00
package-lock.json chore(release): v1.9.15 2026-07-24 21:12:22 -05:00
package.json chore(release): v1.9.15 2026-07-24 21:12:22 -05:00
server.js refactor(auth): centralise session token resolution across manual verify sites 2026-07-24 20:58:05 -05:00
version.js chore(version): single-source VERSION, env-configurable data paths, bump tooling 2026-06-10 12:56:03 -05:00