diff --git a/Auth0.podspec b/Auth0.podspec index 9676f69c..7f4334a1 100644 --- a/Auth0.podspec +++ b/Auth0.podspec @@ -41,22 +41,22 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/auth0/Auth0.swift.git', :tag => s.version.to_s } s.social_media_url = 'https://twitter.com/auth0' s.source_files = 'Auth0/*.swift' - s.swift_versions = ['5.5', '5.6', '5.7'] + s.swift_versions = ['5.7', '5.8'] s.dependency 'SimpleKeychain', '~> 1.0' s.dependency 'JWTDecode', '~> 3.0' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.ios.exclude_files = macos_files s.ios.pod_target_xcconfig = { 'SWIFT_ACTIVE_COMPILATION_CONDITIONS' => 'WEB_AUTH_PLATFORM' } - s.osx.deployment_target = '10.15' + s.osx.deployment_target = '11.0' s.osx.exclude_files = ios_files s.osx.pod_target_xcconfig = { 'SWIFT_ACTIVE_COMPILATION_CONDITIONS' => 'WEB_AUTH_PLATFORM' } - s.tvos.deployment_target = '12.0' + s.tvos.deployment_target = '13.0' s.tvos.exclude_files = excluded_files - s.watchos.deployment_target = '6.2' + s.watchos.deployment_target = '7.0' s.watchos.exclude_files = excluded_files end diff --git a/Auth0.xcodeproj/project.pbxproj b/Auth0.xcodeproj/project.pbxproj index 03a7006a..26cc5022 100644 --- a/Auth0.xcodeproj/project.pbxproj +++ b/Auth0.xcodeproj/project.pbxproj @@ -2039,7 +2039,7 @@ SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 12.0; + TVOS_DEPLOYMENT_TARGET = 13.0; }; name = Debug; }; @@ -2071,7 +2071,7 @@ SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 12.0; + TVOS_DEPLOYMENT_TARGET = 13.0; }; name = Release; }; @@ -2098,7 +2098,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11.0; PRODUCT_BUNDLE_IDENTIFIER = com.auth0.OAuth2Mac; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2132,7 +2132,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11.0; PRODUCT_BUNDLE_IDENTIFIER = com.auth0.OAuth2Mac; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2187,8 +2187,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MACOSX_DEPLOYMENT_TARGET = 10.15; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -2243,8 +2243,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MACOSX_DEPLOYMENT_TARGET = 10.15; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; @@ -2271,7 +2271,7 @@ FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Carthage/Build"; INFOPLIST_FILE = Auth0/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2302,7 +2302,7 @@ FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Carthage/Build"; INFOPLIST_FILE = Auth0/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2340,7 +2340,7 @@ "@executable_path/../Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11.0; OTHER_SWIFT_FLAGS = "-DDEBUG"; PRODUCT_BUNDLE_IDENTIFIER = com.auth0.Auth0; PRODUCT_NAME = Auth0; @@ -2376,7 +2376,7 @@ "@executable_path/../Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11.0; PRODUCT_BUNDLE_IDENTIFIER = com.auth0.Auth0; PRODUCT_NAME = Auth0; SDKROOT = macosx; @@ -2396,7 +2396,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Auth0Tests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2422,7 +2422,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Auth0Tests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2453,7 +2453,7 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11.0; OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = com.auth0.Auth0Tests; PRODUCT_NAME = Auth0Tests; @@ -2481,7 +2481,7 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11.0; OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = com.auth0.Auth0Tests; PRODUCT_NAME = Auth0Tests; @@ -2519,7 +2519,7 @@ SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 6.2; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Debug; }; @@ -2548,7 +2548,7 @@ SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 6.2; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Release; }; @@ -2578,7 +2578,7 @@ SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 12.0; + TVOS_DEPLOYMENT_TARGET = 13.0; }; name = Debug; }; @@ -2607,7 +2607,7 @@ SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 12.0; + TVOS_DEPLOYMENT_TARGET = 13.0; }; name = Release; }; @@ -2631,7 +2631,7 @@ SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/OAuth2TV.app/OAuth2TV"; - TVOS_DEPLOYMENT_TARGET = 12.0; + TVOS_DEPLOYMENT_TARGET = 13.0; }; name = Debug; }; @@ -2655,7 +2655,7 @@ SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/OAuth2TV.app/OAuth2TV"; - TVOS_DEPLOYMENT_TARGET = 12.0; + TVOS_DEPLOYMENT_TARGET = 13.0; }; name = Release; }; @@ -2670,7 +2670,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = App/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2694,7 +2694,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = App/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/Auth0/ASProvider.swift b/Auth0/ASProvider.swift index 66a4ba39..eac4c467 100644 --- a/Auth0/ASProvider.swift +++ b/Auth0/ASProvider.swift @@ -19,9 +19,7 @@ extension WebAuthentication { _ = TransactionStore.shared.resume(callbackURL) } - if #available(iOS 13.0, *) { - session.prefersEphemeralWebBrowserSession = ephemeralSession - } + session.prefersEphemeralWebBrowserSession = ephemeralSession return ASUserAgent(session: session, callback: callback) } @@ -39,9 +37,7 @@ class ASUserAgent: NSObject, WebAuthUserAgent { self.callback = callback super.init() - if #available(iOS 13.0, *) { - session.presentationContextProvider = self - } + session.presentationContextProvider = self } func start() { diff --git a/Auth0/Auth0WebAuth.swift b/Auth0/Auth0WebAuth.swift index 9986e919..bc84ea67 100644 --- a/Auth0/Auth0WebAuth.swift +++ b/Auth0/Auth0WebAuth.swift @@ -1,8 +1,6 @@ #if WEB_AUTH_PLATFORM import Foundation -#if canImport(Combine) import Combine -#endif final class Auth0WebAuth: WebAuth { @@ -279,7 +277,6 @@ final class Auth0WebAuth: WebAuth { // MARK: - Combine -@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) extension Auth0WebAuth { public func start() -> AnyPublisher { @@ -303,8 +300,6 @@ extension Auth0WebAuth { #if canImport(_Concurrency) extension Auth0WebAuth { - #if compiler(>=5.5.2) - @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) func start() async throws -> Credentials { return try await withCheckedThrowingContinuation { continuation in DispatchQueue.main.async { @@ -312,19 +307,7 @@ extension Auth0WebAuth { } } } - #else - @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) - func start() async throws -> Credentials { - return try await withCheckedThrowingContinuation { continuation in - DispatchQueue.main.async { - self.start(continuation.resume) - } - } - } - #endif - #if compiler(>=5.5.2) - @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) func clearSession(federated: Bool) async throws { return try await withCheckedThrowingContinuation { continuation in DispatchQueue.main.async { @@ -334,18 +317,6 @@ extension Auth0WebAuth { } } } - #else - @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) - func clearSession(federated: Bool) async throws { - return try await withCheckedThrowingContinuation { continuation in - DispatchQueue.main.async { - self.clearSession(federated: federated) { result in - continuation.resume(with: result) - } - } - } - } - #endif } #endif diff --git a/Auth0/BioAuthentication.swift b/Auth0/BioAuthentication.swift index 75069ff4..20d3adcb 100644 --- a/Auth0/BioAuthentication.swift +++ b/Auth0/BioAuthentication.swift @@ -33,7 +33,7 @@ struct BioAuthentication { func validateBiometric(callback: @escaping (Error?) -> Void) { self.authContext.evaluatePolicy(evaluationPolicy, localizedReason: self.title) { guard $1 == nil else { return callback($1) } - callback($0 ? nil : LAError(LAError.authenticationFailed)) + callback($0 ? nil : LAError(.authenticationFailed)) } } diff --git a/Auth0/CredentialsManager.swift b/Auth0/CredentialsManager.swift index 3db88c0d..64047e37 100644 --- a/Auth0/CredentialsManager.swift +++ b/Auth0/CredentialsManager.swift @@ -3,12 +3,10 @@ import Foundation import SimpleKeychain import JWTDecode +import Combine #if WEB_AUTH_PLATFORM import LocalAuthentication #endif -#if canImport(Combine) -import Combine -#endif /// Credentials management utility for securely storing and retrieving the user's credentials from the Keychain. /// @@ -36,7 +34,9 @@ public struct CredentialsManager { /// - authentication: Auth0 Authentication API client. /// - storeKey: Key used to store user credentials in the Keychain. Defaults to 'credentials'. /// - storage: The ``CredentialsStorage`` instance used to manage credentials storage. Defaults to a standard `SimpleKeychain` instance. - public init(authentication: Authentication, storeKey: String = "credentials", storage: CredentialsStorage = SimpleKeychain()) { + public init(authentication: Authentication, + storeKey: String = "credentials", + storage: CredentialsStorage = SimpleKeychain()) { self.storeKey = storeKey self.authentication = authentication self.storage = storage @@ -82,7 +82,10 @@ public struct CredentialsManager { /// - fallbackTitle: Fallback message to display when Face ID or Touch ID is used after a failed match. /// - evaluationPolicy: Policy to be used for authentication policy evaluation. /// - Important: Access to the ``user`` property will not be protected by biometric authentication. - public mutating func enableBiometrics(withTitle title: String, cancelTitle: String? = nil, fallbackTitle: String? = nil, evaluationPolicy: LAPolicy = LAPolicy.deviceOwnerAuthenticationWithBiometrics) { + public mutating func enableBiometrics(withTitle title: String, + cancelTitle: String? = nil, + fallbackTitle: String? = nil, + evaluationPolicy: LAPolicy = .deviceOwnerAuthenticationWithBiometrics) { self.bioAuth = BioAuthentication(authContext: LAContext(), evaluationPolicy: evaluationPolicy, title: title, cancelTitle: cancelTitle, fallbackTitle: fallbackTitle) } #endif @@ -152,7 +155,8 @@ public struct CredentialsManager { /// /// - [Refresh Tokens](https://auth0.com/docs/secure/tokens/refresh-tokens) /// - [Authentication API Endpoint](https://auth0.com/docs/api/authentication#revoke-refresh-token) - public func revoke(headers: [String: String] = [:], _ callback: @escaping (CredentialsManagerResult) -> Void) { + public func revoke(headers: [String: String] = [:], + _ callback: @escaping (CredentialsManagerResult) -> Void) { guard let data = self.storage.getEntry(forKey: self.storeKey), let credentials = try? NSKeyedUnarchiver.unarchivedObject(ofClass: Credentials.self, from: data), let refreshToken = credentials.refreshToken else { @@ -275,11 +279,15 @@ public struct CredentialsManager { /// /// - [Refresh Tokens](https://auth0.com/docs/secure/tokens/refresh-tokens) /// - [Authentication API Endpoint](https://auth0.com/docs/api/authentication#refresh-token) - public func credentials(withScope scope: String? = nil, minTTL: Int = 0, parameters: [String: Any] = [:], headers: [String: String] = [:], callback: @escaping (CredentialsManagerResult) -> Void) { + public func credentials(withScope scope: String? = nil, + minTTL: Int = 0, + parameters: [String: Any] = [:], + headers: [String: String] = [:], + callback: @escaping (CredentialsManagerResult) -> Void) { if let bioAuth = self.bioAuth { guard bioAuth.available else { let error = CredentialsManagerError(code: .biometricsFailed, - cause: LAError(LAError.biometryNotAvailable)) + cause: LAError(.biometryNotAvailable)) return callback(.failure(error)) } @@ -295,7 +303,11 @@ public struct CredentialsManager { } } #else - public func credentials(withScope scope: String? = nil, minTTL: Int = 0, parameters: [String: Any] = [:], headers: [String: String] = [:], callback: @escaping (CredentialsManagerResult) -> Void) { + public func credentials(withScope scope: String? = nil, + minTTL: Int = 0, + parameters: [String: Any] = [:], + headers: [String: String] = [:], + callback: @escaping (CredentialsManagerResult) -> Void) { self.retrieveCredentials(withScope: scope, minTTL: minTTL, parameters: parameters, headers: headers, callback: callback) } #endif @@ -338,7 +350,9 @@ public struct CredentialsManager { /// /// - [Refresh Tokens](https://auth0.com/docs/secure/tokens/refresh-tokens) /// - [Authentication API Endpoint](https://auth0.com/docs/api/authentication#refresh-token) - public func renew(parameters: [String: Any] = [:], headers: [String: String] = [:], callback: @escaping (CredentialsManagerResult) -> Void) { + public func renew(parameters: [String: Any] = [:], + headers: [String: String] = [:], + callback: @escaping (CredentialsManagerResult) -> Void) { self.retrieveCredentials(parameters: parameters, headers: headers, forceRenewal: true, callback: callback) } @@ -348,7 +362,12 @@ public struct CredentialsManager { } // swiftlint:disable:next function_body_length - private func retrieveCredentials(withScope scope: String? = nil, minTTL: Int = 0, parameters: [String: Any], headers: [String: String], forceRenewal: Bool = false, callback: @escaping (CredentialsManagerResult) -> Void) { + private func retrieveCredentials(withScope scope: String? = nil, + minTTL: Int = 0, + parameters: [String: Any], + headers: [String: String], + forceRenewal: Bool = false, + callback: @escaping (CredentialsManagerResult) -> Void) { self.dispatchQueue.async { self.dispatchGroup.enter() @@ -428,7 +447,6 @@ public struct CredentialsManager { // MARK: - Combine -@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) public extension CredentialsManager { /// Calls the `/oauth/revoke` endpoint to revoke the refresh token and then clears the credentials if the request @@ -549,7 +567,10 @@ public extension CredentialsManager { /// /// - [Refresh Tokens](https://auth0.com/docs/secure/tokens/refresh-tokens) /// - [Authentication API Endpoint](https://auth0.com/docs/api/authentication#refresh-token) - func credentials(withScope scope: String? = nil, minTTL: Int = 0, parameters: [String: Any] = [:], headers: [String: String] = [:]) -> AnyPublisher { + func credentials(withScope scope: String? = nil, + minTTL: Int = 0, + parameters: [String: Any] = [:], + headers: [String: String] = [:]) -> AnyPublisher { return Deferred { Future { callback in return self.credentials(withScope: scope, @@ -605,7 +626,8 @@ public extension CredentialsManager { /// /// - [Refresh Tokens](https://auth0.com/docs/secure/tokens/refresh-tokens) /// - [Authentication API Endpoint](https://auth0.com/docs/api/authentication#refresh-token) - func renew(parameters: [String: Any] = [:], headers: [String: String] = [:]) -> AnyPublisher { + func renew(parameters: [String: Any] = [:], + headers: [String: String] = [:]) -> AnyPublisher { return Deferred { Future { callback in return self.renew(parameters: parameters, headers: headers, callback: callback) @@ -620,7 +642,6 @@ public extension CredentialsManager { #if canImport(_Concurrency) public extension CredentialsManager { - #if compiler(>=5.5.2) /// Calls the `/oauth/revoke` endpoint to revoke the refresh token and then clears the credentials if the request /// was successful. Otherwise, the credentials are not cleared and an error is thrown. /// @@ -650,22 +671,12 @@ public extension CredentialsManager { /// /// - [Refresh Tokens](https://auth0.com/docs/secure/tokens/refresh-tokens) /// - [Authentication API Endpoint](https://auth0.com/docs/api/authentication#revoke-refresh-token) - @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) - func revoke(headers: [String: String] = [:]) async throws { - return try await withCheckedThrowingContinuation { continuation in - self.revoke(headers: headers, continuation.resume) - } - } - #else - @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) func revoke(headers: [String: String] = [:]) async throws { return try await withCheckedThrowingContinuation { continuation in self.revoke(headers: headers, continuation.resume) } } - #endif - #if compiler(>=5.5.2) /// Retrieves credentials from the Keychain and yields new credentials using the refresh token if the access token /// is expired. Otherwise, return the retrieved credentials as they are not expired. Renewed credentials will be /// stored in the Keychain. **This method is thread-safe**. @@ -722,8 +733,10 @@ public extension CredentialsManager { /// /// - [Refresh Tokens](https://auth0.com/docs/secure/tokens/refresh-tokens) /// - [Authentication API Endpoint](https://auth0.com/docs/api/authentication#refresh-token) - @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) - func credentials(withScope scope: String? = nil, minTTL: Int = 0, parameters: [String: Any] = [:], headers: [String: String] = [:]) async throws -> Credentials { + func credentials(withScope scope: String? = nil, + minTTL: Int = 0, + parameters: [String: Any] = [:], + headers: [String: String] = [:]) async throws -> Credentials { return try await withCheckedThrowingContinuation { continuation in self.credentials(withScope: scope, minTTL: minTTL, @@ -732,20 +745,7 @@ public extension CredentialsManager { callback: continuation.resume) } } - #else - @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) - func credentials(withScope scope: String? = nil, minTTL: Int = 0, parameters: [String: Any] = [:], headers: [String: String] = [:]) async throws -> Credentials { - return try await withCheckedThrowingContinuation { continuation in - self.credentials(withScope: scope, - minTTL: minTTL, - parameters: parameters, - headers: headers, - callback: continuation.resume) - } - } - #endif - #if compiler(>=5.5.2) /// Renews credentials using the refresh token and stores them in the Keychain. **This method is thread-safe**. /// /// ## Usage @@ -782,20 +782,11 @@ public extension CredentialsManager { /// /// - [Refresh Tokens](https://auth0.com/docs/secure/tokens/refresh-tokens) /// - [Authentication API Endpoint](https://auth0.com/docs/api/authentication#refresh-token) - @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) func renew(parameters: [String: Any] = [:], headers: [String: String] = [:]) async throws -> Credentials { return try await withCheckedThrowingContinuation { continuation in self.renew(parameters: parameters, headers: headers, callback: continuation.resume) } } - #else - @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) - func renew(parameters: [String: Any] = [:], headers: [String: String] = [:]) async throws -> Credentials { - return try await withCheckedThrowingContinuation { continuation in - self.renew(parameters: parameters, headers: headers, callback: continuation.resume) - } - } - #endif } #endif diff --git a/Auth0/DesktopWebAuth.swift b/Auth0/DesktopWebAuth.swift index d2f3d86b..5270d2ed 100644 --- a/Auth0/DesktopWebAuth.swift +++ b/Auth0/DesktopWebAuth.swift @@ -13,7 +13,7 @@ extension NSApplication { extension ASUserAgent: ASWebAuthenticationPresentationContextProviding { func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { - return NSApplication.shared()?.windows.filter({ $0.isKeyWindow }).last ?? ASPresentationAnchor() + return NSApplication.shared()?.windows.last(where: \.isKeyWindow) ?? ASPresentationAnchor() } } diff --git a/Auth0/MobileWebAuth.swift b/Auth0/MobileWebAuth.swift index 82384020..8e0f5367 100644 --- a/Auth0/MobileWebAuth.swift +++ b/Auth0/MobileWebAuth.swift @@ -10,11 +10,10 @@ extension UIApplication { } -@available(iOS 13.0, *) extension ASUserAgent: ASWebAuthenticationPresentationContextProviding { func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { - return UIApplication.shared()?.windows.filter({ $0.isKeyWindow }).last ?? ASPresentationAnchor() + return UIApplication.shared()?.windows.last(where: \.isKeyWindow) ?? ASPresentationAnchor() } } diff --git a/Auth0/Request.swift b/Auth0/Request.swift index 2cf5fff0..9996eaaf 100644 --- a/Auth0/Request.swift +++ b/Auth0/Request.swift @@ -1,7 +1,5 @@ import Foundation -#if canImport(Combine) import Combine -#endif #if DEBUG let parameterPropertyKey = "com.auth0.parameter" @@ -117,7 +115,6 @@ public struct Request: Requestable { // MARK: - Combine -@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) public extension Request { /** @@ -136,27 +133,16 @@ public extension Request { #if canImport(_Concurrency) public extension Request { - #if compiler(>=5.5.2) /** Performs the request. - Throws: An error that conforms to ``Auth0APIError``; either an ``AuthenticationError`` or a ``ManagementError``. */ - - @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) - func start() async throws -> T { - return try await withCheckedThrowingContinuation { continuation in - self.start(continuation.resume) - } - } - #else - @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) func start() async throws -> T { return try await withCheckedThrowingContinuation { continuation in self.start(continuation.resume) } } - #endif } #endif diff --git a/Auth0/SafariProvider.swift b/Auth0/SafariProvider.swift index 56ed5b1f..d06e519c 100644 --- a/Auth0/SafariProvider.swift +++ b/Auth0/SafariProvider.swift @@ -44,7 +44,9 @@ public extension WebAuthentication { extension SFSafariViewController { var topViewController: UIViewController? { - guard let root = UIApplication.shared()?.keyWindow?.rootViewController else { return nil } + guard let root = UIApplication.shared()?.windows.last(where: \.isKeyWindow)?.rootViewController else { + return nil + } return self.findTopViewController(from: root) } diff --git a/Auth0/WebAuth.swift b/Auth0/WebAuth.swift index cfd6da40..daf9cb8b 100644 --- a/Auth0/WebAuth.swift +++ b/Auth0/WebAuth.swift @@ -2,9 +2,7 @@ #if WEB_AUTH_PLATFORM import Foundation -#if canImport(Combine) import Combine -#endif /// Thunk that returns a function that creates and returns a ``WebAuthUserAgent`` to perform a web-based operation. /// The ``WebAuthUserAgent`` opens the URL in an external user agent and then invokes the callback when done. @@ -207,7 +205,6 @@ public protocol WebAuth: Trackable, Loggable { func start(_ callback: @escaping (WebAuthResult) -> Void) #if canImport(_Concurrency) - #if compiler(>=5.5.2) /** Starts the Web Auth flow. @@ -230,13 +227,8 @@ public protocol WebAuth: Trackable, Loggable { - Requires: The **Callback URL** to have been added to the **Allowed Callback URLs** field of your Auth0 application settings in the [Dashboard](https://manage.auth0.com/#/applications/). */ - @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) - func start() async throws -> Credentials - #else - @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) func start() async throws -> Credentials #endif - #endif /** Starts the Web Auth flow. @@ -264,7 +256,6 @@ public protocol WebAuth: Trackable, Loggable { - Requires: The **Callback URL** to have been added to the **Allowed Callback URLs** field of your Auth0 application settings in the [Dashboard](https://manage.auth0.com/#/applications/). */ - @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) func start() -> AnyPublisher /** @@ -348,11 +339,9 @@ public protocol WebAuth: Trackable, Loggable { - [Logout](https://auth0.com/docs/authenticate/login/logout) */ - @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) func clearSession(federated: Bool) -> AnyPublisher #if canImport(_Concurrency) - #if compiler(>=5.5.2) /** Removes the Auth0 session and optionally removes the identity provider (IdP) session. @@ -383,12 +372,7 @@ public protocol WebAuth: Trackable, Loggable { - [Logout](https://auth0.com/docs/authenticate/login/logout) */ - @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) func clearSession(federated: Bool) async throws - #else - @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) - func clearSession(federated: Bool) async throws - #endif #endif } @@ -399,23 +383,14 @@ public extension WebAuth { self.clearSession(federated: federated, callback: callback) } - @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) func clearSession(federated: Bool = false) -> AnyPublisher { return self.clearSession(federated: federated) } #if canImport(_Concurrency) - #if compiler(>=5.5.2) - @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) func clearSession(federated: Bool = false) async throws { return try await self.clearSession(federated: federated) } - #else - @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) - func clearSession(federated: Bool = false) async throws { - return try await self.clearSession(federated: federated) - } - #endif #endif } diff --git a/Auth0Tests/ASProviderSpec.swift b/Auth0Tests/ASProviderSpec.swift index a0b6c493..19d34270 100644 --- a/Auth0Tests/ASProviderSpec.swift +++ b/Auth0Tests/ASProviderSpec.swift @@ -31,17 +31,15 @@ class ASProviderSpec: QuickSpec { expect(provider(Url, {_ in })).to(beAKindOf(ASUserAgent.self)) } - if #available(iOS 13.0, *) { - it("should not use an ephemeral session by default") { - userAgent = WebAuthentication.asProvider(urlScheme: Url.scheme!)(Url, { _ in }) as? ASUserAgent - expect(userAgent.session.prefersEphemeralWebBrowserSession) == false - } + it("should not use an ephemeral session by default") { + userAgent = WebAuthentication.asProvider(urlScheme: Url.scheme!)(Url, { _ in }) as? ASUserAgent + expect(userAgent.session.prefersEphemeralWebBrowserSession) == false + } - it("should use an ephemeral session") { - userAgent = WebAuthentication.asProvider(urlScheme: Url.scheme!, - ephemeralSession: true)(Url, { _ in }) as? ASUserAgent - expect(userAgent.session.prefersEphemeralWebBrowserSession) == true - } + it("should use an ephemeral session") { + userAgent = WebAuthentication.asProvider(urlScheme: Url.scheme!, + ephemeralSession: true)(Url, { _ in }) as? ASUserAgent + expect(userAgent.session.prefersEphemeralWebBrowserSession) == true } } @@ -51,10 +49,8 @@ class ASProviderSpec: QuickSpec { expect(userAgent.description) == "ASWebAuthenticationSession" } - if #available(iOS 13.0, *) { - it("should be the web authentication session's presentation context provider") { - expect(session.presentationContextProvider).to(be(userAgent)) - } + it("should be the web authentication session's presentation context provider") { + expect(session.presentationContextProvider).to(be(userAgent)) } it("should call the callback with an error") { diff --git a/Auth0Tests/AuthenticationErrorSpec.swift b/Auth0Tests/AuthenticationErrorSpec.swift index e0a8d55c..7313dd36 100644 --- a/Auth0Tests/AuthenticationErrorSpec.swift +++ b/Auth0Tests/AuthenticationErrorSpec.swift @@ -169,7 +169,7 @@ class AuthenticationErrorSpec: QuickSpec { describe("unknown error structure") { itBehavesLike(UnknownErrorExample) { return [ExampleValuesKey: ["key": "value"]] } - itBehavesLike(UnknownErrorExample) { return [ExampleValuesKey: [:]] } + itBehavesLike(UnknownErrorExample) { return [ExampleValuesKey: [String: String]()] } } diff --git a/Auth0Tests/CredentialsManagerSpec.swift b/Auth0Tests/CredentialsManagerSpec.swift index 40d756d2..65d312e3 100644 --- a/Auth0Tests/CredentialsManagerSpec.swift +++ b/Auth0Tests/CredentialsManagerSpec.swift @@ -453,7 +453,7 @@ class CredentialsManagerSpec: QuickSpec { context("require biometrics") { it("should error when biometrics are unavailable") { - let expectedError = CredentialsManagerError(code: .biometricsFailed, cause: LAError(LAError.biometryNotAvailable)) + let expectedError = CredentialsManagerError(code: .biometricsFailed, cause: LAError(.biometryNotAvailable)) credentialsManager.enableBiometrics(withTitle: "Auth Title", cancelTitle: "Cancel Title", fallbackTitle: "Fallback Title") credentials = Credentials(accessToken: AccessToken, tokenType: TokenType, idToken: IdToken, refreshToken: RefreshToken, expiresIn: Date(timeIntervalSinceNow: -ExpiresIn)) _ = credentialsManager.store(credentials: credentials) @@ -992,229 +992,227 @@ class CredentialsManagerSpec: QuickSpec { } - if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) { - describe("combine") { - var cancellables: Set = [] - - afterEach { - _ = credentialsManager.clear() - cancellables.removeAll() - } - - context("credentials") { - - it("should emit only one value") { - _ = credentialsManager.store(credentials: credentials) - await waitUntil(timeout: Timeout) { done in - credentialsManager - .credentials() - .assertNoFailure() - .count() - .sink(receiveValue: { count in - expect(count) == 1 - done() - }) - .store(in: &cancellables) - } - } + describe("combine") { + var cancellables: Set = [] - it("should complete using the default parameter values") { - _ = credentialsManager.store(credentials: credentials) - await waitUntil(timeout: Timeout) { done in - credentialsManager - .credentials() - .sink(receiveCompletion: { completion in - guard case .finished = completion else { return } - done() - }, receiveValue: { _ in }) - .store(in: &cancellables) - } + afterEach { + _ = credentialsManager.clear() + cancellables.removeAll() + } + + context("credentials") { + + it("should emit only one value") { + _ = credentialsManager.store(credentials: credentials) + await waitUntil(timeout: Timeout) { done in + credentialsManager + .credentials() + .assertNoFailure() + .count() + .sink(receiveValue: { count in + expect(count) == 1 + done() + }) + .store(in: &cancellables) } + } - it("should complete using custom parameter values") { - let key = "foo" - let value = "bar" - stub(condition: isToken(Domain) && hasAtLeast(["refresh_token": RefreshToken, key: value]) && hasHeader(key, value: value)) { _ in - return authResponse(accessToken: NewAccessToken, idToken: NewIdToken, refreshToken: NewRefreshToken, expiresIn: ExpiresIn) - } - credentials = Credentials(accessToken: AccessToken, tokenType: TokenType, idToken: IdToken, refreshToken: RefreshToken, expiresIn: Date(timeIntervalSinceNow: -ExpiresIn)) - _ = credentialsManager.store(credentials: credentials) - await waitUntil(timeout: Timeout) { done in - credentialsManager - .credentials(withScope: "openid profile offline_access", - minTTL: ValidTTL, - parameters: [key: value], - headers: [key: value]) - .sink(receiveCompletion: { completion in - guard case .finished = completion else { return } - done() - }, receiveValue: { _ in }) - .store(in: &cancellables) - } + it("should complete using the default parameter values") { + _ = credentialsManager.store(credentials: credentials) + await waitUntil(timeout: Timeout) { done in + credentialsManager + .credentials() + .sink(receiveCompletion: { completion in + guard case .finished = completion else { return } + done() + }, receiveValue: { _ in }) + .store(in: &cancellables) } + } - it("should complete with an error") { - await waitUntil(timeout: Timeout) { done in - credentialsManager - .credentials() - .ignoreOutput() - .sink(receiveCompletion: { completion in - guard case .failure = completion else { return } - done() - }, receiveValue: { _ in }) - .store(in: &cancellables) - } + it("should complete using custom parameter values") { + let key = "foo" + let value = "bar" + stub(condition: isToken(Domain) && hasAtLeast(["refresh_token": RefreshToken, key: value]) && hasHeader(key, value: value)) { _ in + return authResponse(accessToken: NewAccessToken, idToken: NewIdToken, refreshToken: NewRefreshToken, expiresIn: ExpiresIn) + } + credentials = Credentials(accessToken: AccessToken, tokenType: TokenType, idToken: IdToken, refreshToken: RefreshToken, expiresIn: Date(timeIntervalSinceNow: -ExpiresIn)) + _ = credentialsManager.store(credentials: credentials) + await waitUntil(timeout: Timeout) { done in + credentialsManager + .credentials(withScope: "openid profile offline_access", + minTTL: ValidTTL, + parameters: [key: value], + headers: [key: value]) + .sink(receiveCompletion: { completion in + guard case .finished = completion else { return } + done() + }, receiveValue: { _ in }) + .store(in: &cancellables) } + } + it("should complete with an error") { + await waitUntil(timeout: Timeout) { done in + credentialsManager + .credentials() + .ignoreOutput() + .sink(receiveCompletion: { completion in + guard case .failure = completion else { return } + done() + }, receiveValue: { _ in }) + .store(in: &cancellables) + } } - context("renew") { + } - beforeEach { - _ = credentialsManager.store(credentials: credentials) - } + context("renew") { - it("should emit only one value") { - stub(condition: isToken(Domain) && hasAtLeast(["refresh_token": RefreshToken])) { _ in - return authResponse(accessToken: NewAccessToken, idToken: NewIdToken, refreshToken: NewRefreshToken, expiresIn: ExpiresIn * 2) - }.name = "renewal succeeded" - await waitUntil(timeout: Timeout) { done in - credentialsManager - .renew() - .assertNoFailure() - .count() - .sink(receiveValue: { count in - expect(count) == 1 - done() - }) - .store(in: &cancellables) - } - } + beforeEach { + _ = credentialsManager.store(credentials: credentials) + } - it("should complete using the default parameter values") { - stub(condition: isToken(Domain) && hasAtLeast(["refresh_token": RefreshToken])) { _ in - return authResponse(accessToken: NewAccessToken, idToken: NewIdToken, refreshToken: NewRefreshToken, expiresIn: ExpiresIn * 2) - }.name = "renewal succeeded" - await waitUntil(timeout: Timeout) { done in - credentialsManager - .renew() - .sink(receiveCompletion: { completion in - guard case .finished = completion else { return } - done() - }, receiveValue: { _ in }) - .store(in: &cancellables) - } + it("should emit only one value") { + stub(condition: isToken(Domain) && hasAtLeast(["refresh_token": RefreshToken])) { _ in + return authResponse(accessToken: NewAccessToken, idToken: NewIdToken, refreshToken: NewRefreshToken, expiresIn: ExpiresIn * 2) + }.name = "renewal succeeded" + await waitUntil(timeout: Timeout) { done in + credentialsManager + .renew() + .assertNoFailure() + .count() + .sink(receiveValue: { count in + expect(count) == 1 + done() + }) + .store(in: &cancellables) } + } - it("should complete using custom parameter values") { - let key = "foo" - let value = "bar" - stub(condition: isToken(Domain) && hasAtLeast(["refresh_token": RefreshToken, key: value]) && hasHeader(key, value: value)) { _ in - return authResponse(accessToken: NewAccessToken, idToken: NewIdToken, refreshToken: NewRefreshToken, expiresIn: ExpiresIn) - } - await waitUntil(timeout: Timeout) { done in - credentialsManager - .renew(parameters: [key: value], headers: [key: value]) - .sink(receiveCompletion: { completion in - guard case .finished = completion else { return } - done() - }, receiveValue: { _ in }) - .store(in: &cancellables) - } + it("should complete using the default parameter values") { + stub(condition: isToken(Domain) && hasAtLeast(["refresh_token": RefreshToken])) { _ in + return authResponse(accessToken: NewAccessToken, idToken: NewIdToken, refreshToken: NewRefreshToken, expiresIn: ExpiresIn * 2) + }.name = "renewal succeeded" + await waitUntil(timeout: Timeout) { done in + credentialsManager + .renew() + .sink(receiveCompletion: { completion in + guard case .finished = completion else { return } + done() + }, receiveValue: { _ in }) + .store(in: &cancellables) } + } - it("should complete with an error") { - stub(condition: isToken(Domain) && hasAtLeast(["refresh_token": RefreshToken])) { _ in - return authFailure(code: "invalid_request", description: "missing_params") - }.name = "renewal failed" - await waitUntil(timeout: Timeout) { done in - credentialsManager - .renew() - .ignoreOutput() - .sink(receiveCompletion: { completion in - guard case .failure = completion else { return } - done() - }, receiveValue: { _ in }) - .store(in: &cancellables) - } + it("should complete using custom parameter values") { + let key = "foo" + let value = "bar" + stub(condition: isToken(Domain) && hasAtLeast(["refresh_token": RefreshToken, key: value]) && hasHeader(key, value: value)) { _ in + return authResponse(accessToken: NewAccessToken, idToken: NewIdToken, refreshToken: NewRefreshToken, expiresIn: ExpiresIn) } + await waitUntil(timeout: Timeout) { done in + credentialsManager + .renew(parameters: [key: value], headers: [key: value]) + .sink(receiveCompletion: { completion in + guard case .finished = completion else { return } + done() + }, receiveValue: { _ in }) + .store(in: &cancellables) + } + } + it("should complete with an error") { + stub(condition: isToken(Domain) && hasAtLeast(["refresh_token": RefreshToken])) { _ in + return authFailure(code: "invalid_request", description: "missing_params") + }.name = "renewal failed" + await waitUntil(timeout: Timeout) { done in + credentialsManager + .renew() + .ignoreOutput() + .sink(receiveCompletion: { completion in + guard case .failure = completion else { return } + done() + }, receiveValue: { _ in }) + .store(in: &cancellables) + } } - context("revoke") { + } - it("should emit only one value") { - stub(condition: isRevokeToken(Domain) && hasAtLeast(["token": RefreshToken])) { _ in - return revokeTokenResponse() - } - _ = credentialsManager.store(credentials: credentials) - await waitUntil(timeout: Timeout) { done in - credentialsManager - .revoke() - .assertNoFailure() - .count() - .sink(receiveValue: { count in - expect(count) == 1 - done() - }) - .store(in: &cancellables) - } - } + context("revoke") { - it("should complete using the default parameter values") { - stub(condition: isRevokeToken(Domain) && hasAtLeast(["token": RefreshToken])) { _ in - return revokeTokenResponse() - } - _ = credentialsManager.store(credentials: credentials) - await waitUntil(timeout: Timeout) { done in - credentialsManager - .revoke() - .sink(receiveCompletion: { completion in - guard case .finished = completion else { return } - done() - }, receiveValue: { _ in }) - .store(in: &cancellables) - } + it("should emit only one value") { + stub(condition: isRevokeToken(Domain) && hasAtLeast(["token": RefreshToken])) { _ in + return revokeTokenResponse() + } + _ = credentialsManager.store(credentials: credentials) + await waitUntil(timeout: Timeout) { done in + credentialsManager + .revoke() + .assertNoFailure() + .count() + .sink(receiveValue: { count in + expect(count) == 1 + done() + }) + .store(in: &cancellables) } + } - it("should complete using custom parameter values") { - let key = "foo" - let value = "bar" - stub(condition: isRevokeToken(Domain) && hasAtLeast(["token": RefreshToken]) && hasHeader(key, value: value)) { _ in - return revokeTokenResponse() - } - _ = credentialsManager.store(credentials: credentials) - await waitUntil(timeout: Timeout) { done in - credentialsManager - .revoke(headers: [key: value]) - .sink(receiveCompletion: { completion in - guard case .finished = completion else { return } - done() - }, receiveValue: { _ in }) - .store(in: &cancellables) - } + it("should complete using the default parameter values") { + stub(condition: isRevokeToken(Domain) && hasAtLeast(["token": RefreshToken])) { _ in + return revokeTokenResponse() + } + _ = credentialsManager.store(credentials: credentials) + await waitUntil(timeout: Timeout) { done in + credentialsManager + .revoke() + .sink(receiveCompletion: { completion in + guard case .finished = completion else { return } + done() + }, receiveValue: { _ in }) + .store(in: &cancellables) } + } - it("should complete with an error") { - stub(condition: isRevokeToken(Domain) && hasAtLeast(["token": RefreshToken])) { _ in - return apiFailureResponse() - } - _ = credentialsManager.store(credentials: credentials) - await waitUntil(timeout: Timeout) { done in - credentialsManager - .revoke() - .ignoreOutput() - .sink(receiveCompletion: { completion in - guard case .failure = completion else { return } - done() - }, receiveValue: { _ in }) - .store(in: &cancellables) - } + it("should complete using custom parameter values") { + let key = "foo" + let value = "bar" + stub(condition: isRevokeToken(Domain) && hasAtLeast(["token": RefreshToken]) && hasHeader(key, value: value)) { _ in + return revokeTokenResponse() + } + _ = credentialsManager.store(credentials: credentials) + await waitUntil(timeout: Timeout) { done in + credentialsManager + .revoke(headers: [key: value]) + .sink(receiveCompletion: { completion in + guard case .finished = completion else { return } + done() + }, receiveValue: { _ in }) + .store(in: &cancellables) } + } + it("should complete with an error") { + stub(condition: isRevokeToken(Domain) && hasAtLeast(["token": RefreshToken])) { _ in + return apiFailureResponse() + } + _ = credentialsManager.store(credentials: credentials) + await waitUntil(timeout: Timeout) { done in + credentialsManager + .revoke() + .ignoreOutput() + .sink(receiveCompletion: { completion in + guard case .failure = completion else { return } + done() + }, receiveValue: { _ in }) + .store(in: &cancellables) + } } } + } #if canImport(_Concurrency) @@ -1230,23 +1228,10 @@ class CredentialsManagerSpec: QuickSpec { let credentialsManager = credentialsManager! _ = credentialsManager.store(credentials: credentials) await waitUntil(timeout: Timeout) { done in - #if compiler(>=5.5.2) - if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) { - Task.init { - _ = try await credentialsManager.credentials() - done() - } - } - #else - if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { - Task.init { - _ = try await credentialsManager.credentials() - done() - } - } else { + Task.init { + _ = try await credentialsManager.credentials() done() } - #endif } } @@ -1260,58 +1245,26 @@ class CredentialsManagerSpec: QuickSpec { credentials = Credentials(accessToken: AccessToken, tokenType: TokenType, idToken: IdToken, refreshToken: RefreshToken, expiresIn: Date(timeIntervalSinceNow: -ExpiresIn)) _ = credentialsManager.store(credentials: credentials) await waitUntil(timeout: Timeout) { done in - #if compiler(>=5.5.2) - if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) { - Task.init { - _ = try await credentialsManager.credentials(withScope: "openid profile offline_access", - minTTL: ValidTTL, - parameters: [key: value], - headers: [key: value]) - done() - } - } - #else - if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { - Task.init { - _ = try await credentialsManager.credentials(withScope: "openid profile offline_access", - minTTL: ValidTTL, - parameters: [key: value], - headers: [key: value]) - done() - } - } else { + Task.init { + _ = try await credentialsManager.credentials(withScope: "openid profile offline_access", + minTTL: ValidTTL, + parameters: [key: value], + headers: [key: value]) done() } - #endif } } it("should throw an error") { let credentialsManager = credentialsManager! await waitUntil(timeout: Timeout) { done in - #if compiler(>=5.5.2) - if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) { - Task.init { - do { - _ = try await credentialsManager.credentials() - } catch { - done() - } - } - } - #else - if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { - Task.init { - do { - _ = try await credentialsManager.credentials() - } catch { - done() - } + Task.init { + do { + _ = try await credentialsManager.credentials() + } catch { + done() } - } else { - done() } - #endif } } @@ -1329,29 +1282,13 @@ class CredentialsManagerSpec: QuickSpec { return authResponse(accessToken: NewAccessToken, idToken: NewIdToken, refreshToken: NewRefreshToken, expiresIn: ExpiresIn * 2) }.name = "renewal succeeded" await waitUntil(timeout: Timeout) { done in - #if compiler(>=5.5.2) - if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) { - Task.init { - let newCredentials = try await credentialsManager.renew() - expect(newCredentials.accessToken) == NewAccessToken - expect(newCredentials.idToken) == NewIdToken - expect(newCredentials.refreshToken) == NewRefreshToken - done() - } - } - #else - if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { - Task.init { - let newCredentials = try await credentialsManager.renew() - expect(newCredentials.accessToken) == NewAccessToken - expect(newCredentials.idToken) == NewIdToken - expect(newCredentials.refreshToken) == NewRefreshToken - done() - } - } else { + Task.init { + let newCredentials = try await credentialsManager.renew() + expect(newCredentials.accessToken) == NewAccessToken + expect(newCredentials.idToken) == NewIdToken + expect(newCredentials.refreshToken) == NewRefreshToken done() } - #endif } } @@ -1363,29 +1300,13 @@ class CredentialsManagerSpec: QuickSpec { return authResponse(accessToken: NewAccessToken, idToken: NewIdToken, refreshToken: NewRefreshToken, expiresIn: ExpiresIn) } await waitUntil(timeout: Timeout) { done in - #if compiler(>=5.5.2) - if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) { - Task.init { - let newCredentials = try await credentialsManager.renew(parameters: [key: value], headers: [key: value]) - expect(newCredentials.accessToken) == NewAccessToken - expect(newCredentials.idToken) == NewIdToken - expect(newCredentials.refreshToken) == NewRefreshToken - done() - } - } - #else - if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { - Task.init { - let newCredentials = try await credentialsManager.renew(parameters: [key: value], headers: [key: value]) - expect(newCredentials.accessToken) == NewAccessToken - expect(newCredentials.idToken) == NewIdToken - expect(newCredentials.refreshToken) == NewRefreshToken - done() - } - } else { + Task.init { + let newCredentials = try await credentialsManager.renew(parameters: [key: value], headers: [key: value]) + expect(newCredentials.accessToken) == NewAccessToken + expect(newCredentials.idToken) == NewIdToken + expect(newCredentials.refreshToken) == NewRefreshToken done() } - #endif } } @@ -1395,29 +1316,13 @@ class CredentialsManagerSpec: QuickSpec { return authFailure(code: "invalid_request", description: "missing_params") }.name = "renewal failed" await waitUntil(timeout: Timeout) { done in - #if compiler(>=5.5.2) - if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) { - Task.init { - do { - _ = try await credentialsManager.renew() - } catch { - done() - } - } - } - #else - if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { - Task.init { - do { - _ = try await credentialsManager.renew() - } catch { - done() - } + Task.init { + do { + _ = try await credentialsManager.renew() + } catch { + done() } - } else { - done() } - #endif } } @@ -1432,23 +1337,10 @@ class CredentialsManagerSpec: QuickSpec { } _ = credentialsManager.store(credentials: credentials) await waitUntil(timeout: Timeout) { done in - #if compiler(>=5.5.2) - if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) { - Task.init { - _ = try await credentialsManager.revoke() - done() - } - } - #else - if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { - Task.init { - _ = try await credentialsManager.revoke() - done() - } - } else { + Task.init { + _ = try await credentialsManager.revoke() done() } - #endif } } @@ -1461,23 +1353,10 @@ class CredentialsManagerSpec: QuickSpec { } _ = credentialsManager.store(credentials: credentials) await waitUntil(timeout: Timeout) { done in - #if compiler(>=5.5.2) - if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) { - Task.init { - _ = try await credentialsManager.revoke(headers: [key: value]) - done() - } - } - #else - if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { - Task.init { - _ = try await credentialsManager.revoke(headers: [key: value]) - done() - } - } else { + Task.init { + _ = try await credentialsManager.revoke(headers: [key: value]) done() } - #endif } } @@ -1488,29 +1367,13 @@ class CredentialsManagerSpec: QuickSpec { } _ = credentialsManager.store(credentials: credentials) await waitUntil(timeout: Timeout) { done in - #if compiler(>=5.5.2) - if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) { - Task.init { - do { - _ = try await credentialsManager.revoke() - } catch { - done() - } - } - } - #else - if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { - Task.init { - do { - _ = try await credentialsManager.revoke() - } catch { - done() - } + Task.init { + do { + _ = try await credentialsManager.revoke() + } catch { + done() } - } else { - done() } - #endif } } diff --git a/Auth0Tests/RequestSpec.swift b/Auth0Tests/RequestSpec.swift index 50a7c143..c5955be0 100644 --- a/Auth0Tests/RequestSpec.swift +++ b/Auth0Tests/RequestSpec.swift @@ -133,68 +133,66 @@ class RequestSpec: QuickSpec { } - if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) { - describe("combine") { - var cancellables: Set = [] + describe("combine") { + var cancellables: Set = [] - afterEach { - cancellables.removeAll() - } + afterEach { + cancellables.removeAll() + } - it("should emit only one value") { - stub(condition: isHost(Url.host!)) { _ in - return apiSuccessResponse() - } - let request = Request() - await waitUntil(timeout: Timeout) { done in - request - .start() - .assertNoFailure() - .count() - .sink(receiveValue: { count in - expect(count) == 1 - done() - }) - .store(in: &cancellables) - } + it("should emit only one value") { + stub(condition: isHost(Url.host!)) { _ in + return apiSuccessResponse() } - - it("should complete with the response") { - stub(condition: isHost(Url.host!)) { _ in - return apiSuccessResponse(json: ["foo": "bar"]) - } - let request = Request() - await waitUntil(timeout: Timeout) { done in - request - .start() - .sink(receiveCompletion: { completion in - guard case .finished = completion else { return } - done() - }, receiveValue: { response in - expect(response).toNot(beEmpty()) - }) - .store(in: &cancellables) - } + let request = Request() + await waitUntil(timeout: Timeout) { done in + request + .start() + .assertNoFailure() + .count() + .sink(receiveValue: { count in + expect(count) == 1 + done() + }) + .store(in: &cancellables) } + } - it("should complete with an error") { - stub(condition: isHost(Url.host!)) { _ in - return apiFailureResponse() - } - let request = Request() - await waitUntil(timeout: Timeout) { done in - request - .start() - .ignoreOutput() - .sink(receiveCompletion: { completion in - guard case .failure = completion else { return } - done() - }, receiveValue: { _ in }) - .store(in: &cancellables) - } + it("should complete with the response") { + stub(condition: isHost(Url.host!)) { _ in + return apiSuccessResponse(json: ["foo": "bar"]) + } + let request = Request() + await waitUntil(timeout: Timeout) { done in + request + .start() + .sink(receiveCompletion: { completion in + guard case .finished = completion else { return } + done() + }, receiveValue: { response in + expect(response).toNot(beEmpty()) + }) + .store(in: &cancellables) } + } + it("should complete with an error") { + stub(condition: isHost(Url.host!)) { _ in + return apiFailureResponse() + } + let request = Request() + await waitUntil(timeout: Timeout) { done in + request + .start() + .ignoreOutput() + .sink(receiveCompletion: { completion in + guard case .failure = completion else { return } + done() + }, receiveValue: { _ in }) + .store(in: &cancellables) + } } + } #if canImport(_Concurrency) @@ -206,25 +204,11 @@ class RequestSpec: QuickSpec { } let request = Request() await waitUntil(timeout: Timeout) { done in - #if compiler(>=5.5.2) - if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) { - Task.init { - let response = try await request.start() - expect(response).toNot(beEmpty()) - done() - } - } - #else - if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { - Task.init { - let response = try await request.start() - expect(response).toNot(beEmpty()) - done() - } - } else { + Task.init { + let response = try await request.start() + expect(response).toNot(beEmpty()) done() } - #endif } } @@ -234,29 +218,13 @@ class RequestSpec: QuickSpec { } let request = Request() await waitUntil(timeout: Timeout) { done in - #if compiler(>=5.5.2) - if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *) { - Task.init { - do { - _ = try await request.start() - } catch { - done() - } - } - } - #else - if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { - Task.init { - do { - _ = try await request.start() - } catch { - done() - } + Task.init { + do { + _ = try await request.start() + } catch { + done() } - } else { - done() } - #endif } } diff --git a/Auth0Tests/SafariProviderSpec.swift b/Auth0Tests/SafariProviderSpec.swift index 97b162d6..e8377bc3 100644 --- a/Auth0Tests/SafariProviderSpec.swift +++ b/Auth0Tests/SafariProviderSpec.swift @@ -54,11 +54,11 @@ class SafariProviderSpec: QuickSpec { beforeEach { root = SpyViewController() - UIApplication.shared.keyWindow?.rootViewController = root + UIApplication.shared.windows.last(where: \.isKeyWindow)?.rootViewController = root } it("should return nil when root is nil") { - UIApplication.shared.keyWindow?.rootViewController = nil + UIApplication.shared.windows.last(where: \.isKeyWindow)?.rootViewController = nil expect(safari.topViewController).to(beNil()) } @@ -131,7 +131,7 @@ class SafariProviderSpec: QuickSpec { it("should present the safari view controller") { let root = SpyViewController() - UIApplication.shared.keyWindow?.rootViewController = root + UIApplication.shared.windows.last(where: \.isKeyWindow)?.rootViewController = root let safari = SpySafariViewController(url: Url) userAgent = SafariUserAgent(controller: safari, callback: { _ in }) root.presented = safari diff --git a/Cartfile.private b/Cartfile.private index e7b07396..26cccefe 100644 --- a/Cartfile.private +++ b/Cartfile.private @@ -1,3 +1,3 @@ github "Quick/Quick" ~> 6.0 github "Quick/Nimble" ~> 12.0 -github "AliSoftware/OHHTTPStubs" ~> 9.0 +github "asana/OHHTTPStubs" "9.1.0-asana" diff --git a/Cartfile.resolved b/Cartfile.resolved index 7ca10145..9b1e2b8f 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,5 +1,5 @@ -github "AliSoftware/OHHTTPStubs" "9.1.0" -github "Quick/Nimble" "v12.0.0" +github "Quick/Nimble" "v12.0.1" github "Quick/Quick" "v6.1.0" +github "asana/OHHTTPStubs" "9.1.0-asana" github "auth0/JWTDecode.swift" "3.0.1" github "auth0/SimpleKeychain" "1.0.1" diff --git a/Package.swift b/Package.swift index e3f1fa07..734fa14d 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.5 +// swift-tools-version:5.7 import PackageDescription @@ -7,28 +7,31 @@ let swiftSettings: [SwiftSetting] = [.define("WEB_AUTH_PLATFORM", .when(platform let package = Package( name: "Auth0", - platforms: [.iOS(.v12), .macOS(.v10_15), .tvOS(.v12), .watchOS("6.2")], + platforms: [.iOS(.v13), .macOS(.v11), .tvOS(.v13), .watchOS(.v7)], products: [.library(name: "Auth0", targets: ["Auth0"])], dependencies: [ - .package(name: "SimpleKeychain", url: "https://github.com/auth0/SimpleKeychain.git", .upToNextMajor(from: "1.0.0")), - .package(name: "JWTDecode", url: "https://github.com/auth0/JWTDecode.swift.git", .upToNextMajor(from: "3.0.0")), - .package(name: "Quick", url: "https://github.com/Quick/Quick.git", .upToNextMajor(from: "6.0.0")), - .package(name: "Nimble", url: "https://github.com/Quick/Nimble.git", .upToNextMajor(from: "12.0.0")), - .package(name: "OHHTTPStubs", url: "https://github.com/AliSoftware/OHHTTPStubs.git", .upToNextMajor(from: "9.0.0")) + .package(url: "https://github.com/auth0/SimpleKeychain.git", .upToNextMajor(from: "1.0.0")), + .package(url: "https://github.com/auth0/JWTDecode.swift.git", .upToNextMajor(from: "3.0.0")), + .package(url: "https://github.com/Quick/Quick.git", .upToNextMajor(from: "6.0.0")), + .package(url: "https://github.com/Quick/Nimble.git", .upToNextMajor(from: "12.0.0")), + .package(url: "https://github.com/AliSoftware/OHHTTPStubs.git", .upToNextMajor(from: "9.0.0")) ], targets: [ .target( name: "Auth0", - dependencies: ["SimpleKeychain", "JWTDecode"], + dependencies: [ + .product(name: "SimpleKeychain", package: "SimpleKeychain"), + .product(name: "JWTDecode", package: "JWTDecode.swift") + ], path: "Auth0", exclude: ["Info.plist"], swiftSettings: swiftSettings), .testTarget( name: "Auth0Tests", dependencies: [ - "Auth0", - "Quick", - "Nimble", + "Auth0", + .product(name: "Quick", package: "Quick"), + .product(name: "Nimble", package: "Nimble"), .product(name: "OHHTTPStubsSwift", package: "OHHTTPStubs") ], path: "Auth0Tests", diff --git a/README.md b/README.md index 5bf8db55..ac75b42f 100644 --- a/README.md +++ b/README.md @@ -27,9 +27,9 @@ Migrating from v1? Check the [Migration Guide](V2_MIGRATION_GUIDE.md). ### Requirements -- iOS 12.0+ / macOS 10.15+ / tvOS 12.0+ / watchOS 6.2+ -- Xcode 13.x / 14.x -- Swift 5.5+ +- iOS 13.0+ / macOS 11.0+ / tvOS 13.0+ / watchOS 7.0+ +- Xcode 14.x +- Swift 5.7+ > **Note** > Check the [Support Policy](#support-policy) to learn when dropping Xcode, Swift, and platform versions will not be considered a **breaking change**.