Update KeePassKit (Fixed Group order and Icon issue)

Enhanced database locking to actually encrypt the data although the file is not stored before (so changes might get lost)
Changed version handling a bit to make future export/save as possible
This commit is contained in:
michael starke
2013-09-03 00:44:55 +02:00
parent 0ae2946466
commit 2829e66877
10 changed files with 91 additions and 66 deletions

View File

@@ -13,5 +13,8 @@
FOUNDATION_EXPORT NSString *const MPPasteBoardType; FOUNDATION_EXPORT NSString *const MPPasteBoardType;
FOUNDATION_EXPORT NSString *const MPErrorDomain; FOUNDATION_EXPORT NSString *const MPErrorDomain;
FOUNDATION_EXPORT NSString *const MPLegacyDocumentUTI;
FOUNDATION_EXPORT NSString *const MPXMLDocumentUTI;
#endif #endif

View File

@@ -8,5 +8,7 @@
#import "MPConstants.h" #import "MPConstants.h"
NSString *const MPPasteBoardType = @"com.hicknhack.macpass.pasteboard"; NSString *const MPPasteBoardType = @"com.hicknhack.macpass.pasteboard";
NSString *const MPErrorDomain = @"com.hicknhack.macpass.error"; NSString *const MPErrorDomain = @"com.hicknhack.macpass.error";
NSString *const MPLegacyDocumentUTI = @"com.hicknhack.macpass.kdb";
NSString *const MPXMLDocumentUTI = @"com.hicknhack.macpass.kdbx";

View File

@@ -7,8 +7,7 @@
// //
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import "MPDatabaseVersion.h" #import "KPKVersion.h"
APPKIT_EXTERN NSString *const MPDocumentDidAddGroupNotification; APPKIT_EXTERN NSString *const MPDocumentDidAddGroupNotification;
APPKIT_EXTERN NSString *const MPDocumentDidRevertNotifiation; APPKIT_EXTERN NSString *const MPDocumentDidRevertNotifiation;
@@ -32,9 +31,7 @@ APPKIT_EXTERN NSString *const MPDocumnetDidChangeCurrentEntryNotification;
/* true, if password and/or keyfile are set */ /* true, if password and/or keyfile are set */
@property (assign, readonly) BOOL hasPasswordOrKey; @property (assign, readonly) BOOL hasPasswordOrKey;
/* true, if lock screen is present (no phyiscal locking) */ @property (nonatomic, readonly, assign) BOOL encrypted;
@property (assign, nonatomic) BOOL locked;
@property (assign, readonly) BOOL decrypted;
@property (strong, readonly, nonatomic) KPKTree *tree; @property (strong, readonly, nonatomic) KPKTree *tree;
@property (weak, readonly, nonatomic) KPKGroup *root; @property (weak, readonly, nonatomic) KPKGroup *root;
@@ -55,7 +52,7 @@ APPKIT_EXTERN NSString *const MPDocumnetDidChangeCurrentEntryNotification;
@property (nonatomic, weak) id selectedItem; @property (nonatomic, weak) id selectedItem;
- (id)initWithVersion:(MPDatabaseVersion)version; + (KPKVersion)versionForFileType:(NSString *)fileType;
#pragma mark Lock/Decrypt #pragma mark Lock/Decrypt
- (void)lockDatabase:(id)sender; - (void)lockDatabase:(id)sender;

View File

