2
0

iCloud sync fixes.

[REMOVED]   OS X: Disabled ability to add new sites from OS X until I
            have time to implement it properly without causing
            duplicates etc.
[MOVED]     iCloud and Core Data support was centralised to iOS and OS X
            to make sure both platforms always use the same container
            configuration.
[FIXED]     iCloud sync problems.
[REMOVED]   iCloud KV is not used/needed.
This commit is contained in:
Maarten Billemont 2012-05-04 18:54:58 +02:00
parent 26f8e086bb
commit 376953ae56
21 changed files with 439 additions and 290 deletions

@ -1 +1 @@
Subproject commit 5fd23fd728d2e6e3216c6c2bd5a807d5316966d1
Subproject commit 3ae828f48a63e505bcef7a9a9a78df567706eebc

2
External/Pearl vendored

@ -1 +1 @@
Subproject commit 5736ed0cb528aeabbad5cec1ae133c9002be2983
Subproject commit e23abc67cd80ec03543eed48ffd97b30439b5c84

View File

@ -2142,6 +2142,7 @@
DAB8DA101503972100CED3BC /* PearlSCrypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlSCrypt.h; sourceTree = "<group>"; };
DAB8DA111503972100CED3BC /* PearlSCrypt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlSCrypt.m; sourceTree = "<group>"; };
DAB8DA121503972100CED3BC /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
DAD312C71553051900A3F9ED /* MasterPassword.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = MasterPassword.entitlements; sourceTree = "<group>"; };
DADEA5A41503C9DD00FD084E /* e_os.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = e_os.h; sourceTree = "<group>"; };
DADEA5A51503C9DD00FD084E /* e_os2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = e_os2.h; sourceTree = "<group>"; };
DADEA5A91503CE3000FD084E /* _MWERKS_GUSI_prefix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _MWERKS_GUSI_prefix.h; sourceTree = "<group>"; };
@ -4025,6 +4026,7 @@
DAB8D992150374AD00CED3BC /* MasterPassword */ = {
isa = PBXGroup;
children = (
DAD312C71553051900A3F9ED /* MasterPassword.entitlements */,
DAB8D9B2150375C800CED3BC /* MasterPassword.xcdatamodeld */,
DAB8D9B4150375C800CED3BC /* Mac */,
DA600C2C150565FC008E9AB6 /* MPAppDelegate_Key.h */,
@ -6064,6 +6066,7 @@
DAB8D985150374AD00CED3BC /* Frameworks */,
DAB8D986150374AD00CED3BC /* Resources */,
DA60116B15060F11008E9AB6 /* CopyFiles */,
DAD312C9155305B200A3F9ED /* ShellScript */,
);
buildRules = (
);
@ -6809,6 +6812,23 @@
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
DAD312C9155305B200A3F9ED /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = "/bin/bash -e";
shellScript = "PATH+=:/usr/libexec\n\nsetPlistWithKey() {\n local key=$1 value=$2 plist=${3:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n \n PlistBuddy -c \"Set :'$key' $value\" \"$plist\"\n}\ngetPlistWithKey() {\n local key=$1 plist=${2:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n \n PlistBuddy -c \"Print :'$key'\" \"$plist\"\n}\nsetSettingWithTitle() {\n local i title=$1 value=$2 plist=${3:-\"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Settings.bundle/Root.plist\"}\n \n for (( i=0; 1; ++i )); do\n PlistBuddy -c \"Print :PreferenceSpecifiers:$i\" \"$plist\" &>/dev/null || break\n echo \"Checking preference specifier $i\"\n \n [[ $(PlistBuddy -c \"Print :PreferenceSpecifiers:$i:Title\" \"$plist\" 2>/dev/null) = $title ]] || continue\n \n echo \"Correct title, setting value.\"\n PlistBuddy -c \"Set :PreferenceSpecifiers:$i:DefaultValue $value\" \"$plist\"\n break\n done\n}\n\nbuild=$(git describe --tags --always --dirty --long)\ntag=$(git describe --tags | sed 's/-\\([^-]*\\)-[^-]*$/.\\1/')\n\nsetPlistWithKey CFBundleVersion \"$build\"\nsetPlistWithKey CFBundleShortVersionString \"$tag\"\n\nsetSettingWithTitle \"Build\" \"$build\"\nsetSettingWithTitle \"Version\" \"$tag\"\nsetSettingWithTitle \"Copyright\" \"$(getPlistWithKey NSHumanReadableCopyright)\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
DAB8D984150374AD00CED3BC /* Sources */ = {
isa = PBXSourcesBuildPhase;
@ -7529,6 +7549,8 @@
DAB8D9AA150374AD00CED3BC /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = MasterPassword/MasterPassword.entitlements;
CODE_SIGN_IDENTITY = "Mac Developer";
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "MasterPassword/Mac/MasterPassword-Prefix.pch";
INFOPLIST_FILE = "MasterPassword/Mac/MasterPassword-Info.plist";
@ -7538,6 +7560,8 @@
DAB8D9AB150374AD00CED3BC /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = MasterPassword/MasterPassword.entitlements;
CODE_SIGN_IDENTITY = "Mac Developer";
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "MasterPassword/Mac/MasterPassword-Prefix.pch";
INFOPLIST_FILE = "MasterPassword/Mac/MasterPassword-Info.plist";

View File

@ -56,6 +56,12 @@
ReferencedContainer = "container:MasterPassword-Mac.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "-com.apple.coredata.ubiquity.logLevel 3"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>

View File

@ -4107,7 +4107,6 @@
"$(inherited)",
"\"$(SRCROOT)/TestFlight\"",
);
OTHER_LDFLAGS = "-ObjC";
};
name = Debug;
};
@ -4126,7 +4125,6 @@
"$(inherited)",
"\"$(SRCROOT)/TestFlight\"",
);
OTHER_LDFLAGS = "-ObjC";
};
name = AdHoc;
};
@ -4224,7 +4222,6 @@
"$(inherited)",
"\"$(SRCROOT)/TestFlight\"",
);
OTHER_LDFLAGS = "-ObjC";
};
name = AppStore;
};

