Refactored key file storing into the document.

This commit is contained in:
michael starke
2013-11-17 23:59:36 +01:00
parent cb64396172
commit 9192504939
9 changed files with 98 additions and 73 deletions

View File

@@ -74,7 +74,7 @@
<constraints> <constraints>
<constraint firstAttribute="width" constant="165" id="877"/> <constraint firstAttribute="width" constant="165" id="877"/>
</constraints> </constraints>
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="420"> <popUpButtonCell key="cell" type="push" title="after 1 Minute" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" tag="60" imageScaling="proportionallyDown" inset="2" selectedItem="424" id="420">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/> <font key="font" metaFont="menu"/>
<menu key="menu" title="ClipboardClearInterval" id="421"> <menu key="menu" title="ClipboardClearInterval" id="421">
@@ -84,7 +84,7 @@
</menuItem> </menuItem>
<menuItem title="after 10 Seconds" tag="10" id="422"/> <menuItem title="after 10 Seconds" tag="10" id="422"/>
<menuItem title="after 30 Seconds" tag="30" id="423"/> <menuItem title="after 30 Seconds" tag="30" id="423"/>
<menuItem title="after 1 Minute" tag="60" id="424"/> <menuItem title="after 1 Minute" state="on" tag="60" id="424"/>
</items> </items>
</menu> </menu>
</popUpButtonCell> </popUpButtonCell>

View File

@@ -23,7 +23,7 @@
<rect key="frame" x="0.0" y="0.0" width="524" height="303"/> <rect key="frame" x="0.0" y="0.0" width="524" height="303"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews> <subviews>
<button translatesAutoresizingMaskIntoConstraints="NO" id="2"> <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="2">
<rect key="frame" x="320" y="65" width="83" height="32"/> <rect key="frame" x="320" y="65" width="83" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Unlock" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="3"> <buttonCell key="cell" type="push" title="Unlock" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="3">
@@ -111,7 +111,7 @@ DQ
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
</buttonCell> </buttonCell>
<connections> <connections>
<action selector="_clearKey:" target="-2" id="494"/> <action selector="resetKeyFile:" target="-2" id="2Zh-0g-L0i"/>
</connections> </connections>
</button> </button>
</subviews> </subviews>

View File

