From d7193f77532c7a1ed83c034904ffcce5f325f500 Mon Sep 17 00:00:00 2001 From: Maarten Billemont Date: Sat, 12 Aug 2017 22:26:48 -0400 Subject: [PATCH] Adapt macOS for new APIs. --- core/c/mpw-types.h | 8 +- platform-darwin/Source/MPAlgorithm.h | 4 +- platform-darwin/Source/MPAlgorithmV0.m | 41 +++++-- platform-darwin/Source/MPTypes.h | 13 ++- platform-darwin/Source/Mac/MPMacAppDelegate.m | 105 ++++++++---------- platform-darwin/Source/Mac/MPSiteModel.h | 4 +- platform-darwin/Source/Mac/MPSiteModel.m | 12 +- .../Source/Mac/MPSitesWindowController.m | 6 +- platform-darwin/Source/iOS/MPiOSAppDelegate.m | 8 +- 9 files changed, 105 insertions(+), 96 deletions(-) diff --git a/core/c/mpw-types.h b/core/c/mpw-types.h index 3bfe7238..45ff7c0e 100644 --- a/core/c/mpw-types.h +++ b/core/c/mpw-types.h @@ -23,11 +23,11 @@ #include #include -//#ifdef NS_ENUM -//#define enum(_type, _name) NS_ENUM(_type, _name) -//#else +#ifdef NS_ENUM +#define enum(_type, _name) NS_ENUM(_type, _name) +#else #define enum(_type, _name) _type _name; enum -//#endif +#endif //// Types. diff --git a/platform-darwin/Source/MPAlgorithm.h b/platform-darwin/Source/MPAlgorithm.h index b0f35d87..8b2c72f8 100644 --- a/platform-darwin/Source/MPAlgorithm.h +++ b/platform-darwin/Source/MPAlgorithm.h @@ -64,10 +64,10 @@ NSString *NSStringFromTimeToCrack(TimeToCrack timeToCrack); - (NSString *)mpwLoginForSiteNamed:(NSString *)name usingKey:(MPKey *)key; - (NSString *)mpwTemplateForSiteNamed:(NSString *)name ofType:(MPResultType)type - withCounter:(NSUInteger)counter usingKey:(MPKey *)key; + withCounter:(MPCounterValue)counter usingKey:(MPKey *)key; - (NSString *)mpwAnswerForSiteNamed:(NSString *)name onQuestion:(NSString *)question usingKey:(MPKey *)key; - (NSString *)mpwResultForSiteNamed:(NSString *)name ofType:(MPResultType)type parameter:(NSString *)parameter - withCounter:(NSUInteger)counter variant:(MPKeyPurpose)purpose context:(NSString *)context usingKey:(MPKey *)key; + withCounter:(MPCounterValue)counter variant:(MPKeyPurpose)purpose context:(NSString *)context usingKey:(MPKey *)key; - (BOOL)savePassword:(NSString *)clearPassword toSite:(MPSiteEntity *)site usingKey:(MPKey *)key; diff --git a/platform-darwin/Source/MPAlgorithmV0.m b/platform-darwin/Source/MPAlgorithmV0.m index b4bd6858..f70fb4ad 100644 --- a/platform-darwin/Source/MPAlgorithmV0.m +++ b/platform-darwin/Source/MPAlgorithmV0.m @@ -180,6 +180,9 @@ static NSOperationQueue *_mpwQueue = nil; case MPResultTypeStatefulDevice: return @"Device Private Password"; + + case MPResultTypeDeriveKey: + return @"Crypto Key"; } Throw( @"Type not supported: %lu", (long)type ); @@ -220,6 +223,9 @@ static NSOperationQueue *_mpwQueue = nil; case MPResultTypeStatefulDevice: return @"Device"; + + case MPResultTypeDeriveKey: + return @"Key"; } Throw( @"Type not supported: %lu", (long)type ); @@ -265,6 +271,9 @@ static NSOperationQueue *_mpwQueue = nil; case MPResultTypeStatefulDevice: return [MPStoredSiteEntity class]; + + case MPResultTypeDeriveKey: + break; } Throw( @"Type not supported: %lu", (long)type ); @@ -314,6 +323,8 @@ static NSOperationQueue *_mpwQueue = nil; return MPResultTypeStatefulDevice; case MPResultTypeStatefulDevice: return MPResultTypeTemplatePhrase; + case MPResultTypeDeriveKey: + break; } return [self defaultType]; @@ -330,12 +341,12 @@ static NSOperationQueue *_mpwQueue = nil; - (NSString *)mpwLoginForSiteNamed:(NSString *)name usingKey:(MPKey *)key { - return [self mpwResultForSiteNamed:name ofType:MPResultTypeTemplateName parameter:nil withCounter:1 + return [self mpwResultForSiteNamed:name ofType:MPResultTypeTemplateName parameter:nil withCounter:MPCounterValueInitial variant:MPKeyPurposeIdentification context:nil usingKey:key]; } - (NSString *)mpwTemplateForSiteNamed:(NSString *)name ofType:(MPResultType)type - withCounter:(NSUInteger)counter usingKey:(MPKey *)key { + withCounter:(MPCounterValue)counter usingKey:(MPKey *)key { return [self mpwResultForSiteNamed:name ofType:type parameter:nil withCounter:counter variant:MPKeyPurposeAuthentication context:nil usingKey:key]; @@ -343,17 +354,18 @@ static NSOperationQueue *_mpwQueue = nil; - (NSString *)mpwAnswerForSiteNamed:(NSString *)name onQuestion:(NSString *)question usingKey:(MPKey *)key { - return [self mpwResultForSiteNamed:name ofType:MPResultTypeTemplatePhrase parameter:nil withCounter:1 + return [self mpwResultForSiteNamed:name ofType:MPResultTypeTemplatePhrase parameter:nil withCounter:MPCounterValueInitial variant:MPKeyPurposeRecovery context:question usingKey:key]; } - (NSString *)mpwResultForSiteNamed:(NSString *)name ofType:(MPResultType)type parameter:(NSString *)parameter - withCounter:(NSUInteger)counter variant:(MPKeyPurpose)purpose context:(NSString *)context usingKey:(MPKey *)key { + withCounter:(MPCounterValue)counter variant:(MPKeyPurpose)purpose context:(NSString *)context + usingKey:(MPKey *)key { __block NSString *result = nil; [self mpw_perform:^{ char const *resultBytes = mpw_siteResult( [key keyForAlgorithm:self], - name.UTF8String, (uint32_t)counter, purpose, context.UTF8String, type, parameter.UTF8String, [self version] ); + name.UTF8String, counter, purpose, context.UTF8String, type, parameter.UTF8String, [self version] ); if (resultBytes) { result = [NSString stringWithCString:resultBytes encoding:NSUTF8StringEncoding]; mpw_free_string( resultBytes ); @@ -393,11 +405,11 @@ static NSOperationQueue *_mpwQueue = nil; [PearlKeyChain deleteItemForQuery:siteQuery]; else [PearlKeyChain addOrUpdateItemForQuery:siteQuery withAttributes:@{ - (__bridge id)kSecValueData : state, + (__bridge id)kSecValueData: state, #if TARGET_OS_IPHONE - (__bridge id)kSecAttrAccessible: - site.type & MPSiteFeatureDevicePrivate? (__bridge id)kSecAttrAccessibleWhenUnlockedThisDeviceOnly - : (__bridge id)kSecAttrAccessibleWhenUnlocked, + (__bridge id)kSecAttrAccessible: + site.type & MPSiteFeatureDevicePrivate? (__bridge id)kSecAttrAccessibleWhenUnlockedThisDeviceOnly + : (__bridge id)kSecAttrAccessibleWhenUnlocked, #endif }]; ((MPStoredSiteEntity *)site).contentObject = nil; @@ -490,7 +502,7 @@ static NSOperationQueue *_mpwQueue = nil; break; } - NSUInteger counter = ((MPGeneratedSiteEntity *)site).counter; + MPCounterValue counter = ((MPGeneratedSiteEntity *)site).counter; PearlNotMainQueue( ^{ resultBlock( [algorithm mpwTemplateForSiteNamed:name ofType:type withCounter:counter usingKey:key] ); @@ -517,7 +529,12 @@ static NSOperationQueue *_mpwQueue = nil; } ); break; } + + case MPResultTypeDeriveKey: + break; } + + Throw( @"Type not supported: %lu", (long)type ); } - (void)resolveAnswerForSite:(MPSiteEntity *)site usingKey:(MPKey *)key result:(void ( ^ )(NSString *result))resultBlock { @@ -563,8 +580,8 @@ static NSOperationQueue *_mpwQueue = nil; NSAssert( [[key keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." ); if (cipherText && cipherText.length && site.type & MPResultTypeClassStateful) { NSString *plainText = [self mpwResultForSiteNamed:site.name ofType:site.type parameter:cipherText - withCounter:MPCounterValueInitial variant:MPKeyPurposeAuthentication context:nil - usingKey:importKey]; + withCounter:MPCounterValueInitial variant:MPKeyPurposeAuthentication context:nil + usingKey:importKey]; if (plainText) [self savePassword:plainText toSite:site usingKey:key]; } diff --git a/platform-darwin/Source/MPTypes.h b/platform-darwin/Source/MPTypes.h index c3b268ba..9ca1be81 100644 --- a/platform-darwin/Source/MPTypes.h +++ b/platform-darwin/Source/MPTypes.h @@ -49,13 +49,16 @@ __END_DECLS } \ error; \ }) +#else +#define MPError(error_, message, ...) ({ \ + NSError *error = error_; \ + err( message @"%@%@", ##__VA_ARGS__, error? @"\n": @"", [error fullDescription]?: @"" ); \ + error; \ +}) +#endif + #define MPMakeError(message, ...) ({ \ MPError( [NSError errorWithDomain:MPErrorDomain code:0 userInfo:@{ \ NSLocalizedDescriptionKey: strf( message, ##__VA_ARGS__ ) \ }], @"" ); \ }) -#else -#define MPError(error_, message, ...) ({ \ - err( message @"%@%@", ##__VA_ARGS__, error_? @"\n": @"", [error_ fullDescription]?: @"" ); \ -}) -#endif diff --git a/platform-darwin/Source/Mac/MPMacAppDelegate.m b/platform-darwin/Source/Mac/MPMacAppDelegate.m index 04d73700..bce70854 100644 --- a/platform-darwin/Source/Mac/MPMacAppDelegate.m +++ b/platform-darwin/Source/Mac/MPMacAppDelegate.m @@ -269,23 +269,22 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven [openPanel close]; [[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler: - ^(NSData *importedSitesData, NSURLResponse *response, NSError *error) { - if (error) - MPError( error, @"While reading imported sites from %@.", url ); + ^(NSData *importedSitesData, NSURLResponse *response, NSError *urlError) { + if (urlError) + [[NSAlert alertWithError:MPError( urlError, @"While reading imported sites from %@.", url )] runModal]; if (!importedSitesData) return; NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding]; - MPImportResult result = [self importSites:importedSitesString askImportPassword:^NSString *(NSString *userName) { + [self importSites:importedSitesString askImportPassword:^NSString *(NSString *userName) { __block NSString *masterPassword = nil; PearlMainQueueWait( ^{ NSAlert *alert = [NSAlert new]; [alert addButtonWithTitle:@"Unlock"]; [alert addButtonWithTitle:@"Cancel"]; - alert.messageText = @"Import File's Master Password"; - alert.informativeText = strf( @"%@'s export was done using a different master password.\n" - @"Enter that master password to unlock the exported data.", userName ); + alert.messageText = strf( @"Importing Sites For\n%@", userName ); + alert.informativeText = @"Enter the master password used to create this export file."; alert.accessoryView = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )]; [alert layout]; if ([alert runModal] == NSAlertFirstButtonReturn) @@ -293,16 +292,15 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven } ); return masterPassword; - } askUserPassword:^NSString *(NSString *userName, NSUInteger importCount, NSUInteger deleteCount) { + } askUserPassword:^NSString *(NSString *userName) { __block NSString *masterPassword = nil; PearlMainQueueWait( ^{ NSAlert *alert = [NSAlert new]; [alert addButtonWithTitle:@"Import"]; [alert addButtonWithTitle:@"Cancel"]; - alert.messageText = strf( @"Master Password for\n%@", userName ); - alert.informativeText = strf( @"Imports %lu sites, overwriting %lu.", - (unsigned long)importCount, (unsigned long)deleteCount ); + alert.messageText = strf( @"Master Password For\n%@", userName ); + alert.informativeText = @"Enter the current master password for this user."; alert.accessoryView = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )]; [alert layout]; if ([alert runModal] == NSAlertFirstButtonReturn) @@ -310,37 +308,12 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven } ); return masterPassword; + } result:^(NSError *error) { + [self updateUsers]; + + if (error && !(error.domain == NSCocoaErrorDomain && error.code == NSUserCancelledError)) + [[NSAlert alertWithError:error] runModal]; }]; - - PearlMainQueue( ^{ - switch (result) { - case MPImportResultSuccess: { - [self updateUsers]; - - NSAlert *alert = [NSAlert new]; - alert.messageText = @"Successfully imported sites."; - [alert runModal]; - break; - } - case MPImportResultCancelled: - break; - case MPImportResultInternalError: - [[NSAlert alertWithError:[NSError errorWithDomain:MPErrorDomain code:0 userInfo:@{ - NSLocalizedDescriptionKey: @"Import failed because of an internal error." - }]] runModal]; - break; - case MPImportResultMalformedInput: - [[NSAlert alertWithError:[NSError errorWithDomain:MPErrorDomain code:0 userInfo:@{ - NSLocalizedDescriptionKey: @"The import doesn't look like a Master Password export." - }]] runModal]; - break; - case MPImportResultInvalidPassword: - [[NSAlert alertWithError:[NSError errorWithDomain:MPErrorDomain code:0 userInfo:@{ - NSLocalizedDescriptionKey: @"Incorrect master password for the import sites." - }]] runModal]; - break; - } - } ); }] resume]; } @@ -509,25 +482,43 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven if ([savePanel runModal] == NSFileHandlingPanelCancelButton) return; - NSError *coordinateError = nil; - NSString *exportedSites = [self exportSitesRevealPasswords:revealPasswords]; - [[[NSFileCoordinator alloc] initWithFilePresenter:nil] coordinateWritingItemAtURL:savePanel.URL options:0 - error:&coordinateError byAccessor: - ^(NSURL *newURL) { - NSError *writeError = nil; - if (![exportedSites writeToURL:newURL atomically:NO encoding:NSUTF8StringEncoding error:&writeError]) - MPError( writeError, @"Could not write to the export file." ); + [self exportSitesRevealPasswords:revealPasswords + askExportPassword:^NSString *(NSString *userName) { + return PearlMainQueueAwait( ^id { + NSAlert *alert = [NSAlert new]; + [alert addButtonWithTitle:@"Import"]; + [alert addButtonWithTitle:@"Cancel"]; + alert.messageText = strf( @"Master Password For\n%@", userName ); + alert.informativeText = @"Enter the current master password for this user."; + alert.accessoryView = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )]; + [alert layout]; + if ([alert runModal] == NSAlertFirstButtonReturn) + return ((NSTextField *)alert.accessoryView).stringValue; + else + return nil; + } ); + } result:^(NSString *mpsites, NSError *error) { + if (!mpsites || error) { + PearlMainQueue( ^{ + [[NSAlert alertWithError:MPError( error, @"Failed to export mpsites." )] runModal]; + } ); + return; + } + NSError *coordinateError = nil; + [[[NSFileCoordinator alloc] initWithFilePresenter:nil] + coordinateWritingItemAtURL:savePanel.URL options:0 error:&coordinateError byAccessor:^(NSURL *newURL) { + NSError *writeError = nil; + if (![mpsites writeToURL:newURL atomically:NO encoding:NSUTF8StringEncoding error:&writeError]) PearlMainQueue( ^{ - [[NSAlert alertWithError:writeError] runModal]; + [[NSAlert alertWithError:MPError( writeError, @"Could not write to the export file." )] runModal]; } ); - }]; - if (coordinateError) { - MPError( coordinateError, @"Write access to the export file could not be obtained." ); - PearlMainQueue( ^{ - [[NSAlert alertWithError:coordinateError] runModal]; - } ); - } + }]; + if (coordinateError) + PearlMainQueue( ^{ + [[NSAlert alertWithError:MPError( coordinateError, @"Could not gain access to the export file." )] runModal]; + } ); + }]; } - (void)updateUsers { diff --git a/platform-darwin/Source/Mac/MPSiteModel.h b/platform-darwin/Source/Mac/MPSiteModel.h index fabe3794..429cc090 100644 --- a/platform-darwin/Source/Mac/MPSiteModel.h +++ b/platform-darwin/Source/Mac/MPSiteModel.h @@ -27,7 +27,7 @@ @property(nonatomic) NSString *name; @property(nonatomic) NSAttributedString *displayedName; -@property(nonatomic) MPSiteType type; +@property(nonatomic) MPResultType type; @property(nonatomic) NSString *typeName; @property(nonatomic) NSString *content; @property(nonatomic) NSString *displayedContent; @@ -36,7 +36,7 @@ @property(nonatomic) NSString *loginName; @property(nonatomic) BOOL loginGenerated; @property(nonatomic) NSNumber *uses; -@property(nonatomic) NSUInteger counter; +@property(nonatomic) MPCounterValue counter; @property(nonatomic) NSDate *lastUsed; @property(nonatomic) id algorithm; @property(nonatomic) MPAlgorithmVersion algorithmVersion; diff --git a/platform-darwin/Source/Mac/MPSiteModel.m b/platform-darwin/Source/Mac/MPSiteModel.m index 69ac54df..73080cda 100644 --- a/platform-darwin/Source/Mac/MPSiteModel.m +++ b/platform-darwin/Source/Mac/MPSiteModel.m @@ -81,7 +81,7 @@ self.type = entity.type; self.typeName = entity.typeName; self.uses = entity.uses_; - self.counter = [entity isKindOfClass:[MPGeneratedSiteEntity class]]? [(MPGeneratedSiteEntity *)entity counter]: 0; + self.counter = [entity isKindOfClass:[MPGeneratedSiteEntity class]]? [(MPGeneratedSiteEntity *)entity counter]: MPCounterValueInitial; self.loginGenerated = entity.loginGenerated; // Find all password types and the index of the current type amongst them. @@ -104,7 +104,7 @@ self.type = user.defaultType; self.typeName = [self.algorithm nameOfType:self.type]; self.uses = @0; - self.counter = 1; + self.counter = MPCounterValueDefault; // Find all password types and the index of the current type amongst them. [self updateContent]; @@ -116,14 +116,14 @@ return nil; NSError *error; - MPSiteEntity *entity = (MPSiteEntity *)[moc existingObjectWithID:self.entityOID error:&error]; + MPSiteEntity *entity = [moc existingObjectWithID:self.entityOID error:&error]; if (!entity) MPError( error, @"Couldn't retrieve active site." ); return entity; } -- (void)setCounter:(NSUInteger)counter { +- (void)setCounter:(MPCounterValue)counter { if (self.counter == counter) return; @@ -210,12 +210,12 @@ - (BOOL)generated { - return self.type & MPSiteTypeClassGenerated; + return self.type & MPResultTypeClassTemplate; } - (BOOL)stored { - return self.type & MPSiteTypeClassStored; + return self.type & MPResultTypeClassStateful; } - (BOOL)transient { diff --git a/platform-darwin/Source/Mac/MPSitesWindowController.m b/platform-darwin/Source/Mac/MPSitesWindowController.m index 590446db..69f82316 100644 --- a/platform-darwin/Source/Mac/MPSitesWindowController.m +++ b/platform-darwin/Source/Mac/MPSitesWindowController.m @@ -373,9 +373,9 @@ NSArray *types = [site.algorithm allTypes]; [self.passwordTypesMatrix renewRows:(NSInteger)[types count] columns:1]; for (NSUInteger t = 0; t < [types count]; ++t) { - MPSiteType type = (MPSiteType)[types[t] unsignedIntegerValue]; + MPResultType type = (MPResultType)[types[t] unsignedIntegerValue]; NSString *title = [site.algorithm nameOfType:type]; - if (type & MPSiteTypeClassGenerated) + if (type & MPResultTypeClassTemplate) title = strf( @"%@ – %@", [site.algorithm mpwTemplateForSiteNamed:site.name ofType:type withCounter:site.counter usingKey:[MPMacAppDelegate get].key], title ); @@ -397,7 +397,7 @@ switch (returnCode) { case NSAlertFirstButtonReturn: { // "Save" button. - MPSiteType type = (MPSiteType)[self.passwordTypesMatrix.selectedCell tag]; + MPResultType type = (MPResultType)[self.passwordTypesMatrix.selectedCell tag]; [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { MPSiteEntity *entity = [[MPMacAppDelegate get] changeSite:[self.selectedSite entityInContext:context] saveInContext:context toType:type]; diff --git a/platform-darwin/Source/iOS/MPiOSAppDelegate.m b/platform-darwin/Source/iOS/MPiOSAppDelegate.m index 8b179dff..057e5267 100644 --- a/platform-darwin/Source/iOS/MPiOSAppDelegate.m +++ b/platform-darwin/Source/iOS/MPiOSAppDelegate.m @@ -436,17 +436,15 @@ [self exportSitesRevealPasswords:revealPasswords askExportPassword:^NSString *(NSString *userName) { 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 ) + [PearlAlert showAlertWithTitle:strf( @"Master Password For:\n%@", userName ) + message:@"Enter the user's master password to create an export file." viewStyle:UIAlertViewStyleSecureTextInput initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) { if (buttonIndex_ == [alert_ cancelButtonIndex]) setResult( nil ); else setResult( [alert_ textFieldAtIndex:0].text ); - } - cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Unlock Import", nil]; + } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Export", nil]; } ); } result:^(NSString *mpsites, NSError *error) { if (!mpsites || error) {