client.ts

836 B · raw

1import type { Context } from "hono";23const LOOPBACK = /^(127\.|::1$|::ffff:127\.)/;45/**6 * The client's address, for rate limits. The socket peer, unless the peer is loopback: then it is7 * a reverse proxy on the same host (HAProxy in production), and the address is the8 * rightmost `X-Forwarded-For` entry, the one that proxy appended. Anything to its left came from9 * the client and could be forged, so it is never trusted.10 */11export function clientIp(c: Context): string {12	// Bun passes its server as the env; a test passes a stand-in with the same method.13	const server = c.env as { requestIP?: (request: Request) => { address: string } | null };14	const peer = server?.requestIP?.(c.req.raw)?.address ?? "";15	if (!LOOPBACK.test(peer)) return peer;16	return c.req.header("x-forwarded-for")?.split(",").at(-1)?.trim() || peer;17}