Commit Graph
4 Commits
Author SHA1 Message Date
J3vb c3a8aa477c fix: resolve 20 code review bugs across Rust, TypeScript, and Go
Critical/High Rust (Tauri client):
- BUG-140: replace .run() with .build() + RunEvent::Exit handler; native error dialog on startup failure
- BUG-141: eliminate PTT thread TOCTOU race with Mutex critical section; add AtomicBool shutdown and catch_unwind
- BUG-144: fix TOFU cert store corruption — read-before-write rollback restores previous fingerprint on save failure (all 3 write sites)
- BUG-145: add VK code range guard (1..=254) in is_key_down; fix cast to (state as i16) < 0
- BUG-147: replace bare spawns with JoinSet; abort_all + drain on exit; unconditional closed event
- BUG-150: add CRLF guard in handle_connection before header rewriting
- BUG-151: wrap header read loop in tokio::time::timeout(10s)
- BUG-158: extract CERTS_STORE/SETTINGS_STORE to constants.rs (eliminate 3 duplicates)
- HIGH-2: PTT thread self-cleanup uses unwrap_or_else defensive pattern
- HIGH-4: ws_send distinguishes Full vs Closed errors; warn log on backpressure

Critical/High TypeScript (Tauri client):
- BUG-142: join-generation counter prevents stale connectAndSetup completions
- BUG-143: replace 8 mutable LiveKit session fields with discriminated union SessionState
- BUG-146: 60s token refresh deadline; cleared on reply or voice leave
- BUG-148: ResizeObserver hoisted to outer scope; disconnect() in destroy() before ac.abort()
- BUG-152: dismissSignal.aborted guard already present (no change needed)
- BUG-153: measureRendered split into two-pass read-then-write; eliminates per-message reflow
- BUG-154: WS dedup cache batch-evicts to 80% on overflow (amortised O(1))
- BUG-157: pendingUpdates replaced with coalesced function-composition slot (O(1) queue depth)

Go server:
- BUG-149: safe two-value type assertion in getOutboundIP with localhost fallback
- BUG-155: broadcast buffer 256→1024; broadcastDrops atomic counter exposed in /api/v1/metrics
- BUG-156: LiveKitHealthCheck and implementations accept ctx context.Context; all call sites pass r.Context() (12 files)
- BUG-159: MaxMessageBytes constant in config/constants.go; replaces 1<<20 literals in serve.go and updater.go
- HIGH-1: cert store rollback reads old value before write; restores previous cert on save failure

All validation passes: go build, go vet, cargo check, npm typecheck
2026-04-03 23:18:06 +02:00
jevb 447a4543e7 chore: remaining server changes (code quality, go mod tidy)
Go mod tidy, minor server-side adjustments from security verification
and code quality cleanup pass.
2026-04-01 11:38:33 +02:00
jevb 4c4526e539 fix: security hardening — 45 issues from full-project Copilot audit
Critical (6):
- C1: SQL injection in VACUUM INTO backup path — strict character allowlist
- C2: Unlimited binary download in updater — 500MB LimitReader
- C3: JSON injection in SSE log stream — json.Marshal instead of concat
- C4: CSS injection via custom themes — reject () and {} in values
- C5: Silent DM message loss — error response on participant lookup failure
- C6: LiveKit URL credential leak — strip creds from diagnostics endpoint

High (11):
- H1: DB errors no longer trigger login rate-limit lockout
- H2: Permission fetch failure returns 500, not empty channel list
- H3: TOCTOU race on duplicate WS — atomic check-and-register in hub
- H5: LiveKit webhook verifies voice channel match (already implemented)
- H7: Server host address validated before storage (hostname regex)
- H8: WS message deduplication on reconnect replay (1000-entry Set)
- H9: Admin setup endpoint rate limited (5/min/IP)
- H10: Backup responses return filename only, not full path
- H11: Update binary recovery failure now alerts admin

Medium (17):
- M1: MIME type from magic bytes, not client header
- M3: Nil guard on DM broadcast recipient
- M5: LiveKit process run-done channel race fixed
- M6: Backup restore calls fsync before close
- M7: Partial download file cleaned up on error
- M8: Admin CSP uses nonce instead of unsafe-inline
- M9: Client rate limiter enforced for presence_update
- M10: Voice joinedAt not reset on double-join
- M11: Unread count skips increment during reconnect replay
- M13: Category type uses exact match, not substring
- M14: Storage LimitReader off-by-one fixed
- M15: GitHub token only sent to GitHub hosts
- M16: Content-parser ReDoS regex replaced with split approach
- M17: Audio device switch error handling added

Low (11):
- L1: CORS uses configured origins instead of wildcard
- L2: HSTS header added when TLS enabled
- L3: Consistent JSON error responses across all endpoints
- L4: File modtime from stat, not time.Now()
- L5: Malformed invite JSON returns 400
- L6: TouchSession failure logged at warn
- L8: MessageInput timers cleared on destroy
- L9: Log persistence flush errors caught
- L10: Credential save failure surfaced to user
- L11: Case-insensitive asset name matching in updater

Found by GitHub Copilot full-project review (claude-sonnet-4.6 + claude-haiku-4.5).
2026-03-29 12:35:04 +02:00
jevb f30d267fda feat: add observability, debugging, and diagnostics across all layers
Phase 1 — Server-side logging:
- Enhance HTTP request logging with client_ip, bytes, req_id
- Enrich WS disconnect logs with duration, msgs received/sent/dropped,
  voice channel, and last error
- Add structured logging to LiveKit webhook events
- Enrich voice join/leave logs with username, remote addr, quality,
  channel occupancy
- Add channel_id to voice control debug logs

Phase 1 — Client log persistence:
- New logPersistence.ts: rotating JSONL files in appLogDir with
  5-day retention, 2s debounced flush, append mode
- Wire into app startup with flush on beforeunload
- Scope all new FS capabilities to $APPLOG/**

Phase 1 — Rust proxy logging:
- Replace eprintln! with structured log crate (info/warn/error/debug)
  in livekit_proxy.rs and ws_proxy.rs
- Add env_logger with try_init for safe initialization
- Log TLS handshakes, TOFU checks, connection lifecycle, byte counts

Phase 1 — Cache management UI:
- Add Clear Image Cache, Clear Log Files, and Clear All Cache & Restart
  buttons to Settings > Advanced with confirmation dialog

Phase 2 — LiveKit ICE and lifecycle logging:
- Log ICE candidate types (host/srflx/relay) and selected candidate pair
  on every voice connect and auto-reconnect
- Add room lifecycle event handlers: Reconnecting, Reconnected,
  SignalReconnecting, MediaDevicesError, ConnectionQualityChanged
- Expose ICE connection state in getSessionDebugInfo()

Phase 2 — WebSocket reconnection logging:
- Structured reconnection logs with host, attempt, lastSeq
- Log reconnect success with attempt count
- Detailed connection state transitions (open/close with context)

Phase 2 — Server diagnostics endpoint:
- GET /api/v1/diagnostics/connectivity (auth required)
- Returns server info, LiveKit health/URL/node_ip, client remote_addr,
  and private network detection
2026-03-28 20:42:37 +01:00