@@ -49,117 +49,147 @@ describe("isLocalishHost", () => {
4949} ) ;
5050
5151describe ( "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