Skip to content

Commit 0f5bb31

Browse files
Update packages/remix/src/utils/getIpAddress.ts
Co-authored-by: Katie Byers <[email protected]>
1 parent e5aa3c6 commit 0f5bb31

File tree

1 file changed

+47
-41
lines changed

1 file changed

+47
-41
lines changed

packages/remix/src/utils/getIpAddress.ts

Lines changed: 47 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,6 @@
33

44
import { isIP } from 'net';
55

6-
/**
7-
* This is the list of headers, in order of preference, that will be used to
8-
* determine the client's IP address.
9-
*/
10-
const headerNames = [
11-
'X-Client-IP',
12-
'X-Forwarded-For',
13-
'Fly-Client-IP',
14-
'CF-Connecting-IP',
15-
'Fastly-Client-Ip',
16-
'True-Client-Ip',
17-
'X-Real-IP',
18-
'X-Cluster-Client-IP',
19-
'X-Forwarded',
20-
'Forwarded-For',
21-
'Forwarded',
22-
];
236
/**
247
* Get the IP address of the client sending a request.
258
*
@@ -45,35 +28,58 @@ const headerNames = [
4528
* will be returned.
4629
*/
4730
export function getClientIPAddress(headers: Headers): string | null {
48-
const ipAddress = headerNames
49-
.map((headerName: string) => {
50-
const value = headers.get(headerName);
51-
if (headerName === 'Forwarded') {
52-
return parseForwardedHeader(value);
53-
}
54-
if (!value?.includes(', ')) return value;
55-
return value.split(', ');
56-
})
57-
.reduce((acc: string[], val) => {
58-
if (!val) {
59-
return acc;
60-
}
31+
// The headers to check, in priority order
32+
const headerNames = [
33+
"X-Client-IP",
34+
"X-Forwarded-For",
35+
"Fly-Client-IP",
36+
"CF-Connecting-IP",
37+
"Fastly-Client-Ip",
38+
"True-Client-Ip",
39+
"X-Real-IP",
40+
"X-Cluster-Client-IP",
41+
"X-Forwarded",
42+
"Forwarded-For",
43+
"Forwarded",
44+
];
45+
46+
// This will end up being Array<string | string[] | undefined | null> because of the various possible values a header
47+
// can take
48+
const headerValues = headerNames.map((headerName: string) => {
49+
const value = headers.get(headerName);
50+
51+
if (headerName === "Forwarded") {
52+
return parseForwardedHeader(value);
53+
}
54+
55+
return value?.split(", ");
56+
});
57+
58+
// Flatten the array and filter out any falsy entries
59+
const flattenedHeaderValues = headerValues.reduce((acc: string[], val) => {
60+
if (!val) {
61+
return acc;
62+
}
6163

62-
return acc.concat(val);
63-
}, [])
64-
.find(ip => {
65-
if (ip === null) return false;
66-
return isIP(ip);
67-
});
64+
return acc.concat(val);
65+
}, []);
6866

69-
return ipAddress ?? null;
67+
// Find the first value which is a valid IP address, if any
68+
const ipAddress = flattenedHeaderValues.find((ip) => ip !== null && isIP(ip));
69+
70+
return ipAddress || null;
7071
}
7172

7273
function parseForwardedHeader(value: string | null): string | null {
73-
if (!value) return null;
74-
for (const part of value.split(';')) {
75-
if (part.startsWith('for=')) return part.slice(4);
76-
continue;
74+
if (!value) {
75+
return null;
76+
}
77+
78+
for (const part of value.split(";")) {
79+
if (part.startsWith("for=")) {
80+
return part.slice(4);
81+
}
7782
}
83+
7884
return null;
7985
}

0 commit comments

Comments
 (0)