Skip to content

[Auth] More Swift 6 progress #14867

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 8 additions & 12 deletions FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
import FirebaseCore
import Foundation

// TODO(Swift 6 Breaking): Make checked Sendable.

/// A concrete implementation of `AuthProvider` for phone auth providers.
///
/// This class is available on iOS only.
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
@objc(FIRPhoneAuthProvider) open class PhoneAuthProvider: NSObject {
@objc(FIRPhoneAuthProvider) open class PhoneAuthProvider: NSObject, @unchecked Sendable {
/// A string constant identifying the phone identity provider.
@objc public static let id = "phone"
private static let recaptchaVersion = "RECAPTCHA_ENTERPRISE"
Expand Down Expand Up @@ -56,7 +58,7 @@ import Foundation
@objc(verifyPhoneNumber:UIDelegate:completion:)
open func verifyPhoneNumber(_ phoneNumber: String,
uiDelegate: AuthUIDelegate? = nil,
completion: ((_: String?, _: Error?) -> Void)?) {
completion: (@MainActor (String?, Error?) -> Void)?) {
verifyPhoneNumber(phoneNumber,
uiDelegate: uiDelegate,
multiFactorSession: nil,
Expand All @@ -75,21 +77,17 @@ import Foundation
open func verifyPhoneNumber(_ phoneNumber: String,
uiDelegate: AuthUIDelegate? = nil,
multiFactorSession: MultiFactorSession? = nil,
completion: ((_: String?, _: Error?) -> Void)?) {
completion: (@MainActor (String?, Error?) -> Void)?) {
Task {
do {
let verificationID = try await verifyPhoneNumber(
phoneNumber,
uiDelegate: uiDelegate,
multiFactorSession: multiFactorSession
)
await MainActor.run {
completion?(verificationID, nil)
}
await completion?(verificationID, nil)
} catch {
await MainActor.run {
completion?(nil, error)
}
await completion?(nil, error)
}
}
}
Expand Down Expand Up @@ -135,7 +133,7 @@ import Foundation
open func verifyPhoneNumber(with multiFactorInfo: PhoneMultiFactorInfo,
uiDelegate: AuthUIDelegate? = nil,
multiFactorSession: MultiFactorSession?,
completion: ((_: String?, _: Error?) -> Void)?) {
completion: ((String?, Error?) -> Void)?) {
Task {
do {
let verificationID = try await verifyPhoneNumber(
Expand Down Expand Up @@ -641,7 +639,6 @@ import Foundation
private let auth: Auth
private let callbackScheme: String
private let usingClientIDScheme: Bool
private var recaptchaVerifier: AuthRecaptchaVerifier?

init(auth: Auth) {
self.auth = auth
Expand All @@ -662,7 +659,6 @@ import Foundation
return
}
callbackScheme = ""
recaptchaVerifier = AuthRecaptchaVerifier.shared(auth: auth)
}

private let kAuthTypeVerifyApp = "verifyApp"
Expand Down
4 changes: 3 additions & 1 deletion FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@

import Foundation

// TODO(Swift 6 Breaking): Make checked Sendable.

#if os(iOS)
extension MultiFactorInfo: NSSecureCoding {}

/// Safe public structure used to represent a second factor entity from a client perspective.
///
/// This class is available on iOS only.
@objc(FIRMultiFactorInfo) open class MultiFactorInfo: NSObject {
@objc(FIRMultiFactorInfo) open class MultiFactorInfo: NSObject, @unchecked Sendable {
/// The multi-factor enrollment ID.
@objc(UID) public let uid: String

Expand Down
35 changes: 24 additions & 11 deletions FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,33 +27,46 @@ import Foundation
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
@objc(FIRMultiFactorSession) open class MultiFactorSession: NSObject {
/// The ID token for an enroll flow. This has to be retrieved after recent authentication.
var idToken: String?
let idToken: String?

/// The pending credential after an enrolled second factor user signs in successfully with the
/// first factor.
var mfaPendingCredential: String?
let mfaPendingCredential: String?

/// Current user object.
let currentUser: User?

/// Multi factor info for the current user.
var multiFactorInfo: MultiFactorInfo?

/// Current user object.
var currentUser: User?

class func session(for user: User?) -> MultiFactorSession {
let currentUser = user ?? Auth.auth().currentUser
guard let currentUser else {
fatalError("Internal Auth Error: missing user for multifactor auth")
}
return .init(idToken: currentUser.tokenService.accessToken, currentUser: currentUser)
return .init(
idToken: currentUser.tokenService.accessToken,
mfaPendingCredential: nil,
multiFactorInfo: nil,
currentUser: currentUser
)
}

init(idToken: String?, currentUser: User) {
self.idToken = idToken
self.currentUser = currentUser
convenience init(mfaCredential: String?) {
self.init(
idToken: nil,
mfaPendingCredential: mfaCredential,
multiFactorInfo: nil,
currentUser: nil
)
}

init(mfaCredential: String?) {
mfaPendingCredential = mfaCredential
private init(idToken: String?, mfaPendingCredential: String?, multiFactorInfo: MultiFactorInfo?,
currentUser: User?) {
self.idToken = idToken
self.mfaPendingCredential = mfaPendingCredential
self.multiFactorInfo = multiFactorInfo
self.currentUser = currentUser
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@

import Foundation

// TODO(Swift 6 Breaking): Make checked Sendable.

#if os(iOS)

/// Extends the MultiFactorInfo class for phone number second factors.
///
/// The identifier of this second factor is "phone".
///
/// This class is available on iOS only.
@objc(FIRPhoneMultiFactorInfo) open class PhoneMultiFactorInfo: MultiFactorInfo {
@objc(FIRPhoneMultiFactorInfo) open class PhoneMultiFactorInfo: MultiFactorInfo,
@unchecked Sendable {
/// The string identifier for using phone as a second factor.
@objc(FIRPhoneMultiFactorID) public static let PhoneMultiFactorID = "phone"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@

import Foundation

// TODO(Swift 6 Breaking): Make checked Sendable. Also, does this need
// to be public?

#if os(iOS)

/// Extends the MultiFactorInfo class for time based one-time password second factors.
///
/// The identifier of this second factor is "totp".
///
/// This class is available on iOS only.
class TOTPMultiFactorInfo: MultiFactorInfo {
class TOTPMultiFactorInfo: MultiFactorInfo, @unchecked Sendable {
/// Initialize the AuthProtoMFAEnrollment instance with proto.
/// - Parameter proto: AuthProtoMFAEnrollment proto object.
init(proto: AuthProtoMFAEnrollment) {
Expand Down