From e38925d0ef7a1e45afbb89d28e76c03c165a0a7c Mon Sep 17 00:00:00 2001 From: Michael Starke Date: Wed, 13 Feb 2019 17:07:56 +0100 Subject: [PATCH] Added context menu entry to enable copying references to entries --- MacPass/Base.lproj/EntryInspectorView.xib | 4 +-- MacPass/MPEntryContextMenuDelegate.h | 3 ++ MacPass/MPEntryContextMenuDelegate.m | 30 +++++++++++++++++- MacPass/MPEntryInspectorViewController.m | 5 +++ MacPass/MPEntryViewController.h | 1 + MacPass/MPEntryViewController.m | 19 ++++++++++++ MacPass/MPPasteBoardController.h | 3 +- MacPass/MPPasteBoardController.m | 6 ++++ MacPass/MPReferenceBuilderViewController.m | 4 +-- MacPass/en.lproj/Localizable.strings | 36 ++++++++++++++++++++++ 10 files changed, 105 insertions(+), 6 deletions(-) diff --git a/MacPass/Base.lproj/EntryInspectorView.xib b/MacPass/Base.lproj/EntryInspectorView.xib index 59b96673..11cc4375 100644 --- a/MacPass/Base.lproj/EntryInspectorView.xib +++ b/MacPass/Base.lproj/EntryInspectorView.xib @@ -1,8 +1,8 @@ - + - + diff --git a/MacPass/MPEntryContextMenuDelegate.h b/MacPass/MPEntryContextMenuDelegate.h index 62b7b1dc..bd7add5f 100644 --- a/MacPass/MPEntryContextMenuDelegate.h +++ b/MacPass/MPEntryContextMenuDelegate.h @@ -22,6 +22,9 @@ #import +/** + Delegate is used for context menus that are show in the entries table + */ @interface MPEntryContextMenuDelegate : NSObject @end diff --git a/MacPass/MPEntryContextMenuDelegate.m b/MacPass/MPEntryContextMenuDelegate.m index 7df78953..c50f8016 100644 --- a/MacPass/MPEntryContextMenuDelegate.m +++ b/MacPass/MPEntryContextMenuDelegate.m @@ -27,20 +27,25 @@ static NSUInteger const kMPCustomFieldMenuItem = 1000; static NSUInteger const kMPAttachmentsMenuItem = 2000; +static NSUInteger const kMPCopyAsReferenceMenuItem = 3000; @implementation MPEntryContextMenuDelegate - (void)menuNeedsUpdate:(NSMenu *)menu { NSMenuItem *fieldsMenu = [menu itemWithTag:kMPCustomFieldMenuItem]; NSMenuItem *attachmentsMenu = [menu itemWithTag:kMPAttachmentsMenuItem]; + NSMenuItem *copyReferenceMenu = [menu itemWithTag:kMPCopyAsReferenceMenuItem]; if(fieldsMenu) { [menu removeItem:fieldsMenu]; } if(attachmentsMenu) { [menu removeItem:attachmentsMenu]; } + if(copyReferenceMenu) { + [menu removeItem:copyReferenceMenu]; + } - NSMenuItem *lastItem = [[menu itemArray] lastObject]; + NSMenuItem *lastItem = menu.itemArray.lastObject; if([lastItem isSeparatorItem]) { [menu removeItem:lastItem]; } @@ -66,6 +71,29 @@ static NSUInteger const kMPAttachmentsMenuItem = 2000; attributeItem.submenu = submenu; [menu addItem:attributeItem]; } + + if(entry) { + NSMenuItem *copyReferenceItem = [[NSMenuItem alloc] init]; + copyReferenceItem.title = NSLocalizedString(@"COPY_AS_REFERENCE", "Submenu to copy attributes as reference"); + copyReferenceItem.tag = kMPCopyAsReferenceMenuItem; + NSMenu *subMenu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"COPY_AS_REFERENCE_MENU", "Context menu sub-menu to copy attributes as reference")]; + + NSDictionary *references = @{ kKPKReferenceURLKey: NSLocalizedString(@"COPY_URL_REFERENCE", "Context menu that copies reference to URL"), + kKPKReferenceNotesKey: NSLocalizedString(@"COPY_NOTES_REFERENCE", "Context menu that copies reference to note"), + kKPKReferenceTitleKey: NSLocalizedString(@"COPY_TITLE_REFERENCE", "Context menu that copies reference to title"), + kKPKReferencePasswordKey: NSLocalizedString(@"COPY_PASSWORD_REFERENCE", "Context menu that copies reference to password"), + kKPKReferenceUsernameKey: NSLocalizedString(@"COPY_USERNAME_REFERENCE", "Context menu that copies reference to username"), + }; + for(NSString *key in references) { + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:references[key] action:@selector(copyAsReference:) keyEquivalent:@""]; + item.representedObject = key; + [subMenu addItem:item]; + } + + copyReferenceItem.representedObject = entry.uuid.UUIDString; + copyReferenceItem.submenu = subMenu; + [menu addItem:copyReferenceItem]; + } } @end diff --git a/MacPass/MPEntryInspectorViewController.m b/MacPass/MPEntryInspectorViewController.m index 47a6ac74..da6157cd 100644 --- a/MacPass/MPEntryInspectorViewController.m +++ b/MacPass/MPEntryInspectorViewController.m @@ -586,6 +586,11 @@ typedef NS_ENUM(NSUInteger, MPEntryTab) { return menu; } +/*- (NSArray *)control:(NSControl *)control textView:(NSTextView *)textView completions:(NSArray *)words forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index { + return @[ @"{USERNAME}", @"{PASSWORD}", @"{URL}", @"{TITLE}" ]; +} +*/ + - (BOOL)textField:(NSTextField *)textField textView:(NSTextView *)textView performAction:(SEL)action { if(action == @selector(copy:)) { MPPasteboardOverlayInfoType info = MPPasteboardOverlayInfoCustom; diff --git a/MacPass/MPEntryViewController.h b/MacPass/MPEntryViewController.h index 598a5858..e164228f 100644 --- a/MacPass/MPEntryViewController.h +++ b/MacPass/MPEntryViewController.h @@ -60,6 +60,7 @@ typedef NS_ENUM(NSUInteger, MPDisplayMode) { - (IBAction)copyCustomAttribute:(id)sender; - (IBAction)copyURL:(id)sender; - (IBAction)openURL:(id)sender; +- (IBAction)copyAsReference:(id)sender; /* More Actions */ - (IBAction)delete:(id)sender; diff --git a/MacPass/MPEntryViewController.m b/MacPass/MPEntryViewController.m index a2a67f0f..f60ea31d 100644 --- a/MacPass/MPEntryViewController.m +++ b/MacPass/MPEntryViewController.m @@ -710,6 +710,25 @@ NSString *const _MPTableSecurCellView = @"PasswordCell"; } } +- (void)copyAsReference:(id)sender { + NSDictionary *references = @{ kKPKReferenceURLKey: NSLocalizedString(@"COPIED_URL_REFERENCE", "Context menu that copies reference to URL"), + kKPKReferenceNotesKey: NSLocalizedString(@"COPIED_NOTES_REFERENCE", "Context menu that copies reference to note"), + kKPKReferenceTitleKey: NSLocalizedString(@"COPIED_TITLE_REFERENCE", "Context menu that copies reference to title"), + kKPKReferencePasswordKey: NSLocalizedString(@"COPIED_PASSWORD_REFERENCE", "Context menu that copies reference to password"), + kKPKReferenceUsernameKey: NSLocalizedString(@"COPIED_USERNAME_REFERENCE", "Context menu that copies reference to username"), + }; + if(![sender isKindOfClass:NSMenuItem.class]) { + return; + } + NSString *referencesField = [sender representedObject]; + NSArray *nodes = [self currentTargetNodes]; + KPKEntry *selectedEntry = nodes.count == 1 ? [nodes.firstObject asEntry] : nil; + if(referencesField && selectedEntry) { + NSString *value = [NSString stringWithFormat:@"{%@%@@%@:%@}", kKPKReferencePrefix, referencesField, kKPKReferenceUUIDKey, selectedEntry.uuid.UUIDString]; + [MPPasteBoardController.defaultController copyObjects:@[value] overlayInfo:MPPasteboardOverlayInfoReference name:references[referencesField] atView:self.view]; + } +} + - (void)delete:(id)sender { NSArray *entries = self.currentTargetEntries; MPDocument *document = self.windowController.document; diff --git a/MacPass/MPPasteBoardController.h b/MacPass/MPPasteBoardController.h index 89b5231c..4e012d19 100644 --- a/MacPass/MPPasteBoardController.h +++ b/MacPass/MPPasteBoardController.h @@ -26,7 +26,8 @@ typedef NS_ENUM(NSUInteger, MPPasteboardOverlayInfoType) { MPPasteboardOverlayInfoPassword, MPPasteboardOverlayInfoUsername, MPPasteboardOverlayInfoURL, - MPPasteboardOverlayInfoCustom, + MPPasteboardOverlayInfoCustom, // overlay info that a custom field was copied + MPPasteboardOverlayInfoReference // overlay info that a reference that was copied }; @interface MPPasteBoardController : NSObject diff --git a/MacPass/MPPasteBoardController.m b/MacPass/MPPasteBoardController.m index 09c4106f..06001fd5 100644 --- a/MacPass/MPPasteBoardController.m +++ b/MacPass/MPPasteBoardController.m @@ -142,6 +142,12 @@ NSString *const MPPasteBoardControllerDidClearClipboard = @"com.hicknhack.macpas infoImage = [NSBundle.mainBundle imageForResource:@"00_PasswordTemplate"]; infoText = [NSString stringWithFormat:NSLocalizedString(@"COPIED_FIELD_%@", "Field name that was copied to the pasteboard"), name]; break; + + case MPPasteboardOverlayInfoReference: + infoImage = [NSBundle.mainBundle imageForResource:@"04_KlipperTemplate"]; + infoText = name; + break; + } [MPOverlayWindowController.sharedController displayOverlayImage:infoImage label:infoText atView:view]; } diff --git a/MacPass/MPReferenceBuilderViewController.m b/MacPass/MPReferenceBuilderViewController.m index 95b6ec85..dcad0f14 100644 --- a/MacPass/MPReferenceBuilderViewController.m +++ b/MacPass/MPReferenceBuilderViewController.m @@ -37,8 +37,8 @@ } - (void)viewDidLoad { - [self.searchKeyPopUpButton setMenu:[self _allocateAttributeItemMenu:YES withTitle:NSLocalizedString(@"SEARCH_VALUE", "")]]; - [self.valuePopUpButton setMenu:[self _allocateAttributeItemMenu:NO withTitle:NSLocalizedString(@"OUTPUT_VALUE", "")]]; + self.searchKeyPopUpButton.menu = [self _allocateAttributeItemMenu:YES withTitle:NSLocalizedString(@"SEARCH_VALUE", "")]; + self.valuePopUpButton.menu = [self _allocateAttributeItemMenu:NO withTitle:NSLocalizedString(@"OUTPUT_VALUE", "")]; [self.searchStringTextField bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(searchString)) options:nil]; [self _updateReferenceString]; } diff --git a/MacPass/en.lproj/Localizable.strings b/MacPass/en.lproj/Localizable.strings index 6e4916aa..34945bdd 100644 --- a/MacPass/en.lproj/Localizable.strings +++ b/MacPass/en.lproj/Localizable.strings @@ -153,15 +153,36 @@ /* Field name that was copied to the pasteboard */ "COPIED_FIELD_%@" = "Copied %@"; +/* Context menu that copies reference to note */ +"COPIED_NOTES_REFERENCE" = "Reference to notes copied!"; + /* Password was copied to the pasteboard */ "COPIED_PASSWORD" = "Password copied!"; +/* Context menu that copies reference to password */ +"COPIED_PASSWORD_REFERENCE" = "Reference to password copied!"; + +/* Context menu that copies reference to title */ +"COPIED_TITLE_REFERENCE" = "Reference to title copied!"; + /* URL was copied to the pasteboard */ "COPIED_URL" = "URL copied!"; +/* Context menu that copies reference to URL */ +"COPIED_URL_REFERENCE" = "Reference to URL copied!"; + /* Username was copied to the pasteboard */ "COPIED_USERNAME" = "Username copied!"; +/* Context menu that copies reference to username */ +"COPIED_USERNAME_REFERENCE" = "Reference to username copied!"; + +/* Submenu to copy attributes as reference */ +"COPY_AS_REFERENCE" = "Copy Reference To…"; + +/* Context menu sub-menu to copy attributes as reference */ +"COPY_AS_REFERENCE_MENU" = "Copy as Reference menu"; + /* Submenu to Copy custom fields */ "COPY_CUSTOM_FIELDS" = "Copy Custom Fields"; @@ -178,17 +199,32 @@ /* Action title for copying a group via drag and drop */ "COPY_GROUP" = "Copy Group"; +/* Context menu that copies reference to note */ +"COPY_NOTES_REFERENCE" = "Notes"; + /* Menu item to copy the password of an entry Toolbar item copy password */ "COPY_PASSWORD" = "Copy Password"; +/* Context menu that copies reference to password */ +"COPY_PASSWORD_REFERENCE" = "Password"; + +/* Context menu that copies reference to title */ +"COPY_TITLE_REFERENCE" = "Title"; + /* Menu item to copy the URL of an entry */ "COPY_URL" = "Copy URL"; +/* Context menu that copies reference to URL */ +"COPY_URL_REFERENCE" = "URL"; + /* Menu item to copy the username of an entry Toolbar item copy username */ "COPY_USERNAME" = "Copy Username"; +/* Context menu that copies reference to username */ +"COPY_USERNAME_REFERENCE" = "Username"; + /* Curstom attribute reference item */ "CUSTOM_ATTRIBUTE" = "Custom Attribute";