mirror of
https://github.com/MacPass/MacPass.git
synced 2025-12-14 21:13:35 +00:00
Implemented password enforce and recommendation system
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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.
Reference in New Issue
Block a user