@arcjet/ip
Version:
Arcjet utilities for finding the originating IP of a request
184 lines (183 loc) • 4.93 kB
TypeScript
import { CloudflareOptions, cloudflare } from "./cloudflare.js";
//#region src/index.d.ts
type Ipv4Tuple = [number, number, number, number];
type Ipv6Tuple = [number, number, number, number, number, number, number, number];
declare class Ipv4Cidr {
type: "v4";
partSize: 8;
parts: Readonly<Ipv4Tuple>;
bits: number;
constructor(parts: Ipv4Tuple, bits: number);
contains(ip: Array<number>): boolean;
}
declare class Ipv6Cidr {
type: "v6";
partSize: 16;
parts: Readonly<Ipv6Tuple>;
bits: number;
constructor(parts: Ipv6Tuple, bits: number);
contains(ip: Array<number>): boolean;
}
/**
* Parse CIDR addresses and keep non-CIDR IP addresses.
*
* @param value
* Value to parse.
* @returns
* Parsed {@linkcode Cidr} if range or given `value` if IP.
*/
declare function parseProxy(value: string): string | Cidr;
/**
* Parse a list of trusted proxies.
*
* CIDR range strings are parsed to {@linkcode Cidr} (so they match by range);
* plain IP strings and {@linkcode ProxyService} objects (such as those created
* by {@linkcode cloudflare}) are passed through unchanged. Use this to
* normalize the `proxies` option before handing it to {@linkcode findIp}.
*
* @param proxies
* Trusted proxies to parse.
* @returns
* Parsed proxies.
*/
declare function parseProxies(proxies: ReadonlyArray<string | ProxyService>): Array<string | Cidr | ProxyService>;
/**
* Socket-like interface.
*/
interface PartialSocket {
remoteAddress?: string | null | undefined;
}
/**
* Interface that looks like info.
*/
interface PartialInfo {
remoteAddress?: string | null | undefined;
}
interface PartialIdentiy {
sourceIp?: string | null | undefined;
}
/**
* Interface that looks like a request context.
*/
interface PartialRequestContext {
identity?: PartialIdentiy | null | undefined;
}
/**
* Interface with `headers`.
*/
type HeaderLike = {
/**
* Headers.
*/
headers: Headers | Record<string, string[] | string | undefined>;
};
/**
* Interface that looks like a request,
* of which `headers` is required and several other fields may exist.
*/
type RequestLike = {
/**
* Some platforms pass `info`.
*/
info?: PartialInfo | null | undefined;
/**
* Some platforms such as Cloudflare and Vercel provide `ip` directly on
* `request`.
*/
ip?: unknown;
/**
* Some platforms pass info in `requestContext`.
*/
requestContext?: PartialRequestContext | null | undefined;
/**
* Some platforms pass a `socket`.
*/
socket?: PartialSocket | null | undefined;
} & HeaderLike;
/**
* Platform name.
*/
type Platform = "cloudflare" | "firebase" | "fly-io" | "render" | "vercel";
/**
* Format of a client IP header set by a proxy service.
*
* - `"ip"` — a single IP address (e.g. `CF-Connecting-IP`).
* - `"ips"` — an `X-Forwarded-For`-style comma separated list, parsed
* tail-to-head.
*/
type ClientIpFormat = "ip" | "ips";
/**
* A client IP header set by a proxy service.
*/
interface ClientIpHeader {
/**
* Header name (lower-case).
*/
header: string;
/**
* How to parse the header value.
*/
format: ClientIpFormat;
}
/**
* A trusted proxy service (such as Cloudflare) sitting in front of the
* application.
*
* Identified by IP range, with the header(s) that carry the real client IP.
* Create one with a helper such as {@linkcode cloudflare} and include it in the
* `proxies` array.
*/
interface ProxyService {
/**
* Discriminant marking this entry as a proxy service.
*/
kind: "service";
/**
* Name of the service (such as `"cloudflare"`).
*/
name: string;
/**
* IP addresses and CIDR ranges that identify this service.
*/
ranges: ReadonlyArray<string | Cidr>;
/**
* Header(s) this service uses to relay the real client IP, in priority order.
*/
clientIp: ReadonlyArray<ClientIpHeader>;
}
/**
* Configuration.
*/
interface Options {
/**
* Platform the code is running on;
* used to allow only known more trustworthy headers.
*/
platform?: Platform | null | undefined;
/**
* Trusted proxies.
*
* IP addresses and CIDR ranges are treated as trusted load balancers or
* proxies and skipped when finding the client IP. Proxy services created with
* a helper such as {@linkcode cloudflare} additionally declare which header
* carries the real client IP.
*/
proxies?: ReadonlyArray<string | Cidr | ProxyService> | null | undefined;
}
/**
* Find a client IP address on a request-like object.
*
* @param request
* Request-like object.
* @param [options]
* Configuration (optional).
* @returns
* Found IP address; empty string if not found.
*/
declare function findIp(request: RequestLike, options?: Options | null | undefined): string;
/**
* One of the CIDR ranges.
*/
type Cidr = Ipv4Cidr | Ipv6Cidr;
//#endregion
export { Cidr, ClientIpFormat, ClientIpHeader, type CloudflareOptions, HeaderLike, Options, Platform, ProxyService, RequestLike, cloudflare, findIp as default, findIp, parseProxies, parseProxy };