Skip to content

Commit 08eb3ce

Browse files
committed
feat: add password strength tester with customizable options and update tests
1 parent 286f607 commit 08eb3ce

5 files changed

+121
-128
lines changed

index.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ import isValidPdf from "./src/isValidPdf";
3333
import isValidVideo from "./src/isValidVideo";
3434
import isValidTxt from "./src/isValidTxt";
3535
import type { ValidateFunctions, IsValidFunctions } from "./src/types";
36+
import type {
37+
PasswordStrengthTesterOptions,
38+
PasswordStrengthFunction,
39+
PasswordStrengthType,
40+
} from "./src/passwordStrengthTester";
3641

3742
export {
3843
cpfIsValid,
@@ -108,4 +113,10 @@ export default {
108113
isValidTxt,
109114
};
110115

111-
export type { ValidateFunctions, IsValidFunctions };
116+
export type {
117+
ValidateFunctions,
118+
IsValidFunctions,
119+
PasswordStrengthTesterOptions,
120+
PasswordStrengthFunction,
121+
PasswordStrengthType,
122+
};

src/passwordStrengthTester.ts

Lines changed: 58 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,90 @@
1+
export type PasswordStrengthType =
2+
| "Very weak"
3+
| "Weak"
4+
| "Regular"
5+
| "Strong"
6+
| "Very strong"
7+
| "Not classified";
8+
9+
export type PasswordStrengthFunction = (
10+
password: string,
11+
passwordLength: number,
12+
) => boolean;
13+
14+
export interface PasswordStrengthTesterOptions {
15+
isVeryWeak: PasswordStrengthFunction;
16+
isWeak: PasswordStrengthFunction;
17+
isRegular: PasswordStrengthFunction;
18+
isStrong: PasswordStrengthFunction;
19+
isVeryStrong: PasswordStrengthFunction;
20+
}
21+
122
/**
2-
* @description Avalia a força de uma senha e retorna o tipo de força da senha.
3-
*
4-
* @returns O tipo de força da senha ('veryWeak', 'weak', 'regular', 'strong' ou 'veryStrong').
5-
*
6-
* @example
7-
* passwordStrengthTester('12345'); // Output: 'veryWeak'
8-
*
9-
* @example
10-
* passwordStrengthTester('abcdef'); // Output: 'weak'
23+
* @param password - The password to test
24+
* @param Options - An object containing functions to test the password strength
25+
* @param Options.isVeryWeak - A function to test if the password is very weak
26+
* @param Options.isWeak - A function to test if the password is weak
27+
* @param Options.isRegular - A function to test if the password is regular
28+
* @param Options.isStrong - A function to test if the password is strong
29+
* @param Options.isVeryStrong - A function to test if the password is very strong
30+
* @throws {TypeError} - If the input is not a string
1131
*
1232
* @example
13-
* passwordStrengthTester('abc12345'); // Output: 'regular'
33+
* const options = {
34+
* isVeryWeak: (password, passwordLength) => passwordLength < 6,
35+
* isWeak: (password, passwordLength) => passwordLength < 8,
36+
* isRegular: (password, passwordLength) => passwordLength < 10,
37+
* isStrong: (password, passwordLength) => passwordLength < 12,
38+
* isVeryStrong: (password, passwordLength) => passwordLength >= 12,
39+
* }
1440
*
15-
* @example
16-
* passwordStrengthTester('Abc123awdasd'); // Output: 'strong'
17-
*
18-
* @example
19-
* passwordStrengthTester('SuperSecurePassword123!@'); // Output: 'veryStrong'
41+
* passwordStrengthTester("12345", options); // Very weak
42+
* passwordStrengthTester("1234567", options); // Weak
43+
* @returns {string}
2044
*/
21-
function passwordStrengthTester(password: string): string {
45+
function passwordStrengthTester(
46+
password: string,
47+
{
48+
isVeryWeak,
49+
isWeak,
50+
isRegular,
51+
isStrong,
52+
isVeryStrong,
53+
}: PasswordStrengthTesterOptions,
54+
): string {
2255
if (typeof password !== "string") {
2356
throw new TypeError("The input should be a string.");
2457
}
2558
const passwordLength: number = password.length;
26-
let strengthType: string;
59+
let strengthType: PasswordStrengthType;
2760

2861
switch (true) {
29-
case isVeryWeak(password, passwordLength) || commonPassword(password):
30-
strengthType = "veryWeak";
62+
case isVeryWeak(password, passwordLength):
63+
strengthType = "Very weak";
3164
break;
3265

3366
case isWeak(password, passwordLength):
34-
strengthType = "weak";
67+
strengthType = "Weak";
3568
break;
3669

3770
case isRegular(password, passwordLength):
38-
strengthType = "regular";
39-
break;
40-
41-
case isVeryStrong(password, passwordLength):
42-
strengthType = "veryStrong";
71+
strengthType = "Regular";
4372
break;
4473

4574
case isStrong(password, passwordLength):
46-
strengthType = "strong";
75+
strengthType = "Strong";
4776
break;
4877

49-
case isRegular2(password, passwordLength):
50-
strengthType = "regular";
78+
case isVeryStrong(password, passwordLength):
79+
strengthType = "Very strong";
5180
break;
5281

5382
default:
54-
strengthType = "not classified";
83+
strengthType = "Not classified";
5584
break;
5685
}
5786

5887
return strengthType;
5988
}
6089

61-
function isVeryWeak(password: string, passwordLength: number): boolean {
62-
return passwordLength <= 5 && /^\d+$/.test(password);
63-
}
64-
65-
function isWeak(password: string, passwordLength: number): boolean {
66-
return (
67-
(passwordLength <= 5 && /^[a-zA-Z0-9]+$/.test(password)) ||
68-
(passwordLength >= 6 &&
69-
/^[a-zA-Z0-9]+$/.test(password) &&
70-
passwordLength <= 7) ||
71-
(passwordLength < 10 && /(.)\1{3,}/.test(password)) ||
72-
(passwordLength >= 5 && passwordLength <= 8 && /^\d+$/.test(password))
73-
);
74-
}
75-
76-
function isRegular(password: string, passwordLength: number): boolean {
77-
return /(.)\1{5,}/.test(password) && passwordLength > 10;
78-
}
79-
80-
function isVeryStrong(password: string, passwordLength: number): boolean {
81-
return (
82-
passwordLength > 16 ||
83-
(password.length >= 8 &&
84-
/[A-Z]/.test(password) &&
85-
/[a-z]/.test(password) &&
86-
/\d/.test(password) &&
87-
/[\W_]/.test(password))
88-
);
89-
}
90-
91-
function isRegular2(password: string, passwordLength: number): boolean {
92-
return (
93-
(passwordLength >= 9 && passwordLength <= 12) ||
94-
(password.length >= 6 &&
95-
password.length <= 8 &&
96-
/\d/.test(password) &&
97-
/[a-zA-Z]/.test(password))
98-
);
99-
}
100-
101-
function isStrong(password: string, passwordLength: number): boolean {
102-
return (
103-
(passwordLength >= 13 && passwordLength <= 16) ||
104-
(password.length >= 8 &&
105-
/[A-Z]/.test(password) &&
106-
/[a-z]/.test(password) &&
107-
/\d/.test(password))
108-
);
109-
}
110-
111-
function commonPassword(password: string): boolean {
112-
const commonPasswords: string[] = [
113-
"123",
114-
"1234",
115-
"12345",
116-
"123456",
117-
"1234567",
118-
"12345678",
119-
"123456789",
120-
"password",
121-
"password",
122-
"password!",
123-
"password!1",
124-
"admin",
125-
"admin!",
126-
"Admin",
127-
"Admin!",
128-
"admin123",
129-
"P@ssw0rd",
130-
"Password",
131-
"password123",
132-
"password123!",
133-
"Qwerty",
134-
"Qwerty!",
135-
"Qwerty123",
136-
"Qwerty123!",
137-
];
138-
139-
return commonPasswords.includes(password);
140-
}
141-
14290
export default passwordStrengthTester;
Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,60 @@
11
import { passwordStrengthTester } from "../../index";
2+
import { PasswordStrengthTesterOptions } from "../../src/passwordStrengthTester";
23

34
describe("passwordStrengthTester function", () => {
5+
let options: PasswordStrengthTesterOptions;
6+
7+
beforeEach(() => {
8+
options = {
9+
isVeryWeak: (password: string, passwordLength: number) => {
10+
return passwordLength < 6 && password === "12345";
11+
},
12+
isWeak: (password: string, passwordLength: number) => {
13+
return passwordLength < 8 && password === "1234567";
14+
},
15+
isRegular: (password: string, passwordLength: number) => {
16+
return passwordLength < 10 && password === "123456789";
17+
},
18+
isStrong: (password: string, passwordLength: number) => {
19+
return passwordLength < 12 && password === "12345678910";
20+
},
21+
isVeryStrong: (password: string, passwordLength: number) => {
22+
return passwordLength >= 12 && password === "1234567891011";
23+
},
24+
};
25+
});
26+
427
it("should throw an error if the input is not a string", () => {
5-
expect(() => passwordStrengthTester(123 as any)).toThrow(
28+
expect(() => passwordStrengthTester(123 as any, {} as any)).toThrow(
629
"The input should be a string.",
730
);
831
});
9-
test("should return correct strength type", () => {
10-
expect(passwordStrengthTester("12345")).toBe("veryWeak");
11-
expect(passwordStrengthTester("abcdef")).toBe("weak");
12-
expect(passwordStrengthTester("abc12345")).toBe("regular");
13-
expect(passwordStrengthTester("Abc123awdasd")).toBe("strong");
14-
expect(passwordStrengthTester("SuperSecurePassword123!@")).toBe(
15-
"veryStrong",
32+
33+
it("should return 'Very weak' if the password is very weak", () => {
34+
expect(passwordStrengthTester("12345", options)).toBe("Very weak");
35+
});
36+
37+
it("should return 'Weak' if the password is weak", () => {
38+
expect(passwordStrengthTester("1234567", options)).toBe("Weak");
39+
});
40+
41+
it("should return 'Regular' if the password is regular", () => {
42+
expect(passwordStrengthTester("123456789", options)).toBe("Regular");
43+
});
44+
45+
it("should return 'Strong' if the password is strong", () => {
46+
expect(passwordStrengthTester("12345678910", options)).toBe("Strong");
47+
});
48+
49+
it("should return 'Very strong' if the password is very strong", () => {
50+
expect(passwordStrengthTester("1234567891011", options)).toBe(
51+
"Very strong",
52+
);
53+
});
54+
55+
it("should return 'Not classified' if the password is not classified", () => {
56+
expect(passwordStrengthTester("123456789101112", options)).toBe(
57+
"Not classified",
1658
);
1759
});
1860
});

tests/src/validateUsername.test.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,7 @@ describe("validateUsername", () => {
4646
maxLength: 25,
4747
errorMsg: ["Error message", 123] as any,
4848
}),
49-
).toThrow(
50-
"All values within the array must be strings or null/undefined.",
51-
);
49+
).toThrow("All values within the array must be strings or null/undefined.");
5250
});
5351

5452
it("should throw an error if minLength or maxLength is less than 1", () => {

tests/testerGeral.test.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import {
2323
validateUSPhoneNumber,
2424
validatePhoneNumber,
2525
isNumber,
26-
passwordStrengthTester,
2726
validateName,
2827
validateSurname,
2928
validateTextarea,
@@ -152,11 +151,6 @@ describe("Testes para as funções de validação", () => {
152151
expect(isNumber("NotANumber")).toBe(false);
153152
});
154153

155-
test("passwordStrengthTester should assess password strength correctly", () => {
156-
expect(passwordStrengthTester("Password123")).toBe("strong");
157-
expect(passwordStrengthTester("weak")).toBe("weak");
158-
});
159-
160154
test("validateName should validate names correctly", () => {
161155
expect(validateName("John").isValid).toBe(true);
162156
expect(validateName("InvalidName@").isValid).toBe(false);

0 commit comments

Comments
 (0)