83 lines
2.0 KiB
TypeScript
83 lines
2.0 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
/**
|
|
* Password requirements
|
|
* These are the requirements for the password when signing up or changing the password
|
|
*/
|
|
const requirements = {
|
|
minLength: 6,
|
|
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',
|
|
});
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
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',
|
|
});
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|