Pickchar parser parses options. Output is not converted at the moment

This commit is contained in:
Michael Starke
2017-11-30 15:47:12 +01:00
parent a05a753a13
commit ee418db014
15 changed files with 419 additions and 75 deletions

View File

@@ -1,3 +1,3 @@
github "sparkle-project/Sparkle" ~> 1.18.1 github "sparkle-project/Sparkle" ~> 1.18.1
github "MacPass/KeePassKit" ~> 1.9 github "MacPass/KeePassKit" ~> 1.9
github "mstarke/HNHUi" ~> 1.4.1 github "mstarke/HNHUi" ~> 1.4.2

View File

@@ -1,3 +1,3 @@
github "MacPass/KeePassKit" "1.9" github "MacPass/KeePassKit" "1.9"
github "mstarke/HNHUi" "1.4.1" github "mstarke/HNHUi" "1.4.2"
github "sparkle-project/Sparkle" "1.18.1" github "sparkle-project/Sparkle" "1.18.1"

View File

@@ -191,6 +191,8 @@
4C8B36AB17A6ED4B005E1FF1 /* MPOutlineContextMenuDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8B36AA17A6ED4B005E1FF1 /* MPOutlineContextMenuDelegate.m */; }; 4C8B36AB17A6ED4B005E1FF1 /* MPOutlineContextMenuDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8B36AA17A6ED4B005E1FF1 /* MPOutlineContextMenuDelegate.m */; };
4C8DEAA21C314D2C00D24C32 /* MPTestAutotypeDelay.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8DEAA11C314D2C00D24C32 /* MPTestAutotypeDelay.m */; }; 4C8DEAA21C314D2C00D24C32 /* MPTestAutotypeDelay.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8DEAA11C314D2C00D24C32 /* MPTestAutotypeDelay.m */; };
4C8F0C6E1FCEE9B900BE157F /* MPPluginConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8F0C6D1FCEE9B900BE157F /* MPPluginConstants.m */; }; 4C8F0C6E1FCEE9B900BE157F /* MPPluginConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8F0C6D1FCEE9B900BE157F /* MPPluginConstants.m */; };
4C8F0C711FCEF91400BE157F /* MPPickcharsParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8F0C701FCEF91400BE157F /* MPPickcharsParser.m */; };
4C8F0C731FCF1B7A00BE157F /* MPTestPickcharsParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8F0C721FCF1B7A00BE157F /* MPTestPickcharsParser.m */; };
4C978E0D19AE54AB003067DF /* MPFlagsHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C978E0C19AE54AB003067DF /* MPFlagsHelper.m */; }; 4C978E0D19AE54AB003067DF /* MPFlagsHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C978E0C19AE54AB003067DF /* MPFlagsHelper.m */; };
4CA08DA017A831B200A6544B /* MPAddEntryContextMenuDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CA08D9F17A831B200A6544B /* MPAddEntryContextMenuDelegate.m */; }; 4CA08DA017A831B200A6544B /* MPAddEntryContextMenuDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CA08D9F17A831B200A6544B /* MPAddEntryContextMenuDelegate.m */; };
4CA0B2ED15BCADAC00654E32 /* SettingsWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4CA0B2EC15BCADAC00654E32 /* SettingsWindow.xib */; }; 4CA0B2ED15BCADAC00654E32 /* SettingsWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4CA0B2EC15BCADAC00654E32 /* SettingsWindow.xib */; };
@@ -658,6 +660,9 @@
4C8DEAA11C314D2C00D24C32 /* MPTestAutotypeDelay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTestAutotypeDelay.m; sourceTree = "<group>"; }; 4C8DEAA11C314D2C00D24C32 /* MPTestAutotypeDelay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTestAutotypeDelay.m; sourceTree = "<group>"; };
4C8F0C6C1FCEE98900BE157F /* MPPluginConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPluginConstants.h; sourceTree = "<group>"; }; 4C8F0C6C1FCEE98900BE157F /* MPPluginConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPluginConstants.h; sourceTree = "<group>"; };
4C8F0C6D1FCEE9B900BE157F /* MPPluginConstants.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPluginConstants.m; sourceTree = "<group>"; }; 4C8F0C6D1FCEE9B900BE157F /* MPPluginConstants.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPluginConstants.m; sourceTree = "<group>"; };
4C8F0C6F1FCEF91400BE157F /* MPPickcharsParser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPickcharsParser.h; sourceTree = "<group>"; };
4C8F0C701FCEF91400BE157F /* MPPickcharsParser.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPickcharsParser.m; sourceTree = "<group>"; };
4C8F0C721FCF1B7A00BE157F /* MPTestPickcharsParser.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPTestPickcharsParser.m; sourceTree = "<group>"; };
4C8FB9FA1FC2D0EF003691AA /* MPPlugin_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPlugin_Private.h; sourceTree = "<group>"; }; 4C8FB9FA1FC2D0EF003691AA /* MPPlugin_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPlugin_Private.h; sourceTree = "<group>"; };
4C93C5701FBDFEF700F36855 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/AutotypeCandidateSelectionView.strings; sourceTree = "<group>"; }; 4C93C5701FBDFEF700F36855 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/AutotypeCandidateSelectionView.strings; sourceTree = "<group>"; };
4C93C5711FBDFEF900F36855 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/AutotypeBuilderView.strings; sourceTree = "<group>"; }; 4C93C5711FBDFEF900F36855 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/AutotypeBuilderView.strings; sourceTree = "<group>"; };
@@ -1102,6 +1107,7 @@
4C45FB1E178E09ED0010007D /* MacPassTests */ = { 4C45FB1E178E09ED0010007D /* MacPassTests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
4C8F0C721FCF1B7A00BE157F /* MPTestPickcharsParser.m */,
4CCFA12C1BF0CC7A0078E0A1 /* Databases */, 4CCFA12C1BF0CC7A0078E0A1 /* Databases */,
4C10207E1B750E2F00BFCD59 /* MPTestAutotype.m */, 4C10207E1B750E2F00BFCD59 /* MPTestAutotype.m */,
4C8DEAA11C314D2C00D24C32 /* MPTestAutotypeDelay.m */, 4C8DEAA11C314D2C00D24C32 /* MPTestAutotypeDelay.m */,
@@ -1383,6 +1389,8 @@
4CA3530A18A53CB800839B0F /* MPKeyMapper.m */, 4CA3530A18A53CB800839B0F /* MPKeyMapper.m */,
4C1F7FA01E3A12E600D6A40E /* MPModifiedKey.h */, 4C1F7FA01E3A12E600D6A40E /* MPModifiedKey.h */,
4C1F7FA11E3A12E600D6A40E /* MPModifiedKey.m */, 4C1F7FA11E3A12E600D6A40E /* MPModifiedKey.m */,
4C8F0C6F1FCEF91400BE157F /* MPPickcharsParser.h */,
4C8F0C701FCEF91400BE157F /* MPPickcharsParser.m */,
); );
name = Autotype; name = Autotype;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1820,6 +1828,7 @@
files = ( files = (
4C45FB2D178E0BCB0010007D /* MPDatabaseLoading.m in Sources */, 4C45FB2D178E0BCB0010007D /* MPDatabaseLoading.m in Sources */,
4C8DEAA21C314D2C00D24C32 /* MPTestAutotypeDelay.m in Sources */, 4C8DEAA21C314D2C00D24C32 /* MPTestAutotypeDelay.m in Sources */,
4C8F0C731FCF1B7A00BE157F /* MPTestPickcharsParser.m in Sources */,
4C45FB30178E0CE20010007D /* MPTestDocument.m in Sources */, 4C45FB30178E0CE20010007D /* MPTestDocument.m in Sources */,
4C6BC6601A36717E00BDDF3D /* MPDatabaseSearch.m in Sources */, 4C6BC6601A36717E00BDDF3D /* MPDatabaseSearch.m in Sources */,
4C10207F1B750E2F00BFCD59 /* MPTestAutotype.m in Sources */, 4C10207F1B750E2F00BFCD59 /* MPTestAutotype.m in Sources */,
@@ -1849,6 +1858,7 @@
4CDF01A316D1B76700D0AC08 /* MPEntryViewController.m in Sources */, 4CDF01A316D1B76700D0AC08 /* MPEntryViewController.m in Sources */,
4C3BD51516D276F800389F1F /* MPToolbarDelegate.m in Sources */, 4C3BD51516D276F800389F1F /* MPToolbarDelegate.m in Sources */,
4C7B63731C0CB51F00D7038C /* TTTDataTransformer.m in Sources */, 4C7B63731C0CB51F00D7038C /* TTTDataTransformer.m in Sources */,
4C8F0C711FCEF91400BE157F /* MPPickcharsParser.m in Sources */,
4C61EA0316D2FD0800AC519E /* MPOutlineViewController.m in Sources */, 4C61EA0316D2FD0800AC519E /* MPOutlineViewController.m in Sources */,
4C65C79C16DD283900E32CFF /* MPToolbarButton.m in Sources */, 4C65C79C16DD283900E32CFF /* MPToolbarButton.m in Sources */,
4C431BCD16E2A82800700A81 /* MPPasteBoardController.m in Sources */, 4C431BCD16E2A82800700A81 /* MPPasteBoardController.m in Sources */,

View File

@@ -115,6 +115,7 @@ static MPLockDaemon *_sharedInstance;
} }
- (void)_checkIdleTime:(NSTimer *)timer { - (void)_checkIdleTime:(NSTimer *)timer {
NSLog(@"Check Idle");
if(timer != self.idleCheckTimer) { if(timer != self.idleCheckTimer) {
return; // Wrong timer?! return; // Wrong timer?!
} }

View File

@@ -13,10 +13,12 @@ NS_ASSUME_NONNULL_BEGIN
@property (copy) NSString *sourceValue; @property (copy) NSString *sourceValue;
@property (nonatomic, copy) NSString *pickedValue; @property (nonatomic, copy) NSString *pickedValue;
@property NSInteger countToPick; @property NSInteger minimumCharacterCount;
@property (nonatomic) BOOL hideSource; @property (nonatomic) BOOL hidePickedCharacters;
- (IBAction)reset:(id)sender; - (IBAction)reset:(id)sender;
- (IBAction)submitValue:(id)sender;
@end @end

View File

@@ -12,17 +12,22 @@
#import <HNHUi/HNHUi.h> #import <HNHUi/HNHUi.h>
@interface MPPickcharViewController () <NSTableViewDelegate, NSTableViewDataSource> @interface MPPickcharViewController () <NSTableViewDelegate, NSTableViewDataSource>
@property (weak) IBOutlet NSTableView *characterTableView; @property (weak) IBOutlet NSTableView *characterTableView;
@property (weak) IBOutlet NSTextField *pickedValueTextField; @property (weak) IBOutlet NSTextField *pickedValueTextField;
@property (weak) IBOutlet NSButton *togglePasswordDisplayButton; @property (weak) IBOutlet NSButton *togglePasswordDisplayButton;
@property (weak) IBOutlet NSTextField *messageTextField;
@property (weak) IBOutlet NSTextField *pickedStatusTextField; @property (weak) IBOutlet NSTextField *pickedStatusTextField;
@property (weak) IBOutlet NSButton *submitButton;
@property (nonatomic) NSInteger availableCountToPick; @property (nonatomic) NSInteger availableCountToPick;
@end @end
@implementation MPPickcharViewController @implementation MPPickcharViewController
+ (NSSet<NSString *> *)keyPathsForValuesAffectingAvailableCountToPick { + (NSSet<NSString *> *)keyPathsForValuesAffectingAvailableCountToPick {
return [NSSet setWithArray:@[NSStringFromSelector(@selector(countToPick)), NSStringFromSelector(@selector(pickedValue))]]; return [NSSet setWithArray:@[NSStringFromSelector(@selector(minimumCharacterCount)), NSStringFromSelector(@selector(pickedValue))]];
} }
- (NSString *)nibName { - (NSString *)nibName {
@@ -32,7 +37,7 @@
- (instancetype)initWithCoder:(NSCoder *)coder { - (instancetype)initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder]; self = [super initWithCoder:coder];
if(self) { if(self) {
self.hideSource = NO; self.hidePickedCharacters = NO;
} }
return self; return self;
} }
@@ -40,13 +45,10 @@
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if(self) { if(self) {
self.hideSource = NO; self.hidePickedCharacters = NO;
} }
return self; return self;
} }
- (void)reset:(id)sender {
self.pickedValue = @"";
}
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
@@ -65,28 +67,35 @@
self.characterTableView.enclosingScrollView.horizontalScroller.scrollerStyle = NSScrollerStyleLegacy; self.characterTableView.enclosingScrollView.horizontalScroller.scrollerStyle = NSScrollerStyleLegacy;
[self.pickedValueTextField bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(pickedValue)) options:nil]; [self.pickedValueTextField bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(pickedValue)) options:nil];
[self.togglePasswordDisplayButton bind:NSValueBinding toObject:self.pickedValueTextField withKeyPath:NSStringFromSelector(@selector(showPassword)) options:nil]; [self.togglePasswordDisplayButton bind:NSValueBinding toObject:self.pickedValueTextField withKeyPath:NSStringFromSelector(@selector(showPassword)) options:nil];
[self reset:self]; [self reset:self];
} }
- (void)setHideSource:(BOOL)hideSource { - (void)setHidePickedCharacters:(BOOL)hide {
if(_hideSource != hideSource) { if(_hidePickedCharacters != hide) {
_hideSource = hideSource; _hidePickedCharacters = hide;
[self.characterTableView reloadData]; [self.characterTableView reloadData];
} }
} }
- (void)setPickedValue:(NSString *)pickedValue { - (void)setPickedValue:(NSString *)pickedValue {
_pickedValue = [pickedValue copy]; _pickedValue = [pickedValue copy];
[self _updatePickedStatus]; [self _updateContent];
} }
- (NSInteger)availableCountToPick { - (NSInteger)availableCountToPick {
return (self.countToPick - self.pickedValue.composedCharacterLength); return (self.minimumCharacterCount - self.pickedValue.composedCharacterLength);
} }
- (void)_updatePickedStatus { - (void)_updateContent {
self.pickedStatusTextField.stringValue = [NSString stringWithFormat:@"%ld characters remaining", self.availableCountToPick]; self.messageTextField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"PICKCHAR_INFO_MESSAGE_PICK_CHARACTERS_%ld", "Info about how many character has to pick in pickchar dialog"), self.minimumCharacterCount];
if(self.minimumCharacterCount == 0) {
self.pickedStatusTextField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"PICKED_%ld_CHARACTERS", @"Count of picked characters in pickchars dialog if no limit is set"), self.pickedValue.composedCharacterLength];
}
else {
self.pickedStatusTextField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"%ld_CHARACTERS_TO_PICK_REMAINING", @"Count of characters remaining in pickchars dialog"), self.availableCountToPick];
}
self.submitButton.enabled = (self.availableCountToPick == 0 || self.minimumCharacterCount == 0);
} }
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
@@ -102,12 +111,12 @@
if(index == NSNotFound) { if(index == NSNotFound) {
view.textField.stringValue = @"?"; view.textField.stringValue = @"?";
} }
view.textField.stringValue = self.hideSource ? @"•" : [self.sourceValue composedCharacterAtIndex:index]; view.textField.stringValue = self.hidePickedCharacters ? @"•" : [self.sourceValue composedCharacterAtIndex:index];
return view; return view;
} }
- (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn { - (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn {
if(self.availableCountToPick <= 0) { if(self.minimumCharacterCount != 0 && self.availableCountToPick <= 0) {
return; return;
} }
NSInteger index = [tableView.tableColumns indexOfObjectIdenticalTo:tableColumn]; NSInteger index = [tableView.tableColumns indexOfObjectIdenticalTo:tableColumn];
@@ -122,12 +131,13 @@
} }
} }
- (IBAction)finishedPicking:(id)sender { - (void)submitValue:(id)sender {
[NSApp stopModalWithCode:NSModalResponseOK]; [NSApp stopModalWithCode:NSModalResponseOK];
} }
- (IBAction)cancelPicking:(id)sender { - (void)reset:(id)sender {
[NSApp stopModalWithCode:NSModalResponseCancel]; self.pickedValue = @"";
} }
@end @end

