Skip to content

Release v26.3.1 — Staging → main#956

Merged
accius merged 297 commits into
mainfrom
Staging
May 7, 2026
Merged

Release v26.3.1 — Staging → main#956
accius merged 297 commits into
mainfrom
Staging

Conversation

@accius
Copy link
Copy Markdown
Owner

@accius accius commented May 7, 2026

Summary

Cuts release v26.3.1 — the May server-side security and resource-hardening audit, plus extended grid-locator utilities and a quieter browser console.

WhatsNew entry already in tree (164baa4); package.json bumped to 26.3.1 in dc56b00 so the modal surfaces on deploy.

Highlights

Security / hardening

Resource leaks closed

Cleanup / refactor

Test plan

  • CI passes on Staging head
  • After merge: bump Railway proppy production Root Directory from /iturhfprop-service to empty (matching Staging)
  • Verify curl -s https://proppy-production.up.railway.app/api/health returns OHC's verbose JSON (not ITURHFProp minimal response) post-flip
  • Verify Cloud Relay users re-pair successfully against new token system
  • Smoke-test /api/presence rate-limit on production (one POST, second within 60s should 429)

alanhargreaves and others added 30 commits April 7, 2026 18:40
…s to quickly schedule a full next pull from the API (which we are not using). It also clears the current entries as it believes it's going to pull a full history, This is not the case with SSE.
Don't call fetchFull() on a useVisibilityRefresh() in useWSJTX()
Port the intelligence layer from the OHC server's WSJTX route into the
rig-bridge plugin stack so SSE consumers receive rich events even when
no server relay is configured.

New shared library — rig-bridge/lib/wsjtx-enrich.js
  • gridToLatLon()      — Maidenhead grid → lat/lon (pure math)
  • getBandFromHz()     — Hz → band name (160 m – 70 cm)
  • createGridCache()   — callsign → grid cache (2 h TTL, per-instance)
  • parseDecodeMessage()— FT8/FT4 text parser: CQ/QSO type, caller,
                          modifier, dxCall/deCall, embedded grid;
                          populates grid cache as a side-effect
  • enrichDecode()      — full decode enrichment + grid-cache fallback
  • enrichStatus()      — band name, band-change flag, DX/DE lat/lon
  • enrichQso()         — band name, dxGrid → lat/lon
  • enrichWspr()        — band name, grid → lat/lon

wsjtx-relay.js changes (Phases 1–4)
  • CLEAR message → new `clear` bus event (was silently dropped before)
  • WSPR_DECODE   → new `wspr` bus event with enriched fields
  • STATUS        → enriched with band, bandChanged, dxLat/dxLon, deLat/deLon
  • DECODE        → enriched with parsed message fields, grid → lat/lon,
                    content-based dedup ID; duplicates are suppressed
  • QSO_LOGGED    → enriched with band + lat/lon; 60 s call+freq+mode dedup
  • Grid cache pruned every 5 min; cleared per-client on CLEAR
  • getStatus() now reports gridCacheSize
  • Relay queue still receives raw (un-enriched) messages — server does
    its own enrichment on the relay path (no double-processing)

digital-mode-base.js changes (MSHV / JTDX / JS8Call)
  • Same enrichment applied via wsjtx-enrich helpers
  • CLEAR forwarded as `clear` bus event (was silently dropped)
  • STATUS/DECODE/QSO enriched identically to wsjtx-relay
  • lastBand added to getStatus() alongside existing lastMode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…chment

Adds opt-in background callsign → lat/lon resolution via the HamQTH DXCC
API, matching the server's Phase 5 behaviour but running entirely inside
the local rig-bridge process.

wsjtx-enrich.js
  • createCallsignCache() — 24 h TTL cache for HamQTH results, separate
    from the 2 h gridCache (different source, different lifetime)
  • triggerHamqthLookup(callsign, cache, inflight, onResult) — fire-and-
    forget HTTPS GET to hamqth.com/dxcc.php; max 5 concurrent requests
    (inflightSet guard); writes result into callsignCache and calls
    onResult so callers can emit a decode-update event
  • enrichDecode() — accepts optional 5th param callsignCache; consults
    it as a third fallback tier between gridCache and giving up

