diff --git a/External/UbiquityStoreManager b/External/UbiquityStoreManager index 2586f757..226619a4 160000 --- a/External/UbiquityStoreManager +++ b/External/UbiquityStoreManager @@ -1 +1 @@ -Subproject commit 2586f75779570ae43442ed52a82ac0acb55caa01 +Subproject commit 226619a45744dd4aefbbdb948d7e44ab3ecad341 diff --git a/MasterPassword/ObjC/MPAppDelegate_Store.m b/MasterPassword/ObjC/MPAppDelegate_Store.m index 9a73dade..6e5fcb7f 100644 --- a/MasterPassword/ObjC/MPAppDelegate_Store.m +++ b/MasterPassword/ObjC/MPAppDelegate_Store.m @@ -15,19 +15,22 @@ #define STORE_OPTIONS #endif +#define MPCloudContainerIdentifier @"HL3Q45LX9N.com.lyndir.lhunath.MasterPassword.shared" #define MPMigrationLevelLocalStoreKey @"MPMigrationLevelLocalStoreKey" -typedef enum { - MPMigrationLevelLocalStoreV13, - MPMigrationLevelLocalStoreV14, - MPMigrationLevelLocalStoreCurrent = MPMigrationLevelLocalStoreV14, -} MPMigrationLevelLocalStore; - #define MPMigrationLevelCloudStoreKey @"MPMigrationLevelCloudStoreKey" -typedef enum { - MPMigrationLevelCloudStoreV13, - MPMigrationLevelCloudStoreV14, - MPMigrationLevelCloudStoreCurrent = MPMigrationLevelCloudStoreV14, -} MPMigrationLevelCloudStore; + +typedef NS_ENUM(NSInteger, MPMigrationLevelLocalStore) { + MPMigrationLevelLocalStoreV1, + MPMigrationLevelLocalStoreV2, + MPMigrationLevelLocalStoreCurrent = MPMigrationLevelLocalStoreV2, +}; + +typedef NS_ENUM(NSInteger, MPMigrationLevelCloudStore) { + MPMigrationLevelCloudStoreV1, + MPMigrationLevelCloudStoreV2, + MPMigrationLevelCloudStoreV3, + MPMigrationLevelCloudStoreCurrent = MPMigrationLevelCloudStoreV3, +}; @implementation MPAppDelegate_Shared(Store) #if TARGET_OS_IPHONE @@ -35,7 +38,7 @@ typedef enum { PearlAssociatedObjectProperty(PearlAlert*, FixCloudContentAlert, fixCloudContentAlert); PearlAssociatedObjectProperty(PearlOverlay*, StoreLoading, storeLoading); #endif -PearlAssociatedObjectProperty(NSManagedObjectContext*, PrivateManagedObjectContext, privateManagedObjectContext); + PearlAssociatedObjectProperty(NSManagedObjectContext*, PrivateManagedObjectContext, privateManagedObjectContext); PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, mainManagedObjectContext); @@ -49,7 +52,8 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, if ([[NSThread currentThread] isMainThread]) return mainManagedObjectContext; - NSManagedObjectContext *threadManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType]; + NSManagedObjectContext + *threadManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType]; threadManagedObjectContext.parentContext = mainManagedObjectContext; return threadManagedObjectContext; @@ -104,7 +108,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, return storeManager; storeManager = [[UbiquityStoreManager alloc] initStoreNamed:nil withManagedObjectModel:nil localStoreURL:nil - containerIdentifier:@"HL3Q45LX9N.com.lyndir.lhunath.MasterPassword.shared" + containerIdentifier:MPCloudContainerIdentifier additionalStoreOptions:@{ STORE_OPTIONS } delegate:self]; @@ -132,40 +136,113 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, - (void)migrateStoreForManager:(UbiquityStoreManager *)manager isCloud:(BOOL)isCloudStore { - [self migrateLocalStoreForManager:manager]; + [self migrateLocalStore]; if (isCloudStore) - [self migrateCloudStoreForManager:manager]; + [self migrateCloudStore]; } -- (void)migrateLocalStoreForManager:(UbiquityStoreManager *)manager { +- (void)migrateLocalStore { - MPMigrationLevelLocalStore migrationLevel = (unsigned)[[NSUserDefaults standardUserDefaults] integerForKey:@"MPMigrationLevelLocalStore"]; + MPMigrationLevelLocalStore migrationLevel = (signed)[[NSUserDefaults standardUserDefaults] integerForKey:MPMigrationLevelLocalStoreKey]; if (migrationLevel >= MPMigrationLevelLocalStoreCurrent) - // Local store up-to-date. + // Local store up-to-date. return; + inf(@"Local store migration level: %d (current %d)", (signed)migrationLevel, (signed)MPMigrationLevelLocalStoreCurrent); + if (migrationLevel <= MPMigrationLevelLocalStoreV1) + [self migrateV1LocalStore]; + + [[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelLocalStoreCurrent forKey:MPMigrationLevelLocalStoreKey]; + inf(@"Successfully migrated old to new local store."); +} + +- (void)migrateCloudStore { + + MPMigrationLevelCloudStore migrationLevel = (signed)[[NSUserDefaults standardUserDefaults] integerForKey:MPMigrationLevelCloudStoreKey]; + if (migrationLevel >= MPMigrationLevelCloudStoreCurrent) + // Cloud store up-to-date. + return; + + inf(@"Cloud store migration level: %d (current %d)", (signed)migrationLevel, (signed)MPMigrationLevelCloudStoreCurrent); + if (migrationLevel <= MPMigrationLevelCloudStoreV1) + [self migrateV1CloudStore]; + else if (migrationLevel <= MPMigrationLevelCloudStoreV2) + [self migrateV2CloudStore]; + + [[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelCloudStoreCurrent forKey:MPMigrationLevelCloudStoreKey]; +} + +- (void)migrateV1CloudStore { + + // Migrate cloud enabled preference. + NSNumber *oldCloudEnabled = [[NSUserDefaults standardUserDefaults] objectForKey:@"iCloudEnabledKey"]; + if ([oldCloudEnabled boolValue]) + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:USMCloudEnabledKey]; + + // Migrate cloud store. + NSString *uuid = [[NSUserDefaults standardUserDefaults] stringForKey:@"LocalUUIDKey"]; + if (!uuid) { + inf(@"No V1 cloud store to migrate."); + return; + } + + inf(@"Migrating V1 cloud store: %@ -> %@", uuid, [self.storeManager valueForKey:@"storeUUID"]); + NSURL *cloudContainerURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:MPCloudContainerIdentifier]; + NSURL *oldCloudContentURL = [[cloudContainerURL + URLByAppendingPathComponent:@"Data" isDirectory:YES] + URLByAppendingPathComponent:uuid isDirectory:YES]; + NSURL *oldCloudStoreURL = [[[cloudContainerURL + URLByAppendingPathComponent:@"Database.nosync" isDirectory:YES] + URLByAppendingPathComponent:uuid isDirectory:NO] URLByAppendingPathExtension:@"sqlite"]; + + [self migrateFromCloudStore:oldCloudStoreURL cloudContent:oldCloudContentURL contentName:uuid]; +} + +- (void)migrateV2CloudStore { + + // Migrate cloud store. + NSString *uuid = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:@"USMStoreUUIDKey"]; + if (!uuid) { + inf(@"No V2 cloud store to migrate."); + return; + } + + inf(@"Migrating V2 cloud store: %@ -> %@", uuid, [self.storeManager valueForKey:@"storeUUID"]); + NSURL *cloudContainerURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:MPCloudContainerIdentifier]; + NSURL *oldCloudContentURL = [[cloudContainerURL + URLByAppendingPathComponent:@"CloudLogs" isDirectory:YES] + URLByAppendingPathComponent:uuid isDirectory:YES]; + NSURL *oldCloudStoreURL = [[[cloudContainerURL + URLByAppendingPathComponent:@"CloudStore.nosync" isDirectory:YES] + URLByAppendingPathComponent:uuid isDirectory:NO] URLByAppendingPathExtension:@"sqlite"]; + + [self migrateFromCloudStore:oldCloudStoreURL cloudContent:oldCloudContentURL contentName:uuid]; +} + +- (void)migrateV1LocalStore { + NSURL *applicationFilesDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; NSURL *oldLocalStoreURL = [[applicationFilesDirectory URLByAppendingPathComponent:@"MasterPassword" isDirectory:NO] URLByAppendingPathExtension:@"sqlite"]; - NSURL *newLocalStoreURL = [manager URLForLocalStore]; - if ([newLocalStoreURL isEqual:oldLocalStoreURL]) { - // Old store migration failed earlier and we set the old URL as the manager's local store. - return; - } if (![[NSFileManager defaultManager] fileExistsAtPath:oldLocalStoreURL.path isDirectory:NO]) { - // No local store to migrate. - [[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelLocalStoreCurrent forKey:MPMigrationLevelLocalStoreKey]; - return; - } - if ([[NSFileManager defaultManager] fileExistsAtPath:newLocalStoreURL.path isDirectory:NO]) { - wrn(@"Can't migrate old local store: A new local store already exists."); - [[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelLocalStoreCurrent forKey:MPMigrationLevelLocalStoreKey]; + inf(@"No V1 local store to migrate."); + return; + } + + inf(@"Migrating V1 local store"); + [self migrateFromLocalStore:oldLocalStoreURL]; +} + +- (void)migrateFromLocalStore:(NSURL *)oldLocalStoreURL { + + NSURL *newLocalStoreURL = [self.storeManager URLForLocalStore]; + if ([[NSFileManager defaultManager] fileExistsAtPath:newLocalStoreURL.path isDirectory:NO]) { + wrn(@"Can't migrate local store: A new local store already exists."); return; } - inf(@"Migrating local store..."); NSError *error = nil; NSDictionary *oldLocalStoreOptions = @{ STORE_OPTIONS @@ -179,78 +256,38 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, }; // Create the directory to hold the new local store. - if (![[NSFileManager defaultManager] createDirectoryAtPath:[manager URLForLocalStoreDirectory].path - withIntermediateDirectories:YES attributes:nil error:&error]) { - err(@"While creating directory for new local store: %@", error); - manager.localStoreURL = oldLocalStoreURL; - return; - } + if (![[NSFileManager defaultManager] createDirectoryAtPath:[self.storeManager URLForLocalStoreDirectory].path + withIntermediateDirectories:YES attributes:nil error:&error]) + err(@"While creating directory for new local store: %@", error); - if (![manager copyMigrateStore:oldLocalStoreURL withOptions:oldLocalStoreOptions - toStore:newLocalStoreURL withOptions:newLocalStoreOptions - error:nil cause:nil context:nil]) { - manager.localStoreURL = oldLocalStoreURL; + if (![self.storeManager copyMigrateStore:oldLocalStoreURL withOptions:oldLocalStoreOptions + toStore:newLocalStoreURL withOptions:newLocalStoreOptions + error:nil cause:nil context:nil]) return; - } - [[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelLocalStoreCurrent forKey:MPMigrationLevelLocalStoreKey]; - inf(@"Successfully migrated old to new local store."); + inf(@"Successfully migrated to new local store."); } -- (void)migrateCloudStoreForManager:(UbiquityStoreManager *)manager { +- (void)migrateFromCloudStore:(NSURL *)oldCloudStoreURL cloudContent:(NSURL *)oldCloudContentURL contentName:(NSString *)contentName { - MPMigrationLevelCloudStore migrationLevel = (unsigned)[[NSUserDefaults standardUserDefaults] integerForKey:@"MPMigrationLevelCloudStore"]; - if (migrationLevel >= MPMigrationLevelCloudStoreCurrent) - // Cloud store up-to-date. - return; - - // Migrate cloud enabled preference. - NSNumber *oldCloudEnabled = [[NSUserDefaults standardUserDefaults] objectForKey:@"iCloudEnabledKey"]; - if ([oldCloudEnabled boolValue]) { - [[NSUserDefaults standardUserDefaults] setBool:YES forKey:USMCloudEnabledKey]; - [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"iCloudEnabledKey"]; - } - - // Migrate cloud store. - NSString *uuid = [[NSUserDefaults standardUserDefaults] stringForKey:@"LocalUUIDKey"]; - if (!uuid) { - // No old cloud store to migrate. - [[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelCloudStoreCurrent forKey:MPMigrationLevelCloudStoreKey]; + if (![self.storeManager cloudSafeForSeeding]) { + inf(@"Can't migrate cloud store: A new cloud store already exists."); return; } - if (![manager cloudSafeForSeeding]) { - wrn(@"Can't migrate old cloud store: A new cloud store already exists."); - [[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelCloudStoreCurrent forKey:MPMigrationLevelCloudStoreKey]; - return; - } - - NSURL *cloudContainerURL = [[NSFileManager defaultManager] - URLForUbiquityContainerIdentifier:@"HL3Q45LX9N.com.lyndir.lhunath.MasterPassword.shared"]; - NSURL *newCloudStoreURL = [manager URLForCloudStore]; - NSURL *newCloudContentURL = [manager URLForCloudContent]; - NSURL *oldCloudContentURL = [[cloudContainerURL URLByAppendingPathComponent:@"Data" isDirectory:YES] - URLByAppendingPathComponent:uuid isDirectory:YES]; - NSURL *oldCloudStoreDirectoryURL = [cloudContainerURL URLByAppendingPathComponent:@"Database.nosync" isDirectory:YES]; - NSURL *oldCloudStoreURL = [[oldCloudStoreDirectoryURL URLByAppendingPathComponent:uuid isDirectory:NO] - URLByAppendingPathExtension:@"sqlite"]; - inf(@"Migrating cloud store: %@ -> %@", uuid, [manager valueForKey:@"storeUUID"]); + NSURL *newCloudStoreURL = [self.storeManager URLForCloudStore]; + NSURL *newCloudContentURL = [self.storeManager URLForCloudContent]; NSError *error = nil; NSDictionary *oldCloudStoreOptions = @{ STORE_OPTIONS - // This is here in an attempt to have iCloud recreate the old store file from - // the baseline and transaction logs from the iCloud account. - // In my tests however only the baseline was used to recreate the store which then ended up being empty. - NSPersistentStoreUbiquitousContentNameKey : uuid, + NSPersistentStoreUbiquitousContentNameKey : contentName, NSPersistentStoreUbiquitousContentURLKey : oldCloudContentURL, - // So instead, we'll just open up the old store as read-only, if it exists. - NSReadOnlyPersistentStoreOption : @YES, NSInferMappingModelAutomaticallyOption : @YES }; NSDictionary *newCloudStoreOptions = @{ STORE_OPTIONS - NSPersistentStoreUbiquitousContentNameKey : [manager valueForKey:@"contentName"], + NSPersistentStoreUbiquitousContentNameKey : [self.storeManager valueForKey:@"contentName"], NSPersistentStoreUbiquitousContentURLKey : newCloudContentURL, NSMigratePersistentStoresAutomaticallyOption : @YES, NSInferMappingModelAutomaticallyOption : @YES @@ -258,24 +295,25 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, // Create the directory to hold the new cloud store. // This is only necessary if we want to try to rebuild the old store. See comment above about how that failed. - if (![[NSFileManager defaultManager] createDirectoryAtPath:oldCloudStoreDirectoryURL.path - withIntermediateDirectories:YES attributes:nil error:&error]) { - err(@"While creating directory for old cloud store: %@", error); - return; - } - if (![[NSFileManager defaultManager] createDirectoryAtPath:[manager URLForCloudStoreDirectory].path - withIntermediateDirectories:YES attributes:nil error:&error]) { - err(@"While creating directory for new cloud store: %@", error); - return; - } + if (![[NSFileManager defaultManager] createDirectoryAtPath:[oldCloudStoreURL URLByDeletingLastPathComponent].path + withIntermediateDirectories:YES attributes:nil error:&error]) + err(@"While creating directory for old cloud store: %@", error); + if (![[NSFileManager defaultManager] createDirectoryAtPath:oldCloudContentURL.path + withIntermediateDirectories:YES attributes:nil error:&error]) + err(@"While creating directory for old cloud content: %@", error); + if (![[NSFileManager defaultManager] createDirectoryAtPath:[self.storeManager URLForCloudStoreDirectory].path + withIntermediateDirectories:YES attributes:nil error:&error]) + err(@"While creating directory for new cloud store: %@", error); + if (![[NSFileManager defaultManager] createDirectoryAtPath:[self.storeManager URLForCloudContent].path + withIntermediateDirectories:YES attributes:nil error:&error]) + err(@"While creating directory for new cloud content: %@", error); - if (![manager copyMigrateStore:oldCloudStoreURL withOptions:oldCloudStoreOptions - toStore:newCloudStoreURL withOptions:newCloudStoreOptions - error:nil cause:nil context:nil]) + if (![self.storeManager copyMigrateStore:oldCloudStoreURL withOptions:oldCloudStoreOptions + toStore:newCloudStoreURL withOptions:newCloudStoreOptions + error:nil cause:nil context:nil]) return; - [[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelCloudStoreCurrent forKey:MPMigrationLevelCloudStoreKey]; - inf(@"Successfully migrated old to new cloud store."); + inf(@"Successfully migrated to new cloud store."); } #pragma mark - UbiquityStoreManagerDelegate @@ -314,10 +352,25 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, } ); // Create our contexts. - NSManagedObjectContext *privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; + NSManagedObjectContext + *privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; [privateManagedObjectContext performBlockAndWait:^{ privateManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy; privateManagedObjectContext.persistentStoreCoordinator = coordinator; + +// dbg(@"==="); +// NSError *error; +// for (NSEntityDescription *entityDescription in [coordinator.managedObjectModel entities]) { +// dbg(@"Entities: %@", entityDescription.name); +// NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:entityDescription.name]; +// NSArray *entities = [privateManagedObjectContext executeFetchRequest:request error:&error]; +// if (!entities) +// err(@" - Error: %@", error); +// else +// for (id entity in entities) +// dbg(@" - %@", [entity debugDescription]); +// } +// dbg(@"==="); }]; NSManagedObjectContext *mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; diff --git a/MasterPassword/ObjC/Mac/MPMacAppDelegate.h b/MasterPassword/ObjC/Mac/MPMacAppDelegate.h index 54aa89be..6dcb8f77 100644 --- a/MasterPassword/ObjC/Mac/MPMacAppDelegate.h +++ b/MasterPassword/ObjC/Mac/MPMacAppDelegate.h @@ -25,9 +25,11 @@ @property(nonatomic, weak) IBOutlet NSMenuItem *dialogStyleRegular; @property(nonatomic, weak) IBOutlet NSMenuItem *dialogStyleHUD; +- (IBAction)showPasswordWindow; - (IBAction)activate:(id)sender; - (IBAction)togglePreference:(NSMenuItem *)sender; - (IBAction)newUser:(NSMenuItem *)sender; - (IBAction)lock:(id)sender; +- (IBAction)rebuildCloud:(id)sender; @end diff --git a/MasterPassword/ObjC/Mac/MPMacAppDelegate.m b/MasterPassword/ObjC/Mac/MPMacAppDelegate.m index fc0f4b54..8458787b 100644 --- a/MasterPassword/ObjC/Mac/MPMacAppDelegate.m +++ b/MasterPassword/ObjC/Mac/MPMacAppDelegate.m @@ -11,12 +11,6 @@ #import "MPAppDelegate_Store.h" #import -@interface MPMacAppDelegate() - -@property(nonatomic) BOOL wasRunning; - -@end - @implementation MPMacAppDelegate #pragma clang diagnostic push @@ -46,7 +40,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven // Check which hotkey this was. if (hotKeyID.signature == MPShowHotKey.signature && hotKeyID.id == MPShowHotKey.id) { - [((__bridge MPMacAppDelegate *)userData) activate:nil]; + [((__bridge MPMacAppDelegate *)userData) showPasswordWindow]; return noErr; } if (hotKeyID.signature == MPLockHotKey.signature && hotKeyID.id == MPLockHotKey.id) { @@ -92,15 +86,18 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven @"Then give iCloud some time to sync the new user to your Mac."; } + MPUserEntity *activeUser = self.activeUserForThread; for (MPUserEntity *user in users) { NSMenuItem *userItem = [[NSMenuItem alloc] initWithTitle:user.name action:@selector(selectUser:) keyEquivalent:@""]; [userItem setTarget:self]; [userItem setRepresentedObject:[user objectID]]; [[self.usersItem submenu] addItem:userItem]; - if ([user.name isEqualToString:[MPMacConfig get].usedUserName]) + if (!activeUser && [user.name isEqualToString:[MPMacConfig get].usedUserName]) [self selectUser:userItem]; } + + [self updateMenuItems]; } - (void)selectUser:(NSMenuItem *)item { @@ -192,6 +189,16 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven self.key = nil; } +- (IBAction)rebuildCloud:(id)sender { + + if ([[NSAlert alertWithMessageText:@"iCloud Truth Sync" defaultButton:@"Continue" + alternateButton:nil otherButton:@"Cancel" + informativeTextWithFormat:@"This action will force all your iCloud enabled devices to revert to this device's version of the truth." + @"\n\nThis is only necessary if you notice that your devices aren't syncing properly anymore. " + "Any data on other devices not available from here will be lost."] runModal] == NSAlertDefaultReturn) + [self.storeManager rebuildCloudContentFromCloudStoreOrLocalStore:NO]; +} + - (void)didUpdateConfigForKey:(SEL)configKey fromValue:(id)oldValue { [[NSNotificationCenter defaultCenter] @@ -347,20 +354,16 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven - (void)applicationDidBecomeActive:(NSNotification *)notification { - [self showPasswordWindow]; +// [self showPasswordWindow]; } -- (void)showPasswordWindow { +- (IBAction)showPasswordWindow { // Don't show window if we weren't already running (ie. if we haven't been activated before). - if (!self.wasRunning) - self.wasRunning = YES; - else { - if (!self.passwordWindow) - self.passwordWindow = [[MPPasswordWindowController alloc] initWithWindowNibName:@"MPPasswordWindowController"]; - - [self.passwordWindow showWindow:self]; - } + if (!self.passwordWindow) + self.passwordWindow = [[MPPasswordWindowController alloc] initWithWindowNibName:@"MPPasswordWindowController"]; + + [self.passwordWindow showWindow:self]; } - (void)applicationWillResignActive:(NSNotification *)notification { diff --git a/MasterPassword/ObjC/Mac/MPPasswordWindowController.m b/MasterPassword/ObjC/Mac/MPPasswordWindowController.m index 619be215..613498ce 100644 --- a/MasterPassword/ObjC/Mac/MPPasswordWindowController.m +++ b/MasterPassword/ObjC/Mac/MPPasswordWindowController.m @@ -53,6 +53,8 @@ // } forKeyPath:@"key" options:NSKeyValueObservingOptionInitial context:nil]; [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowDidBecomeKeyNotification object:self.window queue:nil usingBlock:^(NSNotification *note) { + if (![MPMacAppDelegate managedObjectContextForThreadIfReady]) + [self waitUntilStoreLoaded]; if (!self.inProgress) [self unlock]; [self.siteField selectText:self]; @@ -66,10 +68,17 @@ _activeElementOID = nil; [self.window close]; }]; + [[NSNotificationCenter defaultCenter] + addObserverForName:UbiquityManagedStoreDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) { + [self waitUntilStoreLoaded]; + }]; [super windowDidLoad]; } +- (void)waitUntilStoreLoaded { +} + - (void)unlock { NSManagedObjectContext *moc = [MPMacAppDelegate managedObjectContextForThreadIfReady]; @@ -323,12 +332,12 @@ - (void)trySiteWithAction:(BOOL)doAction { + NSString *siteName = [self.siteField stringValue]; [self.backgroundQueue addOperationWithBlock:^{ NSString *content = [[self activeElementForThread].content description]; if (!content) content = @""; - NSString *siteName = [self.siteField stringValue]; dbg(@"name: %@, action: %d", siteName, doAction); if (doAction) { if ([content length]) { diff --git a/MasterPassword/ObjC/Mac/MasterPassword-Mac.xcodeproj/project.pbxproj b/MasterPassword/ObjC/Mac/MasterPassword-Mac.xcodeproj/project.pbxproj index 39598e60..3146ea3d 100644 --- a/MasterPassword/ObjC/Mac/MasterPassword-Mac.xcodeproj/project.pbxproj +++ b/MasterPassword/ObjC/Mac/MasterPassword-Mac.xcodeproj/project.pbxproj @@ -27,6 +27,8 @@ DA3EF17B15A47744003ABF4E /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA3EF17A15A47744003ABF4E /* SenTestingKit.framework */; }; DA3EF17D15A47744003ABF4E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; }; DA4425CC1557BED40052177D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; }; + DA4C45F4173B57B700745CC5 /* NSURL+UbiquityStoreManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DA4C45F2173B57B700745CC5 /* NSURL+UbiquityStoreManager.h */; }; + DA4C45F5173B57B700745CC5 /* NSURL+UbiquityStoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4C45F3173B57B700745CC5 /* NSURL+UbiquityStoreManager.m */; }; DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; }; DA5E5C8817248AA1003798D8 /* crypto_aesctr.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5E5C7B17248AA1003798D8 /* crypto_aesctr.h */; }; DA5E5C8917248AA1003798D8 /* crypto_scrypt.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5E5C7C17248AA1003798D8 /* crypto_scrypt.h */; }; @@ -201,6 +203,8 @@ DA3EF17915A47744003ABF4E /* Tests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; DA3EF17A15A47744003ABF4E /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libUbiquityStoreManager.a; sourceTree = BUILT_PRODUCTS_DIR; }; + DA4C45F2173B57B700745CC5 /* NSURL+UbiquityStoreManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURL+UbiquityStoreManager.h"; sourceTree = ""; }; + DA4C45F3173B57B700745CC5 /* NSURL+UbiquityStoreManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURL+UbiquityStoreManager.m"; sourceTree = ""; }; DA5BFA44147E415C00F98B1E /* MasterPassword.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MasterPassword.app; sourceTree = BUILT_PRODUCTS_DIR; }; DA5BFA4A147E415C00F98B1E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; @@ -577,6 +581,8 @@ DACA22B61705DE7D002C6C22 /* UbiquityStoreManager */ = { isa = PBXGroup; children = ( + DA4C45F2173B57B700745CC5 /* NSURL+UbiquityStoreManager.h */, + DA4C45F3173B57B700745CC5 /* NSURL+UbiquityStoreManager.m */, DACA22BA1705DE7D002C6C22 /* UbiquityStoreManager.h */, DACA22B71705DE7D002C6C22 /* UbiquityStoreManager.m */, DACA22B81705DE7D002C6C22 /* NSError+UbiquityStoreManager.h */, @@ -800,6 +806,7 @@ files = ( DACA22BC1705DE7D002C6C22 /* NSError+UbiquityStoreManager.h in Headers */, DACA22BE1705DE7D002C6C22 /* UbiquityStoreManager.h in Headers */, + DA4C45F4173B57B700745CC5 /* NSURL+UbiquityStoreManager.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1116,6 +1123,7 @@ files = ( DACA22BB1705DE7D002C6C22 /* UbiquityStoreManager.m in Sources */, DACA22BD1705DE7D002C6C22 /* NSError+UbiquityStoreManager.m in Sources */, + DA4C45F5173B57B700745CC5 /* NSURL+UbiquityStoreManager.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MasterPassword/ObjC/Mac/MasterPassword-Mac.xcodeproj/xcshareddata/xcschemes/MasterPassword Mac (Development).xcscheme b/MasterPassword/ObjC/Mac/MasterPassword-Mac.xcodeproj/xcshareddata/xcschemes/MasterPassword Mac (Development).xcscheme index caa0b995..9c5719a9 100644 --- a/MasterPassword/ObjC/Mac/MasterPassword-Mac.xcodeproj/xcshareddata/xcschemes/MasterPassword Mac (Development).xcscheme +++ b/MasterPassword/ObjC/Mac/MasterPassword-Mac.xcodeproj/xcshareddata/xcschemes/MasterPassword Mac (Development).xcscheme @@ -48,6 +48,13 @@ ReferencedContainer = "container:MasterPassword-Mac.xcodeproj"> + + + + diff --git a/MasterPassword/ObjC/Mac/en.lproj/MainMenu.xib b/MasterPassword/ObjC/Mac/en.lproj/MainMenu.xib index 3382c1d5..591cf723 100644 --- a/MasterPassword/ObjC/Mac/en.lproj/MainMenu.xib +++ b/MasterPassword/ObjC/Mac/en.lproj/MainMenu.xib @@ -201,6 +201,41 @@ + + + Advanced + + 2147483647 + + + submenuAction: + + Advanced + + + + iCloud Truth Sync + + 2147483647 + + + + + + YES + Force this device's version of the truth upon all others. + + 2147483647 + + + + Force this device's version of the truth upon all others. + + + + + + YES @@ -288,14 +323,6 @@ 731 - - - activate: - - - - 736 - useICloudItem @@ -408,6 +435,22 @@ 774 + + + rebuildCloud: + + + + 780 + + + + showPasswordWindow + + + + 781 + @@ -503,6 +546,7 @@ + @@ -590,6 +634,33 @@ + + 776 + + + + + + + + 777 + + + + + + + + + 778 + + + + + 779 + + + @@ -628,14 +699,158 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin - 774 + 781 + + + + + MPAppDelegate_Shared + PearlAppDelegate + + IBProjectSource + ./Classes/MPAppDelegate_Shared.h + + + + MPMacAppDelegate + MPAppDelegate_Shared + + id + id + NSMenuItem + id + NSMenuItem + + + + activate: + id + + + lock: + id + + + newUser: + NSMenuItem + + + rebuildCloud: + id + + + togglePreference: + NSMenuItem + + + + NSMenuItem + NSMenuItem + NSMenuItem + NSMenuItem + NSMenuItem + NSMenuItem + NSMenuItem + NSMenu + NSMenuItem + NSMenuItem + + + + createUserItem + NSMenuItem + + + dialogStyleHUD + NSMenuItem + + + dialogStyleRegular + NSMenuItem + + + lockItem + NSMenuItem + + + rememberPasswordItem + NSMenuItem + + + savePasswordItem + NSMenuItem + + + showItem + NSMenuItem + + + statusMenu + NSMenu + + + useICloudItem + NSMenuItem + + + usersItem + NSMenuItem + + + + IBProjectSource + ./Classes/MPMacAppDelegate.h + + + + PearlAppDelegate + UIResponder + + UINavigationController + UIWindow + + + + navigationController + UINavigationController + + + window + UIWindow + + + + IBProjectSource + ./Classes/PearlAppDelegate.h + + + + UINavigationController + UIViewController + + IBProjectSource + ./Classes/UINavigationController.h + + + + UIWindow + UIView + + IBProjectSource + ./Classes/UIWindow.h + + + - 0 IBCocoaFramework diff --git a/MasterPassword/ObjC/iOS/MPMainViewController.m b/MasterPassword/ObjC/iOS/MPMainViewController.m index ca94e307..a3ddcc23 100644 --- a/MasterPassword/ObjC/iOS/MPMainViewController.m +++ b/MasterPassword/ObjC/iOS/MPMainViewController.m @@ -849,16 +849,16 @@ } ); } }]; + + MPCheckpoint( MPCheckpointUseType, @{ + @"type" : element.typeName, + @"version" : @(element.version) + } ); } [self.searchDisplayController setActive:NO animated:YES]; self.searchDisplayController.searchBar.text = element.name; - MPCheckpoint( MPCheckpointUseType, @{ - @"type" : element.typeName, - @"version" : @(element.version) - } ); - [self updateAnimated:YES]; } diff --git a/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard b/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard index 79f798df..f2e2ad39 100644 --- a/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard +++ b/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard @@ -1356,7 +1356,7 @@ L4m3P4sSw0rD -