mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 08:36:13 +00:00
fix(web): trust service CA and send a known target for TTS
soundtouch-web's "Speak" feature proxies to the AfterTouch service's /setup/tts/speak endpoint. Two issues blocked it end to end. 1. TLS: the proxy used http.DefaultClient, which trusts only system roots, so the HTTPS call to a service using its own self-signed CA failed with "x509: certificate signed by unknown authority". Add a --service-ca flag (SERVICE_CA env) that loads the CA PEM, appends it to the system pool, and uses a custom client for the TTS call. 2. Target: soundtouch-web sent device.Client.Host() (a full base URL like http://ip:8090), but the service's SSRF guard exact-matches the target against bare datastore IPs, returning "host ... is not a known device". Prefer the device ID (the canonical key) and send a bare-IP host fallback. Also normalize the incoming host in resolveTTSHost so a URL/host:port form still resolves; it still only ever returns a datastore IP, so the SSRF guarantee is unchanged. Adds unit tests for the CA client builder, hostOnly, and resolveTTSHost (including the preserved unknown-host/device rejections). Documents --service-ca in the soundtouch-web README and TROUBLESHOOTING guide. Wires SERVICE_URL and SERVICE_CA (empty defaults) into the Raspberry Pi install-web.sh env file and documents them in the Pi guide. 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
7051793e81
commit
d94b1bc067
@@ -93,11 +93,38 @@ go build -o soundtouch-web
|
||||
|
||||
### Command Line Options
|
||||
```
|
||||
-port string Web server port (default "8080")
|
||||
-host string Specific SoundTouch device host (optional, enables single-device mode)
|
||||
-help Show help information
|
||||
--port, -p string HTTP port to listen on (default "8080", env PORT)
|
||||
--bind string Address for the HTTP listener: host, IP, or interface name (env BIND_ADDR)
|
||||
--interface string Network interface name for mDNS/UPnP discovery (env DISCOVERY_INTERFACE)
|
||||
--devices strings SoundTouch device IP(s) to add manually, repeatable (env SOUNDTOUCH_DEVICES)
|
||||
--service-url string AfterTouch service base URL, e.g. https://soundtouch.local (env SERVICE_URL)
|
||||
--service-ca string Path to the AfterTouch service CA certificate (PEM) to trust (env SERVICE_CA)
|
||||
--help, -h Show help information
|
||||
```
|
||||
|
||||
### Text-to-Speech (TTS)
|
||||
|
||||
TTS synthesis and the Bose `app_key` live in the AfterTouch service, not in
|
||||
soundtouch-web, so the "Speak" feature proxies to the service's
|
||||
`/setup/tts/speak` endpoint. To use it, point soundtouch-web at the service
|
||||
with `--service-url`.
|
||||
|
||||
When the service is served over HTTPS with its own self-signed certificate
|
||||
(the default), soundtouch-web also needs to trust the service's CA, or the
|
||||
proxied call fails with `x509: certificate signed by unknown authority`. Pass
|
||||
the CA with `--service-ca`; it is the service's `<dataDir>/certs/ca.crt`:
|
||||
|
||||
```bash
|
||||
soundtouch-web \
|
||||
--service-url https://soundtouch.fritz.box \
|
||||
--service-ca /path/to/certs/ca.crt
|
||||
```
|
||||
|
||||
The CA is appended to the system trust store, so a service URL that uses a
|
||||
publicly trusted certificate keeps working without the flag. The target
|
||||
speaker must be known to the service (it resolves the speaker against its own
|
||||
device datastore).
|
||||
|
||||
## Usage
|
||||
|
||||
### Accessing the Interface
|
||||
|
||||
@@ -81,6 +81,11 @@ func main() {
|
||||
Usage: "AfterTouch service base URL (e.g. https://soundtouch.local). Required for custom stream URLs to work as presets via LOCAL_INTERNET_RADIO",
|
||||
EnvVars: []string{"SERVICE_URL"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "service-ca",
|
||||
Usage: "Path to the AfterTouch service CA certificate (PEM) to trust for server-side calls such as TTS. Typically the service's <dataDir>/certs/ca.crt. Appended to the system trust store",
|
||||
EnvVars: []string{"SERVICE_CA"},
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
port := c.String("port")
|
||||
@@ -116,6 +121,17 @@ func main() {
|
||||
webApp.RepoURL = repoURL
|
||||
webApp.ServiceURL = strings.TrimRight(c.String("service-url"), "/")
|
||||
|
||||
if caPath := c.String("service-ca"); caPath != "" {
|
||||
client, err := soundtouchweb.NewServiceHTTPClient(caPath)
|
||||
if err != nil {
|
||||
log.Fatalf("--service-ca: %v", err)
|
||||
}
|
||||
|
||||
webApp.ServiceClient = client
|
||||
|
||||
log.Printf("Trusting AfterTouch service CA from %s", sanitizeLog(caPath))
|
||||
}
|
||||
|
||||
discoveryService := soundtouchweb.NewDiscoveryService(ifaceName)
|
||||
|
||||
// Discover devices on startup
|
||||
|
||||
Reference in New Issue
Block a user