/**
 * Trusted proxy configuration and middleware.
 *
 * Resolves the client IP from `X-Forwarded-For` only when the TCP connection
 * originates from a configured trusted proxy. Without this middleware,
 * `get_client_ip` returns `'unknown'`.
 *
 * @module
 */
import type { Context, MiddlewareHandler } from 'hono';
import type { Logger } from '@fuzdev/fuz_util/log.js';
import type { MiddlewareSpec } from './middleware_spec.js';
/**
 * Normalize an IP address for consistent matching and storage.
 *
 * Delegates to `canonicalize_ip` from `ip_canonical.ts` — collapses
 * RFC 5952-equivalent IPv6 forms (`::1`, `::0001`, `0:0:0:0:0:0:0:1`)
 * into a single key, emits IPv4-mapped IPv6 in dotted form, and
 * strips the `::ffff:` prefix from dotted IPv4-mapped values so the
 * bucket collapses to plain IPv4.
 *
 * - Lowercases for case-insensitive IPv6 comparison.
 * - Idempotent: calling twice produces the same result.
 * - Safe on non-IP strings: `normalize_ip('unknown')` returns `'unknown'`.
 *   Malformed inputs (`'attacker:controlled'`, `'::1\n'`,
 *   `'203.0.113.1:8080'`) pass through unchanged so downstream
 *   `validate_ip_strict` can still reject them — canonicalization
 *   never erases the malformed-form signal.
 */
export declare const normalize_ip: (ip: string) => string;
/**
 * Configuration for trusted proxy resolution.
 */
export interface ProxyOptions {
    /** Trusted proxy IPs or CIDR ranges (e.g. `'127.0.0.1'`, `'10.0.0.0/8'`, `'::1'`). */
    trusted_proxies: Array<string>;
    /** Extract the raw TCP connection IP from the Hono context. */
    get_connection_ip: (c: Context) => string | undefined;
    /** Optional logger for proxy resolution diagnostics. */
    log?: Logger;
}
/**
 * A parsed proxy entry — either an exact IP or a CIDR range.
 */
export type ParsedProxy = {
    type: 'ip';
    address: string;
} | {
    type: 'cidr';
    network: bigint;
    prefix: number;
    address_type: 'IPv4' | 'IPv6';
};
/**
 * Parse a trusted proxy entry string into a structured form.
 *
 * Accepts plain IPs (`'127.0.0.1'`, `'::1'`) and CIDR notation (`'10.0.0.0/8'`, `'fe80::/10'`).
 * Plain IPs are normalized (lowercase, IPv4-mapped IPv6 stripped) and validated.
 * CIDR prefixes are validated against address family bounds.
 *
 * @param entry - IP address or CIDR notation
 * @throws Error on invalid IP, invalid CIDR network, or NaN/negative/over-range prefix
 */
export declare const parse_proxy_entry: (entry: string) => ParsedProxy;
/**
 * Strict IP validity check.
 *
 * Defense in depth around Hono's `hono/utils/ipaddr` helpers, which are
 * lax in two ways:
 *
 * 1. `distinctRemoteAddr` classifies anything-with-a-colon as `'IPv6'`,
 *    including `'host:port'`, `'attacker:controlled'`, `'203.0.113.1:8080'`.
 * 2. `convertIPv6ToBinary` silently accepts malformed forms like
 *    `'[::1]:8080'` and `'::1\n'`, parsing them as inconsistent binary
 *    values that would still serve as distinct rate-limit keys for an
 *    attacker rotating the suffix.
 *
 * Strict validation here is two-layered: a character-set pre-filter
 * (`IP_LITERAL_CHARS`), then a round-trip through `convertIPv*ToBinary`
 * to confirm the input parses cleanly. Either layer alone has holes;
 * together they reject every input form we've seen Hono mis-handle.
 *
 * Used as the security primitive for any code path that takes an IP
 * string from an untrusted source (XFF, query params) and uses it as a
 * key (rate limiting, audit subject) or compares it against trusted
 * proxies via CIDR (where the latent throw would otherwise bubble out).
 *
 * @returns the address family on success, `undefined` if the string is
 *          not a strictly-valid IP
 */
