Merge pull request #3891 from journry789/master

This resolves the issue of being unable to obtain the client's IP add…
This commit is contained in:
Mike Cao 2026-01-06 17:46:04 -08:00 committed by GitHub
commit 5506314e54
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,3 +1,5 @@
import ipaddr from 'ipaddr.js';
export const IP_ADDRESS_HEADERS = [
'true-client-ip', // CDN
'cf-connecting-ip', // Cloudflare
@ -13,35 +15,87 @@ export const IP_ADDRESS_HEADERS = [
'x-forwarded',
];
/**
* Normalize IP strings to a canonical form:
* - strips IPv4-mapped IPv6 (e.g. ::ffff:192.0.2.1 -> 192.0.2.1)
* - keeps valid IPv4/IPv6 as-is (canonically formatted by ipaddr.js)
*/
function normalizeIp(ip?: string | null) {
if (!ip) return ip;
try {
const parsed = ipaddr.parse(ip);
if (parsed.kind() === 'ipv6' && (parsed as ipaddr.IPv6).isIPv4MappedAddress()) {
return (parsed as ipaddr.IPv6).toIPv4Address().toString();
}
return parsed.toString();
} catch {
// Fallback: return original if parsing fails
return ip;
}
}
function resolveIp(ip?: string | null) {
if (!ip) return ip;
// First, try as-is
const normalized = normalizeIp(ip);
try {
ipaddr.parse(normalized);
return normalized;
} catch {
// try stripping port (handles IPv4:port; leaves IPv6 intact)
const stripped = stripPort(ip);
if (stripped !== ip) {
const normalizedStripped = normalizeIp(stripped);
try {
ipaddr.parse(normalizedStripped);
return normalizedStripped;
} catch {
return normalizedStripped;
}
}
return normalized;
}
}
export function getIpAddress(headers: Headers) {
const customHeader = process.env.CLIENT_IP_HEADER;
if (customHeader && headers.get(customHeader)) {
return headers.get(customHeader);
return resolveIp(headers.get(customHeader));
}
const header = IP_ADDRESS_HEADERS.find(name => {
return headers.get(name);
});
const header = IP_ADDRESS_HEADERS.find(name => headers.get(name));
if (!header) {
return undefined;
}
const ip = headers.get(header);
if (header === 'x-forwarded-for') {
return ip?.split(',')?.[0]?.trim();
return resolveIp(ip?.split(',')?.[0]?.trim());
}
if (header === 'forwarded') {
const match = ip.match(/for=(\[?[0-9a-fA-F:.]+\]?)/);
if (match) {
return match[1];
return resolveIp(match[1]);
}
}
return ip;
return resolveIp(ip);
}
export function stripPort(ip: string) {
export function stripPort(ip?: string | null) {
if (!ip) {
return ip;
}
if (ip.startsWith('[')) {
const endBracket = ip.indexOf(']');
if (endBracket !== -1) {