mirror of
https://github.com/fosrl/pangolin.git
synced 2025-05-12 13:20:35 +01:00
Seperate ip and cidr
This commit is contained in:
parent
5b44ffa2fb
commit
3c99fbb1ef
6 changed files with 51 additions and 13 deletions
6
Makefile
6
Makefile
|
@ -12,12 +12,6 @@ build-arm:
|
||||||
build-x86:
|
build-x86:
|
||||||
docker buildx build --platform linux/amd64 -t fosrl/pangolin:latest .
|
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:
|
build:
|
||||||
docker build -t fosrl/pangolin:latest .
|
docker build -t fosrl/pangolin:latest .
|
||||||
|
|
||||||
|
|
|
@ -378,7 +378,7 @@ export const resourceRules = sqliteTable("resourceRules", {
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => resources.resourceId, { onDelete: "cascade" }),
|
.references(() => resources.resourceId, { onDelete: "cascade" }),
|
||||||
action: text("action").notNull(), // ACCEPT, DROP
|
action: text("action").notNull(), // ACCEPT, DROP
|
||||||
match: text("match").notNull(), // CIDR, PATH
|
match: text("match").notNull(), // CIDR, PATH, IP
|
||||||
value: text("value").notNull()
|
value: text("value").notNull()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -494,6 +494,10 @@ async function checkRules(
|
||||||
rule.match == "CIDR" &&
|
rule.match == "CIDR" &&
|
||||||
isIpInCidr(clientIp, rule.value) &&
|
isIpInCidr(clientIp, rule.value) &&
|
||||||
rule.action === "DROP") ||
|
rule.action === "DROP") ||
|
||||||
|
(clientIp &&
|
||||||
|
rule.match == "IP" &&
|
||||||
|
clientIp == rule.value &&
|
||||||
|
rule.action === "DROP") ||
|
||||||
(path &&
|
(path &&
|
||||||
rule.match == "PATH" &&
|
rule.match == "PATH" &&
|
||||||
urlGlobToRegex(rule.value).test(path) &&
|
urlGlobToRegex(rule.value).test(path) &&
|
||||||
|
@ -516,6 +520,9 @@ async function checkRules(
|
||||||
(clientIp &&
|
(clientIp &&
|
||||||
rule.match == "CIDR" &&
|
rule.match == "CIDR" &&
|
||||||
isIpInCidr(clientIp, rule.value)) ||
|
isIpInCidr(clientIp, rule.value)) ||
|
||||||
|
(clientIp &&
|
||||||
|
rule.match == "IP" &&
|
||||||
|
clientIp == rule.value) ||
|
||||||
(path &&
|
(path &&
|
||||||
rule.match == "PATH" &&
|
rule.match == "PATH" &&
|
||||||
urlGlobToRegex(rule.value).test(path))
|
urlGlobToRegex(rule.value).test(path))
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { fromError } from "zod-validation-error";
|
||||||
const createResourceRuleSchema = z
|
const createResourceRuleSchema = z
|
||||||
.object({
|
.object({
|
||||||
action: z.enum(["ACCEPT", "DROP"]),
|
action: z.enum(["ACCEPT", "DROP"]),
|
||||||
match: z.enum(["CIDR", "PATH"]),
|
match: z.enum(["CIDR", "IP", "PATH"]),
|
||||||
value: z.string().min(1)
|
value: z.string().min(1)
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
|
@ -27,7 +27,7 @@ const updateResourceRuleParamsSchema = z
|
||||||
const updateResourceRuleSchema = z
|
const updateResourceRuleSchema = z
|
||||||
.object({
|
.object({
|
||||||
action: z.enum(["ACCEPT", "DROP"]).optional(),
|
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()
|
value: z.string().min(1).optional()
|
||||||
})
|
})
|
||||||
.strict()
|
.strict()
|
||||||
|
|
|
@ -101,7 +101,7 @@ export default function ResourceRules(props: {
|
||||||
resolver: zodResolver(addRuleSchema),
|
resolver: zodResolver(addRuleSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
action: "ACCEPT",
|
action: "ACCEPT",
|
||||||
match: "CIDR",
|
match: "IP",
|
||||||
value: ""
|
value: ""
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -167,6 +167,15 @@ export default function ResourceRules(props: {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
return;
|
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 = {
|
const newRule: LocalRule = {
|
||||||
...data,
|
...data,
|
||||||
|
@ -255,6 +264,15 @@ export default function ResourceRules(props: {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
return;
|
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) {
|
if (rule.new) {
|
||||||
const res = await api.put(`/resource/${params.resourceId}/rule`, data);
|
const res = await api.put(`/resource/${params.resourceId}/rule`, data);
|
||||||
|
@ -336,7 +354,7 @@ export default function ResourceRules(props: {
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<Select
|
<Select
|
||||||
defaultValue={row.original.match}
|
defaultValue={row.original.match}
|
||||||
onValueChange={(value: "CIDR" | "PATH") =>
|
onValueChange={(value: "CIDR" | "IP" | "PATH") =>
|
||||||
updateRule(row.original.ruleId, { match: value })
|
updateRule(row.original.ruleId, { match: value })
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -344,7 +362,8 @@ export default function ResourceRules(props: {
|
||||||
{row.original.match}
|
{row.original.match}
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="CIDR">CIDR</SelectItem>
|
<SelectItem value="IP">IP</SelectItem>
|
||||||
|
<SelectItem value="CIDR">IP Range</SelectItem>
|
||||||
<SelectItem value="PATH">PATH</SelectItem>
|
<SelectItem value="PATH">PATH</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
@ -527,8 +546,11 @@ export default function ResourceRules(props: {
|
||||||
<SelectValue />
|
<SelectValue />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
|
<SelectItem value="IP">
|
||||||
|
IP
|
||||||
|
</SelectItem>
|
||||||
<SelectItem value="CIDR">
|
<SelectItem value="CIDR">
|
||||||
CIDR
|
IP Range
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
{resource.http && (
|
{resource.http && (
|
||||||
<SelectItem value="PATH">
|
<SelectItem value="PATH">
|
||||||
|
@ -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 {
|
function isValidUrlGlobPattern(pattern: string): boolean {
|
||||||
// Remove leading slash if present
|
// Remove leading slash if present
|
||||||
pattern = pattern.startsWith("/") ? pattern.slice(1) : pattern;
|
pattern = pattern.startsWith("/") ? pattern.slice(1) : pattern;
|
||||||
|
|
Loading…
Reference in a new issue