@@ -13,6 +13,7 @@
#import "MPActionHelper.h" #import "MPActionHelper.h"
#import "MPSettingsHelper.h" #import "MPSettingsHelper.h"
#import "MPNotifications.h" #import "MPNotifications.h"
#import "MPConstants.h"
#import "MPSavePanelAccessoryViewController.h" #import "MPSavePanelAccessoryViewController.h"
#import "DDXMLNode.h" #import "DDXMLNode.h"
@@ -48,7 +49,6 @@ typedef NS_ENUM(NSUInteger, MPAlertType) {
@property (weak, nonatomic) KPKGroup *root; @property (weak, nonatomic) KPKGroup *root;
@property (assign, nonatomic) BOOL hasPasswordOrKey; @property (assign, nonatomic) BOOL hasPasswordOrKey;
@property (assign) BOOL decrypted;
@property (assign) BOOL readOnly; @property (assign) BOOL readOnly;
@property (strong) NSURL *lockFileURL; @property (strong) NSURL *lockFileURL;
@@ -62,23 +62,28 @@ typedef NS_ENUM(NSUInteger, MPAlertType) {
@implementation MPDocument @implementation MPDocument
+ (KPKVersion)versionForFileType:(NSString *)fileType {
if( NSOrderedSame == [fileType compare:MPLegacyDocumentUTI options:NSCaseInsensitiveSearch]) {
return KPKLegacyVersion;
}
if( NSOrderedSame == [fileType compare:MPXMLDocumentUTI options:NSCaseInsensitiveSearch]) {
return KPKXmlVersion;
}
return KPKUnknownVersion;
}
+ (BOOL)autosavesInPlace { + (BOOL)autosavesInPlace {
return NO; return NO;
} }
- (id)init { - (id)init {
return [self initWithVersion:MPDatabaseVersion4];
}
#pragma mark NSDocument essentials
- (id)initWithVersion:(MPDatabaseVersion)version {
self = [super init]; self = [super init];
if(self) { if(self) {
_encryptedData = nil; _encryptedData = nil;
_didLockFile = NO; _didLockFile = NO;
_decrypted = YES;
_hasPasswordOrKey = NO; _hasPasswordOrKey = NO;
_locked = NO;
_readOnly = NO; _readOnly = NO;
[self setFileType:MPXMLDocumentUTI];
self.tree = [KPKTree templateTree]; self.tree = [KPKTree templateTree];
} }
return self; return self;
@@ -99,11 +104,15 @@ typedef NS_ENUM(NSUInteger, MPAlertType) {
} }
- (BOOL)writeToURL:(NSURL *)url ofType:(NSString *)typeName error:(NSError **)outError { - (BOOL)writeToURL:(NSURL *)url ofType:(NSString *)typeName error:(NSError **)outError {
/* KPKPassword *password = [[KPKPassword alloc] initWithPassword:self.password key:self.key];
Move this to data:ofType: method with KeePassKit KPKVersion version = [[self class] versionForFileType:(NSString *)typeName];
*/ if(version == KPKUnknownVersion) {
KPKPassword *password = nil; if(outError != NULL) {
NSData *treeData = [self.tree encryptWithPassword:password forVersion:KPKXmlVersion error:outError]; *outError = [NSError errorWithDomain:MPErrorDomain code:0 userInfo:nil];
}
return NO;
}
NSData *treeData = [self.tree encryptWithPassword:password forVersion:version error:outError];
if([treeData writeToURL:url options:NSDataWritingAtomic error:outError]) { if([treeData writeToURL:url options:NSDataWritingAtomic error:outError]) {
NSLog(@"%@", [*outError localizedDescription]); NSLog(@"%@", [*outError localizedDescription]);
return NO; return NO;
@@ -128,7 +137,6 @@ typedef NS_ENUM(NSUInteger, MPAlertType) {
*/ */
self.tree = nil; self.tree = nil;
_encryptedData = [NSData dataWithContentsOfURL:url options:NSDataReadingUncached error:outError]; _encryptedData = [NSData dataWithContentsOfURL:url options:NSDataReadingUncached error:outError];
self.decrypted = NO;
return YES; return YES;
} }
@@ -142,7 +150,7 @@ typedef NS_ENUM(NSUInteger, MPAlertType) {
} }
- (BOOL)isEntireFileLoaded { - (BOOL)isEntireFileLoaded {
return _decrypted; return YES;
} }
- (void)close { - (void)close {
@@ -183,14 +191,11 @@ typedef NS_ENUM(NSUInteger, MPAlertType) {
self.key = keyFileURL; self.key = keyFileURL;
self.password = [password length] > 0 ? password : nil; self.password = [password length] > 0 ? password : nil;
NSError *error; NSError *error;
self.tree = [[KPKTree alloc] initWithData:_encryptedData password:passwordData error:&error]; self.tree = [[KPKTree alloc] initWithData:_encryptedData password:passwordData error:&error];
if(self.tree) {
self.decrypted = YES; return (self.tree != nil);
return YES;
}
self.decrypted = NO;
return NO;
} }
- (void)lockDatabase:(id)sender { - (void)lockDatabase:(id)sender {
@@ -199,10 +204,18 @@ typedef NS_ENUM(NSUInteger, MPAlertType) {
/* Locking needs to be lossless hence just use the XML format */ /* Locking needs to be lossless hence just use the XML format */
_encryptedData = [self.tree encryptWithPassword:password forVersion:KPKXmlVersion error:&error]; _encryptedData = [self.tree encryptWithPassword:password forVersion:KPKXmlVersion error:&error];
self.tree = nil; self.tree = nil;
self.locked = YES;
} }
#pragma mark Custom Setter #pragma mark Properties
- (BOOL)encrypted {
return (self.tree == nil);
}
- (KPKGroup *)root {
return self.tree.root;
}
- (void)setPassword:(NSString *)password { - (void)setPassword:(NSString *)password {
if(![_password isEqualToString:password]) { if(![_password isEqualToString:password]) {
_password = [password copy]; _password = [password copy];
@@ -237,8 +250,6 @@ typedef NS_ENUM(NSUInteger, MPAlertType) {
[[NSNotificationCenter defaultCenter] postNotificationName:MPCurrentItemChangedNotification object:self]; [[NSNotificationCenter defaultCenter] postNotificationName:MPCurrentItemChangedNotification object:self];
} }
} }
#pragma mark Data Accesors
- (void)setTree:(KPKTree *)tree { - (void)setTree:(KPKTree *)tree {
if(_tree != tree) { if(_tree != tree) {
_tree = tree; _tree = tree;
@@ -246,9 +257,7 @@ typedef NS_ENUM(NSUInteger, MPAlertType) {
} }
} }
- (KPKGroup *)root { #pragma mark Data Accesors
return self.tree.root;
}
- (KPKEntry *)findEntry:(NSUUID *)uuid { - (KPKEntry *)findEntry:(NSUUID *)uuid {
return [self.root entryForUUID:uuid]; return [self.root entryForUUID:uuid];

View File

@@ -22,6 +22,7 @@
#import "MPDocumentWindowDelegate.h" #import "MPDocumentWindowDelegate.h"
#import "MPContextToolbarButton.h" #import "MPContextToolbarButton.h"
#import "KPKTree.h"
@interface MPDocumentWindowController () { @interface MPDocumentWindowController () {
@private @private
@@ -68,12 +69,12 @@
[super windowDidLoad]; [super windowDidLoad];
/* Drag and Drop of URLS is working, but the current /* Drag and Drop of URLS is working, but the current
und/Redo system cannot guarantee that the undomanager is found und/Redo system cannot guarantee that the undomanager is found
when no window is active, thus this needs to be addresed when switching to KeePassKit when no window is active, thus this needs to be addresed when switching to KeePassKit
[[self window] setDelegate:self.documentWindowDelegate]; [[self window] setDelegate:self.documentWindowDelegate];
[[self window] registerForDraggedTypes:@[NSURLPboardType]]; [[self window] registerForDraggedTypes:@[NSURLPboardType]];
*/ */
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didRevertDocument:) name:MPDocumentDidRevertNotifiation object:[self document]]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didRevertDocument:) name:MPDocumentDidRevertNotifiation object:[self document]];
@@ -107,7 +108,7 @@
} }
MPDocument *document = [self document]; MPDocument *document = [self document];
if(!document.decrypted) { if(document.encrypted) {
[self showPasswordInput]; [self showPasswordInput];
} }
else { else {
@@ -157,6 +158,23 @@
#pragma mark Actions #pragma mark Actions
- (void)saveDocument:(id)sender { - (void)saveDocument:(id)sender {
MPDocument *document = [self document]; MPDocument *document = [self document];
NSString *fileType = [document fileType];
/* we did open as legacy */
if([fileType isEqualToString:MPLegacyDocumentUTI]) {
if(document.tree.minimumVersion != KPKLegacyVersion) {
NSAlert *alert = [[NSAlert alloc] init];
[alert setAlertStyle:NSWarningAlertStyle];
[alert setMessageText:NSLocalizedString(@"WARNING_ON_LOSSY_SAVE", "")];
[alert setInformativeText:NSLocalizedString(@"WARNING_ON_LOSSY_SAVE_DESCRIPTION", "Informative Text displayed when saving woudl yield data loss")];
[alert addButtonWithTitle:NSLocalizedString(@"SAVE", "Save lossy")];
[alert addButtonWithTitle:NSLocalizedString(@"CANCEL", "Cancel")];
[[alert buttons][1] setKeyEquivalent:[NSString stringWithFormat:@"%c", 0x1b]];
[alert beginSheetModalForWindow:[self window] modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
return;
}
}
if(!document.hasPasswordOrKey) { if(!document.hasPasswordOrKey) {
// warning if no password ist set! // warning if no password ist set!
} }
@@ -180,7 +198,7 @@
SEL itemAction = [menuItem action]; SEL itemAction = [menuItem action];
if(itemAction == @selector(showDatabaseSettings:) if(itemAction == @selector(showDatabaseSettings:)
|| itemAction == @selector(editPassword:)) { || itemAction == @selector(editPassword:)) {
return document.decrypted && !document.isLocked; return !document.encrypted;
} }
BOOL enabled = YES; BOOL enabled = YES;
@@ -188,13 +206,13 @@
enabled &= (nil != document.selectedItem) && (document.selectedItem != document.trash); enabled &= (nil != document.selectedItem) && (document.selectedItem != document.trash);
} }
enabled &= !( !document.decrypted || document.isLocked || document.isReadOnly ); enabled &= !( !document.encrypted || document.isReadOnly );
return enabled; return enabled;
} }
- (BOOL)validateToolbarItem:(NSToolbarItem *)theItem { - (BOOL)validateToolbarItem:(NSToolbarItem *)theItem {
MPDocument *document = [self document]; MPDocument *document = [self document];
if(!document.decrypted || document.isLocked || document.isReadOnly) { if(document.encrypted || document.isReadOnly) {
return NO; return NO;
} }
MPActionType actionType = [MPActionHelper typeForAction:[theItem action]]; MPActionType actionType = [MPActionHelper typeForAction:[theItem action]];
@@ -222,7 +240,7 @@
- (BOOL)validateAction:(SEL)action forItem:(id)item { - (BOOL)validateAction:(SEL)action forItem:(id)item {
MPDocument *document = [self document]; MPDocument *document = [self document];
if(!document.decrypted || document.isLocked || document.isReadOnly) { if(document.encrypted || document.isReadOnly) {
return NO; return NO;
} }
MPActionType actionType = [MPActionHelper typeForAction:action]; MPActionType actionType = [MPActionHelper typeForAction:action];
@@ -281,11 +299,11 @@
if(!document.hasPasswordOrKey) { if(!document.hasPasswordOrKey) {
return; // Document needs a password/keyfile to be lockable return; // Document needs a password/keyfile to be lockable
} }
if(document.isLocked) { if(document.encrypted) {
return; // Document already locked return; // Document already locked
} }
document.locked = YES;
[self showPasswordInput]; [self showPasswordInput];
[document lockDatabase:sender];
} }
- (void)createGroup:(id)sender { - (void)createGroup:(id)sender {
@@ -372,9 +390,6 @@
} }
[contentView layoutSubtreeIfNeeded]; [contentView layoutSubtreeIfNeeded];
MPDocument *document = [self document];
document.locked = NO;
[_entryViewController updateResponderChain]; [_entryViewController updateResponderChain];
[_inspectorViewController updateResponderChain]; [_inspectorViewController updateResponderChain];
[_outlineViewController updateResponderChain]; [_outlineViewController updateResponderChain];

View File

@@ -16,7 +16,7 @@
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender { - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
MPDocument *document = [[[sender draggingDestinationWindow] windowController] document]; MPDocument *document = [[[sender draggingDestinationWindow] windowController] document];
if(document.isLocked || !document.decrypted) { if(document.encrypted) {
return NSDragOperationNone; return NSDragOperationNone;
} }

View File

@@ -60,19 +60,8 @@
id windowController = [[[self view] window] windowController]; id windowController = [[[self view] window] windowController];
MPDocument *document = [windowController document]; MPDocument *document = [windowController document];
if(document) { if(document) {
BOOL isOk = NO; if(![document unlockWithPassword:[self.passwordTextField stringValue]
if(document.decrypted) { keyFileURL:[self.keyPathControl URL]]) {
// TODO: Fix unlocking to actually test
BOOL noPassword = !document.password && [[self.passwordTextField stringValue] length] == 0;
BOOL passwordOk = [document.password isEqualToString:[self.passwordTextField stringValue]];
BOOL noKey = document.key == [self.keyPathControl URL];
BOOL keyOk = [document.key isEqualTo:[self.keyPathControl URL]];
isOk = (noPassword || passwordOk) && (noKey || keyOk);
}
else {
isOk = [document unlockWithPassword:[self.passwordTextField stringValue] keyFileURL:[self.keyPathControl URL]];
}
if(!isOk) {
[self _showError]; [self _showError];
} }
else { else {

View File

@@ -7,12 +7,15 @@
// //
#import "MPViewController.h" #import "MPViewController.h"
#import "KPKVersion.h"
@class MPDocument; @class MPDocument;
@interface MPSavePanelAccessoryViewController : MPViewController @interface MPSavePanelAccessoryViewController : MPViewController
@property (nonatomic, assign) NSSavePanel *savePanel; @property (nonatomic, assign) NSSavePanel *savePanel;
@property (nonatomic, assign) MPDocument *document; @property (nonatomic, assign) MPDocument *document;
@property (nonatomic, assign, readonly) KPKVersion selectedVersion;
@property (nonatomic, weak) IBOutlet NSPopUpButton *fileTypePopupButton; @property (nonatomic, weak) IBOutlet NSPopUpButton *fileTypePopupButton;
@property (nonatomic, weak) IBOutlet NSTextField *infoTextField; @property (nonatomic, weak) IBOutlet NSTextField *infoTextField;

View File

@@ -8,12 +8,13 @@
#import "MPSavePanelAccessoryViewController.h" #import "MPSavePanelAccessoryViewController.h"
#import "MPDocument.h" #import "MPDocument.h"
#import "MPConstants.h"
#import "KPKUTIs.h" #import "KPKUTIs.h"
#import "KPKTree.h" #import "KPKTree.h"
@interface MPSavePanelAccessoryViewController () @interface MPSavePanelAccessoryViewController ()
@property (readwrite, assign) KPKVersion selectedVersion;
@end @end
@implementation MPSavePanelAccessoryViewController @implementation MPSavePanelAccessoryViewController
@@ -45,7 +46,13 @@
- (IBAction)setFileType:(id)sender { - (IBAction)setFileType:(id)sender {
NSString *uti = [[self.fileTypePopupButton selectedItem] representedObject]; NSString *uti = [[self.fileTypePopupButton selectedItem] representedObject];
BOOL showInfoText = (self.document.tree.minimumVersion == KPKLegacyVersion && [uti isEqualToString:@"com.hicknhack.macpass.kdb"]); if([uti isEqualToString:MPLegacyDocumentUTI]) {
self.selectedVersion = KPKLegacyVersion;
}
else if([uti isEqualToString:MPLegacyDocumentUTI]) {
self.selectedVersion = KPKXmlVersion;
}
BOOL showInfoText = (self.document.tree.minimumVersion == KPKLegacyVersion && [uti isEqualToString:MPLegacyDocumentUTI]);
[self.infoTextField setHidden:!showInfoText]; [self.infoTextField setHidden:!showInfoText];
[self.savePanel setAllowedFileTypes:@[uti]]; [self.savePanel setAllowedFileTypes:@[uti]];
} }