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;