View File

@ -39,8 +39,8 @@
</MacroExpansion>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
@ -56,6 +56,12 @@
ReferencedContainer = "container:MasterPassword-iOS.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "-com.apple.coredata.ubiquity.logLevel 3"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>
<AdditionalOptions>
<AdditionalOption
key = "NSZombieEnabled"

View File

@ -8,7 +8,16 @@
#import "MPAppDelegate.h"
@interface MPAppDelegate ()
@interface MPAppDelegate () {
NSPersistentStoreCoordinator *_persistentStoreCoordinator;
NSManagedObjectModel *_managedObjectModel;
NSManagedObjectContext *_managedObjectContext;
}
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (strong, nonatomic) NSData *key;
@property (strong, nonatomic) NSData *keyHash;
@ -20,6 +29,13 @@
+ (MPAppDelegate *)get;
- (NSURL *)applicationFilesDirectory;
+ (NSManagedObjectModel *)managedObjectModel;
+ (NSManagedObjectContext *)managedObjectContext;
- (void)saveContext;
- (void)printStore;
- (void)loadStoredKey;
- (void)signOut;

View File

@ -8,6 +8,7 @@
#import "MPConfig.h"
#import "MPAppDelegate_Key.h"
#import "MPElementEntity.h"
@implementation MPAppDelegate (Key)
@ -35,6 +36,180 @@ static NSDictionary *keyHashQuery() {
return MPKeyHashQuery;
}
- (NSURL *)applicationFilesDirectory {
#if __IPHONE_OS_VERSION_MIN_REQUIRED
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
#else
NSURL *appSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *applicationFilesDirectory = [appSupportURL URLByAppendingPathComponent:@"com.lyndir.lhunath.MasterPassword"];
NSError *error = nil;
[[NSFileManager defaultManager] createDirectoryAtURL:applicationFilesDirectory withIntermediateDirectories:YES attributes:nil error:&error];
if (error)
err(@"Couldn't create application directory: %@, error occurred: %@", applicationFilesDirectory, error);
return applicationFilesDirectory;
#endif
}
#pragma mark - Core Data stack
+ (NSManagedObjectContext *)managedObjectContext {
return [[self get] managedObjectContext];
}
+ (NSManagedObjectModel *)managedObjectModel {
return [[self get] managedObjectModel];
}
- (NSManagedObjectModel *)managedObjectModel {
if (_managedObjectModel)
return _managedObjectModel;
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MasterPassword" withExtension:@"momd"];
return _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
}
- (NSManagedObjectContext *)managedObjectContext {
if (_managedObjectContext)
return _managedObjectContext;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator) {
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
_managedObjectContext.persistentStoreCoordinator = coordinator;
[[NSNotificationCenter defaultCenter] addObserverForName:NSPersistentStoreDidImportUbiquitousContentChangesNotification
object:coordinator
queue:nil
usingBlock:^(NSNotification *note) {
dbg(@"Ubiquitous content change: %@", note);
[_managedObjectContext performBlock:^{
[_managedObjectContext mergeChangesFromContextDidSaveNotification:note];
[self printStore];
[[NSNotificationCenter defaultCenter] postNotification:
[NSNotification notificationWithName:MPNotificationStoreUpdated
object:self userInfo:[note userInfo]]];
}];
}];
}
return _managedObjectContext;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (_persistentStoreCoordinator)
return _persistentStoreCoordinator;
NSString *contentName = @"store";
NSURL *storeURL = [[self applicationFilesDirectory] URLByAppendingPathComponent:@"MasterPassword.sqlite"];
NSURL *contentURL = [[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]
URLByAppendingPathComponent:@"logs" isDirectory:YES];
//#if DEBUG
// dbg(@"Deleting store and content.");
// NSError *storeRemovalError = nil, *contentRemovalError = nil;
// [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&storeRemovalError];
// if (storeRemovalError)
// err(@"Store removal error: %@", storeRemovalError);
// else
// [[NSFileManager defaultManager] removeItemAtURL:contentURL error:&contentRemovalError];
// if (contentRemovalError)
// err(@"Content removal error: %@", contentRemovalError);
//#endif
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
[_persistentStoreCoordinator lock];
@try {
NSError *error = nil;
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL
options:[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
#if __IPHONE_OS_VERSION_MIN_REQUIRED
NSFileProtectionComplete, NSPersistentStoreFileProtectionKey,
#endif
contentURL, NSPersistentStoreUbiquitousContentURLKey,
contentName, NSPersistentStoreUbiquitousContentNameKey,
nil]
error:&error]) {
ftl(@"Unresolved error %@, %@", error, [error userInfo]);
#if DEBUG
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
wrn(@"Deleted datastore: %@", storeURL);
#endif
@throw error;
}
}
@finally {
[_persistentStoreCoordinator unlock];
}
return _persistentStoreCoordinator;
}
- (void)saveContext {
[self.managedObjectContext performBlock:^{
NSError *error = nil;
if ([self.managedObjectContext hasChanges] && ![self.managedObjectContext save:&error])
err(@"Unresolved error %@", error);
}];
}
- (void)printStore {
if (!_managedObjectModel || !_managedObjectContext) {
trc(@"Not printing store: store not initialized.");
return;
}
[self.managedObjectContext performBlock:^{
trc(@"=== All entities ===");
for(NSEntityDescription *entity in [_managedObjectModel entities]) {
NSFetchRequest *request = [NSFetchRequest new];
[request setEntity:entity];
NSError *error;
NSArray *results = [_managedObjectContext executeFetchRequest:request error:&error];
for(NSManagedObject *o in results) {
if ([o isKindOfClass:[MPElementEntity class]]) {
MPElementEntity *e = (MPElementEntity *)o;
trc(@"For descriptor: %@, found: %@: %@ (%@)", entity.name, [o class], e.name, e.mpHashHex);
} else {
trc(@"For descriptor: %@, found: %@", entity.name, [o class]);
}
}
}
trc(@"---");
if ([MPAppDelegate get].keyHashHex) {
trc(@"=== Known sites ===");
NSFetchRequest *fetchRequest = [_managedObjectModel
fetchRequestFromTemplateWithName:@"MPElements"
substitutionVariables:[NSDictionary dictionaryWithObjectsAndKeys:
@"", @"query",
[MPAppDelegate get].keyHashHex, @"mpHashHex",
nil]];
[fetchRequest setSortDescriptors:
[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses" ascending:NO]]];
NSError *error = nil;
for (MPElementEntity *e in [_managedObjectContext executeFetchRequest:fetchRequest error:&error]) {
trc(@"Found site: %@ (%@): %@", e.name, e.mpHashHex, e);
}
trc(@"---");
} else
trc(@"Not printing sites: master password not set.");
}];
}
- (void)forgetKey {
dbg(@"Deleting master key and hash from key chain.");
@ -42,7 +217,9 @@ static NSDictionary *keyHashQuery() {
[PearlKeyChain deleteItemForQuery:keyHashQuery()];
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyForgotten object:self];
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
[TestFlight passCheckpoint:MPTestFlightCheckpointMPForgotten];
#endif
}
- (void)signOut {
@ -61,7 +238,9 @@ static NSDictionary *keyHashQuery() {
// Key should not be stored in keychain. Delete it.
dbg(@"Deleting key from key chain.");
[PearlKeyChain deleteItemForQuery:keyQuery()];
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
[TestFlight passCheckpoint:MPTestFlightCheckpointMPUnstored];
#endif
}
}
@ -92,11 +271,15 @@ static NSDictionary *keyHashQuery() {
if (![keyHash isEqual:tryKeyHash]) {
dbg(@"Key phrase hash mismatch. Expected: %@, answer: %@.", keyHash, tryKeyHash);
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
[TestFlight passCheckpoint:MPTestFlightCheckpointMPMismatch];
#endif
return NO;
}
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
[TestFlight passCheckpoint:MPTestFlightCheckpointMPAsked];
#endif
[self updateKey:tryKey];
return YES;
@ -134,7 +317,9 @@ static NSDictionary *keyHashQuery() {
nil]];
}
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
[TestFlight passCheckpoint:[NSString stringWithFormat:MPTestFlightCheckpointSetKeyphraseLength, key.length]];
#endif
}
}