View File

@@ -0,0 +1,40 @@
//
// MPPickcharParser.h
// MacPass
//
// Created by Michael Starke on 29.11.17.
// Copyright © 2017 HicknHack Software GmbH. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface MPPickcharsParser : NSObject
@property (readonly) BOOL hideCharacters;
@property (readonly) BOOL convertToDownArrows;
@property (readonly) NSUInteger pickCount; // count to pick - 0 if unlimted
@property (readonly) NSUInteger checkboxOffset;
@property (readonly, copy) NSString *checkboxFormat;
/**
Initializes the parser with the given option string.
@param options Options raw as from PICKCHARS entry
@return Parser instance configured with the provided options or defaults if errors occured
*/
- (instancetype)initWithOptions:(NSString *)options NS_DESIGNATED_INITIALIZER;
/**
This message is used to actually process any input string picked by the user
into the format specified by the options.
For a default initalized parsers input will be the same as output,
If conversion is enabled, the string will contain autotype commands for arrow presses, tabs etc.
The returned string is to be processed further by the autotype system to yield the final values.
@param string Input value picked by the user
@return converted input as set by the options
*/
- (NSString *)processPickedString:(NSString *)string;
@end

134
MacPass/MPPickcharsParser.m Normal file
View File

@@ -0,0 +1,134 @@
//
// MPPickcharParser.m
// MacPass
//
// Created by Michael Starke on 29.11.17.
// Copyright © 2017 HicknHack Software GmbH. All rights reserved.
//
#import "MPPickcharsParser.h"
#import <KeePassKit/KeePassKit.h>
@interface MPPickcharsParser ()
@property NSUInteger pickCount; // count to pick
@property NSUInteger checkboxOffset;
@property BOOL convertToDownArrows;
@property BOOL hideCharacters;
@property (copy) NSString *checkboxFormat;
@end
@implementation MPPickcharsParser
- (instancetype)init {
self = [self initWithOptions:nil];
return self;
}
- (instancetype)initWithOptions:(NSString *)options {
self = [super init];
if(self) {
_pickCount = 0;
_checkboxOffset = 0;
_convertToDownArrows = NO;
_hideCharacters = YES;
[self _parseOptions:options];
}
return self;
}
- (NSString *)processPickedString:(NSString *)string {
return string;
}
/*
{PICKCHAR:Field:Options}
Options allow to convert picked character to be typed into drop-down-boxes.
E.g. select digits or letters
Options:
ID=id (id for multiple pickchars in a field will not get processed
Conv=D If set, convert values to down arrow presses
Conv-Offset= Offset for conversion of characters, will be added to all arrow presses
Conv-Fmt= Format of the check-box
0 - Numbers 0129456789
1 - NUmber 1234567890
a - lowercase characters
A - uppercase characters
? - skip combobox item
-> combine for layout e.g. 0a or 0aA 0?aA
*/
- (void)_parseOptions:(NSString *)options {
for(NSString *option in [options componentsSeparatedByString:kKPKPlaceholderPickCharsOptionDelemiter]) {
NSArray <NSString *>*keyValuePair = [option componentsSeparatedByString:@"="];
if(![self _parseOptionKeyValuePair:keyValuePair]) {
NSLog(@"Invalid Option: %@", option);
continue;
};
}
}
- (BOOL)_parseOptionKeyValuePair:(NSArray <NSString *> *)optionPair {
if(optionPair.count != 2) {
return NO;
}
NSString *key = [optionPair.firstObject stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *option = [optionPair.lastObject stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if(NSOrderedSame == [key compare:kKPKPlaceholderPickCharsOptionCount options:NSCaseInsensitiveSearch]
|| NSOrderedSame == [key compare:kKPKPlaceholderPickCharsOptionCountShort options:NSCaseInsensitiveSearch]) {
NSScanner *scanner = [[NSScanner alloc] initWithString:option];
NSInteger count;
if([scanner scanInteger:&count]) {
if(count != INT_MIN && count != INT_MAX) {
self.pickCount = MAX(0,count);
return YES;
}
}
return NO;
}
/*
FOUNDATION_EXPORT NSString *const kKPKPlaceholderPickCharsOptionConvertFormat;
*/
if(NSOrderedSame == [key compare:kKPKPlaceholderPickCharsOptionHide options:NSCaseInsensitiveSearch]) {
if(NSOrderedSame == [option compare:@"false" options:NSCaseInsensitiveSearch]) {
self.hideCharacters = NO;
return YES;
}
if(NSOrderedSame == [option compare:@"true" options:NSCaseInsensitiveSearch]) {
self.hideCharacters = YES;
return YES;
}
return NO;
}
if(NSOrderedSame == [key compare:kKPKPlaceholderPickCharsOptionConvert options:NSCaseInsensitiveSearch]) {
if(NSOrderedSame == [option compare:@"D" options:NSCaseInsensitiveSearch]) {
self.convertToDownArrows = YES;
return YES;
}
return NO;
}
if(NSOrderedSame == [key compare:kKPKPlaceholderPickCharsOptionConvertOffset options:NSCaseInsensitiveSearch]) {
NSScanner *scanner = [[NSScanner alloc] initWithString:option];
NSInteger offset;
if([scanner scanInteger:&offset]) {
if(offset != INT_MIN && offset != INT_MAX) {
self.checkboxOffset = MAX(0,offset);
return YES;
}
}
return NO;
}
if(NSOrderedSame == [key compare:kKPKPlaceholderPickCharsOptionConvertFormat options:NSCaseInsensitiveSearch]) {
self.checkboxFormat = option;
return YES;
}
return NO;
}
@end

View File

@@ -36,7 +36,6 @@ typedef NS_ENUM(NSUInteger, MPPickfieldTableColumn) {
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
self.tableModel = [[MPPickfieldTableModel alloc] initWithEntry:self.representedEntry inDocument:nil]; self.tableModel = [[MPPickfieldTableModel alloc] initWithEntry:self.representedEntry inDocument:nil];
} }
- (KPKEntry *)representedEntry { - (KPKEntry *)representedEntry {

View File

@@ -26,6 +26,7 @@
#import "MPSettingsHelper.h" #import "MPSettingsHelper.h"
#import "MPPickcharViewController.h" #import "MPPickcharViewController.h"
#import "MPPickfieldViewController.h" #import "MPPickfieldViewController.h"
#import "MPPickcharsParser.h"
@interface MPTreeDelegate (); @interface MPTreeDelegate ();
@@ -106,11 +107,12 @@
if(value.length == 0) { if(value.length == 0) {
return @""; // error while retrieving source value return @""; // error while retrieving source value
} }
MPPickcharsParser *parser = [[MPPickcharsParser alloc] initWithOptions:options];
MPPickcharViewController *pickCharViewController = [[MPPickcharViewController alloc] init]; MPPickcharViewController *pickCharViewController = [[MPPickcharViewController alloc] init];
pickCharViewController.sourceValue = value; pickCharViewController.sourceValue = value;
pickCharViewController.countToPick = 10; pickCharViewController.minimumCharacterCount = parser.pickCount;
pickCharViewController.hidePickedCharacters = parser.hideCharacters;
NSPanel *panel = [[NSPanel alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100) NSPanel *panel = [[NSPanel alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
styleMask:NSWindowStyleMaskNonactivatingPanel|NSWindowStyleMaskTitled|NSWindowStyleMaskResizable styleMask:NSWindowStyleMaskNonactivatingPanel|NSWindowStyleMaskTitled|NSWindowStyleMaskResizable

View File

@@ -9,8 +9,10 @@
<customObject id="-2" userLabel="File's Owner" customClass="MPPickcharViewController"> <customObject id="-2" userLabel="File's Owner" customClass="MPPickcharViewController">
<connections> <connections>
<outlet property="characterTableView" destination="KJq-FZ-rAE" id="H5Y-kG-Mvm"/> <outlet property="characterTableView" destination="KJq-FZ-rAE" id="H5Y-kG-Mvm"/>
<outlet property="messageTextField" destination="wAr-f2-ZUQ" id="kaZ-v7-6UW"/>
<outlet property="pickedStatusTextField" destination="e2q-qh-Zlv" id="paL-BH-g7a"/> <outlet property="pickedStatusTextField" destination="e2q-qh-Zlv" id="paL-BH-g7a"/>
<outlet property="pickedValueTextField" destination="KQ1-tZ-qja" id="ETe-j3-jdp"/> <outlet property="pickedValueTextField" destination="KQ1-tZ-qja" id="ETe-j3-jdp"/>
<outlet property="submitButton" destination="k8l-uy-C3l" id="nLN-Wz-dGW"/>
<outlet property="togglePasswordDisplayButton" destination="hKI-WP-N93" id="ZDt-Rp-Ix2"/> <outlet property="togglePasswordDisplayButton" destination="hKI-WP-N93" id="ZDt-Rp-Ix2"/>
<outlet property="view" destination="Hz6-mo-xeY" id="0bl-1N-x8E"/> <outlet property="view" destination="Hz6-mo-xeY" id="0bl-1N-x8E"/>
</connections> </connections>
@@ -18,7 +20,7 @@
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/> <customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="Hz6-mo-xeY"> <customView id="Hz6-mo-xeY">
<rect key="frame" x="0.0" y="0.0" width="410" height="190"/> <rect key="frame" x="0.0" y="0.0" width="410" height="220"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews> <subviews>
<textField horizontalHuggingPriority="249" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KQ1-tZ-qja" customClass="HNHUIRoundedSecureTextField"> <textField horizontalHuggingPriority="249" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KQ1-tZ-qja" customClass="HNHUIRoundedSecureTextField">
@@ -108,13 +110,13 @@
</tableHeaderView> </tableHeaderView>
</scrollView> </scrollView>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="k8l-uy-C3l"> <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="k8l-uy-C3l">
<rect key="frame" x="324" y="13" width="72" height="32"/> <rect key="frame" x="313" y="13" width="83" height="32"/>
<buttonCell key="cell" type="push" title="Done" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="8vP-Ka-vsA"> <buttonCell key="cell" type="push" title="Submit" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="8vP-Ka-vsA">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
</buttonCell> </buttonCell>
<connections> <connections>
<action selector="finishedPicking:" target="-1" id="Gb1-1S-8bv"/> <action selector="submitValue:" target="-2" id="Hvu-95-9mF"/>
</connections> </connections>
</button> </button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Y8X-Bm-qLt"> <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Y8X-Bm-qLt">
@@ -128,8 +130,16 @@
</connections> </connections>
</button> </button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="e2q-qh-Zlv"> <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="e2q-qh-Zlv">
<rect key="frame" x="187" y="49" width="37" height="17"/> <rect key="frame" x="167" y="49" width="76" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Label" id="M3h-q8-FLO"> <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="StatusLabel" id="M3h-q8-FLO">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="wAr-f2-ZUQ">
<rect key="frame" x="18" y="178" width="374" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="MessageLabel" id="sHz-kg-YJQ">
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
@@ -143,19 +153,24 @@
<constraint firstItem="MVS-ug-wys" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" symbolic="YES" id="9cE-TT-pqS"/> <constraint firstItem="MVS-ug-wys" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" symbolic="YES" id="9cE-TT-pqS"/>
<constraint firstItem="hKI-WP-N93" firstAttribute="leading" secondItem="Y8X-Bm-qLt" secondAttribute="trailing" constant="8" id="AVv-zt-6sj"/> <constraint firstItem="hKI-WP-N93" firstAttribute="leading" secondItem="Y8X-Bm-qLt" secondAttribute="trailing" constant="8" id="AVv-zt-6sj"/>
<constraint firstAttribute="trailing" secondItem="k8l-uy-C3l" secondAttribute="trailing" constant="20" symbolic="YES" id="Eaa-oF-Lt5"/> <constraint firstAttribute="trailing" secondItem="k8l-uy-C3l" secondAttribute="trailing" constant="20" symbolic="YES" id="Eaa-oF-Lt5"/>
<constraint firstItem="MVS-ug-wys" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" constant="20" symbolic="YES" id="Klq-Q9-Rjp"/> <constraint firstItem="MVS-ug-wys" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" constant="50" id="Klq-Q9-Rjp"/>
<constraint firstItem="wAr-f2-ZUQ" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" constant="20" symbolic="YES" id="QQM-Db-MJM"/>
<constraint firstItem="Y8X-Bm-qLt" firstAttribute="leading" secondItem="KQ1-tZ-qja" secondAttribute="trailing" constant="8" id="Qxu-Wk-ckL"/> <constraint firstItem="Y8X-Bm-qLt" firstAttribute="leading" secondItem="KQ1-tZ-qja" secondAttribute="trailing" constant="8" id="Qxu-Wk-ckL"/>
<constraint firstAttribute="trailing" secondItem="wAr-f2-ZUQ" secondAttribute="trailing" constant="20" symbolic="YES" id="Scg-AR-d0y"/>
<constraint firstItem="Y8X-Bm-qLt" firstAttribute="centerY" secondItem="KQ1-tZ-qja" secondAttribute="centerY" id="T81-yL-LEh"/> <constraint firstItem="Y8X-Bm-qLt" firstAttribute="centerY" secondItem="KQ1-tZ-qja" secondAttribute="centerY" id="T81-yL-LEh"/>
<constraint firstItem="e2q-qh-Zlv" firstAttribute="top" secondItem="KQ1-tZ-qja" secondAttribute="bottom" constant="8" symbolic="YES" id="UWG-aW-fsW"/> <constraint firstItem="e2q-qh-Zlv" firstAttribute="top" secondItem="KQ1-tZ-qja" secondAttribute="bottom" constant="8" symbolic="YES" id="UWG-aW-fsW"/>
<constraint firstAttribute="bottom" secondItem="k8l-uy-C3l" secondAttribute="bottom" constant="20" symbolic="YES" id="UXs-2n-gB5"/> <constraint firstAttribute="bottom" secondItem="k8l-uy-C3l" secondAttribute="bottom" constant="20" symbolic="YES" id="UXs-2n-gB5"/>
<constraint firstItem="e2q-qh-Zlv" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" symbolic="YES" id="WVC-0y-S19"/> <constraint firstItem="e2q-qh-Zlv" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" symbolic="YES" id="WVC-0y-S19"/>
<constraint firstItem="MVS-ug-wys" firstAttribute="top" secondItem="wAr-f2-ZUQ" secondAttribute="bottom" constant="8" symbolic="YES" id="b0M-bk-j9E"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="e2q-qh-Zlv" secondAttribute="trailing" constant="20" symbolic="YES" id="fCf-pK-CXQ"/> <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="e2q-qh-Zlv" secondAttribute="trailing" constant="20" symbolic="YES" id="fCf-pK-CXQ"/>
<constraint firstItem="k8l-uy-C3l" firstAttribute="top" secondItem="e2q-qh-Zlv" secondAttribute="bottom" constant="8" id="jwg-Z1-txO"/> <constraint firstItem="k8l-uy-C3l" firstAttribute="top" secondItem="e2q-qh-Zlv" secondAttribute="bottom" constant="8" id="jwg-Z1-txO"/>
<constraint firstAttribute="trailing" secondItem="MVS-ug-wys" secondAttribute="trailing" constant="20" symbolic="YES" id="mMv-HC-fEv"/> <constraint firstAttribute="trailing" secondItem="MVS-ug-wys" secondAttribute="trailing" constant="20" symbolic="YES" id="mMv-HC-fEv"/>
<constraint firstItem="KQ1-tZ-qja" firstAttribute="top" secondItem="MVS-ug-wys" secondAttribute="bottom" constant="8" symbolic="YES" id="nKb-eh-ba4"/> <constraint firstItem="KQ1-tZ-qja" firstAttribute="top" secondItem="MVS-ug-wys" secondAttribute="bottom" constant="8" symbolic="YES" id="nKb-eh-ba4"/>
<constraint firstItem="e2q-qh-Zlv" firstAttribute="centerX" secondItem="Hz6-mo-xeY" secondAttribute="centerX" id="tE5-PK-tp0"/> <constraint firstItem="e2q-qh-Zlv" firstAttribute="centerX" secondItem="Hz6-mo-xeY" secondAttribute="centerX" id="tE5-PK-tp0"/>
<constraint firstItem="wAr-f2-ZUQ" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" symbolic="YES" id="xV9-bY-eZn"/>
<constraint firstItem="k8l-uy-C3l" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="319" id="zZ5-GH-8no"/>
</constraints> </constraints>
<point key="canvasLocation" x="-1020" y="-227"/> <point key="canvasLocation" x="-1291" y="-443"/>
</customView> </customView>
</objects> </objects>
<resources> <resources>

View File

@@ -1,21 +1,76 @@
{ <?xml version="1.0" encoding="UTF-8"?>
"DUPLICATE_ENTRIES_%ld" = { <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
NSStringLocalizedFormatKey = "%#@entries@"; <plist version="1.0">
entries = { <dict>
NSStringFormatSpecTypeKey = NSStringPluralRuleType; <key>%ld_CHARACTERS_TO_PICK_REMAINING</key>
NSStringFormatValueTypeKey = ld; <dict>
one = "Eintrag duplizieren"; <key>NSStringLocalizedFormatKey</key>
other = "Eintr\U00e4ge duplizieren"; <string>%#@characters@</string>
}; <key>characters</key>
}; <dict>
"EVERY_%ld_DAYS" = { <key>NSStringFormatSpecTypeKey</key>
NSStringLocalizedFormatKey = "%#@days@"; <string>NSStringPluralRuleType</string>
days = { <key>NSStringFormatValueTypeKey</key>
NSStringFormatSpecTypeKey = NSStringPluralRuleType; <string>ld</string>
NSStringFormatValueTypeKey = ld; <key>zero</key>
one = "jeden Tag"; <string>alle Zeichen ausgewählt</string>
other = "alle %ld Tage"; <key>one</key>
zero = "nach jedem Entsperren"; <string>ein Zeichen übrig</string>
}; <key>other</key>
}; <string>%ld Zeichen übrig</string>
} </dict>
</dict>
<key>PICKED_%ld_CHARACTERS</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@characters@</string>
<key>characters</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>Kein Zeichen ausgewählt</string>
<key>one</key>
<string>%ld character picked</string>
<key>other</key>
<string>%ld characters picked</string>
</dict>
</dict>
<key>DUPLICATE_ENTRIES_%ld</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@entries@</string>
<key>entries</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>Eintrag duplizieren</string>
<key>other</key>
<string>Einträge duplizieren</string>
</dict>
</dict>
<key>EVERY_%ld_DAYS</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@days@</string>
<key>days</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>jeden Tag</string>
<key>other</key>
<string>alle %ld Tage</string>
<key>zero</key>
<string>nach jedem Entsperren</string>
</dict>
</dict>
</dict>
</plist>

View File

@@ -13,6 +13,9 @@
/* % Weeks ago */ /* % Weeks ago */
"%ld_WEEKS_AGO" = "%ld weeks ago"; "%ld_WEEKS_AGO" = "%ld weeks ago";
/* Count of characters remaining in Pickchars view */
"%ld_CHARACTERS_TO_PICK_REMAINING" = "%ld characters to pick remaining";
/* preset to expire after 90 days from now */ /* preset to expire after 90 days from now */
"90_DAYS" = "in 90 days"; "90_DAYS" = "in 90 days";
@@ -404,6 +407,12 @@
/* Menu item to perform autotype with the selected entry */ /* Menu item to perform autotype with the selected entry */
"PERFORM_AUTOTYPE_FOR_ENTRY" = "Perform Autotype"; "PERFORM_AUTOTYPE_FOR_ENTRY" = "Perform Autotype";
/* Count of picked characters in Pickchars view if no limit is set */
"PICKED_%ld_CHARACTERS" = "Picked %ld characters";
/* Comment */
"PICKCHAR_INFO_MESSAGE_PICK_CHARACTERS_%ld" = "Please pick %ld characters";
/* The plugin could not be initalized */ /* The plugin could not be initalized */
"PLUGIN_ERROR_INTILIZATION_FAILED" = "Plugin could not be initalized"; "PLUGIN_ERROR_INTILIZATION_FAILED" = "Plugin could not be initalized";

View File

@@ -1,22 +1,52 @@
{ {
"DUPLICATE_ENTRIES_%ld" = { "PICKCHAR_INFO_MESSAGE_PICK_CHARACTERS_%ld" = {
NSStringLocalizedFormatKey = "%#@entries@"; "NSStringLocalizedFormatKey" = "%#@characters@";
entries = { characters = {
NSStringFormatSpecTypeKey = NSStringPluralRuleType; "NSStringFormatSpecTypeKey" = "NSStringPluralRuleType";
NSStringFormatValueTypeKey = ld; "NSStringFormatValueTypeKey" = ld;
one = "Duplicate Entry"; zero = "Please pick character to use";
other = "Duplicate Entries"; one = "Please pick a single character to use";
zero = "Duplicate Entries"; other = "Pleas pick %ld characters to use";
}; };
}; };
"EVERY_%ld_DAYS" = { "%ld_CHARACTERS_TO_PICK_REMAINING" = {
NSStringLocalizedFormatKey = "%#@days@"; "NSStringLocalizedFormatKey" = "%#@characters@";
days = { characters = {
NSStringFormatSpecTypeKey = NSStringPluralRuleType; "NSStringFormatSpecTypeKey" = "NSStringPluralRuleType";
NSStringFormatValueTypeKey = ld; "NSStringFormatValueTypeKey" = ld;
one = "every day"; zero = "All characters picked";
other = "every %ld days"; one = "One character remaining";
zero = "after each unlock"; other = "%ld characters remaining";
}; };
}; };
"PICKED_%ld_CHARACTERS" = {
"NSStringLocalizedFormatKey" = "%#@characters@";
characters = {
"NSStringFormatSpecTypeKey" = "NSStringPluralRuleType";
"NSStringFormatValueTypeKey" = ld;
zero = "No characters picked";
one = "%ld character picked";
other = "%ld characters picked";
};
};
"DUPLICATE_ENTRIES_%ld" = {
"NSStringLocalizedFormatKey" = "%#@entries@";
entries = {
"NSStringFormatSpecTypeKey" = "NSStringPluralRuleType";
"NSStringFormatValueTypeKey" = ld;
zero = "Duplicate Entries";
one = "Duplicate Entry";
other = "Duplicate Entries";
};
};
"EVERY_%ld_DAYS" = {
"NSStringLocalizedFormatKey" = "%#@days@";
days = {
"NSStringFormatSpecTypeKey" = "NSStringPluralRuleType";
"NSStringFormatValueTypeKey" = ld;
zero = "after each unlock";
one = "every day";
other = "every %ld days";
};
};
} }

View File

@@ -0,0 +1,37 @@
//
// MPTestPickcharsParser.m
// MacPassTests
//
// Created by Michael Starke on 29.11.17.
// Copyright © 2017 HicknHack Software GmbH. All rights reserved.
//
#import <XCTest/XCTest.h>
#import "MPPickcharsParser.h"
@interface MPTestPickcharsParser : XCTestCase
@end
@implementation MPTestPickcharsParser
- (void)testValidOptionsParser {
MPPickcharsParser *parser = [[MPPickcharsParser alloc] initWithOptions:@"Count=10,Hide=false,Conv=D,Conv-Offset=11,Conv-Fmt=0?aA"];
XCTAssertEqual(10, parser.pickCount);
XCTAssertEqual(NO, parser.hideCharacters);
XCTAssertEqual(YES, parser.convertToDownArrows);
XCTAssertEqual(11, parser.checkboxOffset);
XCTAssertEqualObjects(@"0?aA", parser.checkboxFormat);
}
- (void)testInvalidOptionsParser {
MPPickcharsParser *parser = [[MPPickcharsParser alloc] initWithOptions:@"Count=-10,Hide=whatever,Con=D,Conv-Offset=20,Conv-Fmt=0A"];
XCTAssertEqual(0, parser.pickCount); // negative count will result in 0-count
XCTAssertEqual(YES, parser.hideCharacters); // option invalid, default is YES
XCTAssertEqual(NO, parser.convertToDownArrows); // option was invalid, default is NO
XCTAssertEqual(20, parser.checkboxOffset);
XCTAssertEqualObjects(@"0A", parser.checkboxFormat);
}
@end