From a383d0eee7359736e91fb9f66369ed3199872b04 Mon Sep 17 00:00:00 2001 From: Maarten Billemont Date: Thu, 5 Mar 2015 17:28:04 -0500 Subject: [PATCH] Make new site creation on Mac same as iOS. [FIXED] Unable to create a site that is a substring of an existing site. --- MasterPassword/C/mpw-util.c | 40 +++--- .../ObjC/Mac/MPPasswordWindowController.m | 44 ++++--- MasterPassword/ObjC/Mac/MPSiteModel.h | 6 +- MasterPassword/ObjC/Mac/MPSiteModel.m | 114 +++++++++++++----- 4 files changed, 139 insertions(+), 65 deletions(-) diff --git a/MasterPassword/C/mpw-util.c b/MasterPassword/C/mpw-util.c index b50ae37b..347afe70 100644 --- a/MasterPassword/C/mpw-util.c +++ b/MasterPassword/C/mpw-util.c @@ -80,7 +80,7 @@ uint8_t const *mpw_scrypt(const size_t keySize, const char *secret, const uint8_ uint8_t const *mpw_hmac_sha256(const uint8_t *key, const size_t keySize, const uint8_t *salt, const size_t saltSize) { - uint8_t *const buffer = malloc(32); + uint8_t *const buffer = malloc( 32 ); if (!buffer) return NULL; @@ -96,24 +96,29 @@ const char *mpw_idForBuf(const void *buf, size_t length) { return mpw_hex( hash, 32 ); } -static char **mpw_hex_buf = NULL; -static unsigned int mpw_hex_buf_i = 0; +//static char **mpw_hex_buf = NULL; +//static unsigned int mpw_hex_buf_i = 0; + const char *mpw_hex(const void *buf, size_t length) { - if (!mpw_hex_buf) { - mpw_hex_buf = malloc( 10 * sizeof( char* ) ); - for (uint8_t i = 0; i < 10; ++i) - mpw_hex_buf[i] = NULL; - } - mpw_hex_buf_i = (mpw_hex_buf_i + 1) % 10; + // FIXME +// if (!mpw_hex_buf) { +// mpw_hex_buf = malloc( 10 * sizeof( char * ) ); +// for (uint8_t i = 0; i < 10; ++i) +// mpw_hex_buf[i] = NULL; +// } +// mpw_hex_buf_i = (mpw_hex_buf_i + 1) % 10; +// +// mpw_hex_buf[mpw_hex_buf_i] = realloc( mpw_hex_buf[mpw_hex_buf_i], length * 2 + 1 ); +// for (size_t kH = 0; kH < length; kH++) +// sprintf( &(mpw_hex_buf[mpw_hex_buf_i][kH * 2]), "%02X", ((const uint8_t *)buf)[kH] ); - mpw_hex_buf[mpw_hex_buf_i] = realloc( mpw_hex_buf[mpw_hex_buf_i], length * 2 + 1 ); - for (size_t kH = 0; kH < length; kH++) - sprintf( &(mpw_hex_buf[mpw_hex_buf_i][kH * 2]), "%02X", ((const uint8_t *)buf)[kH] ); - - return mpw_hex_buf[mpw_hex_buf_i]; +// return mpw_hex_buf[mpw_hex_buf_i]; + return NULL; } + const char *mpw_hex_l(uint32_t number) { + return mpw_hex( &number, sizeof( number ) ); } @@ -144,7 +149,8 @@ const char *mpw_identicon(const char *fullName, const char *masterPassword) { const char *accessory[] = { "◈", "◎", "◐", "◑", "◒", "◓", "☀", "☁", "☂", "☃", "☄", "★", "☆", "☎", "☏", "⎈", "⌂", "☘", "☢", "☣", "☕", "⌚", "⌛", "⏰", "⚡", "⛄", "⛅", "☔", "♔", "♕", "♖", "♗", "♘", "♙", "♚", "♛", "♜", "♝", "♞", "♟", - "♨", "♩", "♪", "♫", "⚐", "⚑", "⚔", "⚖", "⚙", "⚠", "⌘", "⏎", "✄", "✆", "✈", "✉", "✌" }; + "♨", "♩", "♪", "♫", "⚐", "⚑", "⚔", "⚖", "⚙", "⚠", "⌘", "⏎", "✄", "✆", "✈", "✉", "✌" + }; uint8_t identiconSeed[32]; HMAC_SHA256_Buf( masterPassword, strlen( masterPassword ), fullName, strlen( fullName ), identiconSeed ); @@ -206,8 +212,8 @@ const size_t mpw_charlen(const char *utf8String) { size_t charlen = 0; char *remainingString = (char *)utf8String; - for (int charByteSize; (charByteSize = mpw_charByteSize( *remainingString )); remainingString += charByteSize) + for (int charByteSize; (charByteSize = mpw_charByteSize( (unsigned char)*remainingString )); remainingString += charByteSize) ++charlen; - return charlen; + return charlen; } diff --git a/MasterPassword/ObjC/Mac/MPPasswordWindowController.m b/MasterPassword/ObjC/Mac/MPPasswordWindowController.m index ae733511..3fd217c9 100644 --- a/MasterPassword/ObjC/Mac/MPPasswordWindowController.m +++ b/MasterPassword/ObjC/Mac/MPPasswordWindowController.m @@ -463,26 +463,26 @@ - (void)useSite { MPSiteModel *selectedSite = [self selectedSite]; - if (selectedSite) { - // Performing action while content is available. Copy it. - [self copyContent:selectedSite.content]; + if (!selectedSite) + return; - [self fadeOut]; + if (selectedSite.transient) { + [self createNewSite:selectedSite.name]; + return; + } - NSUserNotification *notification = [NSUserNotification new]; - notification.title = @"Password Copied"; - if (selectedSite.loginName.length) - notification.subtitle = strf( @"%@ at %@", selectedSite.loginName, selectedSite.name ); - else - notification.subtitle = selectedSite.name; - [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification]; - } - else { - NSString *siteName = [self.siteField stringValue]; - if ([siteName length]) - // Performing action without content but a site name is written. - [self createNewSite:siteName]; - } + // Performing action while content is available. Copy it. + [self copyContent:selectedSite.content]; + + [self fadeOut]; + + NSUserNotification *notification = [NSUserNotification new]; + notification.title = @"Password Copied"; + if (selectedSite.loginName.length) + notification.subtitle = strf( @"%@ at %@", selectedSite.loginName, selectedSite.name ); + else + notification.subtitle = selectedSite.name; + [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification]; } - (void)updateUser { @@ -549,9 +549,15 @@ return; } + BOOL exact = NO; NSMutableArray *newSites = [NSMutableArray arrayWithCapacity:[siteResults count]]; - for (MPSiteEntity *site in siteResults) + for (MPSiteEntity *site in siteResults) { [newSites addObject:[[MPSiteModel alloc] initWithEntity:site fuzzyGroups:fuzzyGroups]]; + exact |= [site.name isEqualToString:queryString]; + } + if (!exact && [queryString length]) + [newSites addObject:[[MPSiteModel alloc] initWithName:queryString]]; + dbg( @"newSites: %@", newSites ); self.sites = newSites; }]; } diff --git a/MasterPassword/ObjC/Mac/MPSiteModel.h b/MasterPassword/ObjC/Mac/MPSiteModel.h index e052fdbc..2581dc19 100644 --- a/MasterPassword/ObjC/Mac/MPSiteModel.h +++ b/MasterPassword/ObjC/Mac/MPSiteModel.h @@ -35,10 +35,12 @@ @property (nonatomic) NSUInteger counter; @property (nonatomic) NSDate *lastUsed; @property (nonatomic) id algorithm; -@property (nonatomic) BOOL generated; -@property (nonatomic) BOOL stored; +@property (nonatomic, readonly) BOOL generated; +@property (nonatomic, readonly) BOOL stored; +@property (nonatomic, readonly) BOOL transient; - (instancetype)initWithEntity:(MPSiteEntity *)entity fuzzyGroups:(NSArray *)fuzzyGroups; +- (instancetype)initWithName:(NSString *)siteName; - (MPSiteEntity *)entityInContext:(NSManagedObjectContext *)moc; - (void)updateContent; diff --git a/MasterPassword/ObjC/Mac/MPSiteModel.m b/MasterPassword/ObjC/Mac/MPSiteModel.m index c3e71205..56c7e6df 100644 --- a/MasterPassword/ObjC/Mac/MPSiteModel.m +++ b/MasterPassword/ObjC/Mac/MPSiteModel.m @@ -28,7 +28,7 @@ BOOL _initialized; } -- (id)initWithEntity:(MPSiteEntity *)entity fuzzyGroups:(NSArray *)fuzzyGroups { +- (instancetype)initWithEntity:(MPSiteEntity *)entity fuzzyGroups:(NSArray *)fuzzyGroups { if (!(self = [super init])) return nil; @@ -39,6 +39,17 @@ return self; } +- (instancetype)initWithName:(NSString *)siteName { + + if (!(self = [super init])) + return nil; + + [self setTransientSiteName:siteName]; + _initialized = YES; + + return self; +} + - (void)setEntity:(MPSiteEntity *)entity fuzzyGroups:(NSArray *)fuzzyGroups { if ([_entityOID isEqual:entity.objectID]) @@ -59,7 +70,7 @@ NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new]; paragraphStyle.alignment = NSCenterTextAlignment; [attributedSiteName addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange( 0, [siteName length] )]; - + self.displayedName = attributedSiteName; self.name = siteName; self.algorithm = entity.algorithm; @@ -73,6 +84,28 @@ [self updateContent:entity]; } +- (void)setTransientSiteName:(NSString *)siteName { + + _entityOID = nil; + + NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new]; + paragraphStyle.alignment = NSCenterTextAlignment; + self.displayedName = stra( siteName, @{ + NSBackgroundColorAttributeName : [NSColor alternateSelectedControlColor], + NSParagraphStyleAttributeName : paragraphStyle, + } ); + self.name = siteName; + self.algorithm = MPAlgorithmDefault; + self.lastUsed = nil; + self.type = [MPAppDelegate_Shared get].activeUserForMainThread.defaultType; + self.typeName = [self.algorithm nameOfType:self.type]; + self.uses = @0; + self.counter = 1; + + // Find all password types and the index of the current type amongst them. + [self updateContent]; +} + - (MPSiteEntity *)entityInContext:(NSManagedObjectContext *)moc { if (!_entityOID) @@ -96,15 +129,18 @@ // This wasn't a change to the entity. return; - [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { - MPSiteEntity *entity = [self entityInContext:context]; - if ([entity isKindOfClass:[MPGeneratedSiteEntity class]]) { - ((MPGeneratedSiteEntity *)entity).counter = counter; - [context saveToStore]; + if (_entityOID) + [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { + MPSiteEntity *entity = [self entityInContext:context]; + if ([entity isKindOfClass:[MPGeneratedSiteEntity class]]) { + ((MPGeneratedSiteEntity *)entity).counter = counter; + [context saveToStore]; - [self updateContent:entity]; - } - }]; + [self updateContent:entity]; + } + }]; + else + [self updateContent]; } - (BOOL)generated { @@ -117,36 +153,60 @@ return self.type & MPSiteTypeClassStored; } +- (BOOL)transient { + + return _entityOID == nil; +} + - (void)updateContent { - [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { - [self updateContent:[MPSiteEntity existingObjectWithID:_entityOID inContext:context]]; - }]; + if (_entityOID) + [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { + [self updateContent:[MPSiteEntity existingObjectWithID:_entityOID inContext:context]]; + }]; + else + PearlNotMainQueue( ^{ + NSString *password = [self.algorithm generatePasswordForSiteNamed:self.name ofType:self.type withCounter:self.counter + usingKey:[MPAppDelegate_Shared get].key]; + NSString *loginName = [self.algorithm generateLoginForSiteNamed:self.name usingKey:[MPAppDelegate_Shared get].key]; + [self updatePasswordWithResult:password]; + [self updateLoginNameWithResult:loginName]; + } ); } - (void)updateContent:(MPSiteEntity *)entity { + [entity resolvePasswordUsingKey:[MPAppDelegate_Shared get].key result:^(NSString *result) { + [self updatePasswordWithResult:result]; + }]; + [entity resolveLoginUsingKey:[MPAppDelegate_Shared get].key result:^(NSString *result) { + [self updateLoginNameWithResult:result]; + }]; +} + +- (void)updatePasswordWithResult:(NSString *)result { + static NSRegularExpression *re_anyChar; static dispatch_once_t once = 0; dispatch_once( &once, ^{ re_anyChar = [NSRegularExpression regularExpressionWithPattern:@"." options:0 error:nil]; } ); - [entity resolvePasswordUsingKey:[MPAppDelegate_Shared get].key result:^(NSString *result) { - NSString *displayResult = result; - if ([[MPConfig get].hidePasswords boolValue] && !([NSEvent modifierFlags] & NSAlternateKeyMask)) - displayResult = [displayResult stringByReplacingMatchesOfExpression:re_anyChar withTemplate:@"●"]; + NSString *displayResult = result; + if ([[MPConfig get].hidePasswords boolValue] && !([NSEvent modifierFlags] & NSAlternateKeyMask)) + displayResult = [displayResult stringByReplacingMatchesOfExpression:re_anyChar withTemplate:@"●"]; - PearlMainQueue( ^{ - self.content = result; - self.displayedContent = displayResult; - } ); - }]; - [entity resolveLoginUsingKey:[MPAppDelegate_Shared get].key result:^(NSString *result) { - PearlMainQueue( ^{ - self.loginName = result; - } ); - }]; + PearlMainQueue( ^{ + self.content = result; + self.displayedContent = displayResult; + } ); +} + +- (void)updateLoginNameWithResult:(NSString *)loginName { + + PearlMainQueue( ^{ + self.loginName = loginName; + } ); } @end