mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 16:46:17 +00:00
fix(setup): seed audionotification host(s) into /etc/hosts for /speaker TTS
soundcork#104 confirms speakers validate the /speaker audio-notification app_key against audionotification.api.bosecm.com (100 calls/day on real Bose). Our /v1/auth shim accepts it, but a host-seeded migration only worked if the speaker resolved that host to us. DNS interception already covers it (bosecm.com substring), but the /etc/hosts migration domain list did not — so the speaker method would fail on hosts-based setups. Seed both audionotification.api.bosecm.com and the dev variant (audionotificationdev.api.bosecm.com; firmware may use either) into the migration /etc/hosts lists, and update the mock fixtures/docs accordingly. /v1/auth is path-based, so it already answers regardless of which host the speaker thinks it is calling. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
80cfb03f6e
commit
382c68d2b6
@@ -339,9 +339,15 @@ box. soundtouch-web proxies it to the service, so start it with `--service-url`
|
||||
|
||||
### Notes and limitations
|
||||
|
||||
- **The `app_key` still applies.** Cloud TTS does not bypass the `/speaker`
|
||||
requirement; without a working `app_key` the speaker will reject playback.
|
||||
- **Model support** is the same as the direct path (primarily ST-10 Series III).
|
||||
- **`app_key` validation is handled automatically (speaker method).** The
|
||||
speaker validates the key by calling `GET /v1/auth` on Bose's audio
|
||||
notification host (`audionotification.api.bosecm.com`, and a `…dev…` variant),
|
||||
which AfterTouch intercepts (DNS substring match on `bosecm.com`, plus
|
||||
`/etc/hosts` seeding during migration) and answers `200`. So any non-empty
|
||||
`app_key` works; you don't need a real Bose-issued key. The `radio` method
|
||||
needs no `app_key` at all.
|
||||
- **Model support** for the `speaker` method is the same as the direct `/speaker`
|
||||
path (primarily ST-10 Series III). Use `--method radio` on models without it.
|
||||
- **Reachability:** the speaker must be able to reach the service's
|
||||
`/media/tts/{id}` URL. The service builds it from its configured `server-url`.
|
||||
- Synthesized clips are cached in memory for a short time and identical requests
|
||||
|
||||
@@ -412,7 +412,7 @@ func (m *mockSSH) Run(command string) (string, error) {
|
||||
m.runCount++
|
||||
if m.runCount > 1 {
|
||||
// Return updated hosts for verification
|
||||
return "127.0.0.1 localhost\n192.0.2.100\tstreaming.bose.com\n192.0.2.100\tupdates.bose.com\n192.0.2.100\tstats.bose.com\n192.0.2.100\tbmx.bose.com\n192.0.2.100\tcontent.api.bose.io\n192.0.2.100\tevents.api.bosecm.com\n192.0.2.100\tbose-prod.apigee.net\n192.0.2.100\tworldwide.bose.com\n192.0.2.100\tmedia.bose.io\n192.0.2.100\tdownloads.bose.com\n192.0.2.100\tvoice.api.bose.io", nil
|
||||
return "127.0.0.1 localhost\n192.0.2.100\tstreaming.bose.com\n192.0.2.100\tupdates.bose.com\n192.0.2.100\tstats.bose.com\n192.0.2.100\tbmx.bose.com\n192.0.2.100\tcontent.api.bose.io\n192.0.2.100\tevents.api.bosecm.com\n192.0.2.100\taudionotification.api.bosecm.com\n192.0.2.100\taudionotificationdev.api.bosecm.com\n192.0.2.100\tbose-prod.apigee.net\n192.0.2.100\tworldwide.bose.com\n192.0.2.100\tmedia.bose.io\n192.0.2.100\tdownloads.bose.com\n192.0.2.100\tvoice.api.bose.io", nil
|
||||
}
|
||||
return "127.0.0.1 localhost", nil
|
||||
}
|
||||
|
||||
@@ -426,6 +426,13 @@ func (m *Manager) populatePlannedNetworkConfig(summary *MigrationSummary, _, tar
|
||||
"bmx.bose.com",
|
||||
"content.api.bose.io",
|
||||
"events.api.bosecm.com",
|
||||
// app_key validation for /speaker audio notifications (TTS). Without
|
||||
// these redirects the speaker validates against the dead Bose cloud and
|
||||
// reports an invalid app key. Both the prod and dev hosts are seeded
|
||||
// (firmware may use either). DNS interception already covers them via
|
||||
// the bosecm.com substring; seed here for /etc/hosts migrations too.
|
||||
"audionotification.api.bosecm.com",
|
||||
"audionotificationdev.api.bosecm.com",
|
||||
"bose-prod.apigee.net",
|
||||
"worldwide.bose.com",
|
||||
"music.api.bose.com",
|
||||
@@ -1424,6 +1431,13 @@ func (m *Manager) migrateViaHosts(deviceIP, targetURL string) (string, error) {
|
||||
"bmx.bose.com",
|
||||
"content.api.bose.io",
|
||||
"events.api.bosecm.com",
|
||||
// app_key validation for /speaker audio notifications (TTS). Without
|
||||
// these redirects the speaker validates against the dead Bose cloud and
|
||||
// reports an invalid app key. Both the prod and dev hosts are seeded
|
||||
// (firmware may use either). DNS interception already covers them via
|
||||
// the bosecm.com substring; seed here for /etc/hosts migrations too.
|
||||
"audionotification.api.bosecm.com",
|
||||
"audionotificationdev.api.bosecm.com",
|
||||
"bose-prod.apigee.net",
|
||||
"worldwide.bose.com",
|
||||
"media.bose.io",
|
||||
|
||||
@@ -154,7 +154,7 @@ func TestMigrateViaHosts(t *testing.T) {
|
||||
if command == "cat /etc/hosts" {
|
||||
// Handle both initial read and verification read
|
||||
if len(runCalls) > 2 { // Rough heuristic: verification happens after upload
|
||||
return "192.0.2.100\tstreaming.bose.com\n192.0.2.100\tupdates.bose.com\n192.0.2.100\tstats.bose.com\n192.0.2.100\tbmx.bose.com\n192.0.2.100\tcontent.api.bose.io\n192.0.2.100\tevents.api.bosecm.com\n192.0.2.100\tbose-prod.apigee.net\n192.0.2.100\tworldwide.bose.com\n192.0.2.100\tmedia.bose.io\n192.0.2.100\tdownloads.bose.com\n192.0.2.100\tvoice.api.bose.io", nil
|
||||
return "192.0.2.100\tstreaming.bose.com\n192.0.2.100\tupdates.bose.com\n192.0.2.100\tstats.bose.com\n192.0.2.100\tbmx.bose.com\n192.0.2.100\tcontent.api.bose.io\n192.0.2.100\tevents.api.bosecm.com\n192.0.2.100\taudionotification.api.bosecm.com\n192.0.2.100\taudionotificationdev.api.bosecm.com\n192.0.2.100\tbose-prod.apigee.net\n192.0.2.100\tworldwide.bose.com\n192.0.2.100\tmedia.bose.io\n192.0.2.100\tdownloads.bose.com\n192.0.2.100\tvoice.api.bose.io", nil
|
||||
}
|
||||
return "127.0.0.1 localhost", nil
|
||||
}
|
||||
@@ -232,7 +232,7 @@ func TestMigrateViaHosts_UpdateExisting(t *testing.T) {
|
||||
runCount++
|
||||
if command == "cat /etc/hosts" {
|
||||
if runCount > 1 {
|
||||
return "127.0.0.1 localhost\n192.0.2.100\tstreaming.bose.com\n192.0.2.100\tupdates.bose.com\n192.0.2.100\tstats.bose.com\n192.0.2.100\tbmx.bose.com\n192.0.2.100\tcontent.api.bose.io\n192.0.2.100\tevents.api.bosecm.com\n192.0.2.100\tbose-prod.apigee.net\n192.0.2.100\tworldwide.bose.com\n192.0.2.100\tmedia.bose.io\n192.0.2.100\tdownloads.bose.com\n192.0.2.100\tvoice.api.bose.io", nil
|
||||
return "127.0.0.1 localhost\n192.0.2.100\tstreaming.bose.com\n192.0.2.100\tupdates.bose.com\n192.0.2.100\tstats.bose.com\n192.0.2.100\tbmx.bose.com\n192.0.2.100\tcontent.api.bose.io\n192.0.2.100\tevents.api.bosecm.com\n192.0.2.100\taudionotification.api.bosecm.com\n192.0.2.100\taudionotificationdev.api.bosecm.com\n192.0.2.100\tbose-prod.apigee.net\n192.0.2.100\tworldwide.bose.com\n192.0.2.100\tmedia.bose.io\n192.0.2.100\tdownloads.bose.com\n192.0.2.100\tvoice.api.bose.io", nil
|
||||
}
|
||||
return "127.0.0.1 localhost\n1.2.3.4\tstreaming.bose.com\n1.2.3.4\tupdates.bose.com", nil
|
||||
}
|
||||
@@ -771,7 +771,7 @@ func TestMigrateViaHosts_SkipCAIfTrusted(t *testing.T) {
|
||||
if command == "cat /etc/hosts" {
|
||||
// Handle both initial read and verification read
|
||||
if len(runCalls) > 2 { // Rough heuristic: verification happens after upload
|
||||
return "192.0.2.100\tstreaming.bose.com\n192.0.2.100\tupdates.bose.com\n192.0.2.100\tstats.bose.com\n192.0.2.100\tbmx.bose.com\n192.0.2.100\tcontent.api.bose.io\n192.0.2.100\tevents.api.bosecm.com\n192.0.2.100\tbose-prod.apigee.net\n192.0.2.100\tworldwide.bose.com\n192.0.2.100\tmedia.bose.io\n192.0.2.100\tdownloads.bose.com\n192.0.2.100\tvoice.api.bose.io", nil
|
||||
return "192.0.2.100\tstreaming.bose.com\n192.0.2.100\tupdates.bose.com\n192.0.2.100\tstats.bose.com\n192.0.2.100\tbmx.bose.com\n192.0.2.100\tcontent.api.bose.io\n192.0.2.100\tevents.api.bosecm.com\n192.0.2.100\taudionotification.api.bosecm.com\n192.0.2.100\taudionotificationdev.api.bosecm.com\n192.0.2.100\tbose-prod.apigee.net\n192.0.2.100\tworldwide.bose.com\n192.0.2.100\tmedia.bose.io\n192.0.2.100\tdownloads.bose.com\n192.0.2.100\tvoice.api.bose.io", nil
|
||||
}
|
||||
return "127.0.0.1 localhost", nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user