diff --git a/Cartfile b/Cartfile index 54e3f2ff..9f9143e4 100644 --- a/Cartfile +++ b/Cartfile @@ -1,3 +1,3 @@ github "sparkle-project/Sparkle" ~> 1.17.0 -github "mstarke/KeePassKit" "b25eab0892f6101ee4929bef3f57788dbc5fa607" +github "mstarke/KeePassKit" "6568b250d41e53f1bdc508255432661216d3fe7f" github "mstarke/HNHUi" ~> 1.1 diff --git a/Cartfile.resolved b/Cartfile.resolved index a085d4ea..27a0b2df 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,3 +1,3 @@ github "mstarke/HNHUi" "1.1" -github "mstarke/KeePassKit" "b25eab0892f6101ee4929bef3f57788dbc5fa607" +github "mstarke/KeePassKit" "6568b250d41e53f1bdc508255432661216d3fe7f" github "sparkle-project/Sparkle" "1.17.0" diff --git a/MacPass.xcodeproj/project.pbxproj b/MacPass.xcodeproj/project.pbxproj index aadf97a2..3680c56d 100644 --- a/MacPass.xcodeproj/project.pbxproj +++ b/MacPass.xcodeproj/project.pbxproj @@ -182,6 +182,7 @@ 4C888C9716EB754B003D34A1 /* MPActionHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C888C9616EB754B003D34A1 /* MPActionHelper.m */; }; 4C88C66918D9F8D600F43852 /* MPTemporaryFileStorageCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C88C66818D9F8D600F43852 /* MPTemporaryFileStorageCenter.m */; }; 4C8913661A422C8C0071A4CB /* MPFileWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8913651A422C8C0071A4CB /* MPFileWatcher.m */; }; + 4C8990F71EE978EB0043B48D /* MPDuplicateEntryOptionsWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8990F51EE978EB0043B48D /* MPDuplicateEntryOptionsWindowController.m */; }; 4C89B71019B4B4A300DC0A6A /* MPTreeDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C89B70F19B4B4A300DC0A6A /* MPTreeDelegate.m */; }; 4C89F524182FB4740069C73C /* MPAutotypeCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C89F523182FB4740069C73C /* MPAutotypeCommand.m */; }; 4C8B36AB17A6ED4B005E1FF1 /* MPOutlineContextMenuDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8B36AA17A6ED4B005E1FF1 /* MPOutlineContextMenuDelegate.m */; }; @@ -592,6 +593,8 @@ 4C88C66818D9F8D600F43852 /* MPTemporaryFileStorageCenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTemporaryFileStorageCenter.m; sourceTree = ""; }; 4C8913641A422C8C0071A4CB /* MPFileWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFileWatcher.h; sourceTree = ""; }; 4C8913651A422C8C0071A4CB /* MPFileWatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFileWatcher.m; sourceTree = ""; }; + 4C8990F41EE978EB0043B48D /* MPDuplicateEntryOptionsWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPDuplicateEntryOptionsWindowController.h; sourceTree = ""; }; + 4C8990F51EE978EB0043B48D /* MPDuplicateEntryOptionsWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPDuplicateEntryOptionsWindowController.m; sourceTree = ""; }; 4C89B70E19B4B4A300DC0A6A /* MPTreeDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPTreeDelegate.h; sourceTree = ""; }; 4C89B70F19B4B4A300DC0A6A /* MPTreeDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTreeDelegate.m; sourceTree = ""; }; 4C89F522182FB4740069C73C /* MPAutotypeCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAutotypeCommand.h; sourceTree = ""; }; @@ -1400,6 +1403,9 @@ 4C0B038918E36DA400B9F9C9 /* MPFixAutotypeWindowController.h */, 4C0B038A18E36DA400B9F9C9 /* MPFixAutotypeWindowController.m */, 4C0B038B18E36DA400B9F9C9 /* FixAutotypeWindow.xib */, + 4C8990F41EE978EB0043B48D /* MPDuplicateEntryOptionsWindowController.h */, + 4C8990F51EE978EB0043B48D /* MPDuplicateEntryOptionsWindowController.m */, + 4CB915931A0159A20089CE5B /* DuplicateEntryOptionsWindow.xib */, ); name = "Window Controller"; sourceTree = ""; @@ -1423,7 +1429,6 @@ 4C1DDCDC1711ECEB00C98DA3 /* PasswordCreatorWindow.xib */, 4C7F8B6A1A10B68400CCB83D /* WelcomeWindow.xib */, 4C0DD6C518B2A44700FCB193 /* AutotypeCandidateSelectionWindow.xib */, - 4CB915931A0159A20089CE5B /* DuplicateEntryOptionsWindow.xib */, ); name = Windows; sourceTree = ""; @@ -1776,6 +1781,7 @@ 4C10412C178CDD44001B5239 /* NSDate+Humanized.m in Sources */, 4C0C59F118B17F10009C7B76 /* DDHotKeyUtilities.m in Sources */, 4CEE46DD181C301D006BF1E5 /* MPAutotypeDaemon.m in Sources */, + 4C8990F71EE978EB0043B48D /* MPDuplicateEntryOptionsWindowController.m in Sources */, 4CA3530B18A53CB800839B0F /* MPKeyMapper.m in Sources */, 4CE298EB1795FC2A00DF7BDB /* MPEntryContextMenuDelegate.m in Sources */, 4CCCE8011D75CA48006AA951 /* MPArrayController.m in Sources */, diff --git a/MacPass/DuplicateEntryOptionsWindow.xib b/MacPass/DuplicateEntryOptionsWindow.xib index acdbf975..a011e6ea 100644 --- a/MacPass/DuplicateEntryOptionsWindow.xib +++ b/MacPass/DuplicateEntryOptionsWindow.xib @@ -1,26 +1,62 @@ - + - - + - + + + + + + + + - + - + - + + + - - + + - - + + + - + diff --git a/MacPass/MPDocument.h b/MacPass/MPDocument.h index 46b0f0b0..d509949b 100644 --- a/MacPass/MPDocument.h +++ b/MacPass/MPDocument.h @@ -159,6 +159,7 @@ FOUNDATION_EXPORT NSString *const MPDocumentGroupKey; - (KPKAttribute *)createCustomAttribute:(KPKEntry *)entry; - (void)deleteNode:(KPKNode *)node; +- (void)duplicateEntryWithOptions:(KPKCopyOptions)options; #pragma mark Actions /** @@ -172,11 +173,8 @@ FOUNDATION_EXPORT NSString *const MPDocumentGroupKey; * @param sender sender, that should respond to representedObject and return an NSUUID for the template to use */ - (IBAction)createEntryFromTemplate:(id)sender; - - (IBAction)duplicateEntry:(id)sender; -- (IBAction)duplicateEntryWithOptions:(id)sender; - @end @interface MPDocument (Attachments) diff --git a/MacPass/MPDocument.m b/MacPass/MPDocument.m index 308f0a7e..e45bdaaa 100644 --- a/MacPass/MPDocument.m +++ b/MacPass/MPDocument.m @@ -699,18 +699,18 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGrou } - (void)duplicateEntry:(id)sender { + [self duplicateEntryWithOptions:kKPKCopyOptionNone]; +} + +- (void)duplicateEntryWithOptions:(KPKCopyOptions)options { + BOOL plural = self.selectedEntries.count > 1; for(KPKEntry *entry in self.selectedEntries) { - KPKEntry *duplicate = [entry copyWithTitle:nil options:kKPKCopyOptionNone]; + KPKEntry *duplicate = [entry copyWithTitle:nil options:options]; [duplicate addToGroup:entry.parent]; } - [self.undoManager setActionName:NSLocalizedString(@"DUPLICATE_ENTRY", "")]; + [self.undoManager setActionName:plural ? NSLocalizedString(@"DUPLICATE_ENTRIES", "") : NSLocalizedString(@"DUPLICATE_ENTRY", "")]; } -- (void)duplicateEntryWithOptions:(id)sender { - -} - - #pragma mark Validation - (BOOL)validateMenuItem:(NSMenuItem *)menuItem { return [self validateUserInterfaceItem:menuItem]; diff --git a/MacPass/MPDocumentWindowController.h b/MacPass/MPDocumentWindowController.h index ab469986..83c11038 100644 --- a/MacPass/MPDocumentWindowController.h +++ b/MacPass/MPDocumentWindowController.h @@ -51,6 +51,8 @@ - (IBAction)createEntry:(id)sender; - (IBAction)delete:(id)sender; +- (IBAction)duplicateEntryWithOptions:(id)sender; + - (IBAction)pickExpiryDate:(id)sender; - (IBAction)performAutotypeForEntry:(id)sender; diff --git a/MacPass/MPDocumentWindowController.m b/MacPass/MPDocumentWindowController.m index 9cb8c16e..908bd3ea 100644 --- a/MacPass/MPDocumentWindowController.m +++ b/MacPass/MPDocumentWindowController.m @@ -15,6 +15,7 @@ #import "MPDatabaseSettingsWindowController.h" #import "MPDocument.h" #import "MPDocumentWindowDelegate.h" +#import "MPDuplicateEntryOptionsWindowController.h" #import "MPEntryViewController.h" #import "MPFixAutotypeWindowController.h" #import "MPInspectorViewController.h" @@ -397,6 +398,27 @@ typedef void (^MPPasswordChangedBlock)(BOOL didChangePassword); [self.document deleteNode:node]; } } +- (void)duplicateEntryWithOptions:(id)sender { + MPDuplicateEntryOptionsWindowController *wc = [[MPDuplicateEntryOptionsWindowController alloc] init]; + __weak MPDocumentWindowController *welf = self; + + [self.window beginSheet:wc.window completionHandler:^(NSModalResponse returnCode) { + if(returnCode == NSModalResponseOK) { + + KPKCopyOptions options = kKPKCopyOptionNone; + if(wc.referenceUsername) { + options |= kKPKCopyOptionReferenceUsername; + } + if(wc.referencePassword) { + options |= kKPKCopyOptionReferencePassword; + } + if(wc.duplicateHistory) { + options |= kKPKCopyOptionCopyHistory; + } + [((MPDocument *)welf.document) duplicateEntryWithOptions:options]; + } + }]; +} - (void)pickExpiryDate:(id)sender { [self.inspectorViewController pickExpiryDate:sender]; diff --git a/MacPass/MPDuplicateEntryOptionsWindowController.h b/MacPass/MPDuplicateEntryOptionsWindowController.h new file mode 100644 index 00000000..2522b14f --- /dev/null +++ b/MacPass/MPDuplicateEntryOptionsWindowController.h @@ -0,0 +1,17 @@ +// +// MPDuplicateEntryOptionsWindowController.h +// MacPass +// +// Created by Michael Starke on 08.06.17. +// Copyright © 2017 HicknHack Software GmbH. All rights reserved. +// + +#import + +@interface MPDuplicateEntryOptionsWindowController : NSWindowController + +@property (readonly) BOOL referencePassword; +@property (readonly) BOOL referenceUsername; +@property (readonly) BOOL duplicateHistory; + +@end diff --git a/MacPass/MPDuplicateEntryOptionsWindowController.m b/MacPass/MPDuplicateEntryOptionsWindowController.m new file mode 100644 index 00000000..6aa1fa02 --- /dev/null +++ b/MacPass/MPDuplicateEntryOptionsWindowController.m @@ -0,0 +1,63 @@ +// +// MPDuplicateEntryOptionsWindowController.m +// MacPass +// +// Created by Michael Starke on 08.06.17. +// Copyright © 2017 HicknHack Software GmbH. All rights reserved. +// + +#import "MPDuplicateEntryOptionsWindowController.h" + +@interface MPDuplicateEntryOptionsWindowController () + +@property BOOL referencePassword; +@property BOOL referenceUsername; +@property BOOL duplicateHistory; + +@property (weak) IBOutlet NSButton *referenceUsernameCheckButton; +@property (weak) IBOutlet NSButton *referencePasswordCheckButton; +@property (weak) IBOutlet NSButton *duplicateHistoryCheckButton; + +@end + +@implementation MPDuplicateEntryOptionsWindowController + +- (instancetype)initWithWindow:(NSWindow *)window { + self = [super initWithWindow:window]; + if(self) { + _referencePassword = NO; + _referenceUsername = NO; + _duplicateHistory = NO; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + if(self) { + _referencePassword = NO; + _referenceUsername = NO; + _duplicateHistory = NO; + } + return self; +} + +- (NSString *)windowNibName { + return @"DuplicateEntryOptionsWindow"; +} + +- (void)windowDidLoad { + [super windowDidLoad]; + [self.referencePasswordCheckButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(referencePassword)) options:nil]; + [self.referenceUsernameCheckButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(referenceUsername)) options:nil]; + [self.duplicateHistoryCheckButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(duplicateHistory)) options:nil]; +} +- (IBAction)duplicateEntry:(id)sender { + [self.window.sheetParent endSheet:self.window returnCode:NSModalResponseOK]; +} + +- (IBAction)cancel:(id)sender { + [self.window.sheetParent endSheet:self.window returnCode:NSModalResponseCancel]; +} + +@end