The relay web client re-fetched every macro image through the relay->desktop
proxy on each render (tab switch, WS update) and revoked the object URL on
load, so nothing was reused and fetches were serial — slow to display.
- Client: cache image_path -> Promise<objectURL> and reuse across renders
(macro images are content-addressed by uuid, so immutable); fetch in
parallel and de-duplicate concurrent requests.
- Proxy: send Cache-Control: private, max-age=31536000, immutable on image
responses so the browser also disk-caches them across reloads.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Uniform auth responses remove the session-enumeration oracle: unknown
session and wrong password now return an identical 401 at the API layer and
an identical WS handshake/close; desktop-status and the 503 "not connected"
signal are only exposed after successful auth.
- Session-count cap re-checked after bcrypt.hash so concurrent creates can't
overshoot maxSessions.
- Relay web client reconnect backoff resets only after a successful auth
response (an accept-then-close server no longer defeats the backoff).
- idGenerator comment corrected to match the rejection-sampling; drop unused
recordFailure return value.
- DEPLOY.md: document ALLOWED_ORIGINS for reverse-proxy deployments.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses two Major findings from PR review:
- Auth lockout no longer griefable: the throttle key is namespaced per path
and includes the client IP (web:<session>:<ip> vs desktop:<session>:<ip>),
so a flood of bad web-client auths can neither lock other clients of the
same session nor block the desktop from (re)authenticating. Per-socket
failure close and brute-force lockout are preserved.
- Relay web client XSS eliminated: app.html tab/macro rendering rebuilt with
createElement/textContent (no macro/tab value reaches innerHTML); inline
scripts/handlers externalized to /static/app.js and /static/login.js so the
helmet CSP now uses script-src 'self' (dropped 'unsafe-inline' for scripts).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes the account-takeover chain and related issues found in audit:
- WS auth brute-force protection: per-session lockout (authThrottle) + per-
socket failure cap that closes the socket (1008); applied to both web-client
and desktop auth. Failed auth no longer leaves the socket open for unlimited
guesses.
- WS upgrades now pass an IP-based rate limiter and Origin allowlist before
handleUpgrade (previously bypassed all HTTP middleware); trust proxy set so
limiting keys on the real client IP.
- /health no longer leaks live session IDs (counts only).
- .env.example rate-limit fixed (900000ms / 300) from the accidental ~11k rps.
- Credentials moved out of URLs into the X-MacroPad-Password header; images
fetched via header + blob URLs; login stores creds in sessionStorage.
- Session creation bounded (max sessions, min password length) and TTL-pruned;
session store writes are now atomic (temp+rename) and debounced.
- Session IDs lengthened to 12 chars with rejection sampling (no modulo bias).
- Enable helmet CSP; restrict CORS to configured origins.
- Request IDs use crypto.randomUUID; drop postinstall build hook and uuid dep.
- Uniform response for unknown session IDs (removes enumeration oracle).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add wake lock (keep screen awake) functionality
- Add fullscreen toggle button
- Add dynamic PWA manifest generation
- Add favicon and icons for all relay pages
- Copy icons from main web folder
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add password query parameter to image URLs in the relay server's
app.html - this file has its own inline JavaScript separate from
the main web/js/app.js
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update index.html links to repo.anhonesthost.net
- Adjust rate limit defaults in .env.example
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add index.html explaining what MacroPad Relay is
- Add /ping endpoint for container health checks
- Add route for index page
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add postinstall script to build TypeScript automatically
- Move typescript to dependencies (needed during npm install)
- Update main and start to point to dist/index.js
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Node.js/TypeScript relay server that enables remote access to MacroPad:
- WebSocket-based communication between desktop and relay
- Password authentication with bcrypt hashing
- Session management with consistent IDs
- REST API proxying to desktop app
- Web client WebSocket relay
- Login page and PWA-ready app page
- Designed for cloud-node-container deployment
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>