export declare const validate_ip_strict: (ip: string) => "IPv4" | "IPv6" | undefined;
/**
 * Check whether `ip` matches any entry in the trusted proxy list.
 *
 * Normalizes `ip` before matching (lowercase, IPv4-mapped IPv6 stripped).
 * Uses `validate_ip_strict` to reject malformed input — without strict
 * validation, Hono's lax `distinctRemoteAddr` would let an entry like
 * `'203.0.113.1:8080'` (false-positive `'IPv6'`) reach
 * `convertIPv6ToBinary` in the CIDR-match branch and throw.
 */
export declare const is_trusted_ip: (ip: string, proxies: Array<ParsedProxy>) => boolean;
/**
 * Resolve the real client IP from an `X-Forwarded-For` header value.
 *
 * Walks right-to-left, skipping trusted proxy entries AND any entry
 * that fails strict IP validation (`validate_ip_strict`). The first
 * untrusted, strictly-valid entry is the client IP. If every walked
 * entry is trusted or malformed, returns the leftmost strictly-valid
 * (trusted) entry (likely-misconfigured all-trusted case) or
 * `undefined` (everything was malformed — middleware falls back to
 * the connection IP). All entries are normalized before matching and
 * in the returned value.
 *
 * Skipping malformed entries is the rate-limit-key fix for the
 * "attacker controls XFF and the proxy passes it through" surface —
 * without the skip, an attacker could rotate arbitrary strings (incl.
 * `'attacker:controlled'`, which Hono's lax `distinctRemoteAddr`
 * misclassifies as IPv6) as XFF values to get fresh per-IP rate-limit
 * buckets. Tradeoff: legitimate non-standard proxies that include
 * ports in XFF entries (e.g. `203.0.113.1:8080`) also fail strict
 * validation, so those entries get skipped and the rate-limit bucket
 * collapses to the proxy's connection IP (one bucket for everyone
 * behind that proxy). Standard proxies (nginx, cloud LBs) don't
 * include ports.
 *
 * @param forwarded_for - the `X-Forwarded-For` header value
 * @param proxies - parsed trusted proxy entries
 * @returns the normalized client IP, or `undefined` if the header is empty / all entries malformed
 */
export declare const resolve_client_ip: (forwarded_for: string, proxies: Array<ParsedProxy>) => string | undefined;
/**
 * Create a Hono middleware that resolves the client IP from trusted proxies.
 *
 * Sets `client_ip` on the Hono context for downstream use by `get_client_ip`.
 * All client IPs are normalized (lowercase, IPv4-mapped IPv6 stripped).
 *
 * Resolution logic:
 * 1. No `X-Forwarded-For` → use connection IP directly.
 * 2. `X-Forwarded-For` present but connection is untrusted → ignore header
 *    (spoofed by a direct attacker), use connection IP.
 * 3. `X-Forwarded-For` present and connection is trusted → walk header
 *    right-to-left, strip trusted entries, use first untrusted entry.
 *
 * @param options - trusted proxy configuration
 * @mutates `c.var.client_ip` - set to the resolved (or `'unknown'`) client IP per request
 * @throws Error if any entry in `options.trusted_proxies` is invalid (parsed eagerly via `parse_proxy_entry`)
 */
export declare const create_proxy_middleware: (options: ProxyOptions) => MiddlewareHandler;
/**
 * Create a middleware spec for trusted proxy resolution.
 *
 * Apply before auth middleware so `client_ip` is available for rate limiting.
 *
 * @param options - trusted proxy configuration
 */
export declare const create_proxy_middleware_spec: (options: ProxyOptions) => MiddlewareSpec;
/**
 * Read the resolved client IP from the Hono context.
 *
 * Returns `'unknown'` if the proxy middleware has not run or no IP is available.
 * Set by `create_proxy_middleware`.
 */
export declare const get_client_ip: (c: Context) => string;
//# sourceMappingURL=proxy.d.ts.map