diff --git a/MacPass.xcodeproj/project.pbxproj b/MacPass.xcodeproj/project.pbxproj index 1fab3a23..ea7f8db8 100644 --- a/MacPass.xcodeproj/project.pbxproj +++ b/MacPass.xcodeproj/project.pbxproj @@ -93,6 +93,7 @@ 4C3826CC1AD04D8E007D7D67 /* 65_WikiTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C3826A21AD04D8E007D7D67 /* 65_WikiTemplate.pdf */; }; 4C3826CD1AD04D8E007D7D67 /* 66_MoneyTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C3826A31AD04D8E007D7D67 /* 66_MoneyTemplate.pdf */; }; 4C3826CE1AD04D8E007D7D67 /* 67_CertificatTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C3826A41AD04D8E007D7D67 /* 67_CertificatTemplate.pdf */; }; + 4C3B42871F935316007B04FD /* MPDayCountFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3B42861F935316007B04FD /* MPDayCountFormatter.m */; }; 4C3BD51516D276F800389F1F /* MPToolbarDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3BD51416D276F800389F1F /* MPToolbarDelegate.m */; }; 4C3C4EAF18D7039300153127 /* MPValueTransformerHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3C4EAE18D7039300153127 /* MPValueTransformerHelper.m */; }; 4C3FFD9E16DAF60600DF9186 /* ContextBar.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C3FFD9D16DAF60600DF9186 /* ContextBar.xib */; }; @@ -408,6 +409,8 @@ 4C3826A21AD04D8E007D7D67 /* 65_WikiTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = 65_WikiTemplate.pdf; sourceTree = ""; }; 4C3826A31AD04D8E007D7D67 /* 66_MoneyTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = 66_MoneyTemplate.pdf; sourceTree = ""; }; 4C3826A41AD04D8E007D7D67 /* 67_CertificatTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = 67_CertificatTemplate.pdf; sourceTree = ""; }; + 4C3B42851F935316007B04FD /* MPDayCountFormatter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPDayCountFormatter.h; sourceTree = ""; }; + 4C3B42861F935316007B04FD /* MPDayCountFormatter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPDayCountFormatter.m; sourceTree = ""; }; 4C3BD51316D276F800389F1F /* MPToolbarDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPToolbarDelegate.h; sourceTree = ""; }; 4C3BD51416D276F800389F1F /* MPToolbarDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPToolbarDelegate.m; sourceTree = ""; }; 4C3C4EAD18D7039300153127 /* MPValueTransformerHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPValueTransformerHelper.h; sourceTree = ""; }; @@ -963,6 +966,8 @@ 4C4B7EF717A4B335000234C7 /* MPUniqueCharactersFormatter.m */, 4C224B4017DFCB2300FF6AEE /* MPNumericalInputFormatter.h */, 4C224B4117DFCB2400FF6AEE /* MPNumericalInputFormatter.m */, + 4C3B42851F935316007B04FD /* MPDayCountFormatter.h */, + 4C3B42861F935316007B04FD /* MPDayCountFormatter.m */, 4C3C4EAD18D7039300153127 /* MPValueTransformerHelper.h */, 4C3C4EAE18D7039300153127 /* MPValueTransformerHelper.m */, 4C26C33D18D8C92100CF1A1C /* MPTemporaryFileStorage.h */, @@ -1844,6 +1849,7 @@ 4CE3E62617AB0D2D00D9E4B4 /* MPAttachmentTableDataSource.m in Sources */, 4C0728BD17B5B7F7005A7DD9 /* MPPasswordEditWindowController.m in Sources */, 4C0F647B17B6BC9C00D9522A /* MPSavePanelAccessoryViewController.m in Sources */, + 4C3B42871F935316007B04FD /* MPDayCountFormatter.m in Sources */, 4C57AE1417BA422B00CA4F34 /* MPSegmentedContextCell.m in Sources */, 4CE2961518429AA5005F01CE /* MPAutotypeKeyPress.m in Sources */, 4C32B0E71A1D4436007E12F1 /* KPKFormat+MPUTIDetection.m in Sources */, diff --git a/MacPass/Base.lproj/DatabaseSettingsWindow.xib b/MacPass/Base.lproj/DatabaseSettingsWindow.xib index 230462ec..cc6430e8 100644 --- a/MacPass/Base.lproj/DatabaseSettingsWindow.xib +++ b/MacPass/Base.lproj/DatabaseSettingsWindow.xib @@ -23,17 +23,20 @@ - + + - + + + @@ -46,14 +49,14 @@ - + - + - + @@ -424,101 +427,88 @@ Gw - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - + @@ -526,10 +516,7 @@ Gw - - - - + @@ -542,59 +529,70 @@ Gw - - - + - + - - - - - - - - - - - - + + - - + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -664,7 +688,7 @@ Gw - + diff --git a/MacPass/MPDatabaseSettingsWindowController.h b/MacPass/MPDatabaseSettingsWindowController.h index cf01e6c6..9e739deb 100644 --- a/MacPass/MPDatabaseSettingsWindowController.h +++ b/MacPass/MPDatabaseSettingsWindowController.h @@ -58,7 +58,11 @@ typedef NS_ENUM(NSUInteger, MPDatabaseSettingsTab) { /* Advanced Tab*/ @property (weak) IBOutlet NSButton *enableHistoryCheckButton; @property (weak) IBOutlet NSTextField *historyMaximumItemsTextField; -@property (weak) IBOutlet NSTextField *historyMaxiumSizeTextField; +@property (weak) IBOutlet NSStepper *historyMaximumItemsStepper; + +@property (weak) IBOutlet NSTextField *historyMaximumSizeTextField; +@property (weak) IBOutlet NSStepper *historyMaximumSizeStepper; + @property (weak) IBOutlet NSButton *enableTrashCheckButton; @property (weak) IBOutlet NSButton *emptyTrashOnQuitCheckButton; @property (weak) IBOutlet NSPopUpButton *selectTrashGoupPopUpButton; @@ -69,7 +73,9 @@ typedef NS_ENUM(NSUInteger, MPDatabaseSettingsTab) { @property (weak) IBOutlet NSButton *enforceKeyChangeCheckButton; @property (weak) IBOutlet NSButton *enforceKeyChangeOnceCheckButton; @property (weak) IBOutlet NSTextField *recommendKeyChangeIntervalTextField; +@property (weak) IBOutlet NSStepper *recommendKeyChangeIntervalStepper; @property (weak) IBOutlet NSTextField *enforceKeyChangeIntervalTextField; +@property (weak) IBOutlet NSStepper *enforceKeyChangeIntervalStepper; - (void)showSettingsTab:(MPDatabaseSettingsTab)tab; diff --git a/MacPass/MPDatabaseSettingsWindowController.m b/MacPass/MPDatabaseSettingsWindowController.m index 91794663..6a45ea17 100644 --- a/MacPass/MPDatabaseSettingsWindowController.m +++ b/MacPass/MPDatabaseSettingsWindowController.m @@ -37,7 +37,15 @@ @interface MPDatabaseSettingsWindowController () { NSString *_missingFeature; } + @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 @@ -82,9 +90,6 @@ self.cipherPopupButton.menu = cipherMenu; self.keyDerivationSettingsTabView.tabViewItems[0].identifier = [KPKAESKeyDerivation uuid]; self.keyDerivationSettingsTabView.tabViewItems[1].identifier = [KPKArgon2KeyDerivation uuid]; - - - } #pragma mark Actions @@ -119,11 +124,11 @@ ((MPDocument *)self.document).tree.trash = trashGroup; BOOL requiresHistoryMaintainance = NO; - requiresHistoryMaintainance = (metaData.historyMaxSize > self.historyMaxiumSizeTextField.integerValue || + requiresHistoryMaintainance = (metaData.historyMaxSize > self.historyMaximumSizeTextField.integerValue || metaData.historyMaxItems > self.historyMaximumItemsTextField.integerValue); - metaData.historyMaxItems = self.historyMaximumItemsTextField.integerValue; - metaData.historyMaxSize = self.historyMaxiumSizeTextField.integerValue; + metaData.historyMaxItems = self.enableHistory ? self.maxiumHistoryItems : -1; + metaData.historyMaxSize = self.maxiumHistorySize; /* only maintain history if actually needed */ if(requiresHistoryMaintainance) { @@ -277,11 +282,28 @@ - (void)_setupAdvancedTab:(KPKTree *)tree { /* 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]; + [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: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:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(maxiumHistoryItems)) options:nil]; /* trash */ HNHUISetStateFromBool(self.enableTrashCheckButton, tree.metaData.useTrash); @@ -295,22 +317,29 @@ [self _updateTemplateGroup:tree]; /* key changes */ + self.enforceKeyChange = tree.metaData.enforceMasterKeyChange; + self.recommendKeyChange = tree.metaData.recommendMasterKeyChange; 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.enforceKeyChangeCheckButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enforceKeyChange)) options:nil]; + [self.recommendKeyChangeCheckButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(recommendKeyChange)) options:nil]; - self.enforceKeyChangeIntervalTextField.stringValue = @""; - if(tree.metaData.enforceMasterKeyChange) { - self.enforceKeyChangeIntervalTextField.integerValue = tree.metaData.masterKeyChangeEnforcementInterval; - } - self.recommendKeyChangeIntervalTextField.stringValue = @""; - if(tree.metaData.recommendMasterKeyChange) { - self.recommendKeyChangeIntervalTextField.integerValue = tree.metaData.masterKeyChangeRecommendationInterval; - } - [self.enforceKeyChangeCheckButton bind:NSValueBinding toObject:self.enforceKeyChangeIntervalTextField withKeyPath:NSEnabledBinding options:nil]; - [self.recommendKeyChangeCheckButton bind:NSValueBinding toObject:self.recommendKeyChangeIntervalTextField withKeyPath:NSEnabledBinding 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:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enforceKeyChangeInterval)) options:nil]; + + 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:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(recommendKeyChangeInterval)) options:nil]; } - (void)_updateFirstResponder { diff --git a/MacPass/MPDayCountFormatter.h b/MacPass/MPDayCountFormatter.h new file mode 100644 index 00000000..17cea244 --- /dev/null +++ b/MacPass/MPDayCountFormatter.h @@ -0,0 +1,16 @@ +// +// MPDayCountFormatter.h +// MacPass +// +// Created by Michael Starke on 15.10.17. +// Copyright © 2017 HicknHack Software GmbH. All rights reserved. +// + +#import + +@interface MPDayCountFormatter : NSFormatter + +@property (copy) NSString *zeroFormat; // Supply this to override the default format for a 0-value. Default will localize: "ZERO_DAYS" +@property (copy) NSString *valueFormat; // Supply this to override the defualt format for all values not 0. Default will localized "%ld_DAYS" + +@end diff --git a/MacPass/MPDayCountFormatter.m b/MacPass/MPDayCountFormatter.m new file mode 100644 index 00000000..f5fcd1af --- /dev/null +++ b/MacPass/MPDayCountFormatter.m @@ -0,0 +1,48 @@ +// +// MPDayCountFormatter.m +// MacPass +// +// Created by Michael Starke on 15.10.17. +// Copyright © 2017 HicknHack Software GmbH. All rights reserved. +// + +#import "MPDayCountFormatter.h" + +@implementation MPDayCountFormatter + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + self = [super initWithCoder:aDecoder]; + if(self) { + [self _setupDefaults]; + } + return self; +} + +- (instancetype)init { + self = [super init]; + if(self) { + [self _setupDefaults]; + } + return self; +} + +- (void)_setupDefaults { + self.zeroFormat = NSLocalizedString(@"ZERO_DAYS", @"String to be displayed instead of valueformat with 0 days"); + self.valueFormat = NSLocalizedString(@"%ld_DAYS", @"Display format for days. Should contain a long decimal placeholder!"); +} + +- (NSString *)stringForObjectValue:(id)obj { + NSAssert([obj isKindOfClass:NSNumber.class], @"Unsupporded object class. Only NSNumber objects are allowed!"); + NSNumber *number = obj; + if(number.integerValue == 0) { + return self.zeroFormat; + } + return [NSString stringWithFormat:self.valueFormat, number.integerValue]; +} + +- (BOOL)getObjectValue:(out id _Nullable __autoreleasing *)obj forString:(NSString *)string errorDescription:(out NSString *__autoreleasing _Nullable *)error { + NSAssert(NO,@"Value from string extraction not supported!"); + return NO; +} + +@end diff --git a/MacPass/MPDocumentWindowController.m b/MacPass/MPDocumentWindowController.m index e9bcdcf5..24b228e9 100644 --- a/MacPass/MPDocumentWindowController.m +++ b/MacPass/MPDocumentWindowController.m @@ -523,8 +523,10 @@ typedef void (^MPPasswordChangedBlock)(BOOL didChangePassword); if(NSModalResponseOK == result) { document.tree.metaData.enforceMasterKeyChangeOnce = NO; } - /* password was not changes, so keep nagging the user! */ - [self _presentPasswordIntervalAlerts]; + else { + /* password was not changes, so keep nagging the user! */ + [self _presentPasswordIntervalAlerts]; + } }]; }); }];