mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 04:37:11 +01:00
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:
commit
5506314e54
1 changed files with 62 additions and 8 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue