mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
164 lines
No EOL
4.9 KiB
TypeScript
164 lines
No EOL
4.9 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
export type ListGame = {
|
|
id: string;
|
|
game_name: string;
|
|
game_id: string;
|
|
collection_id: string;
|
|
wishlist_id: string;
|
|
times_played: number;
|
|
thumb_url: string | null;
|
|
in_collection: boolean;
|
|
in_wishlist: boolean;
|
|
};
|
|
|
|
export const modifyListGameSchema = z.object({
|
|
id: z.string()
|
|
});
|
|
|
|
export type ModifyListGame = typeof modifyListGameSchema;
|
|
|
|
export const userSchema = z.object({
|
|
firstName: z.string().trim().optional(),
|
|
lastName: z.string().trim().optional(),
|
|
email: z.string().email({ message: 'Please enter a valid email address' }).optional(),
|
|
username: z
|
|
.string()
|
|
.trim()
|
|
.min(3, { message: 'Username must be at least 3 characters' })
|
|
.max(50, { message: 'Username must be less than 50 characters' }),
|
|
password: z
|
|
.string({ required_error: 'Password is required' })
|
|
.trim()
|
|
.min(8, { message: 'Password must be at least 8 characters' })
|
|
.max(128, { message: 'Password must be less than 128 characters' }),
|
|
confirm_password: z
|
|
.string({ required_error: 'Confirm Password is required' })
|
|
.trim()
|
|
.min(8, { message: 'Confirm Password must be at least 8 characters' }),
|
|
role: z.enum(['USER', 'ADMIN'], { required_error: 'You must have a role' }).default('USER'),
|
|
verified: z.boolean().default(false),
|
|
token: z.string().optional(),
|
|
receiveEmail: z.boolean().default(false),
|
|
createdAt: z.date().optional(),
|
|
updatedAt: z.date().optional()
|
|
});
|
|
|
|
export const signUpSchema = userSchema
|
|
.pick({
|
|
firstName: true,
|
|
lastName: true,
|
|
email: true,
|
|
username: true,
|
|
password: true,
|
|
confirm_password: true,
|
|
terms: true
|
|
})
|
|
.superRefine(({ confirm_password, password }, ctx) => {
|
|
refinePasswords(confirm_password, password, ctx);
|
|
});
|
|
|
|
export const signInSchema = userSchema.pick({
|
|
username: true,
|
|
password: true
|
|
});
|
|
|
|
export const updateUserPasswordSchema = userSchema
|
|
.pick({ password: true, confirm_password: true })
|
|
.superRefine(({ confirm_password, password }, ctx) => {
|
|
refinePasswords(confirm_password, password, ctx);
|
|
});
|
|
|
|
export const changeUserPasswordSchema = z
|
|
.object({
|
|
current_password: z.string({ required_error: 'Current Password is required' }),
|
|
password: z
|
|
.string({ required_error: 'Password is required' })
|
|
.trim(),
|
|
confirm_password: z
|
|
.string({ required_error: 'Confirm Password is required' })
|
|
.trim()
|
|
})
|
|
.superRefine(({ confirm_password, password }, ctx) => {
|
|
refinePasswords(confirm_password, password, ctx);
|
|
});
|
|
|
|
const refinePasswords = async function(confirm_password: string, password: string, ctx: z.RefinementCtx) {
|
|
comparePasswords(confirm_password, password, ctx);
|
|
checkPasswordStrength(password, ctx);
|
|
}
|
|
|
|
const comparePasswords = async function(confirm_password: string, password: string, ctx: z.RefinementCtx) {
|
|
if (confirm_password !== password) {
|
|
ctx.addIssue({
|
|
code: 'custom',
|
|
message: 'Password and Confirm Password must match',
|
|
path: ['confirm_password']
|
|
});
|
|
}
|
|
}
|
|
|
|
const checkPasswordStrength = async function (password: string, ctx: z.RefinementCtx) {
|
|
const minimumLength = password.length < 8;
|
|
const maximumLength = password.length > 128;
|
|
const containsUppercase = (ch: string) => /[A-Z]/.test(ch);
|
|
const containsLowercase = (ch: string) => /[a-z]/.test(ch);
|
|
const containsSpecialChar = (ch: string) =>
|
|
/[`!@#$%^&*()_\-+=\[\]{};':"\\|,.<>\/?~ ]/.test(ch);
|
|
let countOfUpperCase = 0,
|
|
countOfLowerCase = 0,
|
|
countOfNumbers = 0,
|
|
countOfSpecialChar = 0;
|
|
for (let i = 0; i < password.length; i++) {
|
|
const char = password.charAt(i);
|
|
if (!isNaN(+char)) countOfNumbers++;
|
|
else if (containsUppercase(char)) countOfUpperCase++;
|
|
else if (containsLowercase(char)) countOfLowerCase++;
|
|
else if (containsSpecialChar(char)) countOfSpecialChar++;
|
|
}
|
|
|
|
let errors = {
|
|
upperCase: { pass: true, message: "At least one upper case." },
|
|
lowerCase: { pass: true, message: "At least one lower case." },
|
|
specialCharacter: { pass: true, message: "At least one special character." },
|
|
totalNumber: { pass: true, message: "At least one number." },
|
|
minimumLength: { pass: true, message: "At least 8 characters." },
|
|
maximumLength: { pass: true, message: "At most 128 characters." },
|
|
};
|
|
|
|
if (countOfLowerCase < 1) {
|
|
errors = { ...errors, lowerCase: { ...errors.lowerCase, pass: false } };
|
|
}
|
|
if (countOfNumbers < 1) {
|
|
errors = {
|
|
...errors,
|
|
totalNumber: { ...errors.totalNumber, pass: false },
|
|
};
|
|
}
|
|
if (countOfUpperCase < 1) {
|
|
errors = { ...errors, upperCase: { ...errors.upperCase, pass: false } };
|
|
}
|
|
if (countOfSpecialChar < 1) {
|
|
errors = { ...errors, specialCharacter: { ...errors.specialCharacter, pass: false } };
|
|
}
|
|
if (minimumLength) {
|
|
errors = { ...errors, minimumLength: { ...errors.minimumLength, pass: false } };
|
|
}
|
|
if (maximumLength) {
|
|
errors = { ...errors, maximumLength: { ...errors.maximumLength, pass: false } };
|
|
}
|
|
|
|
|
|
if (
|
|
countOfLowerCase < 1 ||
|
|
countOfUpperCase < 1 ||
|
|
countOfSpecialChar < 1 ||
|
|
countOfNumbers < 1
|
|
) {
|
|
ctx.addIssue({
|
|
code: "custom",
|
|
message: JSON.stringify(errors),
|
|
path: ["password"]
|
|
});
|
|
}
|
|
} |