Skip to content

Commit 855bf2d

Browse files
committed
fix MFA with SMS
1 parent 94e28eb commit 855bf2d

File tree

3 files changed

+29
-8
lines changed

3 files changed

+29
-8
lines changed

Sources/xcodeinstall/API/Authentication+MFA.swift

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ extension AppleAuthenticator {
193193
let body = SMSRequest(phoneNumber: PhoneId(id: phoneId), mode: "sms")
194194
let (_, _) = try await apiCall(
195195
url: "https://idmsa.apple.com/appleauth/auth/verify/phone",
196-
method: .POST,
196+
method: .PUT,
197197
body: try JSONEncoder().encode(body),
198198
validResponse: .range(200..<300)
199199
)
@@ -240,6 +240,7 @@ extension AppleAuthenticator {
240240
)
241241
}
242242
case 200, 204:
243+
try await trustSession()
243244
try await self.saveSession(response: response, session: session)
244245
default:
245246
throw AuthenticationError.unexpectedHTTPReturnCode(code: response.statusCode)
@@ -289,6 +290,7 @@ extension AppleAuthenticator {
289290

290291
case 200, 204:
291292
// success
293+
try await trustSession()
292294
try await self.saveSession(response: response, session: session)
293295

294296
default:
@@ -302,6 +304,23 @@ extension AppleAuthenticator {
302304

303305
}
304306

307+
/// Ask Apple to trust this session, upgrading cookies from short-lived to long-lived.
308+
/// This matches Spaceship's post-verification trust step.
309+
func trustSession() async throws {
310+
let (_, response) = try await apiCall(
311+
url: "https://idmsa.apple.com/appleauth/auth/2sv/trust",
312+
validResponse: .range(200..<300)
313+
)
314+
315+
// Update session headers if the trust response provides new values
316+
if let newSessionId = response.value(forHTTPHeaderField: "X-Apple-ID-Session-Id") {
317+
session.xAppleIdSessionId = newSessionId
318+
}
319+
if let newScnt = response.value(forHTTPHeaderField: "scnt") {
320+
session.scnt = newScnt
321+
}
322+
}
323+
305324
func getMFAType() async throws -> MFAType {
306325

307326
let (data, _) = try await apiCall(

Sources/xcodeinstall/API/Authentication.swift

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -303,13 +303,14 @@ class AppleAuthenticator: HTTPClient, AppleAuthenticatorProtocol {
303303
}
304304

305305
func saveSession(response: HTTPURLResponse, session: AppleSession) async throws {
306-
guard let cookies = response.value(forHTTPHeaderField: "Set-Cookie") else {
307-
log.debug("No cookies set, just saving the session")
308-
_ = try await self.secrets.saveSession(session)
309-
return
306+
// always persist the session object (contains xAppleIdSessionId, scnt, etc.)
307+
_ = try await self.secrets.saveSession(session)
308+
309+
// also persist cookies when present
310+
if let cookies = response.value(forHTTPHeaderField: "Set-Cookie") {
311+
_ = try await self.secrets.saveCookies(cookies)
312+
} else {
313+
log.debug("No cookies in response, session saved without cookies")
310314
}
311-
312-
// save session data to reuse in future invocation
313-
_ = try await self.secrets.saveCookies(cookies)
314315
}
315316
}

Sources/xcodeinstall/API/HTTPClient.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ enum ExpectedResponseCode {
5050
enum HTTPVerb: String {
5151
case GET
5252
case POST
53+
case PUT
5354
}
5455

5556
// provide common code for all network clients

0 commit comments

Comments
 (0)