wsjtx-relay.js
  • Instantiates callsignCache + hamqthInflight per plugin instance
  • Passes callsignCache to enrichDecode() when cfg.hamqthLookup is true
  • After emitting a decode with no lat/lon, calls triggerHamqthLookup
    and on resolution emits a decode-update bus event with the resolved
    callsign + coordinates for frontend live-patching
  • gridPruneInterval now also prunes callsignCache every 5 min
  • getStatus() reports callsignCacheSize, hamqthLookup flag, hamqthInflight

rig-bridge/core/server.js (Integrations tab UI)
  • New "HamQTH callsign lookup" checkbox (id=wsjtxHamqth) with help text
    explaining the internet requirement and 24 h cache
  • populateIntegrations() reads w.hamqthLookup → checkbox
  • saveIntegrations() writes checkbox → wsjtxRelay.hamqthLookup
  • Status line now shows callsign cache size when hamqthLookup is active
    and omits relay count when running in SSE-only mode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
rig-bridge/rig-bridge.js
  • decode handler was building a trimmed object that silently dropped all
    fields added by wsjtx-enrich (lat, lon, band, grid, type, caller,
    modifier, dxCall, deCall, gridSource). Now passes them all through.
  • id forwarded directly from enrichDecode (content-based) instead of
    being rebuilt; raw-decode fallback retained for non-enriched plugins.
  • status handler forwards new enriched fields: band, bandChanged,
    dxLat, dxLon, deLat, deLon.
  • qso handler forwards: band, lat, lon, frequency, myCall, myGrid.
  • New clear handler → broadcasts clientId + window to SSE.
  • New wspr handler → broadcasts full enriched WSPR decode to SSE.
  • New decode-update handler → broadcasts HamQTH-resolved callsign
    coordinates to SSE for live map-pin patching.

src/hooks/useWSJTX.js
  • status handler now stores band, bandChanged, dxLat, dxLon so DX
    target resolution and band-change detection work without server.
  • Band-change detection uses the bandChanged flag from the enriched
    status event; falls back to manual prev-band comparison for the
    server/relay path.
  • New clear event handler: filters decodes by clientId.
  • New wspr event handler: prepends to wspr array (capped at 100).
  • New decode-update event handler: patches existing decodes that share
    the resolved callsign and have no lat/lon yet (HamQTH async result).

src/layouts/ModernLayout.jsx
  • Pass wsjtxWspr={wsjtx.wspr} to PSKReporterPanel so the WSPR tab
    actually receives data (DockableApp already had this; ModernLayout
    was the only layout missing it).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nvention

PSKReporterPanel filters on d.type === 'CQ' (uppercase), matching the
OHC server's parseDecodeMessage output. wsjtx-enrich was using lowercase
'cq'/'qso', causing the CQ filter and the blue CQ row colour to never
match in local SSE mode.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Installer scripts generated in `server/routes/rig-bridge.js` now automatically resolve the configured TCP port, TLS scheme, and bindAddress configuration dynamically.
- Refactored both Windows and macOS/Linux installer scripts to halt and interactively request user confirmation after verifying that they read the `README.md` before launching the Setup UI.
- Improved subdirectory flushing using recursive deletions (`rmdir /S` and `find -exec rm -rf`) prior to repo extraction to ensure stale files do not survive updates.
- Refactored Rig Bridge `README.md` text to correctly define the new installation UI behavior.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s work

PORT was present in the shared ctx object but not destructured into
rbn.js, causing a ReferenceError in every try/catch that called the
internal /api/callsign/ endpoint. All three lookup paths
(enrichSpotWithLocation, enrichSpotWithDXLocation, /api/rbn/location/)
silently swallowed the error and cached a _failed marker, so no spot
ever received skimmerLat/skimmerLon or dxLat/dxLon. In spotter mode
this meant every spot failed the Number.isFinite(dxLat) guard and
nothing rendered on the map, even though the stats count was correct.

