Update 111 test files to match security hardening changes:
- acceptInvalidCerts now conditional on allowSelfSigned
- Credential store no longer returns passwords over IPC
- File type validation uses strict MIME allowlist
- Search rate limiter timing adjustments
- Dispatcher cleanup mock additions
- Audio elements screenshare mute preservation
2962 tests passing across 110 test files.
Status Picker (T-061): Wire existing StatusPicker to UserBar with WS
presence updates. Disabled when offline.
Screen Share (T-024): Add share button to VoiceWidget controls with
cyan glow active state and aria-pressed toggle.
User Profile Popup (T-059): New 300px anchored popover with edge-flip
positioning, focus trap, and deleted user handling.
DM Profile Sidebar (T-062): New 340px right panel with slide-in
animation, local Note field, toggle via DM header click.
24 new unit tests across 4 test files.
Replace 3 empty .catch(() => {}) blocks with log.warn() calls in
notifications.ts, ws.ts, and window-state.ts.
Remove SoundboardPlayPayload from types.ts — full soundboard feature
deferred to TODOS.md. Dead type was misleading for contributors.
Fix 3 functions (verifyTotp, uploadFile, getHealth) that hardcoded
danger.acceptInvalidCerts: true unconditionally, bypassing the user's
allowSelfSigned setting. Now conditional like doFetch.
TOTP codes, file uploads, and health checks no longer skip TLS
verification unless the user explicitly opts into self-signed certs.
CRITICAL (5):
- Hub panic recovery now calls h.Stop() after 3 panics (ws/hub.go)
- Ring buffer EventsSince returns non-nil empty slice for current seq (ws/ringbuffer.go)
- PTT event listener stores unsubscribe handle to prevent leak (ptt.ts)
- verifyTotp respects config.allowSelfSigned instead of hardcoding (api.ts)
- ptt_listen_for_key uses spawn_blocking to avoid thread pool starvation (ptt.rs)
HIGH - Server (13):
- TOTP rate-limit checked after body decode; counters reset on success
- TOTP enable returns 409 if already enabled (must disable first)
- Global search pre-computes accessible channel IDs for FTS WHERE clause
- DeleteAccount queries roles by name instead of hard-coded IDs
- BackupToSafe uses absClean in VACUUM INTO
- Voice camera slot uses atomic EnableCameraIfUnderLimit DB method
- readPump snapshots voiceChID before unregister for TOCTOU safety
- Voice join sets state after token send; rollback takes broadcast flag
- Updater download uses probe pattern instead of overflow write
- Webhook checks Authorization header before reading body
- Storage.Save adds fsync and fixes double-close
- Default WS origin denies cross-origin (was: accept all)
HIGH - Client (6):
- WS reconnect uses generation counter to discard stale events
- AudioPipeline uses generation counter against stale worklet callbacks
- Screenshare mute state preserved across reconnect (not full leave)
- handleVoiceToken uses iterative loop instead of unbounded recursion
- store.ts re-entrancy guard with pending update queue
- Notification AudioContext cleaned up on logout
Reviewed by 4 parallel agents across Server Core, Server Realtime,
Client & Tauri, and Security. 55 total findings; 24 CRITICAL+HIGH
fixed here, 31 MEDIUM+LOW tracked in vault backlog (T-265–T-295).
- Video grid: sync stream type attribute on updates, add screenshare data attribute
- Dispatcher: handle voice_token messages, improve video track event handling
- LiveKit session: add video track publication support
- Hub: stale client timeout cleanup, improved voice state management
- Voice join/leave: context propagation, better error handling
- Livekit webhook: structured event handling with room/participant data
- Server DB: voice query improvements, new test coverage
- WS integration tests: expanded coverage for voice and LiveKit flows
- Gitignore: add internal dev tools directory, owncord-server.exe
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace CSS grid-template-columns with a JS layout calculator that
tries every column count and picks the arrangement maximising tile
area while preserving exact 16:9 ratio. ResizeObserver triggers
recalculation on container resize. Tests updated to exercise the
pure computeGridLayout function directly.
- Add hover/focus preview for remote voice users' camera/screenshare
streams in the voice channel sidebar. Preview reuses already-subscribed
LiveKit tracks (zero bandwidth cost). Full-width 16:9 preview with
neon border-glow treatment matching DESIGN.md.
- Fix screenshare focus bug: clicking a screensharing user now correctly
focuses the screenshare tile (userId + SCREENSHARE_TILE_ID_OFFSET)
instead of the camera tile.
- Extract SCREENSHARE_TILE_ID_OFFSET to shared lib/constants.ts (was
duplicated in VideoModeController.ts and MainPage.ts).
- New lib/streamPreview.ts module: attachStreamPreview() with 300ms
debounce, track renegotiation detection, autoplay failure handling,
scroll collapse, keyboard accessibility (focusin/focusout), ARIA
labels, and full AbortSignal cleanup.
- Placeholder shows "Join to preview" with click-to-join behavior.
Live video preview is also clickable to watch the stream.
- 22 new tests (16 stream-preview + 6 channel-sidebar).
Fix multiple bugs across settings tabs (AppearanceTab theme restoration,
AdvancedTab testability, LogsTab refresh, VoiceAudioTab device listing),
harden embeds/media/attachments with cache validation, add logPersistence
rotation logic, and add 8 new test files with expanded test cases for
existing tests. Brings client test coverage from ~68% to ~72%.
- Fix race condition: handleDisconnected no longer nulls the room during
initial connect, allowing the retry loop to complete all 3 attempts
- Fix TLS proxy port: default to 443 instead of 8443 when server host
has no explicit port (servers behind nginx/reverse proxy)
- Fix cert store key: strip :443 suffix so LiveKit proxy fingerprint
lookup matches ws_proxy's stored key format
- Add node_ip config option for LiveKit WebRTC ICE candidates (required
for remote users behind NAT)
- Add resolved URL to all connection error/retry/reconnect logs for
easier debugging
- Add diagnostic logging to resolveLiveKitUrl showing which path was
taken (direct/proxy/passthrough)
Fix accent color not applying on startup due to localStorage key mismatch
in restoreTheme() (was reading "owncord:pref:" instead of "owncord:settings:").
Redesign settings overlay as a centered floating panel with blurred backdrop,
rounded corners, scale animation, and click-outside-to-close.
- Add auto-login toggle on server profiles (lightning bolt icon, single-server
enforcement). On startup, auto-connects with saved credentials; falls back
to login form on failure or 2FA.
- Add online_users field to /api/v1/health endpoint (Go server) and display
user count on server cards in the login page.
- Add periodic health check retry every 15s while on ConnectPage so offline
servers update when they come back online.
- Move DM section above text channels in sidebar, limit to 3 visible DMs
with "View all messages" button for overflow.
- DMs with new messages bubble to top of the list automatically.
- Add total unread badge on DM header (visible even when collapsed).
- Member list collapses to just header bar; state persisted across sessions.
Security fixes (from multi-reviewer code review):
- Add DM participant auth checks to channel_focus, typing, and REST
message endpoints — prevents unauthorized access to DM channels
- Fix TOCTOU race in GetOrCreateDMChannel using IMMEDIATE transaction
- Validate YAML credentials before LiveKit config interpolation
- Add CSS variable injection prevention in custom theme loader
- Validate localStorage JSON before unsafe type casts
LiveKit stability:
- Track remote mic audio elements for cleanup on abnormal disconnect
- Remove duplicate token refresh timer scheduling
- Add .catch() to all floating applyMicMuteState promises
- Clear reconnectAc after async post-connect work completes
- Fix double cmd.Wait() race in LiveKit process Stop()
- Reorder voice_join guards: validate channel before livekit==nil check
- Add startup warning for external LiveKit webhook CIDR mismatch
DM system fixes:
- Emit dm_channel_close WebSocket event from REST close handler
- Re-open DM for caller when channel already exists
- Fix unread count incrementing for own messages and active DMs
- Reset channelBeforeDm after Back navigation (stale state bug)
New feature:
- Voice call duration timer in VoiceWidget (MM:SS / HH:MM:SS elapsed)
- Accent color restored on app startup (was only applied in settings)
Test infrastructure:
- Add DM tables to all test schemas (hubTestSchema)
- Inject test LiveKit client in voice handler tests (fixes 28 failures)
Three DM display fixes:
- Chat header now shows @ prefix and username for DM channels instead of #
- Empty message state shows DM-appropriate welcome text instead of channel welcome
- New DMs are added to dmStore on creation so they appear in the sidebar immediately