From 05d5a1432aee971129b2e8c00e8068506be6b19a Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Sat, 31 Aug 2024 18:59:51 -0400 Subject: [PATCH 01/14] [Auth] Use result type to wrap completion handlers internally --- FirebaseAuth/Sources/Swift/Auth/Auth.swift | 27 ++++++++++++------- .../AuthProvider/PhoneAuthProvider.swift | 4 +-- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Auth/Auth.swift b/FirebaseAuth/Sources/Swift/Auth/Auth.swift index 6c6932973de..ef77f1f76ad 100644 --- a/FirebaseAuth/Sources/Swift/Auth/Auth.swift +++ b/FirebaseAuth/Sources/Swift/Auth/Auth.swift @@ -295,9 +295,9 @@ extension Auth: AuthInterop { Task { do { let response = try await AuthBackend.call(with: request) - Auth.wrapMainAsync(callback: completion, withParam: response.signinMethods, error: nil) + Auth.wrapMainAsync(callback: completion, with: .success(response.signinMethods)) } catch { - Auth.wrapMainAsync(callback: completion, withParam: nil, error: error) + Auth.wrapMainAsync(callback: completion, with: .failure(error)) } } } @@ -1004,9 +1004,9 @@ extension Auth: AuthInterop { let actionCodeInfo = ActionCodeInfo(withOperation: operation, email: email, newEmail: response.verifiedEmail) - Auth.wrapMainAsync(callback: completion, withParam: actionCodeInfo, error: nil) + Auth.wrapMainAsync(callback: completion, with: .success(actionCodeInfo)) } catch { - Auth.wrapMainAsync(callback: completion, withParam: nil, error: error) + Auth.wrapMainAsync(callback: completion, with: .failure(error)) } } } @@ -2223,7 +2223,11 @@ extension Auth: AuthInterop { ((AuthDataResult?, Error?) -> Void)?) -> (AuthDataResult?, Error?) -> Void { let authDataCallback: (((AuthDataResult?, Error?) -> Void)?, AuthDataResult?, Error?) -> Void = { callback, result, error in - Auth.wrapMainAsync(callback: callback, withParam: result, error: error) + if let result { + Auth.wrapMainAsync(callback: callback, with: .success(result)) + } else if let error { + Auth.wrapMainAsync(callback: callback, with: .failure(error)) + } } return { authResult, error in if let error { @@ -2260,11 +2264,14 @@ extension Auth: AuthInterop { } class func wrapMainAsync(callback: ((T?, Error?) -> Void)?, - withParam param: T?, - error: Error?) -> Void { - if let callback { - DispatchQueue.main.async { - callback(param, error) + with result: Result) -> Void { + guard let callback else { return } + DispatchQueue.main.async { + switch result { + case let .success(success): + callback(success, nil) + case let .failure(error): + callback(nil, error) } } } diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift index 32d15499f74..330126542c8 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift @@ -86,9 +86,9 @@ import Foundation uiDelegate: uiDelegate, multiFactorSession: multiFactorSession ) - Auth.wrapMainAsync(callback: completion, withParam: verificationID, error: nil) + Auth.wrapMainAsync(callback: completion, with: .success(verificationID ?? "")) } catch { - Auth.wrapMainAsync(callback: completion, withParam: nil, error: error) + Auth.wrapMainAsync(callback: completion, with: .failure(error)) } } } From 5741f727bcca4380581b4b5f603c6a9ea09ba740 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 3 Sep 2024 12:31:34 -0400 Subject: [PATCH 02/14] Rework to remove optionality --- .../AuthProvider/PhoneAuthProvider.swift | 20 ++++++++++++------- .../SignIn/StartMFASignInResponse.swift | 2 +- .../RPC/SendVerificationTokenResponse.swift | 9 +++++++-- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift index 330126542c8..a8651d12e01 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift @@ -86,7 +86,7 @@ import Foundation uiDelegate: uiDelegate, multiFactorSession: multiFactorSession ) - Auth.wrapMainAsync(callback: completion, with: .success(verificationID ?? "")) + Auth.wrapMainAsync(callback: completion, with: .success(verificationID)) } catch { Auth.wrapMainAsync(callback: completion, with: .failure(error)) } @@ -184,7 +184,7 @@ import Foundation private func internalVerify(phoneNumber: String, uiDelegate: AuthUIDelegate?, multiFactorSession: MultiFactorSession? = nil) async throws - -> String? { + -> String { guard phoneNumber.count > 0 else { throw AuthErrorUtils.missingPhoneNumberError(message: nil) } @@ -209,7 +209,7 @@ import Foundation private func verifyClAndSendVerificationCode(toPhoneNumber phoneNumber: String, retryOnInvalidAppCredential: Bool, uiDelegate: AuthUIDelegate?) async throws - -> String? { + -> String { let codeIdentity = try await verifyClient(withUIDelegate: uiDelegate) let request = SendVerificationCodeRequest(phoneNumber: phoneNumber, codeIdentity: codeIdentity, @@ -236,7 +236,7 @@ import Foundation retryOnInvalidAppCredential: Bool, multiFactorSession session: MultiFactorSession?, uiDelegate: AuthUIDelegate?) async throws - -> String? { + -> String { if let settings = auth.settings, settings.isAppVerificationDisabledForTesting { let request = SendVerificationCodeRequest( @@ -264,7 +264,10 @@ import Foundation enrollmentInfo: startMFARequestInfo, requestConfiguration: auth.requestConfiguration) let response = try await AuthBackend.call(with: request) - return response.phoneSessionInfo?.sessionInfo + guard let sessionInfo = response.phoneSessionInfo?.sessionInfo else { + throw AuthErrorUtils.error(code: .missingMultiFactorInfo) + } + return sessionInfo } else { let request = StartMFASignInRequest(MFAPendingCredential: session.mfaPendingCredential, MFAEnrollmentID: session.multiFactorInfo?.uid, @@ -272,7 +275,10 @@ import Foundation requestConfiguration: auth.requestConfiguration) let response = try await AuthBackend.call(with: request) - return response.responseInfo?.sessionInfo + guard let sessionInfo = response.responseInfo?.sessionInfo else { + throw AuthErrorUtils.error(code: .multiFactorInfoNotFound) + } + return sessionInfo } } catch { return try await handleVerifyErrorWithRetry( @@ -289,7 +295,7 @@ import Foundation phoneNumber: String, retryOnInvalidAppCredential: Bool, multiFactorSession session: MultiFactorSession?, - uiDelegate: AuthUIDelegate?) async throws -> String? { + uiDelegate: AuthUIDelegate?) async throws -> String { if (error as NSError).code == AuthErrorCode.invalidAppCredential.rawValue { if retryOnInvalidAppCredential { auth.appCredentialManager.clearCredential() diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInResponse.swift index a2b3399d03e..883ed317bd2 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInResponse.swift @@ -18,7 +18,7 @@ import Foundation class StartMFASignInResponse: AuthRPCResponse { required init() {} - var responseInfo: AuthProtoStartMFAPhoneResponseInfo? + private(set) var responseInfo: AuthProtoStartMFAPhoneResponseInfo? func setFields(dictionary: [String: AnyHashable]) throws { if let data = dictionary["phoneResponseInfo"] as? [String: AnyHashable] { diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift index a532806c005..23fdc7fd9c7 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift @@ -14,12 +14,17 @@ import Foundation +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) class SendVerificationCodeResponse: AuthRPCResponse { required init() {} - var verificationID: String? + // Default value will be overridden when `setField(dictionary:)` is called. + private(set) var verificationID: String = "" func setFields(dictionary: [String: AnyHashable]) throws { - verificationID = dictionary["sessionInfo"] as? String + guard let verificationID = dictionary["sessionInfo"] as? String else { + throw AuthErrorUtils.unexpectedResponse(deserializedResponse: dictionary) + } + self.verificationID = verificationID } } From b2c894ceb281a890d0cfcf91f1973a429e1b945f Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 3 Sep 2024 14:29:14 -0400 Subject: [PATCH 03/14] fix test --- FirebaseAuth/Tests/Unit/RPCBaseTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAuth/Tests/Unit/RPCBaseTests.swift b/FirebaseAuth/Tests/Unit/RPCBaseTests.swift index 7e7b865287c..7245f13cd39 100644 --- a/FirebaseAuth/Tests/Unit/RPCBaseTests.swift +++ b/FirebaseAuth/Tests/Unit/RPCBaseTests.swift @@ -99,7 +99,7 @@ class RPCBaseTests: XCTestCase { XCTFail("decodedRequest is not a dictionary") } // Dummy response to unblock await. - let _ = try self.rpcIssuer?.respond(withJSON: [:]) + let _ = try self.rpcIssuer?.respond(withJSON: ["sessionInfo": "verification_id_123"]) } let _ = try await AuthBackend.call(with: request) } From 2dda025a40ec1e0455dfe34379f9384300b71da6 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Mon, 4 Nov 2024 18:59:13 -0500 Subject: [PATCH 04/14] remove unneeded diff --- .../Swift/Backend/RPC/SendVerificationTokenResponse.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift index e4f4db33d2e..8f844c25f8c 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift @@ -14,7 +14,6 @@ import Foundation -@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) struct SendVerificationCodeResponse: AuthRPCResponse { // Default value will be overridden when `setField(dictionary:)` is called. private(set) var verificationID: String = "" From 347828a7e91cc481309322ff1958f66044b629f4 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 19 Nov 2024 15:48:43 -0500 Subject: [PATCH 05/14] Additional result types --- FirebaseAuth/Sources/Swift/Auth/Auth.swift | 73 +++++++++---------- .../MultiFactor/MultiFactorResolver.swift | 2 +- 2 files changed, 35 insertions(+), 40 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Auth/Auth.swift b/FirebaseAuth/Sources/Swift/Auth/Auth.swift index 25308f8214c..c00b9f83f41 100644 --- a/FirebaseAuth/Sources/Swift/Auth/Auth.swift +++ b/FirebaseAuth/Sources/Swift/Auth/Auth.swift @@ -365,9 +365,9 @@ extension Auth: AuthInterop { withEmail: email, password: password ) - decoratedCallback(authData, nil) + decoratedCallback(.success(authData)) } catch { - decoratedCallback(nil, error) + decoratedCallback(.failure(error)) } } } @@ -463,9 +463,9 @@ extension Auth: AuthInterop { do { let authData = try await self.internalSignInAndRetrieveData(withCredential: credential, isReauthentication: false) - decoratedCallback(authData, nil) + decoratedCallback(.success(authData)) } catch { - decoratedCallback(nil, error) + decoratedCallback(.failure(error)) } } } @@ -544,9 +544,9 @@ extension Auth: AuthInterop { withCredential: credential, isReauthentication: false ) - decoratedCallback(authData, nil) + decoratedCallback(.success(authData)) } catch { - decoratedCallback(nil, error) + decoratedCallback(.failure(error)) } } } @@ -642,9 +642,9 @@ extension Auth: AuthInterop { do { let authData = try await self.internalSignInAndRetrieveData(withCredential: credential, isReauthentication: false) - decoratedCallback(authData, nil) + decoratedCallback(.success(authData)) } catch { - decoratedCallback(nil, error) + decoratedCallback(.failure(error)) } } } @@ -710,7 +710,7 @@ extension Auth: AuthInterop { let decoratedCallback = self.signInFlowAuthDataResultCallback(byDecorating: completion) if let currentUser = self._currentUser, currentUser.isAnonymous { let result = AuthDataResult(withUser: currentUser, additionalUserInfo: nil) - decoratedCallback(result, nil) + decoratedCallback(.success(result)) return } let request = SignUpNewUserRequest(requestConfiguration: self.requestConfiguration) @@ -728,10 +728,11 @@ extension Auth: AuthInterop { profile: nil, username: nil, isNewUser: true) - decoratedCallback(AuthDataResult(withUser: user, additionalUserInfo: additionalUserInfo), - nil) + decoratedCallback( + .success(AuthDataResult(withUser: user, additionalUserInfo: additionalUserInfo)) + ) } catch { - decoratedCallback(nil, error) + decoratedCallback(.failure(error)) } } } @@ -790,10 +791,11 @@ extension Auth: AuthInterop { profile: nil, username: nil, isNewUser: response.isNewUser) - decoratedCallback(AuthDataResult(withUser: user, additionalUserInfo: additionalUserInfo), - nil) + decoratedCallback( + .success(AuthDataResult(withUser: user, additionalUserInfo: additionalUserInfo)) + ) } catch { - decoratedCallback(nil, error) + decoratedCallback(.failure(error)) } } } @@ -866,7 +868,7 @@ extension Auth: AuthInterop { action: AuthRecaptchaAction.signUpPassword) { response, error in if let error { DispatchQueue.main.async { - decoratedCallback(nil, error) + decoratedCallback(.failure(error)) } return } @@ -881,7 +883,8 @@ extension Auth: AuthInterop { func internalCreateUserWithEmail(request: SignUpNewUserRequest, inResponse: SignUpNewUserResponse? = nil, - decoratedCallback: @escaping (AuthDataResult?, Error?) -> Void) { + decoratedCallback: @escaping (Result) + -> Void) { Task { do { var response: SignUpNewUserResponse @@ -900,11 +903,11 @@ extension Auth: AuthInterop { profile: nil, username: nil, isNewUser: true) - decoratedCallback(AuthDataResult(withUser: user, - additionalUserInfo: additionalUserInfo), - nil) + decoratedCallback( + .success(AuthDataResult(withUser: user, additionalUserInfo: additionalUserInfo)) + ) } catch { - decoratedCallback(nil, error) + decoratedCallback(.failure(error)) } } } @@ -2238,27 +2241,19 @@ extension Auth: AuthInterop { /// Invoked asynchronously on the main thread in the future. /// - Returns: Returns a block that updates the current user. func signInFlowAuthDataResultCallback(byDecorating callback: - ((AuthDataResult?, Error?) -> Void)?) -> (AuthDataResult?, Error?) -> Void { - let authDataCallback: (((AuthDataResult?, Error?) -> Void)?, AuthDataResult?, Error?) -> Void = - { callback, result, error in - if let result { - Auth.wrapMainAsync(callback: callback, with: .success(result)) - } else if let error { + ((AuthDataResult?, Error?) -> Void)?) -> (Result) -> Void { + return { result in + switch result { + case let .success(authResult): + do { + try self.updateCurrentUser(authResult.user, byForce: false, savingToDisk: true) + Auth.wrapMainAsync(callback: callback, with: .success(authResult)) + } catch { Auth.wrapMainAsync(callback: callback, with: .failure(error)) } + case let .failure(error): + Auth.wrapMainAsync(callback: callback, with: .failure(error)) } - return { authResult, error in - if let error { - authDataCallback(callback, nil, error) - return - } - do { - try self.updateCurrentUser(authResult?.user, byForce: false, savingToDisk: true) - } catch { - authDataCallback(callback, nil, error) - return - } - authDataCallback(callback, authResult, nil) } } diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorResolver.swift b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorResolver.swift index 366ccc02023..223c1f9f5f5 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorResolver.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorResolver.swift @@ -80,7 +80,7 @@ import Foundation let result = AuthDataResult(withUser: user, additionalUserInfo: nil) let decoratedCallback = self.auth .signInFlowAuthDataResultCallback(byDecorating: completion) - decoratedCallback(result, nil) + decoratedCallback(.success(result)) } catch { if let completion { completion(nil, error) From 735ee6a7eba10dc382b152974a527b0c2dc6b1d1 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 19 Nov 2024 16:11:56 -0500 Subject: [PATCH 06/14] make responseInfo a constant --- .../Sources/Swift/AuthProvider/PhoneAuthProvider.swift | 2 +- .../RPC/MultiFactor/SignIn/StartMFASignInResponse.swift | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift index 2b0e1407ad7..b8d0fdfc39d 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift @@ -274,7 +274,7 @@ import Foundation signInInfo: startMFARequestInfo, requestConfiguration: auth.requestConfiguration) let response = try await auth.backend.call(with: request) - guard let sessionInfo = response.responseInfo?.sessionInfo else { + guard let sessionInfo = response.responseInfo.sessionInfo else { throw AuthErrorUtils.error(code: .multiFactorInfoNotFound) } return sessionInfo diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInResponse.swift index f65e084591f..35fc6f0bb4b 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInResponse.swift @@ -16,8 +16,7 @@ import Foundation @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) struct StartMFASignInResponse: AuthRPCResponse { -// var responseInfo: AuthProtoStartMFAPhoneResponseInfo? - private(set) var responseInfo: AuthProtoStartMFAPhoneResponseInfo? + let responseInfo: AuthProtoStartMFAPhoneResponseInfo init(dictionary: [String: AnyHashable]) throws { if let data = dictionary["phoneResponseInfo"] as? [String: AnyHashable] { From ccda62490744c0ad8f92cca79df457841fc5747b Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 19 Nov 2024 16:13:47 -0500 Subject: [PATCH 07/14] make responseInfo a constant (2) --- .../Swift/Backend/RPC/SendVerificationTokenResponse.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift index 87fc1f549f8..afa9a104b19 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift @@ -15,8 +15,7 @@ import Foundation struct SendVerificationCodeResponse: AuthRPCResponse { - // Default value will be overridden when `setField(dictionary:)` is called. - private(set) var verificationID: String = "" + let verificationID: String init(dictionary: [String: AnyHashable]) throws { guard let verificationID = dictionary["sessionInfo"] as? String else { From 1272db0f8837540afa124ba540c9e833d07b1c2b Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 19 Nov 2024 17:46:55 -0500 Subject: [PATCH 08/14] Fix CI --- .../Swift/Backend/RPC/SendVerificationTokenResponse.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift index afa9a104b19..f7541607e75 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift @@ -14,6 +14,7 @@ import Foundation +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) struct SendVerificationCodeResponse: AuthRPCResponse { let verificationID: String From 61f2714a630ae2e50fe0e163466765e3a014a8fa Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 3 Dec 2024 16:49:25 -0500 Subject: [PATCH 09/14] Fix some build issues --- .../Sources/Swift/AuthProvider/PhoneAuthProvider.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift index 9a536743c1c..84d4234b9f9 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift @@ -191,7 +191,7 @@ import Foundation private func internalVerify(phoneNumber: String, uiDelegate: AuthUIDelegate?, multiFactorSession: MultiFactorSession? = nil) async throws - -> String { + -> String? { guard !phoneNumber.isEmpty else { throw AuthErrorUtils.missingPhoneNumberError(message: nil) } @@ -236,7 +236,7 @@ import Foundation retryOnInvalidAppCredential: Bool, uiDelegate: AuthUIDelegate?, recaptchaVerifier: AuthRecaptchaVerifier) async throws - -> String? { + -> String { let request = SendVerificationCodeRequest(phoneNumber: phoneNumber, codeIdentity: CodeIdentity.empty, requestConfiguration: auth @@ -350,7 +350,7 @@ import Foundation action: .mfaSmsSignIn ) let response = try await auth.backend.call(with: request) - return response.responseInfo?.sessionInfo + return response.responseInfo.sessionInfo } } catch { // For Audit fallback only after rCE check failed From e7948182f6f63ee7a5aa5ffd9cdde8742aa47ce0 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 3 Dec 2024 16:53:31 -0500 Subject: [PATCH 10/14] Remove some of the thrown errors in favor of optionals --- .../Swift/AuthProvider/PhoneAuthProvider.swift | 18 ++++++------------ .../RPC/SendVerificationTokenResponse.swift | 7 ++----- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift index 84d4234b9f9..b50636615cc 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift @@ -236,7 +236,7 @@ import Foundation retryOnInvalidAppCredential: Bool, uiDelegate: AuthUIDelegate?, recaptchaVerifier: AuthRecaptchaVerifier) async throws - -> String { + -> String? { let request = SendVerificationCodeRequest(phoneNumber: phoneNumber, codeIdentity: CodeIdentity.empty, requestConfiguration: auth @@ -269,7 +269,7 @@ import Foundation retryOnInvalidAppCredential: Bool, uiDelegate: AuthUIDelegate?, auditFallback: Bool = false) async throws - -> String { + -> String? { let codeIdentity = try await verifyClient(withUIDelegate: uiDelegate) let request = SendVerificationCodeRequest(phoneNumber: phoneNumber, codeIdentity: codeIdentity, @@ -375,7 +375,7 @@ import Foundation multiFactorSession session: MultiFactorSession?, uiDelegate: AuthUIDelegate?, auditFallback: Bool = false) async throws - -> String { + -> String? { if let settings = auth.settings, settings.isAppVerificationDisabledForTesting { let request = SendVerificationCodeRequest( @@ -413,20 +413,14 @@ import Foundation enrollmentInfo: startMFARequestInfo, requestConfiguration: auth.requestConfiguration) let response = try await auth.backend.call(with: request) - guard let sessionInfo = response.phoneSessionInfo?.sessionInfo else { - throw AuthErrorUtils.error(code: .missingMultiFactorInfo) - } - return sessionInfo + return response.phoneSessionInfo?.sessionInfo } else { let request = StartMFASignInRequest(MFAPendingCredential: session.mfaPendingCredential, MFAEnrollmentID: session.multiFactorInfo?.uid, signInInfo: startMFARequestInfo, requestConfiguration: auth.requestConfiguration) let response = try await auth.backend.call(with: request) - guard let sessionInfo = response.responseInfo.sessionInfo else { - throw AuthErrorUtils.error(code: .multiFactorInfoNotFound) - } - return sessionInfo + return response.responseInfo.sessionInfo } } catch { return try await handleVerifyErrorWithRetry( @@ -446,7 +440,7 @@ import Foundation retryOnInvalidAppCredential: Bool, multiFactorSession session: MultiFactorSession?, uiDelegate: AuthUIDelegate?, - auditFallback: Bool = false) async throws -> String { + auditFallback: Bool = false) async throws -> String? { if (error as NSError).code == AuthErrorCode.invalidAppCredential.rawValue { if retryOnInvalidAppCredential { auth.appCredentialManager.clearCredential() diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift index f7541607e75..b8c64b3928b 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift @@ -16,12 +16,9 @@ import Foundation @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) struct SendVerificationCodeResponse: AuthRPCResponse { - let verificationID: String + let verificationID: String? init(dictionary: [String: AnyHashable]) throws { - guard let verificationID = dictionary["sessionInfo"] as? String else { - throw AuthErrorUtils.unexpectedResponse(deserializedResponse: dictionary) - } - self.verificationID = verificationID + verificationID = dictionary["sessionInfo"] as? String } } From 935c28cf87b838003f2c5c05b1dec36830f70e33 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 3 Dec 2024 16:57:27 -0500 Subject: [PATCH 11/14] Remove unneeded availability wrap --- .../Swift/Backend/RPC/SendVerificationTokenResponse.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift index b8c64b3928b..7cbd45a7a44 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift @@ -14,7 +14,6 @@ import Foundation -@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) struct SendVerificationCodeResponse: AuthRPCResponse { let verificationID: String? From 9334a93172687d63ace7b3e06c9500ebea089272 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 3 Dec 2024 17:02:14 -0500 Subject: [PATCH 12/14] style --- FirebaseAuth/Sources/Swift/Auth/Auth.swift | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Auth/Auth.swift b/FirebaseAuth/Sources/Swift/Auth/Auth.swift index 0e1212c6467..27aeccf4ece 100644 --- a/FirebaseAuth/Sources/Swift/Auth/Auth.swift +++ b/FirebaseAuth/Sources/Swift/Auth/Auth.swift @@ -2281,10 +2281,8 @@ extension Auth: AuthInterop { guard let callback else { return } DispatchQueue.main.async { switch result { - case let .success(success): - callback(success, nil) - case let .failure(error): - callback(nil, error) + case let .success(success): callback(success, nil) + case let .failure(error): callback(nil, error) } } } From 59c7a1ce94ef779648f9ef1aec0f2dce806f28a4 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 3 Dec 2024 17:06:25 -0500 Subject: [PATCH 13/14] ci From 3b1df3b674b853de41e3324e468c4d5076cee550 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 3 Dec 2024 17:36:14 -0500 Subject: [PATCH 14/14] Remove unneeded test code --- FirebaseAuth/Tests/Unit/RPCBaseTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAuth/Tests/Unit/RPCBaseTests.swift b/FirebaseAuth/Tests/Unit/RPCBaseTests.swift index 5ece08c9f09..8ff45d7d073 100644 --- a/FirebaseAuth/Tests/Unit/RPCBaseTests.swift +++ b/FirebaseAuth/Tests/Unit/RPCBaseTests.swift @@ -99,7 +99,7 @@ class RPCBaseTests: XCTestCase { XCTFail("decodedRequest is not a dictionary") } // Dummy response to unblock await. - let _ = try self.rpcIssuer?.respond(withJSON: ["sessionInfo": "verification_id_123"]) + let _ = try self.rpcIssuer?.respond(withJSON: [:]) } let _ = try await authBackend.call(with: request) }