From dc7bd41eb90aefc7512dda48a81a5c71f98e5690 Mon Sep 17 00:00:00 2001 From: Owen Schwartz Date: Tue, 7 Jan 2025 21:52:45 -0500 Subject: [PATCH] Complex regex for domains/ips --- server/routers/target/createTarget.ts | 30 ++++++++++++++++++- server/routers/target/updateTarget.ts | 30 ++++++++++++++++++- .../[resourceId]/connectivity/page.tsx | 30 ++++++++++++++++++- 3 files changed, 87 insertions(+), 3 deletions(-) diff --git a/server/routers/target/createTarget.ts b/server/routers/target/createTarget.ts index de9ac1f3..e7ae3aca 100644 --- a/server/routers/target/createTarget.ts +++ b/server/routers/target/createTarget.ts @@ -12,6 +12,34 @@ import { isIpInCidr } from "@server/lib/ip"; import { fromError } from "zod-validation-error"; import { addTargets } from "../newt/targets"; +// Regular expressions for validation +const DOMAIN_REGEX = + /^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; +const IPV4_REGEX = + /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; +const IPV6_REGEX = /^(?:[A-F0-9]{1,4}:){7}[A-F0-9]{1,4}$/i; + +// Schema for domain names and IP addresses +const domainSchema = z + .string() + .min(1, "Domain cannot be empty") + .max(255, "Domain name too long") + .refine( + (value) => { + // Check if it's a valid IP address (v4 or v6) + if (IPV4_REGEX.test(value) || IPV6_REGEX.test(value)) { + return true; + } + + // Check if it's a valid domain name + return DOMAIN_REGEX.test(value); + }, + { + message: "Invalid domain name or IP address format", + path: ["domain"] + } + ); + const createTargetParamsSchema = z .object({ resourceId: z @@ -23,7 +51,7 @@ const createTargetParamsSchema = z const createTargetSchema = z .object({ - ip: z.string(), + ip: domainSchema, method: z.string().min(1).max(10), port: z.number().int().min(1).max(65535), protocol: z.string().optional(), diff --git a/server/routers/target/updateTarget.ts b/server/routers/target/updateTarget.ts index 8d774bac..77f127e8 100644 --- a/server/routers/target/updateTarget.ts +++ b/server/routers/target/updateTarget.ts @@ -11,6 +11,34 @@ import { fromError } from "zod-validation-error"; import { addPeer } from "../gerbil/peers"; import { addTargets } from "../newt/targets"; +// Regular expressions for validation +const DOMAIN_REGEX = + /^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; +const IPV4_REGEX = + /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; +const IPV6_REGEX = /^(?:[A-F0-9]{1,4}:){7}[A-F0-9]{1,4}$/i; + +// Schema for domain names and IP addresses +const domainSchema = z + .string() + .min(1, "Domain cannot be empty") + .max(255, "Domain name too long") + .refine( + (value) => { + // Check if it's a valid IP address (v4 or v6) + if (IPV4_REGEX.test(value) || IPV6_REGEX.test(value)) { + return true; + } + + // Check if it's a valid domain name + return DOMAIN_REGEX.test(value); + }, + { + message: "Invalid domain name or IP address format", + path: ["domain"] + } + ); + const updateTargetParamsSchema = z .object({ targetId: z.string().transform(Number).pipe(z.number().int().positive()) @@ -19,7 +47,7 @@ const updateTargetParamsSchema = z const updateTargetBodySchema = z .object({ - ip: z.string().optional(), + ip: domainSchema.optional(), method: z.string().min(1).max(10).optional(), port: z.number().int().min(1).max(65535).optional(), enabled: z.boolean().optional() diff --git a/src/app/[orgId]/settings/resources/[resourceId]/connectivity/page.tsx b/src/app/[orgId]/settings/resources/[resourceId]/connectivity/page.tsx index cb2ff5ac..a6d8821b 100644 --- a/src/app/[orgId]/settings/resources/[resourceId]/connectivity/page.tsx +++ b/src/app/[orgId]/settings/resources/[resourceId]/connectivity/page.tsx @@ -63,8 +63,36 @@ import { } from "@app/components/Settings"; import { SwitchInput } from "@app/components/SwitchInput"; +// Regular expressions for validation +const DOMAIN_REGEX = + /^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; +const IPV4_REGEX = + /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; +const IPV6_REGEX = /^(?:[A-F0-9]{1,4}:){7}[A-F0-9]{1,4}$/i; + +// Schema for domain names and IP addresses +const domainSchema = z + .string() + .min(1, "Domain cannot be empty") + .max(255, "Domain name too long") + .refine( + (value) => { + // Check if it's a valid IP address (v4 or v6) + if (IPV4_REGEX.test(value) || IPV6_REGEX.test(value)) { + return true; + } + + // Check if it's a valid domain name + return DOMAIN_REGEX.test(value); + }, + { + message: "Invalid domain name or IP address format", + path: ["domain"] + } + ); + const addTargetSchema = z.object({ - ip: z.string(), + ip: domainSchema, method: z.string(), port: z.coerce.number().int().positive() // protocol: z.string(),