mirror of
https://github.com/documenso/documenso.git
synced 2026-07-27 18:35:05 +10:00
fix: replace z.string().email() with RFC 5322 compliant ZEmail/zEmail (#2655)
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { ZEmail } from '../../../utils/zod';
|
||||
import type { JobDefinition } from '../../client/_internal/job';
|
||||
|
||||
const SEND_CONFIRMATION_EMAIL_JOB_DEFINITION_ID = 'send.signup.confirmation.email';
|
||||
|
||||
const SEND_CONFIRMATION_EMAIL_JOB_DEFINITION_SCHEMA = z.object({
|
||||
email: z.string().email(),
|
||||
email: ZEmail,
|
||||
force: z.boolean().optional(),
|
||||
});
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { BulkSendCompleteEmail } from '@documenso/email/templates/bulk-send-comp
|
||||
import { sendDocument } from '@documenso/lib/server-only/document/send-document';
|
||||
import { createDocumentFromTemplate } from '@documenso/lib/server-only/template/create-document-from-template';
|
||||
import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id';
|
||||
import { zEmail } from '@documenso/lib/utils/zod';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { getI18nInstance } from '../../../client-only/providers/i18n-server';
|
||||
@@ -22,7 +23,7 @@ import type { TBulkSendTemplateJobDefinition } from './bulk-send-template';
|
||||
const ZRecipientRowSchema = z.object({
|
||||
name: z.string().optional(),
|
||||
email: z.union([
|
||||
z.string().email({ message: 'Value must be a valid email or empty string' }),
|
||||
zEmail('Value must be a valid email or empty string'),
|
||||
z.string().max(0, { message: 'Value must be a valid email or empty string' }),
|
||||
]),
|
||||
});
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { RecipientRole } from '@prisma/client';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { ZEmail } from '../utils/zod';
|
||||
|
||||
export const ZDefaultRecipientSchema = z.object({
|
||||
email: z.string().email(),
|
||||
email: ZEmail,
|
||||
name: z.string(),
|
||||
role: z.nativeEnum(RecipientRole),
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { DocumentSource, FieldType } from '@prisma/client';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { ZEmail } from '../utils/zod';
|
||||
import { ZRecipientAccessAuthTypesSchema, ZRecipientActionAuthTypesSchema } from './document-auth';
|
||||
|
||||
export const ZDocumentAuditLogTypeSchema = z.enum([
|
||||
@@ -279,7 +280,7 @@ export const ZDocumentAuditLogEventDocumentCreatedSchema = z.object({
|
||||
z.object({
|
||||
type: z.literal(DocumentSource.TEMPLATE_DIRECT_LINK),
|
||||
templateId: z.number(),
|
||||
directRecipientEmail: z.string().email(),
|
||||
directRecipientEmail: ZEmail,
|
||||
}),
|
||||
])
|
||||
.optional(),
|
||||
|
||||
@@ -6,6 +6,7 @@ import { VALID_DATE_FORMAT_VALUES } from '@documenso/lib/constants/date-formats'
|
||||
import { ZEnvelopeExpirationPeriod } from '@documenso/lib/constants/envelope-expiration';
|
||||
import { SUPPORTED_LANGUAGE_CODES } from '@documenso/lib/constants/i18n';
|
||||
import { isValidRedirectUrl } from '@documenso/lib/utils/is-valid-redirect-url';
|
||||
import { ZEmail } from '@documenso/lib/utils/zod';
|
||||
import { DocumentMetaSchema } from '@documenso/prisma/generated/zod/modelSchema/DocumentMetaSchema';
|
||||
|
||||
import { ZDocumentEmailSettingsSchema } from './document-email';
|
||||
@@ -127,7 +128,7 @@ export const ZDocumentMetaCreateSchema = z.object({
|
||||
uploadSignatureEnabled: ZDocumentMetaUploadSignatureEnabledSchema.optional(),
|
||||
drawSignatureEnabled: ZDocumentMetaDrawSignatureEnabledSchema.optional(),
|
||||
emailId: z.string().nullish(),
|
||||
emailReplyTo: z.string().email().nullish(),
|
||||
emailReplyTo: ZEmail.nullish(),
|
||||
emailSettings: ZDocumentEmailSettingsSchema.nullish(),
|
||||
envelopeExpirationPeriod: ZEnvelopeExpirationPeriod.nullish(),
|
||||
});
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { ZEmail } from '../utils/zod';
|
||||
import { ZBaseEmbedDataSchema } from './embed-base-schemas';
|
||||
|
||||
export const ZDirectTemplateEmbedDataSchema = ZBaseEmbedDataSchema.extend({
|
||||
email: z
|
||||
.union([z.literal(''), z.string().email()])
|
||||
.union([z.literal(''), ZEmail])
|
||||
.optional()
|
||||
.transform((value) => value || undefined),
|
||||
lockEmail: z.boolean().optional().default(false),
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { ZEmail } from '../utils/zod';
|
||||
import { ZBaseEmbedDataSchema } from './embed-base-schemas';
|
||||
|
||||
export const ZSignDocumentEmbedDataSchema = ZBaseEmbedDataSchema.extend({
|
||||
email: z
|
||||
.union([z.literal(''), z.string().email()])
|
||||
.union([z.literal(''), ZEmail])
|
||||
.optional()
|
||||
.transform((value) => value || undefined),
|
||||
lockEmail: z.boolean().optional().default(false),
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { ZEmail } from '../utils/zod';
|
||||
import { ZBaseEmbedDataSchema } from './embed-base-schemas';
|
||||
|
||||
export const ZEmbedMultiSignDocumentSchema = ZBaseEmbedDataSchema.extend({
|
||||
email: z
|
||||
.union([z.literal(''), z.string().email()])
|
||||
.union([z.literal(''), ZEmail])
|
||||
.optional()
|
||||
.transform((value) => value || undefined),
|
||||
lockEmail: z.boolean().optional().default(false),
|
||||
|
||||
@@ -4,6 +4,7 @@ import { RecipientSchema } from '@documenso/prisma/generated/zod/modelSchema/Rec
|
||||
import { TeamSchema } from '@documenso/prisma/generated/zod/modelSchema/TeamSchema';
|
||||
import { UserSchema } from '@documenso/prisma/generated/zod/modelSchema/UserSchema';
|
||||
|
||||
import { zEmail } from '../utils/zod';
|
||||
import { ZFieldSchema } from './field';
|
||||
|
||||
/**
|
||||
@@ -119,5 +120,5 @@ export const ZEnvelopeRecipientManySchema = ZRecipientManySchema.omit({
|
||||
|
||||
export const ZRecipientEmailSchema = z.union([
|
||||
z.literal(''),
|
||||
z.string().trim().toLowerCase().email({ message: 'Invalid email' }).max(254),
|
||||
zEmail('Invalid email').trim().toLowerCase().max(254),
|
||||
]);
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
ZTextFieldMeta,
|
||||
} from '@documenso/lib/types/field-meta';
|
||||
import { toCheckboxCustomText, toRadioCustomText } from '@documenso/lib/utils/fields';
|
||||
import { ZEmail } from '@documenso/lib/utils/zod';
|
||||
import type { TSignEnvelopeFieldValue } from '@documenso/trpc/server/envelope-router/sign-envelope-field.types';
|
||||
import { checkboxValidationSigns } from '@documenso/ui/primitives/document-flow/field-items-advanced-settings/constants';
|
||||
|
||||
@@ -37,7 +38,7 @@ export const extractFieldInsertionValues = ({
|
||||
}: ExtractFieldInsertionValuesOptions): { customText: string; inserted: boolean } => {
|
||||
return match(fieldValue)
|
||||
.with({ type: FieldType.EMAIL }, (fieldValue) => {
|
||||
const parsedEmailValue = z.string().email().nullable().safeParse(fieldValue.value);
|
||||
const parsedEmailValue = ZEmail.nullable().safeParse(fieldValue.value);
|
||||
|
||||
if (!parsedEmailValue.success) {
|
||||
throw new AppError(AppErrorCode.INVALID_BODY, {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { Envelope } from '@prisma/client';
|
||||
import { type Field, type Recipient, RecipientRole, SigningStatus } from '@prisma/client';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { isSignatureFieldType } from '@documenso/prisma/guards/is-signature-field';
|
||||
|
||||
import { NEXT_PUBLIC_WEBAPP_URL } from '../constants/app';
|
||||
import { AppError, AppErrorCode } from '../errors/app-error';
|
||||
import { extractLegacyIds } from '../universal/id';
|
||||
import { ZEmail } from './zod';
|
||||
|
||||
/**
|
||||
* Roles that require fields to be assigned before a document can be distributed.
|
||||
@@ -93,7 +93,7 @@ export const mapRecipientToLegacyRecipient = (
|
||||
};
|
||||
|
||||
export const isRecipientEmailValidForSending = (recipient: Pick<Recipient, 'email'>) => {
|
||||
return z.string().email().safeParse(recipient.email).success;
|
||||
return ZEmail.safeParse(recipient.email).success;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
/**
|
||||
* RFC 5322 compliant email regex.
|
||||
*
|
||||
* This is more permissive than Zod's built-in `.email()` validator which rejects
|
||||
* valid international characters (e.g. "Søren@gmail.com").
|
||||
*
|
||||
* Compiled once at module level to avoid re-compilation on every validation call.
|
||||
*/
|
||||
const EMAIL_REGEX =
|
||||
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~\u{0080}-\u{FFFF}-]+@[a-zA-Z0-9\u{0080}-\u{FFFF}](?:[a-zA-Z0-9\u{0080}-\u{FFFF}-]{0,61}[a-zA-Z0-9\u{0080}-\u{FFFF}])?(?:\.[a-zA-Z0-9\u{0080}-\u{FFFF}](?:[a-zA-Z0-9\u{0080}-\u{FFFF}-]{0,61}[a-zA-Z0-9\u{0080}-\u{FFFF}])?)*$/u;
|
||||
|
||||
const DEFAULT_EMAIL_MESSAGE = 'Invalid email address';
|
||||
|
||||
/**
|
||||
* A Zod schema for validating email addresses using an RFC 5322 compliant regex.
|
||||
*
|
||||
* This supports international characters in the local part and domain
|
||||
* (e.g. "Søren@gmail.com", "user@dömain.com").
|
||||
*
|
||||
* Use `zEmail()` if you need to pass a custom error message.
|
||||
*/
|
||||
export const ZEmail = z.string().regex(EMAIL_REGEX, { message: DEFAULT_EMAIL_MESSAGE });
|
||||
|
||||
/**
|
||||
* Creates a Zod email schema with an optional custom error message.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // With default message
|
||||
* zEmail()
|
||||
*
|
||||
* // With custom message string
|
||||
* zEmail('Email is invalid')
|
||||
*
|
||||
* // With message object
|
||||
* zEmail({ message: 'Email is invalid' })
|
||||
* ```
|
||||
*/
|
||||
export const zEmail = (options?: string | { message?: string }) => {
|
||||
const message =
|
||||
typeof options === 'string' ? options : (options?.message ?? DEFAULT_EMAIL_MESSAGE);
|
||||
|
||||
return z.string().regex(EMAIL_REGEX, { message });
|
||||
};
|
||||
Reference in New Issue
Block a user