Skip to content

feat(callsign): per-user QRZ/HamQTH credentials on shared instances#1110

Merged
accius merged 2 commits into
mainfrom
feat/per-user-callbook
Jul 8, 2026
Merged

feat(callsign): per-user QRZ/HamQTH credentials on shared instances#1110
accius merged 2 commits into
mainfrom
feat/per-user-callbook

Conversation

@accius

@accius accius commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Hosted users can now enter their own QRZ or HamQTH login in Settings and get full callbook data (name, QTH, grid) in the callsign popup — using only their own account, which is what the callbook terms require on a multi-user site.

How it works

  • Credentials live only in the user's browser (localStorage, deliberately outside the synced config) and ride as base64 auth headers on /api/callsign lookups.
  • The server exchanges them for QRZ/HamQTH session keys in an in-memory LRU map (500-credential cap, never persisted, never logged).
  • Lookup results are cached per credential hash, so one subscriber's callbook data is never served to another user.
  • Lookup order: user QRZ → user HamQTH → instance QRZ → instance HamQTH → DXCC fallback → prefix estimate.
  • New POST /api/callsign/verify-credentials (write-rate-limited) validates a login before the browser stores it; the Settings QRZ/HamQTH sections now work on shared instances with a "Your login (this browser)" badge and Remove button. Self-host server-side config unchanged.

Verified: exercised locally end-to-end (DXCC fallback unchanged, real HamQTH auth-failure round-trip, malformed/garbage headers fall through safely); 190 utils tests pass; tested on staging by Chris — names show up.

Cherry-pick of 0845d71c from Staging. Chris requested the port to production.

🤖 Generated with Claude Code

Hosted users can now enter their own QRZ or HamQTH login in Settings and
get full callbook data (name, QTH, grid) in the callsign popup — using
only their own account, which is what the callbook terms of service
require on a multi-user site.

Credentials are stored only in the user's browser (localStorage,
deliberately outside the synced config) and sent as base64 auth headers
on /api/callsign lookups. The server exchanges them for QRZ/HamQTH
session keys held in an in-memory LRU map (never persisted, never
logged), and lookup results are cached per credential hash so one
subscriber's callbook data is never served to another user. Lookup
order: user QRZ → user HamQTH → instance QRZ → instance HamQTH → DXCC
fallback → prefix estimate.

A new POST /api/callsign/verify-credentials endpoint (write-rate-
limited) validates a login before the browser stores it. The existing
Settings sections for QRZ/HamQTH now work on shared instances: verified
credentials get a "Your login (this browser)" badge and a Remove button;
self-host server-side configuration is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread server/routes/callsign.js Fixed
CodeQL flagged the SHA-256 credential hash (js/insufficient-password-
hash). The key only partitions the in-memory session map and lookup
cache, but deriving it with a real password KDF costs little (async
scrypt on the libuv pool, click-driven request rate) and means the key
can never weaken the password it came from. Key derivation failures now
degrade to an unauthenticated lookup instead of an unhandled rejection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@accius accius merged commit dfd95a5 into main Jul 8, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants