Skip to content

Commit 6a4ab11

Browse files
committed
Fix error for accounts using hardware keys.
1 parent e6d050b commit 6a4ab11

File tree

1 file changed

+27
-6
lines changed

1 file changed

+27
-6
lines changed

Sources/AppleAPI/Client.swift

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public class Client {
1818
case noTrustedPhoneNumbers
1919
case notAuthenticated
2020
case invalidHashcash
21+
case missingSecurityCodeInfo
22+
case accountUsesHardwareKey
2123

2224
public var errorDescription: String? {
2325
switch self {
@@ -33,6 +35,10 @@ public class Client {
3335
return "You are already signed out"
3436
case .invalidHashcash:
3537
return "Could not create a hashcash for the session."
38+
case .missingSecurityCodeInfo:
39+
return "Expected security code info but didn't receive any."
40+
case .accountUsesHardwareKey:
41+
return "Account uses a hardware key for authentication but this is not supported yet."
3642
default:
3743
return String(describing: self)
3844
}
@@ -58,7 +64,7 @@ public class Client {
5864
}
5965
.then { (data, _) -> Promise<(serviceKey: String, hashcash: String)> in
6066
struct ServiceKeyResponse: Decodable {
61-
let authServiceKey: String
67+
let authServiceKey: String?
6268
}
6369

6470
let response = try JSONDecoder().decode(ServiceKeyResponse.self, from: data)
@@ -120,6 +126,8 @@ public class Client {
120126
return Promise.value(())
121127
case .twoFactor:
122128
return self.handleTwoFactor(serviceKey: serviceKey, sessionID: sessionID, scnt: scnt, authOptions: authOptions)
129+
case .hardwareKey:
130+
throw Error.accountUsesHardwareKey
123131
case .unknown:
124132
Current.logging.log("Received a response from Apple that indicates this account has two-step or two-factor authentication enabled, but xcodes is unsure how to handle this response:".red)
125133
String(data: data, encoding: .utf8).map { Current.logging.log($0) }
@@ -134,7 +142,8 @@ public class Client {
134142
// SMS was sent automatically
135143
if authOptions.smsAutomaticallySent {
136144
return firstly { () throws -> Promise<(data: Data, response: URLResponse)> in
137-
let code = self.promptForSMSSecurityCode(length: authOptions.securityCode.length, for: authOptions.trustedPhoneNumbers!.first!)
145+
guard let securityCode = authOptions.securityCode else { throw Error.missingSecurityCodeInfo }
146+
let code = self.promptForSMSSecurityCode(length: securityCode.length, for: authOptions.trustedPhoneNumbers!.first!)
138147
return Current.network.dataTask(with: try URLRequest.submitSecurityCode(serviceKey: serviceKey, sessionID: sessionID, scnt: scnt, code: code))
139148
.validateSecurityCodeResponse()
140149
}
@@ -146,9 +155,10 @@ public class Client {
146155
return handleWithPhoneNumberSelection(authOptions: authOptions, serviceKey: serviceKey, sessionID: sessionID, scnt: scnt)
147156
// Code is shown on trusted devices
148157
} else {
158+
let securityCodeLength: Int = authOptions.securityCode?.length ?? 0
149159
let code = Current.shell.readLine("""
150160
Enter "sms" without quotes to exit this prompt and choose a phone number to send an SMS security code to.
151-
Enter the \(authOptions.securityCode.length) digit code from one of your trusted devices:
161+
Enter the \(securityCodeLength) digit code from one of your trusted devices:
152162
""") ?? ""
153163

154164
if code == "sms" {
@@ -216,7 +226,8 @@ public class Client {
216226
.then { trustedPhoneNumber in
217227
Current.network.dataTask(with: try URLRequest.requestSecurityCode(serviceKey: serviceKey, sessionID: sessionID, scnt: scnt, trustedPhoneID: trustedPhoneNumber.id))
218228
.map { _ in
219-
self.promptForSMSSecurityCode(length: authOptions.securityCode.length, for: trustedPhoneNumber)
229+
guard let securityCodeLength = authOptions.securityCode?.length else { throw Error.missingSecurityCodeInfo }
230+
return self.promptForSMSSecurityCode(length: securityCodeLength, for: trustedPhoneNumber)
220231
}
221232
}
222233
.then { code in
@@ -276,15 +287,18 @@ public extension Promise where T == (data: Data, response: URLResponse) {
276287
struct AuthOptionsResponse: Decodable {
277288
let trustedPhoneNumbers: [TrustedPhoneNumber]?
278289
let trustedDevices: [TrustedDevice]?
279-
let securityCode: SecurityCodeInfo
290+
let securityCode: SecurityCodeInfo?
280291
let noTrustedDevices: Bool?
281292
let serviceErrors: [ServiceError]?
293+
let fsaChallenge: FSAChallenge?
282294

283295
var kind: Kind {
284296
if trustedDevices != nil {
285297
return .twoStep
286298
} else if trustedPhoneNumbers != nil {
287299
return .twoFactor
300+
} else if fsaChallenge != nil {
301+
return .hardwareKey
288302
} else {
289303
return .unknown
290304
}
@@ -321,8 +335,15 @@ struct AuthOptionsResponse: Decodable {
321335
let securityCodeCooldown: Bool
322336
}
323337

338+
struct FSAChallenge: Decodable {
339+
let challenge: String
340+
let keyHandles: [String]
341+
let rpId: String
342+
let allowedCredentials: String
343+
}
344+
324345
enum Kind {
325-
case twoStep, twoFactor, unknown
346+
case twoStep, twoFactor, hardwareKey, unknown
326347
}
327348
}
328349

0 commit comments

Comments
 (0)