Complete Phase 4: security hardening, player/playlist/admin UI, docs

Security:
- New internal/netguard package: podcast feed/enclosure fetching now
  refuses to dial non-public IPs (loopback/RFC1918/link-local/cloud
  metadata/CGNAT), validated per-connection including across redirects,
  closing an SSRF gap where a malicious or compromised feed URL could
  probe the server's internal network. Configurable via
  VIBESONIC_PODCASTS_ALLOW_PRIVATE_NETWORKS for intentional LAN feeds.
- Podcast episode downloads capped at 4GB (was unbounded, disk-exhaustion risk)
- Cover art decoding now rejects images above a 40-megapixel budget
  before full decode (decompression-bomb guard)
- HTTP server sets ReadHeaderTimeout (slowloris hardening)
- Admin folder-scan redirect now validated as same-site instead of
  trusting the raw Referer header (open-redirect fix)
- Legacy Subsonic token/salt auth now uses a constant-time comparison

Web UI completion:
- Persistent player: shuffle and repeat (off/all/one) controls, wired
  into queue advance/prev logic and persisted like other player state
- Admin user-permissions form: adminRole toggle (with a guard against
  demoting the last remaining admin) and per-user music-folder access
  checkboxes, backed by existing schema/enforcement that was previously
  unreachable from the UI
- Playlist M3U8 import/export

Docs: added docs/client-compatibility.md (honest tracking template —
no client testing has been performed), docs/deployment.md,
docs/security.md, docs/backup.md; refreshed README and cross-links;
added a footnote in docs/subsonic-compatibility.md distinguishing
spec-standard from VibeSonic-original OpenSubsonic extensions.

Also added Go fuzz tests for the external-auth CIDR/IP parser and the
LRC lyrics parser.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014r98AtcBbevpscWLsfwVvv
This commit is contained in:
2026-08-23 09:18:17 -05:00
co-authored by Claude Sonnet 5
parent 933ed31550
commit 789bf91eed
36 changed files with 1722 additions and 96 deletions
+10
View File
@@ -239,6 +239,16 @@ in `internal/subsonic/opensubsonic_core_test.go` fails the build if an
extension is ever registered without its handler actually existing, so
this list can't drift ahead of what's real.
Of the extensions below, `apiKeyAuthentication`, `formPost`, and
`songLyrics` come from the published OpenSubsonic extension list.
`getPodcastEpisode`, `indexBasedQueue`, `playbackReport`,
`topSongsByArtistId`, `transcodeOffset`, `transcoding`, and
`sonicSimilarity` are **VibeSonic-original** extensions — real,
implemented, and advertised the same way as any other extension, but
not part of the OpenSubsonic project's own spec, so don't assume
another OpenSubsonic server implements them just because it advertises
OpenSubsonic support in general.
| Extension | Versions | Endpoint(s) | Tested | Notes |
|---|---|---|---|---|
| `apiKeyAuthentication` | 1 | `tokenInfo`, `apiKey=` param on every endpoint | ✅ | Per-user named keys with plaintext shown once, SHA-256 hash stored, creation/last-used tracking, revocation (self or admin). `apiKey` conflicting with `u` returns error 43; an invalid/revoked key returns error 44. Managed at Settings → API Keys; admins see/revoke everyone's keys at `/admin/api-keys`. |