mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 08:36:13 +00:00
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>
55 lines
1.5 KiB
Go
55 lines
1.5 KiB
Go
// Package export provides encryption helpers for the diagnostic export feature.
|
|
package export
|
|
|
|
import (
|
|
"bytes"
|
|
_ "embed"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"filippo.io/age"
|
|
"filippo.io/age/agessh"
|
|
)
|
|
|
|
// diagnosticPublicKey is embedded from diagnostic.pub at compile time.
|
|
// diagnostic.pub is kept in sync with keys/public/diagnostic.pub by
|
|
// scripts/setup-diagnostic-key.sh. To verify it matches the maintainer's
|
|
// GitHub SSH keys:
|
|
//
|
|
// curl -s https://github.com/gesellix.keys | grep "$(awk '{print $2}' keys/public/diagnostic.pub)"
|
|
//
|
|
//go:embed diagnostic.pub
|
|
var diagnosticPublicKeyRaw string
|
|
|
|
// diagnosticPublicKey returns the trimmed SSH public key line.
|
|
func diagnosticPublicKey() string {
|
|
return strings.TrimSpace(diagnosticPublicKeyRaw)
|
|
}
|
|
|
|
// EncryptDiagnostic encrypts plaintext using the embedded SSH public key
|
|
// and returns the age-encrypted bytes. The result can only be decrypted
|
|
// with the corresponding SSH private key (keys/private/diagnostic).
|
|
func EncryptDiagnostic(plaintext []byte) ([]byte, error) {
|
|
recipient, err := agessh.ParseRecipient(diagnosticPublicKey())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parse recipient key: %w", err)
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
|
|
w, err := age.Encrypt(&buf, recipient)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("age encrypt: %w", err)
|
|
}
|
|
|
|
if _, err := w.Write(plaintext); err != nil {
|
|
return nil, fmt.Errorf("write plaintext: %w", err)
|
|
}
|
|
|
|
if err := w.Close(); err != nil {
|
|
return nil, fmt.Errorf("close age writer: %w", err)
|
|
}
|
|
|
|
return buf.Bytes(), nil
|
|
}
|