diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 0c0273a4..e947e785 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -3,6 +3,7 @@
+
diff --git a/MasterPassword/ObjC/MPAppDelegate_Key.m b/MasterPassword/ObjC/MPAppDelegate_Key.m
index ce3cd8dd..3d59b7b2 100644
--- a/MasterPassword/ObjC/MPAppDelegate_Key.m
+++ b/MasterPassword/ObjC/MPAppDelegate_Key.m
@@ -92,60 +92,7 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
user.keyID = tryKey.keyID;
// Migrate existing elements.
- MPKey *recoverKey = nil;
-#ifdef PEARL_UIKIT
- PearlAlert *activityAlert = [PearlAlert showActivityWithTitle:PearlString(@"Migrating %d sites...", [user.elements count])];
-#endif
-
- for (MPElementEntity *element in user.elements) {
- if (element.type & MPElementTypeClassStored && ![element contentUsingKey:tryKey]) {
- id content = nil;
- if (recoverKey)
- content = [element contentUsingKey:recoverKey];
-
- while (!content) {
- __block 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 %@", element.name)
- viewStyle:UIAlertViewStyleSecureTextInput
- initAlert:nil
- tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
- @try {
- 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);
-#endif
- if (!masterPassword)
- // Don't Migrate
- break;
-
- recoverKey = [element.algorithm keyForPassword:masterPassword ofUserNamed:user.name];
- content = [element contentUsingKey:recoverKey];
- }
-
- if (!content)
- // Don't Migrate
- break;
-
- [element setContent:content usingKey:tryKey];
- }
- }
- [user saveContext];
-#ifdef PEARL_UIKIT
- [activityAlert cancelAlert];
-#endif
+ [self migrateElementsForUser:user inContext:user.managedObjectContext toKey:tryKey];
}
}
@@ -216,7 +163,7 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
}
user.lastUsed = [NSDate date];
- [user saveContext];
+ [user.managedObjectContext saveToStore];
self.activeUser = user;
[[NSNotificationCenter defaultCenter] postNotificationName:MPSignedInNotification object:self];
@@ -230,4 +177,66 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
return YES;
}
+- (void)migrateElementsForUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc toKey:(MPKey *)newKey {
+
+ if (![user.elements count])
+ // Nothing to migrate.
+ return;
+
+ MPKey *recoverKey = newKey;
+#ifdef PEARL_UIKIT
+ PearlAlert *activityAlert = [PearlAlert showActivityWithTitle:PearlString( @"Migrating %d sites...", [user.elements count] )];
+#endif
+
+ for (MPElementEntity *element in user.elements) {
+ if (element.type & MPElementTypeClassStored) {
+ id content = nil;
+ while (!(content = [element contentUsingKey:recoverKey])) {
+ // Failed to decrypt element with the current recoveryKey. Ask user for a new one to use.
+ __block 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 %@",
+ element.name )
+ viewStyle:UIAlertViewStyleSecureTextInput
+ initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
+ @try {
+ 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 );
+#endif
+ if (!masterPassword)
+ // Don't Migrate
+ break;
+
+ recoverKey = [element.algorithm keyForPassword:masterPassword ofUserNamed:user.name];
+ }
+
+ if (!content)
+ // Don't Migrate
+ break;
+
+ if (![recoverKey isEqualToKey:newKey])
+ [element setContent:content usingKey:newKey];
+ }
+ }
+
+ [moc saveToStore];
+
+#ifdef PEARL_UIKIT
+ [activityAlert cancelAlert];
+#endif
+}
+
@end
diff --git a/MasterPassword/ObjC/MPEntities.m b/MasterPassword/ObjC/MPEntities.m
index e95e00f1..87232705 100644
--- a/MasterPassword/ObjC/MPEntities.m
+++ b/MasterPassword/ObjC/MPEntities.m
@@ -15,7 +15,7 @@
NSError *error;
if (![self save:&error]) {
- err(@"While saving: %@", NSStringFromClass([self class]), error);
+ err(@"While saving: %@", error);
return NO;
}
@@ -194,13 +194,12 @@
- (id)contentUsingKey:(MPKey *)key {
- if (!(self.type & MPElementTypeClassGenerated)) {
- err(@"Corrupt element: %@, type: %d is not in MPElementTypeClassGenerated", self.name, self.type);
- return nil;
- }
+ assert(self.type & MPElementTypeClassGenerated);
if (![self.name length])
return nil;
+ if (!key)
+ return nil;
return [self.algorithm generateContentForElement:self usingKey:key];
}
@@ -222,6 +221,9 @@
assert(self.type & MPElementTypeClassStored);
+ if (!key)
+ return nil;
+
NSData *encryptedContent;
if (self.type & MPElementFeatureDevicePrivate)
encryptedContent = [PearlKeyChain dataOfItemForQuery:[MPElementStoredEntity queryForDevicePrivateElementNamed:self.name]];
diff --git a/MasterPassword/ObjC/iOS/MPElementListController.m b/MasterPassword/ObjC/iOS/MPElementListController.m
index 187deb76..b27c90a5 100644
--- a/MasterPassword/ObjC/iOS/MPElementListController.m
+++ b/MasterPassword/ObjC/iOS/MPElementListController.m
@@ -44,7 +44,7 @@
element.type = type;
element.lastUsed = [NSDate date];
element.version = MPAlgorithmDefaultVersion;
- [element saveContext];
+ [moc saveToStore];
NSManagedObjectID *elementOID = [element objectID];
dispatch_async(dispatch_get_main_queue(), ^{
diff --git a/MasterPassword/ObjC/iOS/MPMainViewController.m b/MasterPassword/ObjC/iOS/MPMainViewController.m
index d4267702..da800ee2 100644
--- a/MasterPassword/ObjC/iOS/MPMainViewController.m
+++ b/MasterPassword/ObjC/iOS/MPMainViewController.m
@@ -138,7 +138,7 @@
self.outdatedAlertContainer.alpha = 1;
self.suppressOutdatedAlert = YES;
}];
- [activeUser saveContext];
+ [activeUser.managedObjectContext saveToStore];
});
if (![[MPiOSConfig get].actionsTipShown boolValue])
diff --git a/MasterPassword/ObjC/iOS/MPPreferencesViewController.m b/MasterPassword/ObjC/iOS/MPPreferencesViewController.m
index e18ad705..acb1901f 100644
--- a/MasterPassword/ObjC/iOS/MPPreferencesViewController.m
+++ b/MasterPassword/ObjC/iOS/MPPreferencesViewController.m
@@ -49,7 +49,7 @@
if (selected) {
MPUserEntity *activeUser = [MPAppDelegate get].activeUser;
activeUser.avatar = (unsigned)avatar.tag;
- [activeUser saveContext];
+ [activeUser.managedObjectContext saveToStore];
}
} options:0];
avatar.selected = (a == [MPAppDelegate get].activeUser.avatar);
@@ -134,7 +134,7 @@
MPUserEntity *activeUser = [MPAppDelegate get].activeUser;
activeUser.defaultType = type;
- [activeUser saveContext];
+ [activeUser.managedObjectContext saveToStore];
self.defaultTypeLabel.text = [[MPAppDelegate get].key.algorithm shortNameOfType:activeUser.defaultType];
}
@@ -153,7 +153,7 @@
[[MPAppDelegate get] storeSavedKeyFor:activeUser];
else
[[MPAppDelegate get] forgetSavedKeyFor:activeUser];
- [activeUser saveContext];
+ [activeUser.managedObjectContext saveToStore];
}
- (IBAction)settings:(UIBarButtonItem *)sender {
diff --git a/MasterPassword/ObjC/iOS/MPUnlockViewController.m b/MasterPassword/ObjC/iOS/MPUnlockViewController.m
index e6bc04e0..4f2f5297 100644
--- a/MasterPassword/ObjC/iOS/MPUnlockViewController.m
+++ b/MasterPassword/ObjC/iOS/MPUnlockViewController.m
@@ -809,7 +809,7 @@
if (buttonIndex == [sheet firstOtherButtonIndex])
[moc performBlock:^{
- [[MPAppDelegate get] changeMasterPasswordFor:targetedUser didResetBlock:^{
+ [[MPAppDelegate get] changeMasterPasswordFor:targetedUser inContext:moc didResetBlock:^{
dispatch_async(dispatch_get_main_queue(), ^{
[[self avatarForUser:targetedUser] setSelected:YES];
});