From 999c611af4b06a49e2ea225379649842391669ac Mon Sep 17 00:00:00 2001 From: EvgenyWas Date: Wed, 14 Aug 2024 10:47:48 +0100 Subject: [PATCH] refactor: update user profile validations --- configs/properties.ts | 4 ++++ pages/profile/index.vue | 12 ++++++++++++ server/api/auth/login.post.ts | 13 ++++++++----- server/api/auth/signup.post.ts | 17 ++++++++++++----- server/models/user/profile.model.ts | 23 ++++++++++++++++++++--- server/schemas.ts | 18 +++++++++++++----- 6 files changed, 69 insertions(+), 18 deletions(-) diff --git a/configs/properties.ts b/configs/properties.ts index e3b2c78..8d6a963 100644 --- a/configs/properties.ts +++ b/configs/properties.ts @@ -12,7 +12,11 @@ export const FOOTER_LINKS = [ ]; export const MIN_USER_NAME_LENGTH = 3; +export const MAX_USER_NAME_LENGTH = 100; +export const MAX_USER_DESCRIPTION_LENGTH = 500; +export const MAX_USER_ADDRESS_LENGTH = 100; export const MAX_USER_SOCIALS = 4; +export const MAX_USER_SOCIAL_LENGTH = 100; export const MAX_USER_AVATAR_SIZE = 3 * 1024 * 1024; export const USER_AVATAR_FILE_TYPES = 'image/*' as const; diff --git a/pages/profile/index.vue b/pages/profile/index.vue index 00797e8..3ea0d9e 100644 --- a/pages/profile/index.vue +++ b/pages/profile/index.vue @@ -13,9 +13,11 @@ @@ -26,7 +28,9 @@ > @@ -37,7 +41,9 @@ > @@ -82,6 +88,8 @@ :model-value="model.socials[idx]" :rules="socialRules" :label="`social #${social}`" + :maxlength="MAX_USER_SOCIAL_LENGTH" + counter @update:model-value="changeSocial(idx, $event)" /> @@ -106,7 +114,11 @@ import { cloneDeep, isEqual, isUndefined, omit } from 'lodash-es'; import { MIN_USER_NAME_LENGTH, + MAX_USER_NAME_LENGTH, + MAX_USER_DESCRIPTION_LENGTH, + MAX_USER_ADDRESS_LENGTH, MAX_USER_SOCIALS, + MAX_USER_SOCIAL_LENGTH, USER_AVATAR_FILE_TYPES, MAX_USER_AVATAR_SIZE, } from '~/configs/properties'; diff --git a/server/api/auth/login.post.ts b/server/api/auth/login.post.ts index 295a005..eea1143 100644 --- a/server/api/auth/login.post.ts +++ b/server/api/auth/login.post.ts @@ -11,10 +11,13 @@ const anotherAuthProviderMessage = 'You tried signing in with a different authentication method than the one you used during signup. ' + 'Please try again using your original authentication method.'; -const loginPayloadSchema = z.object({ - email: emailValidator, - password: passwordValidator, -}); +const loginPayloadSchema = z + .object({ + email: emailValidator, + password: passwordValidator, + }) + .strict() + .required(); type Payload = z.infer; @@ -34,7 +37,7 @@ export default defineEventHandler(async (event) => { } if (user.auth_provider !== AUTH_PROVIDERS.Email_And_Password) { - throw createError({ statusCode: 404, statusMessage: anotherAuthProviderMessage }); + throw createError({ statusCode: 400, statusMessage: anotherAuthProviderMessage }); } if (user.password !== payload.password) { diff --git a/server/api/auth/signup.post.ts b/server/api/auth/signup.post.ts index 6d6ff70..d112dbd 100644 --- a/server/api/auth/signup.post.ts +++ b/server/api/auth/signup.post.ts @@ -1,19 +1,26 @@ import { z } from 'zod'; -import { AUTH_PROVIDERS, COOKIE_NAMES, MIN_USER_NAME_LENGTH, USER_IDENTITY_MAX_AGE } from '~/configs/properties'; +import { + AUTH_PROVIDERS, + COOKIE_NAMES, + MAX_USER_NAME_LENGTH, + MIN_USER_NAME_LENGTH, + USER_IDENTITY_MAX_AGE, +} from '~/configs/properties'; import Profile from '~/server/models/user/profile.model'; import { jwtGenerator } from '~/server/services'; import type { Profile as IProfile } from '~/types/user'; import { stringToBase64 } from '~/utils/converters'; import { isZodError } from '~/utils/helpers'; -import { emailValidator } from '~/utils/validators'; +import { emailValidator, passwordValidator } from '~/utils/validators'; const signupPayloadSchema = z .object({ - name: z.string().min(MIN_USER_NAME_LENGTH), + name: z.string().min(MIN_USER_NAME_LENGTH).max(MAX_USER_NAME_LENGTH), email: emailValidator, - password: z.string(), + password: passwordValidator, }) + .strict() .required(); type Payload = z.infer; @@ -39,7 +46,7 @@ export default defineEventHandler(async (event) => { throw createError({ statusCode: 404, statusMessage: 'User with the provided email already exists' }); } - const user = await Profile.create({ ...payload, provider: AUTH_PROVIDERS.Email_And_Password }); + const user = await Profile.create({ ...payload, auth_provider: AUTH_PROVIDERS.Email_And_Password }); Object.assign(profile, user.toObject()); } catch (error) { return sendError( diff --git a/server/models/user/profile.model.ts b/server/models/user/profile.model.ts index a07438b..faaf6ec 100644 --- a/server/models/user/profile.model.ts +++ b/server/models/user/profile.model.ts @@ -1,7 +1,14 @@ import { Schema, model } from 'mongoose'; -import { AUTH_PROVIDERS, MAX_USER_SOCIALS, MIN_USER_NAME_LENGTH } from '~/configs/properties'; -import { emailValidator, passwordValidator, dataURIValidator } from '~/utils/validators'; +import { + AUTH_PROVIDERS, + MAX_USER_ADDRESS_LENGTH, + MAX_USER_DESCRIPTION_LENGTH, + MAX_USER_NAME_LENGTH, + MAX_USER_SOCIALS, + MIN_USER_NAME_LENGTH, +} from '~/configs/properties'; +import { emailValidator, passwordValidator, dataURIValidator, phoneValidator } from '~/utils/validators'; const favouritesSubschema = new Schema( { @@ -28,6 +35,7 @@ const schema = new Schema( type: String, required: true, minLength: MIN_USER_NAME_LENGTH, + maxLength: MAX_USER_NAME_LENGTH, }, email: { type: String, @@ -39,29 +47,36 @@ const schema = new Schema( }, password: { type: String, + required: true, validate: { validator: (value: string) => passwordValidator.safeParse(value).success, }, }, avatar: { type: String, + default: '', validate: { validator: (value?: string) => !dataURIValidator.safeParse(value).success, message: 'Avatar in base64 format is forbidden.', }, - default: '', }, description: { type: String, default: '', + maxLength: MAX_USER_DESCRIPTION_LENGTH, }, address: { type: String, default: '', + maxLength: MAX_USER_ADDRESS_LENGTH, }, phone: { type: String, default: '', + validate: { + validator: (value: string) => !value || phoneValidator.safeParse(value).success, + message: 'Phone value is incorrect', + }, }, socials: { type: Array, @@ -74,6 +89,8 @@ const schema = new Schema( auth_provider: { type: String, enum: Object.values(AUTH_PROVIDERS), + immutable: true, + required: true, }, favourites: [favouritesSubschema], }, diff --git a/server/schemas.ts b/server/schemas.ts index 90dc07d..ba32923 100644 --- a/server/schemas.ts +++ b/server/schemas.ts @@ -1,6 +1,14 @@ import { z } from 'zod'; -import { AUTH_PROVIDERS, MAX_USER_SOCIALS, MIN_USER_NAME_LENGTH } from '~/configs/properties'; +import { + AUTH_PROVIDERS, + MAX_USER_ADDRESS_LENGTH, + MAX_USER_DESCRIPTION_LENGTH, + MAX_USER_NAME_LENGTH, + MAX_USER_SOCIAL_LENGTH, + MAX_USER_SOCIALS, + MIN_USER_NAME_LENGTH, +} from '~/configs/properties'; import { dataURIValidator, phoneValidator, urlValidator } from '~/utils/validators'; export const userIdentitySchema = z @@ -21,15 +29,15 @@ export const userFavouriteSchema = z export const userUpdateProfileSchema = z .object({ - name: z.string().min(MIN_USER_NAME_LENGTH), + name: z.string().min(MIN_USER_NAME_LENGTH).max(MAX_USER_NAME_LENGTH), avatar: z .string() .refine((value) => !dataURIValidator.safeParse(value).success) .or(z.literal('')), - description: z.string(), - address: z.string(), + description: z.string().max(MAX_USER_DESCRIPTION_LENGTH), + address: z.string().max(MAX_USER_ADDRESS_LENGTH), phone: phoneValidator.or(z.literal('')), - socials: z.array(urlValidator.or(z.literal(''))).max(MAX_USER_SOCIALS), + socials: z.array(urlValidator.max(MAX_USER_SOCIAL_LENGTH).or(z.literal(''))).max(MAX_USER_SOCIALS), createdAt: z.string().optional(), updatedAt: z.string().optional(), favourites: z.array(userFavouriteSchema).optional(),