The HTTP server was hardcoding auth config with enabled=false,
ignoring the actual configuration from trx-client.toml. This prevented
authentication enforcement even when enabled with passphrases.
Solution: Store auth config values in FrontendRuntimeContext during
initialization in main.rs, then extract and use them in server.rs
build_server() instead of hardcoding.
Fixes auth bypass where unauthenticated users could access the web UI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
When HTTP authentication is disabled (the default), the /auth/session
endpoint now returns { authenticated: true, role: "control" } instead
of 404. This allows the frontend to proceed without showing a login
gate, providing the expected out-of-the-box experience.
With this change:
- Default behavior: no login required, full control access
- Auth enabled: login gate shown, roles enforced per config
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Remove the redundant logo image from the auth gate. The header already
displays the logo, so this duplicate was unnecessary.
The login screen now shows only:
- "Access Required" heading
- "Enter passphrase to continue" subtitle
- Passphrase input
- Login button
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Add box-sizing: border-box to both the passphrase input and login button
to ensure padding is included in width calculations. This makes them
exactly the same width visually.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Hide the Main/Plugins/About tab bar initially, only showing it after
the user successfully authenticates. This prevents navigation options
from being visible when access has not been granted.
Changes:
- Add display:none and id to tab-bar div in index.html
- Update showAuthGate() to hide tab-bar
- Update hideAuthGate() to show tab-bar
Now the UI flow is:
1. Header only (auth gate visible)
2. After login: Header + tabs + content
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
- Derive Default for SameSite enum in auth.rs using #[default] attribute
- Derive Default for CookieSameSite enum in config.rs
- Replace and_then(|x| Some(y)) with map(|x| y) in extract_session_id()
All clippy warnings resolved. Tests pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Phase 4: Frontend login gate and role-based UI
- Add auth-gate HTML overlay with passphrase form
- Implement checkAuthStatus, authLogin, authLogout functions
- Auth startup sequence checks /auth/session before connecting
- Apply role-based restrictions: hide PTT/TX controls for rx role
- Handle 401/403 errors in postPath, return to login screen
- Add logout button in About tab with auth role display
- Passphrase form shows generic error messages (no info leakage)
Phase 5: Documentation
- Update trx-client.toml.example with [frontends.http.auth] section
- All config fields with inline documentation and examples
- security notes about cookie settings
- Update README.md with HTTP Frontend Authentication section
- Role model explanation (rx vs control)
- Configuration example
- Security considerations for local, LAN, and remote deployments
- Architecture overview
UI Features:
- Login gate blocks main UI until authenticated
- Role badge shows authenticated status in About tab
- Error messages clear after 5 seconds
- Logout confirmation prevents accidental logouts
- Smooth transition from auth gate to main UI
All code compiles successfully. HTTP frontend build verified.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Add optional passphrase-based authentication with two roles (rx/control),
session management, auth middleware, and protected routes.
Phase 1: Config model with HttpAuthConfig struct, CookieSameSite enum,
validation logic for enabled auth requiring at least one passphrase.
Phase 2: Auth module with:
- AuthRole enum (Rx, Control)
- SessionRecord and SessionStore for in-memory session management
- AuthConfig at runtime
- /auth/login, /auth/logout, /auth/session endpoints
- Constant-time passphrase comparison for timing attack mitigation
Phase 3: Integration with:
- AuthMiddleware for route protection with public/read/control classification
- Server-side AuthState setup with cleanup task for expired sessions
- Auth endpoints registered in api.rs configure()
Sessions use 128-bit random IDs (hex-encoded), HttpOnly cookies, configurable
SameSite attribute. Auth is disabled by default to preserve current behavior.
All unit and integration tests passing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Refine map plotting and filter UX in HTTP frontend plugins.\n\n- support plotting multiple locator squares from FT8/WSPR messages\n- show locator lists in popup content as newline-separated entries\n- add WSPR map layer filter toggle and marker typing\n- style filter controls for strong dark/light mode contrast\n- keep themed behavior aligned with map and control updates\n\nCo-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Add dark/light mode selector below logo and wire theme-aware visuals.\n\n- add compact theme toggle control under header logo\n- support persistent dark/light theme switching\n- use emoji labels for theme toggle actions\n- make jog and audio level visuals theme-aware\n- add dark-mode map tile layer and live layer switching on theme changes\n- keep responsive behavior for header graph and controls\n\nCo-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Implement UI refinements for the HTTP frontend main and plugin views.\n\n- add dimmed header signal graph with live rendering and scale\n- make graph responsive, colorized by signal strength, and keep last 10s only\n- add APRS and WSPR text filtering, matching FT8 behavior\n- refine responsive layout for controls/map/header behavior\n- tune jog wheel/button sizing and mode selector height alignment\n\nCo-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Adjust responsive behavior and interaction details in the HTTP frontend.\n\n- switch signal measurement from sample-based to time-based averaging\n- move Transmit/Power below Mode+Tune on small viewports\n- add practical mobile breakpoints and width handling\n- resize and tune logo/top spacing/layout placement\n- make map height viewport-aware with adjustable minimum\n- improve FT8/WSPR control wrapping on small screens\n\nCo-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Refine main control interactions and presentation in the HTTP frontend.\n\n- remove frequency and mode Set buttons\n- apply mode changes immediately on picker change\n- place Mode/Tune/Transmit-Power controls in one horizontal row\n- align control labels vertically across that row\n- move and enlarge MHz/kHz/Hz selector beside frequency input\n- keep Enter-to-set frequency behavior\n- switch signal measurement to elapsed-time averaging\n- enlarge header logo 2x\n\nCo-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Add rigctl frontend visibility in HTTP status/about UI and refine frequency controls layout.\n\n- track rigctl listen endpoint and active rigctl client count in frontend runtime context\n- inject rigctl metadata into HTTP /events payload\n- show rigctl endpoint and rigctl client count in About tab\n- remove frequency Set button from UI\n- move MHz/kHz/Hz selector beside frequency input and enlarge it\n- center jog wheel row and keep Enter-to-set frequency behavior\n\nCo-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Improve rigctl interoperability with hamlib/WSJT-X and stabilize FT-817 PTT handling.\n\n- support extended '+' command replies\n- accept decimal and MHz-style frequency inputs\n- retry set_freq rounded to 10 Hz on CAT alignment errors\n- add compatibility handling for get_level probes\n- broaden PTT command parsing and aliases\n- derive PTT capability dynamically from snapshot data\n- improve dump_state/dump_caps compatibility behavior\n- move temporary rigctl diagnostics to debug level\n- make FT-817 set_ptt more reliable with unlock/clear and double-send\n\nCo-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Return setting=value lines with a done terminator for dumpcaps commands so Hamlib netrigctl_open can parse capabilities.
Add a unit test that verifies dumpcaps output formatting.
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Add min_freq_step_hz to RigCapabilities, set backend values, and make HTTP frontend parse suffix-less frequency input using the selected unit while snapping set/jog frequencies to rig step granularity.
Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Make the frequency field render and parse values in the currently selected unit (MHz/kHz/Hz), including immediate refresh when switching jog step.
Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Implement ALSA/CPAL stream auto-recovery by recreating input/output
streams after backend callback failures with bounded retry delay.
Also improve HTTP frontend resilience by polling /status on reconnect
and after SSE errors to refresh snapshot state after broken pipes.
Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Add pskreporter_status to shared rig snapshots and display it in the
HTTP frontend About tab.
Also include audio stream error log throttling to avoid repetitive ALSA
error flooding in backend logs.
Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Wire the WSPR period label to a live 120-second slot countdown so
it no longer stays at the placeholder value.
Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Reorder Plugins subtabs to align with the Overview plugin listing
(APRS, CW, FT8, WSPR), with Map moved to the end.
Also add a live FT8 period countdown indicator in the FT8 panel.
Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Expose a WSPR subtab in the Plugins view with its own controls and
message list, wire a dedicated wspr.js asset endpoint, and route WSPR
decode events to the new panel.
This makes WSPR visible in the HTTP frontend instead of reusing the
FT8 panel for WSPR messages.
Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Add a new trx-wspr crate that wraps wsprd slot decoding and parsed
results, wire it into the server audio pipeline, and emit WSPR decode
events to clients.
Also add frontend event routing for WSPR decode messages and temporary
rendering in the FT8 table until a dedicated WSPR panel is introduced.
Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Replace legacy global FrontendRegistry with bootstrap context adapter that
maintains backward compatibility while delegating to explicit context.
Changes:
- Create BOOTSTRAP_CONTEXT: OnceLock<Arc<Mutex<FrontendRegistrationContext>>>
- register_frontend(): delegates to bootstrap context
- is_frontend_registered(): reads from bootstrap context
- registered_frontends(): reads from bootstrap context
- spawn_frontend(): reads from bootstrap context
Result: Plugins continue calling global functions, but all operations
now route through the bootstrap context. Frontends receive context
parameter explicitly, enabling multiple concurrent instances.
Complete de-globalization achieved with full backward compatibility.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Update all three built-in frontends to accept Arc<FrontendRuntimeContext>
parameter in their spawn_frontend implementations:
- trx-frontend-http: passes context to serve function
- trx-frontend-http-json: passes context to serve function
- trx-frontend-rigctl: accepts context (minimal impact, no globals used)
Frontends are now ready to use context for audio channels, decode
channels, and auth tokens instead of accessing globals directly.
This completes the trait signature change for all frontends.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Update FrontendSpawner trait and related functions to accept and pass
Arc<FrontendRuntimeContext> parameter instead of relying on global
accessors for audio channels, decode channels, and auth tokens.
Changes:
- FrontendSpawner::spawn_frontend now accepts context parameter
- FrontendSpawnFn type signature includes context parameter
- FrontendRegistrationContext::spawn_frontend passes context to spawner
- Global spawn_frontend function accepts and passes context
This enables frontends to receive runtime data explicitly without
accessing globals, improving testability and supporting multiple
concurrent frontends with different contexts.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Create explicit context types for frontend registration and runtime:
FrontendRegistrationContext:
- register_frontend(name, spawner) - register a frontend
- is_frontend_registered(name) - check if registered
- registered_frontends() -> Vec<String> - list all frontends
- spawn_frontend(name, ...) -> DynResult - spawn a frontend
FrontendRuntimeContext (NEW):
- audio_rx: broadcast channel for audio RX
- audio_tx: mpsc channel for audio TX
- audio_info: watch channel for audio stream metadata
- decode_rx: broadcast channel for decoded messages
- aprs_history: Arc<Mutex<VecDeque>> for APRS decode history
- cw_history: Arc<Mutex<VecDeque>> for CW decode history
- ft8_history: Arc<Mutex<VecDeque>> for FT8 decode history
- auth_tokens: HashSet for authentication
Replaces global mutable state with explicit context that can be
threaded through bootstrap. Maintains global API for compatibility.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Use centralized trx-protocol crate for:
- parse_mode and envelope parsing
- command mapping (ClientCommand -> RigCommand)
- token validation via RegistryTokenValidator wrapper
RegistryTokenValidator maintains compatibility with global auth
registry pattern while leveraging shared protocol logic from
trx-protocol. Removes duplicate auth and codec functions.
No behavior changes, all tests pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Remove macOS AppKit frontend (trx-frontend-appkit) and related code:
- Delete appkit crate directory
- Remove appkit dependency and feature from Cargo.toml
- Remove appkit imports, main thread handling, and config from main.rs
- Remove AppKit config struct from config.rs
- Remove appkit section from example config
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>