Improve handling of unexpected failures in local authentication.

pull/1/head
Matthew Chen 7 years ago
parent 461af01943
commit feb5d68f83

@ -11,6 +11,7 @@ import LocalAuthentication
case success case success
case cancel case cancel
case failure(error:String) case failure(error:String)
case unexpectedFailure(error:String)
} }
@objc public let screenLockTimeoutDefault = 15 * kMinuteInterval @objc public let screenLockTimeoutDefault = 15 * kMinuteInterval
@ -122,6 +123,8 @@ import LocalAuthentication
switch outcome { switch outcome {
case .failure(let error): case .failure(let error):
completion(self.authenticationError(errorDescription: error)) completion(self.authenticationError(errorDescription: error))
case .unexpectedFailure(let error):
completion(self.authenticationError(errorDescription: error))
case .success: case .success:
self.setIsScreenLockEnabled(value: true) self.setIsScreenLockEnabled(value: true)
completion(nil) completion(nil)
@ -144,6 +147,8 @@ import LocalAuthentication
switch outcome { switch outcome {
case .failure(let error): case .failure(let error):
completion(self.authenticationError(errorDescription: error)) completion(self.authenticationError(errorDescription: error))
case .unexpectedFailure(let error):
completion(self.authenticationError(errorDescription: error))
case .success: case .success:
self.setIsScreenLockEnabled(value: false) self.setIsScreenLockEnabled(value: false)
completion(nil) completion(nil)
@ -155,6 +160,7 @@ import LocalAuthentication
@objc public func tryToUnlockScreenLock(success: @escaping (() -> Void), @objc public func tryToUnlockScreenLock(success: @escaping (() -> Void),
failure: @escaping ((Error) -> Void), failure: @escaping ((Error) -> Void),
unexpectedFailure: @escaping ((Error) -> Void),
cancel: @escaping (() -> Void)) { cancel: @escaping (() -> Void)) {
guard !ignoreUnlockUntilActive else { guard !ignoreUnlockUntilActive else {
DispatchQueue.main.async { DispatchQueue.main.async {
@ -171,6 +177,8 @@ import LocalAuthentication
switch outcome { switch outcome {
case .failure(let error): case .failure(let error):
failure(self.authenticationError(errorDescription: error)) failure(self.authenticationError(errorDescription: error))
case .unexpectedFailure(let error):
unexpectedFailure(self.authenticationError(errorDescription: error))
case .success: case .success:
success() success()
case .cancel: case .cancel:
@ -215,7 +223,7 @@ import LocalAuthentication
case .success: case .success:
owsFail("\(self.logTag) local authentication unexpected success") owsFail("\(self.logTag) local authentication unexpected success")
completion(.failure(error:defaultErrorDescription)) completion(.failure(error:defaultErrorDescription))
case .cancel, .failure: case .cancel, .failure, .unexpectedFailure:
completion(outcome) completion(outcome)
} }
return return
@ -235,7 +243,7 @@ import LocalAuthentication
case .success: case .success:
owsFail("\(self.logTag) local authentication unexpected success") owsFail("\(self.logTag) local authentication unexpected success")
completion(.failure(error:defaultErrorDescription)) completion(.failure(error:defaultErrorDescription))
case .cancel, .failure: case .cancel, .failure, .unexpectedFailure:
completion(outcome) completion(outcome)
} }
} }
@ -296,10 +304,10 @@ import LocalAuthentication
comment: "Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures.")) comment: "Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures."))
case .invalidContext: case .invalidContext:
owsFail("\(self.logTag) context not valid.") owsFail("\(self.logTag) context not valid.")
break return .unexpectedFailure(error:defaultErrorDescription)
case .notInteractive: case .notInteractive:
owsFail("\(self.logTag) context not interactive.") owsFail("\(self.logTag) context not interactive.")
break return .unexpectedFailure(error:defaultErrorDescription)
} }
} }
return .failure(error:defaultErrorDescription) return .failure(error:defaultErrorDescription)
@ -316,6 +324,9 @@ import LocalAuthentication
let context = LAContext() let context = LAContext()
context.touchIDAuthenticationAllowableReuseDuration = TimeInterval(screenLockTimeout()) context.touchIDAuthenticationAllowableReuseDuration = TimeInterval(screenLockTimeout())
if #available(iOS 11.0, *) {
assert(!context.interactionNotAllowed)
}
return context return context
} }

@ -145,6 +145,9 @@ NS_ASSUME_NONNULL_BEGIN
shouldHaveScreenProtection, shouldHaveScreenProtection,
shouldHaveScreenLock, shouldHaveScreenLock,
shouldShowBlockWindow); shouldShowBlockWindow);
if (self.screenBlockingWindow.hidden != shouldShowBlockWindow) {
DDLogInfo(@"%@, %@.", self.logTag, shouldShowBlockWindow ? @"showing block window" : @"hiding block window");
}
self.screenBlockingWindow.hidden = !shouldShowBlockWindow; self.screenBlockingWindow.hidden = !shouldShowBlockWindow;
[self.screenLockUITimer invalidate]; [self.screenLockUITimer invalidate];
@ -199,7 +202,7 @@ NS_ASSUME_NONNULL_BEGIN
return; return;
} }
DDLogVerbose(@"%@, try to unlock screen lock", self.logTag); DDLogInfo(@"%@, try to unlock screen lock", self.logTag);
self.isShowingScreenLockUI = YES; self.isShowingScreenLockUI = YES;
self.lastUnlockAttemptDate = [NSDate new]; self.lastUnlockAttemptDate = [NSDate new];
@ -217,6 +220,14 @@ NS_ASSUME_NONNULL_BEGIN
[self showScreenLockFailureAlertWithMessage:error.localizedDescription]; [self showScreenLockFailureAlertWithMessage:error.localizedDescription];
} }
unexpectedFailure:^(NSError *error) {
DDLogInfo(@"%@ unlock screen lock unexpectedly failed.", self.logTag);
self.isShowingScreenLockUI = NO;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self ensureScreenProtection];
});
}
cancel:^{ cancel:^{
DDLogInfo(@"%@ unlock screen lock cancelled.", self.logTag); DDLogInfo(@"%@ unlock screen lock cancelled.", self.logTag);
self.isShowingScreenLockUI = NO; self.isShowingScreenLockUI = NO;

Loading…
Cancel
Save