From f06603847631d9dee72406ebad400caffaf93d36 Mon Sep 17 00:00:00 2001 From: michael starke Date: Fri, 13 Oct 2017 16:43:51 +0200 Subject: [PATCH] enforced password changes are only possible after unlock, not before save anymore. Support for one-time forced changes added. --- Cartfile | 2 +- Cartfile.resolved | 2 +- MacPass/Base.lproj/DatabaseSettingsWindow.xib | 69 +++++++++++-------- MacPass/Base.lproj/PluginSettings.xib | 12 ++-- MacPass/MPDatabaseSettingsWindowController.h | 1 + MacPass/MPDatabaseSettingsWindowController.m | 46 ++++++++++--- MacPass/MPDocument.h | 2 +- MacPass/MPDocument.m | 13 +++- MacPass/MPDocumentWindowController.m | 25 +++---- 9 files changed, 107 insertions(+), 65 deletions(-) diff --git a/Cartfile b/Cartfile index fe69e79d..3a2802f0 100644 --- a/Cartfile +++ b/Cartfile @@ -1,3 +1,3 @@ github "sparkle-project/Sparkle" ~> 1.18.1 -github "mstarke/KeePassKit" "6cf17cc6f730c72b02d69ef4becdaceabbc15bd7" +github "mstarke/KeePassKit" ~> 1.2 github "mstarke/HNHUi" ~> 1.1 diff --git a/Cartfile.resolved b/Cartfile.resolved index 0d25c2fa..edcb16e7 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,3 +1,3 @@ github "mstarke/HNHUi" "1.2" -github "mstarke/KeePassKit" "6cf17cc6f730c72b02d69ef4becdaceabbc15bd7" +github "mstarke/KeePassKit" "1.2" github "sparkle-project/Sparkle" "1.18.1" diff --git a/MacPass/Base.lproj/DatabaseSettingsWindow.xib b/MacPass/Base.lproj/DatabaseSettingsWindow.xib index 557cb899..230462ec 100644 --- a/MacPass/Base.lproj/DatabaseSettingsWindow.xib +++ b/MacPass/Base.lproj/DatabaseSettingsWindow.xib @@ -1,8 +1,8 @@ - + - + @@ -28,6 +28,7 @@ + @@ -47,8 +48,8 @@ - - + + - + @@ -156,7 +157,7 @@ Gw - + @@ -423,25 +424,25 @@ Gw - + - + @@ -449,7 +450,7 @@ Gw - + @@ -460,11 +461,11 @@ Gw - + - + @@ -475,7 +476,7 @@ Gw - + @@ -483,7 +484,7 @@ Gw - + @@ -494,11 +495,11 @@ Gw - + - + @@ -506,7 +507,7 @@ Gw - + @@ -514,7 +515,7 @@ Gw - + @@ -525,7 +526,7 @@ Gw - + @@ -542,21 +543,21 @@ Gw - + @@ -567,7 +568,7 @@ Gw - + @@ -578,20 +579,27 @@ Gw - + - + + @@ -612,17 +620,19 @@ Gw - + + + @@ -636,6 +646,7 @@ Gw + @@ -653,7 +664,7 @@ Gw - + diff --git a/MacPass/Base.lproj/PluginSettings.xib b/MacPass/Base.lproj/PluginSettings.xib index b4cc97e3..79c80ff5 100644 --- a/MacPass/Base.lproj/PluginSettings.xib +++ b/MacPass/Base.lproj/PluginSettings.xib @@ -1,7 +1,8 @@ - + - + + @@ -33,7 +34,7 @@ - + @@ -72,7 +73,7 @@ - + @@ -112,6 +113,7 @@ + @@ -120,7 +122,7 @@ - + diff --git a/MacPass/MPDatabaseSettingsWindowController.h b/MacPass/MPDatabaseSettingsWindowController.h index 94fd9663..cf01e6c6 100644 --- a/MacPass/MPDatabaseSettingsWindowController.h +++ b/MacPass/MPDatabaseSettingsWindowController.h @@ -67,6 +67,7 @@ typedef NS_ENUM(NSUInteger, MPDatabaseSettingsTab) { @property (weak) IBOutlet NSButton *recommendKeyChangeCheckButton; @property (weak) IBOutlet NSButton *enforceKeyChangeCheckButton; +@property (weak) IBOutlet NSButton *enforceKeyChangeOnceCheckButton; @property (weak) IBOutlet NSTextField *recommendKeyChangeIntervalTextField; @property (weak) IBOutlet NSTextField *enforceKeyChangeIntervalTextField; diff --git a/MacPass/MPDatabaseSettingsWindowController.m b/MacPass/MPDatabaseSettingsWindowController.m index cc93a22d..91794663 100644 --- a/MacPass/MPDatabaseSettingsWindowController.m +++ b/MacPass/MPDatabaseSettingsWindowController.m @@ -37,6 +37,8 @@ @interface MPDatabaseSettingsWindowController () { NSString *_missingFeature; } +@property (assign) BOOL enableHistory; + @end @implementation MPDatabaseSettingsWindowController @@ -57,10 +59,10 @@ [super windowDidLoad]; NSAssert(self.document != nil, @"Document needs to be present"); - + self.sectionTabView.delegate = self; self.aesEncryptionRoundsTextField.formatter = [[MPNumericalInputFormatter alloc] init]; - + NSMenu *kdfMenu = [[NSMenu alloc] init]; NSArray *keyderivations = [KPKKeyDerivation availableKeyDerivations]; for(KPKKeyDerivation *kd in keyderivations) { @@ -80,6 +82,9 @@ self.cipherPopupButton.menu = cipherMenu; self.keyDerivationSettingsTabView.tabViewItems[0].identifier = [KPKAESKeyDerivation uuid]; self.keyDerivationSettingsTabView.tabViewItems[1].identifier = [KPKArgon2KeyDerivation uuid]; + + + } #pragma mark Actions @@ -94,7 +99,7 @@ KPKMetaData *metaData = ((MPDocument *)self.document).tree.metaData; metaData.databaseDescription = self.databaseDescriptionTextView.string; metaData.databaseName = self.databaseNameTextField.stringValue; - + NSInteger compressionIndex = self.databaseCompressionPopupButton.indexOfSelectedItem; if(compressionIndex >= KPKCompressionNone && compressionIndex < KPKCompressionCount) { metaData.compressionAlgorithm = (uint32_t)compressionIndex; @@ -106,18 +111,30 @@ else { metaData.color = databaseColor; } - + /* Advanced */ metaData.useTrash = HNHUIBoolForState(self.enableTrashCheckButton.state); NSMenuItem *trashMenuItem = self.selectTrashGoupPopUpButton.selectedItem; KPKGroup *trashGroup = trashMenuItem.representedObject; ((MPDocument *)self.document).tree.trash = trashGroup; + BOOL requiresHistoryMaintainance = NO; + requiresHistoryMaintainance = (metaData.historyMaxSize > self.historyMaxiumSizeTextField.integerValue || + metaData.historyMaxItems > self.historyMaximumItemsTextField.integerValue); + + metaData.historyMaxItems = self.historyMaximumItemsTextField.integerValue; + metaData.historyMaxSize = self.historyMaxiumSizeTextField.integerValue; + + /* only maintain history if actually needed */ + if(requiresHistoryMaintainance) { + KPKTree *tree = ((MPDocument *)self.document).tree; + [tree maintainHistory]; + } + NSMenuItem *templateMenuItem = self.templateGroupPopUpButton.selectedItem; KPKGroup *templateGroup = templateMenuItem.representedObject; ((MPDocument *)self.document).templates = templateGroup; - BOOL enforceMasterKeyChange = HNHUIBoolForState(self.enforceKeyChangeCheckButton.state); BOOL recommendMasterKeyChange = HNHUIBoolForState(self.recommendKeyChangeCheckButton.state); @@ -126,9 +143,10 @@ NSInteger enfoceInterval = self.enforceKeyChangeIntervalTextField.integerValue; NSInteger recommendInterval = self.recommendKeyChangeIntervalTextField.integerValue; - + metaData.masterKeyChangeEnforcementInterval = enforceMasterKeyChange ? enfoceInterval : -1; metaData.masterKeyChangeRecommendationInterval = recommendMasterKeyChange ? recommendInterval : -1; + metaData.enforceMasterKeyChangeOnce = HNHUIBoolForState(self.enforceKeyChangeOnceCheckButton.state); metaData.defaultUserName = self.defaultUsernameTextField.stringValue; @@ -257,22 +275,32 @@ } - (void)_setupAdvancedTab:(KPKTree *)tree { - HNHUISetStateFromBool(self.enableTrashCheckButton, tree.metaData.useTrash); - self.selectTrashGoupPopUpButton.enabled = tree.metaData.useTrash; + /* history */ + self.enableHistory = tree.metaData.isHistoryEnabled; + [self.enableHistoryCheckButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enableHistory)) options:nil]; self.historyMaximumItemsTextField.stringValue = [NSString stringWithFormat:@"%ld", tree.metaData.historyMaxItems]; self.historyMaxiumSizeTextField.stringValue = [NSString stringWithFormat:@"%ld", tree.metaData.historyMaxSize]; + [self.historyMaximumItemsTextField bind:NSEnabledBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enableHistory)) options:nil]; + [self.historyMaxiumSizeTextField bind:NSEnabledBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enableHistory)) 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 */ + HNHUISetStateFromBool(self.enforceKeyChangeOnceCheckButton, tree.metaData.enforceMasterKeyChangeOnce); HNHUISetStateFromBool(self.enforceKeyChangeCheckButton, tree.metaData.enforceMasterKeyChange); HNHUISetStateFromBool(self.recommendKeyChangeCheckButton, tree.metaData.recommendMasterKeyChange); [self.enforceKeyChangeIntervalTextField setEnabled:tree.metaData.enforceMasterKeyChange]; [self.recommendKeyChangeIntervalTextField setEnabled:tree.metaData.recommendMasterKeyChange]; - + self.enforceKeyChangeIntervalTextField.stringValue = @""; if(tree.metaData.enforceMasterKeyChange) { self.enforceKeyChangeIntervalTextField.integerValue = tree.metaData.masterKeyChangeEnforcementInterval; diff --git a/MacPass/MPDocument.h b/MacPass/MPDocument.h index 97eae9a1..08670e1c 100644 --- a/MacPass/MPDocument.h +++ b/MacPass/MPDocument.h @@ -146,8 +146,8 @@ FOUNDATION_EXPORT NSString *const MPDocumentGroupKey; - (NSArray *)allEntries; - (NSArray *)allGroups; -- (BOOL)shouldRecommendPasswordChange; - (BOOL)shouldEnforcePasswordChange; +- (BOOL)shouldRecommendPasswordChange; - (void)writeXMLToURL:(NSURL *)url; - (void)readXMLfromURL:(NSURL *)url; diff --git a/MacPass/MPDocument.m b/MacPass/MPDocument.m index 05a70351..18c8ecbf 100644 --- a/MacPass/MPDocument.m +++ b/MacPass/MPDocument.m @@ -581,13 +581,20 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGrou - (BOOL)shouldEnforcePasswordChange { KPKMetaData *metaData = self.tree.metaData; - if(!metaData.enforceMasterKeyChange) { return NO; } - return ( (24*60*60*metaData.masterKeyChangeEnforcementInterval) < -[metaData.masterKeyChanged timeIntervalSinceNow]); + if(metaData.enforceMasterKeyChangeOnce) { + return YES; + } + if(!metaData.enforceMasterKeyChange) { + return NO; + } + return ((24*60*60*metaData.masterKeyChangeEnforcementInterval) < -[metaData.masterKeyChanged timeIntervalSinceNow]); } - (BOOL)shouldRecommendPasswordChange { KPKMetaData *metaData = self.tree.metaData; - if(!metaData.recommendMasterKeyChange) { return NO; } + if(!metaData.recommendMasterKeyChange) { + return NO; + } return ( (24*60*60*metaData.masterKeyChangeRecommendationInterval) < -[metaData.masterKeyChanged timeIntervalSinceNow]); } diff --git a/MacPass/MPDocumentWindowController.m b/MacPass/MPDocumentWindowController.m index 9d1474b5..e9bcdcf5 100644 --- a/MacPass/MPDocumentWindowController.m +++ b/MacPass/MPDocumentWindowController.m @@ -218,15 +218,6 @@ typedef void (^MPPasswordChangedBlock)(BOOL didChangePassword); }]; return; } - else if(document.shouldEnforcePasswordChange) { - [self editPasswordWithCompetionHandler:^(NSInteger result) { - if(result == NSModalResponseOK) { - [self saveDocument:sender]; - } - }]; - [self _presentPasswordIntervalAlerts]; - return; - } /* All set and good ready to save */ [self.document saveDocument:sender]; } @@ -515,7 +506,7 @@ typedef void (^MPPasswordChangedBlock)(BOOL didChangePassword); #pragma mark NSAlert handling - (void)_presentPasswordIntervalAlerts { - MPDocument *document = [self document]; + MPDocument *document = self.document; if(document.shouldEnforcePasswordChange) { NSAlert *alert = [[NSAlert alloc] init]; @@ -524,15 +515,17 @@ typedef void (^MPPasswordChangedBlock)(BOOL didChangePassword); alert.informativeText = NSLocalizedString(@"ENFORCE_PASSWORD_CHANGE_ALERT_DESCRIPTION", ""); [alert addButtonWithTitle:NSLocalizedString(@"CHANGE_PASSWORD_WITH_DOTS", "")]; - [alert addButtonWithTitle:NSLocalizedString(@"CANCEL", "")]; - alert.buttons[1].keyEquivalent = [NSString stringWithFormat:@"%c", 0x1b]; [alert beginSheetModalForWindow:[self.document windowForSheet] completionHandler:^(NSModalResponse returnCode) { - if(NSAlertSecondButtonReturn == returnCode) { - return; - } dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - [self editPassword:nil]; + [self editPasswordWithCompetionHandler:^(NSInteger result) { + /* if password was changed, reset change key and dismiss */ + if(NSModalResponseOK == result) { + document.tree.metaData.enforceMasterKeyChangeOnce = NO; + } + /* password was not changes, so keep nagging the user! */ + [self _presentPasswordIntervalAlerts]; + }]; }); }]; }