@@ -14,87 +14,92 @@ const random = (min: number, max: number): number => {
1414} ;
1515
1616const genPassword = (
17- length : number = 32 ,
18- useLowercase : boolean = true ,
19- useUppercase : boolean = false ,
20- useDigits : boolean = false ,
21- useSpecial : boolean = false ,
22- excludeAmbiguous : boolean = false
17+ length : number = 32 ,
18+ useLowercase : boolean = true ,
19+ useUppercase : boolean = false ,
20+ useDigits : boolean = false ,
21+ useSpecial : boolean = false ,
22+ excludeAmbiguous : boolean = false
2323) : string => {
24- // Define ambiguous characters to exclude
25- // 0O (zero/O), 1lI (one/l/I), 5S (five/S), 8B (eight/B), 2Z (two/Z), 6b (six/b), 9q (nine/q)
26- const ambiguousChars = '0O1lIo5S8B2Z6b9q' ;
27-
28- // Filter character sets if excludeAmbiguous is enabled
29- const filterAmbiguous = ( chars : string ) : string => {
30- if ( ! excludeAmbiguous ) return chars ;
31- return chars . split ( '' ) . filter ( char => ! ambiguousChars . includes ( char ) ) . join ( '' ) ;
32- } ;
33-
34- const charSets : string [ ] = [ ] ;
35- let charPool = '' ;
36-
37- if ( useLowercase ) {
38- const filteredLowercase = filterAmbiguous ( lowercase ) ;
39- if ( filteredLowercase . length > 0 ) {
40- charSets . push ( filteredLowercase ) ;
41- charPool += filteredLowercase ;
42- }
24+ // Define ambiguous characters to exclude
25+ // 0O (zero/O), 1lI (one/l/I), 5S (five/S), 8B (eight/B), 2Z (two/Z), 6b (six/b), 9q (nine/q)
26+ const ambiguousChars = '0O1lIo5S8B2Z6b9q' ;
27+
28+ // Filter character sets if excludeAmbiguous is enabled
29+ const filterAmbiguous = ( chars : string ) : string => {
30+ if ( ! excludeAmbiguous ) return chars ;
31+ return chars
32+ . split ( '' )
33+ . filter ( ( char ) => ! ambiguousChars . includes ( char ) )
34+ . join ( '' ) ;
35+ } ;
36+
37+ const charSets : string [ ] = [ ] ;
38+ let charPool = '' ;
39+
40+ if ( useLowercase ) {
41+ const filteredLowercase = filterAmbiguous ( lowercase ) ;
42+ if ( filteredLowercase . length > 0 ) {
43+ charSets . push ( filteredLowercase ) ;
44+ charPool += filteredLowercase ;
4345 }
46+ }
4447
45- if ( useUppercase ) {
46- const filteredUppercase = filterAmbiguous ( uppercase ) ;
47- if ( filteredUppercase . length > 0 ) {
48- charSets . push ( filteredUppercase ) ;
49- charPool += filteredUppercase ;
50- }
48+ if ( useUppercase ) {
49+ const filteredUppercase = filterAmbiguous ( uppercase ) ;
50+ if ( filteredUppercase . length > 0 ) {
51+ charSets . push ( filteredUppercase ) ;
52+ charPool += filteredUppercase ;
5153 }
54+ }
5255
53- if ( useDigits ) {
54- const filteredDigits = filterAmbiguous ( digits ) ;
55- if ( filteredDigits . length > 0 ) {
56- charSets . push ( filteredDigits ) ;
57- charPool += filteredDigits ;
58- }
56+ if ( useDigits ) {
57+ const filteredDigits = filterAmbiguous ( digits ) ;
58+ if ( filteredDigits . length > 0 ) {
59+ charSets . push ( filteredDigits ) ;
60+ charPool += filteredDigits ;
5961 }
62+ }
6063
61- if ( useSpecial ) {
62- const filteredSpecial = filterAmbiguous ( special ) ;
63- if ( filteredSpecial . length > 0 ) {
64- charSets . push ( filteredSpecial ) ;
65- charPool += filteredSpecial ;
66- }
64+ if ( useSpecial ) {
65+ const filteredSpecial = filterAmbiguous ( special ) ;
66+ if ( filteredSpecial . length > 0 ) {
67+ charSets . push ( filteredSpecial ) ;
68+ charPool += filteredSpecial ;
6769 }
68-
69- if ( charPool . length === 0 ) {
70- throw new Error ( 'At least one character type must be selected' ) ;
71- }
72-
73- if ( length < charSets . length ) {
74- throw new Error ( `Password length must be at least ${ charSets . length } to include all selected character types` ) ;
75- }
76-
77- const result : string [ ] = [ ] ;
78-
79- // Step 1: Guarantee at least one character from each selected set
80- for ( const set of charSets ) {
81- const randomIndex = random ( 0 , set . length ) ;
82- result . push ( set [ randomIndex ] ) ;
83- }
84-
85- // Step 2: Fill remaining positions with random characters from the full pool
86- for ( let i = charSets . length ; i < length ; i ++ ) {
87- const randomIndex = random ( 0 , charPool . length ) ;
88- result . push ( charPool [ randomIndex ] ) ;
89- }
90-
91- // Step 3: Shuffle to avoid predictable patterns (e.g., always lowercase first)
92- for ( let i = result . length - 1 ; i > 0 ; i -- ) {
93- const j = random ( 0 , i + 1 ) ;
94- [ result [ i ] , result [ j ] ] = [ result [ j ] , result [ i ] ] ;
95- }
96-
97- return result . join ( '' ) ;
98- }
70+ }
71+
72+ if ( charPool . length === 0 ) {
73+ throw new Error ( 'At least one character type must be selected' ) ;
74+ }
75+
76+ if ( length < charSets . length ) {
77+ throw new Error (
78+ `Password length must be at least ${ charSets . length } to include all selected character types`
79+ ) ;
80+ }
81+
82+ const result : string [ ] = [ ] ;
83+
84+ // Step 1: Guarantee at least one character from each selected set
85+ for ( const set of charSets ) {
86+ const randomIndex = random ( 0 , set . length ) ;
87+ result . push ( set [ randomIndex ] ) ;
88+ }
89+
90+ // Step 2: Fill remaining positions with random characters from the full pool
91+ for ( let i = charSets . length ; i < length ; i ++ ) {
92+ const randomIndex = random ( 0 , charPool . length ) ;
93+ result . push ( charPool [ randomIndex ] ) ;
94+ }
95+
96+ // Step 3: Shuffle to avoid predictable patterns (e.g., always lowercase first)
97+ for ( let i = result . length - 1 ; i > 0 ; i -- ) {
98+ const j = random ( 0 , i + 1 ) ;
99+ [ result [ i ] , result [ j ] ] = [ result [ j ] , result [ i ] ] ;
100+ }
101+
102+ return result . join ( '' ) ;
103+ } ;
99104
100105export default genPassword ;
0 commit comments