Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/utils/server/IpUtils.ts
T

77 lines
2.0 KiB
TypeScript

import isIP from "is-ip";
/**
* This is the list of headers, in order of preference, that will be used to
* determine the client's IP address.
*/
const headerNames = Object.freeze([
"X-Client-IP",
"CF-Connecting-IP",
"X-Forwarded-For",
"Fly-Client-IP",
"Fastly-Client-Ip",
"True-Client-Ip",
"X-Real-IP",
"X-Cluster-Client-IP",
"X-Forwarded",
"Forwarded-For",
"Forwarded",
"DO-Connecting-IP" /** Digital ocean app platform */,
] as const);
/**
* Get the IP address of the client sending a request.
*
* It receives the Request object or the headers object and use it to get the
* IP address from one of the following headers in order.
*
* - X-Client-IP
* - X-Forwarded-For
* - Fly-Client-IP
* - CF-Connecting-IP
* - Fastly-Client-Ip
* - True-Client-Ip
* - X-Real-IP
* - X-Cluster-Client-IP
* - X-Forwarded
* - Forwarded-For
* - Forwarded
* - DO-Connecting-IP
*
* If the IP address is valid, it will be returned. Otherwise, null will be
* returned.
*
* If the header values contains more than one IP address, the first valid one
* will be returned.
*/
export function getClientIPAddress(headers: Headers): string | null;
export function getClientIPAddress(request: Request): string | null;
export function getClientIPAddress(requestOrHeaders: Request | Headers): string | null {
const headers = requestOrHeaders instanceof Request ? requestOrHeaders.headers : requestOrHeaders;
let ipAddress = headerNames
.flatMap((headerName) => {
let value = headers.get(headerName);
if (headerName === "Forwarded") {
return parseForwardedHeader(value);
}
if (!value?.includes(",")) return value;
return value.split(",").map((ip) => ip.trim());
})
.find((ip) => {
if (ip === null) return false;
return isIP(ip);
});
return ipAddress ?? null;
}
function parseForwardedHeader(value: string | null): string | null {
if (!value) return null;
for (let part of value.split(";")) {
if (part.startsWith("for=")) return part.slice(4);
continue;
}
return null;
}