Registers HandleAlexaCertificate on POST /alexa/certificate. The handler
logs the device MAC from the request body and returns 501 Not
Implemented with a JSON error explaining that AWS IoT integration is
required to provision Alexa device certificates.
Adds voice.api.bose.io to both /etc/hosts domain lists in setup.go (DNS
intercept was already covered by the bose.io wildcard entry in dns.go).
Relates to https://github.com/gesellix/Bose-SoundTouch/discussions/84
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Endpoints:
- POST /streaming/music/musicprovider/{id}/trial/is_eligible (reuses
is_eligible handler)
- POST /bmx/tunein/v1/favorite/{stationID} with datastore persistence
(SaveTuneInFavorite)
- DELETE /bmx/tunein/v1/favorite/{stationID} (DeleteTuneInFavorite)
- POST /bmx/core02/svc-bmx-adapter-orion/prod/orion/token (anonymous
Orion token)
- GET /bmx-icons/* serving embedded static/media assets (media.bose.io)
- GET /ced/* serving embedded firmware index, release notes, and 10
app-help XMLs (downloads.bose.com)
Add media.bose.io and downloads.bose.com to DNS redirect lists (setup.go
both domain slices, dns.go shouldIntercept list, main.go getDomains
map). Document implemented endpoints in
tests/interactions_20260502_missing_external.md; mark rows 0246–0247 as
self/☑ in the interactions table.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces a standalone `soundtouch-backup` CLI with three subcommands:
- `all`: authenticates with the Bose cloud, backs up account data, then
reads device IPs from devices.xml and backs up each reachable speaker
- `cloud`: fetches account profile, devices, sources, presets, and full
endpoint from streaming.bose.com
- `local`: backs up each speaker via HTTP API (12 endpoints) and
optionally via SSH (individual files + /opt/Bose/etc/ and
/mnt/nv/BoseApp-Persistence/1/ directories)
Also centralises pkg/service/ssh → pkg/ssh so both the service and the
backup tool share the same SSH client; adds ReadFile and ReadDir
methods, and handles the firmware quirk where cat exits 1 on empty
files.
Output is a single dated .tar.gz or .zip archive.
Example flow:
```shell
gesellix@Mac Bose-SoundTouch % go run ./cmd/soundtouch-backup all --output _/cloud-backup --email user@example.com
Password:
Authenticating as user@example.com...
✓ Authenticated (account ID: 1234567)
✓ email address (107 bytes)
✓ devices (1492 bytes)
✓ sources (1111 bytes)
✓ presets (2585 bytes)
✓ full account (55037 bytes)
Found 2 device(s) in cloud account, attempting local backup...
✓ ST20: 12 files via HTTP
⚠ ST20: SSH skipped /etc/remote_services (Process exited with status 1)
⚠ ST20: SSH empty file /mnt/nv/remote_services
✓ ST20: 64 files via SSH
✓ ST10: 12 files via HTTP
⚠ ST10: SSH empty file /etc/remote_services
⚠ ST10: SSH skipped /mnt/nv/remote_services (Process exited with status 1)
✓ ST10: 48 files via SSH
Archive written: _/cloud-backup/soundtouch-backup-2026-05-02.tar.gz (141 files)
```
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add SpotifyClientID/Secret/RedirectURI and AmazonClientID/Secret/RedirectURI
fields to datastore.Settings for persistent storage
- Server: add amazonClientID/Secret/RedirectURI fields, SetAmazonConfig,
GetSpotifyConfig/GetAmazonConfig, ReinitSpotifyService/ReinitAmazonService,
and applyMusicServiceCredentials (called under lock from HandleUpdateSettings)
- GET /setup/settings: expose credential fields; mask secrets as "***" when set
- POST /setup/settings: apply credential updates and reinitialize services live
- applyPersistedSettings: fill in music credentials from settings.json when not
set via CLI/env (CLI takes precedence)
- Settings tab: replace read-only Spotify status with editable Client ID / Secret /
Redirect URI inputs for both Spotify and Amazon; save via existing Save button
- script.js: populate and collect the six new fields in fetchSettings/updateSettings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add cmd/mock-amazon/main.go (mirrors mock-spotify, uses testutils/amazon)
- Add amazon-mock service to docker-compose.yml (port 8082)
- Add AMAZON_CLIENT_ID/SECRET/TOKEN_URL/PROFILE_URL to docker-compose.ci.yml
- Add amazon_registration.http: registers account via /mgmt/amazon/callback
before the token-refresh test runs (mirrors spotify_registration.http)
- Update {{amazonRefreshToken}} in env to match mock response (Atzr|amazon-refresh-token)
- Log amazon-mock output on test failure in Makefile
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Groups (stereo pairs of ST10 speakers) were read-only — the GET endpoint
always returned an empty <group/>. Add POST /account/{account}/group,
POST /account/{account}/group/{groupId}, and DELETE
/account/{account}/group/{groupId} with datastore persistence, matching
the API shape observed in soundcork. The GET endpoint now reads live
group state from the datastore.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
feat: improve Bose SoundTouch parity, Spotify integration, and data
reliability
- Update XML marshaling for ServicePreset and ServiceRecent to match
Bose parity requirements.
- Add support for adding music sources via
`/streaming/account/{account}/source`.
- Implement HandleBoseAccountToken for Spotify OAuth code exchange and
token persistence.
- Implement atomic file writes in the datastore to prevent data
corruption.
- Add startup logic to initialize default sources for existing devices.
- Expand test coverage with new parity regression and Spotify
integration tests.
---------
Co-authored-by: Junie <junie@jetbrains.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
- Added detailed provider settings display to account overview
- Made 'Language' field editable with auto-save functionality (currently
only `en` and `de` available without actual effect on any UI or speaker
config)
- Made 'SPOTIFY - STREAMING_QUALITY' editable with descriptive quality
options
- ⚠️ this currently only writes the account config, but does not update
the actual speaker setting
- Improved account data persistence and error handling
- Added tests for new management API endpoints and data store changes
---------
Co-authored-by: Junie <junie@jetbrains.com>
Added 'Skip Mirror Endpoints' setting to allow specific requests like
`/oauth/device/*/music/musicprovider/15/token/cs3` to be handled
exclusively locally, even when mirroring is enabled. Updated
MirrorMiddleware to check against the skip list before performing
mirroring or parity logic. Exposed the setting via the Web UI Settings
tab and the CLI. Updated relevant tests to accommodate the configuration
changes.
Co-authored-by: Junie <junie@jetbrains.com>
- Enhance initial and full data synchronization to better align with
upstream services.
- Update data structures in 'pkg/models' to support missing fields
(e.g., SecretType for Spotify).
- Improve 'datastore' persistence logic for presets, recents, and
sources.
- Add comprehensive regression tests for sync and datastore operations.
- Update documentation on parity status and improvements.
Co-authored-by: Junie <junie@jetbrains.com>
Co-authored-by: Junie <junie@jetbrains.com>
- Add RFC-compliant wildcard certificates (*.api.bose.io, *.api.bosecm.com) for automatic API coverage
- Include additional Bose production domains (worldwide.bose.com, music.api.bose.com, bose-prod.apigee.net)
- Implement TLS certificate request logging and wildcard domain matching logic
- Add detailed TLS handshake debugging with connection state tracking
- Wrap TLS listener with logging to capture certificate selection and handshake failures
- Update documentation with wildcard certificate coverage and debugging features
- Normalize test data to use consistent local IP addresses
This enables automatic coverage of all current and future Bose API subdomains
while providing comprehensive TLS debugging for DNS redirection troubleshooting.
- Replace serial number-based directory structure with deviceId from device /info
- Extract migration logic to handle transition from old to new directory structure
- Fix directory resolution bug that prevented proper migration to deviceId-based paths
- Ensure all device data (Presets.xml, Sources.xml, Recents.xml) preserved during transition
- Add configurable migration with --migration-enabled and --migration-dry-run flags
- Update DeviceInfo.xml to reflect authoritative deviceId from device's /info endpoint
- Directory structure now: /devices/{deviceId}/ instead of /devices/{serialNumber}/
This aligns the directory structure with the device's self-declared identity
and ensures data consistency with the device's /info endpoint.
Implements the ability to mirror local requests to the official Bose
Cloud in the background, allowing for real-time comparison and parity
analysis between the emulated service and the original backend.
Core Changes:
- Implement `MirrorMiddleware` for asynchronous and synchronous mirroring.
- Add `Parity Logger` to detect discrepancies in status, headers, and body.
- Implement storage for parity mismatches in `data/parity_mismatches/`.
- Add `Internal Paths` configuration to exclude management traffic from logs.
Web UI & API:
- Add "Parity & Mirroring" tab to the Web UI for discrepancy analysis.
- Integrated "Internal Paths" configuration in Settings.
- Add "mirror" category filter to the Interactions UI.
- Implement endpoints for listing and clearing parity mismatches.
Infrastructure & Tools:
- Extend `setup.Manager` with `HTTPGet` override for reliable testing.
- Add CLI flags `--mirror-enabled`, `--mirror-endpoints`, and `--internal-paths`.
- Update `datastore.Settings` to persist mirroring and internal path configurations.
Tests:
- Add `pkg/service/handlers/mirror_test.go` for middleware verification.
- Update `TestProxySettingsAPI` and `TestRecordMiddleware` for new settings.
- Refactor `TestMigrationAndCA` to use mocked network calls (30x speedup).