Adds a "Download diagnostic report" button on the Health tab that
produces an age-encrypted .age file the user can attach to a GitHub
issue without exposing sensitive data.
Archive contents (tar.gz, then age-encrypted with the maintainer's
SSH ed25519 public key):
- diagnostic.json structured health/device summary (no secrets)
- datastore/…/*.xml raw on-disk XML verbatim for diff vs HTTP
- http/service/… live service HTTP responses per account/device
- http/speaker/… live speaker API responses (port 8090)
- ssh/speaker/… CA bundles + logread (last 20 min, 127.0.0.1
filtered) + dmesg fetched via SSH
- system/ca.pem service CA cert
- system/resolv.conf host DNS resolver config
- settings.json service settings (OAuth secrets redacted)
- env.txt filtered process environment
- logs/service.txt in-memory service log buffer
Supporting tooling:
- scripts/setup-diagnostic-key.sh one-time SSH key-pair generation
- scripts/decrypt-diagnostic.go go run helper for maintainer decryption
- keys/public/diagnostic.pub committed public key (matches github.com/gesellix.keys)
- docs/DIAGNOSTIC-EXPORT.md maintainer setup + user workflow guide
- docs/concepts/ENCRYPTED-EXPORT.md research notes and architecture rationale
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On a multi-homed host the discovery layer used to walk net.Interfaces()
and pick the first non-loopback IPv4 NIC, while UPnP/SSDP bound a
wildcard UDP socket and let the kernel route the multicast send. That
meant --bind on soundtouch-web only moved the HTTP listener; the
discovery still went out whatever interface the kernel preferred (often
the wrong one on hosts where the speakers sit behind a secondary NIC).
Introduce a separate DiscoveryInterface knob:
* pkg/config: DiscoveryInterface field + DISCOVERY_INTERFACE env var.
* pkg/discovery/mdns: NewMDNSDiscoveryServiceWithInterface; the
interface resolver now honours an explicit name and validates it
has a usable IPv4 address before handing it to hashicorp/mdns.
* pkg/discovery/upnp: when an interface is configured, bind the UDP
socket's source IP to the NIC's IPv4 and call
ipv4.PacketConn.SetMulticastInterface so M-SEARCH leaves the right
NIC. Without an interface, behaviour is unchanged.
* cmd/soundtouch-web: new --interface flag (DISCOVERY_INTERFACE env)
plumbed into the config before the discovery service is built.
go.mod/go.sum reflect promoting golang.org/x/net from indirect to a
direct dependency (now imported for ipv4.PacketConn).
Refs #264.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Refreshes docs/images/ui-{settings,devices,sync,migration}.png by
driving the web UI in chromedp against a synthetic speaker, so
documentation can be regenerated without real hardware and without
leaking personal data from the local network.
Three independent pieces:
- pkg/service/testing/fakespeaker — embeddable library serving the
HTTP and telnet surface the migration wizard probes (/info,
/presets, /recents and a getpdo CurrentSystemConfiguration reply
that places the device on the unmigrated happy path).
- cmd/dummy-speaker — thin CLI wrapping the library; self-registers
with a running service via POST /setup/devices.
- scripts/screenshots — chromedp runner driven by a JSON manifest;
decoupled from speaker/service setup so it can target any backend
URL. run.sh orchestrates a one-shot end-to-end capture and seeds
settings.json with a generic hostname plus discovery disabled to
keep real-network state out of the captures.
Captures are at DPR=2 for retina-sharp text.
Co-Authored-By: Claude Opus 4.7 (1M context) <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>
Bumps the golang group with 1 update:
[golang.org/x/image](https://github.com/golang/image).
Updates `golang.org/x/image` from 0.37.0 to 0.38.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/image/commit/23ae9ed61c1d3343fb95015810f62dcbf444976e"><code>23ae9ed</code></a>
tiff: cap buffer growth to prevent OOM from malicious IFD offset</li>
<li><a
href="https://github.com/golang/image/commit/e589e60f29d0bbbf6400e250e024f93cbc4961ee"><code>e589e60</code></a>
webp: allow VP8L + VP8X(with alpha)</li>
<li>See full diff in <a
href="https://github.com/golang/image/compare/v0.37.0...v0.38.0">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
- Update Go version to 1.26.1 in go.mod and examples to address:
- GO-2026-4602 (os: FileInfo escape)
- GO-2026-4601 (net/url: IPv6 host literal parsing)
- GO-2026-4600 (crypto/x509: panic in name constraint checking)
- GO-2026-4599 (crypto/x509: incorrect email constraint enforcement)
- Upgrade golang.org/x/* and other dependencies to latest stable versions.
- Synchronize go.sum via go mod tidy.
Co-authored-by: Junie <junie@jetbrains.com>
Bumps the golang group with 1 update:
[golang.org/x/sys](https://github.com/golang/sys).
Updates `golang.org/x/sys` from 0.40.0 to 0.41.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/sys/commit/fc646e489fd944b6f77d327ab77f1a4bab81d5ad"><code>fc646e4</code></a>
cpu: use IsProcessorFeaturePresent to calculate ARM64 on windows</li>
<li><a
href="https://github.com/golang/sys/commit/f11c7bb268eb8a49f5a42afe15387a159a506935"><code>f11c7bb</code></a>
windows: add IsProcessorFeaturePresent and processor feature consts</li>
<li><a
href="https://github.com/golang/sys/commit/d25a7aaff8c2b056b2059fd7065afe1d4132e082"><code>d25a7aa</code></a>
unix: add IoctlSetString on all platforms</li>
<li><a
href="https://github.com/golang/sys/commit/6fb913b30f367555467f08da4d60f49996c9b17a"><code>6fb913b</code></a>
unix: return early on error in Recvmsg</li>
<li>See full diff in <a
href="https://github.com/golang/sys/compare/v0.40.0...v0.41.0">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
- Updated Go version from 1.25.6 to 1.25.7 in main go.mod
- Updated Go version in example modules (navigation-station-demo, preset-management)
- Fixes TLS vulnerability: Unexpected session resumption in crypto/tls
- Addresses security issue affecting WebSocket, HTTP handlers, and proxy operations
Reference: https://pkg.go.dev/vuln/GO-2026-4337
- Updated go.mod files to require Go 1.25.6
- Fixes vulnerability in crypto/tls package related to handshake message processing
- All example modules also updated to maintain consistency
- Verified with govulncheck: no vulnerabilities found
Bumps the golang group with 2 updates:
[golang.org/x/net](https://github.com/golang/net) and
[golang.org/x/tools](https://github.com/golang/tools).
Updates `golang.org/x/net` from 0.48.0 to 0.49.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/net/commit/d977772e17ccaa1903b2af736f6405ab3a9f05cc"><code>d977772</code></a>
go.mod: update golang.org/x dependencies</li>
<li><a
href="https://github.com/golang/net/commit/eea413e2942fbb59b323a2af0b1740da4d8aa93e"><code>eea413e</code></a>
internal/http3: use go1.25 synctest.Test instead of go1.24
synctest.Run</li>
<li><a
href="https://github.com/golang/net/commit/9ace223794aa203b4c877d08a1f7bf2f595f6242"><code>9ace223</code></a>
websocket: add missing call to resp.Body.Close</li>
<li><a
href="https://github.com/golang/net/commit/7d3dbb06ceb45c3180f4f446cd635e6b59a0b9c2"><code>7d3dbb0</code></a>
http2: buffer the most recently received PRIORITY_UPDATE frame</li>
<li>See full diff in <a
href="https://github.com/golang/net/compare/v0.48.0...v0.49.0">compare
view</a></li>
</ul>
</details>
<br />
Updates `golang.org/x/tools` from 0.40.0 to 0.41.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/tools/commit/2ad2b30edf98d0e3b67a7b3e8f6d1d6e41c963c3"><code>2ad2b30</code></a>
go.mod: update golang.org/x dependencies</li>
<li><a
href="https://github.com/golang/tools/commit/5832cce571d5c6583d80a58f5c0ff69664056e6c"><code>5832cce</code></a>
internal/diff/lcs: introduce line diffs</li>
<li><a
href="https://github.com/golang/tools/commit/67c42573e2e2b0a6b9c421a2bd2ef4c95adb93d5"><code>67c4257</code></a>
gopls/internal/golang: Definition: fix Windows bug wrt //go:embed</li>
<li><a
href="https://github.com/golang/tools/commit/12c1f0453e55dae26e5fa2206e34a059380e6191"><code>12c1f04</code></a>
gopls/completion: check Selection invariant</li>
<li><a
href="https://github.com/golang/tools/commit/6d871857886c38ce4fbc25c25c4da1619271051e"><code>6d87185</code></a>
internal/server: add vulncheck scanning after vulncheck prompt</li>
<li><a
href="https://github.com/golang/tools/commit/0c3a1fec5617ed70197ee010406883919ede02d7"><code>0c3a1fe</code></a>
go/ast/inspector: FindByPos returns the first innermost node</li>
<li><a
href="https://github.com/golang/tools/commit/ca281cf9505443eb482db8a3e806721c29dfa7f2"><code>ca281cf</code></a>
go/analysis/passes/ctrlflow: add noreturn funcs from popular pkgs</li>
<li><a
href="https://github.com/golang/tools/commit/09c21a934282b0bcf790d54982ff24b869f832c9"><code>09c21a9</code></a>
gopls/internal/analysis/unusedfunc: remove warnings for unused enum
consts</li>
<li><a
href="https://github.com/golang/tools/commit/03cb4551c662c0e078502fe5f317ca4114b89cd8"><code>03cb455</code></a>
internal/modindex: suppress missing modcacheindex message</li>
<li><a
href="https://github.com/golang/tools/commit/15d13e8a95dd0247dec2960fb57e85252984509d"><code>15d13e8</code></a>
gopls/internal/util/typesutil: refine EnclosingSignature bug.Report</li>
<li>Additional commits viewable in <a
href="https://github.com/golang/tools/compare/v0.40.0...v0.41.0">compare
view</a></li>
</ul>
</details>
<br />
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the golang group with 1 update:
[golang.org/x/mod](https://github.com/golang/mod).
Updates `golang.org/x/mod` from 0.31.0 to 0.32.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/mod/commit/4c04067938546e62fc0572259a68a6912726bcdd"><code>4c04067</code></a>
go.mod: update golang.org/x dependencies</li>
<li>See full diff in <a
href="https://github.com/golang/mod/compare/v0.31.0...v0.32.0">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
- Reference original API documentation source from Bose Corporation
- Link to official Bose SoundTouch End-of-Life page
- Clarify this is an independent implementation
- Add disclaimer about non-affiliation with Bose Corporation
- Provide both online and local documentation references
- Added urfave/cli/v2 dependency for better CLI structure
- Created modular command structure with separate files:
- common.go: Shared utilities and client setup
- cmd_discover.go: Device discovery commands
- cmd_info.go: Device information commands
- cmd_volume.go: Volume control commands
- cmd_playback.go: Playback control commands
- cmd_source.go: Source selection commands
- Replaced giant main() function (complexity 149) with organized subcommands
- Added proper flag handling and validation
- Improved help text and user experience
WIP: Some issues remain (flag conflicts, missing commands)
Next: Complete remaining commands and fix conflicts
Features Added:
• mDNS/Bonjour discovery using hashicorp/mdns library
• Unified discovery service combining UPnP + mDNS + configuration
• Parallel discovery execution for optimal performance
• Comprehensive logging for both UPnP and mDNS discovery
• Network diagnostic tools for troubleshooting
New Discovery Methods:
• Configuration-based (fastest, most reliable)
• UPnP/SSDP discovery (widely supported, enhanced logging)
• mDNS/Bonjour discovery (Apple ecosystem friendly)
New Programs & Tools:
• cmd/example-mdns - Standalone mDNS discovery testing
• cmd/example-upnp - Isolated UPnP/SSDP discovery testing
• cmd/mdns-scanner - Network diagnostic tool for mDNS services
Enhanced Build System:
• make dev-mdns / dev-mdns-verbose (mDNS testing)
• make dev-upnp / dev-upnp-verbose (UPnP testing)
• make dev-scan-all (scan all network services)
• make dev-scan-soundtouch (scan for SoundTouch services)
Documentation:
• docs/DISCOVERY.md - Comprehensive discovery guide
• Updated README.md with new features and commands
• Full API documentation and troubleshooting guide
Technical Improvements:
• Detailed request/response logging for UPnP M-SEARCH
• Step-by-step mDNS service discovery tracking
• IP address resolution with IPv4/IPv6 handling
• Service name parsing and device info extraction
• Robust error handling and network diagnostics
Backward Compatibility:
• No breaking changes to existing APIs
• All existing tests pass
• CLI interface unchanged but enhanced
• Legacy UPnP-only service still available
- Implement HTTP client with XML support for SoundTouch Web API
- Add UPnP device discovery with SSDP protocol
- Create type-safe Go models for API responses
- Build CLI tool with device discovery and info commands
- Add comprehensive configuration management via .env and env vars
- Include extensive documentation (API endpoints, patterns, development guide)
- Translate all German documentation to English
- Set up modern Go project structure with testing framework
- Add Makefile for cross-platform builds and development workflow
Features:
✅ Device discovery (UPnP + manual configuration)
✅ Device information retrieval
✅ XML request/response handling
✅ CLI interface with flexible device targeting
✅ Cross-platform compatibility
✅ Comprehensive test coverage with mock data
✅ Production-ready configuration management