registration: GSA login-shape parity per the vendored source (2026-10-14 diff)

- cpd gains the hardware-identity headers (SRL-NO/MLB/ROM chained last) — the
  vendored get_cpd_data carries them in the login BODY; the gsservice HTTP
  header set does NOT (the earlier reading had this inverted).
- GsaHeaderConfig.toHeaders(): drop the hardware headers, add Accept-Language
  (get_gsservice_headers carries it).
- ProvisionedAnisette flavor doc corrected (FLAVOR_MAC=1/FLAVOR_IOS=0 — the
  inverted doc caused the failed vendored-state swap, GSA ec=-22421).
- 'at' stays the recorded boolean false (vendored source writes Integer(0);
  both live-accepted).
This commit is contained in:
fenleon committed 2026-10-14 17:40:40 +02:00
1 parent 478a473629
commit f47fc49eaf
3 files changed
+29 -4

No files matched your search

@@ -125,7 +125,10 @@ data class ProvisionedAnisette(
val mid: ByteArray,
val metadata: ByteArray,
val rinfo: String,
/** 0 = Mac, 1 = IOS (ClearAdiOtp's flavor convention; the reference's ProvisionedFlavor). */
/** 0 = IOS-era provisioning, 1 = Mac (ClearAdiOtp's flavor convention — FLAVOR_MAC=1,
* FLAVOR_IOS=0; the pre-2026-10-14 doc had this inverted and caused the failed
* vendored-state swap: a Mac MID written with flavor 0 dispatches the wrong OTP
* cipher → GSA ec=-22421). */
val flavor: Int,
) {
fun toJson(): String = buildJsonObject {
@@ -63,8 +63,9 @@ enum class GsaFlavor(
* `X-Apple-Security-Upgrade-Context` = `com.apple.authkit.generic`, `cou` = `US`,
* `loc` = `en_US`, and the booleans `X-Apple-Offer-Security-Upgrade`=true, `bootstrap`=true,
* `ckgen`=true, `fcd`=true, `icdrsDisabled`=false, `icscrec`=true, `pbe`=false,
* `prkgen`=true, `webAccessEnabled`=false, `at`=0 (the spec lists `at` among the booleans
* but records its value as `0`; encoded as the plist boolean false).
* `prkgen`=true, `webAccessEnabled`=false, `at`=false (the recorded wire value is the plist
* boolean false from a genuine Mac capture; the vendored Rust source writes Integer(0) —
* both live-accepted, the recording wins).
*/
class GsaCpd(
/** The §1.1 anisette headers (from [AnisetteHeaderProvider.headers]). */
@@ -75,6 +76,14 @@ class GsaCpd(
val flavor: GsaFlavor = GsaFlavor.MESSAGES,
/** Optional APNs token (`ptkn`). */
private val apnsToken: String? = null,
/**
* The Mac hardware-identity headers (§1.1) — chained into the cpd dict like the
* vendored reference's cpd construction (icloud-auth anisette.rs `get_cpd_data` chains
* `client_info.hardware_headers` LAST). This is the login-body machine anchor: the
* gsservice HTTP header set does NOT carry them (2026-10-14 source diff — the earlier
* reading had them as login HTTP headers and missing from the cpd, inverted).
*/
val hardwareHeaders: Map<String, String> = emptyMap(),
) {
/** The cpd dict for one login; [requestUuid] is the uppercase UUIDv4 shared by both steps. */
@@ -92,6 +101,8 @@ class GsaCpd(
dict["loc"] = "en_US"
dict["svct"] = flavor.akContextType
dict["X-Apple-Offer-Security-Upgrade"] = true
// The recorded wire value is the boolean false (genuine Mac capture); the vendored
// Rust source writes Integer(0) — both live-accepted, keep the recording (2026-10-14).
dict["at"] = false
dict["bootstrap"] = true
dict["ckgen"] = true
@@ -102,6 +113,7 @@ class GsaCpd(
dict["prkgen"] = true
dict["webAccessEnabled"] = false
apnsToken?.let { dict["ptkn"] = it }
hardwareHeaders.forEach { (key, value) -> dict[key] = value }
return dict
}
@@ -182,13 +194,21 @@ data class GsaHeaderConfig(
val signInClientInfo: String
get() = "<$hardwareModel> <${osName};${osVersion};${osBuild}> <$AOSKIT_CLIENT_INFO>"
/**
* The GSA login POST header set — the vendored reference's `get_gsservice_headers`
* (icloud-auth anisette.rs, 2026-10-14 source diff): the akd `User-Agent`, the akd
* `X-MMe-Client-Info`, the flavor's context/bundle headers and `Accept-Language`. The
* hardware-identity headers are NOT here — the reference carries them inside the cpd
* dict only ([GsaCpd.hardwareHeaders]).
*/
fun toHeaders(): Map<String, String> = linkedMapOf(
"X-MMe-Client-Info" to clientInfo,
"User-Agent" to AKD_USER_AGENT,
"X-Apple-AK-Context-Type" to flavor.akContextType,
"X-Apple-Client-App-Name" to flavor.clientAppName,
"X-Apple-I-Client-Bundle-Id" to flavor.clientBundleId,
) + hardwareHeaders
"Accept-Language" to "en-US,en;q=0.9",
)
companion object {
/** The recorded akd `User-Agent` literal (§1.5, C59). */
@@ -163,6 +163,8 @@ class GsaCpdTest {
"X-Apple-AK-Context-Type" to "imessage",
"X-Apple-Client-App-Name" to "Messages",
"X-Apple-I-Client-Bundle-Id" to "com.apple.MobileSMS",
// The vendored reference's get_gsservice_headers carries it (2026-10-14 source diff).
"Accept-Language" to "en-US,en;q=0.9",
),
headers,
)