mirror of
https://github.com/yattee/yattee.git
synced 2026-05-14 03:15:03 +00:00
Fix three basic-auth regressions surfaced by end-to-end testing
- InstanceDetector: a single 401 from one probe was over-eagerly concluded as "credentials invalid" / "credentials required". On instances behind a reverse proxy where one probe path (e.g. Yattee Server's /info) hits a same-origin redirect, iOS URLSession strips the Authorization header on the redirect and the request 401s even with valid credentials. Track 401s across all probes and only conclude basicAuthRequired/basicAuthInvalid when no probe matched and at least one returned 401. - InstanceLoginView: the Invidious/Piped login flow constructed an API client backed by the shared appEnvironment.httpClient, which has no per-instance basic-auth headers. For instances behind a reverse proxy, the login POST 401d before reaching the upstream login endpoint. Build a per-instance HTTPClient with the basic-auth Authorization header baked in via setDefaultHeaders, mirroring ContentService.httpClientWithBasicAuth. - InvidiousAPI.login: the login function constructs its own URLSession (to capture Set-Cookie via a redirect-blocking delegate), so it never inherits headers from the injected httpClient. Add an optional extraHeaders parameter and have InstanceLoginView pass the basic-auth header through when present. PipedAPI.login uses httpClient.fetch and inherits defaultHeaders correctly, so no change is needed there.
This commit is contained in:
@@ -177,13 +177,33 @@ struct InstanceLoginView: View {
|
||||
/// Performs the login based on instance type.
|
||||
/// - Returns: The credential (SID for Invidious, token for Piped)
|
||||
private func performLogin(appEnvironment: AppEnvironment) async throws -> String {
|
||||
// If the instance sits behind an HTTP Basic Auth reverse proxy, the login
|
||||
// POST must carry that proxy's Authorization header too — otherwise the
|
||||
// request 401s before reaching the upstream login endpoint. Bake the
|
||||
// header into a fresh per-instance HTTPClient.
|
||||
let basicAuthHeader = appEnvironment.basicAuthCredentialsManager.basicAuthHeader(for: instance)
|
||||
let extraHeaders: [String: String]? = basicAuthHeader.map { ["Authorization": $0] }
|
||||
|
||||
let httpClient: HTTPClient
|
||||
if let basicAuthHeader {
|
||||
httpClient = appEnvironment.httpClientFactory.createClient(for: instance)
|
||||
await httpClient.setDefaultHeaders(["Authorization": basicAuthHeader])
|
||||
} else {
|
||||
httpClient = appEnvironment.httpClient
|
||||
}
|
||||
|
||||
switch instance.type {
|
||||
case .invidious:
|
||||
let api = InvidiousAPI(httpClient: appEnvironment.httpClient)
|
||||
return try await api.login(email: username, password: password, instance: instance)
|
||||
// InvidiousAPI.login uses its own URLSession (to handle redirect/Set-Cookie),
|
||||
// so it doesn't inherit defaultHeaders from the injected HTTPClient. Pass
|
||||
// the basic-auth header explicitly so the login POST passes the proxy.
|
||||
let api = InvidiousAPI(httpClient: httpClient)
|
||||
return try await api.login(email: username, password: password, instance: instance, extraHeaders: extraHeaders)
|
||||
|
||||
case .piped:
|
||||
let api = PipedAPI(httpClient: appEnvironment.httpClient)
|
||||
// PipedAPI.login uses httpClient.fetch which DOES inherit defaultHeaders,
|
||||
// so the basic-auth header on the per-instance client is sufficient.
|
||||
let api = PipedAPI(httpClient: httpClient)
|
||||
return try await api.login(username: username, password: password, instance: instance)
|
||||
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user