Password Generator Sanitize Length (#89)

* Initial commit for length sanitization

* Updated sanitize function

* Updated type instantiation

Co-authored-by: Vincent Salucci <vsalucci@bitwarden.com>
This commit is contained in:
Vincent Salucci 2020-03-18 10:07:57 -05:00 committed by GitHub
parent 0a30c7eb1e
commit 3ad546c39f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 113 additions and 80 deletions

View File

@ -12,4 +12,5 @@ export abstract class PasswordGenerationService {
addHistory: (password: string) => Promise<any>;
clear: () => Promise<any>;
passwordStrength: (password: string, userInputs?: string[]) => zxcvbn.ZXCVBNResult;
normalizeOptions: (options: any, enforcedPolicyOptions: PasswordGeneratorPolicyOptions) => void;
}

View File

@ -80,8 +80,7 @@ export class PasswordGeneratorComponent implements OnInit {
}
private normalizeOptions() {
this.options.minLowercase = 0;
this.options.minUppercase = 0;
// Application level normalize options depedent on class variables
this.options.ambiguous = !this.avoidAmbiguous;
if (!this.options.uppercase && !this.options.lowercase && !this.options.number && !this.options.special) {
@ -94,56 +93,6 @@ export class PasswordGeneratorComponent implements OnInit {
}
}
if (!this.options.length || this.options.length < 5) {
this.options.length = 5;
} else if (this.options.length > 128) {
this.options.length = 128;
}
if (this.options.length < this.enforcedPolicyOptions.minLength) {
this.options.length = this.enforcedPolicyOptions.minLength;
}
if (!this.options.minNumber) {
this.options.minNumber = 0;
} else if (this.options.minNumber > this.options.length) {
this.options.minNumber = this.options.length;
} else if (this.options.minNumber > 9) {
this.options.minNumber = 9;
}
if (this.options.minNumber < this.enforcedPolicyOptions.numberCount) {
this.options.minNumber = this.enforcedPolicyOptions.numberCount;
}
if (!this.options.minSpecial) {
this.options.minSpecial = 0;
} else if (this.options.minSpecial > this.options.length) {
this.options.minSpecial = this.options.length;
} else if (this.options.minSpecial > 9) {
this.options.minSpecial = 9;
}
if (this.options.minSpecial < this.enforcedPolicyOptions.specialCount) {
this.options.minSpecial = this.enforcedPolicyOptions.specialCount;
}
if (this.options.minSpecial + this.options.minNumber > this.options.length) {
this.options.minSpecial = this.options.length - this.options.minNumber;
}
if (this.options.numWords == null || this.options.length < 3) {
this.options.numWords = 3;
} else if (this.options.numWords > 20) {
this.options.numWords = 20;
}
if (this.options.numWords < this.enforcedPolicyOptions.minNumberWords) {
this.options.numWords = this.enforcedPolicyOptions.minNumberWords;
}
if (this.options.wordSeparator != null && this.options.wordSeparator.length > 1) {
this.options.wordSeparator = this.options.wordSeparator[0];
}
this.passwordGenerationService.normalizeOptions(this.options, this.enforcedPolicyOptions);
}
}

View File

@ -57,33 +57,7 @@ export class PasswordGenerationService implements PasswordGenerationServiceAbstr
}
// sanitize
if (o.uppercase && o.minUppercase <= 0) {
o.minUppercase = 1;
} else if (!o.uppercase) {
o.minUppercase = 0;
}
if (o.lowercase && o.minLowercase <= 0) {
o.minLowercase = 1;
} else if (!o.lowercase) {
o.minLowercase = 0;
}
if (o.number && o.minNumber <= 0) {
o.minNumber = 1;
} else if (!o.number) {
o.minNumber = 0;
}
if (o.special && o.minSpecial <= 0) {
o.minSpecial = 1;
} else if (!o.special) {
o.minSpecial = 0;
}
if (!o.length || o.length < 1) {
o.length = 10;
}
this.sanitizePasswordLength(o, true);
const minLength: number = o.minUppercase + o.minLowercase + o.minNumber + o.minSpecial;
if (o.length < minLength) {
@ -419,6 +393,65 @@ export class PasswordGenerationService implements PasswordGenerationServiceAbstr
return result;
}
normalizeOptions(options: any, enforcedPolicyOptions: PasswordGeneratorPolicyOptions) {
options.minLowercase = 0;
options.minUppercase = 0;
if (!options.length || options.length < 5) {
options.length = 5;
} else if (options.length > 128) {
options.length = 128;
}
if (options.length < enforcedPolicyOptions.minLength) {
options.length = enforcedPolicyOptions.minLength;
}
if (!options.minNumber) {
options.minNumber = 0;
} else if (options.minNumber > options.length) {
options.minNumber = options.length;
} else if (options.minNumber > 9) {
options.minNumber = 9;
}
if (options.minNumber < enforcedPolicyOptions.numberCount) {
options.minNumber = enforcedPolicyOptions.numberCount;
}
if (!options.minSpecial) {
options.minSpecial = 0;
} else if (options.minSpecial > options.length) {
options.minSpecial = options.length;
} else if (options.minSpecial > 9) {
options.minSpecial = 9;
}
if (options.minSpecial < enforcedPolicyOptions.specialCount) {
options.minSpecial = enforcedPolicyOptions.specialCount;
}
if (options.minSpecial + options.minNumber > options.length) {
options.minSpecial = options.length - options.minNumber;
}
if (options.numWords == null || options.length < 3) {
options.numWords = 3;
} else if (options.numWords > 20) {
options.numWords = 20;
}
if (options.numWords < enforcedPolicyOptions.minNumberWords) {
options.numWords = enforcedPolicyOptions.minNumberWords;
}
if (options.wordSeparator != null && options.wordSeparator.length > 1) {
options.wordSeparator = options.wordSeparator[0];
}
this.sanitizePasswordLength(options, false);
}
private capitalize(str: string) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
@ -473,4 +506,54 @@ export class PasswordGenerationService implements PasswordGenerationServiceAbstr
[array[i], array[j]] = [array[j], array[i]];
}
}
private sanitizePasswordLength(options: any, forGeneration: boolean) {
let minUppercaseCalc = 0;
let minLowercaseCalc = 0;
let minNumberCalc: number = options.minNumber;
let minSpecialCalc: number = options.minSpecial;
if (options.uppercase && options.minUppercase <= 0) {
minUppercaseCalc = 1;
} else if (!options.uppercase) {
minUppercaseCalc = 0;
}
if (options.lowercase && options.minLowercase <= 0) {
minLowercaseCalc = 1;
} else if (!options.lowercase) {
minLowercaseCalc = 0;
}
if (options.number && options.minNumber <= 0) {
minNumberCalc = 1;
} else if (!options.number) {
minNumberCalc = 0;
}
if (options.special && options.minSpecial <= 0) {
minSpecialCalc = 1;
} else if (!options.special) {
minSpecialCalc = 0;
}
// This should never happen but is a final safety net
if (!options.length || options.length < 1) {
options.length = 10;
}
const minLength: number = minUppercaseCalc + minLowercaseCalc + minNumberCalc + minSpecialCalc;
// Normalize and Generation both require this modification
if (options.length < minLength) {
options.length = minLength;
}
// Apply other changes if the options object passed in is for generation
if (forGeneration) {
options.minUppercase = minUppercaseCalc;
options.minLowercase = minLowercaseCalc;
options.minNumber = minNumberCalc;
options.minSpecial = minSpecialCalc;
}
}
}