// author: simon-pierre boucher import { describe, expect, it } from "vitest"; import { isBlockedIp } from "./ip.js"; describe("isBlockedIp", () => { it("blocks loopback", () => { expect(isBlockedIp("127.0.0.1")).toBe(true); expect(isBlockedIp("127.10.20.30")).toBe(true); expect(isBlockedIp("::1")).toBe(true); }); it("blocks RFC1918 ranges", () => { expect(isBlockedIp("10.0.0.1")).toBe(true); expect(isBlockedIp("172.16.5.4")).toBe(true); expect(isBlockedIp("172.31.255.255")).toBe(true); expect(isBlockedIp("192.168.1.1")).toBe(true); }); it("does not block 172.32.x (outside the /12)", () => { expect(isBlockedIp("172.32.0.1")).toBe(false); }); it("blocks the cloud metadata address", () => { expect(isBlockedIp("169.254.169.254")).toBe(true); }); it("blocks link-local and CGNAT", () => { expect(isBlockedIp("169.254.1.1")).toBe(true); expect(isBlockedIp("100.64.0.1")).toBe(true); }); it("blocks IPv6 ULA and link-local", () => { expect(isBlockedIp("fc00::1")).toBe(true); expect(isBlockedIp("fd12:3456::1")).toBe(true); expect(isBlockedIp("fe80::1")).toBe(true); }); it("unwraps IPv4-mapped IPv6 and blocks private embeds", () => { expect(isBlockedIp("::ffff:127.0.0.1")).toBe(true); expect(isBlockedIp("::ffff:10.0.0.1")).toBe(true); }); it("allows public addresses", () => { expect(isBlockedIp("8.8.8.8")).toBe(false); expect(isBlockedIp("1.1.1.1")).toBe(false); expect(isBlockedIp("93.184.216.34")).toBe(false); expect(isBlockedIp("2606:4700:4700::1111")).toBe(false); }); it("blocks garbage input", () => { expect(isBlockedIp("not-an-ip")).toBe(true); expect(isBlockedIp("999.1.1.1")).toBe(true); }); });