From 847f1955b312afa73e307878c7719f5ee903ca4c Mon Sep 17 00:00:00 2001 From: Izaan Kamal Date: Sat, 17 Oct 2026 23:26:33 -0700 Subject: [PATCH] Report the HTTP status when a GrandSlam response is not a plist GrandSlam reports its own errors inside the plist, so the HTTP status only matters when the body is not one. Since sign-in moved to sendGSARequest it no longer checks the status, so an HTML error page (a 503, or a 429 rate limit) reaches the parser and surfaces as NSCocoaErrorDomain 3840. Parse first and, when that fails on a non-2xx response, throw ALTAppleAPIError.unknown(statusCode:). --- AltSign/Sources/ALTAppleAPI+Authentication.swift | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/AltSign/Sources/ALTAppleAPI+Authentication.swift b/AltSign/Sources/ALTAppleAPI+Authentication.swift index 6cdc7c75..d01c805c 100644 --- a/AltSign/Sources/ALTAppleAPI+Authentication.swift +++ b/AltSign/Sources/ALTAppleAPI+Authentication.swift @@ -499,9 +499,21 @@ private extension ALTAppleAPI self.sendGSARequest(request) { (result) in do { - let (data, _) = try result.get() + let (data, response) = try result.get() - guard let responseDictionary = try PropertyListSerialization.propertyList(from: data, format: nil) as? [String: Any], + let propertyList: Any + do + { + propertyList = try PropertyListSerialization.propertyList(from: data, format: nil) + } + catch + { + // GrandSlam reports its own errors inside the plist, so the HTTP status only matters when the body is not one. + guard (200 ..< 300).contains(response.statusCode) else { throw ALTAppleAPIError.unknown(statusCode: response.statusCode) } + throw error + } + + guard let responseDictionary = propertyList as? [String: Any], let dictionary = responseDictionary["Response"] as? [String: Any], let status = dictionary["Status"] as? [String: Any] else { throw URLError(.badServerResponse) }