Files
myeasycms-v2/packages/features/auth/src/schemas/password.schema.ts
Giancarlo Buomprisco 7ebff31475 Next.js Supabase V3 (#463)
Version 3 of the kit:
- Radix UI replaced with Base UI (using the Shadcn UI patterns)
- next-intl replaces react-i18next
- enhanceAction deprecated; usage moved to next-safe-action
- main layout now wrapped with [locale] path segment
- Teams only mode
- Layout updates
- Zod v4
- Next.js 16.2
- Typescript 6
- All other dependencies updated
- Removed deprecated Edge CSRF
- Dynamic Github Action runner
2026-03-24 13:40:38 +08:00

79 lines
2.0 KiB
TypeScript

import * as z from 'zod';
/**
* Password requirements
* These are the requirements for the password when signing up or changing the password
*/
const requirements = {
minLength: 8,
maxLength: 99,
specialChars:
process.env.NEXT_PUBLIC_PASSWORD_REQUIRE_SPECIAL_CHARS === 'true',
numbers: process.env.NEXT_PUBLIC_PASSWORD_REQUIRE_NUMBERS === 'true',
uppercase: process.env.NEXT_PUBLIC_PASSWORD_REQUIRE_UPPERCASE === 'true',
};
/**
* Password schema
* This is used to validate the password on sign in (for existing users when requirements are not enforced)
*/
export const PasswordSchema = z
.string()
.min(requirements.minLength)
.max(requirements.maxLength);
/**
* Refined password schema with additional requirements
* This is required to validate the password requirements on sign up and password change
*/
export const RefinedPasswordSchema = PasswordSchema.superRefine((val, ctx) =>
validatePassword(val, ctx),
);
export function refineRepeatPassword(
data: { password: string; repeatPassword: string },
ctx: z.RefinementCtx,
) {
if (data.password !== data.repeatPassword) {
ctx.addIssue({
message: 'auth.errors.passwordsDoNotMatch',
path: ['repeatPassword'],
code: 'custom',
});
}
}
function validatePassword(password: string, ctx: z.RefinementCtx) {
if (requirements.specialChars) {
const specialCharsCount =
password.match(/[!@#$%^&*(),.?":{}|<>]/g)?.length ?? 0;
if (specialCharsCount < 1) {
ctx.addIssue({
message: 'auth.errors.minPasswordSpecialChars',
code: 'custom',
});
}
}
if (requirements.numbers) {
const numbersCount = password.match(/\d/g)?.length ?? 0;
if (numbersCount < 1) {
ctx.addIssue({
message: 'auth.errors.minPasswordNumbers',
code: 'custom',
});
}
}
if (requirements.uppercase) {
if (!/[A-Z]/.test(password)) {
ctx.addIssue({
message: 'auth.errors.uppercasePassword',
code: 'custom',
});
}
}
}