screentinker/server
ScreenTinker f06a87f4be fix(api): harden device pairing against brute-force (#87)
The 6-digit pairing code is generated client-side, so the server can't raise its entropy
without a player change. Instead, harden server-side (no client change):
- lib/pair-lockout.js: lock an IP out of POST /api/provision/pair after 5 failed claims
  (15-min lockout), and expire stale provisioning codes after 15 min so a code is not
  claimable indefinitely. A successful claim resets the IP.
- /pair enforces both. Only an UNKNOWN code (404) counts toward the lockout (a real guess);
  an EXPIRED code (410) is a legitimate-but-stale code and does NOT count, so a slow bulk
  rollout from one shared-NAT IP can't lock itself out. getClientIp is Cloudflare-aware
  (CF-Connecting-IP validated against a trusted edge peer), so the lockout keys on the real
  per-client IP, never a shared edge.

Unit-tested deterministically with injected time, incl. the bulk-rollout-never-locks case.

Closes #87

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 20:16:12 -05:00
..
config feat(api): token management endpoints + Settings UI 2026-06-12 18:45:09 -05:00
db feat(api): scoped API token foundation + secure-by-exclusion mounts 2026-06-12 18:45:09 -05:00
lib fix(api): harden device pairing against brute-force (#87) 2026-06-12 20:16:12 -05:00
middleware feat(api): scoped API token foundation + secure-by-exclusion mounts 2026-06-12 18:45:09 -05:00
player feat(scheduling): per-item schedule blocks (#74 dayparting, #75 auto-expire) 2026-06-11 15:46:41 -05:00
routes fix(api): consolidate device pairing to /pair, remove vestigial bare endpoint (#90) 2026-06-12 20:13:16 -05:00
scripts feat(scheduling): per-item schedule blocks (#74 dayparting, #75 auto-expire) 2026-06-11 15:46:41 -05:00
services feat(scheduling): per-item schedule blocks (#74 dayparting, #75 auto-expire) 2026-06-11 15:46:41 -05:00
test fix(api): harden device pairing against brute-force (#87) 2026-06-12 20:16:12 -05:00
ws feat(scheduling): per-item schedule blocks (#74 dayparting, #75 auto-expire) 2026-06-11 15:46:41 -05:00
.gitignore feat(email): Microsoft Graph send + alert spam protection + preferences UI 2026-05-12 18:16:40 -05:00
config.js chore(version): single-source VERSION, env-configurable data paths, bump tooling 2026-06-10 12:56:03 -05:00
package-lock.json test(api): fix spec scope drift + guard it in CI; Redoc provenance 2026-06-12 18:45:09 -05:00
package.json test(api): fix spec scope drift + guard it in CI; Redoc provenance 2026-06-12 18:45:09 -05:00
server.js fix(api): harden device pairing against brute-force (#87) 2026-06-12 20:16:12 -05:00
version.js chore(version): single-source VERSION, env-configurable data paths, bump tooling 2026-06-10 12:56:03 -05:00