diff --git a/convex/auth.ts b/convex/auth.ts index 12e0daa..f31400a 100644 --- a/convex/auth.ts +++ b/convex/auth.ts @@ -14,6 +14,10 @@ export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [Password], }); +export const PASSWORD_MIN = 8; +export const PASSWORD_MAX = 100; +export const PASSWORD_REGEX = /^(?=.{8,100}$)(?!.*\s)(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[\p{P}\p{S}]).*$/u; + export const getUser = query(async (ctx) => { const userId = await getAuthUserId(ctx); if (!userId) return null; diff --git a/src/app/(auth)/signin/page.tsx b/src/app/(auth)/signin/page.tsx index ad60329..031fa0c 100644 --- a/src/app/(auth)/signin/page.tsx +++ b/src/app/(auth)/signin/page.tsx @@ -24,16 +24,14 @@ import { TabsTrigger, } from '@/components/ui'; import { toast } from 'sonner'; +import { PASSWORD_MIN, PASSWORD_MAX, PASSWORD_REGEX } from '~/convex/auth'; const signInFormSchema = z.object({ email: z.email({ message: 'Please enter a valid email address.', }), - password: z - .string() - .regex( - /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,100}$/, - { + password: z.string() + .regex(PASSWORD_REGEX, { message: 'Incorrect password. Does not meet requirements.', }, ), @@ -44,25 +42,35 @@ const signUpFormSchema = z name: z.string().min(2, { message: 'Name must be at least 2 characters.', }), - email: z.email({ + email: z.string().email({ message: 'Please enter a valid email address.', }), password: z .string() - .min(8, { message: 'Password must be at least 8 characters.' }) - .max(100, { message: 'Password must be no more than 100 characters.' }) - .regex(/[0-9]/, { message: 'Password must contain at least one digit.' }) + .min(PASSWORD_MIN, { + message: `Password must be at least ${PASSWORD_MIN} characters.`, + }) + .max(PASSWORD_MAX, { + message: + `Password must be no more than ${PASSWORD_MAX} characters.`, + }) + .regex(/^\S+$/, { + message: 'Password must not contain whitespace.', + }) + .regex(/[0-9]/, { + message: 'Password must contain at least one digit.', + }) .regex(/[a-z]/, { message: 'Password must contain at least one lowercase letter.', }) .regex(/[A-Z]/, { message: 'Password must contain at least one uppercase letter.', }) - .regex(/[@#$%^&+=]/, { - message: 'Password must contain at least one special character.', + .regex(/[\p{P}\p{S}]/u, { + message: 'Password must contain at least one symbol.', }), - confirmPassword: z.string().min(8, { - message: 'Password must be at least 8 characters.', + confirmPassword: z.string().min(PASSWORD_MIN, { + message: `Password must be at least ${PASSWORD_MIN} characters.`, }), }) .refine((data) => data.password === data.confirmPassword, { @@ -70,7 +78,7 @@ const signUpFormSchema = z path: ['confirmPassword'], }); -export default function SignIn() { +const SignIn = () => { const { signIn } = useAuthActions(); const [flow, setFlow] = useState<'signIn' | 'signUp'>('signIn'); const [loading, setLoading] = useState(false); @@ -317,4 +325,5 @@ export default function SignIn() { ); -} +}; +export default SignIn; diff --git a/src/components/layout/profile/reset-password.tsx b/src/components/layout/profile/reset-password.tsx index 59e913d..ea025fa 100644 --- a/src/components/layout/profile/reset-password.tsx +++ b/src/components/layout/profile/reset-password.tsx @@ -21,32 +21,34 @@ import { SubmitButton, } from '@/components/ui'; import { toast } from 'sonner'; +import { PASSWORD_MIN, PASSWORD_MAX, PASSWORD_REGEX } from '~/convex/auth'; const formSchema = z .object({ currentPassword: z .string() - .regex( - /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,100}$/, - { + .regex(PASSWORD_REGEX, { message: 'Incorrect current password. Does not meet requirements.', }, ), newPassword: z .string() - .min(8, { message: 'New password must be at least 8 characters.' }) - .max(100, { message: 'New password must be less than 100 characters.' }) + .min(PASSWORD_MIN, { message: 'New password must be at least 8 characters.' }) + .max(PASSWORD_MAX, { message: 'New password must be less than 100 characters.' }) + .regex(/^\S+$/, { + message: 'Password must not contain whitespace.', + }) .regex(/[0-9]/, { - message: 'New password must contain at least one digit.', + message: 'Password must contain at least one digit.', }) .regex(/[a-z]/, { - message: 'New password must contain at least one lowercase letter.', + message: 'Password must contain at least one lowercase letter.', }) .regex(/[A-Z]/, { - message: 'New password must contain at least one uppercase letter.', + message: 'Password must contain at least one uppercase letter.', }) - .regex(/[@#$%^&+=]/, { - message: 'New password must contain at least one special character.', + .regex(/[\p{P}\p{S}]/u, { + message: 'Password must contain at least one symbol.', }), confirmPassword: z.string(), })