Skip to content

Commit

Permalink
Merge pull request MiniKeePass#491 from tssmith7/lockscreen_fix
Browse files Browse the repository at this point in the history
Lock screen using UIWindow and blurring
  • Loading branch information
tallerthenyou authored Sep 13, 2017
2 parents 1f444bf + 7b684ed commit b6b285f
Show file tree
Hide file tree
Showing 11 changed files with 77 additions and 266 deletions.
12 changes: 0 additions & 12 deletions MiniKeePass.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
682D45191603883900156830 /* OutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 682D450A1603883900156830 /* OutputStream.m */; };
682D451A1603883900156830 /* Sha256OutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 682D450C1603883900156830 /* Sha256OutputStream.m */; };
68496E751AB34F8800370876 /* AppSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 68496E721AB34F8800370876 /* AppSettings.m */; };
6851FAFD186DD11D00A53B0E /* UIActionSheetAutoDismiss.m in Sources */ = {isa = PBXBuildFile; fileRef = 6851FAFC186DD11D00A53B0E /* UIActionSheetAutoDismiss.m */; };
685D9D951603F8EE00D739D3 /* Kdb3Utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 685D9D941603F8EE00D739D3 /* Kdb3Utils.m */; };
68767B651D6F23350039EFE0 /* FilesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68767B641D6F23350039EFE0 /* FilesViewController.swift */; };
68767B671D6F241F0039EFE0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 68767B661D6F241F0039EFE0 /* Main.storyboard */; };
Expand Down Expand Up @@ -117,7 +116,6 @@
689FBE641AB271C6005CB6BD /* KeypadButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 689FBE5B1AB271C6005CB6BD /* KeypadButton.m */; };
689FBE651AB271C6005CB6BD /* KeypadView.m in Sources */ = {isa = PBXBuildFile; fileRef = 689FBE5D1AB271C6005CB6BD /* KeypadView.m */; };
689FBE661AB271C6005CB6BD /* LockScreenManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 689FBE5F1AB271C6005CB6BD /* LockScreenManager.m */; };
689FBE671AB271C6005CB6BD /* LockViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 689FBE611AB271C6005CB6BD /* LockViewController.m */; };
689FBE681AB271C6005CB6BD /* PinViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 689FBE631AB271C6005CB6BD /* PinViewController.m */; };
689FBE781AB27228005CB6BD /* KeychainUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 689FBE751AB27228005CB6BD /* KeychainUtils.m */; };
689FBE791AB27228005CB6BD /* PasswordUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 689FBE771AB27228005CB6BD /* PasswordUtils.m */; };
Expand Down Expand Up @@ -212,8 +210,6 @@
682D450C1603883900156830 /* Sha256OutputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Sha256OutputStream.m; sourceTree = "<group>"; };
68496E711AB34F8800370876 /* AppSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppSettings.h; sourceTree = "<group>"; };
68496E721AB34F8800370876 /* AppSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppSettings.m; sourceTree = "<group>"; };
6851FAFB186DD11D00A53B0E /* UIActionSheetAutoDismiss.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIActionSheetAutoDismiss.h; sourceTree = "<group>"; };
6851FAFC186DD11D00A53B0E /* UIActionSheetAutoDismiss.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIActionSheetAutoDismiss.m; sourceTree = "<group>"; };
685D9D931603F8EE00D739D3 /* Kdb3Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Kdb3Utils.h; sourceTree = "<group>"; };
685D9D941603F8EE00D739D3 /* Kdb3Utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Kdb3Utils.m; sourceTree = "<group>"; };
68767B641D6F23350039EFE0 /* FilesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilesViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -334,8 +330,6 @@
689FBE5D1AB271C6005CB6BD /* KeypadView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeypadView.m; sourceTree = "<group>"; };
689FBE5E1AB271C6005CB6BD /* LockScreenManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LockScreenManager.h; sourceTree = "<group>"; };
689FBE5F1AB271C6005CB6BD /* LockScreenManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LockScreenManager.m; sourceTree = "<group>"; };
689FBE601AB271C6005CB6BD /* LockViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LockViewController.h; sourceTree = "<group>"; };
689FBE611AB271C6005CB6BD /* LockViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LockViewController.m; sourceTree = "<group>"; };
689FBE621AB271C6005CB6BD /* PinViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PinViewController.h; sourceTree = "<group>"; };
689FBE631AB271C6005CB6BD /* PinViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PinViewController.m; sourceTree = "<group>"; };
689FBE741AB27228005CB6BD /* KeychainUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeychainUtils.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -720,8 +714,6 @@
689D042813A42C81005EBD36 /* DatabaseManager.h */,
689D042913A42C81005EBD36 /* DatabaseManager.m */,
68CBC1461A4A0F0E004A3553 /* MiniKeePass.entitlements */,
6851FAFB186DD11D00A53B0E /* UIActionSheetAutoDismiss.h */,
6851FAFC186DD11D00A53B0E /* UIActionSheetAutoDismiss.m */,
689FBE7B1AB27283005CB6BD /* Cells */,
689FBE591AB271C6005CB6BD /* Lock Screen */,
68496E701AB34F8800370876 /* Settings */,
Expand Down Expand Up @@ -815,8 +807,6 @@
689FBE5D1AB271C6005CB6BD /* KeypadView.m */,
689FBE5E1AB271C6005CB6BD /* LockScreenManager.h */,
689FBE5F1AB271C6005CB6BD /* LockScreenManager.m */,
689FBE601AB271C6005CB6BD /* LockViewController.h */,
689FBE611AB271C6005CB6BD /* LockViewController.m */,
689FBE621AB271C6005CB6BD /* PinViewController.h */,
689FBE631AB271C6005CB6BD /* PinViewController.m */,
);
Expand Down Expand Up @@ -1047,7 +1037,6 @@
689D03E213A42B63005EBD36 /* KdbReaderFactory.m in Sources */,
689FBE991AB272BD005CB6BD /* ImageFactory.m in Sources */,
689EA6931D67F94600CF445E /* SelectionViewController.swift in Sources */,
689FBE671AB271C6005CB6BD /* LockViewController.m in Sources */,
68496E751AB34F8800370876 /* AppSettings.m in Sources */,
6895D2EA1D68F95D003D8C44 /* RenameItemViewController.swift in Sources */,
689D03E313A42B63005EBD36 /* KdbWriterFactory.m in Sources */,
Expand Down Expand Up @@ -1093,7 +1082,6 @@
68767B691D70B0830039EFE0 /* Array+Extensions.swift in Sources */,
682D451A1603883900156830 /* Sha256OutputStream.m in Sources */,
685D9D951603F8EE00D739D3 /* Kdb3Utils.m in Sources */,
6851FAFD186DD11D00A53B0E /* UIActionSheetAutoDismiss.m in Sources */,
689FBE931AB27283005CB6BD /* TextFieldCell.m in Sources */,
689EA6871D67F90800CF445E /* CharacterSetsViewController.swift in Sources */,
680C277616050C7A009403DE /* DDXMLDocument+MKPAdditions.m in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion MiniKeePass/Cells/TextFieldCell.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ typedef NS_ENUM(NSInteger, TextFieldCellStyle) {
TextFieldCellStyleUrl
};

@interface TextFieldCell : UITableViewCell <UITextFieldDelegate, UIActionSheetDelegate>
@interface TextFieldCell : UITableViewCell <UITextFieldDelegate>

@property (nonatomic, copy) NSString *title;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
Expand Down
2 changes: 0 additions & 2 deletions MiniKeePass/Lock Screen/KeypadView.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ @implementation KeypadView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor whiteColor];

KeypadButton *alphaButton = [KeypadButton systemButtonWithTitle:@"A-Z"];
KeypadButton *deleteButton = [KeypadButton systemButtonWithTitle:@"Delete"];

Expand Down
177 changes: 59 additions & 118 deletions MiniKeePass/Lock Screen/LockScreenManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,25 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

// See Technical Q&A QA1838

#import <LocalAuthentication/LocalAuthentication.h>
#import <AudioToolbox/AudioToolbox.h>
#import "LockScreenManager.h"
#import "LockViewController.h"
#import "AppDelegate.h"
#import "AppSettings.h"
#import "KeychainUtils.h"
#import "PinViewController.h"
#import "PasswordUtils.h"

@interface LockScreenManager () <PinViewControllerDelegate>
@property (nonatomic, strong) LockViewController *lockViewController;
@property (nonatomic, strong) PinViewController *pinViewController;
@property (nonatomic, assign) BOOL checkingTouchId;
@property (nonatomic, assign) BOOL unlocked;
@end

@implementation LockScreenManager
@implementation LockScreenManager {
UIWindow *lockWindow;
BOOL touchIDFailed;
}

static LockScreenManager *sharedInstance = nil;

Expand All @@ -47,21 +48,34 @@ + (instancetype)sharedInstance {
- (instancetype)init {
self = [super init];
if (self) {
_checkingTouchId = NO;
_unlocked = NO;
touchIDFailed = NO;

lockWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
lockWindow.windowLevel = UIWindowLevelAlert;
lockWindow.screen = [UIScreen mainScreen];

UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleRegular];
UIVisualEffectView *blurView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
blurView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
blurView.frame = [[UIScreen mainScreen] bounds];
self.pinViewController = [[PinViewController alloc] init];
self.pinViewController.delegate = self;

lockWindow.rootViewController = self.pinViewController;
[lockWindow addSubview:blurView];

NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:@selector(applicationDidFinishLaunching:)
name:UIApplicationDidFinishLaunchingNotification
object:nil];
[notificationCenter addObserver:self
selector:@selector(applicationWillResignActive:)
name:UIApplicationWillResignActiveNotification
selector:@selector(applicationWillEnterForeground:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
[notificationCenter addObserver:self
selector:@selector(applicationDidBecomeActive:)
name:UIApplicationDidBecomeActiveNotification
selector:@selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
}
return self;
Expand All @@ -75,21 +89,16 @@ - (void)dealloc {
#pragma mark - Lock/Unlock

- (BOOL)shouldCheckPin {
// Check if we're currently checking TouchID
if (self.checkingTouchId) {
return NO;
}

// Check if we're unlocked
if (self.unlocked) {
return NO;
}

// Check if the PIN is enabled
AppSettings *appSettings = [AppSettings sharedInstance];
if (![appSettings pinEnabled]) {
return NO;
}

// Check if touchID check failed
if (touchIDFailed) {
return YES;
}

// Get the last time the app exited
NSDate *exitTime = [appSettings exitTime];
Expand All @@ -102,82 +111,32 @@ - (BOOL)shouldCheckPin {
return timeInterval > [appSettings pinLockTimeout];
}

- (BOOL)shouldLock {
// Check if we're already locked
if (self.lockViewController != nil) {
return NO;
}

// We should lock if the PIN is enabled or closing the database is enabled
AppSettings *appSettings = [AppSettings sharedInstance];
return [appSettings pinEnabled] || [appSettings closeEnabled];
}

- (void)checkPin {
// If the PIN view is already visible, just return
if (self.pinViewController != nil) {
[self.pinViewController clearPin];
return;
}

// Ensure the lock screen is shown first
if (self.lockViewController == nil) {
[self showLockScreen];
}

// Show either the PIN view or perform Touch ID
// Perform Touch ID if enabled and not already failed.
AppSettings *appSettings = [AppSettings sharedInstance];
if ([appSettings touchIdEnabled]) {
if ([appSettings touchIdEnabled] && !touchIDFailed) {
[self showTouchId];
} else {
[self showPinScreen];
}
}

- (void)showLockScreen {
if (self.lockViewController != nil) {
return;
}

self.unlocked = false;

self.lockViewController = [[LockViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self.lockViewController];
navigationController.toolbarHidden = NO;

// Hack for iOS 8 to ensure the view is displayed before anything else on launch
AppDelegate *appDelegate = [AppDelegate getDelegate];
[appDelegate.window addSubview:navigationController.view];

UIViewController *rootViewController = [LockScreenManager topMostController];
[rootViewController presentViewController:navigationController animated:NO completion:nil];
}

- (void)hideLockScreen {
if (self.lockViewController == nil) {
return;
}

self.unlocked = true;

[self.lockViewController.presentingViewController dismissViewControllerAnimated:YES completion:^{
self.lockViewController = nil;
self.pinViewController = nil;
}];
}

- (void)showPinScreen {
self.pinViewController = [[PinViewController alloc] init];
self.pinViewController.delegate = self;

[self.lockViewController presentViewController:self.pinViewController animated:YES completion:nil];
[UIView animateWithDuration:0.25
animations:^{
lockWindow.alpha = 0.0;
}
completion:^(BOOL finished){
[self.pinViewController clearPin];
touchIDFailed = NO;
lockWindow.hidden = YES;
lockWindow.alpha = 1.0;
}];
}

- (void)showTouchId {
// Check if TouchID is supported
if (![NSClassFromString(@"LAContext") class]) {
// Fallback to the PIN screen
[self showPinScreen];
return;
}

Expand All @@ -188,28 +147,23 @@ - (void)showTouchId {
NSError *error = nil;
if (![context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
// Fallback to the PIN screen
[self showPinScreen];
return;
}

self.checkingTouchId = YES;

touchIDFailed = NO;
// Authenticate User
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:NSLocalizedString(@"Unlock MiniKeePass", nil)
reply:^(BOOL success, NSError *error) {
self.checkingTouchId = NO;

if (success) {
// Dismiss the lock screen
dispatch_async(dispatch_get_main_queue(), ^{
[self hideLockScreen];
});
} else {
// Failed, show the PIN screen
dispatch_async(dispatch_get_main_queue(), ^{
[self showPinScreen];
});
touchIDFailed = YES;
}
}];
}
Expand Down Expand Up @@ -274,7 +228,7 @@ - (void)pinViewController:(PinViewController *)pinViewController pinEntered:(NSS
#pragma mark - Closing the database

- (BOOL)shouldCloseDatabase {
// Check if the PIN is enabled
// Check if Close on Timeout is enabled
AppSettings *appSettings = [AppSettings sharedInstance];
if (![appSettings closeEnabled]) {
return NO;
Expand All @@ -294,45 +248,32 @@ - (BOOL)shouldCloseDatabase {
#pragma mark - Application Notification Handlers

- (void)applicationDidFinishLaunching:(NSNotification *)notification {
if ([self shouldCheckPin]) {
[self showLockScreen];
}
}

- (void)applicationWillResignActive:(NSNotification *)notification {
if ([self shouldLock]) {
AppSettings *appSettings = [AppSettings sharedInstance];
[appSettings setExitTime:[NSDate date]];

[self showLockScreen];
// Lock if the PIN is enabled
AppSettings *appSettings = [AppSettings sharedInstance];
if ([appSettings pinEnabled]) {
[lockWindow makeKeyAndVisible];
[self checkPin];
}
}

- (void)applicationDidBecomeActive:(NSNotification *)notification {
- (void)applicationWillEnterForeground:(NSNotification *)notification {
if ([self shouldCloseDatabase]) {
AppDelegate *appDelegate = [AppDelegate getDelegate];
[appDelegate closeDatabase];
}

if ([self shouldCheckPin]) {
[self checkPin];
} else {
if (!self.checkingTouchId) {
[self hideLockScreen];
}
[self hideLockScreen];
}
}

#pragma mark - Helper method

+ (UIViewController *)topMostController {
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

while (topController.presentedViewController) {
topController = topController.presentedViewController;
}

return topController;
- (void)applicationDidEnterBackground:(NSNotification *)notification {
AppSettings *appSettings = [AppSettings sharedInstance];
[appSettings setExitTime:[NSDate date]];
[self.pinViewController showPinKeypad:[appSettings pinEnabled]];
[lockWindow makeKeyAndVisible];
}

@end
Loading

0 comments on commit b6b285f

Please sign in to comment.