mirror of
https://github.com/MacPass/MacPass.git
synced 2025-12-16 22:09:24 +00:00
Password generator now allows to require a character form each character group
This commit is contained in:
@@ -10,7 +10,7 @@
|
|||||||
<connections>
|
<connections>
|
||||||
<outlet property="customButton" destination="468" id="598"/>
|
<outlet property="customButton" destination="468" id="598"/>
|
||||||
<outlet property="customCharactersTextField" destination="411" id="479"/>
|
<outlet property="customCharactersTextField" destination="411" id="479"/>
|
||||||
<outlet property="ensureCharacterFromEachGroupButton" destination="RDM-JY-oF9" id="btK-Gf-vpP"/>
|
<outlet property="ensureOccuranceButton" destination="RDM-JY-oF9" id="btK-Gf-vpP"/>
|
||||||
<outlet property="entropyIndicator" destination="635" id="676"/>
|
<outlet property="entropyIndicator" destination="635" id="676"/>
|
||||||
<outlet property="entropyTextField" destination="652" id="675"/>
|
<outlet property="entropyTextField" destination="652" id="675"/>
|
||||||
<outlet property="lowerCaseButton" destination="456" id="593"/>
|
<outlet property="lowerCaseButton" destination="456" id="593"/>
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ typedef NS_ENUM(NSUInteger, MPPasswordRating) {
|
|||||||
@property (strong) IBOutlet NSButton *numbersButton;
|
@property (strong) IBOutlet NSButton *numbersButton;
|
||||||
@property (strong) IBOutlet NSButton *symbolsButton;
|
@property (strong) IBOutlet NSButton *symbolsButton;
|
||||||
@property (strong) IBOutlet NSButton *customButton;
|
@property (strong) IBOutlet NSButton *customButton;
|
||||||
@property (strong) IBOutlet NSButton *ensureCharacterFromEachGroupButton;
|
@property (strong) IBOutlet NSButton *ensureOccuranceButton;
|
||||||
@property (strong) IBOutlet NSButton *setDefaultButton;
|
@property (strong) IBOutlet NSButton *setDefaultButton;
|
||||||
@property (strong) IBOutlet NSTextField *entropyTextField;
|
@property (strong) IBOutlet NSTextField *entropyTextField;
|
||||||
@property (strong) IBOutlet NSLevelIndicator *entropyIndicator;
|
@property (strong) IBOutlet NSLevelIndicator *entropyIndicator;
|
||||||
@@ -76,7 +76,7 @@ typedef NS_ENUM(NSUInteger, MPPasswordRating) {
|
|||||||
|
|
||||||
@property (nonatomic, copy) NSString *customString;
|
@property (nonatomic, copy) NSString *customString;
|
||||||
@property (nonatomic, assign) BOOL useCustomString;
|
@property (nonatomic, assign) BOOL useCustomString;
|
||||||
@property (nonatomic, assign) BOOL useCharacterFromEachGroup;
|
@property (nonatomic, assign) BOOL ensureOccurance;
|
||||||
@property (nonatomic, assign) NSUInteger passwordLength;
|
@property (nonatomic, assign) NSUInteger passwordLength;
|
||||||
@property (nonatomic, assign) CGFloat entropy;
|
@property (nonatomic, assign) CGFloat entropy;
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ typedef NS_ENUM(NSUInteger, MPPasswordRating) {
|
|||||||
_entropy = 0.0;
|
_entropy = 0.0;
|
||||||
_useEntryDefaults = NO;
|
_useEntryDefaults = NO;
|
||||||
_allowsEntryDefaults = NO;
|
_allowsEntryDefaults = NO;
|
||||||
_useCharacterFromEachGroup = NO;
|
_ensureOccurance = NO;
|
||||||
[self _setupDefaults];
|
[self _setupDefaults];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
@@ -128,7 +128,7 @@ typedef NS_ENUM(NSUInteger, MPPasswordRating) {
|
|||||||
self.customCharactersTextField.delegate = self;
|
self.customCharactersTextField.delegate = self;
|
||||||
[self.customButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(useCustomString)) options:nil];
|
[self.customButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(useCustomString)) options:nil];
|
||||||
|
|
||||||
[self.ensureCharacterFromEachGroupButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(useCharacterFromEachGroup)) options:nil];
|
[self.ensureOccuranceButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(ensureOccurance)) options:nil];
|
||||||
|
|
||||||
NSString *copyToPasteBoardKeyPath = [MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyCopyGeneratedPasswordToClipboard];
|
NSString *copyToPasteBoardKeyPath = [MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyCopyGeneratedPasswordToClipboard];
|
||||||
NSUserDefaultsController *defaultsController = NSUserDefaultsController.sharedUserDefaultsController;
|
NSUserDefaultsController *defaultsController = NSUserDefaultsController.sharedUserDefaultsController;
|
||||||
@@ -171,7 +171,7 @@ typedef NS_ENUM(NSUInteger, MPPasswordRating) {
|
|||||||
- (IBAction)_generatePassword:(id)sender {
|
- (IBAction)_generatePassword:(id)sender {
|
||||||
self.password = [NSString passwordWithCharactersets:self.characterFlags
|
self.password = [NSString passwordWithCharactersets:self.characterFlags
|
||||||
withCustomCharacters:self._customCharacters
|
withCustomCharacters:self._customCharacters
|
||||||
ensureOccurence:self.useCharacterFromEachGroup
|
ensureOccurence:self.ensureOccurance
|
||||||
length:self.passwordLength];
|
length:self.passwordLength];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +228,7 @@ typedef NS_ENUM(NSUInteger, MPPasswordRating) {
|
|||||||
entryDefaults[kMPSettingsKeyPasswordCharacterFlags] = @(self.characterFlags);
|
entryDefaults[kMPSettingsKeyPasswordCharacterFlags] = @(self.characterFlags);
|
||||||
entryDefaults[kMPSettingsKeyPasswordUseCustomString] = @(self.useCustomString);
|
entryDefaults[kMPSettingsKeyPasswordUseCustomString] = @(self.useCustomString);
|
||||||
entryDefaults[kMPSettingsKeyPasswordCustomString] = self.customCharactersTextField.stringValue;
|
entryDefaults[kMPSettingsKeyPasswordCustomString] = self.customCharactersTextField.stringValue;
|
||||||
entryDefaults[kMPSettingsKeyPasswordEnsureOccurance] = @(self.useCharacterFromEachGroup);
|
entryDefaults[kMPSettingsKeyPasswordEnsureOccurance] = @(self.ensureOccurance);
|
||||||
NSMutableDictionary *availableDefaults = [[self _availableEntryDefaults] mutableCopy];
|
NSMutableDictionary *availableDefaults = [[self _availableEntryDefaults] mutableCopy];
|
||||||
if(!availableDefaults) {
|
if(!availableDefaults) {
|
||||||
availableDefaults = [[NSMutableDictionary alloc] initWithCapacity:1];
|
availableDefaults = [[NSMutableDictionary alloc] initWithCapacity:1];
|
||||||
@@ -284,7 +284,7 @@ typedef NS_ENUM(NSUInteger, MPPasswordRating) {
|
|||||||
if(![_password isEqualToString:password]) {
|
if(![_password isEqualToString:password]) {
|
||||||
_password = [password copy];
|
_password = [password copy];
|
||||||
NSString *customString = self.useCustomString ? self.customCharactersTextField.stringValue : nil;
|
NSString *customString = self.useCustomString ? self.customCharactersTextField.stringValue : nil;
|
||||||
self.entropy = [password entropyWhithPossibleCharacterSet:self.characterFlags andCustomCharacters:customString];
|
self.entropy = [password entropyWhithCharacterSet:self.characterFlags customCharacters:customString ensureOccurance:self.ensureOccurance];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,9 +305,9 @@ typedef NS_ENUM(NSUInteger, MPPasswordRating) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setUseCharacterFromEachGroup:(BOOL)useCharacterFromEachGroup {
|
- (void)setEnsureOccurance:(BOOL)useCharacterFromEachGroup {
|
||||||
if(self.useCharacterFromEachGroup != useCharacterFromEachGroup) {
|
if(self.ensureOccurance != useCharacterFromEachGroup) {
|
||||||
_useCharacterFromEachGroup = useCharacterFromEachGroup;
|
_ensureOccurance = useCharacterFromEachGroup;
|
||||||
[self _resetCharacters];
|
[self _resetCharacters];
|
||||||
[self _generatePassword:nil];
|
[self _generatePassword:nil];
|
||||||
}
|
}
|
||||||
@@ -356,14 +356,14 @@ typedef NS_ENUM(NSUInteger, MPPasswordRating) {
|
|||||||
self.characterFlags = [entryDefaults[kMPSettingsKeyPasswordCharacterFlags] integerValue];
|
self.characterFlags = [entryDefaults[kMPSettingsKeyPasswordCharacterFlags] integerValue];
|
||||||
self.useCustomString = [entryDefaults[kMPSettingsKeyPasswordUseCustomString] boolValue];
|
self.useCustomString = [entryDefaults[kMPSettingsKeyPasswordUseCustomString] boolValue];
|
||||||
self.customString = entryDefaults[kMPSettingsKeyPasswordCustomString];
|
self.customString = entryDefaults[kMPSettingsKeyPasswordCustomString];
|
||||||
self.useCharacterFromEachGroup = [entryDefaults[kMPSettingsKeyPasswordEnsureOccurance] boolValue];
|
self.ensureOccurance = [entryDefaults[kMPSettingsKeyPasswordEnsureOccurance] boolValue];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self.passwordLength = [NSUserDefaults.standardUserDefaults integerForKey:kMPSettingsKeyDefaultPasswordLength];
|
self.passwordLength = [NSUserDefaults.standardUserDefaults integerForKey:kMPSettingsKeyDefaultPasswordLength];
|
||||||
self.characterFlags = [NSUserDefaults.standardUserDefaults integerForKey:kMPSettingsKeyPasswordCharacterFlags];
|
self.characterFlags = [NSUserDefaults.standardUserDefaults integerForKey:kMPSettingsKeyPasswordCharacterFlags];
|
||||||
self.useCustomString = [NSUserDefaults.standardUserDefaults boolForKey:kMPSettingsKeyPasswordUseCustomString];
|
self.useCustomString = [NSUserDefaults.standardUserDefaults boolForKey:kMPSettingsKeyPasswordUseCustomString];
|
||||||
self.customString = [NSUserDefaults.standardUserDefaults stringForKey:kMPSettingsKeyPasswordCustomString];
|
self.customString = [NSUserDefaults.standardUserDefaults stringForKey:kMPSettingsKeyPasswordCustomString];
|
||||||
self.useCharacterFromEachGroup = [NSUserDefaults.standardUserDefaults boolForKey:kMPSettingsKeyPasswordEnsureOccurance];
|
self.ensureOccurance = [NSUserDefaults.standardUserDefaults boolForKey:kMPSettingsKeyPasswordEnsureOccurance];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,19 +393,8 @@ typedef NS_ENUM(NSUInteger, MPPasswordRating) {
|
|||||||
self.symbolsButton.state = (useSymbols ? NSOnState : NSOffState);
|
self.symbolsButton.state = (useSymbols ? NSOnState : NSOffState);
|
||||||
|
|
||||||
// ensure minimum character lenght
|
// ensure minimum character lenght
|
||||||
if(self.useCharacterFromEachGroup) {
|
if(self.ensureOccurance) {
|
||||||
NSUInteger minimumPasswordLength = 0;
|
|
||||||
NSUInteger activeFlags = self.characterFlags;
|
|
||||||
while(activeFlags > 0) {
|
|
||||||
if(activeFlags & 1) {
|
|
||||||
minimumPasswordLength++;
|
|
||||||
}
|
|
||||||
activeFlags >>= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(self.passwordLength < minimumPasswordLength) {
|
|
||||||
self.passwordLength = minimumPasswordLength;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ typedef NS_OPTIONS(NSUInteger, MPPasswordCharacterFlags) {
|
|||||||
|
|
||||||
+ (NSString *)passwordWithDefaultSettings;
|
+ (NSString *)passwordWithDefaultSettings;
|
||||||
|
|
||||||
|
+ (NSUInteger)minimumPasswordLengthWithCharacterSet:(MPPasswordCharacterFlags)characterSet customCharacters:(NSString *)customCharacter ensureOccurance:(BOOL)ensureOccurance;
|
||||||
/**
|
/**
|
||||||
* @return returns a random character from the string
|
* @return returns a random character from the string
|
||||||
*/
|
*/
|
||||||
@@ -84,6 +85,6 @@ typedef NS_OPTIONS(NSUInteger, MPPasswordCharacterFlags) {
|
|||||||
*
|
*
|
||||||
* @return entropy of the receiver as bits
|
* @return entropy of the receiver as bits
|
||||||
*/
|
*/
|
||||||
- (CGFloat)entropyWhithPossibleCharacterSet:(MPPasswordCharacterFlags)allowedCharacters andCustomCharacters:(NSString *)customCharacters;
|
- (CGFloat)entropyWhithCharacterSet:(MPPasswordCharacterFlags)characterSet customCharacters:(NSString *)customCharacters ensureOccurance:(BOOL)ensureOccurance;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -26,23 +26,32 @@
|
|||||||
#import "NSString+MPComposedCharacterAdditions.h"
|
#import "NSString+MPComposedCharacterAdditions.h"
|
||||||
#import "MPSettingsHelper.h"
|
#import "MPSettingsHelper.h"
|
||||||
|
|
||||||
NSString *const kMPLowercaseLetterCharacters = @"abcdefghijklmnopqrstuvwxyz";
|
static NSDictionary<NSNumber *, NSString *> *characterClassMap () {
|
||||||
NSString *const kMPNumberCharacters = @"1234567890";
|
static dispatch_once_t onceToken;
|
||||||
NSString *const kMPSymbolCharacters = @"!$%&\\|/<>(){}[]=?*'+#-_.:,;";
|
static NSDictionary *characterClassMap;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
characterClassMap = @{ @(MPPasswordCharactersLowerCase) : @"abcdefghijklmnopqrstuvwxyz",
|
||||||
|
@(MPPasswordCharactersUpperCase) : @"abcdefghijklmnopqrstuvwxyz".uppercaseString,
|
||||||
|
@(MPPasswordCharactersNumbers) : @"1234567890",
|
||||||
|
@(MPPasswordCharactersSymbols) : @"!$%&\\|/<>(){}[]=?*'+#-_.:,;"
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return characterClassMap;
|
||||||
|
}
|
||||||
|
|
||||||
static NSString *allowedCharactersString(MPPasswordCharacterFlags flags) {
|
static NSString *allowedCharactersString(MPPasswordCharacterFlags flags) {
|
||||||
NSMutableString *characterString = [NSMutableString stringWithCapacity:30];
|
NSMutableString *characterString = [NSMutableString stringWithCapacity:30];
|
||||||
if(flags & MPPasswordCharactersLowerCase) {
|
if(flags & MPPasswordCharactersLowerCase) {
|
||||||
[characterString appendString:kMPLowercaseLetterCharacters];
|
[characterString appendString:characterClassMap()[@(MPPasswordCharactersLowerCase)]];
|
||||||
}
|
}
|
||||||
if(flags & MPPasswordCharactersUpperCase) {
|
if(flags & MPPasswordCharactersUpperCase) {
|
||||||
[characterString appendString:kMPLowercaseLetterCharacters.uppercaseString];
|
[characterString appendString:characterClassMap()[@(MPPasswordCharactersUpperCase)]];
|
||||||
}
|
}
|
||||||
if(flags & MPPasswordCharactersNumbers) {
|
if(flags & MPPasswordCharactersNumbers) {
|
||||||
[characterString appendString:kMPNumberCharacters];
|
[characterString appendString:characterClassMap()[@(MPPasswordCharactersNumbers)]];
|
||||||
}
|
}
|
||||||
if(flags & MPPasswordCharactersSymbols){
|
if(flags & MPPasswordCharactersSymbols){
|
||||||
[characterString appendString:kMPSymbolCharacters];
|
[characterString appendString:characterClassMap()[@(MPPasswordCharactersSymbols)]];
|
||||||
}
|
}
|
||||||
return characterString;
|
return characterString;
|
||||||
}
|
}
|
||||||
@@ -74,10 +83,30 @@ static NSString *mergeWithoutDuplicates(NSString* baseCharacters, NSString* cust
|
|||||||
withCustomCharacters:(NSString *)customCharacters
|
withCustomCharacters:(NSString *)customCharacters
|
||||||
ensureOccurence:(BOOL)ensureOccurence
|
ensureOccurence:(BOOL)ensureOccurence
|
||||||
length:(NSUInteger)length {
|
length:(NSUInteger)length {
|
||||||
|
if(ensureOccurence) {
|
||||||
|
length = MAX(length, [NSString minimumPasswordLengthWithCharacterSet:allowedCharacters customCharacters:customCharacters ensureOccurance:ensureOccurence]);
|
||||||
|
}
|
||||||
NSMutableString *password = [NSMutableString stringWithCapacity:length];
|
NSMutableString *password = [NSMutableString stringWithCapacity:length];
|
||||||
NSString *characters = mergeWithoutDuplicates(
|
NSString *characters = mergeWithoutDuplicates(
|
||||||
allowedCharactersString(allowedCharacters),
|
allowedCharactersString(allowedCharacters),
|
||||||
customCharacters);
|
customCharacters);
|
||||||
|
if(ensureOccurence) {
|
||||||
|
if(allowedCharacters & MPPasswordCharactersLowerCase) {
|
||||||
|
[password appendString:characterClassMap()[@(MPPasswordCharactersLowerCase)].randomCharacter];
|
||||||
|
}
|
||||||
|
if(allowedCharacters & MPPasswordCharactersUpperCase) {
|
||||||
|
[password appendString:characterClassMap()[@(MPPasswordCharactersUpperCase)].randomCharacter];
|
||||||
|
}
|
||||||
|
if(allowedCharacters & MPPasswordCharactersNumbers) {
|
||||||
|
[password appendString:characterClassMap()[@(MPPasswordCharactersNumbers)].randomCharacter];
|
||||||
|
}
|
||||||
|
if(allowedCharacters & MPPasswordCharactersSymbols){
|
||||||
|
[password appendString:characterClassMap()[@(MPPasswordCharactersSymbols)].randomCharacter];
|
||||||
|
}
|
||||||
|
if(customCharacters.length > 0) {
|
||||||
|
[password appendString:customCharacters.randomCharacter];
|
||||||
|
}
|
||||||
|
}
|
||||||
while(password.composedCharacterLength < length) {
|
while(password.composedCharacterLength < length) {
|
||||||
NSString *randomCharacter = characters.randomCharacter;
|
NSString *randomCharacter = characters.randomCharacter;
|
||||||
if(randomCharacter.length > 0) {
|
if(randomCharacter.length > 0) {
|
||||||
@@ -87,7 +116,7 @@ static NSString *mergeWithoutDuplicates(NSString* baseCharacters, NSString* cust
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return password;
|
return ensureOccurence ? password.shuffledString : password;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSString *)passwordWithDefaultSettings {
|
+ (NSString *)passwordWithDefaultSettings {
|
||||||
@@ -103,6 +132,21 @@ static NSString *mergeWithoutDuplicates(NSString* baseCharacters, NSString* cust
|
|||||||
return [NSString passwordWithCharactersets:characterFlags withCustomCharacters:@"" ensureOccurence:NO length:passwordLength];
|
return [NSString passwordWithCharactersets:characterFlags withCustomCharacters:@"" ensureOccurence:NO length:passwordLength];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (NSUInteger)minimumPasswordLengthWithCharacterSet:(MPPasswordCharacterFlags)characterSet customCharacters:(NSString *)customCharacter ensureOccurance:(BOOL)ensureOccurance {
|
||||||
|
NSUInteger minimumPasswordLength = 0;
|
||||||
|
NSUInteger activeFlags = characterSet;
|
||||||
|
while(activeFlags > 0) {
|
||||||
|
if(activeFlags & 1) {
|
||||||
|
minimumPasswordLength++;
|
||||||
|
}
|
||||||
|
activeFlags >>= 1;
|
||||||
|
}
|
||||||
|
if(customCharacter.length > 0) {
|
||||||
|
minimumPasswordLength++;
|
||||||
|
}
|
||||||
|
return minimumPasswordLength;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSString *)passwordWithLength:(NSUInteger)length {
|
- (NSString *)passwordWithLength:(NSUInteger)length {
|
||||||
return [NSString passwordFromString:self length:length];
|
return [NSString passwordFromString:self length:length];
|
||||||
}
|
}
|
||||||
@@ -114,12 +158,18 @@ static NSString *mergeWithoutDuplicates(NSString* baseCharacters, NSString* cust
|
|||||||
return [self composedCharacterAtIndex:arc4random_uniform((int)self.composedCharacterLength)];
|
return [self composedCharacterAtIndex:arc4random_uniform((int)self.composedCharacterLength)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGFloat)entropyWhithPossibleCharacterSet:(MPPasswordCharacterFlags)allowedCharacters andCustomCharacters:(NSString *)customCharacters {
|
|
||||||
NSString *characters = nil;
|
- (CGFloat)entropyWhithCharacterSet:(MPPasswordCharacterFlags)characterSet customCharacters:(NSString *)customCharacters ensureOccurance:(BOOL)ensureOccurance {
|
||||||
characters = mergeWithoutDuplicates(allowedCharactersString(allowedCharacters), customCharacters);
|
if(ensureOccurance) {
|
||||||
CGFloat alphabetCount = characters.composedCharacterLength;
|
return 0;
|
||||||
CGFloat passwordLength = self.composedCharacterLength;
|
}
|
||||||
return passwordLength * ( log10(alphabetCount) / log10(2) );
|
else {
|
||||||
|
NSString *characters = nil;
|
||||||
|
characters = mergeWithoutDuplicates(allowedCharactersString(characterSet), customCharacters);
|
||||||
|
CGFloat alphabetCount = characters.composedCharacterLength;
|
||||||
|
CGFloat passwordLength = self.composedCharacterLength;
|
||||||
|
return passwordLength * ( log10(alphabetCount) / log10(2) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)shuffledString {
|
- (NSString *)shuffledString {
|
||||||
|
|||||||
Reference in New Issue
Block a user