From 395d9be04369b2c29f7b1721bb2ee11f7c0dc3d6 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Fri, 3 Jul 2026 09:14:34 +0200 Subject: [PATCH 1/2] fix: use lenient validation for existing passwords (@fehmer) --- frontend/src/ts/auth.tsx | 18 +++++++++++++++--- .../account-settings/AddPasswordAuthModal.tsx | 4 ++-- .../account-settings/UpdatePasswordModal.tsx | 6 +++--- .../src/ts/components/pages/login/Register.tsx | 2 +- packages/schemas/src/users.ts | 7 ++++++- 5 files changed, 27 insertions(+), 10 deletions(-) diff --git a/frontend/src/ts/auth.tsx b/frontend/src/ts/auth.tsx index 5647b94bec9a..cc57e4dc6cc0 100644 --- a/frontend/src/ts/auth.tsx +++ b/frontend/src/ts/auth.tsx @@ -1,4 +1,4 @@ -import { PasswordSchema } from "@monkeytype/schemas/users"; +import { NewPasswordSchema, PasswordSchema } from "@monkeytype/schemas/users"; import { tryCatch } from "@monkeytype/util/trycatch"; import { FirebaseError } from "firebase/app"; import { @@ -578,8 +578,20 @@ export function isUsingAuthenticationReactive(authMethod: AuthMethod): boolean { return authenticationMemos[authMethod]?.()?.isInUse ?? false; } -export function getPasswordSchema(): ZodString { - return isDevEnvironment() ? z.string().min(6) : PasswordSchema; +/** + * Returns the Zod schema for password validation. + * + * Set `isNew: true` for registration/creation flows (strict rules). + * Omit it for re-authentication flows (lenient: just non-empty). + * + * @param options - Set `isNew: true` for password creation/registration. + * @returns A Zod string schema. + */ +export function getPasswordSchema(options?: { isNew: boolean }): ZodString { + if (options?.isNew) { + return isDevEnvironment() ? z.string().min(6) : NewPasswordSchema; + } + return PasswordSchema; } export function isUsingPasswordAuthentication(): boolean { diff --git a/frontend/src/ts/components/modals/account-settings/AddPasswordAuthModal.tsx b/frontend/src/ts/components/modals/account-settings/AddPasswordAuthModal.tsx index f30813912285..b790f37a9bfa 100644 --- a/frontend/src/ts/components/modals/account-settings/AddPasswordAuthModal.tsx +++ b/frontend/src/ts/components/modals/account-settings/AddPasswordAuthModal.tsx @@ -11,8 +11,8 @@ export function showAddPasswordAuthModal(): void { schema: z.object({ email: UserEmailSchema, emailConfirm: UserEmailSchema, - password: getPasswordSchema(), - passConfirm: getPasswordSchema(), + password: getPasswordSchema({ isNew: true }), + passConfirm: getPasswordSchema({ isNew: true }), }), inputs: { email: { diff --git a/frontend/src/ts/components/modals/account-settings/UpdatePasswordModal.tsx b/frontend/src/ts/components/modals/account-settings/UpdatePasswordModal.tsx index 4344575551ac..371fe34bb3b8 100644 --- a/frontend/src/ts/components/modals/account-settings/UpdatePasswordModal.tsx +++ b/frontend/src/ts/components/modals/account-settings/UpdatePasswordModal.tsx @@ -20,9 +20,9 @@ export function showUpdatePasswordModal(): void { showSimpleModal({ title: "Update password", schema: z.object({ - previousPass: z.string().min(1, "Current password is required"), - newPassword: getPasswordSchema(), - newPassConfirm: getPasswordSchema(), + previousPass: getPasswordSchema(), + newPassword: getPasswordSchema({ isNew: true }), + newPassConfirm: getPasswordSchema({ isNew: true }), }), inputs: { previousPass: { diff --git a/frontend/src/ts/components/pages/login/Register.tsx b/frontend/src/ts/components/pages/login/Register.tsx index 617a57d06bdc..e643300a85a2 100644 --- a/frontend/src/ts/components/pages/login/Register.tsx +++ b/frontend/src/ts/components/pages/login/Register.tsx @@ -213,7 +213,7 @@ export function Register(): JSXElement { ( ; -export const PasswordSchema = z +// stricter schema used while password creation +export const NewPasswordSchema = z .string() .min(8, { message: "must be at least 8 characters" }) .max(64, { message: "must be at most 64 characters" }) @@ -374,6 +375,10 @@ export const PasswordSchema = z .regex(/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/, { message: "must contain at least one special character", }); +export type NewPassword = z.infer; + +// lenient schema for existing passwords +export const PasswordSchema = z.string().min(1, "Required"); export type Password = z.infer; export const FriendSchema = UserSchema.pick({ From 4ca9f9b7dc8732038bf3b8c63f7081b25605af34 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Sat, 4 Jul 2026 16:30:57 +0200 Subject: [PATCH 2/2] review comments --- frontend/src/ts/auth.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/frontend/src/ts/auth.tsx b/frontend/src/ts/auth.tsx index cc57e4dc6cc0..b75d6e8cf2c0 100644 --- a/frontend/src/ts/auth.tsx +++ b/frontend/src/ts/auth.tsx @@ -588,10 +588,9 @@ export function isUsingAuthenticationReactive(authMethod: AuthMethod): boolean { * @returns A Zod string schema. */ export function getPasswordSchema(options?: { isNew: boolean }): ZodString { - if (options?.isNew) { - return isDevEnvironment() ? z.string().min(6) : NewPasswordSchema; - } - return PasswordSchema; + if (!options?.isNew) return PasswordSchema; + if (isDevEnvironment()) return z.string().min(6); + return NewPasswordSchema; } export function isUsingPasswordAuthentication(): boolean {