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
This commit is contained in:
J3vb
2026-04-03 23:18:06 +02:00
parent dcbcc09777
commit c3a8aa477c
36 changed files with 1087 additions and 686 deletions
+8 -3
View File
@@ -25,14 +25,19 @@ import (
"aead.dev/minisign"
"github.com/owncord/server/config"
"github.com/owncord/server/syncutil"
"golang.org/x/mod/semver"
)
const (
defaultBaseURL = "https://api.github.com"
cacheTTL = 1 * time.Hour
defaultBaseURL = "https://api.github.com"
cacheTTL = 1 * time.Hour
// maxFetchBytes caps the response body read for checksum/signature files.
// Prevents a malicious or corrupted release asset from exhausting memory.
maxFetchBytes = config.MaxMessageBytes
errorCacheTTL = 5 * time.Minute
checksumAsset = "checksums.sha256"
signatureAsset = windowsServerBinary + ".sig"
@@ -673,7 +678,7 @@ func (u *Updater) fetchBody(ctx context.Context, url string) ([]byte, error) {
// Cap reads at 1 MiB — checksum and signature files are tiny text;
// this prevents a malicious or corrupted release asset from exhausting memory.
return io.ReadAll(io.LimitReader(resp.Body, 1<<20))
return io.ReadAll(io.LimitReader(resp.Body, maxFetchBytes))
}
// FindClientAssets scans the cached release assets for the Tauri NSIS