Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions FirebaseAuth/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
off of the main actor or main thread.
- [fixed] Simplified completion handler memory management in Auth interop
(#14962).
- [added] Added TOTP support for macOS.

# 11.15.0
- [fixed] Fixed `Sendable` warnings introduced in the Xcode 26 beta. (#14996)
Expand Down
2 changes: 1 addition & 1 deletion FirebaseAuth/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Firebase Auth for iOS
# Firebase Auth for iOS and macOS

Firebase Auth enables apps to easily support multiple authentication options
for their end users.
Expand Down
2 changes: 1 addition & 1 deletion FirebaseAuth/Sources/ObjC/FIRMultiFactorConstants.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

#import <TargetConditionals.h>
#if TARGET_OS_IOS
#if TARGET_OS_IOS || TARGET_OS_OSX

#import <Foundation/Foundation.h>

Expand Down
15 changes: 7 additions & 8 deletions FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
Expand All @@ -22,27 +22,26 @@ NS_ASSUME_NONNULL_BEGIN

/** @typedef FIRMultiFactorSessionCallback
@brief The callback that triggered when a developer calls `getSessionWithCompletion`.
This type is available on iOS only.
This type is available on iOS and macOS.
@param session The multi factor session returned, if any.
@param error The error which occurred, if any.
*/
typedef void (^FIRMultiFactorSessionCallback)(FIRMultiFactorSession *_Nullable session,
NSError *_Nullable error)
NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead.")
API_UNAVAILABLE(macos, tvos, watchos);
NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead.") API_UNAVAILABLE(tvos, watchos);

/**
@brief The string identifier for using phone as a second factor.
This constant is available on iOS only.
This constant is available on iOS and macOS.
*/
extern NSString *const _Nonnull FIRPhoneMultiFactorID NS_SWIFT_NAME(PhoneMultiFactorID)
API_UNAVAILABLE(macos, tvos, watchos);
API_UNAVAILABLE(tvos, watchos);

/**
@brief The string identifier for using TOTP as a second factor.
This constant is available on iOS only.
This constant is available on iOS and macOS.
*/
extern NSString *const _Nonnull FIRTOTPMultiFactorID NS_SWIFT_NAME(TOTPMultiFactorID)
API_UNAVAILABLE(macos, tvos, watchos);
API_UNAVAILABLE(tvos, watchos);

NS_ASSUME_NONNULL_END
17 changes: 17 additions & 0 deletions FirebaseAuth/Sources/Public/FirebaseAuth/FIRTOTPSecret.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright 2019 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

@class FIRTOTPSecret;
1 change: 1 addition & 0 deletions FirebaseAuth/Sources/Public/FirebaseAuth/FirebaseAuth.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@
#import "FIRGoogleAuthProvider.h"
#import "FIRMultiFactor.h"
#import "FIRPhoneAuthProvider.h"
#import "FIRTOTPSecret.h"
#import "FIRTwitterAuthProvider.h"
4 changes: 2 additions & 2 deletions FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ final class AuthBackend: AuthBackendProtocol {
}

private static func generateMFAError(response: AuthRPCResponse, auth: Auth) -> Error? {
#if !os(iOS)
#if !os(iOS) || !os(macOS)
return nil
#else
if let mfaResponse = response as? AuthMFAResponse,
Expand All @@ -124,7 +124,7 @@ final class AuthBackend: AuthBackendProtocol {
} else {
return nil
}
#endif // !os(iOS)
#endif // !os(iOS) || !os(macOS)
}

// Check whether or not the successful response is actually the special case phone
Expand Down
4 changes: 2 additions & 2 deletions FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@

import Foundation

#if os(iOS)
#if os(iOS) || os(macOS)

@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
extension MultiFactor: NSSecureCoding {}

/// The interface defining the multi factor related properties and operations pertaining to a
/// user.
///
/// This class is available on iOS only.
/// This class is available on iOS and macOS.
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
@objc(FIRMultiFactor) open class MultiFactor: NSObject {
@objc open var enrolledFactors: [MultiFactorInfo]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@

import Foundation

#if os(iOS)
#if os(iOS) || os(macOS)

/// The base class for asserting ownership of a second factor. This is equivalent to the
/// AuthCredential class.
///
/// This class is available on iOS only.
/// This class is available on iOS and macOS.
@objc(FIRMultiFactorAssertion) open class MultiFactorAssertion: NSObject {
/// The second factor identifier for this opaque object asserting a second factor.
@objc open var factorID: String
Expand Down
4 changes: 2 additions & 2 deletions FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ import Foundation

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

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

/// Safe public structure used to represent a second factor entity from a client perspective.
///
/// This class is available on iOS only.
/// This class is available on iOS and macOS.
@objc(FIRMultiFactorInfo) open class MultiFactorInfo: NSObject, @unchecked Sendable {
/// The multi-factor enrollment ID.
@objc(UID) public let uid: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@

import Foundation

#if os(iOS)
#if os(iOS) || os(macOS)

/// The subclass of base class `MultiFactorAssertion`, used to assert ownership of a phone
/// second factor.
///
/// This class is available on iOS only.
/// This class is available on iOS and macOS.
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
@objc(FIRMultiFactorResolver)
open class MultiFactorResolver: NSObject {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import Foundation

#if os(iOS)
#if os(iOS) || os(macOS)

/// Opaque object that identifies the current session to enroll a second factor or to
/// complete sign in when previously enrolled.
Expand All @@ -23,7 +23,7 @@ import Foundation
/// or to complete sign in when previously enrolled. It contains additional context on the
/// existing user, notably the confirmation that the user passed the first factor challenge.
///
/// This class is available on iOS only.
/// This class is available on iOS and macOS.
@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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@

import Foundation

#if os(iOS)
#if os(iOS) || os(macOS)

/// The subclass of base class FIRMultiFactorAssertion, used to assert ownership of a phone
/// second factor.
///
/// This class is available on iOS only.
/// This class is available on iOS and macOS.
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
@objc(FIRPhoneMultiFactorAssertion) open class PhoneMultiFactorAssertion: MultiFactorAssertion {
var authCredential: PhoneAuthCredential?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@

import Foundation

#if os(iOS)
#if os(iOS) || os(macOS)

/// The data structure used to help initialize an assertion for a second factor entity to the
/// Firebase Auth/CICP server.
///
/// Depending on the type of second factor, this will help generate the assertion.
///
/// This class is available on iOS only.
/// This class is available on iOS and macOS.
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
@objc(FIRPhoneMultiFactorGenerator)
open class PhoneMultiFactorGenerator: NSObject {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ import Foundation

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

#if os(iOS)
#if os(iOS) || os(macOS)

/// Extends the MultiFactorInfo class for phone number second factors.
///
/// The identifier of this second factor is "phone".
///
/// This class is available on iOS only.
/// This class is available on iOS and macOS.
@objc(FIRPhoneMultiFactorInfo) open class PhoneMultiFactorInfo: MultiFactorInfo,
@unchecked Sendable {
/// The string identifier for using phone as a second factor.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import Foundation

#if os(iOS)
#if os(iOS) || os(macOS)

enum SecretOrID {
case secret(TOTPSecret)
Expand All @@ -24,7 +24,7 @@ import Foundation
/// The subclass of base class MultiFactorAssertion, used to assert ownership of a TOTP
/// (Time-based One Time Password) second factor.
///
/// This class is available on iOS only.
/// This class is available on iOS and macOS.
@objc(FIRTOTPMultiFactorAssertion) open class TOTPMultiFactorAssertion: MultiFactorAssertion {
let oneTimePassword: String
let secretOrID: SecretOrID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@

import Foundation

#if os(iOS)
#if os(iOS) || os(macOS)

/// The data structure used to help initialize an assertion for a second factor entity to the
/// Firebase Auth/CICP server. Depending on the type of second factor, this will help generate
/// the assertion.
///
/// This class is available on iOS only.
/// This class is available on iOS and macOS.
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
@objc(FIRTOTPMultiFactorGenerator) open class TOTPMultiFactorGenerator: NSObject {
/// Creates a TOTP secret as part of enrolling a TOTP second factor. Used for generating a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ import Foundation
// TODO(Swift 6 Breaking): Make checked Sendable. Also, does this need
// to be public?

#if os(iOS)
#if os(iOS) || os(macOS)

/// 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.
/// This class is available on iOS and macOS.
class TOTPMultiFactorInfo: MultiFactorInfo, @unchecked Sendable {
/// Initialize the AuthProtoMFAEnrollment instance with proto.
/// - Parameter proto: AuthProtoMFAEnrollment proto object.
Expand Down
50 changes: 32 additions & 18 deletions FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPSecret.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@ import Foundation
internal import GoogleUtilities_Environment
#endif

#if os(iOS)
import UIKit
#if os(iOS) || os(macOS)
#if os(iOS)
import UIKit
#elseif os(macOS)
import AppKit
#endif

/// The subclass of base class MultiFactorAssertion, used to assert ownership of a TOTP
/// (Time-based One Time Password) second factor.
///
/// This class is available on iOS only.
/// This class is available on iOS and macOS.
@objc(FIRTOTPSecret) open class TOTPSecret: NSObject {
/// Returns the shared secret key/seed used to generate time-based one-time passwords.
@objc open func sharedSecretKey() -> String {
Expand Down Expand Up @@ -57,24 +61,34 @@ import Foundation
@MainActor @objc(openInOTPAppWithQRCodeURL:)
open func openInOTPApp(withQRCodeURL qrCodeURL: String) {
if GULAppEnvironmentUtil.isAppExtension() {
// iOS App extensions should not call [UIApplication sharedApplication], even if
// UIApplication responds to it.
// App extensions should not call [UIApplication sharedApplication] or [NSWorkspace
// sharedWorkspace],
// even if they respond to it.
return
}

// Using reflection here to avoid build errors in extensions.
let sel = NSSelectorFromString("sharedApplication")
guard UIApplication.responds(to: sel),
let rawApplication = UIApplication.perform(sel),
let application = rawApplication.takeUnretainedValue() as? UIApplication else {
return
}
if let url = URL(string: qrCodeURL), application.canOpenURL(url) {
application.open(url, options: [:], completionHandler: nil)
} else {
AuthLog.logError(code: "I-AUT000019",
message: "URL: \(qrCodeURL) cannot be opened")
}
#if os(iOS)
// Using reflection here to avoid build errors in extensions.
let sel = NSSelectorFromString("sharedApplication")
guard UIApplication.responds(to: sel),
let rawApplication = UIApplication.perform(sel),
let application = rawApplication.takeUnretainedValue() as? UIApplication else {
return
}
if let url = URL(string: qrCodeURL), application.canOpenURL(url) {
application.open(url, options: [:], completionHandler: nil)
} else {
AuthLog.logError(code: "I-AUT000019",
message: "URL: \(qrCodeURL) cannot be opened")
}
#elseif os(macOS)
if let url = URL(string: qrCodeURL) {
NSWorkspace.shared.open(url)
} else {
AuthLog.logError(code: "I-AUT000019",
message: "URL: \(qrCodeURL) cannot be opened")
}
#endif
}

/// Shared secret key/seed used for enrolling in TOTP MFA and generating OTPs.
Expand Down
Loading
Loading