Bladeren bron

create target validator and add url validator

Milo Schwartz 5 maanden geleden
bovenliggende
commit
d5a220a004

+ 40 - 7
server/lib/validators.ts

@@ -11,7 +11,7 @@ export function isValidIP(ip: string): boolean {
 export function isValidUrlGlobPattern(pattern: string): boolean {
     // Remove leading slash if present
     pattern = pattern.startsWith("/") ? pattern.slice(1) : pattern;
-    
+
     // Empty string is not valid
     if (!pattern) {
         return false;
@@ -19,11 +19,11 @@ export function isValidUrlGlobPattern(pattern: string): boolean {
 
     // Split path into segments
     const segments = pattern.split("/");
-    
+
     // Check each segment
     for (let i = 0; i < segments.length; i++) {
         const segment = segments[i];
-        
+
         // Empty segments are not allowed (double slashes), except at the end
         if (!segment && i !== segments.length - 1) {
             return false;
@@ -37,12 +37,15 @@ export function isValidUrlGlobPattern(pattern: string): boolean {
         // Check each character in the segment
         for (let j = 0; j < segment.length; j++) {
             const char = segment[j];
-            
+
             // Check for percent-encoded sequences
             if (char === "%" && j + 2 < segment.length) {
                 const hex1 = segment[j + 1];
                 const hex2 = segment[j + 2];
-                if (!/^[0-9A-Fa-f]$/.test(hex1) || !/^[0-9A-Fa-f]$/.test(hex2)) {
+                if (
+                    !/^[0-9A-Fa-f]$/.test(hex1) ||
+                    !/^[0-9A-Fa-f]$/.test(hex2)
+                ) {
                     return false;
                 }
                 j += 2; // Skip the next two characters
@@ -58,6 +61,36 @@ export function isValidUrlGlobPattern(pattern: string): boolean {
             }
         }
     }
-    
+
     return true;
-}
+}
+
+export function isUrlValid(url: string | undefined) {
+    if (!url) return true; // the link is optional in the schema so if it's empty it's valid
+    var pattern = new RegExp(
+        "^(https?:\\/\\/)?" + // protocol
+            "((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + // domain name
+            "((\\d{1,3}\\.){3}\\d{1,3}))" + // OR ip (v4) address
+            "(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*" + // port and path
+            "(\\?[;&a-z\\d%_.~+=-]*)?" + // query string
+            "(\\#[-a-z\\d_]*)?$",
+        "i"
+    );
+    return !!pattern.test(url);
+}
+
+export function isTargetValid(value: string | undefined) {
+    if (!value) return true;
+
+    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;
+
+    if (IPV4_REGEX.test(value) || IPV6_REGEX.test(value)) {
+        return true;
+    }
+
+    return DOMAIN_REGEX.test(value);
+}

+ 2 - 29
server/routers/target/createTarget.ts

@@ -12,34 +12,7 @@ import { fromError } from "zod-validation-error";
 import { addTargets } from "../newt/targets";
 import { eq } from "drizzle-orm";
 import { pickPort } from "./helpers";
-
-// // 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"]
-//         }
-//     );
+import { isTargetValid } from "@server/lib/validators";
 
 const createTargetParamsSchema = z
     .object({
@@ -52,7 +25,7 @@ const createTargetParamsSchema = z
 
 const createTargetSchema = z
     .object({
-        ip: z.string().min(1).max(255),
+        ip: z.string().refine(isTargetValid),
         method: z.string().optional().nullable(),
         port: z.number().int().min(1).max(65535),
         enabled: z.boolean().default(true)

+ 2 - 29
server/routers/target/updateTarget.ts

@@ -11,34 +11,7 @@ import { fromError } from "zod-validation-error";
 import { addPeer } from "../gerbil/peers";
 import { addTargets } from "../newt/targets";
 import { pickPort } from "./helpers";
-
-// // 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"]
-//         }
-//     );
+import { isTargetValid } from "@server/lib/validators";
 
 const updateTargetParamsSchema = z
     .object({
@@ -48,7 +21,7 @@ const updateTargetParamsSchema = z
 
 const updateTargetBodySchema = z
     .object({
-        ip: z.string().min(1).max(255),
+        ip: z.string().refine(isTargetValid),
         method: z.string().min(1).max(10).optional().nullable(),
         port: z.number().int().min(1).max(65535).optional(),
         enabled: z.boolean().optional()

+ 2 - 31
src/app/[orgId]/settings/resources/[resourceId]/connectivity/page.tsx

@@ -62,40 +62,11 @@ import {
     SettingsSectionFooter
 } from "@app/components/Settings";
 import { SwitchInput } from "@app/components/SwitchInput";
-import { useSiteContext } from "@app/hooks/useSiteContext";
-import { InfoPopup } from "@app/components/ui/info-popup";
 import { useRouter } from "next/navigation";
-
-// 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"]
-//         }
-//     );
+import { isTargetValid } from "@server/lib/validators";
 
 const addTargetSchema = z.object({
-    ip: z.string().min(1).max(255),
+    ip: z.string().refine(isTargetValid),
     method: z.string().nullable(),
     port: z.coerce.number().int().positive()
     // protocol: z.string(),