fix: added better UI form validation for password registration
All checks were successful
Deploy / deploy (push) Successful in 1m29s
Security Tests / security-non-db (push) Successful in 20s
Security Tests / security-db (push) Successful in 23s

This commit is contained in:
2026-03-01 22:04:28 -06:00
parent f2b80a1ca0
commit e0313df24b
2 changed files with 19 additions and 5 deletions

View File

@@ -888,7 +888,11 @@ app.post(
authRateLimit, authRateLimit,
async (req, reply) => { async (req, reply) => {
const parsed = RegisterBody.safeParse(req.body); const parsed = RegisterBody.safeParse(req.body);
if (!parsed.success) return reply.code(400).send({ ok: false, message: "Invalid payload" }); if (!parsed.success) {
const firstIssue = parsed.error.issues[0];
const message = firstIssue?.message || "Invalid payload";
return reply.code(400).send({ ok: false, message });
}
const { email, password } = parsed.data; const { email, password } = parsed.data;
const normalizedEmail = normalizeEmail(email); const normalizedEmail = normalizeEmail(email);
const existing = await app.prisma.user.findUnique({ const existing = await app.prisma.user.findUnique({

View File

@@ -37,8 +37,13 @@ export default function RegisterPage() {
const passwordError = const passwordError =
(touched.password || submitted) && !password (touched.password || submitted) && !password
? "Password is required." ? "Password is required."
: (touched.password || submitted) && password.length < 8 : (touched.password || submitted) &&
? "Password must be at least 8 characters." (password.length < 12 ||
!/[a-z]/.test(password) ||
!/[A-Z]/.test(password) ||
!/\d/.test(password) ||
!/[^A-Za-z0-9]/.test(password))
? "Use 12+ chars with upper, lower, number, and symbol."
: ""; : "";
const confirmError = const confirmError =
(touched.confirmPassword || submitted) && !confirmPassword (touched.confirmPassword || submitted) && !confirmPassword
@@ -87,7 +92,7 @@ export default function RegisterPage() {
status === 409 status === 409
? "That email is already registered. Try signing in." ? "That email is already registered. Try signing in."
: status === 400 : status === 400
? "Enter a valid email and password." ? (err instanceof Error ? err.message : "Enter a valid email and password.")
: err instanceof Error : err instanceof Error
? err.message ? err.message
: "Unable to register. Try again."; : "Unable to register. Try again.";
@@ -134,11 +139,16 @@ export default function RegisterPage() {
onBlur={() => setTouched((prev) => ({ ...prev, password: true }))} onBlur={() => setTouched((prev) => ({ ...prev, password: true }))}
autoComplete="new-password" autoComplete="new-password"
required required
minLength={8} minLength={12}
/> />
{passwordError && ( {passwordError && (
<span className="text-xs text-red-400">{passwordError}</span> <span className="text-xs text-red-400">{passwordError}</span>
)} )}
{!passwordError && (
<span className="text-xs muted">
Must be 12+ chars and include uppercase, lowercase, number, and symbol.
</span>
)}
</label> </label>
<label className="stack gap-1"> <label className="stack gap-1">
<span className="text-sm font-medium">Confirm password</span> <span className="text-sm font-medium">Confirm password</span>