View File

@ -16,16 +16,15 @@
- (id)content {
assert(self.type & MPElementTypeClassCalculated);
if (!(self.type & MPElementTypeClassCalculated)) {
err(@"Corrupt element: %@, type: %d, does not match class: %@", self.name, self.type, [self class]);
return nil;
}
if (![self.name length])
return nil;
if (self.type & MPElementTypeClassCalculated)
return MPCalculateContent((unsigned)self.type, self.name, [MPAppDelegate get].key, self.counter);
@throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:[NSString stringWithFormat:@"Unsupported type: %d", self.type] userInfo:nil];
}
@end

View File

@ -104,14 +104,24 @@ NSString *ClassNameFromMPElementType(MPElementType type) {
static NSDictionary *MPTypes_ciphers = nil;
NSString *MPCalculateContent(MPElementType type, NSString *name, NSData *key, int16_t counter) {
assert(type & MPElementTypeClassCalculated);
if (!name) {
err(@"Missing name.");
return nil;
}
if (!(type & MPElementTypeClassCalculated)) {
err(@"Incorrect type (is not MPElementTypeClassCalculated): %d, for: %@", type, name);
return nil;
}
if (!key) {
err(@"Key not set.");
return nil;
}
if (MPTypes_ciphers == nil)
MPTypes_ciphers = [NSDictionary dictionaryWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"ciphers"
withExtension:@"plist"]];
// Determine the hash whose bytes will be used for calculating a password: md4(name-key)
assert(name && key);
uint16_t ncounter = htons(counter);
trc(@"key hash from: %@-%@-%u", name, key, ncounter);
NSData *keyHash = [[NSData dataByConcatenatingWithDelimitor:'-' datas:

View File

@ -13,13 +13,6 @@
@property (assign) IBOutlet NSWindow *window;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
+ (NSManagedObjectModel *)managedObjectModel;
+ (NSManagedObjectContext *)managedObjectContext;
- (IBAction)saveAction:(id)sender;
- (void)loadKey;

View File

@ -8,6 +8,7 @@
#import "MPAppDelegate_Key.h"
#import "MPConfig.h"
#import "MPElementEntity.h"
@interface MPAppDelegate ()
@ -18,11 +19,9 @@
@implementation MPAppDelegate
@synthesize window = _window;
@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
@synthesize managedObjectModel = __managedObjectModel;
@synthesize managedObjectContext = __managedObjectContext;
@synthesize passwordWindow;
@dynamic persistentStoreCoordinator, managedObjectModel, managedObjectContext;
@synthesize key;
@synthesize keyHash;
@synthesize keyHashHex;
@ -32,22 +31,14 @@
[MPConfig get];
#ifdef DEBUG
[PearlLogger get].autoprintLevel = PearlLogLevelDebug;
[PearlLogger get].autoprintLevel = PearlLogLevelTrace
;
#endif
}
+ (NSManagedObjectContext *)managedObjectContext {
return [[self get] managedObjectContext];
}
+ (NSManagedObjectModel *)managedObjectModel {
return [[self get] managedObjectModel];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[self managedObjectContext];
}
- (void)applicationDidBecomeActive:(NSNotification *)notification {
@ -73,6 +64,7 @@
informativeTextWithFormat:@"Your master password is required to unlock the application."];
NSTextField *passwordField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 22)];
[alert setAccessoryView:passwordField];
[passwordField becomeFirstResponder];
[alert layout];
do {
NSInteger button = [alert runModal];
@ -96,97 +88,11 @@
break;
}
} while (![self tryMasterPassword:[passwordField stringValue]]);
[self printStore];
});
}
- (NSURL *)applicationFilesDirectory {
NSURL *appSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *applicationFilesDirectory = [appSupportURL URLByAppendingPathComponent:@"com.lyndir.lhunath.MasterPassword"];
NSError *error = nil;
[[NSFileManager defaultManager] createDirectoryAtURL:applicationFilesDirectory withIntermediateDirectories:YES attributes:nil error:&error];
if (error)
[[NSApplication sharedApplication] presentError:error];
return applicationFilesDirectory;
}
#pragma mark - Core Data stack
- (NSManagedObjectModel *)managedObjectModel {
if (__managedObjectModel)
return __managedObjectModel;
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MasterPassword" withExtension:@"momd"];
return __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
}
- (NSManagedObjectContext *)managedObjectContext {
if (__managedObjectContext)
return __managedObjectContext;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator) {
__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
__managedObjectContext.persistentStoreCoordinator = coordinator;
[[NSNotificationCenter defaultCenter] addObserverForName:NSPersistentStoreDidImportUbiquitousContentChangesNotification
object:coordinator
queue:nil
usingBlock:^(NSNotification *note) {
dbg(@"Ubiquitous content change: %@", note);
[__managedObjectContext performBlock:^{
[__managedObjectContext mergeChangesFromContextDidSaveNotification:note];
[[NSNotificationCenter defaultCenter] postNotification:
[NSNotification notificationWithName:MPNotificationStoreUpdated
object:self userInfo:[note userInfo]]];
}];
}];
}
return __managedObjectContext;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (__persistentStoreCoordinator)
return __persistentStoreCoordinator;
NSURL *storeURL = [[self applicationFilesDirectory] URLByAppendingPathComponent:@"MasterPassword.sqlite"];
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
[__persistentStoreCoordinator lock];
NSError *error = nil;
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL
options:[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[[[NSFileManager defaultManager]
URLForUbiquityContainerIdentifier:nil]
URLByAppendingPathComponent:@"store"
isDirectory:YES], NSPersistentStoreUbiquitousContentURLKey,
@"MasterPassword.store", NSPersistentStoreUbiquitousContentNameKey,
nil]
error:&error]) {
err(@"Unresolved error %@, %@", error, [error userInfo]);
#if DEBUG
wrn(@"Deleted datastore: %@", storeURL);
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
#endif
[[NSApplication sharedApplication] presentError:error];
return nil;
}
[__persistentStoreCoordinator unlock];
return __persistentStoreCoordinator;
}
- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window {
return [[self managedObjectContext] undoManager];
@ -210,7 +116,7 @@
{
// Save changes in the application's managed object context before the application terminates.
if (!__managedObjectContext) {
if (!_managedObjectContext) {
return NSTerminateNow;
}

View File

@ -11,5 +11,6 @@
@interface MPPasswordWindowController : NSWindowController <NSTextFieldDelegate>
@property (weak) IBOutlet NSTextField *siteField;
@property (weak) IBOutlet NSTextField *contentField;
- (IBAction)empty:(id)sender;
@end

View File

@ -66,10 +66,17 @@
if (self.siteResults)
for (MPElementEntity *element in self.siteResults)
[mutableResults addObject:element.name];
[mutableResults addObject:query];
// [mutableResults addObject:query]; // For when the app should be able to create new sites.
return mutableResults;
}
- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector {
dbg(@"Selector = %@", NSStringFromSelector(commandSelector));
return NO;
}
- (void)controlTextDidEndEditing:(NSNotification *)obj {
if (obj.object == self.siteField) {
@ -92,24 +99,37 @@
});
});
else
[[MPAppDelegate get].managedObjectContext performBlock:^{
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPElementGeneratedEntity class])
inManagedObjectContext:[MPAppDelegate get].managedObjectContext];
assert([element isKindOfClass:ClassFromMPElementType(element.type)]);
assert([MPAppDelegate get].keyHashHex);
element.name = siteName;
element.mpHashHex = [MPAppDelegate get].keyHashHex;
NSString *description = [element description];
[element use];
dispatch_async(dispatch_get_main_queue(), ^{
[self.contentField setStringValue:description? description: @""];
});
}];
// For when the app should be able to create new sites.
// else
// [[MPAppDelegate get].managedObjectContext performBlock:^{
// MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPElementGeneratedEntity class])
// inManagedObjectContext:[MPAppDelegate get].managedObjectContext];
// assert([element isKindOfClass:ClassFromMPElementType(element.type)]);
// assert([MPAppDelegate get].keyHashHex);
//
// element.name = siteName;
// element.mpHashHex = [MPAppDelegate get].keyHashHex;
//
// NSString *description = [element description];
// [element use];
//
// dispatch_async(dispatch_get_main_queue(), ^{
// [self.contentField setStringValue:description? description: @""];
// });
// }];
}
}
- (IBAction)empty:(id)sender {
for(NSEntityDescription *entity in [[MPAppDelegate managedObjectModel] entities]) {
NSFetchRequest *request = [NSFetchRequest new];
[request setEntity:entity];
NSError *error;
NSArray *results = [[MPAppDelegate managedObjectContext] executeFetchRequest:request error:&error];
for(NSManagedObject *o in results) {
[[MPAppDelegate managedObjectContext] deleteObject:o];
}
}
}
@end

