598abeb8cfd550008c4ea3442ae3dc4a2c259d3b
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9d324ab2d0 |
feat: Minstrel backs itself up nightly to a folder or an S3 bucket, off until an admin switches it on (#6773)
release / integration (push) Failing after 3m29s
release / web (push) Failing after 15s
release / govulncheck (push) Successful in 16s
release / go (push) Failing after 41s
release / android (push) Successful in 4m7s
release / Attach APK to the Release (tag releases only) (push) Canceled after 0s
release / Build + push container image (push) Canceled after 0s
release / Verify release artifacts (tag releases only) (push) Canceled after 0s
release / Build signed APK (push) Canceled after 5m34s
Admin › Backups shows a verdict first (off, not set up, waiting, backed up, overdue, failing since when), Back up now, Test destination and the latest runs, with the settings beside them. - backup.Service: one run at a time, bounded at 30 minutes; the schedule ticks every 5 minutes, catches up a slot missed while the server was down, and retries a failure after an hour and then after as long as it has been failing. Runs are recorded in backup_runs, pruned after 90 days; a run cut off by a shutdown is marked failed at the next start. - A folder destination writes database/minstrel-<UTC stamp>.tar and refuses a folder that isn't there. An S3 destination stages the file, hashes it, and uploads it under database/ through a throttled reader (4 MiB/s by default, 0 for no limit). - Test destination checks the form as typed and only lists. - The bucket secret is sealed like every stored credential; backup_settings and backup_runs are left out of the backup itself. - The panel polls only while a run is going, capped at the run limit plus five minutes. The music switch named in the task is left to #6774, so no control ships that does nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
a8a2d20307 |
feat: stored credentials are sealed at rest, so a copy of the database alone reveals none of them (#6767)
release / govulncheck (push) Successful in 28s
release / web (push) Successful in 1m18s
release / go (push) Successful in 1m35s
release / android (push) Successful in 4m45s
release / Build signed APK (push) Successful in 4m57s
release / integration (push) Successful in 5m3s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 1m14s
release / Verify release artifacts (tag releases only) (push) Skipped
Minstrel keeps credentials it has to read back: indexer, Prowlarr and download-client keys and passwords, the AcoustID key, cover-art and tag provider keys, the SMTP password, and each user's ListenBrainz token and Subsonic password. They were stored in the clear; they are now sealed with AES-256-GCM under a per-column HKDF key derived from the stream secret, each value bound to its row. - internal/secret: Seal/Open/Reveal, and Columns, the one list of sealed columns (a backup will leave them out). Install takes the master key at startup; SealStored seals any value still in the clear, so an existing database is brought over in place on the first boot. - Every write seals and every read opens: acquire (one read path, getService / usableServices), acoustid settings, SMTP, ListenBrainz, Subsonic auth and password generation, cover-art and tag provider settings. - A value that does not open (the stream secret changed) is logged and reads as unset, to be entered again in Settings. docs/security.md says so. - Tests: secret unit tests (wrong owner/purpose/key, malformed, no key), a SealStored integration test over all eight columns plus a schema check that each listed column exists, and the existing tests now assert sealed storage. dbtest installs a test key for integration tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
94a9c8cbe3 |
chore(deps): SvelteKit 3 with adapter-static 4 and TypeScript 6, full-tree npm audit (#5021)
Merges Renovate's kit 3 (PR #149) and adapter-static 4 (PR #148) bumps, plus the migration they need. The mechanical part is `sv migrate sveltekit-3`, run one task at a time and reviewed: - svelte.config.js is gone. Its options move into sveltekit() in vite.config.ts, exported as kitOptions so vitest.config.ts runs the same kit setup, including the $test-utils alias the tests import. - $lib becomes #lib through package.json "imports". There is no src/lib/index, so only the "#lib/*" entry is kept. - tsconfig extends $app/tsconfig. - Peer floors raised to kit 3's requirements: svelte ^5.57.1, vite ^8.0.12, svelte-check ^4.7.5. By hand, from the codemod's list of non-automated tasks: - goto's replaceState option is now replace; keepFocus becomes reset: false. For the search typeahead, reset: false also stops the scroll-to-top, which is wanted while typing. - The test setup mocks drop pushState/replaceState and $app/paths base/assets, which kit 3 removed, and mock refreshAll in place of invalidateAll. - The other flagged files only read page.url or goto internal routes, so they needed no change. TypeScript goes to ^6, not the ^7 Renovate offers: kit 3 declares typescript ^6 as a peer and svelte-check 4.7 accepts ^5 || ^6. Move to 7 once both accept it. With Tailwind 4 and kit 3 in, `npm audit` on the whole tree reports 0, so the web lane now audits every dependency rather than only what ships to browsers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
edd9a3a6db |
fix(auth): the Subsonic password is generated, never the login password (M462 #5026)
release / govulncheck (push) Successful in 39s
release / web (push) Successful in 1m8s
release / go (push) Successful in 1m30s
release / integration (push) Successful in 4m37s
release / android (push) Successful in 5m56s
release / Build signed APK (releases and dev) (push) Successful in 5m55s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 1m23s
release / Verify release artifacts (tag releases only) (push) Skipped
`minstrel admin reset-password` copied the new login password into subsonic_password, which is stored in plain text because Subsonic t/s sign-in needs it. Every account recovered through the CLI had its login password readable in the database, and changing the password later left the copy behind. - reset-password now changes only password_hash. - Migration 0064 clears every subsonic_password, removing the copies. - Settings gets a Subsonic password card: the server generates a random password, shows it once, and it can be regenerated or turned off (GET/POST/DELETE /api/me/subsonic-password, audited). Generated rather than user-chosen so it can never be a reused password. - docs/security.md describes the separate password instead of the known issue. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
522503e011 |
docs: hosting guide and security notes; README setup and HTTPS guidance (M462 #4986)
- docs/hosting.md: LAN vs internet; binding 4533 to 127.0.0.1 behind an HTTPS proxy (Caddy example, no buffering, long read timeouts for SSE and streams); the Client IP detection hop count (default 1, so 0 with no proxy or clients can forge X-Forwarded-For); the public address that password-reset links need; finding the setup token. - docs/security.md: sessions, API keys, rate limits, headers and CSP; why CSRF rests on SameSite=Strict plus JSON-only cookie writes; the Subsonic password column, including the known issue that admin reset-password writes the login password there (#5026); why Android allows plain HTTP; the CI publish gate. - README: keeps the LAN-first port mapping with a pointer for internet hosts, scopes "plain http:// is fine" to trusted networks, explains the setup token in first-run step 1, and links both docs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |