diff --git a/MasterPassword/ObjC/MPAlgorithm.h b/MasterPassword/ObjC/MPAlgorithm.h index 2c8d3b11..ab251671 100644 --- a/MasterPassword/ObjC/MPAlgorithm.h +++ b/MasterPassword/ObjC/MPAlgorithm.h @@ -18,6 +18,7 @@ #import "MPKey.h" #import "MPStoredSiteEntity.h" #import "MPGeneratedSiteEntity.h" +#import "MPSiteQuestionEntity.h" #define MPAlgorithmDefaultVersion 2 #define MPAlgorithmDefault MPAlgorithmForVersion(MPAlgorithmDefaultVersion) @@ -75,7 +76,7 @@ NSString *NSStringFromTimeToCrack(TimeToCrack timeToCrack); - (NSString *)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey; - (NSString *)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey; - (NSString *)resolveAnswerForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey; -- (NSString *)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question ofSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey; +- (NSString *)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question usingKey:(MPKey *)siteKey; - (void)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey result:(void ( ^ )(NSString *result))resultBlock; @@ -83,8 +84,8 @@ NSString *NSStringFromTimeToCrack(TimeToCrack timeToCrack); result:(void ( ^ )(NSString *result))resultBlock; - (void)resolveAnswerForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey result:(void ( ^ )(NSString *result))resultBlock; -- (void)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question ofSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey - result:(void ( ^ )(NSString *result))resultBlock; +- (void)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question usingKey:(MPKey *)siteKey + result:(void ( ^ )(NSString *result))resultBlock; - (void)importProtectedPassword:(NSString *)protectedPassword protectedByKey:(MPKey *)importKey intoSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey; diff --git a/MasterPassword/ObjC/MPAlgorithmV0.m b/MasterPassword/ObjC/MPAlgorithmV0.m index cb8a6e7c..f5bd4be5 100644 --- a/MasterPassword/ObjC/MPAlgorithmV0.m +++ b/MasterPassword/ObjC/MPAlgorithmV0.m @@ -535,12 +535,12 @@ return result; } -- (NSString *)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question ofSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey { +- (NSString *)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question usingKey:(MPKey *)siteKey { dispatch_group_t group = dispatch_group_create(); dispatch_group_enter( group ); __block NSString *result = nil; - [self resolveAnswerForQuestion:question ofSite:site usingKey:siteKey result:^(NSString *result_) { + [self resolveAnswerForQuestion:question usingKey:siteKey result:^(NSString *result_) { result = result_; dispatch_group_leave( group ); }]; @@ -657,19 +657,19 @@ } ); } -- (void)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question ofSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey +- (void)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question usingKey:(MPKey *)siteKey result:(void ( ^ )(NSString *result))resultBlock { - NSAssert( [siteKey.keyID isEqualToData:site.user.keyID], @"Site does not belong to current user." ); - NSString *name = site.name; + NSAssert( [siteKey.keyID isEqualToData:question.site.user.keyID], @"Site does not belong to current user." ); + NSString *name = question.site.name; NSString *keyword = question.keyword; id algorithm = nil; - if (!site.name.length) + if (!name.length) err( @"Missing name." ); else if (!siteKey.keyData.length) err( @"Missing key." ); else - algorithm = site.algorithm; + algorithm = question.site.algorithm; dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ NSString *result = [algorithm generateAnswerForSiteNamed:name onQuestion:keyword usingKey:siteKey]; diff --git a/MasterPassword/ObjC/MPAppDelegate_Store.m b/MasterPassword/ObjC/MPAppDelegate_Store.m index c38413db..e09a8009 100644 --- a/MasterPassword/ObjC/MPAppDelegate_Store.m +++ b/MasterPassword/ObjC/MPAppDelegate_Store.m @@ -35,6 +35,8 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, PrivateManagedObjectCont PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext, mainManagedObjectContext ); +PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted ); + #pragma mark - Core Data setup + (NSManagedObjectContext *)managedObjectContextForMainThreadIfReady { @@ -144,6 +146,10 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext self.privateManagedObjectContext = nil; }]; + // Don't load when the store is corrupted. + if ([self.storeCorrupted boolValue]) + return; + // Check if migration is necessary. [self migrateStore]; @@ -168,9 +174,11 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext STORE_OPTIONS } error:&error]) { err( @"Failed to open store: %@", [error fullDescription] ); + self.storeCorrupted = @YES; [self handleCoordinatorError:error]; return; } + self.storeCorrupted = @NO; // Create our contexts and observer. self.privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; diff --git a/MasterPassword/ObjC/MPSiteQuestionEntity.h b/MasterPassword/ObjC/MPSiteQuestionEntity.h index 0a0c132f..313daf11 100644 --- a/MasterPassword/ObjC/MPSiteQuestionEntity.h +++ b/MasterPassword/ObjC/MPSiteQuestionEntity.h @@ -1,8 +1,8 @@ // // MPSiteQuestionEntity.h -// MasterPassword-Mac +// MasterPassword-iOS // -// Created by Maarten Billemont on 2014-09-21. +// Created by Maarten Billemont on 2014-09-27. // Copyright (c) 2014 Lyndir. All rights reserved. // @@ -14,5 +14,6 @@ @interface MPSiteQuestionEntity : NSManagedObject @property (nonatomic, retain) NSString * keyword; +@property (nonatomic, retain) MPSiteEntity *site; @end diff --git a/MasterPassword/ObjC/MPSiteQuestionEntity.m b/MasterPassword/ObjC/MPSiteQuestionEntity.m index 891cdf3b..12004ada 100644 --- a/MasterPassword/ObjC/MPSiteQuestionEntity.m +++ b/MasterPassword/ObjC/MPSiteQuestionEntity.m @@ -1,8 +1,8 @@ // // MPSiteQuestionEntity.m -// MasterPassword-Mac +// MasterPassword-iOS // -// Created by Maarten Billemont on 2014-09-21. +// Created by Maarten Billemont on 2014-09-27. // Copyright (c) 2014 Lyndir. All rights reserved. // @@ -13,5 +13,6 @@ @implementation MPSiteQuestionEntity @dynamic keyword; +@dynamic site; @end diff --git a/MasterPassword/ObjC/MasterPassword.xcdatamodeld/MasterPassword 6.xcdatamodel/contents b/MasterPassword/ObjC/MasterPassword.xcdatamodeld/MasterPassword 6.xcdatamodel/contents index 96ba87f6..f305f0c2 100644 --- a/MasterPassword/ObjC/MasterPassword.xcdatamodeld/MasterPassword 6.xcdatamodel/contents +++ b/MasterPassword/ObjC/MasterPassword.xcdatamodeld/MasterPassword 6.xcdatamodel/contents @@ -15,11 +15,12 @@ - + + @@ -38,7 +39,7 @@ - + diff --git a/MasterPassword/ObjC/iOS/MPAnswersViewController.m b/MasterPassword/ObjC/iOS/MPAnswersViewController.m index feb4efed..b13e8b19 100644 --- a/MasterPassword/ObjC/iOS/MPAnswersViewController.m +++ b/MasterPassword/ObjC/iOS/MPAnswersViewController.m @@ -8,12 +8,7 @@ #import "MPAnswersViewController.h" #import "MPiOSAppDelegate.h" -#import "MPAppDelegate_Key.h" #import "MPAppDelegate_Store.h" -#import "UIColor+Expanded.h" -#import "MPPasswordsViewController.h" -#import "MPCoachmarkViewController.h" -#import "MPSiteQuestionEntity.h" #import "MPOverlayViewController.h" @interface MPAnswersViewController() @@ -171,7 +166,6 @@ NSOrderedSet *questions = [site_.questions copy]; for (MPSiteQuestionEntity *question in questions) [context deleteObject:question]; - [site_ removeQuestions:questions]; [context saveToStore]; [self setMultiple:NO animated:YES]; }]; @@ -191,7 +185,7 @@ NSMutableString *bodyBuilder = [NSMutableString string]; [bodyBuilder appendFormat:@"Master Password generated the following security answers for your site: %@\n\n", site.name]; for (MPSiteQuestionEntity *question in site.questions) { - NSObject *answer = [site.algorithm resolveAnswerForQuestion:question ofSite:site usingKey:[MPiOSAppDelegate get].key]; + NSObject *answer = [site.algorithm resolveAnswerForQuestion:question usingKey:[MPiOSAppDelegate get].key]; [bodyBuilder appendFormat:@"For question: '%@', use answer: %@\n", question.keyword, answer]; } [bodyBuilder appendFormat:@"\n\nUse the answer for the matching security question.\n" @@ -280,8 +274,10 @@ [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { MPSiteEntity *site = [MPSiteEntity existingObjectWithID:_siteOID inContext:context]; MPSiteQuestionEntity *question = [MPSiteQuestionEntity existingObjectWithID:_questionOID inContext:context]; - if (!question) + if (!question) { [site addQuestionsObject:question = [MPSiteQuestionEntity insertNewObjectInContext:context]]; + question.site = site; + } question.keyword = keyword; @@ -313,7 +309,7 @@ PearlMainQueue( ^{ self.answerField.text = @"..."; } ); - [site.algorithm resolveAnswerForQuestion:question ofSite:site usingKey:[MPiOSAppDelegate get].key result:^(NSString *result) { + [site.algorithm resolveAnswerForQuestion:question usingKey:[MPiOSAppDelegate get].key result:^(NSString *result) { PearlMainQueue( ^{ self.questionField.text = keyword; self.answerField.text = result; diff --git a/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj b/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj index 6ab120dc..5b25c052 100644 --- a/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj +++ b/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj @@ -115,7 +115,6 @@ DA30E9D815723E6900A68B4C /* PearlLazy.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9D615723E6900A68B4C /* PearlLazy.m */; }; DA32CFF019CF1C8F004F3F0E /* MPUserEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA32CFE619CF1C8F004F3F0E /* MPUserEntity.m */; }; DA32CFF119CF1C8F004F3F0E /* MPStoredSiteEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA32CFE819CF1C8F004F3F0E /* MPStoredSiteEntity.m */; }; - DA32CFF219CF1C8F004F3F0E /* MPSiteQuestionEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA32CFEA19CF1C8F004F3F0E /* MPSiteQuestionEntity.m */; }; DA32CFF319CF1C8F004F3F0E /* MPSiteEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA32CFEC19CF1C8F004F3F0E /* MPSiteEntity.m */; }; DA32CFF419CF1C8F004F3F0E /* MPGeneratedSiteEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA32CFEE19CF1C8F004F3F0E /* MPGeneratedSiteEntity.m */; }; DA32D00819CF4735004F3F0E /* MasterPassword.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DA32D00119CF4735004F3F0E /* MasterPassword.xcdatamodeld */; }; @@ -136,6 +135,7 @@ DA32D05019D2F59B004F3F0E /* meter_fuel.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D04D19D2F59B004F3F0E /* meter_fuel.png */; }; DA32D05119D3D107004F3F0E /* icon_meter.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37BA1711E29600CF925C /* icon_meter.png */; }; DA32D05219D3D107004F3F0E /* icon_meter@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37BB1711E29600CF925C /* icon_meter@2x.png */; }; + DA32D05519D741DC004F3F0E /* MPSiteQuestionEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA32D05419D741DC004F3F0E /* MPSiteQuestionEntity.m */; }; DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3509FC15F101A500C14A8E /* PearlQueue.h */; }; DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3509FD15F101A500C14A8E /* PearlQueue.m */; }; DA38D6A318CCB5BF009AEB3E /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */; }; @@ -544,8 +544,6 @@ DA32CFE719CF1C8F004F3F0E /* MPUserEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUserEntity.h; sourceTree = ""; }; DA32CFE819CF1C8F004F3F0E /* MPStoredSiteEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPStoredSiteEntity.m; sourceTree = ""; }; DA32CFE919CF1C8F004F3F0E /* MPStoredSiteEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPStoredSiteEntity.h; sourceTree = ""; }; - DA32CFEA19CF1C8F004F3F0E /* MPSiteQuestionEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSiteQuestionEntity.m; sourceTree = ""; }; - DA32CFEB19CF1C8F004F3F0E /* MPSiteQuestionEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSiteQuestionEntity.h; sourceTree = ""; }; DA32CFEC19CF1C8F004F3F0E /* MPSiteEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSiteEntity.m; sourceTree = ""; }; DA32CFED19CF1C8F004F3F0E /* MPSiteEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSiteEntity.h; sourceTree = ""; }; DA32CFEE19CF1C8F004F3F0E /* MPGeneratedSiteEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPGeneratedSiteEntity.m; sourceTree = ""; }; @@ -570,6 +568,8 @@ DA32D04B19D2F59B004F3F0E /* meter_fuel@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "meter_fuel@3x.png"; sourceTree = ""; }; DA32D04C19D2F59B004F3F0E /* meter_fuel@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "meter_fuel@2x.png"; sourceTree = ""; }; DA32D04D19D2F59B004F3F0E /* meter_fuel.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = meter_fuel.png; sourceTree = ""; }; + DA32D05319D741DC004F3F0E /* MPSiteQuestionEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSiteQuestionEntity.h; sourceTree = ""; }; + DA32D05419D741DC004F3F0E /* MPSiteQuestionEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSiteQuestionEntity.m; sourceTree = ""; }; DA3509FC15F101A500C14A8E /* PearlQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlQueue.h; sourceTree = ""; }; DA3509FD15F101A500C14A8E /* PearlQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlQueue.m; sourceTree = ""; }; DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Storyboard.storyboard; sourceTree = ""; }; @@ -2337,12 +2337,12 @@ DABD3B9F1711E2DB00CF925C /* ObjC */ = { isa = PBXGroup; children = ( + DA32D05319D741DC004F3F0E /* MPSiteQuestionEntity.h */, + DA32D05419D741DC004F3F0E /* MPSiteQuestionEntity.m */, DA32CFE619CF1C8F004F3F0E /* MPUserEntity.m */, DA32CFE719CF1C8F004F3F0E /* MPUserEntity.h */, DA32CFE819CF1C8F004F3F0E /* MPStoredSiteEntity.m */, DA32CFE919CF1C8F004F3F0E /* MPStoredSiteEntity.h */, - DA32CFEA19CF1C8F004F3F0E /* MPSiteQuestionEntity.m */, - DA32CFEB19CF1C8F004F3F0E /* MPSiteQuestionEntity.h */, DA32CFEC19CF1C8F004F3F0E /* MPSiteEntity.m */, DA32CFED19CF1C8F004F3F0E /* MPSiteEntity.h */, DA32CFEE19CF1C8F004F3F0E /* MPGeneratedSiteEntity.m */, @@ -3341,12 +3341,12 @@ DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */, DABD3C271711E2DC00CF925C /* main.m in Sources */, 93D39F8A9254177891F38705 /* MPSetupViewController.m in Sources */, - DA32CFF219CF1C8F004F3F0E /* MPSiteQuestionEntity.m in Sources */, DA095E75172F4CD8001C948B /* MPLogsViewController.m in Sources */, 93D39D596A2E376D6F6F5DA1 /* MPCombinedViewController.m in Sources */, DA32CFF419CF1C8F004F3F0E /* MPGeneratedSiteEntity.m in Sources */, 93D3957237D303DE2D38C267 /* MPAvatarCell.m in Sources */, 93D39B8F90F58A5D158DDBA3 /* MPPasswordsViewController.m in Sources */, + DA32D05519D741DC004F3F0E /* MPSiteQuestionEntity.m in Sources */, 93D3954FCE045A3CC7E804B7 /* MPUsersViewController.m in Sources */, 93D39392DEDA376F93C6C718 /* MPCell.m in Sources */, 93D39A5FF670957C0AF8298D /* MPPasswordCell.m in Sources */, diff --git a/MasterPassword/ObjC/iOS/Storyboard.storyboard b/MasterPassword/ObjC/iOS/Storyboard.storyboard index 12755ae4..edf587b3 100644 --- a/MasterPassword/ObjC/iOS/Storyboard.storyboard +++ b/MasterPassword/ObjC/iOS/Storyboard.storyboard @@ -1,7 +1,6 @@ - @@ -2435,7 +2434,7 @@ See -