2
0

UI improvements & security.

[ADDED]     Settings for remembering and storing the master password.
[ADDED]     KeyChain used to store master password & hash.
[IMPROVED]  Remember whether help is hidden.
[FIXED]     Making passwords stored.
[ADDED]     Generated password counter. Edit stored passwords.
[IMPROVED]  UI prettier and better documented.
[ADDED]     Warnings when changing a site's password.
This commit is contained in:
Maarten Billemont
2012-01-19 17:40:39 +01:00
parent f4eb33e728
commit 713ec69a20
32 changed files with 857 additions and 254 deletions

View File

@@ -10,6 +10,13 @@
#import "OPMainViewController.h"
@interface OPAppDelegate ()
+ (NSDictionary *)keyPhraseQuery;
+ (NSDictionary *)keyPhraseHashQuery;
@end
@implementation OPAppDelegate
@synthesize managedObjectContext = __managedObjectContext;
@@ -22,26 +29,63 @@
[Logger get].autoprintLevel = LogLevelDebug;
}
- (void)applicationWillResignActive:(UIApplication *)application {
+ (NSDictionary *)keyPhraseQuery {
if (![[OPConfig get].rememberKeyPhrase boolValue])
self.keyPhrase = nil;
static NSDictionary *OPKeyPhraseQuery = nil;
if (!OPKeyPhraseQuery)
OPKeyPhraseQuery = [KeyChain createQueryForClass:kSecClassGenericPassword
attributes:[NSDictionary dictionaryWithObject:@"MasterKeyPhrase"
forKey:(__bridge id)kSecAttrService]
matches:nil];
return OPKeyPhraseQuery;
}
+ (NSDictionary *)keyPhraseHashQuery {
static NSDictionary *OPKeyPhraseHashQuery = nil;
if (!OPKeyPhraseHashQuery)
OPKeyPhraseHashQuery = [KeyChain createQueryForClass:kSecClassGenericPassword
attributes:[NSDictionary dictionaryWithObject:@"MasterKeyPhraseHash"
forKey:(__bridge id)kSecAttrService]
matches:nil];
return OPKeyPhraseHashQuery;
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
if (!self.keyPhrase)
if ([[OPConfig get].storeKeyPhrase boolValue]) {
// Key phrase is stored in keychain. Load it.
dbg(@"Loading master key phrase from key chain.");
NSData *keyPhraseData = [KeyChain dataOfItemForQuery:[OPAppDelegate keyPhraseQuery]];
dbg(@" -> Master key phrase %@.", keyPhraseData? @"found": @"NOT found");
self.keyPhrase = keyPhraseData? [[NSString alloc] initWithBytes:keyPhraseData.bytes length:keyPhraseData.length
encoding:NSUTF8StringEncoding]: nil;
} else {
// Key phrase should not be stored in keychain. Delete it.
dbg(@"Deleting master key phrase from key chain.");
[KeyChain deleteItemForQuery:[OPAppDelegate keyPhraseQuery]];
}
if (!self.keyPhrase) {
// Key phrase is not known. Ask user to set/specify it.
dbg(@"Key phrase not known. Will ask user.");
dispatch_async(dispatch_get_main_queue(), ^{
NSString *keyPhraseHash = [OPConfig get].keyPhraseHash;
NSData *keyPhraseHash = [KeyChain dataOfItemForQuery:[OPAppDelegate keyPhraseHashQuery]];
dbg(@"Key phrase hash %@.", keyPhraseHash? @"known": @"NOT known");
AlertViewController *keyPhraseAlert = [[AlertViewController alloc] initQuestionWithTitle:@"One Password"
message:keyPhraseHash? @"Unlock with your master password:": @"Choose your master password:"
tappedButtonBlock:
^(NSInteger buttonIndex, NSString *answer) {
if (buttonIndex == 0)
if (!buttonIndex)
exit(0);
if (![answer length]) {
// User didn't enter a key phrase.
[AlertViewController showAlertWithTitle:[PearlStrings get].commonTitleError
message:@"No master password entered."
tappedButtonBlock:
@@ -50,9 +94,13 @@
} cancelTitle:@"Quit" otherTitles:nil];
}
NSString *answerHash = [[answer hashWith:PearlDigestSHA1] encodeHex];
if (keyPhraseHash) {
if (![keyPhraseHash isEqualToString:answerHash]) {
NSData *answerHash = [answer hashWith:PearlDigestSHA512];
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:answerHash]) {
dbg(@"Key phrase hash mismatch. Expected: %@, answer: %@.", keyPhraseHash, answerHash);
[AlertViewController showAlertWithTitle:[PearlStrings get].commonTitleError
message:@"Incorrect master password."
tappedButtonBlock:
@@ -62,16 +110,23 @@
return;
}
} else
[OPConfig get].keyPhraseHash = answerHash;
self.keyPhrase = answer;
} cancelTitle:@"Quit" otherTitles:@"Unlock", nil];
keyPhraseAlert.alertField.autocapitalizationType = UITextAutocapitalizationTypeNone;
keyPhraseAlert.alertField.autocorrectionType = UITextAutocorrectionTypeNo;
keyPhraseAlert.alertField.enablesReturnKeyAutomatically = YES;
keyPhraseAlert.alertField.returnKeyType = UIReturnKeyGo;
keyPhraseAlert.alertField.secureTextEntry = YES;
[keyPhraseAlert showAlert];
});
}
}
- (void)applicationWillResignActive:(UIApplication *)application {
if (![[OPConfig get].rememberKeyPhrase boolValue])
self.keyPhrase = nil;
}
- (void)applicationWillTerminate:(UIApplication *)application
@@ -85,6 +140,11 @@
return (OPAppDelegate *)[super get];
}
+ (NSManagedObjectContext *)managedObjectContext{
return [(OPAppDelegate *)[UIApplication sharedApplication].delegate managedObjectContext];
}
- (void)saveContext
{
NSError *error = nil;
@@ -99,6 +159,25 @@
}
}
- (void)setKeyPhrase:(NSString *)keyPhrase {
_keyPhrase = keyPhrase;
if (keyPhrase) {
NSData *keyPhraseHash = [keyPhrase hashWith:PearlDigestSHA512];
dbg(@"Updating master key phrase hash to: %@.", keyPhraseHash);
[KeyChain addOrUpdateItemForQuery:[OPAppDelegate keyPhraseHashQuery]
withAttributes:[NSDictionary dictionaryWithObject:keyPhraseHash
forKey:(__bridge id)kSecValueData]];
if ([[OPConfig get].storeKeyPhrase boolValue]) {
dbg(@"Storing master key phrase in key chain.");
[KeyChain addOrUpdateItemForQuery:[OPAppDelegate keyPhraseQuery]
withAttributes:[NSDictionary dictionaryWithObject:[keyPhrase dataUsingEncoding:NSUTF8StringEncoding]
forKey:(__bridge id)kSecValueData]];
}
}
}
#pragma mark - Core Data stack
/**