From 118abfbdb78375aa0af22ed78e2d71d7f7b0d7bd Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 13 Mar 2026 17:52:49 +0000 Subject: [PATCH] test: simplify trusted proxy coverage --- src/gateway/net.test.ts | 252 ++++++++++++++++++++++------------------ 1 file changed, 141 insertions(+), 111 deletions(-) diff --git a/src/gateway/net.test.ts b/src/gateway/net.test.ts index f5ee5db9a8e..185325d5428 100644 --- a/src/gateway/net.test.ts +++ b/src/gateway/net.test.ts @@ -49,117 +49,147 @@ describe("isLocalishHost", () => { }); describe("isTrustedProxyAddress", () => { - describe("exact IP matching", () => { - it("returns true when IP matches exactly", () => { - expect(isTrustedProxyAddress("192.168.1.1", ["192.168.1.1"])).toBe(true); - }); - - it("returns false when IP does not match", () => { - expect(isTrustedProxyAddress("192.168.1.2", ["192.168.1.1"])).toBe(false); - }); - - it("returns true when IP matches one of multiple proxies", () => { - expect(isTrustedProxyAddress("10.0.0.5", ["192.168.1.1", "10.0.0.5", "172.16.0.1"])).toBe( - true, - ); - }); - - it("ignores surrounding whitespace in exact IP entries", () => { - expect(isTrustedProxyAddress("10.0.0.5", [" 10.0.0.5 "])).toBe(true); - }); - }); - - describe("CIDR subnet matching", () => { - it("returns true when IP is within /24 subnet", () => { - expect(isTrustedProxyAddress("10.42.0.59", ["10.42.0.0/24"])).toBe(true); - expect(isTrustedProxyAddress("10.42.0.1", ["10.42.0.0/24"])).toBe(true); - expect(isTrustedProxyAddress("10.42.0.254", ["10.42.0.0/24"])).toBe(true); - }); - - it("returns false when IP is outside /24 subnet", () => { - expect(isTrustedProxyAddress("10.42.1.1", ["10.42.0.0/24"])).toBe(false); - expect(isTrustedProxyAddress("10.43.0.1", ["10.42.0.0/24"])).toBe(false); - }); - - it("returns true when IP is within /16 subnet", () => { - expect(isTrustedProxyAddress("172.19.5.100", ["172.19.0.0/16"])).toBe(true); - expect(isTrustedProxyAddress("172.19.255.255", ["172.19.0.0/16"])).toBe(true); - }); - - it("returns false when IP is outside /16 subnet", () => { - expect(isTrustedProxyAddress("172.20.0.1", ["172.19.0.0/16"])).toBe(false); - }); - - it("returns true when IP is within /32 subnet (single IP)", () => { - expect(isTrustedProxyAddress("10.42.0.0", ["10.42.0.0/32"])).toBe(true); - }); - - it("returns false when IP does not match /32 subnet", () => { - expect(isTrustedProxyAddress("10.42.0.1", ["10.42.0.0/32"])).toBe(false); - }); - - it("handles mixed exact IPs and CIDR notation", () => { - const proxies = ["192.168.1.1", "10.42.0.0/24", "172.19.0.0/16"]; - expect(isTrustedProxyAddress("192.168.1.1", proxies)).toBe(true); // exact match - expect(isTrustedProxyAddress("10.42.0.59", proxies)).toBe(true); // CIDR match - expect(isTrustedProxyAddress("172.19.5.100", proxies)).toBe(true); // CIDR match - expect(isTrustedProxyAddress("10.43.0.1", proxies)).toBe(false); // no match - }); - - it("supports IPv6 CIDR notation", () => { - expect(isTrustedProxyAddress("2001:db8::1234", ["2001:db8::/32"])).toBe(true); - expect(isTrustedProxyAddress("2001:db9::1234", ["2001:db8::/32"])).toBe(false); - }); - }); - - describe("backward compatibility", () => { - it("preserves exact IP matching behavior (no CIDR notation)", () => { - // Old configs with exact IPs should work exactly as before - expect(isTrustedProxyAddress("192.168.1.1", ["192.168.1.1"])).toBe(true); - expect(isTrustedProxyAddress("192.168.1.2", ["192.168.1.1"])).toBe(false); - expect(isTrustedProxyAddress("10.0.0.5", ["192.168.1.1", "10.0.0.5"])).toBe(true); - }); - - it("does NOT treat plain IPs as /32 CIDR (exact match only)", () => { - // "10.42.0.1" without /32 should match ONLY that exact IP - expect(isTrustedProxyAddress("10.42.0.1", ["10.42.0.1"])).toBe(true); - expect(isTrustedProxyAddress("10.42.0.2", ["10.42.0.1"])).toBe(false); - expect(isTrustedProxyAddress("10.42.0.59", ["10.42.0.1"])).toBe(false); - }); - - it("handles IPv4-mapped IPv6 addresses (existing normalizeIp behavior)", () => { - // Existing normalizeIp() behavior should be preserved - expect(isTrustedProxyAddress("::ffff:192.168.1.1", ["192.168.1.1"])).toBe(true); - }); - }); - - describe("edge cases", () => { - it("returns false when IP is undefined", () => { - expect(isTrustedProxyAddress(undefined, ["192.168.1.1"])).toBe(false); - }); - - it("returns false when trustedProxies is undefined", () => { - expect(isTrustedProxyAddress("192.168.1.1", undefined)).toBe(false); - }); - - it("returns false when trustedProxies is empty", () => { - expect(isTrustedProxyAddress("192.168.1.1", [])).toBe(false); - }); - - it("returns false for invalid CIDR notation", () => { - expect(isTrustedProxyAddress("10.42.0.59", ["10.42.0.0/33"])).toBe(false); // invalid prefix - expect(isTrustedProxyAddress("10.42.0.59", ["10.42.0.0/-1"])).toBe(false); // negative prefix - expect(isTrustedProxyAddress("10.42.0.59", ["invalid/24"])).toBe(false); // invalid IP - }); - - it("ignores surrounding whitespace in CIDR entries", () => { - expect(isTrustedProxyAddress("10.42.0.59", [" 10.42.0.0/24 "])).toBe(true); - }); - - it("ignores blank trusted proxy entries", () => { - expect(isTrustedProxyAddress("10.0.0.5", [" ", "\t"])).toBe(false); - expect(isTrustedProxyAddress("10.0.0.5", [" ", "10.0.0.5", ""])).toBe(true); - }); + it.each([ + { + name: "matches exact IP entries", + ip: "192.168.1.1", + trustedProxies: ["192.168.1.1"], + expected: true, + }, + { + name: "rejects non-matching exact IP entries", + ip: "192.168.1.2", + trustedProxies: ["192.168.1.1"], + expected: false, + }, + { + name: "matches one of multiple exact entries", + ip: "10.0.0.5", + trustedProxies: ["192.168.1.1", "10.0.0.5", "172.16.0.1"], + expected: true, + }, + { + name: "ignores surrounding whitespace in exact IP entries", + ip: "10.0.0.5", + trustedProxies: [" 10.0.0.5 "], + expected: true, + }, + { + name: "matches /24 CIDR entries", + ip: "10.42.0.59", + trustedProxies: ["10.42.0.0/24"], + expected: true, + }, + { + name: "rejects IPs outside /24 CIDR entries", + ip: "10.42.1.1", + trustedProxies: ["10.42.0.0/24"], + expected: false, + }, + { + name: "matches /16 CIDR entries", + ip: "172.19.255.255", + trustedProxies: ["172.19.0.0/16"], + expected: true, + }, + { + name: "rejects IPs outside /16 CIDR entries", + ip: "172.20.0.1", + trustedProxies: ["172.19.0.0/16"], + expected: false, + }, + { + name: "treats /32 as a single-IP CIDR", + ip: "10.42.0.0", + trustedProxies: ["10.42.0.0/32"], + expected: true, + }, + { + name: "rejects non-matching /32 CIDR entries", + ip: "10.42.0.1", + trustedProxies: ["10.42.0.0/32"], + expected: false, + }, + { + name: "handles mixed exact IP and CIDR entries", + ip: "172.19.5.100", + trustedProxies: ["192.168.1.1", "10.42.0.0/24", "172.19.0.0/16"], + expected: true, + }, + { + name: "rejects IPs missing from mixed exact IP and CIDR entries", + ip: "10.43.0.1", + trustedProxies: ["192.168.1.1", "10.42.0.0/24", "172.19.0.0/16"], + expected: false, + }, + { + name: "supports IPv6 CIDR notation", + ip: "2001:db8::1234", + trustedProxies: ["2001:db8::/32"], + expected: true, + }, + { + name: "rejects IPv6 addresses outside the configured CIDR", + ip: "2001:db9::1234", + trustedProxies: ["2001:db8::/32"], + expected: false, + }, + { + name: "preserves exact matching behavior for plain IP entries", + ip: "10.42.0.59", + trustedProxies: ["10.42.0.1"], + expected: false, + }, + { + name: "normalizes IPv4-mapped IPv6 addresses", + ip: "::ffff:192.168.1.1", + trustedProxies: ["192.168.1.1"], + expected: true, + }, + { + name: "returns false when IP is undefined", + ip: undefined, + trustedProxies: ["192.168.1.1"], + expected: false, + }, + { + name: "returns false when trusted proxies are undefined", + ip: "192.168.1.1", + trustedProxies: undefined, + expected: false, + }, + { + name: "returns false when trusted proxies are empty", + ip: "192.168.1.1", + trustedProxies: [], + expected: false, + }, + { + name: "rejects invalid CIDR prefixes and addresses", + ip: "10.42.0.59", + trustedProxies: ["10.42.0.0/33", "10.42.0.0/-1", "invalid/24", "2001:db8::/129"], + expected: false, + }, + { + name: "ignores surrounding whitespace in CIDR entries", + ip: "10.42.0.59", + trustedProxies: [" 10.42.0.0/24 "], + expected: true, + }, + { + name: "ignores blank trusted proxy entries", + ip: "10.0.0.5", + trustedProxies: [" ", "10.0.0.5", ""], + expected: true, + }, + { + name: "treats all-blank trusted proxy entries as no match", + ip: "10.0.0.5", + trustedProxies: [" ", "\t"], + expected: false, + }, + ])("$name", ({ ip, trustedProxies, expected }) => { + expect(isTrustedProxyAddress(ip, trustedProxies)).toBe(expected); }); });