package emby import ( "context" "net/http" "strings" "testing" "time" ) // The authorisation header is what Emby's dashboard shows for a television, and it is the // one string the gateway sends to a third party — so both halves are pinned: the client // name is never the product name, and the version is the set's own build rather than a // constant that made every device look alike. func TestAuthHeaderCarriesClientVersion(t *testing.T) { client := New("http://emby:8096", "https://emby.example", "MbyATV", "MbyGateway", time.Second) req, err := client.newRequest( context.Background(), http.MethodGet, "/Items", nil, Credentials{DeviceID: "tv-1", DeviceName: `Living "room"`, ClientVersion: "0.2.4"}, nil, ) if err != nil { t.Fatal(err) } got := req.Header.Get("X-Emby-Authorization") want := `MediaBrowser Client="MbyATV", Device="Living room", DeviceId="tv-1", Version="0.2.4"` if got != want { t.Fatalf("auth header =\n %q\nwant\n %q", got, want) } } func TestAuthHeaderFallsBackToGatewayVersion(t *testing.T) { client := New("http://emby:8096", "https://emby.example", "MbyATV", "MbyGateway", time.Second) req, err := client.newRequest( context.Background(), http.MethodGet, "/Items", nil, Credentials{}, nil, ) if err != nil { t.Fatal(err) } got := req.Header.Get("X-Emby-Authorization") if strings.Contains(got, `Version=""`) || strings.Contains(got, `Version="1.0"`) { t.Fatalf("gateway request reported no usable version: %q", got) } if !strings.Contains(got, `Version="`+client.gatewayVersion+`"`) { t.Fatalf("auth header %q does not carry the gateway build %q", got, client.gatewayVersion) } } // A request the gateway makes for itself — the sync, the health probe, an operator // signing into the admin console — is not a television, and Emby's device list said it // was. It reports the gateway's own name and never falls back to the unnamed-set // placeholder, which is what made the server read as somebody's TV. func TestAuthHeaderNamesTheGatewayForItsOwnRequests(t *testing.T) { client := New("http://emby:8096", "https://emby.example", "MbyATV", "MbyGateway", time.Second) req, err := client.newRequest( context.Background(), http.MethodGet, "/Items", nil, Credentials{Gateway: true}, nil, ) if err != nil { t.Fatal(err) } got := req.Header.Get("X-Emby-Authorization") if !strings.Contains(got, `Client="MbyGateway"`) { t.Fatalf("gateway request did not report the gateway client name: %q", got) } if strings.Contains(got, "Memby") { t.Fatalf("gateway request carried the product name to Emby: %q", got) } } // A television's request must keep reporting the television's client name, whatever the // gateway calls itself — the two identities are separate rows in Emby's device list. func TestAuthHeaderKeepsTelevisionClientName(t *testing.T) { client := New("http://emby:8096", "https://emby.example", "MbyATV", "MbyGateway", time.Second) req, err := client.newRequest( context.Background(), http.MethodGet, "/Items", nil, Credentials{DeviceID: "tv-1", DeviceName: "Living room", ClientVersion: "0.2.57"}, nil, ) if err != nil { t.Fatal(err) } if got := req.Header.Get("X-Emby-Authorization"); !strings.Contains(got, `Client="MbyATV"`) { t.Fatalf("television request did not report the app client name: %q", got) } } // A blank gateway name must not silently become the television's, which would put the // server back in the device list as a set. func TestGatewayClientNameFallsBackToDefault(t *testing.T) { client := New("http://emby:8096", "https://emby.example", "MbyATV", " ", time.Second) if client.gatewayClientName != DefaultGatewayClientName { t.Fatalf("gateway client name = %q, want %q", client.gatewayClientName, DefaultGatewayClientName) } }