umami/src/lib/ip.ts
Mike Cao 5398cd89fe
Some checks are pending
Create docker images (cloud) / Build, push, and deploy (push) Waiting to run
Node.js CI / build (postgresql, 18.18, 10) (push) Waiting to run
Reordered IP headers.
2025-11-03 21:01:12 -08:00

60 lines
1.3 KiB
TypeScript

export const IP_ADDRESS_HEADERS = [
'true-client-ip', // CDN
'x-real-ip', // Reverse proxy
'x-forwarded-for',
'cf-connecting-ip', // Cloudflare
'fastly-client-ip', // Fastly
'x-nf-client-connection-ip', // Netlify
'do-connecting-ip', // Digital Ocean
'x-appengine-user-ip', // Google App Ending
'x-client-ip',
'x-cluster-client-ip',
'x-forwarded',
'forwarded',
];
export function getIpAddress(headers: Headers) {
const customHeader = process.env.CLIENT_IP_HEADER;
if (customHeader && headers.get(customHeader)) {
return headers.get(customHeader);
}
const header = IP_ADDRESS_HEADERS.find(name => {
return headers.get(name);
});
const ip = headers.get(header);
if (header === 'x-forwarded-for') {
return ip?.split(',')?.[0]?.trim();
}
if (header === 'forwarded') {
const match = ip.match(/for=(\[?[0-9a-fA-F:.]+\]?)/);
if (match) {
return match[1];
}
}
return ip;
}
export function stripPort(ip: string) {
if (ip.startsWith('[')) {
const endBracket = ip.indexOf(']');
if (endBracket !== -1) {
return ip.slice(0, endBracket + 1);
}
}
const idx = ip.lastIndexOf(':');
if (idx !== -1) {
if (ip.includes('.') || /^[a-zA-Z0-9.-]+$/.test(ip.slice(0, idx))) {
return ip.slice(0, idx);
}
}
return ip;
}