d2faf98ac1
Fixes the 13-item codebase health scan backlog: wraps meal-plan generation in a transaction, adds missing userId/GIN indexes, fixes an IPv6-parsing gap in the webhook SSRF guard (and an identical duplicated bug in the AI URL-import path, now consolidated onto one implementation), paginates the collections list, dedupes the AI recipe Zod schemas, wires up Stripe tier sync, rate-limits AI key rotation, gets `pnpm typecheck` actually working, and adds test coverage for the previously-untested admin/webhooks routes. Two flagged issues (collection removeRecipeId IDOR, tier-limit race) turned out to already be fixed/non-issues on inspection — noted in TODO.md rather than silently dropped. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
55 lines
2.1 KiB
TypeScript
55 lines
2.1 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { isPrivateAddress } from "../validate-webhook-url";
|
|
|
|
describe("isPrivateAddress", () => {
|
|
it("flags IPv4 private/reserved ranges", () => {
|
|
expect(isPrivateAddress("127.0.0.1")).toBe(true);
|
|
expect(isPrivateAddress("10.1.2.3")).toBe(true);
|
|
expect(isPrivateAddress("172.16.0.1")).toBe(true);
|
|
expect(isPrivateAddress("192.168.1.1")).toBe(true);
|
|
expect(isPrivateAddress("169.254.1.1")).toBe(true);
|
|
expect(isPrivateAddress("224.0.0.1")).toBe(true);
|
|
});
|
|
|
|
it("allows public IPv4 addresses", () => {
|
|
expect(isPrivateAddress("8.8.8.8")).toBe(false);
|
|
expect(isPrivateAddress("1.1.1.1")).toBe(false);
|
|
});
|
|
|
|
it("fails closed on malformed IPv4 octets", () => {
|
|
expect(isPrivateAddress("999.999.999.999")).toBe(true);
|
|
});
|
|
|
|
it("flags IPv6 loopback and unspecified addresses in any compression form", () => {
|
|
expect(isPrivateAddress("::1")).toBe(true);
|
|
expect(isPrivateAddress("::")).toBe(true);
|
|
expect(isPrivateAddress("0:0:0:0:0:0:0:1")).toBe(true);
|
|
});
|
|
|
|
it("flags IPv6 unique-local (fc00::/7) and link-local (fe80::/10) ranges", () => {
|
|
expect(isPrivateAddress("fc00::1")).toBe(true);
|
|
expect(isPrivateAddress("fd12:3456::1")).toBe(true);
|
|
expect(isPrivateAddress("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")).toBe(true);
|
|
expect(isPrivateAddress("fe80::1")).toBe(true);
|
|
expect(isPrivateAddress("fe00::1")).toBe(false);
|
|
});
|
|
|
|
it("recurses into IPv4-mapped IPv6 addresses, including non-compressed forms", () => {
|
|
expect(isPrivateAddress("::ffff:127.0.0.1")).toBe(true);
|
|
expect(isPrivateAddress("::ffff:10.0.0.5")).toBe(true);
|
|
expect(isPrivateAddress("::ffff:8.8.8.8")).toBe(false);
|
|
});
|
|
|
|
it("fails closed on a malformed IPv4-mapped address (out-of-range octets)", () => {
|
|
expect(isPrivateAddress("::ffff:999.999.999.999")).toBe(true);
|
|
});
|
|
|
|
it("allows public IPv6 addresses", () => {
|
|
expect(isPrivateAddress("2001:4860:4860::8888")).toBe(false);
|
|
});
|
|
|
|
it("fails closed on unparseable input", () => {
|
|
expect(isPrivateAddress("not-an-ip")).toBe(true);
|
|
});
|
|
});
|