2
0
MasterPassword/MasterPassword/MPAppDelegate_Key.m

175 lines
5.8 KiB
Mathematica
Raw Normal View History

//
// MPAppDelegate.m
// MasterPassword
//
// Created by Maarten Billemont on 24/11/11.
// Copyright (c) 2011 Lyndir. All rights reserved.
//
#import <Crashlytics/Crashlytics.h>
#import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h"
#import "LocalyticsSession.h"
@implementation MPAppDelegate_Shared (Key)
static NSDictionary *keyQuery(MPUserEntity *user) {
2012-06-07 22:40:30 +00:00
return [PearlKeyChain createQueryForClass:kSecClassGenericPassword
attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2012-06-08 21:46:13 +00:00
@"Saved Master Password", (__bridge id)kSecAttrService,
user.name, (__bridge id)kSecAttrAccount,
nil]
matches:nil];
}
2012-06-07 22:40:30 +00:00
- (NSData *)loadSavedKeyFor:(MPUserEntity *)user {
NSData *key = [PearlKeyChain dataOfItemForQuery:keyQuery(user)];
if (key)
inf(@"Found key in keychain for: %@", user.userID);
2012-06-07 22:40:30 +00:00
else {
user.saveKey = NO;
inf(@"No key found in keychain for: %@", user.userID);
}
2012-06-07 22:40:30 +00:00
return key;
}
2012-06-07 22:40:30 +00:00
- (void)storeSavedKeyFor:(MPUserEntity *)user {
2012-06-07 22:40:30 +00:00
if (user.saveKey) {
NSData *existingKey = [PearlKeyChain dataOfItemForQuery:keyQuery(user)];
2012-06-07 22:40:30 +00:00
if (![existingKey isEqualToData:self.key]) {
inf(@"Saving key in keychain for: %@", user.userID);
2012-06-07 22:40:30 +00:00
[PearlKeyChain addOrUpdateItemForQuery:keyQuery(user)
withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
2012-06-08 21:46:13 +00:00
self.key, (__bridge id)kSecValueData,
#if TARGET_OS_IPHONE
kSecAttrAccessibleWhenUnlockedThisDeviceOnly, (__bridge id)kSecAttrAccessible,
#endif
nil]];
2012-06-07 22:40:30 +00:00
}
}
}
2012-06-07 22:40:30 +00:00
- (void)forgetSavedKeyFor:(MPUserEntity *)user {
OSStatus result = [PearlKeyChain deleteItemForQuery:keyQuery(user)];
if (result == noErr || result == errSecItemNotFound) {
user.saveKey = NO;
if (result == noErr) {
inf(@"Removed key from keychain for: %@", user.userID);
2012-06-07 22:40:30 +00:00
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyForgotten object:self];
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointForgetSavedKey];
#endif
}
}
2012-06-07 22:40:30 +00:00
}
- (void)signOut {
2012-06-08 21:46:13 +00:00
self.key = nil;
2012-06-07 22:40:30 +00:00
self.activeUser = nil;
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationSignedOut object:self];
}
- (BOOL)signInAsUser:(MPUserEntity *)user usingMasterPassword:(NSString *)password {
NSData *tryKey = nil;
// Method 1: When the user has no keyID set, set a new key from the given master password.
if (!user.keyID) {
if ([password length])
if ((tryKey = keyForPassword(password, user.name))) {
user.keyID = keyIDForKey(tryKey);
[[MPAppDelegate_Shared get] saveContext];
}
}
// Method 2: Depending on the user's saveKey, load or remove the key from the keychain.
if (!user.saveKey)
2012-06-08 21:46:13 +00:00
// Key should not be stored in keychain. Delete it.
2012-06-07 22:40:30 +00:00
[self forgetSavedKeyFor:user];
2012-06-08 21:46:13 +00:00
else
if (!tryKey) {
// Key should be saved in keychain. Load it.
if ((tryKey = [self loadSavedKeyFor:user]))
if (![user.keyID isEqual:keyIDForKey(tryKey)]) {
// Loaded password doesn't match user's keyID. Forget saved password: it is incorrect.
inf(@"Saved password doesn't match keyID for: %@", user.userID);
2012-06-08 21:46:13 +00:00
tryKey = nil;
[self forgetSavedKeyFor:user];
}
}
2012-06-07 22:40:30 +00:00
// Method 3: Check the given master password string.
if (!tryKey) {
if ([password length])
if ((tryKey = keyForPassword(password, user.name)))
if (![user.keyID isEqual:keyIDForKey(tryKey)]) {
inf(@"Key derived from password doesn't match keyID for: %@", user.userID);
2012-06-07 22:40:30 +00:00
tryKey = nil;
2012-06-07 22:40:30 +00:00
}
}
// No more methods left, fail if key still not known.
if (!tryKey) {
inf(@"Login failed for: %@", user.userID);
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointSignInFailed];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointSignInFailed attributes:nil];
2012-06-07 22:40:30 +00:00
return NO;
}
inf(@"Logged in: %@", user.userID);
2012-06-07 22:40:30 +00:00
if (![self.key isEqualToData:tryKey]) {
self.key = tryKey;
2012-06-07 22:40:30 +00:00
[self storeSavedKeyFor:user];
}
2012-06-07 22:40:30 +00:00
@try {
if ([[MPiOSConfig get].sendInfo boolValue]) {
[TestFlight addCustomEnvironmentInformation:user.userID forKey:@"username"];
[[Crashlytics sharedInstance] setObjectValue:user.userID forKey:@"username"];
}
}
@catch (id exception) {
err(@"While setting username: %@", exception);
}
2012-06-08 21:46:13 +00:00
user.lastUsed = [NSDate date];
self.activeUser = user;
2012-06-07 22:40:30 +00:00
[[MPAppDelegate_Shared get] saveContext];
2012-06-07 22:40:30 +00:00
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationSignedIn object:self];
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointSignedIn];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointSignedIn
attributes:nil];
2012-06-07 22:40:30 +00:00
return YES;
}
- (NSData *)keyWithLength:(NSUInteger)keyLength {
2012-06-07 22:40:30 +00:00
return [self.key subdataWithRange:NSMakeRange(0, MIN(keyLength, self.key.length))];
}
@end