From 0ff30990cc25fc299fd3d75193fb43093448ec89 Mon Sep 17 00:00:00 2001 From: Jose Trejo Date: Wed, 14 Oct 2026 12:29:01 -0500 Subject: [PATCH 1/2] Follow-up to #337. With the Android client identity, accounts that get `secondaryAuth` can't finish logging in: GSA rejects POST /auth/verify/phone/put?mode=sms with HTTP 403 ("Could not connect to iCloud"). The JSON flavor of those endpoints (GET /auth, PUT /auth/verify/phone/) answers 401 as well. GsService2/validate still accepts a code generated on a trusted device (Settings > Sign-In & Security > Get Verification Code), so ask for one instead of failing. Tested on WSL (Ubuntu 26.04) with an iOS 27 device. --- .../GrandSlamTwoFactorAuthenticateOperation.swift | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Sources/XKit/GrandSlam/Operations/GrandSlamTwoFactorAuthenticateOperation.swift b/Sources/XKit/GrandSlam/Operations/GrandSlamTwoFactorAuthenticateOperation.swift index a3a39d98..cafdc8a2 100644 --- a/Sources/XKit/GrandSlam/Operations/GrandSlamTwoFactorAuthenticateOperation.swift +++ b/Sources/XKit/GrandSlam/Operations/GrandSlamTwoFactorAuthenticateOperation.swift @@ -27,7 +27,16 @@ struct GrandSlamTwoFactorAuthenticateOperation { private func performSMSAuth() async throws { // TODO: parse phone number list from o=complete req? let phoneNumberID = "1" - try await client.send(GrandSlamSMSAuthRequest(loginData: loginData, phoneNumberID: phoneNumberID)) + do { + try await client.send(GrandSlamSMSAuthRequest(loginData: loginData, phoneNumberID: phoneNumberID)) + } catch let error as HTTPResponseError { + print(""" + Could not send an SMS (HTTP \(error.status.code)). Generate a code on a trusted device instead: \ + Settings > [your name] > Sign-In & Security > Get Verification Code + """) + try await validateCode() + return + } try await validateCode(phoneNumberID: phoneNumberID) } From 032d405b65c61e2d2d4711aba98bdb0ea45ac404 Mon Sep 17 00:00:00 2001 From: Kabir Oberai Date: Sun, 18 Oct 2026 20:43:26 -0400 Subject: [PATCH 2/2] Tweaks --- ...GrandSlamTwoFactorAuthenticateOperation.swift | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Sources/XKit/GrandSlam/Operations/GrandSlamTwoFactorAuthenticateOperation.swift b/Sources/XKit/GrandSlam/Operations/GrandSlamTwoFactorAuthenticateOperation.swift index cafdc8a2..64f362b6 100644 --- a/Sources/XKit/GrandSlam/Operations/GrandSlamTwoFactorAuthenticateOperation.swift +++ b/Sources/XKit/GrandSlam/Operations/GrandSlamTwoFactorAuthenticateOperation.swift @@ -29,12 +29,11 @@ struct GrandSlamTwoFactorAuthenticateOperation { let phoneNumberID = "1" do { try await client.send(GrandSlamSMSAuthRequest(loginData: loginData, phoneNumberID: phoneNumberID)) - } catch let error as HTTPResponseError { + } catch let error as HTTPResponseError where error.status.code == 403 { print(""" - Could not send an SMS (HTTP \(error.status.code)). Generate a code on a trusted device instead: \ - Settings > [your name] > Sign-In & Security > Get Verification Code + warning: Could not send verification code via SMS. Falling back to trusted device authentication... """) - try await validateCode() + try await performTrustedDeviceAuth() return } try await validateCode(phoneNumberID: phoneNumberID) @@ -60,7 +59,14 @@ struct GrandSlamTwoFactorAuthenticateOperation { private func performTrustedDeviceAuth() async throws { let request = GrandSlamTrustedDeviceRequest(loginData: loginData) - try await client.send(request) + do { + try await client.send(request) + } catch let error as HTTPResponseError where error.status.code == 403 { + print(""" + warning: Could not send verification code. Generate one manually. + See https://github.com/xtool-org/xtool/discussions/368 + """) + } try await validateCode() }