2012-03-05 21:19:05 +00:00
|
|
|
//
|
|
|
|
// MPAppDelegate.m
|
|
|
|
// MasterPassword
|
|
|
|
//
|
|
|
|
// Created by Maarten Billemont on 24/11/11.
|
|
|
|
// Copyright (c) 2011 Lyndir. All rights reserved.
|
|
|
|
//
|
|
|
|
|
2012-05-11 20:45:05 +00:00
|
|
|
#import "MPAppDelegate_Key.h"
|
2012-03-05 21:19:05 +00:00
|
|
|
|
2012-05-11 20:45:05 +00:00
|
|
|
@implementation MPAppDelegate_Shared (Key)
|
2012-03-05 21:19:05 +00:00
|
|
|
|
2012-06-04 09:27:02 +00:00
|
|
|
static NSDictionary *keyQuery(MPUserEntity *user) {
|
2012-03-05 21:19:05 +00:00
|
|
|
|
2012-06-04 09:27:02 +00:00
|
|
|
return [PearlKeyChain createQueryForClass:kSecClassGenericPassword
|
|
|
|
attributes:[NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
@"Saved Master Password", (__bridge id)kSecAttrService,
|
|
|
|
user.name, (__bridge id)kSecAttrAccount,
|
|
|
|
nil]
|
|
|
|
matches:nil];
|
2012-03-05 21:19:05 +00:00
|
|
|
}
|
|
|
|
|
2012-06-04 09:27:02 +00:00
|
|
|
- (void)forgetSavedKey {
|
2012-03-05 21:19:05 +00:00
|
|
|
|
2012-06-04 09:27:02 +00:00
|
|
|
if ([PearlKeyChain deleteItemForQuery:keyQuery(self.activeUser)] != errSecItemNotFound) {
|
2012-05-13 17:50:40 +00:00
|
|
|
inf(@"Removed key from keychain.");
|
2012-06-04 09:27:02 +00:00
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyForgotten object:self];
|
2012-05-11 20:45:05 +00:00
|
|
|
#ifdef TESTFLIGHT_SDK_VERSION
|
2012-06-04 09:27:02 +00:00
|
|
|
[TestFlight passCheckpoint:MPTestFlightCheckpointMPForgotten];
|
2012-05-04 16:54:58 +00:00
|
|
|
#endif
|
2012-06-04 09:27:02 +00:00
|
|
|
}
|
2012-03-05 21:19:05 +00:00
|
|
|
}
|
|
|
|
|
2012-05-05 11:32:09 +00:00
|
|
|
- (IBAction)signOut:(id)sender {
|
2012-05-13 17:50:40 +00:00
|
|
|
|
2012-06-04 09:27:02 +00:00
|
|
|
[self forgetSavedKey];
|
|
|
|
[self unsetKey];
|
2012-03-05 21:19:05 +00:00
|
|
|
}
|
|
|
|
|
2012-06-04 09:27:02 +00:00
|
|
|
- (void)loadSavedKey {
|
2012-03-05 21:19:05 +00:00
|
|
|
|
2012-06-04 22:55:02 +00:00
|
|
|
if (self.activeUser.saveKey) {
|
2012-06-04 09:27:02 +00:00
|
|
|
// Key should be saved in keychain. Load it.
|
|
|
|
self.key = [PearlKeyChain dataOfItemForQuery:keyQuery(self.activeUser)];
|
2012-05-12 16:31:05 +00:00
|
|
|
inf(@"Looking for key in keychain: %@.", self.key? @"found": @"missing");
|
2012-06-04 09:27:02 +00:00
|
|
|
if (self.key)
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeySet object:self];
|
2012-03-05 21:19:05 +00:00
|
|
|
} else {
|
|
|
|
// Key should not be stored in keychain. Delete it.
|
2012-06-04 09:27:02 +00:00
|
|
|
if ([PearlKeyChain deleteItemForQuery:keyQuery(self.activeUser)] != errSecItemNotFound)
|
2012-05-12 16:31:05 +00:00
|
|
|
inf(@"Removed key from keychain.");
|
2012-05-11 20:45:05 +00:00
|
|
|
#ifdef TESTFLIGHT_SDK_VERSION
|
2012-03-05 21:19:05 +00:00
|
|
|
[TestFlight passCheckpoint:MPTestFlightCheckpointMPUnstored];
|
2012-05-04 16:54:58 +00:00
|
|
|
#endif
|
2012-03-05 21:19:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-04 09:27:02 +00:00
|
|
|
- (BOOL)tryMasterPassword:(NSString *)tryPassword forUser:(MPUserEntity *)user {
|
2012-03-05 21:19:05 +00:00
|
|
|
|
|
|
|
if (![tryPassword length])
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
NSData *tryKey = keyForPassword(tryPassword);
|
2012-05-12 17:24:29 +00:00
|
|
|
NSData *tryKeyID = keyIDForKey(tryKey);
|
2012-06-04 09:27:02 +00:00
|
|
|
inf(@"Key ID known? %@.", user.keyID? @"YES": @"NO");
|
|
|
|
if (user.keyID)
|
2012-05-12 17:24:29 +00:00
|
|
|
// A key ID is known -> a password is set.
|
|
|
|
// Make sure the user's entered password matches it.
|
2012-06-04 09:27:02 +00:00
|
|
|
if (![user.keyID isEqual:tryKeyID]) {
|
|
|
|
wrn(@"Key ID mismatch. Expected: %@, answer: %@.", [user.keyID encodeHex], [tryKeyID encodeHex]);
|
2012-03-05 21:19:05 +00:00
|
|
|
|
2012-05-11 20:45:05 +00:00
|
|
|
#ifdef TESTFLIGHT_SDK_VERSION
|
2012-03-05 21:19:05 +00:00
|
|
|
[TestFlight passCheckpoint:MPTestFlightCheckpointMPMismatch];
|
2012-05-04 16:54:58 +00:00
|
|
|
#endif
|
2012-03-05 21:19:05 +00:00
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2012-05-11 20:45:05 +00:00
|
|
|
#ifdef TESTFLIGHT_SDK_VERSION
|
2012-05-11 15:04:51 +00:00
|
|
|
[TestFlight passCheckpoint:MPTestFlightCheckpointMPEntered];
|
2012-05-04 16:54:58 +00:00
|
|
|
#endif
|
2012-03-05 21:19:05 +00:00
|
|
|
|
2012-06-04 09:27:02 +00:00
|
|
|
if (self.key != tryKey) {
|
|
|
|
self.key = tryKey;
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeySet object:self];
|
|
|
|
}
|
|
|
|
|
|
|
|
self.activeUser = user;
|
|
|
|
|
|
|
|
#ifdef TESTFLIGHT_SDK_VERSION
|
|
|
|
[TestFlight passCheckpoint:MPTestFlightCheckpointSetKey];
|
|
|
|
#endif
|
|
|
|
|
2012-03-05 21:19:05 +00:00
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2012-06-04 09:27:02 +00:00
|
|
|
- (void)storeSavedKey {
|
2012-03-05 21:19:05 +00:00
|
|
|
|
2012-06-04 22:55:02 +00:00
|
|
|
if (self.activeUser.saveKey) {
|
2012-06-04 09:27:02 +00:00
|
|
|
NSData *existingKey = [PearlKeyChain dataOfItemForQuery:keyQuery(self.activeUser)];
|
2012-05-11 20:45:05 +00:00
|
|
|
|
2012-06-04 09:27:02 +00:00
|
|
|
if (![existingKey isEqualToData:self.key]) {
|
|
|
|
inf(@"Updating key in keychain.");
|
|
|
|
[PearlKeyChain addOrUpdateItemForQuery:keyQuery(self.activeUser)
|
2012-05-12 16:31:05 +00:00
|
|
|
withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
|
2012-06-04 09:27:02 +00:00
|
|
|
self.key, (__bridge id)kSecValueData,
|
2012-05-11 15:04:51 +00:00
|
|
|
#if TARGET_OS_IPHONE
|
2012-06-04 09:27:02 +00:00
|
|
|
kSecAttrAccessibleWhenUnlockedThisDeviceOnly, (__bridge id)kSecAttrAccessible,
|
2012-03-05 21:43:20 +00:00
|
|
|
#endif
|
2012-05-12 16:31:05 +00:00
|
|
|
nil]];
|
|
|
|
}
|
2012-03-05 21:19:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-04 09:27:02 +00:00
|
|
|
- (void)unsetKey {
|
|
|
|
|
|
|
|
self.key = nil;
|
|
|
|
self.activeUser = nil;
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyUnset object:self];
|
|
|
|
}
|
|
|
|
|
2012-03-05 21:19:05 +00:00
|
|
|
- (NSData *)keyWithLength:(NSUInteger)keyLength {
|
|
|
|
|
|
|
|
return [self.key subdataWithRange:NSMakeRange(0, MIN(keyLength, self.key.length))];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|