fix: use native URL parser instead of wrong regex (#1206)

Updates the current regex based approach for validating redirect urls to 
instead use the native URL constructor which is available in browsers and 
Node.js and handles several valid cases that were previously not working.
This commit is contained in:
aeris
2024-07-31 07:26:05 +02:00
committed by GitHub
parent 0c744a1123
commit a9025b5d97
7 changed files with 38 additions and 19 deletions

View File

@ -1,2 +0,0 @@
export const URL_REGEX =
/^(https?):\/\/(?:www\.)?(?:[a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z0-9()]{2,}(?:\/[a-zA-Z0-9-._?&=/]*)?$/i;

View File

@ -1,12 +1,12 @@
import { z } from 'zod'; import { z } from 'zod';
import { URL_REGEX } from '../constants/url-regex'; import { isValidRedirectUrl } from '../utils/is-valid-redirect-url';
/** /**
* Note this allows empty strings. * Note this allows empty strings.
*/ */
export const ZUrlSchema = z export const ZUrlSchema = z
.string() .string()
.refine((value) => value === undefined || value === '' || URL_REGEX.test(value), { .refine((value) => value === undefined || value === '' || isValidRedirectUrl(value), {
message: 'Please enter a valid URL', message: 'Please enter a valid URL, make sure you include http:// or https:// part of the url.',
}); });

View File

@ -0,0 +1,16 @@
const ALLOWED_PROTOCOLS = ['http', 'https'];
export const isValidRedirectUrl = (value: string) => {
try {
const url = new URL(value);
console.log({ protocol: url.protocol });
if (!ALLOWED_PROTOCOLS.includes(url.protocol.slice(0, -1).toLowerCase())) {
return false;
}
return true;
} catch {
return false;
}
};

View File

@ -1,11 +1,11 @@
import { z } from 'zod'; import { z } from 'zod';
import { URL_REGEX } from '@documenso/lib/constants/url-regex';
import { import {
ZDocumentAccessAuthTypesSchema, ZDocumentAccessAuthTypesSchema,
ZDocumentActionAuthTypesSchema, ZDocumentActionAuthTypesSchema,
} from '@documenso/lib/types/document-auth'; } from '@documenso/lib/types/document-auth';
import { ZBaseTableSearchParamsSchema } from '@documenso/lib/types/search-params'; import { ZBaseTableSearchParamsSchema } from '@documenso/lib/types/search-params';
import { isValidRedirectUrl } from '@documenso/lib/utils/is-valid-redirect-url';
import { FieldType, RecipientRole } from '@documenso/prisma/client'; import { FieldType, RecipientRole } from '@documenso/prisma/client';
export const ZFindDocumentAuditLogsQuerySchema = ZBaseTableSearchParamsSchema.extend({ export const ZFindDocumentAuditLogsQuerySchema = ZBaseTableSearchParamsSchema.extend({
@ -65,8 +65,9 @@ export const ZSetSettingsForDocumentMutationSchema = z.object({
redirectUrl: z redirectUrl: z
.string() .string()
.optional() .optional()
.refine((value) => value === undefined || value === '' || URL_REGEX.test(value), { .refine((value) => value === undefined || value === '' || isValidRedirectUrl(value), {
message: 'Please enter a valid URL', message:
'Please enter a valid URL, make sure you include http:// or https:// part of the url.',
}), }),
}), }),
}); });
@ -131,8 +132,9 @@ export const ZSendDocumentMutationSchema = z.object({
redirectUrl: z redirectUrl: z
.string() .string()
.optional() .optional()
.refine((value) => value === undefined || value === '' || URL_REGEX.test(value), { .refine((value) => value === undefined || value === '' || isValidRedirectUrl(value), {
message: 'Please enter a valid URL', message:
'Please enter a valid URL, make sure you include http:// or https:// part of the url.',
}), }),
}), }),
}); });

View File

