mirror of
https://github.com/fosrl/pangolin.git
synced 2025-07-10 14:04:51 +02:00
create target validator and add url validator
This commit is contained in:
parent
a418195b28
commit
d5a220a004
4 changed files with 46 additions and 96 deletions
|
@ -42,7 +42,10 @@ export function isValidUrlGlobPattern(pattern: string): boolean {
|
||||||
if (char === "%" && j + 2 < segment.length) {
|
if (char === "%" && j + 2 < segment.length) {
|
||||||
const hex1 = segment[j + 1];
|
const hex1 = segment[j + 1];
|
||||||
const hex2 = segment[j + 2];
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
j += 2; // Skip the next two characters
|
j += 2; // Skip the next two characters
|
||||||
|
@ -61,3 +64,33 @@ export function isValidUrlGlobPattern(pattern: string): boolean {
|
||||||
|
|
||||||
return true;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -12,34 +12,7 @@ import { fromError } from "zod-validation-error";
|
||||||
import { addTargets } from "../newt/targets";
|
import { addTargets } from "../newt/targets";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { pickPort } from "./helpers";
|
import { pickPort } from "./helpers";
|
||||||
|
import { isTargetValid } from "@server/lib/validators";
|
||||||
// // 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
|
const createTargetParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -52,7 +25,7 @@ const createTargetParamsSchema = z
|
||||||
|
|
||||||
const createTargetSchema = z
|
const createTargetSchema = z
|
||||||
.object({
|
.object({
|
||||||
ip: z.string().min(1).max(255),
|
ip: z.string().refine(isTargetValid),
|
||||||
method: z.string().optional().nullable(),
|
method: z.string().optional().nullable(),
|
||||||
port: z.number().int().min(1).max(65535),
|
port: z.number().int().min(1).max(65535),
|
||||||
enabled: z.boolean().default(true)
|
enabled: z.boolean().default(true)
|
||||||
|
|
|
@ -11,34 +11,7 @@ import { fromError } from "zod-validation-error";
|
||||||
import { addPeer } from "../gerbil/peers";
|
import { addPeer } from "../gerbil/peers";
|
||||||
import { addTargets } from "../newt/targets";
|
import { addTargets } from "../newt/targets";
|
||||||
import { pickPort } from "./helpers";
|
import { pickPort } from "./helpers";
|
||||||
|
import { isTargetValid } from "@server/lib/validators";
|
||||||
// // 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
|
const updateTargetParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -48,7 +21,7 @@ const updateTargetParamsSchema = z
|
||||||
|
|
||||||
const updateTargetBodySchema = z
|
const updateTargetBodySchema = z
|
||||||
.object({
|
.object({
|
||||||
ip: z.string().min(1).max(255),
|
ip: z.string().refine(isTargetValid),
|
||||||
method: z.string().min(1).max(10).optional().nullable(),
|
method: z.string().min(1).max(10).optional().nullable(),
|
||||||
port: z.number().int().min(1).max(65535).optional(),
|
port: z.number().int().min(1).max(65535).optional(),
|
||||||
enabled: z.boolean().optional()
|
enabled: z.boolean().optional()
|
||||||
|
|
|
@ -62,40 +62,11 @@ import {
|
||||||
SettingsSectionFooter
|
SettingsSectionFooter
|
||||||
} from "@app/components/Settings";
|
} from "@app/components/Settings";
|
||||||
import { SwitchInput } from "@app/components/SwitchInput";
|
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";
|
import { useRouter } from "next/navigation";
|
||||||
|
import { isTargetValid } from "@server/lib/validators";
|
||||||
// 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({
|
const addTargetSchema = z.object({
|
||||||
ip: z.string().min(1).max(255),
|
ip: z.string().refine(isTargetValid),
|
||||||
method: z.string().nullable(),
|
method: z.string().nullable(),
|
||||||
port: z.coerce.number().int().positive()
|
port: z.coerce.number().int().positive()
|
||||||
// protocol: z.string(),
|
// protocol: z.string(),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue