Implemented password enforce and recommendation system

This commit is contained in:
michael starke
2014-08-26 18:59:26 +02:00
parent f322c44fdf
commit d16df3ff02
6 changed files with 99 additions and 25 deletions

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5053" systemVersion="13C64" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="13E28" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment defaultVersion="1080" identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5053"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5056"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="MPDatePickingViewController">
@@ -49,7 +49,7 @@ AQABAAEAAQAB//+dkAEA//+PgAAE//+dkAEI//+dkAEMUERUAFBTVABQV1QAUFBUAAAAAAEAAAABA
</calendarDate>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<datePickerElements key="datePickerElements" year="YES" month="YES" day="YES" hour="YES" minute="YES" second="YES"/>
<datePickerElements key="datePickerElements" year="YES" month="YES" day="YES" hour="YES" minute="YES"/>
</datePickerCell>
</datePicker>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="15">
@@ -87,7 +87,6 @@ AQABAAEAAQAB//+dkAEA//+PgAAE//+dkAEI//+dkAEMUERUAFBTVABQV1QAUFBUAAAAAAEAAAABA
<constraints>
<constraint firstItem="3" firstAttribute="leading" secondItem="1" secondAttribute="leading" constant="20" symbolic="YES" id="13"/>
<constraint firstItem="3" firstAttribute="top" secondItem="1" secondAttribute="top" constant="20" symbolic="YES" id="14"/>
<constraint firstItem="15" firstAttribute="top" secondItem="3" secondAttribute="bottom" constant="20" symbolic="YES" id="21"/>
<constraint firstItem="15" firstAttribute="leading" secondItem="1" secondAttribute="leading" constant="20" symbolic="YES" id="22"/>
<constraint firstAttribute="trailing" secondItem="15" secondAttribute="trailing" constant="20" symbolic="YES" id="24"/>
<constraint firstAttribute="trailing" secondItem="25" secondAttribute="trailing" constant="20" symbolic="YES" id="27"/>
@@ -96,6 +95,7 @@ AQABAAEAAQAB//+dkAEA//+PgAAE//+dkAEI//+dkAEMUERUAFBTVABQV1QAUFBUAAAAAAEAAAABA
<constraint firstAttribute="trailing" secondItem="3" secondAttribute="trailing" constant="20" id="6Qs-OP-VRr"/>
<constraint firstItem="25" firstAttribute="centerY" secondItem="29" secondAttribute="centerY" id="M8N-5g-ClS"/>
<constraint firstItem="25" firstAttribute="leading" secondItem="29" secondAttribute="trailing" constant="8" symbolic="YES" id="on5-xg-jcC"/>
<constraint firstItem="15" firstAttribute="top" secondItem="3" secondAttribute="bottom" constant="20" symbolic="YES" id="qKB-vi-OAw"/>
<constraint firstItem="25" firstAttribute="top" secondItem="15" secondAttribute="bottom" constant="8" symbolic="YES" id="sxX-fk-xaJ"/>
</constraints>
</customView>

View File

@@ -50,9 +50,7 @@ typedef NS_ENUM(NSUInteger, MPDatePreset) {
[presetMenu addItem:item];
}
MPDocument *document = [[self windowController] document];
[self.datePicker setDateValue:document.selectedItem.timeInfo.expiryTime];
[self.datePicker setDateValue:[NSDate date]];
[self.presetPopupButton setAction:@selector(setDatePreset:)];
[self.presetPopupButton setMenu:presetMenu];
}

View File

