2323// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2424// SOFTWARE.
2525
26- import { isIP } from 'net' ;
26+ // The headers to check, in priority order
27+ export const ipHeaderNames = [
28+ 'X-Client-IP' ,
29+ 'X-Forwarded-For' ,
30+ 'Fly-Client-IP' ,
31+ 'CF-Connecting-IP' ,
32+ 'Fastly-Client-Ip' ,
33+ 'True-Client-Ip' ,
34+ 'X-Real-IP' ,
35+ 'X-Cluster-Client-IP' ,
36+ 'X-Forwarded' ,
37+ 'Forwarded-For' ,
38+ 'Forwarded' ,
39+ 'X-Vercel-Forwarded-For' ,
40+ ] ;
2741
2842/**
2943 * Get the IP address of the client sending a request.
3044 *
3145 * It receives a Request headers object and use it to get the
3246 * IP address from one of the following headers in order.
3347 *
34- * - X-Client-IP
35- * - X-Forwarded-For
36- * - Fly-Client-IP
37- * - CF-Connecting-IP
38- * - Fastly-Client-Ip
39- * - True-Client-Ip
40- * - X-Real-IP
41- * - X-Cluster-Client-IP
42- * - X-Forwarded
43- * - Forwarded-For
44- * - Forwarded
45- *
4648 * If the IP address is valid, it will be returned. Otherwise, null will be
4749 * returned.
4850 *
4951 * If the header values contains more than one IP address, the first valid one
5052 * will be returned.
5153 */
52- export function getClientIPAddress ( headers : Headers ) : string | null {
53- // The headers to check, in priority order
54- const headerNames = [
55- 'X-Client-IP' ,
56- 'X-Forwarded-For' ,
57- 'Fly-Client-IP' ,
58- 'CF-Connecting-IP' ,
59- 'Fastly-Client-Ip' ,
60- 'True-Client-Ip' ,
61- 'X-Real-IP' ,
62- 'X-Cluster-Client-IP' ,
63- 'X-Forwarded' ,
64- 'Forwarded-For' ,
65- 'Forwarded' ,
66- ] ;
67-
54+ export function getClientIPAddress ( headers : { [ key : string ] : string | string [ ] | undefined } ) : string | null {
6855 // This will end up being Array<string | string[] | undefined | null> because of the various possible values a header
6956 // can take
70- const headerValues = headerNames . map ( ( headerName : string ) => {
71- const value = headers . get ( headerName ) ;
57+ const headerValues = ipHeaderNames . map ( ( headerName : string ) => {
58+ const rawValue = headers [ headerName ] ;
59+ const value = Array . isArray ( rawValue ) ? rawValue . join ( ';' ) : rawValue ;
7260
7361 if ( headerName === 'Forwarded' ) {
7462 return parseForwardedHeader ( value ) ;
7563 }
7664
77- return value ? .split ( ',' ) . map ( ( v : string ) => v . trim ( ) ) ;
65+ return value && value . split ( ',' ) . map ( ( v : string ) => v . trim ( ) ) ;
7866 } ) ;
7967
8068 // Flatten the array and filter out any falsy entries
@@ -92,7 +80,7 @@ export function getClientIPAddress(headers: Headers): string | null {
9280 return ipAddress || null ;
9381}
9482
95- function parseForwardedHeader ( value : string | null ) : string | null {
83+ function parseForwardedHeader ( value : string | null | undefined ) : string | null {
9684 if ( ! value ) {
9785 return null ;
9886 }
@@ -105,3 +93,31 @@ function parseForwardedHeader(value: string | null): string | null {
10593
10694 return null ;
10795}
96+
97+ //
98+ /**
99+ * Custom method instead of importing this from `net` package, as this only exists in node
100+ * Accepts:
101+ * 127.0.0.1
102+ * 192.168.1.1
103+ * 192.168.1.255
104+ * 255.255.255.255
105+ * 10.1.1.1
106+ * 0.0.0.0
107+ * 2b01:cb19:8350:ed00:d0dd:fa5b:de31:8be5
108+ *
109+ * Rejects:
110+ * 1.1.1.01
111+ * 30.168.1.255.1
112+ * 127.1
113+ * 192.168.1.256
114+ * -1.2.3.4
115+ * 1.1.1.1.
116+ * 3...3
117+ * 192.168.1.099
118+ */
119+ function isIP ( str : string ) : boolean {
120+ const regex =
121+ / (?: ^ (?: 2 5 [ 0 - 5 ] | 2 [ 0 - 4 ] \d | 1 \d \d | [ 1 - 9 ] \d | \d ) (?: \. (?: 2 5 [ 0 - 5 ] | 2 [ 0 - 4 ] \d | 1 \d \d | [ 1 - 9 ] \d | \d ) ) { 3 } $ ) | (?: ^ (?: (?: [ a - f A - F \d ] { 1 , 4 } : ) { 7 } (?: [ a - f A - F \d ] { 1 , 4 } | : ) | (?: [ a - f A - F \d ] { 1 , 4 } : ) { 6 } (?: (?: 2 5 [ 0 - 5 ] | 2 [ 0 - 4 ] \d | 1 \d \d | [ 1 - 9 ] \d | \d ) (?: \\ .(?: 2 5 [ 0 - 5 ] | 2 [ 0 - 4 ] \d | 1 \d \d | [ 1 - 9 ] \d | \d ) ) { 3 } | : [ a - f A - F \d ] { 1 , 4 } | : ) | (?: [ a - f A - F \d ] { 1 , 4 } : ) { 5 } (?: : (?: 2 5 [ 0 - 5 ] | 2 [ 0 - 4 ] \d | 1 \d \d | [ 1 - 9 ] \d | \d ) (?: \\ .(?: 2 5 [ 0 - 5 ] | 2 [ 0 - 4 ] \d | 1 \d \d | [ 1 - 9 ] \d | \d ) ) { 3 } | (?: : [ a - f A - F \d ] { 1 , 4 } ) { 1 , 2 } | : ) | (?: [ a - f A - F \d ] { 1 , 4 } : ) { 4 } (?: (?: : [ a - f A - F \d ] { 1 , 4 } ) { 0 , 1 } : (?: 2 5 [ 0 - 5 ] | 2 [ 0 - 4 ] \d | 1 \d \d | [ 1 - 9 ] \d | \d ) (?: \\ .(?: 2 5 [ 0 - 5 ] | 2 [ 0 - 4 ] \d | 1 \d \d | [ 1 - 9 ] \d | \d ) ) { 3 } | (?: : [ a - f A - F \d ] { 1 , 4 } ) { 1 , 3 } | : ) | (?: [ a - f A - F \d ] { 1 , 4 } : ) { 3 } (?: (?: : [ a - f A - F \d ] { 1 , 4 } ) { 0 , 2 } : (?: 2 5 [ 0 - 5 ] | 2 [ 0 - 4 ] \d | 1 \d \d | [ 1 - 9 ] \d | \d ) (?: \\ .(?: 2 5 [ 0 - 5 ] | 2 [ 0 - 4 ] \d | 1 \d \d | [ 1 - 9 ] \d | \d ) ) { 3 } | (?: : [ a - f A - F \d ] { 1 , 4 } ) { 1 , 4 } | : ) | (?: [ a - f A - F \d ] { 1 , 4 } : ) { 2 } (?: (?: : [ a - f A - F \d ] { 1 , 4 } ) { 0 , 3 } : (?: 2 5 [ 0 - 5 ] | 2 [ 0 - 4 ] \d | 1 \d \d | [ 1 - 9 ] \d | \d ) (?: \\ .(?: 2 5 [ 0 - 5 ] | 2 [ 0 - 4 ] \d | 1 \d \d | [ 1 - 9 ] \d | \d ) ) { 3 } | (?: : [ a - f A - F \d ] { 1 , 4 } ) { 1 , 5 } | : ) | (?: [ a - f A - F \d ] { 1 , 4 } : ) { 1 } (?: (?: : [ a - f A - F \d ] { 1 , 4 } ) { 0 , 4 } : (?: 2 5 [ 0 - 5 ] | 2 [ 0 - 4 ] \d | 1 \d \d | [ 1 - 9 ] \d | \d ) (?: \\ .(?: 2 5 [ 0 - 5 ] | 2 [ 0 - 4 ] \d | 1 \d \d | [ 1 - 9 ] \d | \d ) ) { 3 } | (?: : [ a - f A - F \d ] { 1 , 4 } ) { 1 , 6 } | : ) | (?: : (?: (?: : [ a - f A - F \d ] { 1 , 4 } ) { 0 , 5 } : (?: 2 5 [ 0 - 5 ] | 2 [ 0 - 4 ] \d | 1 \d \d | [ 1 - 9 ] \d | \d ) (?: \\ .(?: 2 5 [ 0 - 5 ] | 2 [ 0 - 4 ] \d | 1 \d \d | [ 1 - 9 ] \d | \d ) ) { 3 } | (?: : [ a - f A - F \d ] { 1 , 4 } ) { 1 , 7 } | : ) ) ) (?: % [ 0 - 9 a - z A - Z ] { 1 , } ) ? $ ) / ;
122+ return regex . test ( str ) ;
123+ }
0 commit comments