From ab15694d9ab479df0b9556d403bef80857aff7cc Mon Sep 17 00:00:00 2001 From: Maarten Billemont Date: Thu, 2 May 2013 11:19:34 -0400 Subject: [PATCH] Safer migration, boolean description fix. [ADDED] Safer store migration: don't delete the old store, allowing the client to downgrade. [ADDED] Log checkpoints and send to TestFlight too. [FIXED] Describe booleans as YES/NO, not 1/0. --- External/Pearl | 2 +- MasterPassword/ObjC/MPAppDelegate_Store.m | 62 +++++++++++++--------- MasterPassword/ObjC/MPTypes.h | 6 ++- MasterPassword/ObjC/iOS/MPiOSAppDelegate.m | 31 ++++++----- 4 files changed, 61 insertions(+), 40 deletions(-) diff --git a/External/Pearl b/External/Pearl index b889e631..720acb2e 160000 --- a/External/Pearl +++ b/External/Pearl @@ -1 +1 @@ -Subproject commit b889e6312d5ecd9d2e45eb1402cadc6e27ed84c4 +Subproject commit 720acb2e6583a2ed9efbbe28ab53681a19070a42 diff --git a/MasterPassword/ObjC/MPAppDelegate_Store.m b/MasterPassword/ObjC/MPAppDelegate_Store.m index f41730bd..1ceffd40 100644 --- a/MasterPassword/ObjC/MPAppDelegate_Store.m +++ b/MasterPassword/ObjC/MPAppDelegate_Store.m @@ -15,6 +15,20 @@ #define STORE_OPTIONS #endif +#define MPMigrationLevelLocalStoreKey @"MPMigrationLevelLocalStoreKey" +typedef enum { + MPMigrationLevelLocalStoreV13, + MPMigrationLevelLocalStoreV14, + MPMigrationLevelLocalStoreCurrent = MPMigrationLevelLocalStoreV14, +} MPMigrationLevelLocalStore; + +#define MPMigrationLevelCloudStoreKey @"MPMigrationLevelCloudStoreKey" +typedef enum { + MPMigrationLevelCloudStoreV13, + MPMigrationLevelCloudStoreV14, + MPMigrationLevelCloudStoreCurrent = MPMigrationLevelCloudStoreV14, +} MPMigrationLevelCloudStore; + @implementation MPAppDelegate_Shared(Store) #if TARGET_OS_IPHONE PearlAssociatedObjectProperty(PearlAlert*, HandleCloudContentAlert, handleCloudContentAlert); @@ -98,18 +112,18 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillTerminateNotification object:[UIApplication sharedApplication] queue:nil usingBlock:^(NSNotification *note) { - [self saveContexts]; + [[self mainManagedObjectContext] saveToStore]; }]; [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:[UIApplication sharedApplication] queue:nil usingBlock:^(NSNotification *note) { - [self saveContexts]; + [[self mainManagedObjectContext] saveToStore]; }]; #else [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationWillTerminateNotification object:[NSApplication sharedApplication] queue:nil usingBlock:^(NSNotification *note) { - [self saveContexts]; + [[self mainManagedObjectContext] saveToStore]; }]; #endif @@ -126,6 +140,11 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, - (void)migrateLocalStoreForManager:(UbiquityStoreManager *)manager { + MPMigrationLevelLocalStore migrationLevel = [[NSUserDefaults standardUserDefaults] integerForKey:@"MPMigrationLevelLocalStore"]; + if (migrationLevel >= MPMigrationLevelLocalStoreCurrent) + // Local store up-to-date. + return; + NSURL *applicationFilesDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; NSURL *oldLocalStoreURL = [[applicationFilesDirectory @@ -137,10 +156,12 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, } 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]; return; } @@ -172,11 +193,17 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, return; } + [[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelLocalStoreCurrent forKey:MPMigrationLevelLocalStoreKey]; inf(@"Successfully migrated old to new local store."); } - (void)migrateCloudStoreForManager:(UbiquityStoreManager *)manager { + MPMigrationLevelCloudStore migrationLevel = [[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]) { @@ -186,12 +213,15 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, // Migrate cloud store. NSString *uuid = [[NSUserDefaults standardUserDefaults] stringForKey:@"LocalUUIDKey"]; - if (!uuid) - // No old cloud store to migrate. + if (!uuid) { + // No old cloud store to migrate. + [[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelCloudStoreCurrent forKey:MPMigrationLevelCloudStoreKey]; return; + } if (![manager cloudSafeForSeeding]) { wrn(@"Can't migrate old cloud store: A new cloud store already exists."); + [[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelCloudStoreCurrent forKey:MPMigrationLevelCloudStoreKey]; return; } @@ -244,27 +274,10 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, error:nil cause:nil context:nil]) return; - [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"LocalUUIDKey"]; + [[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelCloudStoreCurrent forKey:MPMigrationLevelCloudStoreKey]; inf(@"Successfully migrated old to new cloud store."); } -- (void)saveContexts { - - NSManagedObjectContext *mainManagedObjectContext = self.mainManagedObjectContext; - [mainManagedObjectContext performBlockAndWait:^{ - NSError *error = nil; - if (![mainManagedObjectContext save:&error]) - err(@"While saving main context: %@", error); - }]; - - NSManagedObjectContext *privateManagedObjectContext = [self privateManagedObjectContextIfReady]; - [privateManagedObjectContext performBlockAndWait:^{ - NSError *error = nil; - if (![privateManagedObjectContext save:&error]) - err(@"While saving private context: %@", error); - }]; -} - #pragma mark - UbiquityStoreManagerDelegate - (NSManagedObjectContext *)managedObjectContextForUbiquityStoreManager:(UbiquityStoreManager *)usm { @@ -301,8 +314,7 @@ 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; diff --git a/MasterPassword/ObjC/MPTypes.h b/MasterPassword/ObjC/MPTypes.h index 2b887694..ff9b19a7 100644 --- a/MasterPassword/ObjC/MPTypes.h +++ b/MasterPassword/ObjC/MPTypes.h @@ -68,7 +68,7 @@ typedef enum { #define MPCheckpointApps @"MPCheckpointApps" #define MPCheckpointApp @"MPCheckpointApp" #define MPCheckpointEmergencyGenerator @"MPCheckpointEmergencyGenerator" -#define MPCheckpointLogs @"MPCheckpointLogs" +#define MPCheckpointLogs @"MPCheckpointLogs" #define MPSignedInNotification @"MPSignedInNotification" #define MPSignedOutNotification @"MPSignedOutNotification" @@ -78,7 +78,11 @@ typedef enum { static void MPCheckpoint(NSString *checkpoint, NSDictionary *attributes) { + inf(@"%@: %@", checkpoint, attributes); #ifdef LOCALYTICS [[LocalyticsSession sharedLocalyticsSession] tagEvent:checkpoint attributes:attributes]; #endif +#ifdef TESTFLIGHT_SDK_VERSION + [TestFlight passCheckpoint:checkpoint]; +#endif } diff --git a/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m b/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m index 7b924d11..81c9f5f9 100644 --- a/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m +++ b/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m @@ -202,23 +202,28 @@ [[Crashlytics sharedInstance] setObjectValue:[PearlConfig get].reviewedVersion forKey:@"reviewedVersion"]; #ifdef TESTFLIGHT_SDK_VERSION - [TestFlight addCustomEnvironmentInformation:[@([[MPConfig get].rememberLogin boolValue]) description] + [TestFlight addCustomEnvironmentInformation:PearlStringNSB([MPConfig get].rememberLogin) forKey:@"rememberLogin"]; - [TestFlight addCustomEnvironmentInformation:[@([self storeManager].cloudEnabled) description] forKey:@"iCloud"]; - [TestFlight addCustomEnvironmentInformation:[@([[MPConfig get].iCloudDecided boolValue]) description] + [TestFlight addCustomEnvironmentInformation:PearlStringB([self storeManager].cloudEnabled) + forKey:@"iCloud"]; + [TestFlight addCustomEnvironmentInformation:PearlStringNSB([MPConfig get].iCloudDecided) forKey:@"iCloudDecided"]; - [TestFlight addCustomEnvironmentInformation:[@([[MPiOSConfig get].sendInfo boolValue]) description] forKey:@"sendInfo"]; - [TestFlight addCustomEnvironmentInformation:[@([[MPiOSConfig get].helpHidden boolValue]) description] + [TestFlight addCustomEnvironmentInformation:PearlStringNSB([MPiOSConfig get].sendInfo) + forKey:@"sendInfo"]; + [TestFlight addCustomEnvironmentInformation:PearlStringNSB([MPiOSConfig get].helpHidden) forKey:@"helpHidden"]; - [TestFlight addCustomEnvironmentInformation:[@([[MPiOSConfig get].showSetup boolValue]) description] + [TestFlight addCustomEnvironmentInformation:PearlStringNSB([MPiOSConfig get].showSetup) forKey:@"showQuickStart"]; - [TestFlight addCustomEnvironmentInformation:[@([[PearlConfig get].firstRun boolValue]) description] forKey:@"firstRun"]; - [TestFlight addCustomEnvironmentInformation:[[PearlConfig get].launchCount description] forKey:@"launchCount"]; - [TestFlight addCustomEnvironmentInformation:[@([[PearlConfig get].askForReviews boolValue]) description] + [TestFlight addCustomEnvironmentInformation:PearlStringNSB([PearlConfig get].firstRun) + forKey:@"firstRun"]; + [TestFlight addCustomEnvironmentInformation:PearlStringNSB([PearlConfig get].launchCount) + forKey:@"launchCount"]; + [TestFlight addCustomEnvironmentInformation:PearlStringNSB([PearlConfig get].askForReviews) forKey:@"askForReviews"]; - [TestFlight addCustomEnvironmentInformation:[[PearlConfig get].reviewAfterLaunches description] + [TestFlight addCustomEnvironmentInformation:PearlStringNSB([PearlConfig get].reviewAfterLaunches) forKey:@"reviewAfterLaunches"]; - [TestFlight addCustomEnvironmentInformation:[PearlConfig get].reviewedVersion forKey:@"reviewedVersion"]; + [TestFlight addCustomEnvironmentInformation:[PearlConfig get].reviewedVersion + forKey:@"reviewedVersion"]; #endif MPCheckpoint( MPCheckpointConfig, @{ @"rememberLogin" : @([[MPConfig get].rememberLogin boolValue]), @@ -228,9 +233,9 @@ @"helpHidden" : @([[MPiOSConfig get].helpHidden boolValue]), @"showQuickStart" : @([[MPiOSConfig get].showSetup boolValue]), @"firstRun" : @([[PearlConfig get].firstRun boolValue]), - @"launchCount" : NilToNSNull([[PearlConfig get].launchCount description]), + @"launchCount" : NilToNSNull([PearlConfig get].launchCount), @"askForReviews" : @([[PearlConfig get].askForReviews boolValue]), - @"reviewAfterLaunches" : NilToNSNull([[PearlConfig get].reviewAfterLaunches description]), + @"reviewAfterLaunches" : NilToNSNull([PearlConfig get].reviewAfterLaunches), @"reviewedVersion" : NilToNSNull([PearlConfig get].reviewedVersion) } ); }