@@ -161,6 +161,9 @@ typedef NS_OPTIONS(NSUInteger, MPEntrySearchFlags) {
- (NSArray *)allEntries;
- (NSArray *)allGroups;
- (BOOL)shouldRecommendPasswordChange;
- (BOOL)shouldEnforcePasswordChange;
/**
* Determines, whether the given item is inside the trash.
* The trash group itself is not considered as trashed.

View File

@@ -282,6 +282,7 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey
BOOL isUnlocked = (nil != self.tree);
if(isUnlocked) {
self.unlockCount += 1;
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidUnlockDatabaseNotification object:self];
/* Make sure to only store */
MPAppDelegate *delegate = [NSApp delegate];
@@ -292,11 +293,6 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey
else {
self.compositeKey = nil; // clear the key?
}
if(isUnlocked) {
self.unlockCount += 1;
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidUnlockDatabaseNotification object:self];
}
return isUnlocked;
}
@@ -312,6 +308,8 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey
[self.compositeKey setPassword:password andKeyfile:keyFileURL];
}
self.tree.metaData.masterKeyChanged = [NSDate date];
/* Key change is not undoable so just recored the change as done */
[self updateChangeCount:NSChangeDone];
/* We need to store the key file once the user actually writes the database */
return YES;
}
@@ -438,6 +436,18 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey
return NO;
}
- (BOOL)shouldEnforcePasswordChange {
KPKMetaData *metaData = self.tree.metaData;
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; }
return ( (24*60*60*metaData.masterKeyChangeRecommendationInterval) < -[metaData.masterKeyChanged timeIntervalSinceNow]);
}
#pragma mark Data manipulation
- (KPKEntry *)createEntry:(KPKGroup *)parent {
if(!parent) {

View File

@@ -30,7 +30,7 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) {
MPAlertLossySaveWarning,
};
typedef void (^MPPasswordChangedBlock)(void);
typedef void (^MPPasswordChangedBlock)(BOOL didChangePassword);
@interface MPDocumentWindowController () {
@private
@@ -88,7 +88,7 @@ typedef void (^MPPasswordChangedBlock)(void);
MPDocument *document = [self document];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didRevertDocument:) name:MPDocumentDidRevertNotifiation object:document];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showEntries) name:MPDocumentDidUnlockDatabaseNotification object:document];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didUnlockDatabase:) name:MPDocumentDidUnlockDatabaseNotification object:document];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didAddEntry:) name:MPDocumentDidAddEntryNotification object:document];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didAddGroup:) name:MPDocumentDidAddGroupNotification object:document];
@@ -181,6 +181,12 @@ typedef void (^MPPasswordChangedBlock)(void);
[self showInspector:self];
}
- (void)_didUnlockDatabase:(NSNotification *)notification {
[self showEntries];
/* Show password reminders */
[self _presentPasswordIntervalAlters];
}
#pragma mark Actions
- (void)saveDocument:(id)sender {
self.passwordChangedBlock = nil;
@@ -204,8 +210,12 @@ typedef void (^MPPasswordChangedBlock)(void);
}
else if(!document.compositeKey) {
__weak MPDocument *weakDocument = [self document];
self.passwordChangedBlock = ^void(void){[weakDocument saveDocument:sender];};
[self editPassword:sender];
self.passwordChangedBlock = ^void(BOOL didChangePassword){
if(didChangePassword) {
[weakDocument saveDocument:sender];
}
};
[self _editPasswordRequiringValidInput:YES];
return;
}
/* All set and good ready to save */
@@ -216,8 +226,12 @@ typedef void (^MPPasswordChangedBlock)(void);
MPDocument *document = [self document];
if(!document.compositeKey) {
__weak MPDocument *weakDocument = [self document];
self.passwordChangedBlock = ^void(void){[weakDocument saveDocumentAs:sender];};
[self editPassword:sender];
self.passwordChangedBlock = ^void(BOOL didChangePassword){
if(didChangePassword) {
[weakDocument saveDocumentAs:sender];
}
};
[self _editPasswordRequiringValidInput:YES];
return;
}
[[self document] saveDocumentAs:sender];
@@ -269,12 +283,16 @@ typedef void (^MPPasswordChangedBlock)(void);
}
- (void)editPassword:(id)sender {
[self _editPasswordRequiringValidInput:YES];
}
- (void)_editPasswordRequiringValidInput:(BOOL)canCancel {
if(!self.passwordEditWindowController) {
self.passwordEditWindowController = [[MPPasswordEditWindowController alloc] initWithDocument:[self document]];
self.passwordEditWindowController.delegate = self;
}
/* Disallow empty password if we want to save afterwards, otherwise the dialog keeps poping up */
self.passwordEditWindowController.allowsEmptyPasswordOrKey = (self.passwordChangedBlock == nil);
self.passwordEditWindowController.allowsEmptyPasswordOrKey = canCancel;
[NSApp beginSheet:[self.passwordEditWindowController window] modalForWindow:[self window] modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
}
@@ -327,9 +345,9 @@ typedef void (^MPPasswordChangedBlock)(void);
else {
[self.splitView addSubview:inspectorView];
[self.splitView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"[inspectorView(>=200)]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(inspectorView)]];
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(inspectorView)]];
[self.inspectorViewController updateResponderChain];
}
[[NSUserDefaults standardUserDefaults] setBool:!inspectorWasVisible forKey:kMPSettingsKeyShowInspector];
@@ -422,13 +440,35 @@ typedef void (^MPPasswordChangedBlock)(void);
#pragma mark MPPasswordEditWindowDelegate
- (void)didFinishPasswordEditing:(BOOL)changedPasswordOrKey {
if(changedPasswordOrKey && self.passwordChangedBlock) {
self.passwordChangedBlock();
if(self.passwordChangedBlock) {
self.passwordChangedBlock(changedPasswordOrKey);
}
self.passwordChangedBlock = nil;
}
#pragma mark Alert Delegate
#pragma mark NSAlert handling
- (void)_presentPasswordIntervalAlters {
MPDocument *document = [self document];
if(document.shouldEnforcePasswordChange) {
NSAlert *alert = [[NSAlert alloc] init];
[alert setAlertStyle:NSCriticalAlertStyle];
[alert setMessageText:NSLocalizedString(@"ENFORCE_PASSWORD_CHANGE_ALERT_TITLE", "")];
[alert setInformativeText:NSLocalizedString(@"ENFORCE_PASSWORD_CHANGE_ALERT_DESCRIPTION", "")];
[alert addButtonWithTitle:NSLocalizedString(@"CHANGE_PASSWORD", "")];
[alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:@selector(_enforcePasswordChangeAlertDidEnd:returnCode:contextInfo:) contextInfo:NULL];
}
else if(document.shouldRecommendPasswordChange) {
NSAlert *alert = [[NSAlert alloc] init];
[alert setAlertStyle:NSInformationalAlertStyle];
[alert setMessageText:NSLocalizedString(@"RECOMMEND_PASSWORD_CHANGE_ALERT_TITLE", "")];
[alert setInformativeText:NSLocalizedString(@"RECOMMEND_PASSWORD_CHANGE_ALERT_DESCRIPTION", "")];
[alert addButtonWithTitle:NSLocalizedString(@"CHANGE_PASSWORD", "")];
[alert addButtonWithTitle:NSLocalizedString(@"CANCEL", "")];
[[alert buttons][1] setKeyEquivalent:[NSString stringWithFormat:@"%c", 0x1b]];
[alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:@selector(_recommentPasswordChangeAlertDidEnd:returnCode:contextInfo:) contextInfo:NULL];
}
}
- (void)_dataLossOnSaveAlertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
switch(returnCode) {
@@ -450,6 +490,29 @@ typedef void (^MPPasswordChangedBlock)(void);
}
}
- (void)_recommentPasswordChangeAlertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
if(returnCode == NSAlertFirstButtonReturn) {
id __weak welf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[welf _editPasswordRequiringValidInput:YES];
});
}
}
- (void)_enforcePasswordChangeAlertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
NSAssert(returnCode == NSAlertFirstButtonReturn, @"Return for password change should always be NSAlertFirstButtonReturn");
id __weak welf = self;
self.passwordChangedBlock = ^(BOOL didChangePassword){
if(!didChangePassword) {
[welf _presentPasswordIntervalAlters];
}
};
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[welf _editPasswordRequiringValidInput:NO];
});
}
#pragma mark -
#pragma mark UI Helper

Binary file not shown.