Also fix three CLAUDE.md violations (falsy && checks on lat/lon that
would mishandle stations on the equator or prime meridian), and
improve the spotter-mode debug log to show dxLat/dxLon/dxGrid instead
of the irrelevant skimmer coordinates.

Fixes: #897

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix(rbn): restore PORT in ctx destructuring so spotter-mode spots appear on map

I verified it does what it should and teh other changes are good good code cleanup.
When a DX cluster spot is clicked, the callsign is now captured
alongside the coordinates and displayed to the right of the grid
locator in ModernLayout and ClassicLayout. Typing a grid manually
clears the callsign. Persisted to localStorage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…out)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…A spot click

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Polls /api/rbn/spots for all 18 IBP beacon callsigns every 60 s.
When a beacon has been heard by RBN skimmers in the last 5 minutes,
a compact "RBN N× +XdB" indicator appears beneath its location in
the IBP panel, showing skimmer count and best SNR.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds ibp.title, ibp.cycleCountdown, ibp.cycleCountdown.tooltip,
ibp.slotProgress.tooltip, ibp.footer, ibp.tune, ibp.rbn.heard,
ibp.rbn.tooltip, plugins.layers.ibp.name and .description to:
ca, de, es, fr, it, ja, ka, ko, ms, nl, pt, ru, sl, th, zh

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
IBP beacons transmit in CW but getModeFromFreq() returns DATA/USB for
14.100, 21.150, 24.930 and 28.200 MHz. Pass 'CW' explicitly as the
second argument to tuneTo() in both IBPPanel and the map layer so all
5 beacon frequencies set the correct mode regardless of the band plan.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- th.json: improve ibp.rbn.tooltip and plugins.layers.ibp.description
  wording for more natural Thai
- useIBPRBN.js: apply Prettier formatting (fetch options object style)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ckableApp

Prevents button overlap when a long callsign is displayed alongside
the grid locator in narrow dockable panels.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Feature/Show DX spot callsign in the DX panel
accius and others added 24 commits May 4, 2026 09:06
[fix] add periodic purges to emcomm.js caches
[fix] Validate that `imageUrl` parses as `https://*.nasa.gov` before fetching.
…api_presence

[fix] lockout frequent POST to /api/presence
[util] geo.js extends maidenhead grid support
fix(security): harden rig-bridge relay and status endpoints
Covers PRs #946, #945, #943, #942, #941, #940, #938, #935, #932 — all
merged to Staging on 2026-05-04. Grouped into five themes: Cloud Relay
credential overhaul (with breaking-change heads-up), API surface
hardening, server cache leak closures, extended Maidenhead grid
utilities, and the client-side console cleanup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ve existing definitions of same function.

Load in server.js and pass in ctx object.
[fix] fixes issue#950 non-NASA imageUrl report in throw
…ockdown

[refactor] fixes issue #948 nit fix /api/health_lockdown redundant ternary
…presence

[fix/refactor] fixes issue#949, cleanup lockout frequent POST to /api/presence
…nCache

[refactor] Issue#947, create server/utils/cache.js with maintainCache
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-RigBridge-Token': config.apiToken || '' },
// Skip cert verification for loopback self-signed cert
rejectUnauthorized: false,
const entry = sessionId ? relayIssuedTokens.get(sessionId) : undefined;
if (!sessionId || !token || !entry || token !== entry.token) {
logWarn(
`[RigBridge] relay auth failed — sessionId: ${sessionId ? sessionId.slice(0, 8) + '…' : '(none)'}, ` +
@railway-app railway-app Bot temporarily deployed to openhamclock / Staging May 7, 2026 03:36 Inactive
@accius accius merged commit 1ac7877 into main May 7, 2026
10 of 11 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.

7 participants