Surface HTTP errors from GSA auth instead of a plist parse failure - #48
Surface HTTP errors from GSA auth instead of a plist parse failure#48oddharsh wants to merge 1 commit into
Conversation
gsa.apple.com/grandslam/GsService2 occasionally responds to the auth request with a plain HTTP error page (e.g. 503 Service Temporarily Unavailable) instead of a plist body. sendAuthenticationRequestWithParameters: fed that HTML straight into NSPropertyListSerialization, which failed with "Encountered unknown tag html on line 1" / kCFPropertyListOldStyleParsingError - a confusing, low-level error that gives no hint the real issue is a transient server error on Apple's end. Check the response status code before parsing and return a clear, actionable error when it's non-2xx.
|
Heads up, this is against As far as I can tell no AltStore branch pins it. main pins I also checked a shipped binary rather than just the pointers. The AltSign-Dynamic.framework inside AltServer 1.7.2 exports So this probably will not reach the builds people are reporting on. I opened #49 with the Swift equivalent against Two thoughts on the status code check:
|
|
Update, and a correction to the guess I made above. I put logging in a build and ran it on an affected Mac. Your 503 is the real thing. The 401 I mentioned was from malformed test requests I was sending, so ignore that part. The third GSA call is what fails: Apple ID, password and anisette are all fine, Apple accepts them twice. Only Not rate limiting either, which I had also guessed. init and complete go through from the same IP in the same second, and adding a 6 second delay before apptokens changed nothing. Same result three runs in a row. The same 503 is hitting SideStore, open since Aug 7 with an identical payload. Apple's developer status page shows everything green and GrandSlam is not listed there, so there is nothing to wait on. None of this changes either patch, HTML still should not go to the plist parser. But neither of us is fixing sign in, we are just making it readable. Probably worth saying that in both descriptions so people do not expect a login fix. |
|
Correcting myself again, we found the actual cause. Apple's GSA edge pins a connection to a backend node, and once that node starts failing every later request on the same connection returns 5xx and never recovers:
So my earlier guesses were both wrong: not rate limiting, not IP based. It is connection reuse. The fix is to retry 5xx with each attempt on its own session, so it opens a new connection. Plain retry on the shared session does nothing, I tried it and it failed five times in a row on the same dead connection. With a fresh connection per attempt, sign in went through first try on a machine that had never completed it. That is on #49 now. Worth doing on this branch too if master is still built for anything, since the status code check alone will report the 503 clearly but the sign in will still fail. |
|
One correction to what I wrote above. I said GSA returned 200 for the old akd UA, the new AuthKit one and no UA at all, so the UA was unrelated. That came from a 6 request sample and it was wrong. Re-measured interleaved, 100 requests each: So #47 is addressing a real trigger. The connection reuse problem is still underneath it, a reused connection sours with the new UA too, just later, so both changes are worth having. |
What
sendAuthenticationRequestWithParameters:anisetteData:completionHandler:inALTAppleAPI+Authentication.mparses the GSA auth response body as a plist without first checking the HTTP status code. Whengsa.apple.com/grandslam/GsService2returns a non-2xx response (observed: a plain503 Service Temporarily UnavailableHTML page) instead of the expected plist, that HTML gets fed straight intoNSPropertyListSerialization, which fails with:That's the parser's generic "this isn't a plist" error — it gives no indication the actual cause is a transient server error on Apple's end. Users just see AltServer/AltStore report "could not sign in... the data is not in the correct format", which reads as a local/config problem and sends people chasing anisette or account issues instead of just retrying later.
How I found it
Traced a live repro (AltServer 1.7.2, macOS 27 beta) by hooking
CFPropertyListCreateWithDataand+[NSPropertyListSerialization propertyListWithData:options:format:error:]in-process to capture the raw response bytes on parse failure. The captured body was:with the failing call originating from
AltSign-DynamicviasendAuthenticationRequestWithParameters:anisetteData:completionHandler:, confirming the response is passed to the plist parser unconditionally.Fix
Check
NSHTTPURLResponse.statusCodebefore attempting to parse. On a non-2xx status, return a clearALTAppleAPIErrorUnknownerror describing the HTTP status instead of surfacing the plist parse failure.Testing
Verified against the captured 503 response locally (confirmed the existing code path throws the "unknown tag html" parse error on that input, and that the new status check intercepts it before parsing). I don't have a way to build/run the full AltSign target here, so this hasn't been exercised through Xcode — flagging that for review.