View File

@ -3,20 +3,22 @@
<data>
<int key="IBDocument.SystemTarget">1070</int>
<string key="IBDocument.SystemVersion">11D50</string>
<string key="IBDocument.InterfaceBuilderVersion">2177</string>
<string key="IBDocument.InterfaceBuilderVersion">2182</string>
<string key="IBDocument.AppKitVersion">1138.32</string>
<string key="IBDocument.HIToolboxVersion">568.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="NS.object.0">2177</string>
<string key="NS.object.0">2182</string>
</object>
<array key="IBDocument.IntegratedClassDependencies">
<string>NSTextField</string>
<string>NSTextFieldCell</string>
<string>NSWindowTemplate</string>
<string>NSView</string>
<string>IBNSLayoutConstraint</string>
<string>NSWindowTemplate</string>
<string>NSCustomObject</string>
<string>IBNSLayoutConstraint</string>
<string>NSButtonCell</string>
<string>NSButton</string>
<string>NSTextFieldCell</string>
</array>
<array key="IBDocument.PluginDependencies">
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
@ -55,7 +57,7 @@
<int key="NSvFlags">268</int>
<string key="NSFrame">{{140, 92}, {200, 22}}</string>
<reference key="NSSuperview" ref="258451033"/>
<reference key="NSNextKeyView" ref="226215720"/>
<reference key="NSNextKeyView" ref="524129387"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="NSEnabled">YES</bool>
@ -63,7 +65,7 @@
<int key="NSCellFlags">-1804468671</int>
<int key="NSCellFlags2">138413120</int>
<string key="NSContents"/>
<object class="NSFont" key="NSSupport">
<object class="NSFont" key="NSSupport" id="590895625">
<string key="NSName">LucidaGrande</string>
<double key="NSSize">13</double>
<int key="NSfFlags">1044</int>
@ -128,6 +130,30 @@
</object>
</object>
</object>
<object class="NSButton" id="524129387">
<reference key="NSNextResponder" ref="258451033"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{384, 85}, {82, 32}}</string>
<reference key="NSSuperview" ref="258451033"/>
<reference key="NSNextKeyView" ref="226215720"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="NSEnabled">YES</bool>
<object class="NSButtonCell" key="NSCell" id="1001833466">
<int key="NSCellFlags">67239424</int>
<int key="NSCellFlags2">134217728</int>
<string key="NSContents">Empty</string>
<reference key="NSSupport" ref="590895625"/>
<string key="NSCellIdentifier">_NS:9</string>
<reference key="NSControlView" ref="524129387"/>
<int key="NSButtonFlags">-2038284033</int>
<int key="NSButtonFlags2">129</int>
<string key="NSAlternateContents"/>
<string key="NSKeyEquivalent"/>
<int key="NSPeriodicDelay">200</int>
<int key="NSPeriodicInterval">25</int>
</object>
</object>
</array>
<string key="NSFrameSize">{480, 134}</string>
<reference key="NSSuperview"/>
@ -168,6 +194,14 @@
</object>
<int key="connectionID">42</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">empty:</string>
<reference key="source" ref="1001"/>
<reference key="destination" ref="524129387"/>
</object>
<int key="connectionID">48</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">delegate</string>
@ -385,6 +419,39 @@
</object>
<reference ref="226215720"/>
<reference ref="291791585"/>
<reference ref="524129387"/>
<object class="IBNSLayoutConstraint" id="118079668">
<reference key="firstItem" ref="258451033"/>
<int key="firstAttribute">6</int>
<int key="relation">0</int>
<reference key="secondItem" ref="524129387"/>
<int key="secondAttribute">6</int>
<float key="multiplier">1</float>
<object class="IBNSLayoutSymbolicConstant" key="constant">
<double key="value">20</double>
</object>
<float key="priority">1000</float>
<int key="scoringType">8</int>
<float key="scoringTypeFloat">29</float>
<int key="contentType">3</int>
<reference key="containingView" ref="258451033"/>
</object>
<object class="IBNSLayoutConstraint" id="840794562">
<reference key="firstItem" ref="524129387"/>
<int key="firstAttribute">11</int>
<int key="relation">0</int>
<reference key="secondItem" ref="291791585"/>
<int key="secondAttribute">11</int>
<float key="multiplier">1</float>
<object class="IBLayoutConstant" key="constant">
<double key="value">0.0</double>
</object>
<float key="priority">1000</float>
<int key="scoringType">6</int>
<float key="scoringTypeFloat">24</float>
<int key="contentType">2</int>
<reference key="containingView" ref="258451033"/>
</object>
</array>
<reference key="parent" ref="45434518"/>
</object>
@ -485,6 +552,29 @@
<reference key="object" ref="254722226"/>
<reference key="parent" ref="226215720"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">44</int>
<reference key="object" ref="524129387"/>
<array class="NSMutableArray" key="children">
<reference ref="1001833466"/>
</array>
<reference key="parent" ref="258451033"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">45</int>
<reference key="object" ref="1001833466"/>
<reference key="parent" ref="524129387"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">46</int>
<reference key="object" ref="118079668"/>
<reference key="parent" ref="258451033"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">47</int>
<reference key="object" ref="840794562"/>
<reference key="parent" ref="258451033"/>
</object>
</array>
</object>
<dictionary class="NSMutableDictionary" key="flattenedProperties">
@ -495,7 +585,7 @@
<boolean value="YES" key="22.IBNSWindowAutoPositionCentersVertical"/>
<string key="22.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES" key="22.NSWindowTemplate.visibleAtLaunch"/>
<array class="NSMutableArray" key="23.IBNSViewMetadataConstraints">
<array key="23.IBNSViewMetadataConstraints">
<reference ref="137127436"/>
<reference ref="582018795"/>
<reference ref="453166348"/>
@ -506,6 +596,8 @@
<reference ref="490796257"/>
<reference ref="51508433"/>
<reference ref="456428551"/>
<reference ref="118079668"/>
<reference ref="840794562"/>
</array>
<string key="23.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="24.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
@ -528,12 +620,17 @@
<string key="36.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="37.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="38.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="NO" key="44.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/>
<string key="44.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="45.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="46.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="47.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
</dictionary>
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
<nil key="activeLocalization"/>
<dictionary class="NSMutableDictionary" key="localizations"/>
<nil key="sourceID"/>
<int key="maxID">43</int>
<int key="maxID">48</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes"/>
<int key="IBDocument.localizationMode">0</int>

