From 3379a52d8c81b662eb500b373d0d12e60120ad30 Mon Sep 17 00:00:00 2001 From: fenleon Date: Tue, 13 Oct 2026 13:11:20 +0200 Subject: [PATCH] =?UTF-8?q?gsa:=20prefpane=20V1=20body=20keeps=20Basic=20a?= =?UTF-8?q?uth=20(live=202026-10-13:=20V1=20body=20without=20Basic=20?= =?UTF-8?q?=E2=86=92=20401=20UNAUTHORIZED;=20the=20closure's=20basic=5Faut?= =?UTF-8?q?h=20needs=20no=20string=20constants)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dev/fenn/imessage/registration/GsaDelegateLogin.kt | 10 ++++++---- .../fenn/imessage/registration/GsaDelegateLoginTest.kt | 5 +++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/registration/src/main/kotlin/dev/fenn/imessage/registration/GsaDelegateLogin.kt b/registration/src/main/kotlin/dev/fenn/imessage/registration/GsaDelegateLogin.kt index 89a74ad..8020b95 100644 --- a/registration/src/main/kotlin/dev/fenn/imessage/registration/GsaDelegateLogin.kt +++ b/registration/src/main/kotlin/dev/fenn/imessage/registration/GsaDelegateLogin.kt @@ -152,9 +152,11 @@ class GsaDelegateLoginClient( ) // The vendored reference (open_absinthe, RE 2026-10-13) ships ONLY the V1 request // shape on this endpoint: kebab-case `AuthRequest {apple-id, client-id, delegates, - // password}` with the PET in the body and NO Authorization header — the .so has no - // V2AuthRequest/protocolVersion/userInfo strings at all. The V2 wrapper is kept for - // the recorded v2 endpoint (§1.5 C59). + // password}` with the PET in the body — the .so has no V2AuthRequest/protocolVersion/ + // userInfo strings at all. Basic `username:PET` still rides (the closure's + // basic_auth needs no string constants; live 2026-10-13: V1 body WITHOUT Basic → + // 401 UNAUTHORIZED, so the server reads Basic even on the V1 shape). The V2 wrapper + // is kept for the recorded v2 endpoint (§1.5 C59). val prefpane = endpoint == PREFPANE_ENDPOINT val body = if (prefpane) { linkedMapOf( @@ -179,7 +181,7 @@ class GsaDelegateLoginClient( } val headers = buildMap { putAll(request.anisette) - if (!prefpane) put("Authorization", "Basic $basic") + put("Authorization", "Basic $basic") put(HEADER_NAS_QUALIFY, Base64.getEncoder().encodeToString(request.validationData)) put(HEADER_ADSID, request.adsid) put(HEADER_CLIENT_INFO, request.clientInfo) diff --git a/registration/src/test/kotlin/dev/fenn/imessage/registration/GsaDelegateLoginTest.kt b/registration/src/test/kotlin/dev/fenn/imessage/registration/GsaDelegateLoginTest.kt index e1906f7..1b970b2 100644 --- a/registration/src/test/kotlin/dev/fenn/imessage/registration/GsaDelegateLoginTest.kt +++ b/registration/src/test/kotlin/dev/fenn/imessage/registration/GsaDelegateLoginTest.kt @@ -100,7 +100,7 @@ class GsaDelegateLoginTest { } @Test - fun `prefpane endpoint posts the vendored V1 body without Basic auth`() = runBlocking { + fun `prefpane endpoint posts the vendored V1 body with Basic auth`() = runBlocking { val http = ScriptedIdsHttp(listOf(IdsHttpResponse(200, emptyMap(), okResponse()))) GsaDelegateLoginClient( http, @@ -109,7 +109,8 @@ class GsaDelegateLoginTest { val call = http.calls.single() assertEquals(GsaDelegateLoginClient.PREFPANE_ENDPOINT, call.url) - assertNull(call.headers["Authorization"]) + assertEquals("Basic " + Base64.getEncoder().encodeToString("user@example.com:pet-token".toByteArray()), + call.headers["Authorization"]) assertEquals(Base64.getEncoder().encodeToString(byteArrayOf(1, 2, 3)), call.headers["X-Mme-Nas-Qualify"]) val body = XmlPlist.decode(call.body) as Map<*, *>