Spaces:
Paused
Paused
| import { isIP } from "node:net"; | |
| /** | |
| * T07: Extract the real client IP from X-Forwarded-For header. | |
| * Skips invalid entries like "unknown" or empty strings. | |
| * Falls back to remoteAddress if no valid IP found. | |
| * Ref: sub2api PR #1135 | |
| * | |
| * @param xForwardedFor - Value of the X-Forwarded-For header (may be CSV) | |
| * @param remoteAddress - Fallback from the raw socket (req.socket.remoteAddress) | |
| * @returns The first valid IP address found, or "unknown" | |
| */ | |
| export function extractClientIp( | |
| xForwardedFor: string | null | undefined, | |
| remoteAddress: string | undefined | |
| ): string { | |
| if (xForwardedFor) { | |
| const entries = xForwardedFor.split(","); | |
| for (const entry of entries) { | |
| const trimmed = entry.trim(); | |
| if (trimmed && isIP(trimmed) !== 0) { | |
| return trimmed; // First valid IP wins | |
| } | |
| } | |
| } | |
| return remoteAddress?.trim() ?? "unknown"; | |
| } | |
| /** | |
| * Extract client IP from a Request or NextRequest object. | |
| * Checks X-Forwarded-For, X-Real-IP, CF-Connecting-IP, then socket. | |
| */ | |
| export function getClientIpFromRequest(req: { | |
| headers?: Headers | { get?: (n: string) => string | null }; | |
| socket?: { remoteAddress?: string }; | |
| ip?: string; | |
| }): string { | |
| // Helper to get header value from either Headers object or plain object | |
| const getHeader = (name: string): string | null => { | |
| if (!req.headers) return null; | |
| if (typeof (req.headers as Headers).get === "function") { | |
| return (req.headers as Headers).get(name); | |
| } | |
| return null; | |
| }; | |
| // Priority: CF-Connecting-IP (Cloudflare) > X-Forwarded-For > X-Real-IP > socket | |
| const cfIp = getHeader("cf-connecting-ip"); | |
| if (cfIp && isIP(cfIp.trim()) !== 0) return cfIp.trim(); | |
| const xff = getHeader("x-forwarded-for"); | |
| const realIp = getHeader("x-real-ip"); | |
| const remoteAddress = req.ip ?? req.socket?.remoteAddress; | |
| return extractClientIp(xff ?? realIp, remoteAddress); | |
| } | |