diff --git a/Makefile b/Makefile index 02d97f3..793a348 100644 --- a/Makefile +++ b/Makefile @@ -12,12 +12,6 @@ build-arm: build-x86: docker buildx build --platform linux/amd64 -t fosrl/pangolin:latest . -auth-ecr: - aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/g5j5p7x0 - -build-x86-ecr: - docker buildx build --platform linux/amd64 -t 216989133116.dkr.ecr.us-east-1.amazonaws.com/pangolin:latest --push . - build: docker build -t fosrl/pangolin:latest . diff --git a/server/db/schema.ts b/server/db/schema.ts index cf5ad53..16d8ada 100644 --- a/server/db/schema.ts +++ b/server/db/schema.ts @@ -378,7 +378,7 @@ export const resourceRules = sqliteTable("resourceRules", { .notNull() .references(() => resources.resourceId, { onDelete: "cascade" }), action: text("action").notNull(), // ACCEPT, DROP - match: text("match").notNull(), // CIDR, PATH + match: text("match").notNull(), // CIDR, PATH, IP value: text("value").notNull() }); diff --git a/server/routers/badger/verifySession.ts b/server/routers/badger/verifySession.ts index a65b24a..a4a2944 100644 --- a/server/routers/badger/verifySession.ts +++ b/server/routers/badger/verifySession.ts @@ -494,6 +494,10 @@ async function checkRules( rule.match == "CIDR" && isIpInCidr(clientIp, rule.value) && rule.action === "DROP") || + (clientIp && + rule.match == "IP" && + clientIp == rule.value && + rule.action === "DROP") || (path && rule.match == "PATH" && urlGlobToRegex(rule.value).test(path) && @@ -516,6 +520,9 @@ async function checkRules( (clientIp && rule.match == "CIDR" && isIpInCidr(clientIp, rule.value)) || + (clientIp && + rule.match == "IP" && + clientIp == rule.value) || (path && rule.match == "PATH" && urlGlobToRegex(rule.value).test(path)) diff --git a/server/routers/resource/createResourceRule.ts b/server/routers/resource/createResourceRule.ts index f01ed11..24b08fc 100644 --- a/server/routers/resource/createResourceRule.ts +++ b/server/routers/resource/createResourceRule.ts @@ -12,7 +12,7 @@ import { fromError } from "zod-validation-error"; const createResourceRuleSchema = z .object({ action: z.enum(["ACCEPT", "DROP"]), - match: z.enum(["CIDR", "PATH"]), + match: z.enum(["CIDR", "IP", "PATH"]), value: z.string().min(1) }) .strict(); diff --git a/server/routers/resource/updateResourceRule.ts b/server/routers/resource/updateResourceRule.ts index f96ea0f..0eaacc0 100644 --- a/server/routers/resource/updateResourceRule.ts +++ b/server/routers/resource/updateResourceRule.ts @@ -27,7 +27,7 @@ const updateResourceRuleParamsSchema = z const updateResourceRuleSchema = z .object({ action: z.enum(["ACCEPT", "DROP"]).optional(), - match: z.enum(["CIDR", "PATH"]).optional(), + match: z.enum(["CIDR", "IP", "PATH"]).optional(), value: z.string().min(1).optional() }) .strict() diff --git a/src/app/[orgId]/settings/resources/[resourceId]/rules/page.tsx b/src/app/[orgId]/settings/resources/[resourceId]/rules/page.tsx index bffcc9a..6a961a6 100644 --- a/src/app/[orgId]/settings/resources/[resourceId]/rules/page.tsx +++ b/src/app/[orgId]/settings/resources/[resourceId]/rules/page.tsx @@ -101,7 +101,7 @@ export default function ResourceRules(props: { resolver: zodResolver(addRuleSchema), defaultValues: { action: "ACCEPT", - match: "CIDR", + match: "IP", value: "" } }); @@ -167,6 +167,15 @@ export default function ResourceRules(props: { setLoading(false); return; } + if (data.match === "IP" && !isValidIP(data.value)) { + toast({ + variant: "destructive", + title: "Invalid IP", + description: "Please enter a valid IP address" + }); + setLoading(false); + return; + } const newRule: LocalRule = { ...data, @@ -255,6 +264,15 @@ export default function ResourceRules(props: { setLoading(false); return; } + if (rule.match === "IP" && !isValidIP(rule.value)) { + toast({ + variant: "destructive", + title: "Invalid IP", + description: "Please enter a valid IP address" + }); + setLoading(false); + return; + } if (rule.new) { const res = await api.put(`/resource/${params.resourceId}/rule`, data); @@ -336,7 +354,7 @@ export default function ResourceRules(props: { cell: ({ row }) => ( @@ -527,8 +546,11 @@ export default function ResourceRules(props: { + + IP + - CIDR + IP Range {resource.http && ( @@ -657,6 +679,21 @@ function isValidCIDR(cidr: string): boolean { }); } +function isValidIP(ip: string): boolean { + const ipPattern = /^([0-9]{1,3}\.){3}[0-9]{1,3}$/; + + if (!ipPattern.test(ip)) { + return false; + } + + const octets = ip.split("."); + + return octets.every((octet) => { + const num = parseInt(octet, 10); + return num >= 0 && num <= 255; + }); +} + function isValidUrlGlobPattern(pattern: string): boolean { // Remove leading slash if present pattern = pattern.startsWith("/") ? pattern.slice(1) : pattern;