From 9192504939103132db17cec9c97c6d5b210706b8 Mon Sep 17 00:00:00 2001 From: michael starke Date: Sun, 17 Nov 2013 23:59:36 +0100 Subject: [PATCH] Refactored key file storing into the document. --- MacPass/Base.lproj/GeneralSettings.xib | 4 +- MacPass/Base.lproj/PasswordInputView.xib | 4 +- MacPass/MPDocument.h | 10 ++++ MacPass/MPDocument.m | 56 ++++++++++++++++--- MacPass/MPDocumentWindowController.m | 4 -- MacPass/MPPasswordInputController.h | 2 - MacPass/MPPasswordInputController.m | 69 +++++------------------- MacPass/MPPasteBoardController.h | 11 ++++ MacPass/MPPasteBoardController.m | 11 +++- 9 files changed, 98 insertions(+), 73 deletions(-) diff --git a/MacPass/Base.lproj/GeneralSettings.xib b/MacPass/Base.lproj/GeneralSettings.xib index 2ffb09c5..d72408e5 100644 --- a/MacPass/Base.lproj/GeneralSettings.xib +++ b/MacPass/Base.lproj/GeneralSettings.xib @@ -74,7 +74,7 @@ - + @@ -84,7 +84,7 @@ - + diff --git a/MacPass/Base.lproj/PasswordInputView.xib b/MacPass/Base.lproj/PasswordInputView.xib index 5af982a3..60439661 100644 --- a/MacPass/Base.lproj/PasswordInputView.xib +++ b/MacPass/Base.lproj/PasswordInputView.xib @@ -23,7 +23,7 @@ - diff --git a/MacPass/MPDocument.h b/MacPass/MPDocument.h index eb4fffb7..0690cc3d 100644 --- a/MacPass/MPDocument.h +++ b/MacPass/MPDocument.h @@ -9,6 +9,8 @@ #import #import "KPKVersion.h" +APPKIT_EXTERN NSString *const MPDocumentDidChangeStoredKeyFilesSettings; + APPKIT_EXTERN NSString *const MPDocumentDidAddGroupNotification; APPKIT_EXTERN NSString *const MPDocumentDidRevertNotifiation; @@ -55,6 +57,14 @@ APPKIT_EXTERN NSString *const MPDocumentGroupKey; #pragma mark Lock/Decrypt - (void)lockDatabase:(id)sender; - (BOOL)unlockWithPassword:(NSString *)password keyFileURL:(NSURL *)keyFileURL error:(NSError *__autoreleasing*)error; +/** + * Returns the suggest key URL for this document. This might be nil. + * If the user did disable remeberKeyFiles in the settings, this always returns nil + * Otherwise the preferences are searched to locate the last know key url for this document + * + * @return The suggested key URL if one was found and the settings are allowing suggesting key locations + */ +- (NSURL *)suggestedKeyURL; #pragma mark Data Lookup /** diff --git a/MacPass/MPDocument.m b/MacPass/MPDocument.m index fb328adf..c1d7d70a 100644 --- a/MacPass/MPDocument.m +++ b/MacPass/MPDocument.m @@ -26,6 +26,8 @@ #import "KPKMetaData.h" #import "KPKAttribute.h" +NSString *const MPDocumentDidChangeStoredKeyFilesSettings = @"com.hicknhack.macpass.MPDocumentDidChangeStoredKeyFilesSettings"; + NSString *const MPDocumentDidAddGroupNotification = @"com.hicknhack.macpass.MPDocumentDidAddGroupNotification"; NSString *const MPDocumentDidRevertNotifiation = @"com.hicknhack.macpass.MPDocumentDidRevertNotifiation"; @@ -52,8 +54,8 @@ typedef NS_ENUM(NSUInteger, MPAlertType) { @property (weak, nonatomic) KPKGroup *root; @property (assign) BOOL readOnly; - @property (strong) NSURL *lockFileURL; +@property (nonatomic, assign) BOOL isAllowedToStoreKeyFile; @property (readonly) BOOL useTrash; @property (strong) IBOutlet NSView *warningView; @@ -97,12 +99,18 @@ typedef NS_ENUM(NSUInteger, MPAlertType) { _encryptedData = nil; _didLockFile = NO; _readOnly = NO; + _isAllowedToStoreKeyFile = NO; self.tree = [KPKTree templateTree]; + [self bind:@"isAllowedToStoreKeyFile" + toObject:[NSUserDefaultsController sharedUserDefaultsController] + withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyRememberKeyFilesForDatabases] + options:nil]; } return self; } - (void)dealloc { + [self unbind:@"isAllowedToStoreKeyFile"]; [self _cleanupLock]; } @@ -212,6 +220,13 @@ typedef NS_ENUM(NSUInteger, MPAlertType) { #pragma mark Lock/Unlock/Decrypt +- (void)lockDatabase:(id)sender { + NSError *error; + /* Locking needs to be lossless hence just use the XML format */ + _encryptedData = [self.tree encryptWithPassword:self.compositeKey forVersion:KPKXmlVersion error:&error]; + self.tree = nil; +} + - (BOOL)unlockWithPassword:(NSString *)password keyFileURL:(NSURL *)keyFileURL error:(NSError *__autoreleasing*)error{ self.compositeKey = [[KPKCompositeKey alloc] initWithPassword:password key:keyFileURL]; self.tree = [[KPKTree alloc] initWithData:_encryptedData password:self.compositeKey error:error]; @@ -219,6 +234,9 @@ typedef NS_ENUM(NSUInteger, MPAlertType) { BOOL isUnlocked = (nil != self.tree); if(isUnlocked) { [[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidUnlockDatabaseNotification object:self]; + if([password length] > 0 && self.isAllowedToStoreKeyFile) { + [self _storeKeyURL:keyFileURL]; + } } else { self.compositeKey = nil; // clear the key? @@ -226,11 +244,16 @@ typedef NS_ENUM(NSUInteger, MPAlertType) { return isUnlocked; } -- (void)lockDatabase:(id)sender { - NSError *error; - /* Locking needs to be lossless hence just use the XML format */ - _encryptedData = [self.tree encryptWithPassword:self.compositeKey forVersion:KPKXmlVersion error:&error]; - self.tree = nil; +- (NSURL *)suggestedKeyURL { + if(!self.isAllowedToStoreKeyFile) { + return nil; + } + NSDictionary *keysForFiles = [[NSUserDefaults standardUserDefaults] dictionaryForKey:kMPSettingsKeyRememeberdKeysForDatabases]; + NSString *keyPath = keysForFiles[[[self fileURL] path]]; + if(!keyPath) { + return nil; + } + return [NSURL fileURLWithPath:keyPath]; } #pragma mark Properties @@ -273,6 +296,17 @@ typedef NS_ENUM(NSUInteger, MPAlertType) { } } +- (void)setIsAllowedToStoreKeyFile:(BOOL)isAllowedToStoreKeyFile { + if(_isAllowedToStoreKeyFile != isAllowedToStoreKeyFile) { + _isAllowedToStoreKeyFile = isAllowedToStoreKeyFile; + if(!self.isAllowedToStoreKeyFile) { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:kMPSettingsKeyRememeberdKeysForDatabases]; + } + /* Inform anyone that might be interested that we can now no longer/ or can use keyfiles */ + [[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidChangeStoredKeyFilesSettings object:self]; + } +} + #pragma mark Data Accesors - (KPKEntry *)findEntry:(NSUUID *)uuid { @@ -474,6 +508,16 @@ typedef NS_ENUM(NSUInteger, MPAlertType) { return [super validateUserInterfaceItem:anItem]; } +- (void)_storeKeyURL:(NSURL *)keyURL { + NSAssert(self.isAllowedToStoreKeyFile, @"We can only store if we are allowed to do so!"); + NSMutableDictionary *keysForFiles = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:kMPSettingsKeyRememeberdKeysForDatabases] mutableCopy]; + if(nil == keysForFiles) { + keysForFiles = [[NSMutableDictionary alloc] initWithCapacity:1]; + } + keysForFiles[[[self fileURL] path]] = [keyURL path]; + [[NSUserDefaults standardUserDefaults] setObject:keysForFiles forKey:kMPSettingsKeyRememeberdKeysForDatabases]; +} + - (void)_cleanupLock { if(_didLockFile) { [[NSFileManager defaultManager] removeItemAtURL:_lockFileURL error:nil]; diff --git a/MacPass/MPDocumentWindowController.m b/MacPass/MPDocumentWindowController.m index 5d48a19b..e8c277e5 100644 --- a/MacPass/MPDocumentWindowController.m +++ b/MacPass/MPDocumentWindowController.m @@ -283,10 +283,6 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) { - (void)showPasswordInput { if(!self.passwordInputController) { self.passwordInputController = [[MPPasswordInputController alloc] init]; - self.passwordInputController.showLastUsedKeyFile = YES; - } - else { - self.passwordInputController.showLastUsedKeyFile = NO; } [self _setContentViewController:self.passwordInputController]; [self.passwordInputController requestPassword]; diff --git a/MacPass/MPPasswordInputController.h b/MacPass/MPPasswordInputController.h index d78531d1..732fff81 100644 --- a/MacPass/MPPasswordInputController.h +++ b/MacPass/MPPasswordInputController.h @@ -10,8 +10,6 @@ @interface MPPasswordInputController : MPViewController -@property (nonatomic, assign) BOOL showLastUsedKeyFile; - - (void)requestPassword; @end diff --git a/MacPass/MPPasswordInputController.m b/MacPass/MPPasswordInputController.m index bc7c91c0..0c7144e9 100644 --- a/MacPass/MPPasswordInputController.m +++ b/MacPass/MPPasswordInputController.m @@ -24,12 +24,8 @@ @property (weak) IBOutlet NSTextField *errorInfoTextField; @property (weak) IBOutlet NSButton *togglePasswordButton; -@property (nonatomic, assign) BOOL shouldRememberKeyURL; @property (assign) BOOL showPassword; -- (IBAction)_decrypt:(id)sender; -- (IBAction)_clearKey:(id)sender; - @end @implementation MPPasswordInputController @@ -42,21 +38,20 @@ - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if(self) { - _showLastUsedKeyFile = NO; - _shouldRememberKeyURL = NO; - NSUserDefaultsController *defaultsController = [NSUserDefaultsController sharedUserDefaultsController]; - [self bind:@"shouldRememberKeyURL" toObject:defaultsController withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyRememberKeyFilesForDatabases ] options:nil]; - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_selectKeyURL) name:MPDocumentDidChangeStoredKeyFilesSettings object:nil]; } return self; } +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + - (void)didLoadView { [self.keyPathControl setDelegate:self.pathControlDelegate]; [self.errorImageView setImage:[NSImage imageNamed:NSImageNameCaution]]; [self.passwordTextField bind:@"showPassword" toObject:self withKeyPath:@"showPassword" options:nil]; [self.togglePasswordButton bind:NSValueBinding toObject:self withKeyPath:@"showPassword" options:nil]; - [self _reset]; } @@ -67,20 +62,6 @@ - (void)requestPassword { // show Warnign if read-only mode! [self _reset]; - if(self.showLastUsedKeyFile) { - [self _selectRecentKeyFile]; - } -} - -#pragma mark Properties -- (void)setShouldRememberKeyURL:(BOOL)shouldSelectKeyFile { - if(_shouldRememberKeyURL != shouldSelectKeyFile) { - _shouldRememberKeyURL = shouldSelectKeyFile; - if(!self.shouldRememberKeyURL) { - /* Remove any old settings to clean them up */ - [[NSUserDefaults standardUserDefaults] removeObjectForKey:kMPSettingsKeyRememeberdKeysForDatabases]; - } - } } #pragma mark - @@ -89,53 +70,29 @@ MPDocument *document = [[self windowController] document]; if(document) { NSError *error = nil; - NSURL *keyURL = [self.keyPathControl URL]; - if([document unlockWithPassword:[self.passwordTextField stringValue] keyFileURL:keyURL error:&error]) { - [self _setUsedKeyURL:keyURL forDocument:document]; - } - else { + if(![document unlockWithPassword:[self.passwordTextField stringValue] + keyFileURL:[self.keyPathControl URL] + error:&error]) { [self _showError:error]; } } } -- (IBAction)_clearKey:(id)sender { - [self.keyPathControl setURL:nil]; +- (IBAction)resetKeyFile:(id)sender { + [self _selectKeyURL]; } - (void)_reset { self.showPassword = NO; [self.passwordTextField setStringValue:@""]; - [self.keyPathControl setURL:nil]; [self.errorInfoTextField setHidden:YES]; [self.errorImageView setHidden:YES]; + [self resetKeyFile:nil]; } -- (void)_selectRecentKeyFile { - if(!self.shouldRememberKeyURL) { - [self.keyPathControl setURL:nil]; - return; // If we aren't supposed to preselect paths, clear them! - } - NSDictionary *keysForFiles = [[NSUserDefaults standardUserDefaults] dictionaryForKey:kMPSettingsKeyRememeberdKeysForDatabases]; +- (void)_selectKeyURL { MPDocument *document = [[self windowController] document]; - if(document) { - NSString *keyPath = keysForFiles[[[document fileURL] path]]; - NSURL *keyURL = keyPath != nil ? [NSURL fileURLWithPath:keyPath] : nil; - [self.keyPathControl setURL:keyURL]; - } -} - -- (void)_setUsedKeyURL:(NSURL *)keyURL forDocument:(NSDocument *)document { - if(!self.shouldRememberKeyURL) { - return; - } - NSMutableDictionary *keysForFiles = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:kMPSettingsKeyRememeberdKeysForDatabases] mutableCopy]; - if(nil == keysForFiles) { - keysForFiles = [[NSMutableDictionary alloc] initWithCapacity:1]; - } - //NSLog(@"remembering keyfile %@ for document %@ at URL %@", keyURL, [document displayName], [document fileURL]); - keysForFiles[[[document fileURL] path]] = [keyURL path]; - [[NSUserDefaults standardUserDefaults] setObject:keysForFiles forKey:kMPSettingsKeyRememeberdKeysForDatabases]; + [self.keyPathControl setURL:document.suggestedKeyURL]; } - (void)_showError:(NSError *)error { diff --git a/MacPass/MPPasteBoardController.h b/MacPass/MPPasteBoardController.h index 9f9cddd6..806bd90c 100644 --- a/MacPass/MPPasteBoardController.h +++ b/MacPass/MPPasteBoardController.h @@ -10,6 +10,17 @@ @interface MPPasteBoardController : NSObject +/** + * The PasteBoardController did copy new items to the pasteboard + * The userInfo dictionary is empty. You can optain the timeout via the clearTimeout property + */ +FOUNDATION_EXPORT NSString *const MPPasteBoardControllerDidCopyObjects; +/** + * The PasteBoardController did clear the clipboard. + * The userInfo dictionary is empty + */ +FOUNDATION_EXPORT NSString *const MPPasteBoardControllerDidClearClipboard; + /* This time sets the time interval after which a copied entry shoudl be purged from the pasteboard */ diff --git a/MacPass/MPPasteBoardController.m b/MacPass/MPPasteBoardController.m index bbdb4bbd..3b7aada6 100644 --- a/MacPass/MPPasteBoardController.m +++ b/MacPass/MPPasteBoardController.m @@ -9,6 +9,10 @@ #import "MPPasteBoardController.h" #import "MPSettingsHelper.h" +/* Notifications */ +NSString *const MPPasteBoardControllerDidCopyObjects = @"com.hicknhack.macpass.MPPasteBoardControllerDidCopyObjects"; +NSString *const MPPasteBoardControllerDidClearClipboard = @"com.hicknhack.macpass.MPPasteBoardControllerDidCopyObjects"; + @interface MPPasteBoardController () @property (assign) BOOL isEmpty; @@ -69,16 +73,21 @@ } - (void)copyObjects:(NSArray *)objects { + /* Should we save the old content ?*/ [[NSPasteboard generalPasteboard] clearContents]; [[NSPasteboard generalPasteboard] writeObjects:objects]; self.isEmpty = NO; - [self performSelector:@selector(_clearPasteboardContents) withObject:nil afterDelay:self.clearTimeout]; + if(self.clearTimeout != 0) { + [[NSNotificationCenter defaultCenter] postNotificationName:MPPasteBoardControllerDidCopyObjects object:self]; + [self performSelector:@selector(_clearPasteboardContents) withObject:nil afterDelay:self.clearTimeout]; + } } - (void)_clearPasteboardContents { /* Only clear stuff we might have put there */ if(!self.isEmpty) { [[NSPasteboard generalPasteboard] clearContents]; + [[NSNotificationCenter defaultCenter] postNotificationName:MPPasteBoardControllerDidClearClipboard object:self]; } self.isEmpty = YES; }