Skip to content

Commit 118abfb

Browse files
committed
test: simplify trusted proxy coverage
1 parent 87c447e commit 118abfb

File tree

1 file changed

+141
-111
lines changed

1 file changed

+141
-111
lines changed

src/gateway/net.test.ts

Lines changed: 141 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -49,117 +49,147 @@ describe("isLocalishHost", () => {
4949
});
5050

5151
describe("isTrustedProxyAddress", () => {
52-
describe("exact IP matching", () => {
53-
it("returns true when IP matches exactly", () => {
54-
expect(isTrustedProxyAddress("192.168.1.1", ["192.168.1.1"])).toBe(true);
55-
});
56-
57-
it("returns false when IP does not match", () => {
58-
expect(isTrustedProxyAddress("192.168.1.2", ["192.168.1.1"])).toBe(false);
59-
});
60-
61-
it("returns true when IP matches one of multiple proxies", () => {
62-
expect(isTrustedProxyAddress("10.0.0.5", ["192.168.1.1", "10.0.0.5", "172.16.0.1"])).toBe(
63-
true,
64-
);
65-
});
66-
67-
it("ignores surrounding whitespace in exact IP entries", () => {
68-
expect(isTrustedProxyAddress("10.0.0.5", [" 10.0.0.5 "])).toBe(true);
69-
});
70-
});
71-
72-
describe("CIDR subnet matching", () => {
73-
it("returns true when IP is within /24 subnet", () => {
74-
expect(isTrustedProxyAddress("10.42.0.59", ["10.42.0.0/24"])).toBe(true);
75-
expect(isTrustedProxyAddress("10.42.0.1", ["10.42.0.0/24"])).toBe(true);
76-
expect(isTrustedProxyAddress("10.42.0.254", ["10.42.0.0/24"])).toBe(true);
77-
});
78-
79-
it("returns false when IP is outside /24 subnet", () => {
80-
expect(isTrustedProxyAddress("10.42.1.1", ["10.42.0.0/24"])).toBe(false);
81-
expect(isTrustedProxyAddress("10.43.0.1", ["10.42.0.0/24"])).toBe(false);
82-
});
83-
84-
it("returns true when IP is within /16 subnet", () => {
85-
expect(isTrustedProxyAddress("172.19.5.100", ["172.19.0.0/16"])).toBe(true);
86-
expect(isTrustedProxyAddress("172.19.255.255", ["172.19.0.0/16"])).toBe(true);
87-
});
88-
89-
it("returns false when IP is outside /16 subnet", () => {
90-
expect(isTrustedProxyAddress("172.20.0.1", ["172.19.0.0/16"])).toBe(false);
91-
});
92-
93-
it("returns true when IP is within /32 subnet (single IP)", () => {
94-
expect(isTrustedProxyAddress("10.42.0.0", ["10.42.0.0/32"])).toBe(true);
95-
});
96-
97-
it("returns false when IP does not match /32 subnet", () => {
98-
expect(isTrustedProxyAddress("10.42.0.1", ["10.42.0.0/32"])).toBe(false);
99-
});
100-
101-
it("handles mixed exact IPs and CIDR notation", () => {
102-
const proxies = ["192.168.1.1", "10.42.0.0/24", "172.19.0.0/16"];
103-
expect(isTrustedProxyAddress("192.168.1.1", proxies)).toBe(true); // exact match
104-
expect(isTrustedProxyAddress("10.42.0.59", proxies)).toBe(true); // CIDR match
105-
expect(isTrustedProxyAddress("172.19.5.100", proxies)).toBe(true); // CIDR match
106-
expect(isTrustedProxyAddress("10.43.0.1", proxies)).toBe(false); // no match
107-
});
108-
109-
it("supports IPv6 CIDR notation", () => {
110-
expect(isTrustedProxyAddress("2001:db8::1234", ["2001:db8::/32"])).toBe(true);
111-
expect(isTrustedProxyAddress("2001:db9::1234", ["2001:db8::/32"])).toBe(false);
112-
});
113-
});
114-
115-
describe("backward compatibility", () => {
116-
it("preserves exact IP matching behavior (no CIDR notation)", () => {
117-
// Old configs with exact IPs should work exactly as before
118-
expect(isTrustedProxyAddress("192.168.1.1", ["192.168.1.1"])).toBe(true);
119-
expect(isTrustedProxyAddress("192.168.1.2", ["192.168.1.1"])).toBe(false);
120-
expect(isTrustedProxyAddress("10.0.0.5", ["192.168.1.1", "10.0.0.5"])).toBe(true);
121-
});
122-
123-
it("does NOT treat plain IPs as /32 CIDR (exact match only)", () => {
124-
// "10.42.0.1" without /32 should match ONLY that exact IP
125-
expect(isTrustedProxyAddress("10.42.0.1", ["10.42.0.1"])).toBe(true);
126-
expect(isTrustedProxyAddress("10.42.0.2", ["10.42.0.1"])).toBe(false);
127-
expect(isTrustedProxyAddress("10.42.0.59", ["10.42.0.1"])).toBe(false);
128-
});
129-
130-
it("handles IPv4-mapped IPv6 addresses (existing normalizeIp behavior)", () => {
131-
// Existing normalizeIp() behavior should be preserved
132-
expect(isTrustedProxyAddress("::ffff:192.168.1.1", ["192.168.1.1"])).toBe(true);
133-
});
134-
});
135-
136-
describe("edge cases", () => {
137-
it("returns false when IP is undefined", () => {
138-
expect(isTrustedProxyAddress(undefined, ["192.168.1.1"])).toBe(false);
139-
});
140-
141-
it("returns false when trustedProxies is undefined", () => {
142-
expect(isTrustedProxyAddress("192.168.1.1", undefined)).toBe(false);
143-
});
144-
145-
it("returns false when trustedProxies is empty", () => {
146-
expect(isTrustedProxyAddress("192.168.1.1", [])).toBe(false);
147-
});
148-
149-
it("returns false for invalid CIDR notation", () => {
150-
expect(isTrustedProxyAddress("10.42.0.59", ["10.42.0.0/33"])).toBe(false); // invalid prefix
151-
expect(isTrustedProxyAddress("10.42.0.59", ["10.42.0.0/-1"])).toBe(false); // negative prefix
152-
expect(isTrustedProxyAddress("10.42.0.59", ["invalid/24"])).toBe(false); // invalid IP
153-
});
154-
155-
it("ignores surrounding whitespace in CIDR entries", () => {
156-
expect(isTrustedProxyAddress("10.42.0.59", [" 10.42.0.0/24 "])).toBe(true);
157-
});
158-
159-
it("ignores blank trusted proxy entries", () => {
160-
expect(isTrustedProxyAddress("10.0.0.5", [" ", "\t"])).toBe(false);
161-
expect(isTrustedProxyAddress("10.0.0.5", [" ", "10.0.0.5", ""])).toBe(true);
162-
});
52+
it.each([
53+
{
54+
name: "matches exact IP entries",
55+
ip: "192.168.1.1",
56+
trustedProxies: ["192.168.1.1"],
57+
expected: true,
58+
},
59+
{
60+
name: "rejects non-matching exact IP entries",
61+
ip: "192.168.1.2",
62+
trustedProxies: ["192.168.1.1"],
63+
expected: false,
64+
},
65+
{
66+
name: "matches one of multiple exact entries",
67+
ip: "10.0.0.5",
68+
trustedProxies: ["192.168.1.1", "10.0.0.5", "172.16.0.1"],
69+
expected: true,
70+
},
71+
{
72+
name: "ignores surrounding whitespace in exact IP entries",
73+
ip: "10.0.0.5",
74+
trustedProxies: [" 10.0.0.5 "],
75+
expected: true,
76+
},
77+
{
78+
name: "matches /24 CIDR entries",
79+
ip: "10.42.0.59",
80+
trustedProxies: ["10.42.0.0/24"],
81+
expected: true,
82+
},
83+
{
84+
name: "rejects IPs outside /24 CIDR entries",
85+
ip: "10.42.1.1",
86+
trustedProxies: ["10.42.0.0/24"],
87+
expected: false,
88+
},
89+
{
90+
name: "matches /16 CIDR entries",
91+
ip: "172.19.255.255",
92+
trustedProxies: ["172.19.0.0/16"],
93+
expected: true,
94+
},
95+
{
96+
name: "rejects IPs outside /16 CIDR entries",
97+
ip: "172.20.0.1",
98+
trustedProxies: ["172.19.0.0/16"],
99+
expected: false,
100+
},
101+
{
102+
name: "treats /32 as a single-IP CIDR",
103+
ip: "10.42.0.0",
104+
trustedProxies: ["10.42.0.0/32"],
105+
expected: true,
106+
},
107+
{
108+
name: "rejects non-matching /32 CIDR entries",
109+
ip: "10.42.0.1",
110+
trustedProxies: ["10.42.0.0/32"],
111+
expected: false,
112+
},
113+
{
114+
name: "handles mixed exact IP and CIDR entries",
115+
ip: "172.19.5.100",
116+
trustedProxies: ["192.168.1.1", "10.42.0.0/24", "172.19.0.0/16"],
117+
expected: true,
118+
},
119+
{
120+
name: "rejects IPs missing from mixed exact IP and CIDR entries",
121+
ip: "10.43.0.1",
122+
trustedProxies: ["192.168.1.1", "10.42.0.0/24", "172.19.0.0/16"],
123+
expected: false,
124+
},
125+
{
126+
name: "supports IPv6 CIDR notation",
127+
ip: "2001:db8::1234",
128+
trustedProxies: ["2001:db8::/32"],
129+
expected: true,
130+
},
131+
{
132+
name: "rejects IPv6 addresses outside the configured CIDR",
133+
ip: "2001:db9::1234",
134+
trustedProxies: ["2001:db8::/32"],
135+
expected: false,
136+
},
137+
{
138+
name: "preserves exact matching behavior for plain IP entries",
139+
ip: "10.42.0.59",
140+
trustedProxies: ["10.42.0.1"],
141+
expected: false,
142+
},
143+
{
144+
name: "normalizes IPv4-mapped IPv6 addresses",
145+
ip: "::ffff:192.168.1.1",
146+
trustedProxies: ["192.168.1.1"],
147+
expected: true,
148+
},
149+
{
150+
name: "returns false when IP is undefined",
151+
ip: undefined,
152+
trustedProxies: ["192.168.1.1"],
153+
expected: false,
154+
},
155+
{
156+
name: "returns false when trusted proxies are undefined",
157+
ip: "192.168.1.1",
158+
trustedProxies: undefined,
159+
expected: false,
160+
},
161+
{
162+
name: "returns false when trusted proxies are empty",
163+
ip: "192.168.1.1",
164+
trustedProxies: [],
165+
expected: false,
166+
},
167+
{
168+
name: "rejects invalid CIDR prefixes and addresses",
169+
ip: "10.42.0.59",
170+
trustedProxies: ["10.42.0.0/33", "10.42.0.0/-1", "invalid/24", "2001:db8::/129"],
171+
expected: false,
172+
},
173+
{
174+
name: "ignores surrounding whitespace in CIDR entries",
175+
ip: "10.42.0.59",
176+
trustedProxies: [" 10.42.0.0/24 "],
177+
expected: true,
178+
},
179+
{
180+
name: "ignores blank trusted proxy entries",
181+
ip: "10.0.0.5",
182+
trustedProxies: [" ", "10.0.0.5", ""],
183+
expected: true,
184+
},
185+
{
186+
name: "treats all-blank trusted proxy entries as no match",
187+
ip: "10.0.0.5",
188+
trustedProxies: [" ", "\t"],
189+
expected: false,
190+
},
191+
])("$name", ({ ip, trustedProxies, expected }) => {
192+
expect(isTrustedProxyAddress(ip, trustedProxies)).toBe(expected);
163193
});
164194
});
165195

0 commit comments

Comments
 (0)