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 e143691..83bd6c5 100644 --- a/registration/src/main/kotlin/dev/fenn/imessage/registration/GsaDelegateLogin.kt +++ b/registration/src/main/kotlin/dev/fenn/imessage/registration/GsaDelegateLogin.kt @@ -240,6 +240,13 @@ class GsaDelegateLoginClient( companion object { const val SIGNIN_ENDPOINT = "https://setup.icloud.com/setup/signin/v2/login" + + /** + * The reference client's delegate sign-in endpoint (.so strings, 2026-10-13) — same + * header/body family as [SIGNIN_ENDPOINT]; the endpoint where its delegate sign-ins + * succeed live (the recorded v2 form answers 409 ICLOUD_UNSUPPORTED_DEVICE). + */ + const val PREFPANE_ENDPOINT = "https://setup.icloud.com/setup/prefpane/login" const val CONTENT_TYPE = "application/x-apple-plist" const val PROTOCOL_VERSION = "1.0" const val IDS_DELEGATE_BUNDLE_ID = "com.apple.private.ids" diff --git a/registration/src/main/kotlin/dev/fenn/imessage/registration/GsaLoginChain.kt b/registration/src/main/kotlin/dev/fenn/imessage/registration/GsaLoginChain.kt index 496ca93..8d06f97 100644 --- a/registration/src/main/kotlin/dev/fenn/imessage/registration/GsaLoginChain.kt +++ b/registration/src/main/kotlin/dev/fenn/imessage/registration/GsaLoginChain.kt @@ -134,13 +134,20 @@ class GsaLoginChain( private val twoFactorHeaders: suspend () -> GsaTwoFactorHeaders? = { null }, /** The §1.5 akd-variant headers of the GSA POSTs (C59 values) — null omits them. */ private val headerConfig: GsaHeaderConfig? = null, + /** + * The delegate sign-in endpoint. The recorded form is `/setup/signin/v2/login` (§1.5 C59); + * the reference client (vendored rustpush/open_absinthe, .so strings 2026-10-13) uses + * `/setup/prefpane/login` — which is where its delegate sign-ins succeed while the + * recorded endpoint answers 409 ICLOUD_UNSUPPORTED_DEVICE (live 2026-10-03/13). + */ + val delegateEndpoint: String = GsaDelegateLoginClient.SIGNIN_ENDPOINT, private val random: SecureRandom = SecureRandom(), private val clock: () -> Long = System::currentTimeMillis, private val logEvent: (String) -> Unit = {}, ) { private val loginClient = GsaLoginClient(http, logEvent = logEvent) - private val delegateClient = GsaDelegateLoginClient(http, logEvent = logEvent) + private val delegateClient = GsaDelegateLoginClient(http, endpoint = delegateEndpoint, logEvent = logEvent) /** §1.5: the filtered anisette header set + the akd-variant headers, one per login. */ private suspend fun gsaHeaders(): Map =