Improved signin/signout state logic.
This commit is contained in:
@@ -10,13 +10,11 @@
|
||||
|
||||
@interface MPAppDelegate_Shared (Key)
|
||||
|
||||
- (void)loadSavedKey;
|
||||
- (IBAction)signOut:(id)sender;
|
||||
- (BOOL)signInAsUser:(MPUserEntity *)user usingMasterPassword:(NSString *)password;
|
||||
- (void)signOut;
|
||||
|
||||
- (BOOL)tryMasterPassword:(NSString *)tryPassword forUser:(MPUserEntity *)user;
|
||||
- (void)storeSavedKey;
|
||||
- (void)forgetSavedKey;
|
||||
- (void)unsetKey;
|
||||
- (void)storeSavedKeyFor:(MPUserEntity *)user;
|
||||
- (void)forgetSavedKeyFor:(MPUserEntity *)user;
|
||||
|
||||
- (NSData *)keyWithLength:(NSUInteger)keyLength;
|
||||
|
||||
|
@@ -12,7 +12,7 @@
|
||||
@implementation MPAppDelegate_Shared (Key)
|
||||
|
||||
static NSDictionary *keyQuery(MPUserEntity *user) {
|
||||
|
||||
|
||||
return [PearlKeyChain createQueryForClass:kSecClassGenericPassword
|
||||
attributes:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"Saved Master Password", (__bridge id)kSecAttrService,
|
||||
@@ -21,113 +21,131 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
|
||||
matches:nil];
|
||||
}
|
||||
|
||||
- (void)forgetSavedKey {
|
||||
|
||||
if ([PearlKeyChain deleteItemForQuery:keyQuery(self.activeUser)] != errSecItemNotFound) {
|
||||
inf(@"Removed key from keychain.");
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyForgotten object:self];
|
||||
#ifdef TESTFLIGHT_SDK_VERSION
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointMPForgotten];
|
||||
#endif
|
||||
- (NSData *)loadSavedKeyFor:(MPUserEntity *)user {
|
||||
|
||||
NSData *key = [PearlKeyChain dataOfItemForQuery:keyQuery(user)];
|
||||
if (key)
|
||||
inf(@"Found key (for: %@) in keychain.", user.name);
|
||||
|
||||
else {
|
||||
user.saveKey = NO;
|
||||
inf(@"No key found (for: %@) in keychain.", user.name);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
- (IBAction)signOut:(id)sender {
|
||||
- (void)storeSavedKeyFor:(MPUserEntity *)user {
|
||||
|
||||
[self forgetSavedKey];
|
||||
[self unsetKey];
|
||||
}
|
||||
if (user.saveKey) {
|
||||
NSData *existingKey = [PearlKeyChain dataOfItemForQuery:keyQuery(user)];
|
||||
|
||||
- (void)loadSavedKey {
|
||||
|
||||
if (self.activeUser.saveKey) {
|
||||
// Key should be saved in keychain. Load it.
|
||||
self.key = [PearlKeyChain dataOfItemForQuery:keyQuery(self.activeUser)];
|
||||
inf(@"Looking for key in keychain: %@.", self.key? @"found": @"missing");
|
||||
if (self.key)
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeySet object:self];
|
||||
} else {
|
||||
// Key should not be stored in keychain. Delete it.
|
||||
if ([PearlKeyChain deleteItemForQuery:keyQuery(self.activeUser)] != errSecItemNotFound)
|
||||
inf(@"Removed key from keychain.");
|
||||
#ifdef TESTFLIGHT_SDK_VERSION
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointMPUnstored];
|
||||
if (![existingKey isEqualToData:self.key]) {
|
||||
inf(@"Updating key in keychain.");
|
||||
[PearlKeyChain addOrUpdateItemForQuery:keyQuery(user)
|
||||
withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
self.key, (__bridge id) kSecValueData,
|
||||
#if TARGET_OS_IPHONE
|
||||
kSecAttrAccessibleWhenUnlockedThisDeviceOnly, (__bridge id) kSecAttrAccessible,
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)tryMasterPassword:(NSString *)tryPassword forUser:(MPUserEntity *)user {
|
||||
|
||||
if (![tryPassword length])
|
||||
return NO;
|
||||
|
||||
NSData *tryKey = keyForPassword(tryPassword, user.name);
|
||||
NSData *tryKeyID = keyIDForKey(tryKey);
|
||||
inf(@"Key ID was known? %@.", user.keyID? @"YES": @"NO");
|
||||
if (user.keyID) {
|
||||
// A key ID is known -> a master password is set.
|
||||
// Make sure the user's entered master password matches it.
|
||||
if (![user.keyID isEqual:tryKeyID]) {
|
||||
wrn(@"Key ID mismatch. Expected: %@, answer: %@.", [user.keyID encodeHex], [tryKeyID encodeHex]);
|
||||
|
||||
#ifdef TESTFLIGHT_SDK_VERSION
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointMPMismatch];
|
||||
#endif
|
||||
return NO;
|
||||
nil]];
|
||||
}
|
||||
} else {
|
||||
// A key ID is not known -> recording a new master password.
|
||||
user.keyID = tryKeyID;
|
||||
[[MPAppDelegate_Shared get] saveContext];
|
||||
}
|
||||
user.lastUsed = [NSDate date];
|
||||
}
|
||||
|
||||
- (void)forgetSavedKeyFor:(MPUserEntity *)user {
|
||||
|
||||
OSStatus result = [PearlKeyChain deleteItemForQuery:keyQuery(user)];
|
||||
if (result == noErr || result == errSecItemNotFound) {
|
||||
user.saveKey = NO;
|
||||
|
||||
if (result == noErr) {
|
||||
inf(@"Removed key (for: %@) from keychain.", user.name);
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyForgotten object:self];
|
||||
#ifdef TESTFLIGHT_SDK_VERSION
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointForgetSavedKey];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)signOut {
|
||||
|
||||
self.key = nil;
|
||||
self.activeUser = nil;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationSignedOut object:self];
|
||||
}
|
||||
|
||||
- (BOOL)signInAsUser:(MPUserEntity *)user usingMasterPassword:(NSString *)password {
|
||||
|
||||
NSData *tryKey = nil;
|
||||
|
||||
// Method 1: When the user has no keyID set, set a new key from the given master password.
|
||||
if (!user.keyID) {
|
||||
if ([password length])
|
||||
if ((tryKey = keyForPassword(password, user.name))) {
|
||||
user.keyID = keyIDForKey(tryKey);
|
||||
[[MPAppDelegate_Shared get] saveContext];
|
||||
}
|
||||
}
|
||||
|
||||
// Method 2: Depending on the user's saveKey, load or remove the key from the keychain.
|
||||
if (!user.saveKey)
|
||||
// Key should not be stored in keychain. Delete it.
|
||||
[self forgetSavedKeyFor:user];
|
||||
|
||||
else if (!tryKey) {
|
||||
// Key should be saved in keychain. Load it.
|
||||
if ((tryKey = [self loadSavedKeyFor:user]))
|
||||
if (![user.keyID isEqual:keyIDForKey(tryKey)]) {
|
||||
// Loaded password doesn't match user's keyID. Forget saved password: it is incorrect.
|
||||
tryKey = nil;
|
||||
[self forgetSavedKeyFor:user];
|
||||
|
||||
#ifdef TESTFLIGHT_SDK_VERSION
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointMPEntered];
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointMPMismatch];
|
||||
#endif
|
||||
|
||||
if (self.key != tryKey) {
|
||||
self.key = tryKey;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeySet object:self];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Method 3: Check the given master password string.
|
||||
if (!tryKey) {
|
||||
if ([password length])
|
||||
if ((tryKey = keyForPassword(password, user.name)))
|
||||
if (![user.keyID isEqual:keyIDForKey(tryKey)]) {
|
||||
tryKey = nil;
|
||||
|
||||
#ifdef TESTFLIGHT_SDK_VERSION
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointMPMismatch];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// No more methods left, fail if key still not known.
|
||||
if (!tryKey)
|
||||
return NO;
|
||||
|
||||
if (![self.key isEqualToData:tryKey]) {
|
||||
self.key = tryKey;
|
||||
[self storeSavedKeyFor:user];
|
||||
}
|
||||
|
||||
user.lastUsed = [NSDate date];
|
||||
self.activeUser = user;
|
||||
|
||||
[[MPAppDelegate_Shared get] saveContext];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationSignedIn object:self];
|
||||
#ifdef TESTFLIGHT_SDK_VERSION
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointSetKey];
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointSignedIn];
|
||||
#endif
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)storeSavedKey {
|
||||
|
||||
if (self.activeUser.saveKey) {
|
||||
NSData *existingKey = [PearlKeyChain dataOfItemForQuery:keyQuery(self.activeUser)];
|
||||
|
||||
if (![existingKey isEqualToData:self.key]) {
|
||||
inf(@"Updating key in keychain.");
|
||||
[PearlKeyChain addOrUpdateItemForQuery:keyQuery(self.activeUser)
|
||||
withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
self.key, (__bridge id)kSecValueData,
|
||||
#if TARGET_OS_IPHONE
|
||||
kSecAttrAccessibleWhenUnlockedThisDeviceOnly, (__bridge id)kSecAttrAccessible,
|
||||
#endif
|
||||
nil]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unsetKey {
|
||||
|
||||
self.key = nil;
|
||||
self.activeUser = nil;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyUnset object:self];
|
||||
}
|
||||
|
||||
- (NSData *)keyWithLength:(NSUInteger)keyLength {
|
||||
|
||||
|
||||
return [self.key subdataWithRange:NSMakeRange(0, MIN(keyLength, self.key.length))];
|
||||
}
|
||||
|
||||
|
@@ -59,22 +59,21 @@ typedef enum {
|
||||
#define MPTestFlightCheckpointDeactivated @"MPTestFlightCheckpointDeactivated"
|
||||
#define MPTestFlightCheckpointTerminated @"MPTestFlightCheckpointTerminated"
|
||||
#define MPTestFlightCheckpointShowGuide @"MPTestFlightCheckpointShowGuide"
|
||||
#define MPTestFlightCheckpointMPForgotten @"MPTestFlightCheckpointMPForgotten"
|
||||
#define MPTestFlightCheckpointMPChanged @"MPTestFlightCheckpointMPChanged"
|
||||
#define MPTestFlightCheckpointMPUnstored @"MPTestFlightCheckpointMPUnstored"
|
||||
#define MPTestFlightCheckpointForgetSavedKey @"MPTestFlightCheckpointForgetSavedKey"
|
||||
#define MPTestFlightCheckpointChangeMP @"MPTestFlightCheckpointChangeMP"
|
||||
#define MPTestFlightCheckpointMPMismatch @"MPTestFlightCheckpointMPMismatch"
|
||||
#define MPTestFlightCheckpointMPEntered @"MPTestFlightCheckpointMPEntered"
|
||||
#define MPTestFlightCheckpointMPValid @"MPTestFlightCheckpointMPValid"
|
||||
#define MPTestFlightCheckpointLocalStoreIncompatible @"MPTestFlightCheckpointLocalStoreIncompatible"
|
||||
#define MPTestFlightCheckpointCloudStoreIncompatible @"MPTestFlightCheckpointCloudStoreIncompatible"
|
||||
#define MPTestFlightCheckpointSetKey @"MPTestFlightCheckpointSetKey"
|
||||
#define MPTestFlightCheckpointSignedIn @"MPTestFlightCheckpointSetKey"
|
||||
#define MPTestFlightCheckpointCloudEnabled @"MPTestFlightCheckpointCloudEnabled"
|
||||
#define MPTestFlightCheckpointCloudDisabled @"MPTestFlightCheckpointCloudDisabled"
|
||||
#define MPTestFlightCheckpointSitesImported @"MPTestFlightCheckpointSitesImported"
|
||||
#define MPTestFlightCheckpointSitesExported @"MPTestFlightCheckpointSitesExported"
|
||||
|
||||
#define MPNotificationStoreUpdated @"MPNotificationStoreUpdated"
|
||||
#define MPNotificationKeySet @"MPNotificationKeySet"
|
||||
#define MPNotificationKeyUnset @"MPNotificationKeyUnset"
|
||||
#define MPNotificationSignedIn @"MPNotificationKeySet"
|
||||
#define MPNotificationSignedOut @"MPNotificationKeyUnset"
|
||||
#define MPNotificationKeyForgotten @"MPNotificationKeyForgotten"
|
||||
#define MPNotificationElementUsed @"MPNotificationElementUsed"
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
<entity name="MPElementEntity" representedClassName="MPElementEntity" isAbstract="YES" syncable="YES">
|
||||
<attribute name="content" optional="YES" transient="YES" attributeType="Transformable" syncable="YES"/>
|
||||
<attribute name="lastUsed" attributeType="Date" syncable="YES"/>
|
||||
<attribute name="name" attributeType="String" minValueString="1" indexed="YES" syncable="YES" isSyncIdentityProperty="YES"/>
|
||||
<attribute name="name" attributeType="String" minValueString="1" indexed="YES" syncable="YES"/>
|
||||
<attribute name="type_" attributeType="Integer 16" defaultValueString="17" syncable="YES"/>
|
||||
<attribute name="uses_" attributeType="Integer 16" defaultValueString="0" syncable="YES"/>
|
||||
<relationship name="user" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="MPUserEntity" inverseName="elements" inverseEntity="MPUserEntity" syncable="YES"/>
|
||||
@@ -18,8 +18,8 @@
|
||||
<attribute name="avatar_" attributeType="Integer 16" defaultValueString="0" syncable="YES"/>
|
||||
<attribute name="keyID" optional="YES" attributeType="Binary" syncable="YES"/>
|
||||
<attribute name="lastUsed" optional="YES" attributeType="Date" syncable="YES"/>
|
||||
<attribute name="name" attributeType="String" syncable="YES" isSyncIdentityProperty="YES"/>
|
||||
<attribute name="saveKey_" attributeType="Boolean" defaultValueString="NO" syncable="YES"/>
|
||||
<attribute name="name" attributeType="String" syncable="YES"/>
|
||||
<attribute name="saveKey_" attributeType="Boolean" defaultValueString="NO"/>
|
||||
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity" inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
|
||||
</entity>
|
||||
<elements>
|
||||
|
@@ -14,8 +14,8 @@
|
||||
|
||||
+ (MPAppDelegate *)get;
|
||||
|
||||
- (void)checkConfig;
|
||||
- (void)showGuide;
|
||||
- (void)loadKey:(BOOL)animated;
|
||||
|
||||
- (void)export;
|
||||
- (void)changeMP;
|
||||
|
@@ -50,6 +50,12 @@
|
||||
return (MPAppDelegate *)[super get];
|
||||
}
|
||||
|
||||
- (void)checkConfig {
|
||||
|
||||
if ([[MPConfig get].iCloud boolValue] != [self.storeManager iCloudEnabled])
|
||||
[self.storeManager useiCloudStore:[[MPConfig get].iCloud boolValue] alertUser:YES];
|
||||
}
|
||||
|
||||
- (void)showGuide {
|
||||
|
||||
[self.navigationController performSegueWithIdentifier:@"MP_Guide" sender:self];
|
||||
@@ -57,21 +63,6 @@
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointShowGuide];
|
||||
}
|
||||
|
||||
- (void)loadKey:(BOOL)animated {
|
||||
|
||||
if (!self.key)
|
||||
// Try and load the key from the keychain.
|
||||
[self loadSavedKey];
|
||||
|
||||
if (!self.key)
|
||||
// Ask the user to set the key through his master password.
|
||||
PearlMainThread(^{
|
||||
[self.navigationController presentViewController:
|
||||
[self.navigationController.storyboard instantiateViewControllerWithIdentifier:@"MPUnlockViewController"]
|
||||
animated:animated completion:nil];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)export {
|
||||
|
||||
[PearlAlert showNotice:
|
||||
@@ -131,10 +122,10 @@
|
||||
if (buttonIndex == [alert cancelButtonIndex])
|
||||
return;
|
||||
|
||||
[[MPAppDelegate get] forgetSavedKey];
|
||||
[[MPAppDelegate get] loadKey:YES];
|
||||
self.activeUser.keyID = nil;
|
||||
[self signOut];
|
||||
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointMPChanged];
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointChangeMP];
|
||||
}
|
||||
cancelTitle:[PearlStrings get].commonButtonAbort
|
||||
otherTitles:[PearlStrings get].commonButtonContinue, nil];
|
||||
@@ -147,12 +138,6 @@
|
||||
[self checkConfig];
|
||||
}
|
||||
|
||||
- (void)checkConfig {
|
||||
|
||||
if ([[MPConfig get].iCloud boolValue] != [self.storeManager iCloudEnabled])
|
||||
[self.storeManager useiCloudStore:[[MPConfig get].iCloud boolValue] alertUser:YES];
|
||||
}
|
||||
|
||||
#pragma mark - UIApplicationDelegate
|
||||
|
||||
|
||||
@@ -287,7 +272,11 @@
|
||||
[[UISegmentedControl appearance] setDividerImage:segmentUnselectedUnselected forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
|
||||
[[UISegmentedControl appearance] setDividerImage:segmentSelectedUnselected forLeftSegmentState:UIControlStateSelected rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
|
||||
[[UISegmentedControl appearance] setDividerImage:segUnselectedSelected forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateSelected barMetrics:UIBarMetricsDefault];*/
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserverForName:MPNotificationSignedOut object:nil queue:nil
|
||||
usingBlock:^(NSNotification *note) {
|
||||
[self.navigationController performSegueWithIdentifier:@"MP_Unlock" sender:nil];
|
||||
}];
|
||||
[[NSNotificationCenter defaultCenter] addObserverForName:kIASKAppSettingChanged object:nil queue:nil
|
||||
usingBlock:^(NSNotification *note) {
|
||||
[self checkConfig];
|
||||
@@ -379,11 +368,7 @@
|
||||
|
||||
if ([[MPiOSConfig get].showQuickStart boolValue])
|
||||
[self showGuide];
|
||||
else {
|
||||
[self loadKey:NO];
|
||||
[self checkConfig];
|
||||
}
|
||||
|
||||
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointActivated];
|
||||
|
||||
[super applicationDidBecomeActive:application];
|
||||
@@ -421,11 +406,9 @@
|
||||
|
||||
[self saveContext];
|
||||
|
||||
if (![[MPiOSConfig get].rememberLogin boolValue]) {
|
||||
[self unsetKey];
|
||||
[self loadKey:NO];
|
||||
}
|
||||
|
||||
if (![[MPiOSConfig get].rememberLogin boolValue])
|
||||
[self signOut];
|
||||
|
||||
[TestFlight passCheckpoint:MPTestFlightCheckpointDeactivated];
|
||||
}
|
||||
|
||||
|
@@ -32,14 +32,6 @@
|
||||
[MPiOSConfig get].showQuickStart = [NSNumber numberWithBool:NO];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated {
|
||||
|
||||
[super viewDidDisappear:animated];
|
||||
|
||||
[[MPAppDelegate get] loadKey:animated];
|
||||
}
|
||||
|
||||
|
||||
- (void)viewDidUnload {
|
||||
|
||||
[self setScrollView:nil];
|
||||
|
@@ -71,6 +71,8 @@
|
||||
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
if (![MPAppDelegate get].activeUser)
|
||||
[self.navigationController performSegueWithIdentifier:@"MP_Unlock" sender:self];
|
||||
if (self.activeElement.user != [MPAppDelegate get].activeUser)
|
||||
self.activeElement = nil;
|
||||
self.searchDisplayController.searchBar.text = nil;
|
||||
@@ -103,6 +105,8 @@
|
||||
}
|
||||
}];
|
||||
|
||||
[[MPAppDelegate get] checkConfig];
|
||||
|
||||
[super viewDidAppear:animated];
|
||||
}
|
||||
|
||||
@@ -220,7 +224,7 @@
|
||||
- (void)webViewDidFinishLoad:(UIWebView *)webView {
|
||||
|
||||
NSString *error = [self.helpView stringByEvaluatingJavaScriptFromString:
|
||||
PearlString(@"setClass('%@');", ClassNameFromMPElementType(self.activeElement.type))];
|
||||
PearlString(@"setClass('%@');", ClassNameFromMPElementType(self.activeElement.type))];
|
||||
if (error.length)
|
||||
err(@"helpView.setClass: %@", error);
|
||||
}
|
||||
@@ -419,8 +423,8 @@
|
||||
case 5:
|
||||
#endif
|
||||
{
|
||||
[[MPAppDelegate get] signOut:self];
|
||||
[[MPAppDelegate get] loadKey:YES];
|
||||
[[MPAppDelegate get] forgetSavedKeyFor:[MPAppDelegate get].activeUser];
|
||||
[[MPAppDelegate get] signOut];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import "MPPreferencesViewController.h"
|
||||
#import "MPAppDelegate.h"
|
||||
#import "MPAppDelegate_Key.h"
|
||||
|
||||
@interface MPPreferencesViewController ()
|
||||
|
||||
@@ -114,7 +115,10 @@
|
||||
|
||||
- (IBAction)didToggleSwitch:(UISwitch *)sender {
|
||||
|
||||
[MPAppDelegate get].activeUser.saveKey = sender.on;
|
||||
if (([MPAppDelegate get].activeUser.saveKey = sender.on))
|
||||
[[MPAppDelegate get] storeSavedKeyFor:[MPAppDelegate get].activeUser];
|
||||
else
|
||||
[[MPAppDelegate get] forgetSavedKeyFor:[MPAppDelegate get].activeUser];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@@ -119,12 +119,6 @@
|
||||
[self.avatarsView autoSizeContentIgnoreHidden:YES ignoreInvisible:YES limitPadding:NO ignoreSubviews:nil];
|
||||
|
||||
[self updateLayoutAnimated:YES allowScroll:YES completion:nil];
|
||||
|
||||
self.deleteTip.alpha = 0;
|
||||
if ([users count] > 1)
|
||||
[UIView animateWithDuration:0.5f animations:^{
|
||||
self.deleteTip.alpha = 1;
|
||||
}];
|
||||
}
|
||||
|
||||
- (UIButton *)setupAvatar:(UIButton *)avatar forUser:(MPUserEntity *)user {
|
||||
@@ -169,7 +163,11 @@
|
||||
|
||||
if (!self.selectedUser)
|
||||
[self.passwordField resignFirstResponder];
|
||||
|
||||
else if ([[MPAppDelegate get] signInAsUser:self.selectedUser usingMasterPassword:nil]) {
|
||||
[self dismissModalViewControllerAnimated:YES];
|
||||
return;
|
||||
}
|
||||
|
||||
[self updateLayoutAnimated:YES allowScroll:YES completion:^(BOOL finished) {
|
||||
if (finished)
|
||||
if (self.selectedUser)
|
||||
@@ -230,6 +228,7 @@
|
||||
self.nameLabel.backgroundColor = [UIColor blackColor];
|
||||
self.oldNameLabel.center = self.nameLabel.center;
|
||||
self.avatarShadowColor = [UIColor whiteColor];
|
||||
self.deleteTip.alpha = 0;
|
||||
} else if (!self.selectedUser && self.passwordView.alpha == 1) {
|
||||
self.passwordView.alpha = 0;
|
||||
self.avatarsView.center = CGPointMake(160, 240);
|
||||
@@ -238,6 +237,7 @@
|
||||
self.nameLabel.backgroundColor = [UIColor clearColor];
|
||||
self.oldNameLabel.center = self.nameLabel.center;
|
||||
self.avatarShadowColor = [UIColor lightGrayColor];
|
||||
self.deleteTip.alpha = [self.avatarToUser count] > 2? 1: 0;
|
||||
}
|
||||
|
||||
MPUserEntity *targetedUser = self.selectedUser;
|
||||
@@ -294,14 +294,14 @@
|
||||
[self setSpinnerActive:YES];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
BOOL unlocked = [[MPAppDelegate get] tryMasterPassword:self.passwordField.text forUser:self.selectedUser];
|
||||
BOOL unlocked = [[MPAppDelegate get] signInAsUser:self.selectedUser usingMasterPassword:self.passwordField.text];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (unlocked) {
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (long) (NSEC_PER_SEC * 0.5f)), dispatch_get_main_queue(), ^{
|
||||
[self dismissModalViewControllerAnimated:YES];
|
||||
});
|
||||
} else
|
||||
} else if (self.passwordField.text.length)
|
||||
[self setPasswordTip:@"Incorrect password."];
|
||||
|
||||
[self setSpinnerActive:NO];
|
||||
|
@@ -925,6 +925,7 @@ L4m3P4sSw0rD</string>
|
||||
<connections>
|
||||
<segue destination="PQa-Xl-A3x" kind="relationship" relationship="rootViewController" id="LUg-eF-JQd"/>
|
||||
<segue destination="qz3-eG-aEi" kind="modal" identifier="MP_Guide" id="vyG-wN-8hU"/>
|
||||
<segue destination="Nbn-Rv-sP1" kind="modal" identifier="MP_Unlock" id="6s2-3H-q5S"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
</objects>
|
||||
|
Reference in New Issue
Block a user