@ -1,11 +1,11 @@
import { z } from 'zod'; import { z } from 'zod';
import { URL_REGEX } from '@documenso/lib/constants/url-regex';
import { import {
ZDocumentAccessAuthTypesSchema, ZDocumentAccessAuthTypesSchema,
ZDocumentActionAuthTypesSchema, ZDocumentActionAuthTypesSchema,
} from '@documenso/lib/types/document-auth'; } from '@documenso/lib/types/document-auth';
import { ZBaseTableSearchParamsSchema } from '@documenso/lib/types/search-params'; import { ZBaseTableSearchParamsSchema } from '@documenso/lib/types/search-params';
import { isValidRedirectUrl } from '@documenso/lib/utils/is-valid-redirect-url';
import { TemplateType } from '@documenso/prisma/client'; import { TemplateType } from '@documenso/prisma/client';
import { ZSignFieldWithTokenMutationSchema } from '../field-router/schema'; import { ZSignFieldWithTokenMutationSchema } from '../field-router/schema';
@ -96,8 +96,9 @@ export const ZUpdateTemplateSettingsMutationSchema = z.object({
redirectUrl: z redirectUrl: z
.string() .string()
.optional() .optional()
.refine((value) => value === undefined || value === '' || URL_REGEX.test(value), { .refine((value) => value === undefined || value === '' || isValidRedirectUrl(value), {
message: 'Please enter a valid URL', message:
'Please enter a valid URL, make sure you include http:// or https:// part of the url.',
}), }),
}) })
.optional(), .optional(),

View File

@ -2,11 +2,11 @@ import { z } from 'zod';
import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats'; import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
import { DEFAULT_DOCUMENT_TIME_ZONE } from '@documenso/lib/constants/time-zones'; import { DEFAULT_DOCUMENT_TIME_ZONE } from '@documenso/lib/constants/time-zones';
import { URL_REGEX } from '@documenso/lib/constants/url-regex';
import { import {
ZDocumentAccessAuthTypesSchema, ZDocumentAccessAuthTypesSchema,
ZDocumentActionAuthTypesSchema, ZDocumentActionAuthTypesSchema,
} from '@documenso/lib/types/document-auth'; } from '@documenso/lib/types/document-auth';
import { isValidRedirectUrl } from '@documenso/lib/utils/is-valid-redirect-url';
export const ZMapNegativeOneToUndefinedSchema = z export const ZMapNegativeOneToUndefinedSchema = z
.string() .string()
@ -34,8 +34,9 @@ export const ZAddSettingsFormSchema = z.object({
redirectUrl: z redirectUrl: z
.string() .string()
.optional() .optional()
.refine((value) => value === undefined || value === '' || URL_REGEX.test(value), { .refine((value) => value === undefined || value === '' || isValidRedirectUrl(value), {
message: 'Please enter a valid URL', message:
'Please enter a valid URL, make sure you include http:// or https:// part of the url.',
}), }),
}), }),
}); });

View File

@ -2,11 +2,11 @@ import { z } from 'zod';
import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats'; import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
import { DEFAULT_DOCUMENT_TIME_ZONE } from '@documenso/lib/constants/time-zones'; import { DEFAULT_DOCUMENT_TIME_ZONE } from '@documenso/lib/constants/time-zones';
import { URL_REGEX } from '@documenso/lib/constants/url-regex';
import { import {
ZDocumentAccessAuthTypesSchema, ZDocumentAccessAuthTypesSchema,
ZDocumentActionAuthTypesSchema, ZDocumentActionAuthTypesSchema,
} from '@documenso/lib/types/document-auth'; } from '@documenso/lib/types/document-auth';
import { isValidRedirectUrl } from '@documenso/lib/utils/is-valid-redirect-url';
import { ZMapNegativeOneToUndefinedSchema } from '../document-flow/add-settings.types'; import { ZMapNegativeOneToUndefinedSchema } from '../document-flow/add-settings.types';
@ -27,8 +27,9 @@ export const ZAddTemplateSettingsFormSchema = z.object({
redirectUrl: z redirectUrl: z
.string() .string()
.optional() .optional()
.refine((value) => value === undefined || value === '' || URL_REGEX.test(value), { .refine((value) => value === undefined || value === '' || isValidRedirectUrl(value), {
message: 'Please enter a valid URL', message:
'Please enter a valid URL, make sure you include http:// or https:// part of the url.',
}), }),
}), }),
}); });