From d9a0c31bf76cfc25c961567de6a2846ae4a5f058 Mon Sep 17 00:00:00 2001 From: Rushi Sangani Date: Wed, 14 Oct 2020 11:45:46 +0530 Subject: [PATCH] #38 Fixed: touchIDAuthenticationAllowableReuseDuration --- .../project.pbxproj | 16 ++- .../BiometricAuthentication.xcscheme | 6 +- .../Authentication/AuthenticationErrors.swift | 15 ++- .../BioMetricAuthenticator.swift | 121 ++++++++---------- .../project.pbxproj | 12 +- 5 files changed, 88 insertions(+), 82 deletions(-) diff --git a/BiometricAuthentication/BiometricAuthentication.xcodeproj/project.pbxproj b/BiometricAuthentication/BiometricAuthentication.xcodeproj/project.pbxproj index 73c3e7e..e362153 100644 --- a/BiometricAuthentication/BiometricAuthentication.xcodeproj/project.pbxproj +++ b/BiometricAuthentication/BiometricAuthentication.xcodeproj/project.pbxproj @@ -115,7 +115,7 @@ D8DB659D1FA46C7E00351903 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; + LastUpgradeCheck = 1200; ORGANIZATIONNAME = "Rushi Sangani"; TargetAttributes = { D8DB65A51FA46C7E00351903 = { @@ -192,6 +192,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -218,7 +219,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -254,6 +255,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -274,7 +276,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -287,7 +289,7 @@ D8DB65AF1FA46C7E00351903 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = T5CX5N9HK9; @@ -296,7 +298,8 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = BiometricAuthentication/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + "IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 13.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MARKETING_VERSION = 3.1.2; PRODUCT_BUNDLE_IDENTIFIER = com.rushi.BiometricAuthentication; @@ -320,7 +323,8 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = BiometricAuthentication/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + "IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 13.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MARKETING_VERSION = 3.1.2; PRODUCT_BUNDLE_IDENTIFIER = com.rushi.BiometricAuthentication; diff --git a/BiometricAuthentication/BiometricAuthentication.xcodeproj/xcshareddata/xcschemes/BiometricAuthentication.xcscheme b/BiometricAuthentication/BiometricAuthentication.xcodeproj/xcshareddata/xcschemes/BiometricAuthentication.xcscheme index c1c8d7d..555b6f1 100644 --- a/BiometricAuthentication/BiometricAuthentication.xcodeproj/xcshareddata/xcschemes/BiometricAuthentication.xcscheme +++ b/BiometricAuthentication/BiometricAuthentication.xcodeproj/xcshareddata/xcschemes/BiometricAuthentication.xcscheme @@ -1,6 +1,6 @@ - - - - AuthenticationError { switch Int32(error.errorCode) { @@ -62,14 +70,19 @@ public enum AuthenticationError: Error { switch self { case .canceledByUser, .fallback, .canceledBySystem: return "" + case .passcodeNotSet: return isFaceIdDevice ? kSetPasscodeToUseFaceID : kSetPasscodeToUseTouchID + case .biometryNotAvailable: return kBiometryNotAvailableReason + case .biometryNotEnrolled: return isFaceIdDevice ? kNoFaceIdentityEnrolled : kNoFingerprintEnrolled + case .biometryLockedout: return isFaceIdDevice ? kFaceIdPasscodeAuthenticationReason : kTouchIdPasscodeAuthenticationReason + default: return isFaceIdDevice ? kDefaultFaceIDAuthenticationFailedReason : kDefaultTouchIDAuthenticationFailedReason } diff --git a/BiometricAuthentication/BiometricAuthentication/Authentication/BioMetricAuthenticator.swift b/BiometricAuthentication/BiometricAuthentication/Authentication/BioMetricAuthenticator.swift index 8a5ac0b..215bce6 100644 --- a/BiometricAuthentication/BiometricAuthentication/Authentication/BioMetricAuthenticator.swift +++ b/BiometricAuthentication/BiometricAuthentication/Authentication/BioMetricAuthenticator.swift @@ -33,21 +33,9 @@ open class BioMetricAuthenticator: NSObject { // MARK: - Private private override init() {} - private lazy var context: LAContext? = { - return LAContext() - }() - + // MARK: - Public - public var allowableReuseDuration: TimeInterval? = nil { - didSet { - guard let duration = allowableReuseDuration else { - return - } - if #available(iOS 9.0, *) { - self.context?.touchIDAuthenticationAllowableReuseDuration = duration - } - } - } + public var allowableReuseDuration: TimeInterval = 0 } // MARK:- Public @@ -60,56 +48,65 @@ public extension BioMetricAuthenticator { var isBiometricAuthenticationAvailable = false var error: NSError? = nil - if LAContext().canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: &error) { + if LAContext().canEvaluatePolicy( + LAPolicy.deviceOwnerAuthenticationWithBiometrics, + error: &error + ) { isBiometricAuthenticationAvailable = (error == nil) } return isBiometricAuthenticationAvailable } /// Check for biometric authentication - class func authenticateWithBioMetrics(reason: String, fallbackTitle: String? = "", cancelTitle: String? = "", completion: @escaping (Result) -> Void) { + class func authenticateWithBioMetrics( + reason: String, + fallbackTitle: String? = "", + cancelTitle: String? = "", + completion: @escaping (Result) -> Void + ) { // reason - let reasonString = reason.isEmpty ? BioMetricAuthenticator.shared.defaultBiometricAuthenticationReason() : reason + let reasonString = reason.isEmpty + ? BioMetricAuthenticator.shared.defaultBiometricAuthenticationReason() + : reason // context - var context: LAContext! - if BioMetricAuthenticator.shared.isReuseDurationSet() { - context = BioMetricAuthenticator.shared.context - }else { - context = LAContext() - } + let context = LAContext() + context.touchIDAuthenticationAllowableReuseDuration = BioMetricAuthenticator.shared.allowableReuseDuration context.localizedFallbackTitle = fallbackTitle - - // cancel button title - if #available(iOS 10.0, *) { - context.localizedCancelTitle = cancelTitle - } + context.localizedCancelTitle = cancelTitle // authenticate - BioMetricAuthenticator.shared.evaluate(policy: .deviceOwnerAuthenticationWithBiometrics, with: context, reason: reasonString, completion: completion) + BioMetricAuthenticator.shared.evaluate( + policy: .deviceOwnerAuthenticationWithBiometrics, + with: context, + reason: reasonString, + completion: completion + ) } /// Check for device passcode authentication - class func authenticateWithPasscode(reason: String, cancelTitle: String? = "", completion: @escaping (Result) -> ()) { + class func authenticateWithPasscode( + reason: String, + cancelTitle: String? = "", + completion: @escaping (Result) -> () + ) { // reason - let reasonString = reason.isEmpty ? BioMetricAuthenticator.shared.defaultPasscodeAuthenticationReason() : reason + let reasonString = reason.isEmpty + ? BioMetricAuthenticator.shared.defaultPasscodeAuthenticationReason() + : reason let context = LAContext() - - // cancel button title - if #available(iOS 10.0, *) { - context.localizedCancelTitle = cancelTitle - } + context.localizedCancelTitle = cancelTitle // authenticate - if #available(iOS 9.0, *) { - BioMetricAuthenticator.shared.evaluate(policy: .deviceOwnerAuthentication, with: context, reason: reasonString, completion: completion) - } else { - // Fallback on earlier versions - BioMetricAuthenticator.shared.evaluate(policy: .deviceOwnerAuthenticationWithBiometrics, with: context, reason: reasonString, completion: completion) - } + BioMetricAuthenticator.shared.evaluate( + policy: .deviceOwnerAuthentication, + with: context, + reason: reasonString, + completion: completion + ) } /// checks if device supports face id and authentication can be done @@ -117,11 +114,11 @@ public extension BioMetricAuthenticator { let context = LAContext() var error: NSError? - let canEvaluate = context.canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: &error) - if #available(iOS 11.0, *) { - return canEvaluate && context.biometryType == .faceID - } - return canEvaluate + let canEvaluate = context.canEvaluatePolicy( + LAPolicy.deviceOwnerAuthenticationWithBiometrics, + error: &error + ) + return canEvaluate && context.biometryType == .faceID } /// checks if device supports touch id and authentication can be done @@ -129,11 +126,11 @@ public extension BioMetricAuthenticator { let context = LAContext() var error: NSError? - let canEvaluate = context.canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: &error) - if #available(iOS 11.0, *) { - return canEvaluate && context.biometryType == .touchID - } - return canEvaluate + let canEvaluate = context.canEvaluatePolicy( + LAPolicy.deviceOwnerAuthenticationWithBiometrics, + error: &error + ) + return canEvaluate && context.biometryType == .touchID } /// checks if device has faceId @@ -142,10 +139,7 @@ public extension BioMetricAuthenticator { func isFaceIdDevice() -> Bool { let context = LAContext() _ = context.canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: nil) - if #available(iOS 11.0, *) { - return context.biometryType == .faceID - } - return false + return context.biometryType == .faceID } } @@ -162,16 +156,13 @@ extension BioMetricAuthenticator { return faceIDAvailable() ? kFaceIdPasscodeAuthenticationReason : kTouchIdPasscodeAuthenticationReason } - /// checks if allowableReuseDuration is set - private func isReuseDurationSet() -> Bool { - guard allowableReuseDuration != nil else { - return false - } - return true - } - /// evaluate policy - private func evaluate(policy: LAPolicy, with context: LAContext, reason: String, completion: @escaping (Result) -> ()) { + private func evaluate( + policy: LAPolicy, + with context: LAContext, + reason: String, + completion: @escaping (Result) -> () + ) { context.evaluatePolicy(policy, localizedReason: reason) { (success, err) in DispatchQueue.main.async { diff --git a/BiometricAuthenticationExample/BiometricAuthenticationExample.xcodeproj/project.pbxproj b/BiometricAuthenticationExample/BiometricAuthenticationExample.xcodeproj/project.pbxproj index 5155b7c..8022127 100644 --- a/BiometricAuthenticationExample/BiometricAuthenticationExample.xcodeproj/project.pbxproj +++ b/BiometricAuthenticationExample/BiometricAuthenticationExample.xcodeproj/project.pbxproj @@ -125,7 +125,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0900; - LastUpgradeCheck = 0940; + LastUpgradeCheck = 1200; ORGANIZATIONNAME = "Rushi Sangani"; TargetAttributes = { D8DB65861FA46C5C00351903 = { @@ -225,6 +225,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -250,7 +251,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -284,6 +285,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -303,7 +305,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -318,7 +320,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = T5CX5N9HK9; INFOPLIST_FILE = BiometricAuthenticationExample/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.rosterbuster.BiometricAuthenticationExample; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -334,7 +336,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = T5CX5N9HK9; INFOPLIST_FILE = BiometricAuthenticationExample/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.rosterbuster.BiometricAuthenticationExample; PRODUCT_NAME = "$(TARGET_NAME)";