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 = [
|
export const IP_ADDRESS_HEADERS = [
|
||||||
'true-client-ip', // CDN
|
'true-client-ip', // CDN
|
||||||
'cf-connecting-ip', // Cloudflare
|
'cf-connecting-ip', // Cloudflare
|
||||||
|
|
@ -13,35 +15,87 @@ export const IP_ADDRESS_HEADERS = [
|
||||||
'x-forwarded',
|
'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) {
|
export function getIpAddress(headers: Headers) {
|
||||||
const customHeader = process.env.CLIENT_IP_HEADER;
|
const customHeader = process.env.CLIENT_IP_HEADER;
|
||||||
|
|
||||||
if (customHeader && headers.get(customHeader)) {
|
if (customHeader && headers.get(customHeader)) {
|
||||||
return headers.get(customHeader);
|
return resolveIp(headers.get(customHeader));
|
||||||
}
|
}
|
||||||
|
|
||||||
const header = IP_ADDRESS_HEADERS.find(name => {
|
const header = IP_ADDRESS_HEADERS.find(name => headers.get(name));
|
||||||
return headers.get(name);
|
if (!header) {
|
||||||
});
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
const ip = headers.get(header);
|
const ip = headers.get(header);
|
||||||
|
|
||||||
if (header === 'x-forwarded-for') {
|
if (header === 'x-forwarded-for') {
|
||||||
return ip?.split(',')?.[0]?.trim();
|
return resolveIp(ip?.split(',')?.[0]?.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header === 'forwarded') {
|
if (header === 'forwarded') {
|
||||||
const match = ip.match(/for=(\[?[0-9a-fA-F:.]+\]?)/);
|
const match = ip.match(/for=(\[?[0-9a-fA-F:.]+\]?)/);
|
||||||
|
|
||||||
if (match) {
|
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('[')) {
|
if (ip.startsWith('[')) {
|
||||||
const endBracket = ip.indexOf(']');
|
const endBracket = ip.indexOf(']');
|
||||||
if (endBracket !== -1) {
|
if (endBracket !== -1) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue