diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 29cfc7fa..10a12b0a 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -38,73 +38,6 @@ "portPlaceholder": "443", "migration": "Restore the backup" }, - "zod": { - "client": { - "id": "Client ID must be a valid number", - "name": "Name must be a valid string", - "nameMin": "Name must be at least 1 Character", - "expireDate": "expiredDate must be a valid string", - "expireDateMin": "expiredDate must be at least 1 Character", - "address4": "IPv4 Address must be a valid string", - "address4Min": "IPv4 Address must be a be at least 1 Character", - "address6": "IPv6 Address must be a valid string", - "address6Min": "IPv6 Address must be a be at least 1 Character", - "serverAllowedIps": "Allowed IPs must be a valid array of strings" - }, - "user": { - "username": "Username must be a valid string", - "usernameMin": "Username must be at least 8 Characters", - "password": "Password must be a valid string", - "passwordMin": "Password must be at least 12 Characters", - "passwordUppercase": "Password must have at least 1 uppercase letter", - "passwordLowercase": "Password must have at least 1 lowercase letter", - "passwordNumber": "Password must have at least 1 number", - "passwordSpecial": "Password must have at least 1 special character", - "remember": "Remember must be a valid boolean", - "accept": "Please accept the condition", - "name": "Name must be a valid string", - "nameMin": "Name must be at least 1 Character", - "email": "Email must be a valid string", - "emailMin": "Email must be at least 1 Character", - "emailInvalid": "Email must be a valid email", - "passwordMatch": "Passwords must match" - }, - "userConfig": { - "host": "Host must be a valid string", - "hostMin": "Host must contain at least 1 character" - }, - "general": { - "sessionTimeout": "Session Timeout must be a valid number" - }, - "interface": { - "cidr": "CIDR must be a valid string", - "cidrMin": "CIDR must be at least 1 Character", - "device": "Device must be a valid string", - "deviceMin": "Device must be at least 1 Character" - }, - "otl": { - "otl": "oneTimeLink must be a valid string", - "otlMin": "oneTimeLink must be at least 1 Character" - }, - "stringMalformed": "String is malformed", - "body": "Body must be a valid object", - "hook": "Hook must be a valid string", - "mtu": "MTU must be a valid number", - "mtuMin": "MTU must be at least 1280", - "mtuMax": "MTU must be at most 9000", - "port": "Port must be a valid number", - "portMin": "Port must be at least 1", - "portMax": "Port must be at most 65535", - "persistentKeepalive": "Persistent Keepalive must be a valid number", - "persistentKeepaliveMin": "Persistent Keepalive must be at least 0", - "persistentKeepaliveMax": "Persistent Keepalive must be at most 65535", - "address": "IP Address must be a valid string", - "addressMin": "IP Address must be a be at least 1 Character", - "dns": "DNS must be a valid array of strings", - "dnsMin": "DNS must have at least 1 item", - "allowedIps": "Allowed IPs must be a valid array of strings", - "allowedIpsMin": "Allowed IPs must have at least 1 item" - }, "name": "Name", "username": "Username", "signIn": "Sign In", @@ -151,16 +84,67 @@ "clear": "Clear", "login": "Log in error" }, - "general": { - "sessionTimeout": "Session Timeout", - "metrics": "Metrics", - "prometheus": "Prometheus", - "json": "JSON" - }, "form": { "actions": "Actions", "save": "Save", "revert": "Revert" }, - "password": "Password" + "password": "Password", + "zod": { + "generic": { + "required": "{0} is required", + "validNumber": "{0} must be a valid number", + "validString": "{0} must be a valid string", + "validBoolean": "{0} must be a valid boolean", + "validArray": "{0} must be a valid array", + "stringMin": "{0} must be at least {1} Character", + "numberMin": "{0} must be at least {1}" + }, + "client": { + "id": "Client ID", + "name": "Name", + "expiresAt": "Expires At", + "address4": "IPv4 Address", + "address6": "IPv6 Address", + "serverAllowedIps": "Server Allowed IPs" + }, + "user": { + "username": "Username", + "password": "Password", + "passwordUppercase": "Password must have at least 1 uppercase letter", + "passwordLowercase": "Password must have at least 1 lowercase letter", + "passwordNumber": "Password must have at least 1 number", + "passwordSpecial": "Password must have at least 1 special character", + "remember": "Remember", + "accept": "Accept", + "acceptTrue": "Accept Conditions to continue", + "name": "Name", + "email": "Email", + "emailInvalid": "Email must be a valid email", + "passwordMatch": "Passwords must match" + }, + "userConfig": { + "host": "Host" + }, + "general": { + "sessionTimeout": "Session Timeout", + "metricsEnabled": "Metrics", + "metricsPassword": "Metrics Password" + }, + "interface": { + "cidr": "CIDR", + "device": "Device" + }, + "otl": "One Time link", + "stringMalformed": "String is malformed", + "body": "Body must be a valid object", + "hook": "Hook", + "enabled": "Enabled", + "mtu": "MTU", + "port": "Port", + "persistentKeepalive": "Persistent Keepalive", + "address": "IP Address", + "dns": "DNS", + "allowedIps": "Allowed IPs" + } } diff --git a/src/server/api/client/[clientId]/configuration.get.ts b/src/server/api/client/[clientId]/configuration.get.ts index 7faa531a..2fe407d5 100644 --- a/src/server/api/client/[clientId]/configuration.get.ts +++ b/src/server/api/client/[clientId]/configuration.get.ts @@ -6,7 +6,7 @@ export default definePermissionEventHandler( async ({ event, checkPermissions }) => { const { clientId } = await getValidatedRouterParams( event, - validateZod(ClientGetSchema) + validateZod(ClientGetSchema, event) ); const client = await Database.clients.get(clientId); checkPermissions(client); diff --git a/src/server/api/client/[clientId]/disable.post.ts b/src/server/api/client/[clientId]/disable.post.ts index 2e1a58c0..0338045f 100644 --- a/src/server/api/client/[clientId]/disable.post.ts +++ b/src/server/api/client/[clientId]/disable.post.ts @@ -6,7 +6,7 @@ export default definePermissionEventHandler( async ({ event, checkPermissions }) => { const { clientId } = await getValidatedRouterParams( event, - validateZod(ClientGetSchema) + validateZod(ClientGetSchema, event) ); const client = await Database.clients.get(clientId); diff --git a/src/server/api/client/[clientId]/enable.post.ts b/src/server/api/client/[clientId]/enable.post.ts index 2e1a58c0..0338045f 100644 --- a/src/server/api/client/[clientId]/enable.post.ts +++ b/src/server/api/client/[clientId]/enable.post.ts @@ -6,7 +6,7 @@ export default definePermissionEventHandler( async ({ event, checkPermissions }) => { const { clientId } = await getValidatedRouterParams( event, - validateZod(ClientGetSchema) + validateZod(ClientGetSchema, event) ); const client = await Database.clients.get(clientId); diff --git a/src/server/api/client/[clientId]/generateOneTimeLink.post.ts b/src/server/api/client/[clientId]/generateOneTimeLink.post.ts index 618addf5..9363ed93 100644 --- a/src/server/api/client/[clientId]/generateOneTimeLink.post.ts +++ b/src/server/api/client/[clientId]/generateOneTimeLink.post.ts @@ -6,7 +6,7 @@ export default definePermissionEventHandler( async ({ event, checkPermissions }) => { const { clientId } = await getValidatedRouterParams( event, - validateZod(ClientGetSchema) + validateZod(ClientGetSchema, event) ); const client = await Database.clients.get(clientId); diff --git a/src/server/api/client/[clientId]/index.delete.ts b/src/server/api/client/[clientId]/index.delete.ts index 171ad9e2..2267e89d 100644 --- a/src/server/api/client/[clientId]/index.delete.ts +++ b/src/server/api/client/[clientId]/index.delete.ts @@ -6,7 +6,7 @@ export default definePermissionEventHandler( async ({ event, checkPermissions }) => { const { clientId } = await getValidatedRouterParams( event, - validateZod(ClientGetSchema) + validateZod(ClientGetSchema, event) ); const client = await Database.clients.get(clientId); diff --git a/src/server/api/client/[clientId]/index.post.ts b/src/server/api/client/[clientId]/index.post.ts index 21bdd4e2..82f49b52 100644 --- a/src/server/api/client/[clientId]/index.post.ts +++ b/src/server/api/client/[clientId]/index.post.ts @@ -9,7 +9,7 @@ export default definePermissionEventHandler( async ({ event, checkPermissions }) => { const { clientId } = await getValidatedRouterParams( event, - validateZod(ClientGetSchema) + validateZod(ClientGetSchema, event) ); const data = await readValidatedBody( diff --git a/src/server/api/client/[clientId]/qrcode.svg.get.ts b/src/server/api/client/[clientId]/qrcode.svg.get.ts index 19ad85e6..6d25d577 100644 --- a/src/server/api/client/[clientId]/qrcode.svg.get.ts +++ b/src/server/api/client/[clientId]/qrcode.svg.get.ts @@ -6,7 +6,7 @@ export default definePermissionEventHandler( async ({ event, checkPermissions }) => { const { clientId } = await getValidatedRouterParams( event, - validateZod(ClientGetSchema) + validateZod(ClientGetSchema, event) ); const client = await Database.clients.get(clientId); diff --git a/src/server/api/client/index.post.ts b/src/server/api/client/index.post.ts index ea4940fe..930c625e 100644 --- a/src/server/api/client/index.post.ts +++ b/src/server/api/client/index.post.ts @@ -6,7 +6,7 @@ export default definePermissionEventHandler( async ({ event }) => { const { name, expiresAt } = await readValidatedBody( event, - validateZod(ClientCreateSchema) + validateZod(ClientCreateSchema, event) ); await Database.clients.create({ name, expiresAt }); diff --git a/src/server/api/me/index.post.ts b/src/server/api/me/index.post.ts index 10b338ef..daf19c55 100644 --- a/src/server/api/me/index.post.ts +++ b/src/server/api/me/index.post.ts @@ -3,11 +3,14 @@ import { UserUpdateSchema } from '#db/repositories/user/types'; export default definePermissionEventHandler( 'me', 'update', - async ({ event, user }) => { + async ({ event, user, checkPermissions }) => { const { name, email } = await readValidatedBody( event, - validateZod(UserUpdateSchema) + validateZod(UserUpdateSchema, event) ); + + checkPermissions(user); + await Database.users.update(user.id, name, email); return { success: true }; } diff --git a/src/server/api/me/password.post.ts b/src/server/api/me/password.post.ts index b7fad3d3..87ace186 100644 --- a/src/server/api/me/password.post.ts +++ b/src/server/api/me/password.post.ts @@ -3,11 +3,14 @@ import { UserUpdatePasswordSchema } from '#db/repositories/user/types'; export default definePermissionEventHandler( 'me', 'update', - async ({ event, user }) => { + async ({ event, user, checkPermissions }) => { const { newPassword, currentPassword } = await readValidatedBody( event, - validateZod(UserUpdatePasswordSchema) + validateZod(UserUpdatePasswordSchema, event) ); + + checkPermissions(user); + await Database.users.updatePassword(user.id, currentPassword, newPassword); return { success: true }; } diff --git a/src/server/api/setup/4.post.ts b/src/server/api/setup/4.post.ts index 4c8eb82a..0869b07f 100644 --- a/src/server/api/setup/4.post.ts +++ b/src/server/api/setup/4.post.ts @@ -6,6 +6,8 @@ export default defineSetupEventHandler(async ({ event }) => { validateZod(UserSetupSchema, event) ); + // TODO: validate setup step + await Database.users.create(username, password); await Database.general.setSetupStep(5); return { success: true }; diff --git a/src/server/api/setup/5.post.ts b/src/server/api/setup/5.post.ts index 4a2de39e..593fc1b0 100644 --- a/src/server/api/setup/5.post.ts +++ b/src/server/api/setup/5.post.ts @@ -5,6 +5,7 @@ export default defineSetupEventHandler(async ({ event }) => { event, validateZod(UserConfigSetupSchema, event) ); + // TODO: validate setup step await Database.userConfigs.updateHostPort(host, port); await Database.general.setSetupStep(0); return { success: true }; diff --git a/src/server/database/repositories/client/types.ts b/src/server/database/repositories/client/types.ts index 51c759ec..849d6747 100644 --- a/src/server/database/repositories/client/types.ts +++ b/src/server/database/repositories/client/types.ts @@ -3,8 +3,6 @@ import z from 'zod'; import type { client } from './schema'; -export type ID = string; - export type ClientType = InferSelectModel; export type CreateClientType = Omit< @@ -18,28 +16,28 @@ export type UpdateClientType = Omit< >; const name = z - .string({ message: 'zod.client.name' }) - .min(1, 'zod.client.nameMin') + .string({ message: t('zod.client.name') }) + .min(1, t('zod.client.name')) .pipe(safeStringRefine); const expiresAt = z - .string({ message: 'zod.client.expireDate' }) - .min(1, 'zod.client.expireDateMin') + .string({ message: t('zod.client.expiresAt') }) + .min(1, t('zod.client.expiresAt')) .pipe(safeStringRefine) .nullable(); const address4 = z - .string({ message: 'zod.client.address4' }) - .min(1, { message: 'zod.client.address4Min' }) + .string({ message: t('zod.client.address4') }) + .min(1, { message: t('zod.client.address4') }) .pipe(safeStringRefine); const address6 = z - .string({ message: 'zod.client.address6' }) - .min(1, { message: 'zod.client.address6Min' }) + .string({ message: t('zod.client.address6') }) + .min(1, { message: t('zod.client.address6') }) .pipe(safeStringRefine); const serverAllowedIps = z.array(AddressSchema, { - message: 'zod.serverAllowedIps', + message: t('zod.client.serverAllowedIps'), }); export const ClientCreateSchema = z.object({ @@ -65,7 +63,7 @@ export const ClientUpdateSchema = schemaForType()( ); // TODO: investigate if coerce is bad -const clientId = z.number({ message: 'zod.client.id', coerce: true }); +const clientId = z.number({ message: t('zod.client.id'), coerce: true }); export const ClientGetSchema = z.object({ clientId: clientId, diff --git a/src/server/database/repositories/general/types.ts b/src/server/database/repositories/general/types.ts index 74d8dfc2..576b2f02 100644 --- a/src/server/database/repositories/general/types.ts +++ b/src/server/database/repositories/general/types.ts @@ -4,11 +4,13 @@ import z from 'zod'; export type GeneralType = InferSelectModel; -const sessionTimeout = z.number({ message: 'zod.general.sessionTimeout' }); -const metricsEnabled = z.boolean({ message: 'zod.general.metricsEnabled' }); +const sessionTimeout = z.number({ message: t('zod.general.sessionTimeout') }); + +const metricsEnabled = z.boolean({ message: t('zod.general.metricsEnabled') }); + const metricsPassword = z - .string({ message: 'zod.general.metricsPassword' }) - .min(1, { message: 'zod.general.metricsPasswordMin' }) + .string({ message: t('zod.general.metricsPassword') }) + .min(1, { message: t('zod.general.metricsPassword') }) // TODO: validate argon2 regex? .nullable(); diff --git a/src/server/database/repositories/hooks/types.ts b/src/server/database/repositories/hooks/types.ts index 3e76d045..b450cbf5 100644 --- a/src/server/database/repositories/hooks/types.ts +++ b/src/server/database/repositories/hooks/types.ts @@ -6,7 +6,7 @@ export type HooksType = InferSelectModel; export type HooksUpdateType = Omit; -const hook = z.string({ message: 'zod.hook' }).pipe(safeStringRefine); +const hook = z.string({ message: t('zod.hook') }).pipe(safeStringRefine); export const HooksUpdateSchema = schemaForType()( z.object({ diff --git a/src/server/database/repositories/interface/types.ts b/src/server/database/repositories/interface/types.ts index df271333..a68a6cfb 100644 --- a/src/server/database/repositories/interface/types.ts +++ b/src/server/database/repositories/interface/types.ts @@ -15,13 +15,13 @@ export type InterfaceUpdateType = Omit< >; const device = z - .string({ message: 'zod.interface.device' }) - .min(1, 'zod.interface.deviceMin') + .string({ message: t('zod.interface.device') }) + .min(1, t('zod.interface.device')) .pipe(safeStringRefine); const cidr = z - .string({ message: 'zod.interface.cidr' }) - .min(1, { message: 'zod.interface.cidrMin' }) + .string({ message: t('zod.interface.cidr') }) + .min(1, { message: t('zod.interface.cidr') }) .pipe(safeStringRefine); export const InterfaceUpdateSchema = schemaForType()( diff --git a/src/server/database/repositories/oneTimeLink/types.ts b/src/server/database/repositories/oneTimeLink/types.ts index a2a34968..423a61d5 100644 --- a/src/server/database/repositories/oneTimeLink/types.ts +++ b/src/server/database/repositories/oneTimeLink/types.ts @@ -5,8 +5,8 @@ import { z } from 'zod'; export type OneTimeLinkType = InferSelectModel; const oneTimeLinkType = z - .string({ message: 'zod.otl.otl' }) - .min(1, 'zod.otl.otlMin') + .string({ message: t('zod.otl.otl') }) + .min(1, t('zod.otl.otl')) .pipe(safeStringRefine); export const OneTimeLinkGetSchema = z.object( diff --git a/src/server/database/repositories/user/types.ts b/src/server/database/repositories/user/types.ts index 5837b19e..1c071926 100644 --- a/src/server/database/repositories/user/types.ts +++ b/src/server/database/repositories/user/types.ts @@ -5,32 +5,20 @@ import z from 'zod'; export type UserType = InferSelectModel; const username = z - .string({ message: 'zod.user.username' }) - .min(8, 'zod.user.usernameMin') + .string({ message: t('zod.user.username') }) + .min(8, t('zod.user.username')) .pipe(safeStringRefine); const password = z - .string({ message: 'zod.user.password' }) - .min(12, 'zod.user.passwordMin') - .regex(/[A-Z]/, 'zod.user.passwordUppercase') - .regex(/[a-z]/, 'zod.user.passwordLowercase') - .regex(/\d/, 'zod.user.passwordNumber') - .regex(/[!@#$%^&*(),.?":{}|<>]/, 'zod.user.passwordSpecial') + .string({ message: t('zod.user.password') }) + .min(12, t('zod.user.password')) + .regex(/[A-Z]/, t('zod.user.passwordUppercase')) + .regex(/[a-z]/, t('zod.user.passwordLowercase')) + .regex(/\d/, t('zod.user.passwordNumber')) + .regex(/[!@#$%^&*(),.?":{}|<>]/, t('zod.user.passwordSpecial')) .pipe(safeStringRefine); -const remember = z.boolean({ message: 'zod.user.remember' }); - -const name = z - .string({ message: 'zod.user.name' }) - .min(1, 'zod.user.nameMin') - .pipe(safeStringRefine); - -const email = z - .string({ message: 'zod.user.email' }) - .min(5, 'zod.user.emailMin') - .email({ message: 'zod.user.emailInvalid' }) - .pipe(safeStringRefine) - .nullable(); +const remember = z.boolean({ message: t('zod.user.remember') }); export const UserLoginSchema = z.object( { @@ -41,9 +29,11 @@ export const UserLoginSchema = z.object( { message: objectMessage } ); -const accept = z.boolean().refine((val) => val === true, { - message: 'zod.user.accept', -}); +const accept = z + .boolean({ message: t('zod.user.accept') }) + .refine((val) => val === true, { + message: t('zod.user.acceptTrue'), + }); export const UserSetupSchema = z.object( { @@ -54,6 +44,18 @@ export const UserSetupSchema = z.object( { message: objectMessage } ); +const name = z + .string({ message: t('zod.user.name') }) + .min(1, 'zod.user.name') + .pipe(safeStringRefine); + +const email = z + .string({ message: t('zod.user.email') }) + .min(5, t('zod.user.email')) + .email({ message: t('zod.user.emailInvalid') }) + .pipe(safeStringRefine) + .nullable(); + export const UserUpdateSchema = z.object( { name: name, @@ -72,5 +74,5 @@ export const UserUpdatePasswordSchema = z { message: objectMessage } ) .refine((val) => val.newPassword === val.confirmPassword, { - message: 'zod.user.passwordMatch', + message: t('zod.user.passwordMatch'), }); diff --git a/src/server/database/repositories/userConfig/types.ts b/src/server/database/repositories/userConfig/types.ts index 89e59ef2..71f1189d 100644 --- a/src/server/database/repositories/userConfig/types.ts +++ b/src/server/database/repositories/userConfig/types.ts @@ -5,8 +5,8 @@ import z from 'zod'; export type UserConfigType = InferSelectModel; const host = z - .string({ message: 'zod.userConfig.host' }) - .min(1, 'zod.userConfig.hostMin') + .string({ message: t('zod.userConfig.host') }) + .min(1, t('zod.userConfig.host')) .pipe(safeStringRefine); export const UserConfigSetupSchema = z.object({ diff --git a/src/server/routes/cnf/[oneTimeLink].ts b/src/server/routes/cnf/[oneTimeLink].ts index 79592533..a7e6497b 100644 --- a/src/server/routes/cnf/[oneTimeLink].ts +++ b/src/server/routes/cnf/[oneTimeLink].ts @@ -3,7 +3,7 @@ import { OneTimeLinkGetSchema } from '#db/repositories/oneTimeLink/types'; export default defineEventHandler(async (event) => { const { oneTimeLink } = await getValidatedRouterParams( event, - validateZod(OneTimeLinkGetSchema) + validateZod(OneTimeLinkGetSchema, event) ); const clients = await WireGuard.getAllClients(); const client = clients.find( diff --git a/src/server/utils/types.ts b/src/server/utils/types.ts index 41607b52..a8dd0a7c 100644 --- a/src/server/utils/types.ts +++ b/src/server/utils/types.ts @@ -2,46 +2,53 @@ import type { ZodSchema } from 'zod'; import z from 'zod'; import type { H3Event, EventHandlerRequest } from 'h3'; -export const objectMessage = 'zod.body'; +/** + * return the string as is + * + * used for i18n ally + */ +export const t = (v: string) => v; + +export const objectMessage = t('zod.body'); export const safeStringRefine = z .string() .refine( (v) => v !== '__proto__' && v !== 'constructor' && v !== 'prototype', - { message: 'zod.stringMalformed' } + { message: t('zod.stringMalformed') } ); // TODO: create custom getValidatedRouterParams and readValidatedBody wrapper -export const EnabledSchema = z.boolean({ message: 'zod.enabled' }); +export const EnabledSchema = z.boolean({ message: t('zod.enabled') }); export const MtuSchema = z - .number({ message: 'zod.mtu' }) - .min(1280, { message: 'zod.mtuMin' }) - .max(9000, { message: 'zod.mtuMax' }); + .number({ message: t('zod.mtu') }) + .min(1280, { message: t('zod.mtu') }) + .max(9000, { message: t('zod.mtu') }); export const PortSchema = z - .number({ message: 'zod.port' }) - .min(1, { message: 'zod.portMin' }) - .max(65535, { message: 'zod.portMax' }); + .number({ message: t('zod.port') }) + .min(1, { message: t('zod.port') }) + .max(65535, { message: t('zod.port') }); export const PersistentKeepaliveSchema = z - .number({ message: 'zod.persistentKeepalive' }) - .min(0, 'zod.persistentKeepaliveMin') - .max(65535, 'zod.persistentKeepaliveMax'); + .number({ message: t('zod.persistentKeepalive') }) + .min(0, t('zod.persistentKeepalive')) + .max(65535, t('zod.persistentKeepalive')); export const AddressSchema = z - .string({ message: 'zod.address' }) - .min(1, { message: 'zod.addressMin' }) + .string({ message: t('zod.address') }) + .min(1, { message: t('zod.address') }) .pipe(safeStringRefine); export const DnsSchema = z - .array(AddressSchema, { message: 'zod.dns' }) - .min(1, 'zod.dnsMin'); + .array(AddressSchema, { message: t('zod.dns') }) + .min(1, t('zod.dns')); export const AllowedIpsSchema = z - .array(AddressSchema, { message: 'zod.allowedIps' }) - .min(1, { message: 'zod.allowedIpsMin' }); + .array(AddressSchema, { message: t('zod.allowedIps') }) + .min(1, { message: t('zod.allowedIps') }); export const schemaForType = () => @@ -52,26 +59,78 @@ export const schemaForType = export function validateZod( schema: ZodSchema, - event?: H3Event + event: H3Event ) { return async (data: unknown) => { - let t: null | ((key: string) => string) = null; - - if (event) { - t = await useTranslation(event); - } - try { return await schema.parseAsync(data); } catch (error) { let message = 'Unexpected Error'; if (error instanceof z.ZodError) { + const t = await useTranslation(event); + message = error.issues .map((v) => { let m = v.message; if (t) { - m = t(m); + let newMessage = null; + if (v.message.startsWith('zod.')) { + switch (v.code) { + case 'too_small': + switch (v.type) { + case 'string': + newMessage = t('zod.generic.stringMin', [ + t(v.message), + v.minimum, + ]); + break; + case 'number': + newMessage = t('zod.generic.numberMin', [ + t(v.message), + v.minimum, + ]); + break; + } + break; + case 'invalid_type': { + if (v.received === 'null' || v.received === 'undefined') { + newMessage = t('zod.generic.required', [ + v.path.join('.'), + ]); + } else { + switch (v.expected) { + case 'string': + newMessage = t('zod.generic.validString', [ + t(v.message), + ]); + break; + case 'boolean': + newMessage = t('zod.generic.validBoolean', [ + t(v.message), + ]); + break; + case 'number': + newMessage = t('zod.generic.validNumber', [ + t(v.message), + ]); + break; + case 'array': + newMessage = t('zod.generic.validArray', [ + t(v.message), + ]); + break; + } + } + break; + } + } + } + if (newMessage) { + m = newMessage; + } else { + m = t(v.message); + } } return m;