mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 16:46:17 +00:00
fix(bmx): relax TuneIn + Orion Authorization gate, log instead
Seven BMX adapter handlers required a non-empty `Authorization` header and returned 401 from writeBMXUnauthorized when missing: TuneIn: Playback, PodcastInfo, PlaybackPodcast, Report, Navigate, Search Orion: Playback Speakers calling these endpoints directly carry their margeAuthToken in the header, so the gate works for them. But the Stockholm browser proxy (pkg/service/stockholm/proxy.go injectBackendHeaders) only injects Authorization for hosts ending in .bose.com or .apigee.net with a marge path — when Stockholm calls back into our own service for TuneIn browsing/playback/search/etc., no header is added and every request 401s. Disable the gate at all seven sites; log the missing-header case so the absence remains visible. Keep writeBMXUnauthorized as the future-restore point (//nolint:unused) — when the gate comes back (e.g. behind a BMX_STRICT_AUTH env-var or once the Stockholm proxy learns to inject Authorization for our own host), callers will use this helper again. Tests that assert 401 for missing Authorization (TestBMXUnauthorized, TestHandleTuneInReport/Unauthorized, TestHandleTuneInNavigate/Unauthorized, TestHandleTuneInSearch/Unauthorized) are `t.Skip`'d with a pointer back to handlers_bmx_tunein.go — they stay in the file to come back to life the day the gate does. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
d7bbc09ce6
commit
b9c1cdad29
@@ -45,8 +45,11 @@ func (s *Server) HandleBMXServicesAvailability(w http.ResponseWriter, _ *http.Re
|
||||
|
||||
// writeBMXUnauthorized writes the canonical 401 used by every BMX adapter
|
||||
// handler that requires an Authorization header (TuneIn variants, Orion
|
||||
// playback). Kept here so all per-service files can share it without
|
||||
// duplicating the body markup.
|
||||
// playback). Currently unused because all gate sites are temporarily
|
||||
// disabled (log-only); kept as the future-restore point — when we re-add
|
||||
// the gate, callers will use this helper.
|
||||
//
|
||||
//nolint:unused // intentional: future-restore point for the disabled auth gate.
|
||||
func (s *Server) writeBMXUnauthorized(w http.ResponseWriter) {
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
|
||||
@@ -7,6 +7,7 @@ package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gesellix/bose-soundtouch/pkg/service/bmx"
|
||||
@@ -52,9 +53,12 @@ func (s *Server) HandleOrionToken(w http.ResponseWriter, _ *http.Request) {
|
||||
// before they ever follow a LOCAL_INTERNET_RADIO preset, so this
|
||||
// check shouldn't cost any legitimate caller.
|
||||
func (s *Server) HandleOrionPlayback(w http.ResponseWriter, r *http.Request) {
|
||||
// Authorization gate temporarily disabled (was: 401 if header missing).
|
||||
// See HandleTuneInPlayback for the rationale. Logged so we can spot
|
||||
// callers that would have been rejected; do NOT 401.
|
||||
if r.Header.Get("Authorization") == "" {
|
||||
s.writeBMXUnauthorized(w)
|
||||
return
|
||||
log.Printf("[BMX] Authorization missing (gate temporarily disabled, see handlers_bmx.go); path=%q ua=%q",
|
||||
r.URL.Path, r.UserAgent())
|
||||
}
|
||||
|
||||
data := r.URL.Query().Get("data")
|
||||
|
||||
@@ -73,6 +73,8 @@ func TestHandleTuneInReport(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Unauthorized", func(t *testing.T) {
|
||||
t.Skip("auth gate temporarily disabled in handlers_bmx_tunein.go; restore this assertion when the gate is re-enabled")
|
||||
|
||||
req, _ := http.NewRequest("POST", ts.URL+"/bmx/tunein/v1/report", nil)
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
|
||||
@@ -159,6 +159,8 @@ func TestCustomPlayback(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBMXUnauthorized(t *testing.T) {
|
||||
t.Skip("auth gate temporarily disabled in handlers_bmx_tunein.go and handlers_bmx_orion.go; restore this assertion when the gate is re-enabled")
|
||||
|
||||
r, _ := setupRouter("http://localhost:8001", nil)
|
||||
|
||||
ts := httptest.NewServer(r)
|
||||
|
||||
@@ -38,9 +38,13 @@ func (s *Server) tuneInStreamFormats() string {
|
||||
|
||||
// HandleTuneInPlayback returns TuneIn playback information.
|
||||
func (s *Server) HandleTuneInPlayback(w http.ResponseWriter, r *http.Request) {
|
||||
// Authorization gate temporarily disabled (was: 401 if header missing).
|
||||
// The Stockholm browser proxy doesn't inject Authorization for requests
|
||||
// that target our own service. Logged so we can spot callers that would
|
||||
// have been rejected; do NOT 401.
|
||||
if r.Header.Get("Authorization") == "" {
|
||||
s.writeBMXUnauthorized(w)
|
||||
return
|
||||
log.Printf("[BMX] Authorization missing (gate temporarily disabled, see handlers_bmx.go); path=%q ua=%q",
|
||||
r.URL.Path, r.UserAgent())
|
||||
}
|
||||
|
||||
stationID := chi.URLParam(r, "stationID")
|
||||
@@ -61,9 +65,13 @@ func (s *Server) HandleTuneInPlayback(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// HandleTuneInPodcastInfo returns TuneIn podcast information.
|
||||
func (s *Server) HandleTuneInPodcastInfo(w http.ResponseWriter, r *http.Request) {
|
||||
// Authorization gate temporarily disabled (was: 401 if header missing).
|
||||
// The Stockholm browser proxy doesn't inject Authorization for requests
|
||||
// that target our own service. Logged so we can spot callers that would
|
||||
// have been rejected; do NOT 401.
|
||||
if r.Header.Get("Authorization") == "" {
|
||||
s.writeBMXUnauthorized(w)
|
||||
return
|
||||
log.Printf("[BMX] Authorization missing (gate temporarily disabled, see handlers_bmx.go); path=%q ua=%q",
|
||||
r.URL.Path, r.UserAgent())
|
||||
}
|
||||
|
||||
podcastID := chi.URLParam(r, "podcastID")
|
||||
@@ -85,9 +93,13 @@ func (s *Server) HandleTuneInPodcastInfo(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
// HandleTuneInPlaybackPodcast returns TuneIn podcast playback information.
|
||||
func (s *Server) HandleTuneInPlaybackPodcast(w http.ResponseWriter, r *http.Request) {
|
||||
// Authorization gate temporarily disabled (was: 401 if header missing).
|
||||
// The Stockholm browser proxy doesn't inject Authorization for requests
|
||||
// that target our own service. Logged so we can spot callers that would
|
||||
// have been rejected; do NOT 401.
|
||||
if r.Header.Get("Authorization") == "" {
|
||||
s.writeBMXUnauthorized(w)
|
||||
return
|
||||
log.Printf("[BMX] Authorization missing (gate temporarily disabled, see handlers_bmx.go); path=%q ua=%q",
|
||||
r.URL.Path, r.UserAgent())
|
||||
}
|
||||
|
||||
podcastID := chi.URLParam(r, "podcastID")
|
||||
@@ -135,9 +147,13 @@ func (s *Server) HandleTuneInToken(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// HandleTuneInReport handles TuneIn playback reporting.
|
||||
func (s *Server) HandleTuneInReport(w http.ResponseWriter, r *http.Request) {
|
||||
// Authorization gate temporarily disabled (was: 401 if header missing).
|
||||
// The Stockholm browser proxy doesn't inject Authorization for requests
|
||||
// that target our own service. Logged so we can spot callers that would
|
||||
// have been rejected; do NOT 401.
|
||||
if r.Header.Get("Authorization") == "" {
|
||||
s.writeBMXUnauthorized(w)
|
||||
return
|
||||
log.Printf("[BMX] Authorization missing (gate temporarily disabled, see handlers_bmx.go); path=%q ua=%q",
|
||||
r.URL.Path, r.UserAgent())
|
||||
}
|
||||
|
||||
var req struct {
|
||||
@@ -179,9 +195,13 @@ func (s *Server) HandleTuneInReport(w http.ResponseWriter, r *http.Request) {
|
||||
// - sub/{n}/{encodedURI} → single subsection of a browse page
|
||||
// - profiles/{type}/{id}/{encodedURI} → artist/program profile page
|
||||
func (s *Server) HandleTuneInNavigate(w http.ResponseWriter, r *http.Request) {
|
||||
// Authorization gate temporarily disabled (was: 401 if header missing).
|
||||
// The Stockholm browser proxy doesn't inject Authorization for requests
|
||||
// that target our own service. Logged so we can spot callers that would
|
||||
// have been rejected; do NOT 401.
|
||||
if r.Header.Get("Authorization") == "" {
|
||||
s.writeBMXUnauthorized(w)
|
||||
return
|
||||
log.Printf("[BMX] Authorization missing (gate temporarily disabled, see handlers_bmx.go); path=%q ua=%q",
|
||||
r.URL.Path, r.UserAgent())
|
||||
}
|
||||
|
||||
wildcard := chi.URLParam(r, "*")
|
||||
@@ -242,9 +262,13 @@ func parseTuneInNavigatePath(wildcard string) (interface{}, error) {
|
||||
|
||||
// HandleTuneInSearch returns live TuneIn search results for the given query.
|
||||
func (s *Server) HandleTuneInSearch(w http.ResponseWriter, r *http.Request) {
|
||||
// Authorization gate temporarily disabled (was: 401 if header missing).
|
||||
// The Stockholm browser proxy doesn't inject Authorization for requests
|
||||
// that target our own service. Logged so we can spot callers that would
|
||||
// have been rejected; do NOT 401.
|
||||
if r.Header.Get("Authorization") == "" {
|
||||
s.writeBMXUnauthorized(w)
|
||||
return
|
||||
log.Printf("[BMX] Authorization missing (gate temporarily disabled, see handlers_bmx.go); path=%q ua=%q",
|
||||
r.URL.Path, r.UserAgent())
|
||||
}
|
||||
|
||||
query := r.URL.Query().Get("q")
|
||||
|
||||
@@ -47,6 +47,8 @@ func TestHandleTuneInNavigate(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Unauthorized", func(t *testing.T) {
|
||||
t.Skip("auth gate temporarily disabled in handlers_bmx_tunein.go; restore this assertion when the gate is re-enabled")
|
||||
|
||||
req := httptest.NewRequest("GET", "/bmx/tunein/v1/navigate", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
@@ -83,6 +85,8 @@ func TestHandleTuneInSearch(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Unauthorized", func(t *testing.T) {
|
||||
t.Skip("auth gate temporarily disabled in handlers_bmx_tunein.go; restore this assertion when the gate is re-enabled")
|
||||
|
||||
req := httptest.NewRequest("GET", "/bmx/tunein/v1/search?q=music", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user