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:
parent
26f8e086bb
commit
376953ae56
2
External/InAppSettingsKit
vendored
2
External/InAppSettingsKit
vendored
@ -1 +1 @@
|
||||
Subproject commit 5fd23fd728d2e6e3216c6c2bd5a807d5316966d1
|
||||
Subproject commit 3ae828f48a63e505bcef7a9a9a78df567706eebc
|
2
External/Pearl
vendored
2
External/Pearl
vendored
@ -1 +1 @@
|
||||
Subproject commit 5736ed0cb528aeabbad5cec1ae133c9002be2983
|
||||
Subproject commit e23abc67cd80ec03543eed48ffd97b30439b5c84
|
@ -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";
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -11,5 +11,6 @@
|
||||
@interface MPPasswordWindowController : NSWindowController <NSTextFieldDelegate>
|
||||
@property (weak) IBOutlet NSTextField *siteField;
|
||||
@property (weak) IBOutlet NSTextField *contentField;
|
||||
- (IBAction)empty:(id)sender;
|
||||
|
||||
@end
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
12
MasterPassword/MasterPassword.entitlements
Normal file
12
MasterPassword/MasterPassword.entitlements
Normal 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>
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user