diff --git a/MacPass/Base.lproj/DatabaseSettingsWindow.xib b/MacPass/Base.lproj/DatabaseSettingsWindow.xib index ea2f50e7..6df349ab 100644 --- a/MacPass/Base.lproj/DatabaseSettingsWindow.xib +++ b/MacPass/Base.lproj/DatabaseSettingsWindow.xib @@ -51,14 +51,14 @@ - + - - + + - + @@ -569,268 +569,288 @@ Gw - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -848,7 +868,7 @@ Gw - + diff --git a/MacPass/MPAdvancedDatabaseSettingsViewController.m b/MacPass/MPAdvancedDatabaseSettingsViewController.m index f98eb8bc..27090bdc 100644 --- a/MacPass/MPAdvancedDatabaseSettingsViewController.m +++ b/MacPass/MPAdvancedDatabaseSettingsViewController.m @@ -7,9 +7,45 @@ // #import "MPAdvancedDatabaseSettingsViewController.h" +#import "MPDocument.h" +#import "MPDayCountFormatter.h" +#import "KPKNode+IconImage.h" + +#import +#import @interface MPAdvancedDatabaseSettingsViewController () +@property (strong) IBOutlet NSButton *enableHistoryCheckButton; +@property (strong) IBOutlet NSTextField *historyMaximumItemsTextField; +@property (strong) IBOutlet NSStepper *historyMaximumItemsStepper; + +@property (strong) IBOutlet NSTextField *historyMaximumSizeTextField; +@property (strong) IBOutlet NSStepper *historyMaximumSizeStepper; + +@property (strong) IBOutlet NSButton *enableTrashCheckButton; +@property (strong) IBOutlet NSButton *emptyTrashOnQuitCheckButton; +@property (strong) IBOutlet NSPopUpButton *selectTrashGoupPopUpButton; +@property (strong) IBOutlet NSTextField *defaultUsernameTextField; +@property (strong) IBOutlet NSPopUpButton *templateGroupPopUpButton; + +@property (strong) IBOutlet NSButton *recommendKeyChangeCheckButton; +@property (strong) IBOutlet NSButton *enforceKeyChangeCheckButton; +@property (strong) IBOutlet NSButton *enforceKeyChangeOnceCheckButton; +@property (strong) IBOutlet NSTextField *recommendKeyChangeIntervalTextField; +@property (strong) IBOutlet NSStepper *recommendKeyChangeIntervalStepper; +@property (strong) IBOutlet NSTextField *enforceKeyChangeIntervalTextField; +@property (strong) IBOutlet NSStepper *enforceKeyChangeIntervalStepper; + +@property (assign) BOOL enableHistory; +@property (assign) NSInteger maxiumHistoryItems; +@property (assign) NSInteger maxiumHistorySize; + +@property (assign) BOOL enforceKeyChange; +@property (assign) BOOL recommendKeyChange; +@property (assign) NSInteger enforceKeyChangeInterval; +@property (assign) NSInteger recommendKeyChangeInterval; + @end @implementation MPAdvancedDatabaseSettingsViewController @@ -19,4 +55,140 @@ // Do view setup here. } +- (void)_setupAdvancedTab { + /* history */ + MPDocument *document = (MPDocument*)self.view.window.windowController.document; + KPKTree *tree = document.tree; + + self.enableHistory = tree.metaData.isHistoryEnabled; + [self.enableHistoryCheckButton bind:NSValueBinding + toObject:self + withKeyPath:NSStringFromSelector(@selector(enableHistory)) + options:nil]; + + /* history size */ + self.maxiumHistorySize = tree.metaData.historyMaxSize; + self.historyMaximumSizeStepper.minValue = 0; + self.historyMaximumSizeStepper.maxValue = NSIntegerMax; + self.historyMaximumSizeStepper.increment = 1024*1024; // 1MB + [self.historyMaximumSizeStepper bind:NSEnabledBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enableHistory)) options:nil]; + [self.historyMaximumSizeStepper bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(maxiumHistorySize)) options:nil]; + [self.historyMaximumSizeTextField bind:NSEnabledBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enableHistory)) options:nil]; + [self.historyMaximumSizeTextField bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(maxiumHistorySize)) options:nil]; + + /* history count */ + self.maxiumHistoryItems = MAX(0,tree.metaData.historyMaxItems); // prevent -1 form showing up directly + self.historyMaximumItemsStepper.minValue = 0; + self.historyMaximumItemsStepper.maxValue = NSIntegerMax; + self.historyMaximumItemsStepper.increment = 1; + [self.historyMaximumItemsStepper bind:NSEnabledBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enableHistory)) options:nil]; + [self.historyMaximumItemsStepper bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(maxiumHistoryItems)) options:nil]; + [self.historyMaximumItemsTextField bind:NSEnabledBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enableHistory)) options:nil]; + [self.historyMaximumItemsTextField bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(maxiumHistoryItems)) options:nil]; + + /* trash */ + HNHUISetStateFromBool(self.enableTrashCheckButton, tree.metaData.useTrash); + self.selectTrashGoupPopUpButton.enabled = tree.metaData.useTrash; + [self.enableTrashCheckButton bind:NSValueBinding toObject:self.selectTrashGoupPopUpButton withKeyPath:NSEnabledBinding options:nil]; + [self _updateTrashFolders:tree]; + + /* default username */ + self.defaultUsernameTextField.stringValue = tree.metaData.defaultUserName; + self.defaultUsernameTextField.editable = YES; + [self _updateTemplateGroup:tree]; + + /* key changes */ + self.enforceKeyChange = tree.metaData.enforceMasterKeyChange; + self.recommendKeyChange = tree.metaData.recommendMasterKeyChange; + HNHUISetStateFromBool(self.enforceKeyChangeOnceCheckButton, tree.metaData.enforceMasterKeyChangeOnce); + + [self.enforceKeyChangeCheckButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enforceKeyChange)) options:nil]; + [self.recommendKeyChangeCheckButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(recommendKeyChange)) options:nil]; + + /* intervals use -1 to encode disabled, do not show this in text fields! */ + self.enforceKeyChangeInterval = MAX(0,tree.metaData.masterKeyChangeEnforcementInterval); + self.enforceKeyChangeIntervalStepper.minValue = 0; + self.enforceKeyChangeIntervalStepper.maxValue = NSIntegerMax; + self.enforceKeyChangeIntervalStepper.increment = 1; // 1 day steps + [self.enforceKeyChangeIntervalStepper bind:NSEnabledBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enforceKeyChange)) options:nil]; + [self.enforceKeyChangeIntervalStepper bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enforceKeyChangeInterval)) options:nil]; + [self.enforceKeyChangeIntervalTextField bind:NSEnabledBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enforceKeyChange)) options:nil]; + [self.enforceKeyChangeIntervalTextField bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enforceKeyChangeInterval)) options:nil]; + + NSString *valueFormat = NSLocalizedString(@"EVERY_%ld_DAYS", @"Recommend/Enforce key change intervall format"); + + ((MPDayCountFormatter *)self.enforceKeyChangeIntervalTextField.formatter).valueFormat = valueFormat; + + self.recommendKeyChangeInterval = MAX(0,tree.metaData.masterKeyChangeRecommendationInterval); + self.recommendKeyChangeIntervalStepper.minValue = 0; + self.recommendKeyChangeIntervalStepper.maxValue = NSIntegerMax; + self.recommendKeyChangeIntervalStepper.increment = 1; // 1 day steps + [self.recommendKeyChangeIntervalStepper bind:NSEnabledBinding toObject:self withKeyPath:NSStringFromSelector(@selector(recommendKeyChange)) options:nil]; + [self.recommendKeyChangeIntervalStepper bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(recommendKeyChangeInterval)) options:nil]; + [self.recommendKeyChangeIntervalTextField bind:NSEnabledBinding toObject:self withKeyPath:NSStringFromSelector(@selector(recommendKeyChange)) options:nil]; + [self.recommendKeyChangeIntervalTextField bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(recommendKeyChangeInterval)) options:nil]; + ((MPDayCountFormatter *)self.recommendKeyChangeIntervalTextField.formatter).valueFormat = valueFormat; +} + +- (void)_updateTrashFolders:(KPKTree *)tree { + NSMenu *menu = [self _buildTrashTreeMenu:tree]; + self.selectTrashGoupPopUpButton.menu = menu; +} + +- (void)_updateTemplateGroup:(KPKTree *)tree { + NSMenu *menu = [self _buildTemplateTreeMenu:tree]; + self.templateGroupPopUpButton.menu = menu; +} + +- (NSMenu *)_buildTrashTreeMenu:(KPKTree *)tree { + NSMenu *menu = [self _buildTreeMenu:tree preselect:tree.metaData.trashUuid]; + + NSMenuItem *selectItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"AUTOCREATE_TRASH_FOLDER", @"Menu item for automatic trash creation") + action:NULL + keyEquivalent:@""]; + selectItem.enabled = YES; + [menu insertItem:selectItem atIndex:0]; + + return menu; +} + +- (NSMenu *)_buildTemplateTreeMenu:(KPKTree *)tree { + NSMenu *menu = [self _buildTreeMenu:tree preselect:tree.metaData.entryTemplatesGroupUuid]; + + NSMenuItem *selectItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"NO_TEMPLATE_GROUP", @"Menu item to reset the template groups") + action:NULL + keyEquivalent:@""]; + selectItem.enabled = YES; + [menu insertItem:selectItem atIndex:0]; + + return menu; +} + + +- (NSMenu *)_buildTreeMenu:(KPKTree *)tree preselect:(NSUUID *)uuid { + NSMenu *menu = [[NSMenu alloc] init]; + menu.autoenablesItems = NO; + for(KPKGroup *group in tree.root.groups) { + [self _insertMenuItemsForGroup:group atLevel:0 inMenu:menu preselect:uuid]; + } + return menu; +} + +- (void)_insertMenuItemsForGroup:(KPKGroup *)group atLevel:(NSUInteger)level inMenu:(NSMenu *)menu preselect:(NSUUID *)uuid{ + NSMenuItem *groupItem = [[NSMenuItem alloc] init]; + groupItem.image = group.iconImage; + groupItem.title = group.title; + groupItem.representedObject = group; + groupItem.enabled = YES; + if(uuid && [group.uuid isEqual:uuid]) { + groupItem.state = NSOnState; + } + groupItem.indentationLevel = level; + [menu addItem:groupItem]; + for(KPKGroup *childGroup in group.groups) { + [self _insertMenuItemsForGroup:childGroup atLevel:level + 1 inMenu:menu preselect:uuid]; + } +} + + @end diff --git a/MacPass/MPSecurityDatabaseSettingsViewController.m b/MacPass/MPSecurityDatabaseSettingsViewController.m index 24a4a1e1..8c49f5f0 100644 --- a/MacPass/MPSecurityDatabaseSettingsViewController.m +++ b/MacPass/MPSecurityDatabaseSettingsViewController.m @@ -7,9 +7,33 @@ // #import "MPSecurityDatabaseSettingsViewController.h" +#import "MPDocument.h" +#import + @interface MPSecurityDatabaseSettingsViewController () +@property (assign) NSInteger argon2dMemory; +@property (assign) NSInteger argon2idMemory; + +@property (strong) IBOutlet NSButton *createKeyDerivationParametersButton; +@property (strong) IBOutlet NSPopUpButton *cipherPopupButton; +@property (strong) IBOutlet NSPopUpButton *keyDerivationPopupButton; +@property (strong) IBOutlet NSTabView *keyDerivationSettingsTabView; + +/* AES */ +@property (strong) IBOutlet NSTextField *aesEncryptionRoundsTextField; +/* Argon2d */ +@property (strong) IBOutlet NSTextField *argon2dThreadsTextField; +@property (strong) IBOutlet NSTextField *argon2dIterationsTextField; +@property (strong) IBOutlet NSTextField *argon2dMemoryTextField; +@property (strong) IBOutlet NSStepper *argon2dMemoryStepper; +/* Argon2id */ +@property (strong) IBOutlet NSTextField *argon2idThreadsTextField; +@property (strong) IBOutlet NSTextField *argon2idIterationsTextField; +@property (strong) IBOutlet NSTextField *argon2idMemoryTextField; +@property (strong) IBOutlet NSStepper *argon2idMemoryStepper; + @end @implementation MPSecurityDatabaseSettingsViewController @@ -19,4 +43,75 @@ // Do view setup here. } +- (void)_setupSecurityTab { + + MPDocument *document = (MPDocument *)self.view.window.windowController.document; + KPKTree *tree = document.tree; + KPKMetaData *metaData = tree.metaData; + + /* + If kdf or cipher is not found, exceptions are thrown. + This should not happen since we should not be able to load a file with unknown cipher/kdf + */ + KPKKeyDerivation *keyDerivation = [KPKKeyDerivation keyDerivationWithParameters:metaData.keyDerivationParameters]; + NSUInteger kdfIndex = [self.keyDerivationPopupButton.menu indexOfItemWithRepresentedObject:keyDerivation.uuid]; + [self.keyDerivationPopupButton selectItemAtIndex:kdfIndex]; + [self.keyDerivationSettingsTabView selectTabViewItemWithIdentifier:keyDerivation.uuid]; + + /* fill defaults for AES */ + KPKAESKeyDerivation *aesKdf = [[KPKAESKeyDerivation alloc] initWithParameters:[KPKAESKeyDerivation defaultParameters]]; + self.aesEncryptionRoundsTextField.integerValue = aesKdf.rounds; + + /* fill defaults for Argon2d */ + KPKArgon2DKeyDerivation *argon2dKdf = [[KPKArgon2DKeyDerivation alloc] initWithParameters:[KPKArgon2DKeyDerivation defaultParameters]]; + self.argon2dIterationsTextField.integerValue = argon2dKdf.iterations; + self.argon2dMemory = argon2dKdf.memory; + self.argon2dThreadsTextField.integerValue = argon2dKdf.threads; + + /* fill defaults for Argon2id */ + KPKArgon2IDKeyDerivation *argon2idKdf = [[KPKArgon2IDKeyDerivation alloc] initWithParameters:[KPKArgon2IDKeyDerivation defaultParameters]]; + self.argon2idIterationsTextField.integerValue = argon2idKdf.iterations; + self.argon2idMemory = argon2idKdf.memory; + self.argon2idThreadsTextField.integerValue = argon2idKdf.threads; + + if([keyDerivation isMemberOfClass:KPKAESKeyDerivation.class]) { + /* set to database values */ + KPKAESKeyDerivation *aesKdf = (KPKAESKeyDerivation *)keyDerivation; + self.aesEncryptionRoundsTextField.integerValue = aesKdf.rounds; + self.createKeyDerivationParametersButton.enabled = YES; + } + else if([keyDerivation isMemberOfClass:KPKArgon2DKeyDerivation.class]) { + /* set to database value */ + KPKArgon2DKeyDerivation *argon2dKdf = (KPKArgon2DKeyDerivation *)keyDerivation; + self.argon2dMemory = argon2dKdf.memory; + self.argon2dThreadsTextField.integerValue = argon2dKdf.threads; + self.argon2dIterationsTextField.integerValue = argon2dKdf.iterations; + } + else if([keyDerivation isMemberOfClass:KPKArgon2IDKeyDerivation.class]) { + /* set to database value */ + KPKArgon2IDKeyDerivation *argon2idKdf = (KPKArgon2IDKeyDerivation *)keyDerivation; + self.argon2idMemory = argon2idKdf.memory; + self.argon2idThreadsTextField.integerValue = argon2idKdf.threads; + self.argon2idIterationsTextField.integerValue = argon2idKdf.iterations; + } + else { + NSAssert(NO, @"Unkown key derivation"); + } + + self.argon2dMemoryStepper.minValue = 8*1024; // 8KB minimum + self.argon2dMemoryStepper.maxValue = NSIntegerMax; + self.argon2dMemoryStepper.increment = 1024*1024; // 1 megabytes steps + [self.argon2dMemoryTextField bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(argon2dMemory)) options:nil]; + [self.argon2dMemoryStepper bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(argon2dMemory)) options:nil]; + + self.argon2idMemoryStepper.minValue = 8*1024; // 8KB minimum + self.argon2idMemoryStepper.maxValue = NSIntegerMax; + self.argon2idMemoryStepper.increment = 1024*1024; // 1 megabytes steps + [self.argon2idMemoryTextField bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(argon2idMemory)) options:nil]; + [self.argon2idMemoryStepper bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(argon2idMemory)) options:nil]; + + NSUInteger cipherIndex = [self.cipherPopupButton.menu indexOfItemWithRepresentedObject:metaData.cipherUUID]; + [self.cipherPopupButton selectItemAtIndex:cipherIndex]; +} + @end diff --git a/MacPass/MPSecurityDatabaseSettingsViewController.xib b/MacPass/MPSecurityDatabaseSettingsViewController.xib index 7d7a76a8..0ddcbe63 100644 --- a/MacPass/MPSecurityDatabaseSettingsViewController.xib +++ b/MacPass/MPSecurityDatabaseSettingsViewController.xib @@ -8,6 +8,7 @@ + @@ -16,7 +17,319 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +