diff --git a/platform-darwin/External/Pearl b/platform-darwin/External/Pearl index 3ceb601b..6f3efd7a 160000 --- a/platform-darwin/External/Pearl +++ b/platform-darwin/External/Pearl @@ -1 +1 @@ -Subproject commit 3ceb601ba4cb900e38f8a15a14fde537718afcfa +Subproject commit 6f3efd7abd80019ea1945f3a2cc5a6f4bbb3ad67 diff --git a/platform-darwin/Source/MPAlgorithmV0.m b/platform-darwin/Source/MPAlgorithmV0.m index 089c9f8c..a839d9fb 100644 --- a/platform-darwin/Source/MPAlgorithmV0.m +++ b/platform-darwin/Source/MPAlgorithmV0.m @@ -430,58 +430,38 @@ NSOperationQueue *_mpwQueue = nil; - (NSString *)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey { - dispatch_group_t group = dispatch_group_create(); - dispatch_group_enter( group ); - __block NSString *result = nil; - [self resolveLoginForSite:site usingKey:siteKey result:^(NSString *result_) { - result = result_; - dispatch_group_leave( group ); - }]; - dispatch_group_wait( group, DISPATCH_TIME_FOREVER ); - - return result; + return PearlAwait( ^(void (^setResult)(id)) { + [self resolveLoginForSite:site usingKey:siteKey result:^(NSString *result_) { + setResult( result_ ); + }]; + } ); } - (NSString *)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey { - dispatch_group_t group = dispatch_group_create(); - dispatch_group_enter( group ); - __block NSString *result = nil; - [self resolvePasswordForSite:site usingKey:siteKey result:^(NSString *result_) { - result = result_; - dispatch_group_leave( group ); - }]; - dispatch_group_wait( group, DISPATCH_TIME_FOREVER ); - - return result; + return PearlAwait( ^(void (^setResult)(id)) { + [self resolvePasswordForSite:site usingKey:siteKey result:^(NSString *result_) { + setResult( result_ ); + }]; + } ); } - (NSString *)resolveAnswerForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey { - dispatch_group_t group = dispatch_group_create(); - dispatch_group_enter( group ); - __block NSString *result = nil; - [self resolveAnswerForSite:site usingKey:siteKey result:^(NSString *result_) { - result = result_; - dispatch_group_leave( group ); - }]; - dispatch_group_wait( group, DISPATCH_TIME_FOREVER ); - - return result; + return PearlAwait( ^(void (^setResult)(id)) { + [self resolveAnswerForSite:site usingKey:siteKey result:^(NSString *result_) { + setResult( result_ ); + }]; + } ); } - (NSString *)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question usingKey:(MPKey *)siteKey { - dispatch_group_t group = dispatch_group_create(); - dispatch_group_enter( group ); - __block NSString *result = nil; - [self resolveAnswerForQuestion:question usingKey:siteKey result:^(NSString *result_) { - result = result_; - dispatch_group_leave( group ); - }]; - dispatch_group_wait( group, DISPATCH_TIME_FOREVER ); - - return result; + return PearlAwait( ^(void (^setResult)(id)) { + [self resolveAnswerForQuestion:question usingKey:siteKey result:^(NSString *result_) { + setResult( result_ ); + }]; + } ); } - (void)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey result:(void ( ^ )(NSString *result))resultBlock { diff --git a/platform-darwin/Source/MPAppDelegate_Key.m b/platform-darwin/Source/MPAppDelegate_Key.m index 17777bc3..2a7ada9b 100644 --- a/platform-darwin/Source/MPAppDelegate_Key.m +++ b/platform-darwin/Source/MPAppDelegate_Key.m @@ -72,14 +72,20 @@ static NSDictionary *createKeyQuery(MPUserEntity *user, BOOL newItem, MPKeyOrigi MPKeyOrigin keyOrigin; NSDictionary *keyQuery = createKeyQuery( user, NO, &keyOrigin ); - NSData *keyData = [PearlKeyChain dataOfItemForQuery:keyQuery]; - if (!keyData) { - inf( @"No key found in keychain for user: %@", user.userID ); - return nil; - } + id keyAlgorithm = user.algorithm; + MPKey *key = [[MPKey alloc] initForFullName:user.name withKeyResolver:^NSData *(id algorithm) { + return ![algorithm isEqual:keyAlgorithm]? nil: + PearlMainQueueAwait( (id)^{ + return [PearlKeyChain dataOfItemForQuery:keyQuery]; + } ); + } keyOrigin:keyOrigin]; - inf( @"Found key in keychain for user: %@", user.userID ); - return [[MPKey alloc] initForFullName:user.name withKeyData:keyData forAlgorithm:user.algorithm keyOrigin:keyOrigin]; + if ([key keyIDForAlgorithm:user.algorithm]) + inf( @"Found key in keychain for user: %@", user.userID ); + else + inf( @"No key found in keychain for user: %@", user.userID ); + + return key; } - (void)storeSavedKeyFor:(MPUserEntity *)user { @@ -230,28 +236,22 @@ static NSDictionary *createKeyQuery(MPUserEntity *user, BOOL newItem, MPKeyOrigi NSString *content; while (!(content = [site.algorithm storedPasswordForSite:(MPStoredSiteEntity *)site usingKey:recoverKey])) { // Failed to decrypt site with the current recoveryKey. Ask user for a new one to use. - __block NSString *masterPassword = nil; + NSString *masterPassword = nil; #ifdef PEARL_UIKIT - dispatch_group_t recoverPasswordGroup = dispatch_group_create(); - dispatch_group_enter( recoverPasswordGroup ); - [PearlAlert showAlertWithTitle:@"Enter Old Master Password" - message:PearlString( @"Your old master password is required to migrate the stored password for %@", - site.name ) - viewStyle:UIAlertViewStyleSecureTextInput - initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) { - @try { + masterPassword = PearlAwait( ^(void (^setResult)(id)) { + [PearlAlert showAlertWithTitle:@"Enter Old Master Password" + message:PearlString( + @"Your old master password is required to migrate the stored password for %@", + site.name ) + viewStyle:UIAlertViewStyleSecureTextInput + initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) { if (buttonIndex_ == [alert_ cancelButtonIndex]) - // Don't Migrate - return; - - masterPassword = [alert_ textFieldAtIndex:0].text; - } - @finally { - dispatch_group_leave( recoverPasswordGroup ); - } - } cancelTitle:@"Don't Migrate" otherTitles:@"Migrate", nil]; - dispatch_group_wait( recoverPasswordGroup, DISPATCH_TIME_FOREVER ); + setResult( nil ); + else + setResult( [alert_ textFieldAtIndex:0].text ); + } cancelTitle:@"Don't Migrate" otherTitles:@"Migrate", nil]; + } ); #endif if (!masterPassword) // Don't Migrate diff --git a/platform-darwin/Source/MPKey.h b/platform-darwin/Source/MPKey.h index bcdb08e3..b5182d80 100644 --- a/platform-darwin/Source/MPKey.h +++ b/platform-darwin/Source/MPKey.h @@ -28,12 +28,12 @@ typedef NS_ENUM( NSUInteger, MPKeyOrigin ) { @interface MPKey : NSObject -@property(nonatomic, readonly) NSString *fullName; @property(nonatomic, readonly) MPKeyOrigin origin; +@property(nonatomic, readonly, copy) NSString *fullName; - (instancetype)initForFullName:(NSString *)fullName withMasterPassword:(NSString *)masterPassword; -- (instancetype)initForFullName:(NSString *)fullName withKeyData:(NSData *)keyData - forAlgorithm:(id)algorithm keyOrigin:(MPKeyOrigin)origin; +- (instancetype)initForFullName:(NSString *)fullName withKeyResolver:(NSData *( ^ )(id))keyResolver + keyOrigin:(MPKeyOrigin)origin; - (NSData *)keyIDForAlgorithm:(id)algorithm; - (NSData *)keyDataForAlgorithm:(id)algorithm; diff --git a/platform-darwin/Source/MPKey.m b/platform-darwin/Source/MPKey.m index b482e5ec..c3d934be 100644 --- a/platform-darwin/Source/MPKey.m +++ b/platform-darwin/Source/MPKey.m @@ -19,9 +19,9 @@ @interface MPKey() -@property(nonatomic) NSString *fullName; @property(nonatomic) MPKeyOrigin origin; -@property(nonatomic) NSString *masterPassword; +@property(nonatomic, copy) NSString *fullName; +@property(nonatomic, copy) NSData *( ^keyResolver )(id); @end @@ -31,25 +31,22 @@ - (instancetype)initForFullName:(NSString *)fullName withMasterPassword:(NSString *)masterPassword { + return [self initForFullName:fullName withKeyResolver:^NSData *(id algorithm) { + return [algorithm keyDataForFullName:self.fullName withMasterPassword:masterPassword]; + } keyOrigin:MPKeyOriginMasterPassword]; +} + +- (instancetype)initForFullName:(NSString *)fullName withKeyResolver:(NSData *( ^ )(id))keyResolver + keyOrigin:(MPKeyOrigin)origin { + if (!(self = [super init])) return nil; _keyCache = [NSCache new]; - self.fullName = fullName; - self.origin = MPKeyOriginMasterPassword; - self.masterPassword = masterPassword; - - return self; -} - -- (instancetype)initForFullName:(NSString *)fullName withKeyData:(NSData *)keyData - forAlgorithm:(id)algorithm keyOrigin:(MPKeyOrigin)origin { - - if (!(self = [self initForFullName:fullName withMasterPassword:nil])) - return nil; self.origin = origin; - [_keyCache setObject:keyData forKey:algorithm]; + self.fullName = fullName; + self.keyResolver = keyResolver; return self; } @@ -61,15 +58,17 @@ - (NSData *)keyDataForAlgorithm:(id)algorithm { - NSData *keyData = [_keyCache objectForKey:algorithm]; - if (keyData) + @synchronized (self) { + NSData *keyData = [_keyCache objectForKey:algorithm]; + if (keyData) + return keyData; + + keyData = self.keyResolver( algorithm ); + if (keyData) + [_keyCache setObject:keyData forKey:algorithm]; + return keyData; - - keyData = [algorithm keyDataForFullName:self.fullName withMasterPassword:self.masterPassword]; - if (keyData) - [_keyCache setObject:keyData forKey:algorithm]; - - return keyData; + } } - (NSData *)keyDataForAlgorithm:(id)algorithm trimmedLength:(NSUInteger)subKeyLength { @@ -80,7 +79,7 @@ - (BOOL)isEqualToKey:(MPKey *)key { - return [self.fullName isEqualToString:key.fullName] && [self.masterPassword isEqualToString:self.masterPassword]; + return [[self keyIDForAlgorithm:MPAlgorithmDefault] isEqualToData:[key keyIDForAlgorithm:MPAlgorithmDefault]]; } - (BOOL)isEqual:(id)object { diff --git a/platform-darwin/Source/iOS/MPPasswordsViewController.m b/platform-darwin/Source/iOS/MPPasswordsViewController.m index 9a98524c..b332bb89 100644 --- a/platform-darwin/Source/iOS/MPPasswordsViewController.m +++ b/platform-darwin/Source/iOS/MPPasswordsViewController.m @@ -361,6 +361,7 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) { if (mainContext) PearlAddNotificationObserver( NSManagedObjectContextDidSaveNotification, mainContext, nil, ^(MPPasswordsViewController *self, NSNotification *note) { + // TODO: either move this into the app delegate or remove the duplicate signOutAnimated: call from the app delegate. if (![[MPiOSAppDelegate get] activeUserInContext:note.object]) [[MPiOSAppDelegate get] signOutAnimated:YES]; } ); diff --git a/platform-darwin/Source/iOS/MPiOSAppDelegate.m b/platform-darwin/Source/iOS/MPiOSAppDelegate.m index 1f010b26..92df73fc 100644 --- a/platform-darwin/Source/iOS/MPiOSAppDelegate.m +++ b/platform-darwin/Source/iOS/MPiOSAppDelegate.m @@ -19,7 +19,6 @@ #import "MPiOSAppDelegate.h" #import "MPAppDelegate_Key.h" #import "MPAppDelegate_Store.h" -#import "IASKSettingsReader.h" #import "MPStoreViewController.h" @interface MPiOSAppDelegate() @@ -199,57 +198,33 @@ PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:@"Importing"]; MPImportResult result = [self importSites:importedSitesString askImportPassword:^NSString *(NSString *userName) { - __block NSString *masterPassword = nil; - - dispatch_group_t importPasswordGroup = dispatch_group_create(); - dispatch_group_enter( importPasswordGroup ); - dispatch_async( dispatch_get_main_queue(), ^{ + return PearlAwait( ^(void (^setResult)(id)) { [PearlAlert showAlertWithTitle:@"Import File's Master Password" message:strf( @"%@'s export was done using a different master password.\n" @"Enter that master password to unlock the exported data.", userName ) viewStyle:UIAlertViewStyleSecureTextInput initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) { - @try { - if (buttonIndex_ == [alert_ cancelButtonIndex]) - return; - - masterPassword = [alert_ textFieldAtIndex:0].text; - } - @finally { - dispatch_group_leave( importPasswordGroup ); - } + if (buttonIndex_ == [alert_ cancelButtonIndex]) + setResult( nil ); + else + setResult( [alert_ textFieldAtIndex:0].text ); } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Unlock Import", nil]; } ); - dispatch_group_wait( importPasswordGroup, DISPATCH_TIME_FOREVER ); - - return masterPassword; } askUserPassword:^NSString *(NSString *userName, NSUInteger importCount, NSUInteger deleteCount) { - __block NSString *masterPassword = nil; - - dispatch_group_t userPasswordGroup = dispatch_group_create(); - dispatch_group_enter( userPasswordGroup ); - dispatch_async( dispatch_get_main_queue(), ^{ + return PearlAwait( (id)^(void (^setResult)(id)) { [PearlAlert showAlertWithTitle:strf( @"Master Password for\n%@", userName ) message:strf( @"Imports %lu sites, overwriting %lu.", (unsigned long)importCount, (unsigned long)deleteCount ) viewStyle:UIAlertViewStyleSecureTextInput initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) { - @try { - if (buttonIndex_ == [alert_ cancelButtonIndex]) - return; - - masterPassword = [alert_ textFieldAtIndex:0].text; - } - @finally { - dispatch_group_leave( userPasswordGroup ); - } + if (buttonIndex_ == [alert_ cancelButtonIndex]) + setResult( nil ); + else + setResult( [alert_ textFieldAtIndex:0].text ); } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Import", nil]; } ); - dispatch_group_wait( userPasswordGroup, DISPATCH_TIME_FOREVER ); - - return masterPassword; }]; switch (result) { diff --git a/platform-darwin/Source/iOS/Storyboard.storyboard b/platform-darwin/Source/iOS/Storyboard.storyboard index 71673169..5ada040b 100644 --- a/platform-darwin/Source/iOS/Storyboard.storyboard +++ b/platform-darwin/Source/iOS/Storyboard.storyboard @@ -328,7 +328,7 @@ - + @@ -3041,7 +3041,7 @@ invested: 3.7 work hours