-
Notifications
You must be signed in to change notification settings - Fork 446
Expand file tree
/
Copy pathcomplexity.ts
More file actions
80 lines (69 loc) · 2.29 KB
/
complexity.ts
File metadata and controls
80 lines (69 loc) · 2.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import type { PasswordSettingsData } from '../../../types';
export type ComplexityErrors = {
[key in keyof Partial<Omit<PasswordSettingsData, 'disable_hibp' | 'min_zxcvbn_strength' | 'show_zxcvbn'>>]?: boolean;
};
export type UsePasswordComplexityConfig = Omit<
PasswordSettingsData,
'disable_hibp' | 'min_zxcvbn_strength' | 'show_zxcvbn'
>;
const createTestComplexityCases = (config: Pick<UsePasswordComplexityConfig, 'allowed_special_characters'>) => {
let specialCharsRegex: RegExp;
if (config.allowed_special_characters) {
// Avoid a nested group by escaping the `[]` characters
let escaped = config.allowed_special_characters.replace('[', '\\[');
escaped = escaped.replace(']', '\\]');
specialCharsRegex = new RegExp(`[${escaped}]`);
} else {
specialCharsRegex = /[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]/;
}
return (
password: string,
{
minLength,
maxLength,
}: {
minLength: number;
maxLength: number;
},
) => {
return {
max_length: password.length < maxLength,
min_length: password.length >= minLength,
require_numbers: /\d/.test(password),
require_lowercase: /[a-z]/.test(password),
require_uppercase: /[A-Z]/.test(password),
require_special_char: specialCharsRegex.test(password),
};
};
};
export const validate = (password: string, config: UsePasswordComplexityConfig): ComplexityErrors => {
const { max_length, min_length, require_special_char, require_lowercase, require_numbers, require_uppercase } =
config;
const testComplexityCases = createTestComplexityCases(config);
const testCases = testComplexityCases(password, {
maxLength: config.max_length,
minLength: config.min_length,
});
const keys = {
max_length,
min_length,
require_special_char,
require_lowercase,
require_numbers,
require_uppercase,
};
const _validationsFailedMap = new Map();
for (const k in keys) {
const key = k as keyof typeof keys;
if (!keys[key]) {
continue;
}
if (!testCases[key]) {
_validationsFailedMap.set(key, true);
}
}
return Object.freeze(Object.fromEntries(_validationsFailedMap));
};
export const createValidateComplexity = (config: UsePasswordComplexityConfig) => {
return (password: string) => validate(password, config);
};