first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
# `forwarded` — `X-Forwarded-Host` trust enforcement
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Implements CIDR-based trust enforcement for the optional
`X-Forwarded-Host` header. Edge proxies (CDN, load balancer, reverse
proxy) rewrite the inbound `Host` to their internal hostname and stash
the public host on `X-Forwarded-Host`. The resolver may honour that
header, but ONLY when (a) the operator opted in via
`trustForwardedHost: true` and (b) the upstream IP belongs to a
trusted-proxy CIDR — otherwise a malicious client could spoof its
tenant by sending `X-Forwarded-Host: victim.api.example.com` directly
to the origin.
This module owns the parser (`parseCidr`, `parseIp`) and the matcher
(`cidrMatches`, `isTrustedProxy`) used by the resolver hot-path.
## Features
- IPv4 and IPv6 support (including `::` shorthand and zone-id stripping).
- Byte-array comparison with bit-aware prefix masking — no string
manipulation in the hot-path.
- Family-disjoint match — an IPv6 CIDR never matches an IPv4 address.
- `parseCidr` returns `null` on malformed input so the caller (options
parser) surfaces a stable `INVALID_OPTIONS` error rather than
silently widening the trust set.
## Usage: Basic
```ts
import {
isTrustedProxy,
parseCidr,
} from "@suaveplan/api-tenant-resolver-subdomain/forwarded";
const cidrs = ["10.0.0.0/8", "2001:db8::/32"]
.map((c) => parseCidr(c)!)
.filter((c) => c !== null);
isTrustedProxy("10.4.7.2", cidrs); // → true
isTrustedProxy("8.8.8.8", cidrs); // → false
```
## Usage: Advanced
```ts
import {
cidrMatches,
parseCidr,
parseIp,
} from "@suaveplan/api-tenant-resolver-subdomain/forwarded";
const cidr = parseCidr("172.16.0.0/12");
const ip = parseIp("172.16.5.99");
if (cidr !== null && ip !== null && cidrMatches(ip, cidr)) {
// ...trusted...
}
```
## API Reference
- `ParsedCidr` — `{ bytes: Uint8Array; prefix: number; family: 4 | 6 }`.
- `parseCidr(input: string): ParsedCidr | null`.
- `parseIp(addr: string): { bytes: Uint8Array; family: 4 | 6 } | null`.
- `cidrMatches(ip, cidr): boolean`.
- `isTrustedProxy(remoteAddress, cidrs): boolean`.
## Implementation Notes
IPv6 parsing handles the canonical `::` double-colon expansion, zone-id
suffixes (`%eth0` is stripped — never meaningful for trust checks),
and rejects > 8 groups or non-hex content. Prefix matching extracts
the full-byte run with a byte-equality loop, then applies a
high-bit mask to the trailing partial byte; `prefix === 0` is the
"match everything in this family" case and is handled implicitly
(loop runs zero times, tail short-circuit returns `true`).
The module is dependency-free — no `node:net`, no `ipaddr.js`. This
keeps the package universal and the CIDR parsing observable in
tests without runtime injection.