1- // Copyright (c) 2019 - 2020 Apple Inc. Licensed under MIT License.
1+ // Copyright (c) 2019 - 2021 Apple Inc. Licensed under MIT License.
22// Adapted to typescript and Bitwarden by João Miguel P. Campos (github @mikibakaiki) for PassCert project.
33// npm package by João Miguel P. Campos (github @mikibakaiki) for PassCert project.
44
5+ import { PasswordBlocklist } from './data/passwordBlocklist' ;
56import { CustomCharacterData } from './data/customCharacterData' ;
6- import { CHARACTER_CLASS_END_SENTINEL , CHARACTER_CLASS_START_SENTINEL , Identifier , PROPERTY_SEPARATOR , PROPERTY_VALUE_SEPARATOR , PROPERTY_VALUE_START_SENTINEL , RuleName , SHOULD_NOT_BE_REACHED , SPACE_CODE_POINT } from './data/data.enum' ;
7+ import { BlockListIdentifier , CHARACTER_CLASS_END_SENTINEL , CHARACTER_CLASS_START_SENTINEL , Identifier , PROPERTY_SEPARATOR , PROPERTY_VALUE_SEPARATOR , PROPERTY_VALUE_START_SENTINEL , RuleName , SHOULD_NOT_BE_REACHED , SPACE_CODE_POINT } from './data/data.enum' ;
78import { NamedCharacterData } from './data/namedCharacterData' ;
89import { RuleData } from './data/ruleData' ;
910
11+
1012export class PasswordRulesParser {
1113
1214 /**
@@ -60,6 +62,9 @@ export class PasswordRulesParser {
6062 case RuleName . MIN_CLASSES :
6163 actualMinClasses = rule . value ;
6264 break ;
65+ case RuleName . BLOCK_LIST :
66+ newPasswordRules . push ( new RuleData ( RuleName . BLOCK_LIST , rule . value ) ) ;
67+
6368 }
6469 }
6570 newAllowedValues = this . _canonicalizedPropertyValues ( newAllowedValues , suppressCopyingRequiredToAllowed ) ;
@@ -81,13 +86,15 @@ export class PasswordRulesParser {
8186 if ( minimumMaxLength !== null ) {
8287 newPasswordRules . push ( new RuleData ( RuleName . MAX_LENGTH , minimumMaxLength ) ) ;
8388 }
89+
8490 if ( actualMinClasses >= 1 && actualMinClasses <= 4 ) {
8591 newPasswordRules . push ( new RuleData ( RuleName . MIN_CLASSES , actualMinClasses ) ) ;
8692 } else if ( actualMinClasses < 1 ) {
8793 newPasswordRules . push ( new RuleData ( RuleName . MIN_CLASSES , 1 ) ) ;
8894 } else {
8995 newPasswordRules . push ( new RuleData ( RuleName . MIN_CLASSES , 4 ) ) ;
9096 }
97+
9198 return newPasswordRules ;
9299 }
93100
@@ -381,6 +388,14 @@ export class PasswordRulesParser {
381388 return identifier && Object . values ( Identifier ) . includes ( identifier . toLowerCase ( ) ) ;
382389 }
383390
391+ /**
392+ * Check if the identifier is a valid one for the "blocklist" rule.
393+ * @param identifier The identifier to verify.
394+ * @returns True if it is a valid identifier. False if it is not a valid identifier.
395+ */
396+ private _isValidBlockListPropertyValueIdentifier ( identifier : string ) : boolean {
397+ return identifier && Object . values ( BlockListIdentifier ) . includes ( identifier . toLowerCase ( ) ) ;
398+ }
384399
385400 /**
386401 * Parse a custom character class. These classes are defined by the user and are surrounded by squared brackets ([]).
@@ -492,6 +507,35 @@ export class PasswordRulesParser {
492507 return [ propertyValues , position ] ;
493508 }
494509
510+ /**
511+ * Parse the values given to the rule "blocklist". If it's 'default', there is a list with the 100 000 most commonly used passwords.
512+ * @param input The string that contains the rules to be parsed.
513+ * @param position The position from where to start parsing the input.
514+ * @returns Returns an array with the information about the blocklist and the last position analyzed
515+ */
516+ private _parseBlockListPropertyValue ( input : string , position : number ) : [ string [ ] , number ] {
517+ let propertyValues = [ ] ;
518+ if ( this . _isIdentifierCharacter ( input [ position ] ) ) {
519+ let identifierStartPosition = position ;
520+ let [ propertyValue , index ] = this . _parseIdentifier ( input , position ) ;
521+ position = index ;
522+ if ( ! this . _isValidBlockListPropertyValueIdentifier ( propertyValue ) ) {
523+ console . error ( "Unrecognized property value identifier: " + propertyValue ) ;
524+ return [ null , identifierStartPosition ] ;
525+ }
526+ // TODO maybe here we can fetch the default word list and make this the value of the rule: an array of all the words
527+ if ( propertyValue === 'default' ) {
528+ const passwordBlocklist = PasswordBlocklist . getInstance ( ) ;
529+ passwordBlocklist . blocklist . forEach ( pw => {
530+ propertyValues . push ( pw ) ;
531+ } )
532+ } else {
533+ propertyValues . push ( propertyValue ) ;
534+ }
535+ }
536+ return [ propertyValues , position ] ;
537+ }
538+
495539 /**
496540 * Parse a password rule.
497541 * @param input The string that contains the rules to be parsed.
@@ -565,6 +609,14 @@ export class PasswordRulesParser {
565609 }
566610 return [ new RuleData ( property . name , property . propValue ) , position ] ;
567611 }
612+ case RuleName . BLOCK_LIST : {
613+ let [ blocklist , index ] = this . _parseBlockListPropertyValue ( input , position ) ;
614+ position = index ;
615+ if ( blocklist ) {
616+ property . propValue = blocklist ;
617+ }
618+ return [ new RuleData ( property . name , property . propValue ) , position ] ;
619+ }
568620 }
569621 console . assert ( false , SHOULD_NOT_BE_REACHED ) ;
570622 }
0 commit comments