mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
fix: resolve 24 critical and high issues from full code & security review
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).
This commit is contained in:
@@ -124,7 +124,12 @@ func (s *Storage) Save(uuid string, r io.Reader) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating file %s: %w", dst, err)
|
||||
}
|
||||
defer f.Close() //nolint:errcheck
|
||||
closed := false
|
||||
defer func() {
|
||||
if !closed {
|
||||
_ = f.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
// Reconstruct the full stream: header bytes we already read + remainder.
|
||||
maxBytes := int64(s.maxSizeMB) * 1024 * 1024
|
||||
@@ -138,14 +143,17 @@ func (s *Storage) Save(uuid string, r io.Reader) error {
|
||||
if written == maxBytes {
|
||||
var probe [1]byte
|
||||
if n, _ := full.Read(probe[:]); n > 0 {
|
||||
// File exceeds limit — remove the partial write and reject.
|
||||
_ = f.Close()
|
||||
closed = true
|
||||
if removeErr := os.Remove(dst); removeErr != nil {
|
||||
slog.Error("storage: failed to remove oversized file", "path", dst, "err", removeErr)
|
||||
}
|
||||
return fmt.Errorf("file exceeds maximum size of %d MB", s.maxSizeMB)
|
||||
}
|
||||
}
|
||||
if syncErr := f.Sync(); syncErr != nil {
|
||||
return fmt.Errorf("syncing file %s: %w", dst, syncErr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user