The separate J3vb/OwnCord-releases repo existed only because this repo was
private: it carried the AGPL source snapshot and provided a publicly-readable
update feed. Once this repo is public both roles collapse into its own Releases
page, so the mirror is pure redundancy.
- Server/config/config.go: github.repo default OwnCord-releases -> OwnCord.
This one default drives both the server self-update and the client
auto-update chain (tauri.conf.json updater.endpoints is empty, so the client
resolves through the server). No test pinned the old value.
- release.yml: drop the mirror step and its RELEASES_REPO_TOKEN guard, whose
AGPL/private-repo premise no longer holds. The existing Create GitHub Release
step is now the sole publish target. All 31 SHA pins verified intact.
- Repoint the README badge/download link, both SECURITY.md links, the
server-configuration table and sample, the system-overview diagram node and
the CHANGELOG note. SECURITY.md's advisory link is the load-bearing one: left
alone it would 404 once the mirror repo is deleted.
- README: Go 1.25+ -> 1.26+ (badge and prerequisite) to match the toolchain
actually required.
Deleting the mirror repo loses nothing: both repos' v1.1.0-alpha.2 carry
byte-identical asset sets, signatures and update manifest included.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Servers reachable via both a LAN IP and a public IP could only serve voice
on one of them: config.yaml accepts a single voice.node_ip and OwnCord
regenerates data/livekit.yaml on every start, discarding manual edits.
LiveKit has no multi-IP list, but it does support advertising internal host
candidates alongside the external mapping.
- New voice.advertise_internal_ip (OWNCORD_VOICE_ADVERTISE_INTERNAL_IP):
emits rtc.advertise_internal_ip: true so LAN clients get a reachable
candidate while remote clients keep using node_ip.
- livekit.yaml escape hatch: if the file exists without the auto-generated
marker header, OwnCord leaves it untouched, giving operators access to
every LiveKit option (ips.includes, interfaces, stun_servers, ...). The
generated header documents how to take ownership.
Closes#111
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwtnpHAoSFr1ZibQgQkNQK
Publish every release to the public OwnCord-releases repo with a full
source snapshot (AGPL section 6 for binary recipients), and make the
updater's repo coordinates configurable (github.owner/github.repo),
defaulting to OwnCord-releases. Both the server self-update and the
/client-update chain follow the new default, so deployed servers keep
updating after the source repo goes private.
The publish step fails closed: a private source repo with no
RELEASES_REPO_TOKEN aborts the release instead of silently shipping
binaries with no public source or update feed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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).