From d26d4761da74a1434ed52541216e9aee6102fe3d Mon Sep 17 00:00:00 2001 From: klmhyeonwoo Date: Mon, 1 Sep 2025 22:52:39 +0900 Subject: [PATCH 1/2] feat: Add checkPassword util function --- README.md | 8 +++++ .../checkPassword/index.test.ts | 34 +++++++++++++++++++ package/validationUtil/checkPassword/index.ts | 31 +++++++++++++++++ package/validationUtil/index.ts | 1 + 4 files changed, 74 insertions(+) create mode 100644 package/validationUtil/checkPassword/index.test.ts create mode 100644 package/validationUtil/checkPassword/index.ts diff --git a/README.md b/README.md index 91bd88d..a8c06f6 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,13 @@ const isValid = validationUtil.checkEmail("user@example.com"); // true const isHttpUrl = validationUtil.checkHttpUrl("https://example.com"); // true const isDomain = validationUtil.checkDomain("example.com"); // true const isBase64 = validationUtil.checkBase64("U29tZSB2YWxpZCBiYXNlNjQgc3RyaW5n"); // true +const isPasswordValid = validationUtil.checkPassword("Abc123!@#", { + minLength: 8, + requireUppercase: true, + requireLowercase: true, + requireNumber: true, + requireSpecialChar: true, +}); // true // Common utilities const empty = commonUtil.isEmpty(""); // true @@ -87,6 +94,7 @@ const theme = cookieUtil.getCookie("theme"); - `checkHttpUrl(url: string): boolean` - Validates HTTP/HTTPS URL format - `checkDomain(domain: string): boolean` - Validates domain name format - `checkBase64(value: string): boolean` - Validates whether a string is a valid base64 encoded value +- `checkPassword(password: string, options?: { minLength?: number; maxLength?: number; requireUppercase?: boolean; requireLowercase?: boolean; requireNumber?: boolean; requireSpecialChar?: boolean }): boolean` - Validates password strength and requirements ### CommonUtil diff --git a/package/validationUtil/checkPassword/index.test.ts b/package/validationUtil/checkPassword/index.test.ts new file mode 100644 index 0000000..2e6cd25 --- /dev/null +++ b/package/validationUtil/checkPassword/index.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, test } from "vitest"; +import checkPassword from "."; + +describe("checkPassword 유틸 함수 테스트", () => { + describe("유효한 비밀번호에 대해 true를 반환해야 합니다.", () => { + test("기본 상태는 아무 옵션도 설정되어있지 않기 때문에 true를 반환해야 합니다.", () => { + expect(checkPassword("Valid123!", {})).toBe(true); + }); + test("특수 문자가 필요한 경우 true를 반환해야 합니다.", () => { + expect(checkPassword("vsdvdsvsdvs1!", { requireSpecialChar: true })).toBe( + true + ); + }); + test("대문자가 필요한 경우 true를 반환해야 합니다.", () => { + expect(checkPassword("Vsdvd", { requireUppercase: true })).toBe(true); + }); + test("최소 3자, 최대 5자의 길이를 가져야 하는 경우 true를 반환해야 합니다.", () => { + expect(checkPassword("Vsd", { minLength: 3, maxLength: 5 })).toBe(true); + }); + }); + + describe("유효하지 않은 비밀번호에 대해 false를 반환해야 합니다.", () => { + test("길이가 유효하지 않은 경우 false를 반환해야 합니다.", () => { + expect(checkPassword("invalid", { minLength: 3, maxLength: 5 })).toBe( + false + ); + }); + test("특수 문자가 없는 경우 false를 반환해야 합니다.", () => { + expect(checkPassword("dffadsfas", { requireSpecialChar: true })).toBe( + false + ); + }); + }); +}); diff --git a/package/validationUtil/checkPassword/index.ts b/package/validationUtil/checkPassword/index.ts new file mode 100644 index 0000000..c03035b --- /dev/null +++ b/package/validationUtil/checkPassword/index.ts @@ -0,0 +1,31 @@ +export default function checkPassword( + password: string, + options?: { + minLength?: number | null; + maxLength?: number | null; + requireUppercase?: boolean; + requireLowercase?: boolean; + requireNumber?: boolean; + requireSpecialChar?: boolean; + } +): boolean { + const { + minLength = null, + maxLength = null, + requireUppercase = false, + requireLowercase = false, + requireNumber = false, + requireSpecialChar = false, + } = options || {}; + + if (minLength !== null && password.length < minLength) return false; + if (maxLength !== null && password.length > maxLength) return false; + const hasUpperCase = requireUppercase ? /[A-Z]/.test(password) : true; + const hasLowerCase = requireLowercase ? /[a-z]/.test(password) : true; + const hasNumber = requireNumber ? /\d/.test(password) : true; + const hasSpecialChar = requireSpecialChar + ? /[!@#$%^&*(),.?":{}|<>]/.test(password) + : true; + + return hasUpperCase && hasLowerCase && hasNumber && hasSpecialChar; +} diff --git a/package/validationUtil/index.ts b/package/validationUtil/index.ts index e49429b..f530838 100644 --- a/package/validationUtil/index.ts +++ b/package/validationUtil/index.ts @@ -2,3 +2,4 @@ export { default as checkEmail } from "./checkEmail"; export { default as checkHttpUrl } from "./checkHttpUrl"; export { default as checkDomain } from "./checkDomain"; export { default as checkBase64 } from "./checkBase64"; +export { default as checkPassword } from "./checkPassword"; From e207546373f0ad004c86519481a4ba2c87585840 Mon Sep 17 00:00:00 2001 From: klmhyeonwoo Date: Mon, 1 Sep 2025 22:59:47 +0900 Subject: [PATCH 2/2] refactor: Improvements to better type inference --- package/validationUtil/checkPassword/index.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package/validationUtil/checkPassword/index.ts b/package/validationUtil/checkPassword/index.ts index c03035b..d137c65 100644 --- a/package/validationUtil/checkPassword/index.ts +++ b/package/validationUtil/checkPassword/index.ts @@ -1,8 +1,8 @@ export default function checkPassword( password: string, options?: { - minLength?: number | null; - maxLength?: number | null; + minLength?: number; + maxLength?: number; requireUppercase?: boolean; requireLowercase?: boolean; requireNumber?: boolean; @@ -10,16 +10,16 @@ export default function checkPassword( } ): boolean { const { - minLength = null, - maxLength = null, + minLength, + maxLength, requireUppercase = false, requireLowercase = false, requireNumber = false, requireSpecialChar = false, } = options || {}; - if (minLength !== null && password.length < minLength) return false; - if (maxLength !== null && password.length > maxLength) return false; + if (minLength !== undefined && password.length < minLength) return false; + if (maxLength !== undefined && password.length > maxLength) return false; const hasUpperCase = requireUppercase ? /[A-Z]/.test(password) : true; const hasLowerCase = requireLowercase ? /[a-z]/.test(password) : true; const hasNumber = requireNumber ? /\d/.test(password) : true;