@@ -9,6 +9,8 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import "KPKVersion.h" #import "KPKVersion.h"
APPKIT_EXTERN NSString *const MPDocumentDidChangeStoredKeyFilesSettings;
APPKIT_EXTERN NSString *const MPDocumentDidAddGroupNotification; APPKIT_EXTERN NSString *const MPDocumentDidAddGroupNotification;
APPKIT_EXTERN NSString *const MPDocumentDidRevertNotifiation; APPKIT_EXTERN NSString *const MPDocumentDidRevertNotifiation;
@@ -55,6 +57,14 @@ APPKIT_EXTERN NSString *const MPDocumentGroupKey;
#pragma mark Lock/Decrypt #pragma mark Lock/Decrypt
- (void)lockDatabase:(id)sender; - (void)lockDatabase:(id)sender;
- (BOOL)unlockWithPassword:(NSString *)password keyFileURL:(NSURL *)keyFileURL error:(NSError *__autoreleasing*)error; - (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 #pragma mark Data Lookup
/** /**

View File

@@ -26,6 +26,8 @@
#import "KPKMetaData.h" #import "KPKMetaData.h"
#import "KPKAttribute.h" #import "KPKAttribute.h"
NSString *const MPDocumentDidChangeStoredKeyFilesSettings = @"com.hicknhack.macpass.MPDocumentDidChangeStoredKeyFilesSettings";
NSString *const MPDocumentDidAddGroupNotification = @"com.hicknhack.macpass.MPDocumentDidAddGroupNotification"; NSString *const MPDocumentDidAddGroupNotification = @"com.hicknhack.macpass.MPDocumentDidAddGroupNotification";
NSString *const MPDocumentDidRevertNotifiation = @"com.hicknhack.macpass.MPDocumentDidRevertNotifiation"; NSString *const MPDocumentDidRevertNotifiation = @"com.hicknhack.macpass.MPDocumentDidRevertNotifiation";
@@ -52,8 +54,8 @@ typedef NS_ENUM(NSUInteger, MPAlertType) {
@property (weak, nonatomic) KPKGroup *root; @property (weak, nonatomic) KPKGroup *root;
@property (assign) BOOL readOnly; @property (assign) BOOL readOnly;
@property (strong) NSURL *lockFileURL; @property (strong) NSURL *lockFileURL;
@property (nonatomic, assign) BOOL isAllowedToStoreKeyFile;
@property (readonly) BOOL useTrash; @property (readonly) BOOL useTrash;
@property (strong) IBOutlet NSView *warningView; @property (strong) IBOutlet NSView *warningView;
@@ -97,12 +99,18 @@ typedef NS_ENUM(NSUInteger, MPAlertType) {
_encryptedData = nil; _encryptedData = nil;
_didLockFile = NO; _didLockFile = NO;
_readOnly = NO; _readOnly = NO;
_isAllowedToStoreKeyFile = NO;
self.tree = [KPKTree templateTree]; self.tree = [KPKTree templateTree];
[self bind:@"isAllowedToStoreKeyFile"
toObject:[NSUserDefaultsController sharedUserDefaultsController]
withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyRememberKeyFilesForDatabases]
options:nil];
} }
return self; return self;
} }
- (void)dealloc { - (void)dealloc {
[self unbind:@"isAllowedToStoreKeyFile"];
[self _cleanupLock]; [self _cleanupLock];
} }
@@ -212,6 +220,13 @@ typedef NS_ENUM(NSUInteger, MPAlertType) {
#pragma mark Lock/Unlock/Decrypt #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{ - (BOOL)unlockWithPassword:(NSString *)password keyFileURL:(NSURL *)keyFileURL error:(NSError *__autoreleasing*)error{
self.compositeKey = [[KPKCompositeKey alloc] initWithPassword:password key:keyFileURL]; self.compositeKey = [[KPKCompositeKey alloc] initWithPassword:password key:keyFileURL];
self.tree = [[KPKTree alloc] initWithData:_encryptedData password:self.compositeKey error:error]; 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); BOOL isUnlocked = (nil != self.tree);
if(isUnlocked) { if(isUnlocked) {
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidUnlockDatabaseNotification object:self]; [[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidUnlockDatabaseNotification object:self];
if([password length] > 0 && self.isAllowedToStoreKeyFile) {
[self _storeKeyURL:keyFileURL];
}
} }
else { else {
self.compositeKey = nil; // clear the key? self.compositeKey = nil; // clear the key?
@@ -226,11 +244,16 @@ typedef NS_ENUM(NSUInteger, MPAlertType) {
return isUnlocked; return isUnlocked;
} }
- (void)lockDatabase:(id)sender { - (NSURL *)suggestedKeyURL {
NSError *error; if(!self.isAllowedToStoreKeyFile) {
/* Locking needs to be lossless hence just use the XML format */ return nil;
_encryptedData = [self.tree encryptWithPassword:self.compositeKey forVersion:KPKXmlVersion error:&error]; }
self.tree = nil; NSDictionary *keysForFiles = [[NSUserDefaults standardUserDefaults] dictionaryForKey:kMPSettingsKeyRememeberdKeysForDatabases];
NSString *keyPath = keysForFiles[[[self fileURL] path]];
if(!keyPath) {
return nil;
}
return [NSURL fileURLWithPath:keyPath];
} }
#pragma mark Properties #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 #pragma mark Data Accesors
- (KPKEntry *)findEntry:(NSUUID *)uuid { - (KPKEntry *)findEntry:(NSUUID *)uuid {
@@ -474,6 +508,16 @@ typedef NS_ENUM(NSUInteger, MPAlertType) {
return [super validateUserInterfaceItem:anItem]; 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 { - (void)_cleanupLock {
if(_didLockFile) { if(_didLockFile) {
[[NSFileManager defaultManager] removeItemAtURL:_lockFileURL error:nil]; [[NSFileManager defaultManager] removeItemAtURL:_lockFileURL error:nil];

View File

@@ -283,10 +283,6 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) {
- (void)showPasswordInput { - (void)showPasswordInput {
if(!self.passwordInputController) { if(!self.passwordInputController) {
self.passwordInputController = [[MPPasswordInputController alloc] init]; self.passwordInputController = [[MPPasswordInputController alloc] init];
self.passwordInputController.showLastUsedKeyFile = YES;
}
else {
self.passwordInputController.showLastUsedKeyFile = NO;
} }
[self _setContentViewController:self.passwordInputController]; [self _setContentViewController:self.passwordInputController];
[self.passwordInputController requestPassword]; [self.passwordInputController requestPassword];

View File

@@ -10,8 +10,6 @@
@interface MPPasswordInputController : MPViewController @interface MPPasswordInputController : MPViewController
@property (nonatomic, assign) BOOL showLastUsedKeyFile;
- (void)requestPassword; - (void)requestPassword;
@end @end

View File

@@ -24,12 +24,8 @@
@property (weak) IBOutlet NSTextField *errorInfoTextField; @property (weak) IBOutlet NSTextField *errorInfoTextField;
@property (weak) IBOutlet NSButton *togglePasswordButton; @property (weak) IBOutlet NSButton *togglePasswordButton;
@property (nonatomic, assign) BOOL shouldRememberKeyURL;
@property (assign) BOOL showPassword; @property (assign) BOOL showPassword;
- (IBAction)_decrypt:(id)sender;
- (IBAction)_clearKey:(id)sender;
@end @end
@implementation MPPasswordInputController @implementation MPPasswordInputController
@@ -42,21 +38,20 @@
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if(self) { if(self) {
_showLastUsedKeyFile = NO; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_selectKeyURL) name:MPDocumentDidChangeStoredKeyFilesSettings object:nil];
_shouldRememberKeyURL = NO;
NSUserDefaultsController *defaultsController = [NSUserDefaultsController sharedUserDefaultsController];
[self bind:@"shouldRememberKeyURL" toObject:defaultsController withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyRememberKeyFilesForDatabases ] options:nil];
} }
return self; return self;
} }
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)didLoadView { - (void)didLoadView {
[self.keyPathControl setDelegate:self.pathControlDelegate]; [self.keyPathControl setDelegate:self.pathControlDelegate];
[self.errorImageView setImage:[NSImage imageNamed:NSImageNameCaution]]; [self.errorImageView setImage:[NSImage imageNamed:NSImageNameCaution]];
[self.passwordTextField bind:@"showPassword" toObject:self withKeyPath:@"showPassword" options:nil]; [self.passwordTextField bind:@"showPassword" toObject:self withKeyPath:@"showPassword" options:nil];
[self.togglePasswordButton bind:NSValueBinding toObject:self withKeyPath:@"showPassword" options:nil]; [self.togglePasswordButton bind:NSValueBinding toObject:self withKeyPath:@"showPassword" options:nil];
[self _reset]; [self _reset];
} }
@@ -67,20 +62,6 @@
- (void)requestPassword { - (void)requestPassword {
// show Warnign if read-only mode! // show Warnign if read-only mode!
[self _reset]; [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 - #pragma mark -
@@ -89,53 +70,29 @@
MPDocument *document = [[self windowController] document]; MPDocument *document = [[self windowController] document];
if(document) { if(document) {
NSError *error = nil; NSError *error = nil;
NSURL *keyURL = [self.keyPathControl URL]; if(![document unlockWithPassword:[self.passwordTextField stringValue]
if([document unlockWithPassword:[self.passwordTextField stringValue] keyFileURL:keyURL error:&error]) { keyFileURL:[self.keyPathControl URL]
[self _setUsedKeyURL:keyURL forDocument:document]; error:&error]) {
}
else {
[self _showError:error]; [self _showError:error];
} }
} }
} }
- (IBAction)_clearKey:(id)sender { - (IBAction)resetKeyFile:(id)sender {
[self.keyPathControl setURL:nil]; [self _selectKeyURL];
} }
- (void)_reset { - (void)_reset {
self.showPassword = NO; self.showPassword = NO;
[self.passwordTextField setStringValue:@""]; [self.passwordTextField setStringValue:@""];
[self.keyPathControl setURL:nil];
[self.errorInfoTextField setHidden:YES]; [self.errorInfoTextField setHidden:YES];
[self.errorImageView setHidden:YES]; [self.errorImageView setHidden:YES];
[self resetKeyFile:nil];
} }
- (void)_selectRecentKeyFile { - (void)_selectKeyURL {
if(!self.shouldRememberKeyURL) {
[self.keyPathControl setURL:nil];
return; // If we aren't supposed to preselect paths, clear them!
}
NSDictionary *keysForFiles = [[NSUserDefaults standardUserDefaults] dictionaryForKey:kMPSettingsKeyRememeberdKeysForDatabases];
MPDocument *document = [[self windowController] document]; MPDocument *document = [[self windowController] document];
if(document) { [self.keyPathControl setURL:document.suggestedKeyURL];
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];
} }
- (void)_showError:(NSError *)error { - (void)_showError:(NSError *)error {

View File

@@ -10,6 +10,17 @@
@interface MPPasteBoardController : NSObject @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 This time sets the time interval after which a copied entry shoudl be purged from the pasteboard
*/ */

View File

@@ -9,6 +9,10 @@
#import "MPPasteBoardController.h" #import "MPPasteBoardController.h"
#import "MPSettingsHelper.h" #import "MPSettingsHelper.h"
/* Notifications */
NSString *const MPPasteBoardControllerDidCopyObjects = @"com.hicknhack.macpass.MPPasteBoardControllerDidCopyObjects";
NSString *const MPPasteBoardControllerDidClearClipboard = @"com.hicknhack.macpass.MPPasteBoardControllerDidCopyObjects";
@interface MPPasteBoardController () @interface MPPasteBoardController ()
@property (assign) BOOL isEmpty; @property (assign) BOOL isEmpty;
@@ -69,16 +73,21 @@
} }
- (void)copyObjects:(NSArray *)objects { - (void)copyObjects:(NSArray *)objects {
/* Should we save the old content ?*/
[[NSPasteboard generalPasteboard] clearContents]; [[NSPasteboard generalPasteboard] clearContents];
[[NSPasteboard generalPasteboard] writeObjects:objects]; [[NSPasteboard generalPasteboard] writeObjects:objects];
self.isEmpty = NO; self.isEmpty = NO;
if(self.clearTimeout != 0) {
[[NSNotificationCenter defaultCenter] postNotificationName:MPPasteBoardControllerDidCopyObjects object:self];
[self performSelector:@selector(_clearPasteboardContents) withObject:nil afterDelay:self.clearTimeout]; [self performSelector:@selector(_clearPasteboardContents) withObject:nil afterDelay:self.clearTimeout];
}
} }
- (void)_clearPasteboardContents { - (void)_clearPasteboardContents {
/* Only clear stuff we might have put there */ /* Only clear stuff we might have put there */
if(!self.isEmpty) { if(!self.isEmpty) {
[[NSPasteboard generalPasteboard] clearContents]; [[NSPasteboard generalPasteboard] clearContents];
[[NSNotificationCenter defaultCenter] postNotificationName:MPPasteBoardControllerDidClearClipboard object:self];
} }
self.isEmpty = YES; self.isEmpty = YES;
} }