View File

@ -9,7 +9,7 @@
<key>CFBundleIconFile</key>
<string>iTunesArtwork-Rounded.png</string>
<key>CFBundleIdentifier</key>
<string>com.lyndir.lhunath.${PRODUCT_NAME:rfc1034identifier}</string>
<string>com.lyndir.lhunath.${PRODUCT_NAME:rfc1034identifier}.Mac</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
@ -17,11 +17,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<string>[auto]</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<string>[auto]</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.productivity</string>
<key>LSMinimumSystemVersion</key>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.ubiquity-container-identifiers</key>
<array>
<string>$(TeamIdentifierPrefix)com.lyndir.lhunath.MasterPassword.1</string>
</array>
<key>com.apple.security.app-sandbox</key>
<true/>
</dict>
</plist>

View File

@ -10,16 +10,6 @@
@interface MPAppDelegate : PearlAppDelegate
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
+ (NSManagedObjectModel *)managedObjectModel;
+ (NSManagedObjectContext *)managedObjectContext;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
- (void)showGuide;
- (void)loadKey:(BOOL)animated;

View File

@ -263,118 +263,6 @@
[TestFlight passCheckpoint:MPTestFlightCheckpointDeactivated];
}
+ (NSManagedObjectContext *)managedObjectContext {
return [[self get] managedObjectContext];
}
+ (NSManagedObjectModel *)managedObjectModel {
return [[self get] managedObjectModel];
}
- (void)saveContext {
[self.managedObjectContext performBlock:^{
NSError *error = nil;
if ([self.managedObjectContext hasChanges] && ![self.managedObjectContext save:&error])
err(@"Unresolved error %@", error);
}];
}
#pragma mark - Core Data stack
- (NSManagedObjectModel *)managedObjectModel {
if (__managedObjectModel)
return __managedObjectModel;
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MasterPassword" withExtension:@"momd"];
return __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
}
- (NSManagedObjectContext *)managedObjectContext {
if (__managedObjectContext)
return __managedObjectContext;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator) {
__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
__managedObjectContext.persistentStoreCoordinator = coordinator;
[[NSNotificationCenter defaultCenter] addObserverForName:NSPersistentStoreDidImportUbiquitousContentChangesNotification
object:coordinator
queue:nil
usingBlock:^(NSNotification *note) {
dbg(@"Ubiquitous content change: %@", note);
[__managedObjectContext performBlock:^{
[__managedObjectContext mergeChangesFromContextDidSaveNotification:note];
[[NSNotificationCenter defaultCenter] postNotification:
[NSNotification notificationWithName:MPNotificationStoreUpdated
object:self userInfo:[note userInfo]]];
}];
}];
}
return __managedObjectContext;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (__persistentStoreCoordinator)
return __persistentStoreCoordinator;
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MasterPassword.sqlite"];
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
[__persistentStoreCoordinator lock];
NSError *error = nil;
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL
options:[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[[[NSFileManager defaultManager]
URLForUbiquityContainerIdentifier:nil]
URLByAppendingPathComponent:@"store"
isDirectory:YES], NSPersistentStoreUbiquitousContentURLKey,
@"MasterPassword.store", NSPersistentStoreUbiquitousContentNameKey,
nil]
error:&error]) {
err(@"Unresolved error %@, %@", error, [error userInfo]);
#if DEBUG
wrn(@"Deleted datastore: %@", storeURL);
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
#endif
[TestFlight passCheckpoint:MPTestFlightCheckpointStoreIncompatible];
@throw [NSException exceptionWithName:error.domain reason:error.localizedDescription
userInfo:[NSDictionary dictionaryWithObject:error forKey:@"cause"]];
}
if (![[NSFileManager defaultManager] setAttributes:[NSDictionary dictionaryWithObject:NSFileProtectionComplete
forKey:NSFileProtectionKey]
ofItemAtPath:storeURL.path error:&error])
err(@"Unresolved error %@, %@", error, [error userInfo]);
[__persistentStoreCoordinator unlock];
return __persistentStoreCoordinator;
}
#pragma mark - Application's Documents directory
/**
Returns the URL to the application's Documents directory.
*/
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
#pragma mark - TestFlight

View File

@ -479,6 +479,7 @@
@"Go to %@ and set or change the password for your account to the password above.\n"
@"Do this right away: if you forget, you may have trouble remembering which password to use to log into the site later on.",
self.activeElement.name, self.activeElement.name)];
[[MPAppDelegate get] saveContext];
[self.searchDisplayController setActive:NO animated:YES];
self.searchDisplayController.searchBar.text = self.activeElement.name;

View File

@ -4,10 +4,8 @@
<dict>
<key>com.apple.developer.ubiquity-container-identifiers</key>
<array>
<string>$(TeamIdentifierPrefix)com.lyndir.lhunath.MasterPassword</string>
<string>$(TeamIdentifierPrefix)com.lyndir.lhunath.MasterPassword.1</string>
</array>
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
<string>$(TeamIdentifierPrefix)com.lyndir.lhunath.MasterPassword</string>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)com.lyndir.lhunath.MasterPassword</string>