Skip to content

Commit

Permalink
[Auth] Refactor MultiFactor.swift (#14241)
Browse files Browse the repository at this point in the history
  • Loading branch information
ncooke3 authored Jan 6, 2025
1 parent ffe6cf2 commit c092c02
Showing 1 changed file with 77 additions and 83 deletions.
160 changes: 77 additions & 83 deletions FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,104 +67,98 @@ import Foundation
displayName: String?,
completion: ((Error?) -> Void)?) {
// TODO: Refactor classes so this duplicated code isn't necessary for phone and totp.

guard
assertion.factorID == PhoneMultiFactorInfo.TOTPMultiFactorID ||
assertion.factorID == PhoneMultiFactorInfo.PhoneMultiFactorID
else {
return
}

guard let user, let auth = user.auth else {
fatalError("Internal Auth error: failed to get user enrolling in MultiFactor")
}

let request = Self.enrollmentFinalizationRequest(
with: assertion,
displayName: displayName,
user: user,
auth: auth
)

Task {
do {
let response = try await auth.backend.call(with: request)
let user = try await auth.completeSignIn(withAccessToken: response.idToken,
accessTokenExpirationDate: nil,
refreshToken: response.refreshToken,
anonymous: false)
try auth.updateCurrentUser(user, byForce: false, savingToDisk: true)
if let completion {
DispatchQueue.main.async {
completion(nil)
}
}
} catch {
if let completion {
DispatchQueue.main.async {
completion(error)
}
}
}
}
}

private static func enrollmentFinalizationRequest(with assertion: MultiFactorAssertion,
displayName: String?,
user: User,
auth: Auth) -> FinalizeMFAEnrollmentRequest {
var request: FinalizeMFAEnrollmentRequest? = nil
if assertion.factorID == PhoneMultiFactorInfo.TOTPMultiFactorID {
guard let totpAssertion = assertion as? TOTPMultiFactorAssertion else {
fatalError("Auth Internal Error: Failed to find TOTPMultiFactorAssertion")
}
switch totpAssertion.secretOrID {
case .enrollmentID: fatalError("Missing secret in totpAssertion")
case let .secret(secret):
guard let user = user, let auth = user.auth else {
fatalError("Internal Auth error: failed to get user enrolling in MultiFactor")
}
let finalizeMFATOTPRequestInfo =
AuthProtoFinalizeMFATOTPEnrollmentRequestInfo(sessionInfo: secret.sessionInfo,
verificationCode: totpAssertion
.oneTimePassword)
let request = FinalizeMFAEnrollmentRequest(idToken: self.user?.rawAccessToken(),
displayName: displayName,
totpVerificationInfo: finalizeMFATOTPRequestInfo,
requestConfiguration: user
.requestConfiguration)
Task {
do {
let response = try await auth.backend.call(with: request)
do {
let user = try await auth.completeSignIn(withAccessToken: response.idToken,
accessTokenExpirationDate: nil,
refreshToken: response.refreshToken,
anonymous: false)
try auth.updateCurrentUser(user, byForce: false, savingToDisk: true)
if let completion {
DispatchQueue.main.async {
completion(nil)
}
}
} catch {
DispatchQueue.main.async {
if let completion {
completion(error)
}
}
}
} catch {
if let completion {
completion(error)
}
}
}
request = FinalizeMFAEnrollmentRequest(idToken: user.rawAccessToken(),
displayName: displayName,
totpVerificationInfo: finalizeMFATOTPRequestInfo,
requestConfiguration: user
.requestConfiguration)
}
return
} else if assertion.factorID != PhoneMultiFactorInfo.PhoneMultiFactorID {
return
}
let phoneAssertion = assertion as? PhoneMultiFactorAssertion
guard let credential = phoneAssertion?.authCredential else {
fatalError("Internal Error: Missing credential")
}
switch credential.credentialKind {
case .phoneNumber: fatalError("Internal Error: Missing verificationCode")
case let .verification(verificationID, code):
let finalizeMFAPhoneRequestInfo =
AuthProtoFinalizeMFAPhoneRequestInfo(sessionInfo: verificationID, verificationCode: code)
guard let user = user, let auth = user.auth else {
fatalError("Internal Auth error: failed to get user enrolling in MultiFactor")
} else if assertion.factorID == PhoneMultiFactorInfo.PhoneMultiFactorID {
let phoneAssertion = assertion as? PhoneMultiFactorAssertion
guard let credential = phoneAssertion?.authCredential else {
fatalError("Internal Error: Missing credential")
}
let request = FinalizeMFAEnrollmentRequest(
idToken: self.user?.rawAccessToken(),
displayName: displayName,
phoneVerificationInfo: finalizeMFAPhoneRequestInfo,
requestConfiguration: user.requestConfiguration
)

Task {
do {
let response = try await auth.backend.call(with: request)
do {
let user = try await auth.completeSignIn(withAccessToken: response.idToken,
accessTokenExpirationDate: nil,
refreshToken: response.refreshToken,
anonymous: false)
try auth.updateCurrentUser(user, byForce: false, savingToDisk: true)
if let completion {
DispatchQueue.main.async {
completion(nil)
}
}
} catch {
DispatchQueue.main.async {
if let completion {
completion(error)
}
}
}
} catch {
if let completion {
completion(error)
}
}
switch credential.credentialKind {
case .phoneNumber: fatalError("Internal Error: Missing verificationCode")
case let .verification(verificationID, code):
let finalizeMFAPhoneRequestInfo =
AuthProtoFinalizeMFAPhoneRequestInfo(
sessionInfo: verificationID,
verificationCode: code
)
request = FinalizeMFAEnrollmentRequest(
idToken: user.rawAccessToken(),
displayName: displayName,
phoneVerificationInfo: finalizeMFAPhoneRequestInfo,
requestConfiguration: user.requestConfiguration
)
}
}

guard let request else {
// Assertion is not a phone assertion or TOTP assertion.
fatalError("Internal Error: Unsupported assertion with factor ID: \(assertion.factorID).")
}

return request
}

/// Enrolls a second factor as identified by the `MultiFactorAssertion` parameter for the
Expand Down

0 comments on commit c092c02

Please sign in to comment.