import { IncomingMessage } from "http";
/**
* Extract client IP address from request headers
*/
export function getClientIp(req: IncomingMessage): string | undefined {
// Check both possible header casings
const forwardedFor =
req.headers["x-forwarded-for"] || req.headers["X-Forwarded-For"];
if (forwardedFor) {
// X-Forwarded-For can contain multiple IPs
const ips = Array.isArray(forwardedFor) ? forwardedFor[0] : forwardedFor;
const ipList = ips.split(",").map((ip) => ip.trim());
// Find the first public IP address
for (const ip of ipList) {
const plainIp = ip.replace(/^::ffff:/, "");
if (
!plainIp.startsWith("10.") &&
!plainIp.startsWith("192.168.") &&
!/^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(plainIp)
) {
return plainIp;
}
}
// If all are private, use the first one
return ipList[0].replace(/^::ffff:/, "");
}
// Fallback: use remote address, strip IPv6-mapped IPv4
if (req.socket?.remoteAddress) {
return req.socket.remoteAddress.replace(/^::ffff:/, "");
}
return undefined;
}
/**
* Parse request body as JSON
*/
export function parseRequestBody(req: IncomingMessage): Promise<any> {
return new Promise((resolve, reject) => {
let body = "";
req.on("data", (chunk) => {
body += chunk.toString();
});
req.on("end", () => {
try {
if (body) {
resolve(JSON.parse(body));
} else {
resolve({});
}
} catch (error) {
console.error("Error parsing request body:", error);
reject(new Error("Invalid JSON in request body"));
}
});
req.on("error", (error) => {
reject(error);
});
});
}