What's New
Security Hardening
- WebSocket authentication — connections require
Sec-Fetch-Site: same-origin(browser) or validX-Api-Key(external clients) before upgrade - SSRF protection on notification plugin HTTP clients (Discord, Slack) via safedialer
- Path traversal protection on import endpoint via shared
pathutil.ValidateContentPath - API key masking — config endpoint returns masked key; separate
/api/v1/system/config/apikeyendpoint for reveal - Email header injection prevention — CRLF stripping in SMTP headers
- Restore endpoint body limit — 500 MiB override prevents the global 1 MiB limit from blocking database restores
- VACUUM INTO fix — proper SQL quoting prevents injection in backup paths
- Configurable TLS verification for Plex/Emby/Jellyfin media server connections
- Radarr import credentials moved from
localStoragetosessionStorage - Release URL validation —
hrefattributes only render forhttp:///https://URLs - Dead auth middleware removed (had timing-leak vulnerability, was unused)
Code Quality
- Shared
dbutilpackage — extractedBoolToInt,MergeSettings,IsUniqueViolation(eliminated 6+ copy-pasted implementations) IsUniqueViolationnow uses SQLite error code (2067) instead of fragile string matching- History filtering pushed into SQL — 3 new filtered queries replace "fetch 1000, filter in Go" pattern
- RSS title matching uses word-boundary alignment to prevent false positives on short titles (e.g., "It")
- Download client auth race fixed — qBittorrent and Deluge
ensureAuthnow holds the lock during the entire login flow CountCutoffUnmetoptimized — skips unnecessary Movie object conversion and sorting when only a count is needed- Releases handler double-fetch eliminated — reuses movie from first DB lookup
- Notification event filtering — proper JSON unmarshal replaces substring matching
- Queue item lookup — direct
GetGrabByIDreplaces O(n) list scan - Dead
CutoffCounterinterface removed
In-Memory Log Viewer
A complete log viewing system accessible from Settings > System > Logs.
- Ring buffer — thread-safe circular buffer holding the last 1,000 log entries in memory
- TeeHandler — custom
slog.Handlerthat wraps the existing logger and captures entries without affecting normal log output GET /api/v1/system/logs— new endpoint with?level=(debug/info/warn/error) and?limit=query parameters- Frontend — level filter dropdown, color-coded level badges, scrollable table with sticky headers, expandable structured fields, 10-second auto-refresh
- 8 new tests (ring buffer + tee handler)
Full Changelog: v0.3.0...v0.4.0