Prepare key handling logic for sharing with OS X.
[MOVED] Key logic now in a common class extension on MPAppDelegate so it can be shared between iOS and OS X apps. [MOVED] MPConfig for sharing between iOS and OS X apps. [CHANGED] keyphrase -> key.
This commit is contained in:
parent
6bda70920b
commit
02ffa9611a
@ -13,6 +13,8 @@
|
|||||||
DA5BFA4B147E415C00F98B1E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
DA5BFA4B147E415C00F98B1E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
||||||
DA5BFA4D147E415C00F98B1E /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */; };
|
DA5BFA4D147E415C00F98B1E /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */; };
|
||||||
DA5BFA4F147E415C00F98B1E /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4E147E415C00F98B1E /* CoreData.framework */; };
|
DA5BFA4F147E415C00F98B1E /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4E147E415C00F98B1E /* CoreData.framework */; };
|
||||||
|
DA600C2515054F3A008E9AB6 /* MPAppDelegate_Key.m in Sources */ = {isa = PBXBuildFile; fileRef = DA600C2315054F3A008E9AB6 /* MPAppDelegate_Key.m */; };
|
||||||
|
DA600C2815056428008E9AB6 /* MPConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = DA600C2715056427008E9AB6 /* MPConfig.m */; };
|
||||||
DA672D2F14F92C6B004A189C /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DA672D2E14F92C6B004A189C /* libz.dylib */; };
|
DA672D2F14F92C6B004A189C /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DA672D2E14F92C6B004A189C /* libz.dylib */; };
|
||||||
DA672D3014F9413D004A189C /* libPearl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC77CAD148291A600BCF976 /* libPearl.a */; };
|
DA672D3014F9413D004A189C /* libPearl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC77CAD148291A600BCF976 /* libPearl.a */; };
|
||||||
DA95D59D14DF063C008D1B94 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
DA95D59D14DF063C008D1B94 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
||||||
@ -61,7 +63,7 @@
|
|||||||
DAB8D46015036BCF00CED3BC /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAB8D44215036BCF00CED3BC /* MainStoryboard_iPhone.storyboard */; };
|
DAB8D46015036BCF00CED3BC /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAB8D44215036BCF00CED3BC /* MainStoryboard_iPhone.storyboard */; };
|
||||||
DAB8D46215036BCF00CED3BC /* MasterPassword.entitlements in Resources */ = {isa = PBXBuildFile; fileRef = DAB8D44515036BCF00CED3BC /* MasterPassword.entitlements */; };
|
DAB8D46215036BCF00CED3BC /* MasterPassword.entitlements in Resources */ = {isa = PBXBuildFile; fileRef = DAB8D44515036BCF00CED3BC /* MasterPassword.entitlements */; };
|
||||||
DAB8D46315036BCF00CED3BC /* MPAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44715036BCF00CED3BC /* MPAppDelegate.m */; };
|
DAB8D46315036BCF00CED3BC /* MPAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44715036BCF00CED3BC /* MPAppDelegate.m */; };
|
||||||
DAB8D46415036BCF00CED3BC /* MPConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44915036BCF00CED3BC /* MPConfig.m */; };
|
DAB8D46415036BCF00CED3BC /* MPiOSConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44915036BCF00CED3BC /* MPiOSConfig.m */; };
|
||||||
DAB8D46515036BCF00CED3BC /* MPGuideViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44B15036BCF00CED3BC /* MPGuideViewController.m */; };
|
DAB8D46515036BCF00CED3BC /* MPGuideViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44B15036BCF00CED3BC /* MPGuideViewController.m */; };
|
||||||
DAB8D46615036BCF00CED3BC /* MPMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44D15036BCF00CED3BC /* MPMainViewController.m */; };
|
DAB8D46615036BCF00CED3BC /* MPMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44D15036BCF00CED3BC /* MPMainViewController.m */; };
|
||||||
DAB8D46715036BCF00CED3BC /* MPSearchDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44F15036BCF00CED3BC /* MPSearchDelegate.m */; };
|
DAB8D46715036BCF00CED3BC /* MPSearchDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44F15036BCF00CED3BC /* MPSearchDelegate.m */; };
|
||||||
@ -841,6 +843,10 @@
|
|||||||
DA5BFA4A147E415C00F98B1E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
DA5BFA4A147E415C00F98B1E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||||
DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
||||||
DA5BFA4E147E415C00F98B1E /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
|
DA5BFA4E147E415C00F98B1E /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
|
||||||
|
DA600C2315054F3A008E9AB6 /* MPAppDelegate_Key.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppDelegate_Key.m; sourceTree = "<group>"; };
|
||||||
|
DA600C2415054F3A008E9AB6 /* MPAppDelegate_Key.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppDelegate_Key.h; sourceTree = "<group>"; };
|
||||||
|
DA600C2615056427008E9AB6 /* MPConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MPConfig.h; path = MasterPassword/MPConfig.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
DA600C2715056427008E9AB6 /* MPConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MPConfig.m; path = MasterPassword/MPConfig.m; sourceTree = SOURCE_ROOT; };
|
||||||
DA672D2E14F92C6B004A189C /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
|
DA672D2E14F92C6B004A189C /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
|
||||||
DA95D59C14DF063C008D1B94 /* libInAppSettingsKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libInAppSettingsKit.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
DA95D59C14DF063C008D1B94 /* libInAppSettingsKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libInAppSettingsKit.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
DA95D5A814DF0691008D1B94 /* IASKAppSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKAppSettingsViewController.h; sourceTree = "<group>"; };
|
DA95D5A814DF0691008D1B94 /* IASKAppSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKAppSettingsViewController.h; sourceTree = "<group>"; };
|
||||||
@ -891,8 +897,8 @@
|
|||||||
DAB8D44515036BCF00CED3BC /* MasterPassword.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = MasterPassword.entitlements; sourceTree = "<group>"; };
|
DAB8D44515036BCF00CED3BC /* MasterPassword.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = MasterPassword.entitlements; sourceTree = "<group>"; };
|
||||||
DAB8D44615036BCF00CED3BC /* MPAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppDelegate.h; sourceTree = "<group>"; };
|
DAB8D44615036BCF00CED3BC /* MPAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppDelegate.h; sourceTree = "<group>"; };
|
||||||
DAB8D44715036BCF00CED3BC /* MPAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppDelegate.m; sourceTree = "<group>"; };
|
DAB8D44715036BCF00CED3BC /* MPAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppDelegate.m; sourceTree = "<group>"; };
|
||||||
DAB8D44815036BCF00CED3BC /* MPConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPConfig.h; sourceTree = "<group>"; };
|
DAB8D44815036BCF00CED3BC /* MPiOSConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPiOSConfig.h; sourceTree = "<group>"; };
|
||||||
DAB8D44915036BCF00CED3BC /* MPConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPConfig.m; sourceTree = "<group>"; };
|
DAB8D44915036BCF00CED3BC /* MPiOSConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPiOSConfig.m; sourceTree = "<group>"; };
|
||||||
DAB8D44A15036BCF00CED3BC /* MPGuideViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPGuideViewController.h; sourceTree = "<group>"; };
|
DAB8D44A15036BCF00CED3BC /* MPGuideViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPGuideViewController.h; sourceTree = "<group>"; };
|
||||||
DAB8D44B15036BCF00CED3BC /* MPGuideViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPGuideViewController.m; sourceTree = "<group>"; };
|
DAB8D44B15036BCF00CED3BC /* MPGuideViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPGuideViewController.m; sourceTree = "<group>"; };
|
||||||
DAB8D44C15036BCF00CED3BC /* MPMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPMainViewController.h; sourceTree = "<group>"; };
|
DAB8D44C15036BCF00CED3BC /* MPMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPMainViewController.h; sourceTree = "<group>"; };
|
||||||
@ -1754,6 +1760,10 @@
|
|||||||
children = (
|
children = (
|
||||||
DAB8D43C15036BCF00CED3BC /* MasterPassword.xcdatamodeld */,
|
DAB8D43C15036BCF00CED3BC /* MasterPassword.xcdatamodeld */,
|
||||||
DAB8D43E15036BCF00CED3BC /* iOS */,
|
DAB8D43E15036BCF00CED3BC /* iOS */,
|
||||||
|
DA600C2415054F3A008E9AB6 /* MPAppDelegate_Key.h */,
|
||||||
|
DA600C2315054F3A008E9AB6 /* MPAppDelegate_Key.m */,
|
||||||
|
DA600C2615056427008E9AB6 /* MPConfig.h */,
|
||||||
|
DA600C2715056427008E9AB6 /* MPConfig.m */,
|
||||||
DAB8D45515036BCF00CED3BC /* MPElementStoredEntity.m */,
|
DAB8D45515036BCF00CED3BC /* MPElementStoredEntity.m */,
|
||||||
DAB8D45615036BCF00CED3BC /* MPTypes.m */,
|
DAB8D45615036BCF00CED3BC /* MPTypes.m */,
|
||||||
DAB8D45715036BCF00CED3BC /* MPElementEntity.h */,
|
DAB8D45715036BCF00CED3BC /* MPElementEntity.h */,
|
||||||
@ -1862,8 +1872,8 @@
|
|||||||
DAB8D44215036BCF00CED3BC /* MainStoryboard_iPhone.storyboard */,
|
DAB8D44215036BCF00CED3BC /* MainStoryboard_iPhone.storyboard */,
|
||||||
DAB8D44615036BCF00CED3BC /* MPAppDelegate.h */,
|
DAB8D44615036BCF00CED3BC /* MPAppDelegate.h */,
|
||||||
DAB8D44715036BCF00CED3BC /* MPAppDelegate.m */,
|
DAB8D44715036BCF00CED3BC /* MPAppDelegate.m */,
|
||||||
DAB8D44815036BCF00CED3BC /* MPConfig.h */,
|
DAB8D44815036BCF00CED3BC /* MPiOSConfig.h */,
|
||||||
DAB8D44915036BCF00CED3BC /* MPConfig.m */,
|
DAB8D44915036BCF00CED3BC /* MPiOSConfig.m */,
|
||||||
DAB8D44A15036BCF00CED3BC /* MPGuideViewController.h */,
|
DAB8D44A15036BCF00CED3BC /* MPGuideViewController.h */,
|
||||||
DAB8D44B15036BCF00CED3BC /* MPGuideViewController.m */,
|
DAB8D44B15036BCF00CED3BC /* MPGuideViewController.m */,
|
||||||
DAB8D44C15036BCF00CED3BC /* MPMainViewController.h */,
|
DAB8D44C15036BCF00CED3BC /* MPMainViewController.h */,
|
||||||
@ -3675,7 +3685,7 @@
|
|||||||
DAB8D45D15036BCF00CED3BC /* MasterPassword.xcdatamodeld in Sources */,
|
DAB8D45D15036BCF00CED3BC /* MasterPassword.xcdatamodeld in Sources */,
|
||||||
DAB8D45F15036BCF00CED3BC /* main.m in Sources */,
|
DAB8D45F15036BCF00CED3BC /* main.m in Sources */,
|
||||||
DAB8D46315036BCF00CED3BC /* MPAppDelegate.m in Sources */,
|
DAB8D46315036BCF00CED3BC /* MPAppDelegate.m in Sources */,
|
||||||
DAB8D46415036BCF00CED3BC /* MPConfig.m in Sources */,
|
DAB8D46415036BCF00CED3BC /* MPiOSConfig.m in Sources */,
|
||||||
DAB8D46515036BCF00CED3BC /* MPGuideViewController.m in Sources */,
|
DAB8D46515036BCF00CED3BC /* MPGuideViewController.m in Sources */,
|
||||||
DAB8D46615036BCF00CED3BC /* MPMainViewController.m in Sources */,
|
DAB8D46615036BCF00CED3BC /* MPMainViewController.m in Sources */,
|
||||||
DAB8D46715036BCF00CED3BC /* MPSearchDelegate.m in Sources */,
|
DAB8D46715036BCF00CED3BC /* MPSearchDelegate.m in Sources */,
|
||||||
@ -3685,6 +3695,8 @@
|
|||||||
DAB8D46C15036BCF00CED3BC /* MPTypes.m in Sources */,
|
DAB8D46C15036BCF00CED3BC /* MPTypes.m in Sources */,
|
||||||
DAB8D46D15036BCF00CED3BC /* MPElementEntity.m in Sources */,
|
DAB8D46D15036BCF00CED3BC /* MPElementEntity.m in Sources */,
|
||||||
DAB8D46E15036BCF00CED3BC /* MPElementGeneratedEntity.m in Sources */,
|
DAB8D46E15036BCF00CED3BC /* MPElementGeneratedEntity.m in Sources */,
|
||||||
|
DA600C2515054F3A008E9AB6 /* MPAppDelegate_Key.m in Sources */,
|
||||||
|
DA600C2815056428008E9AB6 /* MPConfig.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
33
MasterPassword/MPAppDelegate_Key.h
Normal file
33
MasterPassword/MPAppDelegate_Key.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// MPAppDelegate_Key.h
|
||||||
|
// MasterPassword
|
||||||
|
//
|
||||||
|
// Created by Maarten Billemont on 24/11/11.
|
||||||
|
// Copyright (c) 2011 Lyndir. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import "MPAppDelegate.h"
|
||||||
|
|
||||||
|
@interface MPAppDelegate ()
|
||||||
|
|
||||||
|
@property (strong, nonatomic) NSData *key;
|
||||||
|
@property (strong, nonatomic) NSData *keyHash;
|
||||||
|
@property (strong, nonatomic) NSString *keyHashHex;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MPAppDelegate (Key)
|
||||||
|
|
||||||
|
+ (MPAppDelegate *)get;
|
||||||
|
|
||||||
|
- (void)loadStoredKey;
|
||||||
|
- (void)signOut;
|
||||||
|
|
||||||
|
- (BOOL)tryMasterPassword:(NSString *)tryPassword;
|
||||||
|
- (void)updateKey:(NSData *)key;
|
||||||
|
- (void)forgetKey;
|
||||||
|
|
||||||
|
- (NSData *)keyWithLength:(NSUInteger)keyLength;
|
||||||
|
|
||||||
|
@end
|
148
MasterPassword/MPAppDelegate_Key.m
Normal file
148
MasterPassword/MPAppDelegate_Key.m
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
//
|
||||||
|
// MPAppDelegate.m
|
||||||
|
// MasterPassword
|
||||||
|
//
|
||||||
|
// Created by Maarten Billemont on 24/11/11.
|
||||||
|
// Copyright (c) 2011 Lyndir. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPAppDelegate_Key.h"
|
||||||
|
|
||||||
|
#import "MPMainViewController.h"
|
||||||
|
#import "IASKSettingsReader.h"
|
||||||
|
|
||||||
|
@implementation MPAppDelegate (Key)
|
||||||
|
|
||||||
|
static NSDictionary *keyQuery() {
|
||||||
|
|
||||||
|
static NSDictionary *MPKeyQuery = nil;
|
||||||
|
if (!MPKeyQuery)
|
||||||
|
MPKeyQuery = [PearlKeyChain createQueryForClass:kSecClassGenericPassword
|
||||||
|
attributes:[NSDictionary dictionaryWithObject:@"Master Password Key"
|
||||||
|
forKey:(__bridge id)kSecAttrService]
|
||||||
|
matches:nil];
|
||||||
|
|
||||||
|
return MPKeyQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NSDictionary *keyHashQuery() {
|
||||||
|
|
||||||
|
static NSDictionary *MPKeyHashQuery = nil;
|
||||||
|
if (!MPKeyHashQuery)
|
||||||
|
MPKeyHashQuery = [PearlKeyChain createQueryForClass:kSecClassGenericPassword
|
||||||
|
attributes:[NSDictionary dictionaryWithObject:@"Master Password Key Hash"
|
||||||
|
forKey:(__bridge id)kSecAttrService]
|
||||||
|
matches:nil];
|
||||||
|
|
||||||
|
return MPKeyHashQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)forgetKey {
|
||||||
|
|
||||||
|
dbg(@"Deleting master key and hash from key chain.");
|
||||||
|
[PearlKeyChain deleteItemForQuery:keyQuery()];
|
||||||
|
[PearlKeyChain deleteItemForQuery:keyHashQuery()];
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyForgotten object:self];
|
||||||
|
#ifndef PRODUCTION
|
||||||
|
[TestFlight passCheckpoint:MPTestFlightCheckpointMPForgotten];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)signOut {
|
||||||
|
|
||||||
|
[self updateKey:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)loadStoredKey {
|
||||||
|
|
||||||
|
if ([[MPiOSConfig get].storeKey boolValue]) {
|
||||||
|
// Key is stored in keychain. Load it.
|
||||||
|
dbg(@"Loading key from key chain.");
|
||||||
|
[self updateKey:[PearlKeyChain dataOfItemForQuery:keyQuery()]];
|
||||||
|
dbg(@" -> Key %@.", self.key? @"found": @"NOT found");
|
||||||
|
} else {
|
||||||
|
// Key should not be stored in keychain. Delete it.
|
||||||
|
dbg(@"Deleting key from key chain.");
|
||||||
|
[PearlKeyChain deleteItemForQuery:keyQuery()];
|
||||||
|
#ifndef PRODUCTION
|
||||||
|
[TestFlight passCheckpoint:MPTestFlightCheckpointMPUnstored];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (MPAppDelegate *)get {
|
||||||
|
|
||||||
|
return (MPAppDelegate *)[super get];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)tryMasterPassword:(NSString *)tryPassword {
|
||||||
|
|
||||||
|
NSData *keyHash = [PearlKeyChain dataOfItemForQuery:keyHashQuery()];
|
||||||
|
dbg(@"Key hash %@.", keyHash? @"known": @"NOT known");
|
||||||
|
|
||||||
|
if (![tryPassword length])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
NSData *tryKey = keyForPassword(tryPassword);
|
||||||
|
NSData *tryKeyHash = keyHashForKey(tryKey);
|
||||||
|
if (keyHash)
|
||||||
|
// A key hash is known -> a key is set.
|
||||||
|
// Make sure the user's entered key matches it.
|
||||||
|
if (![keyHash isEqual:tryKeyHash]) {
|
||||||
|
dbg(@"Key phrase hash mismatch. Expected: %@, answer: %@.", keyHash, tryKeyHash);
|
||||||
|
|
||||||
|
#ifndef PRODUCTION
|
||||||
|
[TestFlight passCheckpoint:MPTestFlightCheckpointMPMismatch];
|
||||||
|
#endif
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PRODUCTION
|
||||||
|
[TestFlight passCheckpoint:MPTestFlightCheckpointMPAsked];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[self updateKey:tryKey];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateKey:(NSData *)key {
|
||||||
|
|
||||||
|
self.key = key;
|
||||||
|
|
||||||
|
if (key)
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeySet object:self];
|
||||||
|
else
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyUnset object:self];
|
||||||
|
|
||||||
|
if (key) {
|
||||||
|
self.keyHash = keyHashForKey(key);
|
||||||
|
self.keyHashHex = [self.keyHash encodeHex];
|
||||||
|
|
||||||
|
dbg(@"Updating key hash to: %@.", self.keyHashHex);
|
||||||
|
[PearlKeyChain addOrUpdateItemForQuery:keyHashQuery()
|
||||||
|
withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
self.keyHash, (__bridge id)kSecValueData,
|
||||||
|
kSecAttrAccessibleWhenUnlocked, (__bridge id)kSecAttrAccessible,
|
||||||
|
nil]];
|
||||||
|
if ([[MPiOSConfig get].storeKey boolValue]) {
|
||||||
|
dbg(@"Storing key in key chain.");
|
||||||
|
[PearlKeyChain addOrUpdateItemForQuery:keyQuery()
|
||||||
|
withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
key, (__bridge id)kSecValueData,
|
||||||
|
kSecAttrAccessibleWhenUnlocked, (__bridge id)kSecAttrAccessible,
|
||||||
|
nil]];
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PRODUCTION
|
||||||
|
[TestFlight passCheckpoint:[NSString stringWithFormat:MPTestFlightCheckpointSetKeyphraseLength, key.length]];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSData *)keyWithLength:(NSUInteger)keyLength {
|
||||||
|
|
||||||
|
return [self.key subdataWithRange:NSMakeRange(0, MIN(keyLength, self.key.length))];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
@ -9,10 +9,8 @@
|
|||||||
@interface MPConfig : PearlConfig
|
@interface MPConfig : PearlConfig
|
||||||
|
|
||||||
@property (nonatomic, retain) NSNumber *dataStoreError;
|
@property (nonatomic, retain) NSNumber *dataStoreError;
|
||||||
@property (nonatomic, retain) NSNumber *storeKeyPhrase;
|
@property (nonatomic, retain) NSNumber *storeKey;
|
||||||
@property (nonatomic, retain) NSNumber *rememberKeyPhrase;
|
@property (nonatomic, retain) NSNumber *rememberKey;
|
||||||
@property (nonatomic, retain) NSNumber *helpHidden;
|
|
||||||
@property (nonatomic, retain) NSNumber *showQuickStart;
|
|
||||||
|
|
||||||
+ (MPConfig *)get;
|
+ (MPConfig *)get;
|
||||||
|
|
@ -9,7 +9,7 @@
|
|||||||
#import "MPConfig.h"
|
#import "MPConfig.h"
|
||||||
|
|
||||||
@implementation MPConfig
|
@implementation MPConfig
|
||||||
@dynamic dataStoreError, storeKeyPhrase, rememberKeyPhrase, helpHidden, showQuickStart;
|
@dynamic dataStoreError, storeKey, rememberKey;
|
||||||
|
|
||||||
- (id)init {
|
- (id)init {
|
||||||
|
|
||||||
@ -18,10 +18,8 @@
|
|||||||
|
|
||||||
[self.defaults registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
|
[self.defaults registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(dataStoreError)),
|
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(dataStoreError)),
|
||||||
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(storeKeyPhrase)),
|
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(storeKey)),
|
||||||
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(rememberKeyPhrase)),
|
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(rememberKey)),
|
||||||
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(helpHidden)),
|
|
||||||
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(showQuickStart)),
|
|
||||||
nil]];
|
nil]];
|
||||||
|
|
||||||
return self;
|
return self;
|
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "MPElementGeneratedEntity.h"
|
#import "MPElementGeneratedEntity.h"
|
||||||
#import "MPAppDelegate.h"
|
#import "MPAppDelegate_Key.h"
|
||||||
|
|
||||||
|
|
||||||
@implementation MPElementGeneratedEntity
|
@implementation MPElementGeneratedEntity
|
||||||
@ -22,7 +22,7 @@
|
|||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
if (self.type & MPElementTypeClassCalculated)
|
if (self.type & MPElementTypeClassCalculated)
|
||||||
return MPCalculateContent(self.type, self.name, [MPAppDelegate get].keyPhrase, self.counter);
|
return MPCalculateContent(self.type, self.name, [MPAppDelegate get].key, self.counter);
|
||||||
|
|
||||||
@throw [NSException exceptionWithName:NSInternalInconsistencyException
|
@throw [NSException exceptionWithName:NSInternalInconsistencyException
|
||||||
reason:[NSString stringWithFormat:@"Unsupported type: %d", self.type] userInfo:nil];
|
reason:[NSString stringWithFormat:@"Unsupported type: %d", self.type] userInfo:nil];
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "MPElementStoredEntity.h"
|
#import "MPElementStoredEntity.h"
|
||||||
#import "MPAppDelegate.h"
|
#import "MPAppDelegate_Key.h"
|
||||||
|
|
||||||
@interface MPElementStoredEntity ()
|
@interface MPElementStoredEntity ()
|
||||||
|
|
||||||
@ -39,14 +39,14 @@
|
|||||||
else
|
else
|
||||||
encryptedContent = self.contentObject;
|
encryptedContent = self.contentObject;
|
||||||
|
|
||||||
NSData *decryptedContent = [encryptedContent decryptWithSymmetricKey:[[MPAppDelegate get] keyPhraseWithLength:PearlCryptKeySize]
|
NSData *decryptedContent = [encryptedContent decryptWithSymmetricKey:[[MPAppDelegate get] keyWithLength:PearlCryptKeySize]
|
||||||
usePadding:YES];
|
usePadding:YES];
|
||||||
return [[NSString alloc] initWithBytes:decryptedContent.bytes length:decryptedContent.length encoding:NSUTF8StringEncoding];
|
return [[NSString alloc] initWithBytes:decryptedContent.bytes length:decryptedContent.length encoding:NSUTF8StringEncoding];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setContent:(id)content {
|
- (void)setContent:(id)content {
|
||||||
|
|
||||||
NSData *encryptedContent = [[content description] encryptWithSymmetricKey:[[MPAppDelegate get] keyPhraseWithLength:PearlCryptKeySize]
|
NSData *encryptedContent = [[content description] encryptWithSymmetricKey:[[MPAppDelegate get] keyWithLength:PearlCryptKeySize]
|
||||||
usePadding:YES];
|
usePadding:YES];
|
||||||
|
|
||||||
if (self.type == MPElementTypeStoredDevicePrivate) {
|
if (self.type == MPElementTypeStoredDevicePrivate) {
|
||||||
|
@ -63,10 +63,10 @@ typedef enum {
|
|||||||
#define MPNotificationKeyUnset @"MPNotificationKeyUnset"
|
#define MPNotificationKeyUnset @"MPNotificationKeyUnset"
|
||||||
#define MPNotificationKeyForgotten @"MPNotificationKeyForgotten"
|
#define MPNotificationKeyForgotten @"MPNotificationKeyForgotten"
|
||||||
|
|
||||||
NSData *keyPhraseForPassword(NSString *password);
|
NSData *keyForPassword(NSString *password);
|
||||||
NSData *keyPhraseHashForPassword(NSString *password);
|
NSData *keyHashForPassword(NSString *password);
|
||||||
NSData *keyPhraseHashForKeyPhrase(NSData *keyPhrase);
|
NSData *keyHashForKey(NSData *key);
|
||||||
NSString *NSStringFromMPElementType(MPElementType type);
|
NSString *NSStringFromMPElementType(MPElementType type);
|
||||||
NSString *ClassNameFromMPElementType(MPElementType type);
|
NSString *ClassNameFromMPElementType(MPElementType type);
|
||||||
Class ClassFromMPElementType(MPElementType type);
|
Class ClassFromMPElementType(MPElementType type);
|
||||||
NSString *MPCalculateContent(MPElementType type, NSString *name, NSData *keyPhrase, uint16_t counter);
|
NSString *MPCalculateContent(MPElementType type, NSString *name, NSData *key, uint16_t counter);
|
||||||
|
@ -17,18 +17,18 @@
|
|||||||
#define MP_dkLen 64
|
#define MP_dkLen 64
|
||||||
#define MP_hash PearlDigestSHA256
|
#define MP_hash PearlDigestSHA256
|
||||||
|
|
||||||
NSData *keyPhraseForPassword(NSString *password) {
|
NSData *keyForPassword(NSString *password) {
|
||||||
|
|
||||||
return [PearlSCrypt deriveKeyWithLength:MP_dkLen fromPassword:[password dataUsingEncoding:NSUTF8StringEncoding]
|
return [PearlSCrypt deriveKeyWithLength:MP_dkLen fromPassword:[password dataUsingEncoding:NSUTF8StringEncoding]
|
||||||
usingSalt:MP_salt N:MP_N r:MP_r p:MP_p];
|
usingSalt:MP_salt N:MP_N r:MP_r p:MP_p];
|
||||||
}
|
}
|
||||||
NSData *keyPhraseHashForPassword(NSString *password) {
|
NSData *keyHashForPassword(NSString *password) {
|
||||||
|
|
||||||
return keyPhraseHashForKeyPhrase(keyPhraseForPassword(password));
|
return keyHashForKey(keyForPassword(password));
|
||||||
}
|
}
|
||||||
NSData *keyPhraseHashForKeyPhrase(NSData *keyPhrase) {
|
NSData *keyHashForKey(NSData *key) {
|
||||||
|
|
||||||
return [keyPhrase hashWith:MP_hash];
|
return [key hashWith:MP_hash];
|
||||||
}
|
}
|
||||||
NSString *NSStringFromMPElementType(MPElementType type) {
|
NSString *NSStringFromMPElementType(MPElementType type) {
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ NSString *ClassNameFromMPElementType(MPElementType type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NSDictionary *MPTypes_ciphers = nil;
|
static NSDictionary *MPTypes_ciphers = nil;
|
||||||
NSString *MPCalculateContent(MPElementType type, NSString *name, NSData *keyPhrase, uint16_t counter) {
|
NSString *MPCalculateContent(MPElementType type, NSString *name, NSData *key, uint16_t counter) {
|
||||||
|
|
||||||
assert(type & MPElementTypeClassCalculated);
|
assert(type & MPElementTypeClassCalculated);
|
||||||
|
|
||||||
@ -108,12 +108,12 @@ NSString *MPCalculateContent(MPElementType type, NSString *name, NSData *keyPhra
|
|||||||
MPTypes_ciphers = [NSDictionary dictionaryWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"ciphers"
|
MPTypes_ciphers = [NSDictionary dictionaryWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"ciphers"
|
||||||
withExtension:@"plist"]];
|
withExtension:@"plist"]];
|
||||||
|
|
||||||
// Determine the hash whose bytes will be used for calculating a password: md4(name-keyPhrase)
|
// Determine the hash whose bytes will be used for calculating a password: md4(name-key)
|
||||||
assert(name && keyPhrase);
|
assert(name && key);
|
||||||
uint16_t ncounter = htons(counter);
|
uint16_t ncounter = htons(counter);
|
||||||
NSData *keyHash = [[NSData dataByConcatenatingWithDelimitor:'-' datas:
|
NSData *keyHash = [[NSData dataByConcatenatingWithDelimitor:'-' datas:
|
||||||
[name dataUsingEncoding:NSUTF8StringEncoding],
|
[name dataUsingEncoding:NSUTF8StringEncoding],
|
||||||
keyPhrase,
|
key,
|
||||||
[NSData dataWithBytes:&ncounter length:sizeof(ncounter)],
|
[NSData dataWithBytes:&ncounter length:sizeof(ncounter)],
|
||||||
nil] hashWith:PearlDigestSHA1];
|
nil] hashWith:PearlDigestSHA1];
|
||||||
const char *keyBytes = keyHash.bytes;
|
const char *keyBytes = keyHash.bytes;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import "MPPasswordWindowController.h"
|
||||||
|
|
||||||
@interface MPAppDelegate : NSObject <NSApplicationDelegate>
|
@interface MPAppDelegate : NSObject <NSApplicationDelegate>
|
||||||
|
|
||||||
@ -16,9 +17,13 @@
|
|||||||
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
|
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
|
||||||
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
|
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
|
||||||
|
|
||||||
|
@property (readonly, strong, nonatomic) MPPasswordWindowController *passwordWindow;
|
||||||
@property (readonly, strong, nonatomic) NSData *keyPhrase;
|
@property (readonly, strong, nonatomic) NSData *keyPhrase;
|
||||||
|
@property (readonly, strong, nonatomic) NSString *keyPhraseHashHex;
|
||||||
|
|
||||||
+ (MPAppDelegate *)get;
|
+ (MPAppDelegate *)get;
|
||||||
|
+ (NSManagedObjectModel *)managedObjectModel;
|
||||||
|
+ (NSManagedObjectContext *)managedObjectContext;
|
||||||
|
|
||||||
- (IBAction)saveAction:(id)sender;
|
- (IBAction)saveAction:(id)sender;
|
||||||
- (NSData *)keyPhraseWithLength:(NSUInteger)keyLength;
|
- (NSData *)keyPhraseWithLength:(NSUInteger)keyLength;
|
||||||
|
@ -8,12 +8,18 @@
|
|||||||
|
|
||||||
#import "MPAppDelegate.h"
|
#import "MPAppDelegate.h"
|
||||||
|
|
||||||
@implementation MPAppDelegate
|
@interface MPAppDelegate ()
|
||||||
|
|
||||||
|
@property (readwrite, strong, nonatomic) MPPasswordWindowController *passwordWindow;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPAppDelegate
|
||||||
@synthesize window = _window;
|
@synthesize window = _window;
|
||||||
@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
|
@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
|
||||||
@synthesize managedObjectModel = __managedObjectModel;
|
@synthesize managedObjectModel = __managedObjectModel;
|
||||||
@synthesize managedObjectContext = __managedObjectContext;
|
@synthesize managedObjectContext = __managedObjectContext;
|
||||||
|
@synthesize passwordWindow;
|
||||||
@synthesize keyPhrase;
|
@synthesize keyPhrase;
|
||||||
|
|
||||||
+ (MPAppDelegate *)get {
|
+ (MPAppDelegate *)get {
|
||||||
@ -21,9 +27,25 @@
|
|||||||
return (MPAppDelegate *)[NSApplication sharedApplication].delegate;
|
return (MPAppDelegate *)[NSApplication sharedApplication].delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
+ (NSManagedObjectContext *)managedObjectContext {
|
||||||
{
|
|
||||||
// Insert code here to initialize your application
|
return [[self get] managedObjectContext];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSManagedObjectModel *)managedObjectModel {
|
||||||
|
|
||||||
|
return [[self get] managedObjectModel];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidBecomeActive:(NSNotification *)notification {
|
||||||
|
|
||||||
|
if (!self.passwordWindow)
|
||||||
|
self.passwordWindow = [[MPPasswordWindowController alloc] initWithWindowNibName:@"MPPasswordWindowController"];
|
||||||
|
[self.passwordWindow showWindow:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURL *)applicationFilesDirectory {
|
- (NSURL *)applicationFilesDirectory {
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
@interface MPPasswordWindowController : NSWindowController
|
@interface MPPasswordWindowController : NSWindowController <NSTextFieldDelegate>
|
||||||
@property (weak) IBOutlet NSTextField *siteField;
|
@property (weak) IBOutlet NSTextField *siteField;
|
||||||
@property (weak) IBOutlet NSTextField *contentField;
|
@property (weak) IBOutlet NSTextField *contentField;
|
||||||
|
|
||||||
|
@ -7,20 +7,58 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "MPPasswordWindowController.h"
|
#import "MPPasswordWindowController.h"
|
||||||
|
#import "MPAppDelegate.h"
|
||||||
|
|
||||||
@interface MPPasswordWindowController ()
|
@interface MPPasswordWindowController ()
|
||||||
|
|
||||||
|
@property (nonatomic, assign) BOOL completingSiteName;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation MPPasswordWindowController
|
@implementation MPPasswordWindowController
|
||||||
|
@synthesize completingSiteName;
|
||||||
@synthesize siteField;
|
@synthesize siteField;
|
||||||
@synthesize contentField;
|
@synthesize contentField;
|
||||||
|
|
||||||
- (void)windowDidLoad {
|
- (void)windowDidLoad {
|
||||||
|
|
||||||
[super windowDidLoad];
|
|
||||||
|
|
||||||
[self.contentField setStringValue:@""];
|
[self.contentField setStringValue:@""];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillCloseNotification object:self.window queue:nil
|
||||||
|
usingBlock:^(NSNotification *note) {
|
||||||
|
[[NSApplication sharedApplication] hide:self];
|
||||||
|
}];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserverForName:NSControlTextDidChangeNotification object:self.siteField queue:nil
|
||||||
|
usingBlock:^(NSNotification *note) {
|
||||||
|
if (!self.completingSiteName) {
|
||||||
|
self.completingSiteName = YES;
|
||||||
|
[[[note userInfo] objectForKey:@"NSFieldEditor"] complete:nil];
|
||||||
|
self.completingSiteName = NO;
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
[super windowDidLoad];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray *)control:(NSControl *)control textView:(NSTextView *)textView completions:(NSArray *)words forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index {
|
||||||
|
|
||||||
|
NSString *query = [[control stringValue] substringWithRange:charRange];
|
||||||
|
NSFetchRequest *fetchRequest = [MPAppDelegate.managedObjectModel
|
||||||
|
fetchRequestFromTemplateWithName:@"MPElements"
|
||||||
|
substitutionVariables:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
query, @"query",
|
||||||
|
[MPAppDelegate get].keyPhraseHashHex, @"mpHashHex",
|
||||||
|
nil]];
|
||||||
|
|
||||||
|
return [NSArray arrayWithObjects:@"cow", @"milk", @"hippopotamus", nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)controlTextDidEndEditing:(NSNotification *)obj {
|
||||||
|
|
||||||
|
if (obj.object == self.siteField) {
|
||||||
|
// NSString *siteName = [self.siteField stringValue];
|
||||||
|
|
||||||
|
// [self.contentField setStringValue:];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
<string key="NSClassName">NSApplication</string>
|
<string key="NSClassName">NSApplication</string>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSWindowTemplate" id="45434518">
|
<object class="NSWindowTemplate" id="45434518">
|
||||||
<int key="NSWindowStyleMask">8223</int>
|
<int key="NSWindowStyleMask">8215</int>
|
||||||
<int key="NSWindowBacking">2</int>
|
<int key="NSWindowBacking">2</int>
|
||||||
<string key="NSWindowRect">{{600, 530}, {480, 134}}</string>
|
<string key="NSWindowRect">{{600, 530}, {480, 134}}</string>
|
||||||
<int key="NSWTFlags">611845120</int>
|
<int key="NSWTFlags">611845120</int>
|
||||||
@ -68,7 +68,7 @@
|
|||||||
<double key="NSSize">13</double>
|
<double key="NSSize">13</double>
|
||||||
<int key="NSfFlags">1044</int>
|
<int key="NSfFlags">1044</int>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSPlaceholderString">Enter site name</string>
|
<string key="NSPlaceholderString">Enter site name X</string>
|
||||||
<string key="NSCellIdentifier">_NS:9</string>
|
<string key="NSCellIdentifier">_NS:9</string>
|
||||||
<reference key="NSControlView" ref="291791585"/>
|
<reference key="NSControlView" ref="291791585"/>
|
||||||
<bool key="NSDrawsBackground">YES</bool>
|
<bool key="NSDrawsBackground">YES</bool>
|
||||||
@ -98,7 +98,6 @@
|
|||||||
<int key="NSvFlags">268</int>
|
<int key="NSvFlags">268</int>
|
||||||
<string key="NSFrame">{{17, 20}, {446, 64}}</string>
|
<string key="NSFrame">{{17, 20}, {446, 64}}</string>
|
||||||
<reference key="NSSuperview" ref="258451033"/>
|
<reference key="NSSuperview" ref="258451033"/>
|
||||||
<reference key="NSNextKeyView"/>
|
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||||
<string key="NSAntiCompressionPriority">{250, 750}</string>
|
<string key="NSAntiCompressionPriority">{250, 750}</string>
|
||||||
@ -177,6 +176,14 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">39</int>
|
<int key="connectionID">39</int>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBOutletConnection" key="connection">
|
||||||
|
<string key="label">delegate</string>
|
||||||
|
<reference key="source" ref="291791585"/>
|
||||||
|
<reference key="destination" ref="1001"/>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">43</int>
|
||||||
|
</object>
|
||||||
</array>
|
</array>
|
||||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||||
<array key="orderedObjects">
|
<array key="orderedObjects">
|
||||||
@ -526,7 +533,7 @@
|
|||||||
<nil key="activeLocalization"/>
|
<nil key="activeLocalization"/>
|
||||||
<dictionary class="NSMutableDictionary" key="localizations"/>
|
<dictionary class="NSMutableDictionary" key="localizations"/>
|
||||||
<nil key="sourceID"/>
|
<nil key="sourceID"/>
|
||||||
<int key="maxID">42</int>
|
<int key="maxID">43</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBClassDescriber" key="IBDocument.Classes"/>
|
<object class="IBClassDescriber" key="IBDocument.Classes"/>
|
||||||
<int key="IBDocument.localizationMode">0</int>
|
<int key="IBDocument.localizationMode">0</int>
|
||||||
|
@ -13,11 +13,7 @@
|
|||||||
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
|
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
|
||||||
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
|
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
|
||||||
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
|
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
|
||||||
@property (readonly, strong, nonatomic) NSData *keyPhrase;
|
|
||||||
@property (readonly, strong, nonatomic) NSData *keyPhraseHash;
|
|
||||||
@property (readonly, strong, nonatomic) NSString *keyPhraseHashHex;
|
|
||||||
|
|
||||||
+ (MPAppDelegate *)get;
|
|
||||||
+ (NSManagedObjectModel *)managedObjectModel;
|
+ (NSManagedObjectModel *)managedObjectModel;
|
||||||
+ (NSManagedObjectContext *)managedObjectContext;
|
+ (NSManagedObjectContext *)managedObjectContext;
|
||||||
|
|
||||||
@ -25,10 +21,6 @@
|
|||||||
- (NSURL *)applicationDocumentsDirectory;
|
- (NSURL *)applicationDocumentsDirectory;
|
||||||
|
|
||||||
- (void)showGuide;
|
- (void)showGuide;
|
||||||
- (void)loadKeyPhrase:(BOOL)animated;
|
- (void)loadKey:(BOOL)animated;
|
||||||
- (void)signOut;
|
|
||||||
- (void)forgetKeyPhrase;
|
|
||||||
- (NSData *)keyPhraseWithLength:(NSUInteger)keyLength;
|
|
||||||
- (BOOL)tryMasterPassword:(NSString *)tryPassword;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -7,21 +7,14 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "MPAppDelegate.h"
|
#import "MPAppDelegate.h"
|
||||||
|
#import "MPAppDelegate_Key.h"
|
||||||
|
|
||||||
#import "MPMainViewController.h"
|
#import "MPMainViewController.h"
|
||||||
#import "IASKSettingsReader.h"
|
#import "IASKSettingsReader.h"
|
||||||
|
|
||||||
@interface MPAppDelegate ()
|
@interface MPAppDelegate ()
|
||||||
|
|
||||||
@property (strong, nonatomic) NSData *keyPhrase;
|
- (void)askKey:(BOOL)animated;
|
||||||
@property (strong, nonatomic) NSData *keyPhraseHash;
|
|
||||||
@property (strong, nonatomic) NSString *keyPhraseHashHex;
|
|
||||||
|
|
||||||
+ (NSDictionary *)keyPhraseQuery;
|
|
||||||
+ (NSDictionary *)keyPhraseHashQuery;
|
|
||||||
|
|
||||||
- (void)loadStoredKeyPhrase;
|
|
||||||
- (void)askKeyPhrase:(BOOL)animated;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -31,13 +24,13 @@
|
|||||||
@synthesize managedObjectContext = __managedObjectContext;
|
@synthesize managedObjectContext = __managedObjectContext;
|
||||||
@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
|
@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
|
||||||
|
|
||||||
@synthesize keyPhrase = _keyPhrase;
|
@synthesize key;
|
||||||
@synthesize keyPhraseHash = _keyPhraseHash;
|
@synthesize keyHash;
|
||||||
@synthesize keyPhraseHashHex = _keyPhraseHashHex;
|
@synthesize keyHashHex;
|
||||||
|
|
||||||
+ (void)initialize {
|
+ (void)initialize {
|
||||||
|
|
||||||
[MPConfig get];
|
[MPiOSConfig get];
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
[PearlLogger get].autoprintLevel = PearlLogLevelTrace;
|
[PearlLogger get].autoprintLevel = PearlLogLevelTrace;
|
||||||
@ -45,30 +38,6 @@
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSDictionary *)keyPhraseQuery {
|
|
||||||
|
|
||||||
static NSDictionary *MPKeyPhraseQuery = nil;
|
|
||||||
if (!MPKeyPhraseQuery)
|
|
||||||
MPKeyPhraseQuery = [PearlKeyChain createQueryForClass:kSecClassGenericPassword
|
|
||||||
attributes:[NSDictionary dictionaryWithObject:@"MasterPassword"
|
|
||||||
forKey:(__bridge id)kSecAttrService]
|
|
||||||
matches:nil];
|
|
||||||
|
|
||||||
return MPKeyPhraseQuery;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSDictionary *)keyPhraseHashQuery {
|
|
||||||
|
|
||||||
static NSDictionary *MPKeyPhraseHashQuery = nil;
|
|
||||||
if (!MPKeyPhraseHashQuery)
|
|
||||||
MPKeyPhraseHashQuery = [PearlKeyChain createQueryForClass:kSecClassGenericPassword
|
|
||||||
attributes:[NSDictionary dictionaryWithObject:@"MasterPasswordHash"
|
|
||||||
forKey:(__bridge id)kSecAttrService]
|
|
||||||
matches:nil];
|
|
||||||
|
|
||||||
return MPKeyPhraseHashQuery;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||||
|
|
||||||
#ifndef PRODUCTION
|
#ifndef PRODUCTION
|
||||||
@ -145,14 +114,14 @@
|
|||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:kIASKAppSettingChanged object:nil queue:nil
|
[[NSNotificationCenter defaultCenter] addObserverForName:kIASKAppSettingChanged object:nil queue:nil
|
||||||
usingBlock:^(NSNotification *note) {
|
usingBlock:^(NSNotification *note) {
|
||||||
if ([NSStringFromSelector(@selector(storeKeyPhrase))
|
if ([NSStringFromSelector(@selector(storeKey))
|
||||||
isEqualToString:[note.object description]]) {
|
isEqualToString:[note.object description]]) {
|
||||||
self.keyPhrase = self.keyPhrase;
|
[self updateKey:self.key];
|
||||||
[self loadKeyPhrase:YES];
|
[self loadKey:YES];
|
||||||
}
|
}
|
||||||
if ([NSStringFromSelector(@selector(forgetKeyPhrase))
|
if ([NSStringFromSelector(@selector(forgetKey))
|
||||||
isEqualToString:[note.object description]])
|
isEqualToString:[note.object description]])
|
||||||
[self loadKeyPhrase:YES];
|
[self loadKey:YES];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
#ifndef PRODUCTION
|
#ifndef PRODUCTION
|
||||||
@ -175,10 +144,10 @@
|
|||||||
|
|
||||||
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
||||||
|
|
||||||
if ([[MPConfig get].showQuickStart boolValue])
|
if ([[MPiOSConfig get].showQuickStart boolValue])
|
||||||
[self showGuide];
|
[self showGuide];
|
||||||
else
|
else
|
||||||
[self loadKeyPhrase:NO];
|
[self loadKey:NO];
|
||||||
|
|
||||||
#ifndef PRODUCTION
|
#ifndef PRODUCTION
|
||||||
[TestFlight passCheckpoint:MPTestFlightCheckpointActivated];
|
[TestFlight passCheckpoint:MPTestFlightCheckpointActivated];
|
||||||
@ -194,78 +163,21 @@
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)loadKeyPhrase:(BOOL)animated {
|
- (void)loadKey:(BOOL)animated {
|
||||||
|
|
||||||
if (self.keyPhrase)
|
if (self.key)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[self loadStoredKeyPhrase];
|
[self loadStoredKey];
|
||||||
if (!self.keyPhrase) {
|
if (!self.key) {
|
||||||
// Key phrase is not known. Ask user to set/specify it.
|
// Key is not known. Ask user to set/specify it.
|
||||||
dbg(@"Key phrase not known. Will ask user.");
|
dbg(@"Key not known. Will ask user.");
|
||||||
[self askKeyPhrase:animated];
|
[self askKey:animated];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)forgetKeyPhrase {
|
- (void)askKey:(BOOL)animated {
|
||||||
|
|
||||||
dbg(@"Forgetting key phrase.");
|
|
||||||
[PearlAlert showAlertWithTitle:@"Changing Master Password"
|
|
||||||
message:
|
|
||||||
@"This will allow you to log in with a different master password.\n\n"
|
|
||||||
@"Note that you will only see the sites and passwords for the master password you log in with.\n"
|
|
||||||
@"If you log in with a different master password, your current sites will be unavailable.\n\n"
|
|
||||||
@"You can always change back to your current master password later.\n"
|
|
||||||
@"Your current sites and passwords will then become available again."
|
|
||||||
viewStyle:UIAlertViewStyleDefault
|
|
||||||
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
|
||||||
if (buttonIndex != [alert cancelButtonIndex]) {
|
|
||||||
// Key phrase reset. Delete it.
|
|
||||||
dbg(@"Deleting master key phrase and hash from key chain.");
|
|
||||||
[PearlKeyChain deleteItemForQuery:[MPAppDelegate keyPhraseQuery]];
|
|
||||||
[PearlKeyChain deleteItemForQuery:[MPAppDelegate keyPhraseHashQuery]];
|
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyForgotten object:self];
|
|
||||||
#ifndef PRODUCTION
|
|
||||||
[TestFlight passCheckpoint:MPTestFlightCheckpointMPForgotten];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
[self loadKeyPhrase:YES];
|
|
||||||
|
|
||||||
#ifndef PRODUCTION
|
|
||||||
[TestFlight passCheckpoint:MPTestFlightCheckpointMPChanged];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
cancelTitle:[PearlStrings get].commonButtonAbort
|
|
||||||
otherTitles:[PearlStrings get].commonButtonContinue, nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)signOut {
|
|
||||||
|
|
||||||
self.keyPhrase = nil;
|
|
||||||
[self loadKeyPhrase:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)loadStoredKeyPhrase {
|
|
||||||
|
|
||||||
if ([[MPConfig get].storeKeyPhrase boolValue]) {
|
|
||||||
// Key phrase is stored in keychain. Load it.
|
|
||||||
dbg(@"Loading master key phrase from key chain.");
|
|
||||||
self.keyPhrase = [PearlKeyChain dataOfItemForQuery:[MPAppDelegate keyPhraseQuery]];
|
|
||||||
dbg(@" -> Master key phrase %@.", self.keyPhrase? @"found": @"NOT found");
|
|
||||||
} else {
|
|
||||||
// Key phrase should not be stored in keychain. Delete it.
|
|
||||||
dbg(@"Deleting master key phrase from key chain.");
|
|
||||||
[PearlKeyChain deleteItemForQuery:[MPAppDelegate keyPhraseQuery]];
|
|
||||||
#ifndef PRODUCTION
|
|
||||||
[TestFlight passCheckpoint:MPTestFlightCheckpointMPUnstored];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)askKeyPhrase:(BOOL)animated {
|
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[self.navigationController presentViewController:
|
[self.navigationController presentViewController:
|
||||||
@ -278,8 +190,8 @@
|
|||||||
|
|
||||||
[self saveContext];
|
[self saveContext];
|
||||||
|
|
||||||
if (![[MPConfig get].rememberKeyPhrase boolValue])
|
if (![[MPiOSConfig get].rememberKey boolValue])
|
||||||
self.keyPhrase = nil;
|
[self updateKey:nil];
|
||||||
|
|
||||||
#ifndef PRODUCTION
|
#ifndef PRODUCTION
|
||||||
[TestFlight passCheckpoint:MPTestFlightCheckpointDeactivated];
|
[TestFlight passCheckpoint:MPTestFlightCheckpointDeactivated];
|
||||||
@ -302,12 +214,12 @@
|
|||||||
|
|
||||||
+ (NSManagedObjectContext *)managedObjectContext {
|
+ (NSManagedObjectContext *)managedObjectContext {
|
||||||
|
|
||||||
return [(MPAppDelegate *)[UIApplication sharedApplication].delegate managedObjectContext];
|
return [[self get] managedObjectContext];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSManagedObjectModel *)managedObjectModel {
|
+ (NSManagedObjectModel *)managedObjectModel {
|
||||||
|
|
||||||
return [(MPAppDelegate *)[UIApplication sharedApplication].delegate managedObjectModel];
|
return [[self get] managedObjectModel];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)saveContext {
|
- (void)saveContext {
|
||||||
@ -319,75 +231,6 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)tryMasterPassword:(NSString *)tryPassword {
|
|
||||||
|
|
||||||
NSData *keyPhraseHash = [PearlKeyChain dataOfItemForQuery:[MPAppDelegate keyPhraseHashQuery]];
|
|
||||||
dbg(@"Key phrase hash %@.", keyPhraseHash? @"known": @"NOT known");
|
|
||||||
|
|
||||||
if (![tryPassword length])
|
|
||||||
return NO;
|
|
||||||
|
|
||||||
NSData *tryKeyPhrase = keyPhraseForPassword(tryPassword);
|
|
||||||
NSData *tryKeyPhraseHash = keyPhraseHashForKeyPhrase(tryKeyPhrase);
|
|
||||||
if (keyPhraseHash)
|
|
||||||
// A key phrase hash is known -> a key phrase is set.
|
|
||||||
// Make sure the user's entered key phrase matches it.
|
|
||||||
if (![keyPhraseHash isEqual:tryKeyPhraseHash]) {
|
|
||||||
dbg(@"Key phrase hash mismatch. Expected: %@, answer: %@.", keyPhraseHash, tryKeyPhraseHash);
|
|
||||||
|
|
||||||
#ifndef PRODUCTION
|
|
||||||
[TestFlight passCheckpoint:MPTestFlightCheckpointMPMismatch];
|
|
||||||
#endif
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef PRODUCTION
|
|
||||||
[TestFlight passCheckpoint:MPTestFlightCheckpointMPAsked];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
self.keyPhrase = tryKeyPhrase;
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setKeyPhrase:(NSData *)keyPhrase {
|
|
||||||
|
|
||||||
_keyPhrase = keyPhrase;
|
|
||||||
|
|
||||||
if (keyPhrase)
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeySet object:self];
|
|
||||||
else
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyUnset object:self];
|
|
||||||
|
|
||||||
if (keyPhrase) {
|
|
||||||
self.keyPhraseHash = keyPhraseHashForKeyPhrase(keyPhrase);
|
|
||||||
self.keyPhraseHashHex = [self.keyPhraseHash encodeHex];
|
|
||||||
|
|
||||||
dbg(@"Updating master key phrase hash to: %@.", self.keyPhraseHashHex);
|
|
||||||
[PearlKeyChain addOrUpdateItemForQuery:[MPAppDelegate keyPhraseHashQuery]
|
|
||||||
withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
|
|
||||||
self.keyPhraseHash, (__bridge id)kSecValueData,
|
|
||||||
kSecAttrAccessibleWhenUnlocked, (__bridge id)kSecAttrAccessible,
|
|
||||||
nil]];
|
|
||||||
if ([[MPConfig get].storeKeyPhrase boolValue]) {
|
|
||||||
dbg(@"Storing master key phrase in key chain.");
|
|
||||||
[PearlKeyChain addOrUpdateItemForQuery:[MPAppDelegate keyPhraseQuery]
|
|
||||||
withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
|
|
||||||
keyPhrase, (__bridge id)kSecValueData,
|
|
||||||
kSecAttrAccessibleWhenUnlocked, (__bridge id)kSecAttrAccessible,
|
|
||||||
nil]];
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef PRODUCTION
|
|
||||||
[TestFlight passCheckpoint:[NSString stringWithFormat:MPTestFlightCheckpointSetKeyphraseLength, _keyPhrase.length]];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSData *)keyPhraseWithLength:(NSUInteger)keyLength {
|
|
||||||
|
|
||||||
return [self.keyPhrase subdataWithRange:NSMakeRange(0, MIN(keyLength, self.keyPhrase.length))];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Core Data stack
|
#pragma mark - Core Data stack
|
||||||
|
|
||||||
- (NSManagedObjectModel *)managedObjectModel {
|
- (NSManagedObjectModel *)managedObjectModel {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "MPGuideViewController.h"
|
#import "MPGuideViewController.h"
|
||||||
#import "MPAppDelegate.h"
|
#import "MPAppDelegate_Key.h"
|
||||||
|
|
||||||
@implementation MPGuideViewController
|
@implementation MPGuideViewController
|
||||||
@synthesize scrollView;
|
@synthesize scrollView;
|
||||||
@ -28,14 +28,14 @@
|
|||||||
|
|
||||||
[super viewWillDisappear:animated];
|
[super viewWillDisappear:animated];
|
||||||
|
|
||||||
[MPConfig get].showQuickStart = [NSNumber numberWithBool:NO];
|
[MPiOSConfig get].showQuickStart = [NSNumber numberWithBool:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidDisappear:(BOOL)animated {
|
- (void)viewDidDisappear:(BOOL)animated {
|
||||||
|
|
||||||
[super viewDidDisappear:animated];
|
[super viewDidDisappear:animated];
|
||||||
|
|
||||||
[[MPAppDelegate get] loadKeyPhrase:animated];
|
[[MPAppDelegate get] loadKey:animated];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "MPMainViewController.h"
|
#import "MPMainViewController.h"
|
||||||
#import "MPAppDelegate.h"
|
#import "MPAppDelegate_Key.h"
|
||||||
#import "MPElementGeneratedEntity.h"
|
#import "MPElementGeneratedEntity.h"
|
||||||
#import "MPElementStoredEntity.h"
|
#import "MPElementStoredEntity.h"
|
||||||
#import "IASKAppSettingsViewController.h"
|
#import "IASKAppSettingsViewController.h"
|
||||||
@ -75,7 +75,7 @@
|
|||||||
self.searchTipContainer.alpha = 1;
|
self.searchTipContainer.alpha = 1;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[self setHelpHidden:[[MPConfig get].helpHidden boolValue] animated:animated];
|
[self setHelpHidden:[[MPiOSConfig get].helpHidden boolValue] animated:animated];
|
||||||
[self updateAnimated:animated];
|
[self updateAnimated:animated];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,14 +109,14 @@
|
|||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:[NSOperationQueue mainQueue]
|
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:[NSOperationQueue mainQueue]
|
||||||
usingBlock:^(NSNotification *note) {
|
usingBlock:^(NSNotification *note) {
|
||||||
if (![MPAppDelegate get].keyPhrase) {
|
if (![MPAppDelegate get].key) {
|
||||||
self.activeElement = nil;
|
self.activeElement = nil;
|
||||||
[self updateAnimated:NO];
|
[self updateAnimated:NO];
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:[NSOperationQueue mainQueue]
|
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:[NSOperationQueue mainQueue]
|
||||||
usingBlock:^(NSNotification *note) {
|
usingBlock:^(NSNotification *note) {
|
||||||
if (![MPAppDelegate get].keyPhrase) {
|
if (![MPAppDelegate get].key) {
|
||||||
self.activeElement = nil;
|
self.activeElement = nil;
|
||||||
[self updateAnimated:NO];
|
[self updateAnimated:NO];
|
||||||
}
|
}
|
||||||
@ -205,11 +205,11 @@
|
|||||||
if (hidden) {
|
if (hidden) {
|
||||||
self.contentContainer.frame = CGRectSetHeight(self.contentContainer.frame, self.view.bounds.size.height - 44);
|
self.contentContainer.frame = CGRectSetHeight(self.contentContainer.frame, self.view.bounds.size.height - 44);
|
||||||
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, self.view.bounds.size.height);
|
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, self.view.bounds.size.height);
|
||||||
[MPConfig get].helpHidden = [NSNumber numberWithBool:YES];
|
[MPiOSConfig get].helpHidden = [NSNumber numberWithBool:YES];
|
||||||
} else {
|
} else {
|
||||||
self.contentContainer.frame = CGRectSetHeight(self.contentContainer.frame, 175);
|
self.contentContainer.frame = CGRectSetHeight(self.contentContainer.frame, 175);
|
||||||
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, 216);
|
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, 216);
|
||||||
[MPConfig get].helpHidden = [NSNumber numberWithBool:NO];
|
[MPiOSConfig get].helpHidden = [NSNumber numberWithBool:NO];
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
@ -373,8 +373,11 @@
|
|||||||
#else
|
#else
|
||||||
case 4:
|
case 4:
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
[[MPAppDelegate get] signOut];
|
[[MPAppDelegate get] signOut];
|
||||||
|
[[MPAppDelegate get] loadKey:YES];
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCTION
|
#ifndef PRODUCTION
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "MPSearchDelegate.h"
|
#import "MPSearchDelegate.h"
|
||||||
#import "MPAppDelegate.h"
|
#import "MPAppDelegate_Key.h"
|
||||||
#import "MPElementGeneratedEntity.h"
|
#import "MPElementGeneratedEntity.h"
|
||||||
|
|
||||||
@interface MPSearchDelegate (Private)
|
@interface MPSearchDelegate (Private)
|
||||||
@ -109,12 +109,12 @@
|
|||||||
- (void)update {
|
- (void)update {
|
||||||
|
|
||||||
assert(self.query);
|
assert(self.query);
|
||||||
assert([MPAppDelegate get].keyPhraseHashHex);
|
assert([MPAppDelegate get].keyHashHex);
|
||||||
NSFetchRequest *fetchRequest = [[MPAppDelegate get].managedObjectModel
|
NSFetchRequest *fetchRequest = [[MPAppDelegate get].managedObjectModel
|
||||||
fetchRequestFromTemplateWithName:@"MPElements"
|
fetchRequestFromTemplateWithName:@"MPElements"
|
||||||
substitutionVariables:[NSDictionary dictionaryWithObjectsAndKeys:
|
substitutionVariables:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
self.query, @"query",
|
self.query, @"query",
|
||||||
[MPAppDelegate get].keyPhraseHashHex, @"mpHashHex",
|
[MPAppDelegate get].keyHashHex, @"mpHashHex",
|
||||||
nil]];
|
nil]];
|
||||||
[fetchRequest setSortDescriptors:
|
[fetchRequest setSortDescriptors:
|
||||||
[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses" ascending:NO]]];
|
[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses" ascending:NO]]];
|
||||||
@ -266,7 +266,7 @@
|
|||||||
assert([element isKindOfClass:ClassFromMPElementType(element.type)]);
|
assert([element isKindOfClass:ClassFromMPElementType(element.type)]);
|
||||||
|
|
||||||
element.name = siteName;
|
element.name = siteName;
|
||||||
element.mpHashHex = [MPAppDelegate get].keyPhraseHashHex;
|
element.mpHashHex = [MPAppDelegate get].keyHashHex;
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[self.delegate didSelectElement:element];
|
[self.delegate didSelectElement:element];
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#import <QuartzCore/QuartzCore.h>
|
#import <QuartzCore/QuartzCore.h>
|
||||||
|
|
||||||
#import "MPUnlockViewController.h"
|
#import "MPUnlockViewController.h"
|
||||||
#import "MPAppDelegate.h"
|
#import "MPAppDelegate_Key.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MPLockscreenIdle,
|
MPLockscreenIdle,
|
||||||
@ -199,7 +199,27 @@ typedef enum {
|
|||||||
|
|
||||||
- (IBAction)changeMP {
|
- (IBAction)changeMP {
|
||||||
|
|
||||||
[[MPAppDelegate get] forgetKeyPhrase];
|
dbg(@"Forgetting key phrase.");
|
||||||
|
[PearlAlert showAlertWithTitle:@"Changing Master Password"
|
||||||
|
message:
|
||||||
|
@"This will allow you to log in with a different master password.\n\n"
|
||||||
|
@"Note that you will only see the sites and passwords for the master password you log in with.\n"
|
||||||
|
@"If you log in with a different master password, your current sites will be unavailable.\n\n"
|
||||||
|
@"You can always change back to your current master password later.\n"
|
||||||
|
@"Your current sites and passwords will then become available again."
|
||||||
|
viewStyle:UIAlertViewStyleDefault
|
||||||
|
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
||||||
|
if (buttonIndex != [alert cancelButtonIndex])
|
||||||
|
[[MPAppDelegate get] forgetKey];
|
||||||
|
|
||||||
|
[[MPAppDelegate get] loadKey:YES];
|
||||||
|
|
||||||
|
#ifndef PRODUCTION
|
||||||
|
[TestFlight passCheckpoint:MPTestFlightCheckpointMPChanged];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
cancelTitle:[PearlStrings get].commonButtonAbort
|
||||||
|
otherTitles:[PearlStrings get].commonButtonContinue, nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
18
MasterPassword/iOS/MPiOSConfig.h
Normal file
18
MasterPassword/iOS/MPiOSConfig.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// MPConfig.h
|
||||||
|
// MasterPassword
|
||||||
|
//
|
||||||
|
// Created by Maarten Billemont on 02/01/12.
|
||||||
|
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPConfig.h"
|
||||||
|
|
||||||
|
@interface MPiOSConfig : MPConfig
|
||||||
|
|
||||||
|
@property (nonatomic, retain) NSNumber *helpHidden;
|
||||||
|
@property (nonatomic, retain) NSNumber *showQuickStart;
|
||||||
|
|
||||||
|
+ (MPiOSConfig *)get;
|
||||||
|
|
||||||
|
@end
|
32
MasterPassword/iOS/MPiOSConfig.m
Normal file
32
MasterPassword/iOS/MPiOSConfig.m
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// MPConfig.m
|
||||||
|
// MasterPassword
|
||||||
|
//
|
||||||
|
// Created by Maarten Billemont on 02/01/12.
|
||||||
|
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPiOSConfig.h"
|
||||||
|
|
||||||
|
@implementation MPiOSConfig
|
||||||
|
@dynamic helpHidden, showQuickStart;
|
||||||
|
|
||||||
|
- (id)init {
|
||||||
|
|
||||||
|
if(!(self = [super init]))
|
||||||
|
return self;
|
||||||
|
|
||||||
|
[self.defaults registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(helpHidden)),
|
||||||
|
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(showQuickStart)),
|
||||||
|
nil]];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (MPiOSConfig *)get {
|
||||||
|
|
||||||
|
return (MPiOSConfig *)[super get];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
@ -21,4 +21,4 @@
|
|||||||
#import "Pearl-Prefix.pch"
|
#import "Pearl-Prefix.pch"
|
||||||
|
|
||||||
#import "MPTypes.h"
|
#import "MPTypes.h"
|
||||||
#import "MPConfig.h"
|
#import "MPiOSConfig.h"
|
||||||
|
Loading…
Reference in New Issue
Block a user