diff --git a/MacPass/Base.lproj/EntryInspectorView.xib b/MacPass/Base.lproj/EntryInspectorView.xib index e6645f26..ec71694e 100644 --- a/MacPass/Base.lproj/EntryInspectorView.xib +++ b/MacPass/Base.lproj/EntryInspectorView.xib @@ -1,8 +1,9 @@ - - + + - + + @@ -95,10 +96,10 @@ - + - + @@ -215,7 +216,6 @@ - @@ -275,10 +275,10 @@ - + - + @@ -399,7 +399,6 @@ - @@ -489,7 +488,7 @@ - + @@ -743,7 +742,7 @@ - + @@ -768,6 +767,7 @@ + @@ -784,7 +784,6 @@ - diff --git a/MacPass/ContextBar.xib b/MacPass/ContextBar.xib index d5efa587..82fa7e84 100644 --- a/MacPass/ContextBar.xib +++ b/MacPass/ContextBar.xib @@ -1,8 +1,9 @@ - - + + - + + diff --git a/MacPass/DDHotKey+MacPassAdditions.h b/MacPass/DDHotKey+MacPassAdditions.h index 5ae2442c..3ebcf040 100644 --- a/MacPass/DDHotKey+MacPassAdditions.h +++ b/MacPass/DDHotKey+MacPassAdditions.h @@ -12,11 +12,17 @@ @property (readonly, copy) NSData *keyData; + +/** + Use this method to retrieve the data, since deallocation of a hotkey unregisters it, this could yield unwanted behaviour! + @return data for the default hot key. +*/ ++ (NSData *)hotKeyDataWithKeyCode:(unsigned short)keyCode modifierFlags:(NSUInteger)flags; ++ (NSData *)defaultHotKeyData; + (instancetype)defaultHotKey; + (instancetype)defaultHotKeyWithTask:(DDHotKeyTask)task; - -- (instancetype)initWithKeyData:(NSData *)data task:(DDHotKeyTask)task; -- (instancetype)initWithKeyData:(NSData *)data; ++ (instancetype)hotKeyWithKeyData:(NSData *)data task:(DDHotKeyTask)task; ++ (instancetype)hotKeyWithKeyData:(NSData *)data; @end diff --git a/MacPass/DDHotKey+MacPassAdditions.m b/MacPass/DDHotKey+MacPassAdditions.m index db1fc74d..40ed2281 100644 --- a/MacPass/DDHotKey+MacPassAdditions.m +++ b/MacPass/DDHotKey+MacPassAdditions.m @@ -14,45 +14,48 @@ @implementation DDHotKey (MPKeydata) ++ (NSData *)hotKeyDataWithKeyCode:(unsigned short)keyCode modifierFlags:(NSUInteger)flags { + NSMutableData *data = [[NSMutableData alloc] init]; + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; + [archiver encodeInt:keyCode forKey:NSStringFromSelector(@selector(keyCode))]; + [archiver encodeInteger:flags forKey:NSStringFromSelector(@selector(modifierFlags))]; + [archiver finishEncoding]; + return [data copy]; +} + ++ (NSData *)defaultHotKeyData { + return [self hotKeyDataWithKeyCode:kVK_ANSI_M modifierFlags:kCGEventFlagMaskControl|kCGEventFlagMaskAlternate]; +} + + (instancetype)defaultHotKey { return [DDHotKey defaultHotKeyWithTask:nil]; } + (instancetype)defaultHotKeyWithTask:(DDHotKeyTask)task { - return [[DDHotKey alloc] initWithKeyData:nil task:task]; + return [DDHotKey hotKeyWithKeyData:nil task:task]; } -- (instancetype)initWithKeyData:(NSData *)data { - self = [self initWithKeyData:data task:nil]; - return self; ++ (instancetype)hotKeyWithKeyData:(NSData *)data { + return [self hotKeyWithKeyData:data task:nil]; } -- (instancetype)initWithKeyData:(NSData *)data task:(DDHotKeyTask)task{ ++ (instancetype)hotKeyWithKeyData:(NSData *)data task:(DDHotKeyTask)task { NSUInteger modifierFlags; unsigned short keyCode; if(!data) { - self = [DDHotKey hotKeyWithKeyCode:kVK_ANSI_M modifierFlags:kCGEventFlagMaskControl|kCGEventFlagMaskAlternate task:task]; + return [DDHotKey hotKeyWithKeyCode:kVK_ANSI_M modifierFlags:kCGEventFlagMaskControl|kCGEventFlagMaskAlternate task:task]; } - else if([self _getKeyCode:&keyCode modifierFlags:&modifierFlags fromData:data]) { - self = [DDHotKey hotKeyWithKeyCode:keyCode modifierFlags:modifierFlags task:task]; + if([self _getKeyCode:&keyCode modifierFlags:&modifierFlags fromData:data]) { + return [DDHotKey hotKeyWithKeyCode:keyCode modifierFlags:modifierFlags task:task]; } - else { - self = nil; - } - return self; + return nil; } - (NSData *)keyData { - NSMutableData *data = [[NSMutableData alloc] init]; - NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; - [archiver encodeInt:self.keyCode forKey:NSStringFromSelector(@selector(keyCode))]; - [archiver encodeInteger:self.modifierFlags forKey:NSStringFromSelector(@selector(modifierFlags))]; - [archiver finishEncoding]; - return [data copy]; + return [self.class hotKeyDataWithKeyCode:self.keyCode modifierFlags:self.modifierFlags]; } - -- (BOOL)_getKeyCode:(unsigned short *)keyCode modifierFlags:(NSUInteger *)modifierFlags fromData:(NSData *)data { ++ (BOOL)_getKeyCode:(unsigned short *)keyCode modifierFlags:(NSUInteger *)modifierFlags fromData:(NSData *)data { if(keyCode == NULL || modifierFlags == NULL || data == nil) { return NO; } diff --git a/MacPass/MPAttachmentTableDataSource.m b/MacPass/MPAttachmentTableDataSource.m index ede6825c..56df38c0 100644 --- a/MacPass/MPAttachmentTableDataSource.m +++ b/MacPass/MPAttachmentTableDataSource.m @@ -52,7 +52,7 @@ KPKEntry *entry = document.selectedEntries.count == 1 ? document.selectedEntries.lastObject : nil; NSPasteboard *draggingPasteBoard = [info draggingPasteboard]; - NSArray *arrayOfURLs = [draggingPasteBoard readObjectsForClasses:@[[NSArray class]] options:nil]; + NSArray *arrayOfURLs = [draggingPasteBoard readObjectsForClasses:@[[NSURL class]] options:nil]; for(NSURL *fileUrl in arrayOfURLs) { [document addAttachment:fileUrl toEntry:entry]; diff --git a/MacPass/MPAutotypeDaemon.m b/MacPass/MPAutotypeDaemon.m index 715bf69e..db48fc4c 100644 --- a/MacPass/MPAutotypeDaemon.m +++ b/MacPass/MPAutotypeDaemon.m @@ -147,16 +147,32 @@ static MPAutotypeDaemon *_sharedInstance; return; // We do not perform Autotype on ourselves } - NSArray *documents = [self _findAutotypeDocuments]; + /* find autotype documents */ + NSArray *documents = [NSApp orderedDocuments]; + /* No open document, inform the user and return without any action */ if(documents.count == 0) { - /* We do not have a document. This can be - a) there is none - nothing happens - b) there is at least one, but locked - we get called again after the document has been unlocked - */ + NSUserNotification *notification = [[NSUserNotification alloc] init]; + notification.title = NSApp.applicationName; + notification.informativeText = NSLocalizedString(@"AUTOTYPE_OVERLAY_NO_DOCUMENTS", ""); + [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification]; return; } + NSPredicate *filterPredicate = [NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary * _Nullable bindings) { + MPDocument *document = evaluatedObject; + return !document.encrypted;}]; + NSArray *unlockedDocuments = [documents filteredArrayUsingPredicate:filterPredicate]; + /* We look for all unlocked documents, if all open documents are locked, we pop the front most and try to search again */ + if(unlockedDocuments.count == 0) { + [NSApp activateIgnoringOtherApps:YES]; + [NSApp.mainWindow makeKeyAndOrderFront:self]; + /* show the actual document window to the user */ + [documents.firstObject showWindows]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didUnlockDatabase:) name:MPDocumentDidUnlockDatabaseNotification object:nil]; + return; // wait for the unlock to happen + } + MPAutotypeContext *context = [self _autotypeContextForDocuments:documents forWindowTitle:self.targetWindowTitle preferredEntry:entryOrNil]; - /* TODO: that's popping up if the mulit seleciton dialog goes up! */ + /* TODO: that's popping up if the mulit selection dialog goes up! */ if(!entryOrNil) { NSUserNotification *notification = [[NSUserNotification alloc] init]; notification.title = NSApp.applicationName; @@ -171,22 +187,6 @@ static MPAutotypeDaemon *_sharedInstance; [self _performAutotypeForContext:context]; } -- (NSArray *)_findAutotypeDocuments { - - NSArray *documents = [NSApp orderedDocuments]; - NSPredicate *filterPredicate = [NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary * _Nullable bindings) { - MPDocument *document = evaluatedObject; - return !document.encrypted;}]; - NSArray *unlockedDocuments = [documents filteredArrayUsingPredicate:filterPredicate]; - /* We look for all unlocked documents, if all open documents are locked, we pop the front most and try to search again */ - if(unlockedDocuments.count == 0 && documents.count > 0) { - [NSApp activateIgnoringOtherApps:YES]; - [NSApp.mainWindow makeKeyAndOrderFront:self]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didUnlockDatabase:) name:MPDocumentDidUnlockDatabaseNotification object:nil]; - } - return unlockedDocuments; -} - - (MPAutotypeContext *)_autotypeContextForDocuments:(NSArray *)documents forWindowTitle:(NSString *)windowTitle preferredEntry:(KPKEntry *)entry { /* Query the document to generate a autotype command list for the window title @@ -230,22 +230,18 @@ static MPAutotypeDaemon *_sharedInstance; #pragma mark - #pragma mark Hotkey Registration - (void)_registerHotKey { + if(!self.hotKeyData) { + return; + } __weak MPAutotypeDaemon *welf = self; DDHotKeyTask aTask = ^(NSEvent *event) { [welf _didPressHotKey]; }; - DDHotKey *storedHotkey; - if(nil == self.hotKeyData) { - storedHotkey = [DDHotKey defaultHotKeyWithTask:aTask]; - } - else { - storedHotkey = [[DDHotKey alloc] initWithKeyData:self.hotKeyData task:aTask]; - } - self.registredHotKey = [[DDHotKeyCenter sharedHotKeyCenter] registerHotKey:storedHotkey]; + self.registredHotKey = [[DDHotKeyCenter sharedHotKeyCenter] registerHotKey:[DDHotKey hotKeyWithKeyData:self.hotKeyData task:aTask]]; } - (void)_unregisterHotKey { - if(nil != self.registredHotKey) { + if(self.registredHotKey) { [[DDHotKeyCenter sharedHotKeyCenter] unregisterHotKey:self.registredHotKey]; self.registredHotKey = nil; } diff --git a/MacPass/MPDocument.m b/MacPass/MPDocument.m index c95f40e9..af0786f4 100644 --- a/MacPass/MPDocument.m +++ b/MacPass/MPDocument.m @@ -361,11 +361,7 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGrou self.encryptedData = nil; self.unlockCount += 1; [[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidUnlockDatabaseNotification object:self]; - /* Make sure to only store */ - MPAppDelegate *delegate = (MPAppDelegate *)[NSApp delegate]; - if(self.compositeKey.hasKeyFile && self.compositeKey.hasPassword && delegate.isAllowedToStoreKeyFile) { - [self _storeKeyURL:keyFileURL]; - } + [self _storeKeyURL:keyFileURL]; } else { self.compositeKey = nil; // clear the key? @@ -768,17 +764,21 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGrou } - (void)_storeKeyURL:(NSURL *)keyURL { - if(nil == keyURL) { - return; // no URL to store in the first place - } - MPAppDelegate *delegate = (MPAppDelegate *)[NSApp delegate]; - NSAssert(delegate.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]; + MPAppDelegate *delegate = (MPAppDelegate *)[NSApp delegate]; + if(!delegate.isAllowedToStoreKeyFile || nil == keyURL) { + /* user has removed the keyfile or we should not safe it so remove it */ + [keysForFiles removeObjectForKey:self.fileURL.path.sha1HexDigest]; + } + else if(self.compositeKey.hasPassword && self.compositeKey.hasKeyFile) { + if(nil == keysForFiles) { + keysForFiles = [[NSMutableDictionary alloc] initWithCapacity:1]; + } + keysForFiles[self.fileURL.path.sha1HexDigest] = keyURL.path; + } + if(keysForFiles) { + [[NSUserDefaults standardUserDefaults] setObject:keysForFiles forKey:kMPSettingsKeyRememeberdKeysForDatabases]; } - keysForFiles[self.fileURL.path.sha1HexDigest] = keyURL.path; - [[NSUserDefaults standardUserDefaults] setObject:keysForFiles forKey:kMPSettingsKeyRememeberdKeysForDatabases]; } - (void)_cleanupLock { diff --git a/MacPass/MPEntryInspectorViewController.m b/MacPass/MPEntryInspectorViewController.m index 960101cf..7d0a505e 100644 --- a/MacPass/MPEntryInspectorViewController.m +++ b/MacPass/MPEntryInspectorViewController.m @@ -350,6 +350,11 @@ typedef NS_ENUM(NSUInteger, MPEntryTab) { options:0 metrics:nil views:views]]; + [clipView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view]" + options:0 + metrics:nil + views:views]]; + [[self view] layoutSubtreeIfNeeded]; } @@ -399,10 +404,7 @@ typedef NS_ENUM(NSUInteger, MPEntryTab) { withKeyPath:[NSString stringWithFormat:@"%@.%@.%@", NSStringFromSelector(@selector(representedObject)), NSStringFromSelector(@selector(uuid)), NSStringFromSelector(@selector(UUIDString))] options:@{ NSConditionallySetsEditableBindingOption: @NO }]; self.uuidTextField.editable = NO; - - /*for(id item in items) { - [item bind:NSEnabledBinding toObject:self.entryController withKeyPath:NSStringFromSelector(@selector(isEditable)) options:nil]; - }*/ + } - (void)_bindAttachments { diff --git a/MacPass/MPEntryViewController.m b/MacPass/MPEntryViewController.m index b989c0a6..e8f244db 100644 --- a/MacPass/MPEntryViewController.m +++ b/MacPass/MPEntryViewController.m @@ -410,7 +410,7 @@ NSString *const _MPTableSecurCellView = @"PasswordCell"; return; // we are showing the correct object right now. } } - self.representedObject = document.selectedGroups.count == 1 ? document.selectedGroups.firstObject : nil; + self.representedObject = document.selectedGroups.count == 1 ? document.selectedGroups.lastObject : nil; } [self _updateContextBar]; } diff --git a/MacPass/MPIntegrationSettingsController.m b/MacPass/MPIntegrationSettingsController.m index 895d0042..9c417465 100644 --- a/MacPass/MPIntegrationSettingsController.m +++ b/MacPass/MPIntegrationSettingsController.m @@ -58,7 +58,7 @@ } - (void)willShowTab { - _hotKey = [[DDHotKey alloc] initWithKeyData:[[NSUserDefaults standardUserDefaults] dataForKey:kMPSettingsKeyGlobalAutotypeKeyDataKey]]; + _hotKey = [DDHotKey hotKeyWithKeyData:[[NSUserDefaults standardUserDefaults] dataForKey:kMPSettingsKeyGlobalAutotypeKeyDataKey]]; /* Change any invalid hotkeys to valid ones? */ self.hotKeyTextField.hotKey = self.hotKey; } diff --git a/MacPass/MPSettingsHelper.m b/MacPass/MPSettingsHelper.m index b04243ce..a0bb06d5 100644 --- a/MacPass/MPSettingsHelper.m +++ b/MacPass/MPSettingsHelper.m @@ -110,7 +110,7 @@ NSString *const kMPDeprecatedSettingsKeyDefaultPasswordRounds = @"Ke kMPSettingsKeyRememberKeyFilesForDatabases: @NO, kMPSettingsKeySendCommandForControlKey: @YES, kMPSettingsKeyEnableGlobalAutotype: @NO, - kMPSettingsKeyGlobalAutotypeKeyDataKey: [[DDHotKey defaultHotKey] keyData], + kMPSettingsKeyGlobalAutotypeKeyDataKey: [DDHotKey defaultHotKeyData], kMPSettingsKeyDefaultGlobalAutotypeSequence: @"{USERNAME}{TAB}{PASSWORD}{ENTER}", kMPSettingsKeyAutotypeMatchTitle: @YES, kMPSettingsKeyAutotypeMatchURL: @NO, diff --git a/MacPass/MPSettingsWindowController.m b/MacPass/MPSettingsWindowController.m index 41977fd2..8969d76f 100644 --- a/MacPass/MPSettingsWindowController.m +++ b/MacPass/MPSettingsWindowController.m @@ -80,7 +80,6 @@ [contentView.subviews.firstObject removeFromSuperview]; } [contentView addSubview:tabView]; - [contentView layout]; [contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[tabView]-0-|" options:0 metrics:nil @@ -90,6 +89,7 @@ metrics:nil views:NSDictionaryOfVariableBindings(tabView)]]; + [contentView layout]; [contentView layoutSubtreeIfNeeded]; if([tab respondsToSelector:@selector(didShowTab)]) { [tab didShowTab]; diff --git a/MacPass/MPToolbarDelegate.m b/MacPass/MPToolbarDelegate.m index 71a3890d..25d6a99d 100644 --- a/MacPass/MPToolbarDelegate.m +++ b/MacPass/MPToolbarDelegate.m @@ -292,9 +292,9 @@ NSString *const MPToolbarItemCopyPassword = @"TOOLBAR_COPY_PASSWORD"; _didShowToolbarForSearch = YES; self.toolbar.visible = YES; } - _displayModeBeforeSearch = [self.toolbar displayMode]; + _displayModeBeforeSearch = self.toolbar.displayMode; if(_displayModeBeforeSearch == NSToolbarDisplayModeLabelOnly) { - [self.toolbar setDisplayMode:NSToolbarDisplayModeIconAndLabel]; + self.toolbar.displayMode = NSToolbarDisplayModeIconAndLabel; } /* only make the searchfield first responder if it's not already in an active search */ if(![self.searchField currentEditor]) { diff --git a/MacPass/de.lproj/Localizable.strings b/MacPass/de.lproj/Localizable.strings index 1429fa87..ec6fb88f 100644 Binary files a/MacPass/de.lproj/Localizable.strings and b/MacPass/de.lproj/Localizable.strings differ diff --git a/MacPass/en.lproj/Localizable.strings b/MacPass/en.lproj/Localizable.strings index 7c316199..d8d1f641 100644 Binary files a/MacPass/en.lproj/Localizable.strings and b/MacPass/en.lproj/Localizable.strings differ diff --git a/MacPass/fr.lproj/Localizable.strings b/MacPass/fr.lproj/Localizable.strings index abb3da39..8693e62d 100644 Binary files a/MacPass/fr.lproj/Localizable.strings and b/MacPass/fr.lproj/Localizable.strings differ diff --git a/MacPass/it.lproj/Localizable.strings b/MacPass/it.lproj/Localizable.strings index 500a3d72..3b37c573 100644 Binary files a/MacPass/it.lproj/Localizable.strings and b/MacPass/it.lproj/Localizable.strings differ diff --git a/MacPass/nl.lproj/Localizable.strings b/MacPass/nl.lproj/Localizable.strings index cee03724..9965b161 100644 Binary files a/MacPass/nl.lproj/Localizable.strings and b/MacPass/nl.lproj/Localizable.strings differ diff --git a/MacPass/ru.lproj/Localizable.strings b/MacPass/ru.lproj/Localizable.strings index 5d672103..64c9406e 100644 Binary files a/MacPass/ru.lproj/Localizable.strings and b/MacPass/ru.lproj/Localizable.strings differ diff --git a/MacPass/zh-Hans.lproj/Localizable.strings b/MacPass/zh-Hans.lproj/Localizable.strings index d82179ae..ef2175c0 100644 Binary files a/MacPass/zh-Hans.lproj/Localizable.strings and b/MacPass/zh-Hans.lproj/Localizable.strings differ