23
23
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
24
// SOFTWARE.
25
25
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
+ ] ;
27
41
28
42
/**
29
43
* Get the IP address of the client sending a request.
30
44
*
31
45
* It receives a Request headers object and use it to get the
32
46
* IP address from one of the following headers in order.
33
47
*
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
- *
46
48
* If the IP address is valid, it will be returned. Otherwise, null will be
47
49
* returned.
48
50
*
49
51
* If the header values contains more than one IP address, the first valid one
50
52
* will be returned.
51
53
*/
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 {
68
55
// This will end up being Array<string | string[] | undefined | null> because of the various possible values a header
69
56
// 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 ;
72
60
73
61
if ( headerName === 'Forwarded' ) {
74
62
return parseForwardedHeader ( value ) ;
75
63
}
76
64
77
- return value ? .split ( ',' ) . map ( ( v : string ) => v . trim ( ) ) ;
65
+ return value && value . split ( ',' ) . map ( ( v : string ) => v . trim ( ) ) ;
78
66
} ) ;
79
67
80
68
// Flatten the array and filter out any falsy entries
@@ -92,7 +80,7 @@ export function getClientIPAddress(headers: Headers): string | null {
92
80
return ipAddress || null ;
93
81
}
94
82
95
- function parseForwardedHeader ( value : string | null ) : string | null {
83
+ function parseForwardedHeader ( value : string | null | undefined ) : string | null {
96
84
if ( ! value ) {
97
85
return null ;
98
86
}
@@ -105,3 +93,31 @@ function parseForwardedHeader(value: string | null): string | null {
105
93
106
94
return null ;
107
95
}
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