Files
MacPass/MacPass/MPPasswordInputController.m
Christoph Leimbrock fc70464e19 Various usability improvements (#665)
* Set password creator window title

* Fix TODO, help url is read from Info.plist instead of a string literal

* Remove width constraint for 'Set Defaults' button of password generator so text is not cropped

* Improve keyboard shortcuts
New entries can be created using cmd + n, while cmd + shift + n creates new groups. Creating new databases is probably done too rarely to warrant a keyboard shortcut.
Additionally the 'New' menu item now has a submenu containing actions to create new entries, groups and databases (fixing #405).

* Hook up keyboard shortcut cmd + backspace to delete action

* Use shorter date format in inspector and add special output for distant future

* Show date picker when expiration is activates for either groups or entries but no date set

* Prompt for key file pops up automatically when the field is selected using tab

* Focus title field when new groups are created (#606).

* Rename search method so text fields don't capture it (#531)

* Don't show empty tags

* Remove menu item used for debugging.
2017-10-19 13:10:43 +02:00

178 lines
6.0 KiB
Objective-C

//
// MPPasswordInputController.m
// MacPass
//
// Created by Michael Starke on 17.02.13.
// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
//
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#import "MPPasswordInputController.h"
#import "MPAppDelegate.h"
#import "MPDocumentWindowController.h"
#import "MPDocument.h"
#import "MPSettingsHelper.h"
#import "MPKeyfilePathControlDelegate.h"
#import "HNHUi/HNHUi.h"
#import "NSError+Messages.h"
@interface MPPasswordInputController ()
@property (weak) IBOutlet HNHUIRoundedSecureTextField *passwordTextField;
@property (weak) IBOutlet NSPathControl *keyPathControl;
@property (strong) MPKeyfilePathControlDelegate *pathControlDelegate;
@property (weak) IBOutlet NSImageView *errorImageView;
@property (weak) IBOutlet NSTextField *errorInfoTextField;
@property (weak) IBOutlet NSButton *togglePasswordButton;
@property (weak) IBOutlet NSButton *enablePasswordCheckBox;
@property (weak) IBOutlet NSButton *unlockButton;
@property (weak) IBOutlet NSButton *cancelButton;
@property (copy) NSString *message;
@property (copy) NSString *cancelLabel;
@property (assign) BOOL showPassword;
@property (nonatomic, assign) BOOL enablePassword;
@property (copy) passwordInputCompletionBlock completionHandler;
@end
@implementation MPPasswordInputController
- (NSString *)nibName {
return @"PasswordInputView";
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if(self) {
_enablePassword = YES;
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(_selectKeyURL) name:MPDidChangeStoredKeyFilesSettings object:nil];
}
return self;
}
- (void)dealloc {
[NSNotificationCenter.defaultCenter removeObserver:self];
}
- (void)viewDidLoad {
self.keyPathControl.delegate = self.pathControlDelegate = [[MPKeyfilePathControlDelegate alloc] init];
self.errorImageView.image = [NSImage imageNamed:NSImageNameCaution];
[self.passwordTextField bind:NSStringFromSelector(@selector(showPassword)) toObject:self withKeyPath:NSStringFromSelector(@selector(showPassword)) options:nil];
[self.togglePasswordButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(showPassword)) options:nil];
[self.enablePasswordCheckBox bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enablePassword)) options:nil];
[self.togglePasswordButton bind:NSEnabledBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enablePassword)) options:nil];
[self.passwordTextField bind:NSEnabledBinding toObject:self withKeyPath:NSStringFromSelector(@selector(enablePassword)) options:nil];
[self.passwordTextField setNextKeyView:self.keyPathControl];
[self _reset];
}
- (NSResponder *)reconmendedFirstResponder {
return self.passwordTextField;
}
- (void)requestPasswordWithMessage:(NSString *)message cancelLabel:(NSString *)cancelLabel completionHandler:(passwordInputCompletionBlock)completionHandler {
self.completionHandler = completionHandler;
self.message = message;
self.cancelLabel = cancelLabel;
[self _reset];
}
- (void)requestPasswordWithCompletionHandler:(passwordInputCompletionBlock)completionHandler {
[self requestPasswordWithMessage:nil cancelLabel:nil completionHandler:completionHandler];
}
#pragma mark Properties
- (void)setEnablePassword:(BOOL)enablePassword {
if(_enablePassword != enablePassword) {
_enablePassword = enablePassword;
if(!_enablePassword) {
self.passwordTextField.stringValue = @"";
}
}
NSString *placeHolderString = _enablePassword ? NSLocalizedString(@"PASSWORD_INPUT_ENTER_PASSWORD", "") : NSLocalizedString(@"PASSWORD_INPUT_NO_PASSWORD", "");
((NSTextFieldCell *)self.passwordTextField.cell).placeholderString = placeHolderString;
}
#pragma mark -
#pragma mark Private
- (IBAction)_submit:(id)sender {
if(!self.completionHandler) {
return;
}
/* No password is different than an empty password */
NSError *error = nil;
NSString *password = self.enablePassword ? self.passwordTextField.stringValue : nil;
BOOL cancel = (sender == self.cancelButton);
BOOL result = self.completionHandler(password, self.keyPathControl.URL, cancel, &error);
if(cancel || result) {
return;
}
[self _showError:error];
/* do not shake if we are a sheet */
if(!self.view.window.isSheet) {
[self.view.window shakeWindow:nil];
}
}
- (IBAction)resetKeyFile:(id)sender {
/* If the reset was triggered by ourselves we want to preselect the keyfile */
if(sender == self) {
[self _selectKeyURL];
}
else {
self.keyPathControl.URL = nil;
}
}
- (void)_reset {
self.showPassword = NO;
self.enablePassword = YES;
self.passwordTextField.stringValue = @"";
self.errorInfoTextField.hidden = (nil == self.message);
if(self.message) {
self.errorInfoTextField.stringValue = self.message;
}
self.errorImageView.hidden = (nil == self.message);;
self.cancelButton.hidden = (nil == self.cancelLabel);
if(self.cancelLabel) {
self.cancelButton.stringValue = self.cancelLabel;
}
[self resetKeyFile:self];
}
- (void)_selectKeyURL {
MPDocument *document = self.windowController.document;
self.keyPathControl.URL = document.suggestedKeyURL;
}
- (void)_showError:(NSError *)error {
if(error) {
self.errorInfoTextField.stringValue = error.descriptionForErrorCode;
}
self.errorImageView.hidden = NO;
self.errorInfoTextField.hidden = NO;
}
@end