From 5a9ff43a90b5139ec37a4a344d5506c3ff7b0574 Mon Sep 17 00:00:00 2001 From: anshul23102 Date: Sat, 23 May 2026 23:16:27 +0530 Subject: [PATCH] fix(signup): align frontend password validation with backend Zod schema The frontend regex accepted passwords that the backend Zod schema rejects, causing silent server-side failures with no actionable inline feedback. Root cause: Signup.tsx used a weaker regex that only required one letter and one digit, allowed # (not in the backend allowlist), and gave no indication that uppercase or a special character was needed. Changes in src/pages/Signup/Signup.tsx: - Extract PASSWORD_REGEX constant that mirrors the Zod rule in backend/validators/authValidator.js exactly: requires lowercase, uppercase, digit, one of @$!%*?& and 8+ chars - Replace the old regex in both handleChange and handleSubmit with PASSWORD_REGEX so a single source of truth drives both validation paths - Replace the vague error message with a descriptive one that lists all four requirements and the allowed special characters No backend changes needed: authValidator.js is already correct and is the reference source for the frontend rule. Fixes #415 --- src/pages/Signup/Signup.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/pages/Signup/Signup.tsx b/src/pages/Signup/Signup.tsx index 2ac51dcc..733c6137 100644 --- a/src/pages/Signup/Signup.tsx +++ b/src/pages/Signup/Signup.tsx @@ -8,6 +8,13 @@ import type { ThemeContextType } from "../../context/ThemeContext"; const backendUrl = import.meta.env.VITE_BACKEND_URL; +// Must mirror the Zod rule in backend/validators/authValidator.js exactly. +// Requires: lowercase, uppercase, digit, and one special character from @$!%*?& +// Minimum 8 characters, maximum enforced by the backend (100). +const PASSWORD_REGEX = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/; +const PASSWORD_ERROR = + "Password must be at least 8 characters and include uppercase, lowercase, a number, and a special character (@$!%*?&)"; + interface SignUpFormData { username: string; email: string; @@ -53,8 +60,8 @@ const SignUp: React.FC = () => { if (name === "password") { if (!value.trim()) { errorMessage = "Password is required"; - } else if (!/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d@$!%*#?&]{8,}$/.test(value)) { - errorMessage = "Password must be 8+ characters with letters and numbers"; + } else if (!PASSWORD_REGEX.test(value)) { + errorMessage = PASSWORD_ERROR; } } setErrors((prev) => ({ ...prev, [name]: errorMessage })); @@ -74,8 +81,8 @@ const SignUp: React.FC = () => { : ""; const passwordError = !formData.password.trim() ? "Password is required" - : !/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d@$!%*#?&]{8,}$/.test(formData.password) - ? "Password must be 8+ characters with letters and numbers" + : !PASSWORD_REGEX.test(formData.password) + ? PASSWORD_ERROR : ""; if (usernameError || emailError || passwordError) { setErrors({ username: usernameError, email: emailError, password: passwordError });