hono-ip 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,3 +1,367 @@
1
+ // src/validate.ts
2
+ import ipaddr from "ipaddr.js";
3
+ function parseIp(raw) {
4
+ if (typeof raw !== "string")
5
+ return null;
6
+ const trimmed = raw.trim();
7
+ if (!trimmed)
8
+ return null;
9
+ const zoneIdx = trimmed.indexOf("%");
10
+ const candidate = zoneIdx === -1 ? trimmed : trimmed.slice(0, zoneIdx);
11
+ if (ipaddr.IPv4.isValidFourPartDecimal(candidate)) {
12
+ return candidate;
13
+ }
14
+ if (ipaddr.IPv6.isValid(candidate)) {
15
+ const v6 = ipaddr.IPv6.parse(candidate);
16
+ if (v6.isIPv4MappedAddress()) {
17
+ return v6.toIPv4Address().toString();
18
+ }
19
+ return v6.toNormalizedString();
20
+ }
21
+ return null;
22
+ }
23
+ function isIpV4(ip) {
24
+ return ipaddr.IPv4.isValidFourPartDecimal(ip);
25
+ }
26
+ function isIpV6(ip) {
27
+ return !isIpV4(ip);
28
+ }
29
+ function ipKind(ip) {
30
+ return isIpV4(ip) ? "ipv4" : "ipv6";
31
+ }
32
+ function extractIp(raw) {
33
+ if (typeof raw !== "string")
34
+ return null;
35
+ let s = raw.trim();
36
+ if (!s)
37
+ return null;
38
+ if (s.startsWith("[")) {
39
+ const close = s.indexOf("]");
40
+ if (close === -1)
41
+ return null;
42
+ s = s.slice(1, close);
43
+ return parseIp(s);
44
+ }
45
+ const firstColon = s.indexOf(":");
46
+ const lastColon = s.lastIndexOf(":");
47
+ if (firstColon !== -1 && firstColon === lastColon) {
48
+ const left = s.slice(0, firstColon);
49
+ if (ipaddr.IPv4.isValidFourPartDecimal(left)) {
50
+ return parseIp(left);
51
+ }
52
+ }
53
+ return parseIp(s);
54
+ }
55
+ function isCidr(value) {
56
+ return ipaddr.isValidCIDR(value);
57
+ }
58
+ // src/trust.ts
59
+ import ipaddr2 from "ipaddr.js";
60
+ var PRESETS = {
61
+ loopback: ["127.0.0.0/8", "::1/128"],
62
+ linklocal: ["169.254.0.0/16", "fe80::/10"],
63
+ uniquelocal: ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "fc00::/7"],
64
+ private: [
65
+ "127.0.0.0/8",
66
+ "::1/128",
67
+ "10.0.0.0/8",
68
+ "172.16.0.0/12",
69
+ "192.168.0.0/16",
70
+ "fc00::/7",
71
+ "fe80::/10"
72
+ ],
73
+ cloudflare: [
74
+ "173.245.48.0/20",
75
+ "103.21.244.0/22",
76
+ "103.22.200.0/22",
77
+ "103.31.4.0/22",
78
+ "141.101.64.0/18",
79
+ "108.162.192.0/18",
80
+ "190.93.240.0/20",
81
+ "188.114.96.0/20",
82
+ "197.234.240.0/22",
83
+ "198.41.128.0/17",
84
+ "162.158.0.0/15",
85
+ "104.16.0.0/13",
86
+ "104.24.0.0/14",
87
+ "172.64.0.0/13",
88
+ "131.0.72.0/22",
89
+ "2400:cb00::/32",
90
+ "2606:4700::/32",
91
+ "2803:f800::/32",
92
+ "2405:b500::/32",
93
+ "2405:8100::/32",
94
+ "2a06:98c0::/29",
95
+ "2c0f:f248::/32"
96
+ ]
97
+ };
98
+ function compileTrust(input) {
99
+ if (input === "all")
100
+ return () => true;
101
+ if (input === "none")
102
+ return () => false;
103
+ if (typeof input === "function")
104
+ return input;
105
+ const v4Ranges = [];
106
+ const v6Ranges = [];
107
+ for (const entry of input) {
108
+ if (entry in PRESETS) {
109
+ for (const cidr of PRESETS[entry]) {
110
+ pushRange(cidr, v4Ranges, v6Ranges);
111
+ }
112
+ } else {
113
+ if (!isCidr(entry)) {
114
+ throw new Error(`[ip-middleware] Invalid CIDR or preset name: "${entry}"`);
115
+ }
116
+ pushRange(entry, v4Ranges, v6Ranges);
117
+ }
118
+ }
119
+ return (ip) => {
120
+ let parsed;
121
+ try {
122
+ parsed = ipaddr2.parse(ip);
123
+ } catch {
124
+ return false;
125
+ }
126
+ const ranges = parsed.kind() === "ipv4" ? v4Ranges : v6Ranges;
127
+ for (const range of ranges) {
128
+ if (parsed.match(range))
129
+ return true;
130
+ }
131
+ return false;
132
+ };
133
+ }
134
+ function pushRange(cidr, v4, v6) {
135
+ const [addr, bits] = ipaddr2.parseCIDR(cidr);
136
+ if (addr.kind() === "ipv4")
137
+ v4.push([addr, bits]);
138
+ else
139
+ v6.push([addr, bits]);
140
+ }
141
+ // src/parsers.ts
142
+ import forwardedParse from "forwarded-parse";
143
+
144
+ // src/types.ts
145
+ var MAX_HEADER_BYTES = 8 * 1024;
146
+ var MAX_CHAIN_ENTRIES = 50;
147
+
148
+ // src/parsers.ts
149
+ function asNonEmpty(arr) {
150
+ if (arr.length === 0)
151
+ return null;
152
+ return arr;
153
+ }
154
+ function parseXForwardedFor(raw) {
155
+ if (!raw)
156
+ return { ok: false, reason: "empty" };
157
+ if (raw.length > MAX_HEADER_BYTES)
158
+ return { ok: false, reason: "too-large" };
159
+ const parts = raw.split(",");
160
+ if (parts.length > MAX_CHAIN_ENTRIES) {
161
+ return { ok: false, reason: "too-many" };
162
+ }
163
+ const chain = [];
164
+ for (const part of parts) {
165
+ const ip = extractIp(part);
166
+ if (ip)
167
+ chain.push(ip);
168
+ }
169
+ const nonEmpty = asNonEmpty(chain);
170
+ if (!nonEmpty)
171
+ return { ok: false, reason: "empty" };
172
+ return { ok: true, chain: nonEmpty };
173
+ }
174
+ function parseForwarded(raw) {
175
+ if (!raw)
176
+ return { ok: false, reason: "empty" };
177
+ if (raw.length > MAX_HEADER_BYTES)
178
+ return { ok: false, reason: "too-large" };
179
+ let entries;
180
+ try {
181
+ entries = forwardedParse(raw);
182
+ } catch {
183
+ return { ok: false, reason: "empty" };
184
+ }
185
+ if (entries.length > MAX_CHAIN_ENTRIES) {
186
+ return { ok: false, reason: "too-many" };
187
+ }
188
+ const chain = [];
189
+ for (const entry of entries) {
190
+ const forValue = entry.for;
191
+ if (!forValue)
192
+ continue;
193
+ const ip = extractIp(forValue);
194
+ if (ip)
195
+ chain.push(ip);
196
+ }
197
+ const nonEmpty = asNonEmpty(chain);
198
+ if (!nonEmpty)
199
+ return { ok: false, reason: "empty" };
200
+ return { ok: true, chain: nonEmpty };
201
+ }
202
+ // src/presets.ts
203
+ var cloudflare = () => ({
204
+ kind: "single-header",
205
+ header: "cf-connecting-ip"
206
+ });
207
+ var fly = () => ({
208
+ kind: "single-header",
209
+ header: "fly-client-ip"
210
+ });
211
+ var vercel = () => ({
212
+ kind: "single-header",
213
+ header: "x-real-ip"
214
+ });
215
+ var behindReverseProxy = (opts = {}) => ({
216
+ kind: "xff-rightmost-untrusted",
217
+ trustedProxies: opts.trustedProxies ?? ["loopback", "uniquelocal"]
218
+ });
219
+ var direct = (getConnInfo) => ({
220
+ kind: "conn-info",
221
+ getConnInfo
222
+ });
223
+ // src/middleware.ts
224
+ import { createMiddleware } from "hono/factory";
225
+
226
+ // src/strategies.ts
227
+ function compileStrategy(strategy) {
228
+ switch (strategy.kind) {
229
+ case "single-header":
230
+ return resolveSingleHeader(strategy.header.toLowerCase());
231
+ case "xff-rightmost-untrusted":
232
+ return resolveXffTrusted(compileTrust(strategy.trustedProxies));
233
+ case "xff-leftmost-insecure":
234
+ return resolveXffLeftmost();
235
+ case "forwarded-rightmost-untrusted":
236
+ return resolveForwardedTrusted(compileTrust(strategy.trustedProxies));
237
+ case "conn-info":
238
+ return resolveConnInfo(strategy.getConnInfo);
239
+ case "first-of": {
240
+ const compiled = strategy.strategies.map(compileStrategy);
241
+ return (c) => {
242
+ let lastFailure = {
243
+ ok: false,
244
+ reason: "no-header",
245
+ attempted: "none"
246
+ };
247
+ for (const r of compiled) {
248
+ const out = r(c);
249
+ if (out.ok)
250
+ return out;
251
+ lastFailure = out;
252
+ }
253
+ return lastFailure;
254
+ };
255
+ }
256
+ }
257
+ }
258
+ function resolveSingleHeader(header) {
259
+ return (c) => {
260
+ const raw = c.req.header(header);
261
+ if (!raw) {
262
+ return { ok: false, reason: "no-header", attempted: "single-header" };
263
+ }
264
+ const ip = parseIp(raw);
265
+ if (!ip) {
266
+ return {
267
+ ok: false,
268
+ reason: "header-malformed",
269
+ attempted: "single-header"
270
+ };
271
+ }
272
+ return { ok: true, ip, source: "single-header" };
273
+ };
274
+ }
275
+ function resolveXffTrusted(trust) {
276
+ return (c) => {
277
+ const result = parseXForwardedFor(c.req.header("x-forwarded-for"));
278
+ return walkChainTrusted(result, trust, "xff-rightmost-untrusted");
279
+ };
280
+ }
281
+ function resolveForwardedTrusted(trust) {
282
+ return (c) => {
283
+ const result = parseForwarded(c.req.header("forwarded"));
284
+ return walkChainTrusted(result, trust, "forwarded-rightmost-untrusted");
285
+ };
286
+ }
287
+ function walkChainTrusted(parsed, trust, source) {
288
+ if (!parsed.ok) {
289
+ const reason = parsed.reason === "too-large" ? "header-too-large" : parsed.reason === "too-many" ? "too-many-entries" : "header-empty";
290
+ return { ok: false, reason, attempted: source };
291
+ }
292
+ const { chain } = parsed;
293
+ for (let i = chain.length - 1;i >= 0; i--) {
294
+ const ip = chain[i];
295
+ if (!trust(ip)) {
296
+ return { ok: true, ip, source, hopIndex: i };
297
+ }
298
+ }
299
+ return { ok: false, reason: "all-hops-trusted", attempted: source };
300
+ }
301
+ function resolveXffLeftmost() {
302
+ return (c) => {
303
+ const result = parseXForwardedFor(c.req.header("x-forwarded-for"));
304
+ if (!result.ok) {
305
+ return {
306
+ ok: false,
307
+ reason: result.reason === "empty" ? "header-empty" : "header-malformed",
308
+ attempted: "xff-leftmost-explicit-insecure"
309
+ };
310
+ }
311
+ const [head] = result.chain;
312
+ return {
313
+ ok: true,
314
+ ip: head,
315
+ source: "xff-leftmost-explicit-insecure",
316
+ hopIndex: 0
317
+ };
318
+ };
319
+ }
320
+ function resolveConnInfo(getConnInfo) {
321
+ return (c) => {
322
+ let addr;
323
+ try {
324
+ addr = getConnInfo(c)?.remote?.address;
325
+ } catch {
326
+ return {
327
+ ok: false,
328
+ reason: "conn-info-unavailable",
329
+ attempted: "conn-info"
330
+ };
331
+ }
332
+ if (!addr) {
333
+ return {
334
+ ok: false,
335
+ reason: "conn-info-unavailable",
336
+ attempted: "conn-info"
337
+ };
338
+ }
339
+ const ip = parseIp(addr);
340
+ if (!ip) {
341
+ return { ok: false, reason: "header-malformed", attempted: "conn-info" };
342
+ }
343
+ return { ok: true, ip, source: "conn-info" };
344
+ };
345
+ }
346
+
347
+ // src/middleware.ts
348
+ function ipMiddleware(opts) {
349
+ const variable = opts.variable ?? "ip";
350
+ const outcomeVar = `${variable}Outcome`;
351
+ const resolve = compileStrategy(opts.strategy);
352
+ return createMiddleware(async (c, next) => {
353
+ const outcome = resolve(c);
354
+ c.set(variable, outcome.ok ? outcome.ip : null);
355
+ c.set(outcomeVar, outcome);
356
+ if (!outcome.ok) {
357
+ opts.onFailure?.(outcome);
358
+ if (opts.required) {
359
+ return c.text("Unable to determine client IP", 400);
360
+ }
361
+ }
362
+ await next();
363
+ });
364
+ }
1
365
  export {
2
366
  vercel,
3
367
  parseXForwardedFor,
@@ -17,4 +381,4 @@ export {
17
381
  PRESETS
18
382
  };
19
383
 
20
- //# debugId=211C0359C15CA00664756E2164756E21
384
+ //# debugId=76B7D6C1CC08A7D664756E2164756E21
package/dist/index.js.map CHANGED
@@ -1,9 +1,16 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": [],
3
+ "sources": ["../src/validate.ts", "../src/trust.ts", "../src/parsers.ts", "../src/types.ts", "../src/presets.ts", "../src/middleware.ts", "../src/strategies.ts"],
4
4
  "sourcesContent": [
5
+ "import ipaddr from \"ipaddr.js\";\nimport type { IpAddress, IpV4, IpV6, IpKind, Cidr } from \"./types.js\";\n\nexport function parseIp(raw: string): IpAddress | null {\n if (typeof raw !== \"string\") return null;\n const trimmed = raw.trim();\n if (!trimmed) return null;\n\n const zoneIdx = trimmed.indexOf(\"%\");\n const candidate = zoneIdx === -1 ? trimmed : trimmed.slice(0, zoneIdx);\n\n if (ipaddr.IPv4.isValidFourPartDecimal(candidate)) {\n return candidate as IpAddress;\n }\n if (ipaddr.IPv6.isValid(candidate)) {\n const v6 = ipaddr.IPv6.parse(candidate);\n if (v6.isIPv4MappedAddress()) {\n return v6.toIPv4Address().toString() as IpAddress;\n }\n return v6.toNormalizedString() as IpAddress;\n }\n return null;\n}\n\nexport function isIpV4(ip: IpAddress): ip is IpV4 {\n return ipaddr.IPv4.isValidFourPartDecimal(ip);\n}\n\nexport function isIpV6(ip: IpAddress): ip is IpV6 {\n return !isIpV4(ip);\n}\n\nexport function ipKind(ip: IpAddress): IpKind {\n return isIpV4(ip) ? \"ipv4\" : \"ipv6\";\n}\n\nexport function extractIp(raw: string): IpAddress | null {\n if (typeof raw !== \"string\") return null;\n let s = raw.trim();\n if (!s) return null;\n\n if (s.startsWith(\"[\")) {\n const close = s.indexOf(\"]\");\n if (close === -1) return null;\n s = s.slice(1, close);\n return parseIp(s);\n }\n\n const firstColon = s.indexOf(\":\");\n const lastColon = s.lastIndexOf(\":\");\n if (firstColon !== -1 && firstColon === lastColon) {\n const left = s.slice(0, firstColon);\n if (ipaddr.IPv4.isValidFourPartDecimal(left)) {\n return parseIp(left);\n }\n }\n return parseIp(s);\n}\n\nexport function isCidr(value: string): value is Cidr {\n return ipaddr.isValidCIDR(value);\n}\n",
6
+ "import ipaddr from \"ipaddr.js\";\nimport type { IpAddress, Cidr } from \"./types.js\";\nimport { isCidr } from \"./validate.js\";\n\nexport const PRESETS = {\n loopback: [\"127.0.0.0/8\", \"::1/128\"],\n linklocal: [\"169.254.0.0/16\", \"fe80::/10\"],\n uniquelocal: [\"10.0.0.0/8\", \"172.16.0.0/12\", \"192.168.0.0/16\", \"fc00::/7\"],\n private: [\n \"127.0.0.0/8\",\n \"::1/128\",\n \"10.0.0.0/8\",\n \"172.16.0.0/12\",\n \"192.168.0.0/16\",\n \"fc00::/7\",\n \"fe80::/10\",\n ],\n cloudflare: [\n \"173.245.48.0/20\",\n \"103.21.244.0/22\",\n \"103.22.200.0/22\",\n \"103.31.4.0/22\",\n \"141.101.64.0/18\",\n \"108.162.192.0/18\",\n \"190.93.240.0/20\",\n \"188.114.96.0/20\",\n \"197.234.240.0/22\",\n \"198.41.128.0/17\",\n \"162.158.0.0/15\",\n \"104.16.0.0/13\",\n \"104.24.0.0/14\",\n \"172.64.0.0/13\",\n \"131.0.72.0/22\",\n \"2400:cb00::/32\",\n \"2606:4700::/32\",\n \"2803:f800::/32\",\n \"2405:b500::/32\",\n \"2405:8100::/32\",\n \"2a06:98c0::/29\",\n \"2c0f:f248::/32\",\n ],\n} as const satisfies Record<string, readonly string[]>;\n\nexport type PresetName = keyof typeof PRESETS;\n\nexport type TrustedProxiesInput =\n | ReadonlyArray<string | PresetName>\n | ((ip: IpAddress) => boolean)\n | \"all\"\n | \"none\";\n\ntype ParsedRange = readonly [ipaddr.IPv4 | ipaddr.IPv6, number];\n\nexport type TrustFn = (ip: IpAddress) => boolean;\n\nexport function compileTrust(input: TrustedProxiesInput): TrustFn {\n if (input === \"all\") return () => true;\n if (input === \"none\") return () => false;\n if (typeof input === \"function\") return input;\n\n const v4Ranges: ParsedRange[] = [];\n const v6Ranges: ParsedRange[] = [];\n\n for (const entry of input) {\n if (entry in PRESETS) {\n for (const cidr of PRESETS[entry as PresetName]) {\n pushRange(cidr, v4Ranges, v6Ranges);\n }\n } else {\n if (!isCidr(entry)) {\n throw new Error(\n `[ip-middleware] Invalid CIDR or preset name: \"${entry}\"`,\n );\n }\n pushRange(entry, v4Ranges, v6Ranges);\n }\n }\n\n return (ip: IpAddress): boolean => {\n let parsed: ipaddr.IPv4 | ipaddr.IPv6;\n try {\n parsed = ipaddr.parse(ip);\n } catch {\n return false;\n }\n const ranges = parsed.kind() === \"ipv4\" ? v4Ranges : v6Ranges;\n for (const range of ranges) {\n if (parsed.match(range as [typeof parsed, number])) return true;\n }\n return false;\n };\n}\n\nfunction pushRange(cidr: string, v4: ParsedRange[], v6: ParsedRange[]): void {\n const [addr, bits] = ipaddr.parseCIDR(cidr as Cidr);\n if (addr.kind() === \"ipv4\") v4.push([addr, bits]);\n else v6.push([addr, bits]);\n}\n",
7
+ "import forwardedParse from \"forwarded-parse\";\nimport { extractIp } from \"./validate.js\";\nimport {\n MAX_CHAIN_ENTRIES,\n MAX_HEADER_BYTES,\n type IpAddress,\n type NonEmptyReadonlyArray,\n} from \"./types.js\";\n\nexport type ChainParseResult =\n | {\n readonly ok: true;\n readonly chain: NonEmptyReadonlyArray<IpAddress>;\n }\n | {\n readonly ok: false;\n readonly reason: \"too-large\" | \"too-many\" | \"empty\";\n };\n\nfunction asNonEmpty<T>(arr: T[]): NonEmptyReadonlyArray<T> | null {\n if (arr.length === 0) return null;\n return arr as unknown as NonEmptyReadonlyArray<T>;\n}\n\nexport function parseXForwardedFor(raw: string | undefined): ChainParseResult {\n if (!raw) return { ok: false, reason: \"empty\" };\n if (raw.length > MAX_HEADER_BYTES) return { ok: false, reason: \"too-large\" };\n\n const parts = raw.split(\",\");\n if (parts.length > MAX_CHAIN_ENTRIES) {\n return { ok: false, reason: \"too-many\" };\n }\n\n const chain: IpAddress[] = [];\n for (const part of parts) {\n const ip = extractIp(part);\n if (ip) chain.push(ip);\n }\n const nonEmpty = asNonEmpty(chain);\n if (!nonEmpty) return { ok: false, reason: \"empty\" };\n return { ok: true, chain: nonEmpty };\n}\n\nexport function parseForwarded(raw: string | undefined): ChainParseResult {\n if (!raw) return { ok: false, reason: \"empty\" };\n if (raw.length > MAX_HEADER_BYTES) return { ok: false, reason: \"too-large\" };\n\n let entries: ReadonlyArray<Record<string, string>>;\n try {\n entries = forwardedParse(raw);\n } catch {\n return { ok: false, reason: \"empty\" };\n }\n\n if (entries.length > MAX_CHAIN_ENTRIES) {\n return { ok: false, reason: \"too-many\" };\n }\n\n const chain: IpAddress[] = [];\n for (const entry of entries) {\n const forValue = entry.for;\n if (!forValue) continue;\n const ip = extractIp(forValue);\n if (ip) chain.push(ip);\n }\n const nonEmpty = asNonEmpty(chain);\n if (!nonEmpty) return { ok: false, reason: \"empty\" };\n return { ok: true, chain: nonEmpty };\n}\n",
8
+ "declare const IpAddressBrand: unique symbol;\ndeclare const IpV4Brand: unique symbol;\ndeclare const IpV6Brand: unique symbol;\ndeclare const CidrBrand: unique symbol;\n\nexport type IpAddress = string & { readonly [IpAddressBrand]: true };\nexport type IpV4 = IpAddress & { readonly [IpV4Brand]: true };\nexport type IpV6 = IpAddress & { readonly [IpV6Brand]: true };\nexport type Cidr = string & { readonly [CidrBrand]: true };\n\nexport type IpKind = \"ipv4\" | \"ipv6\";\n\nexport type NonEmptyReadonlyArray<T> = readonly [T, ...T[]];\n\nexport type ResolutionOutcome =\n | {\n readonly ok: true;\n readonly ip: IpAddress;\n readonly source: ResolutionSource;\n readonly hopIndex?: number;\n }\n | {\n readonly ok: false;\n readonly reason: ResolutionFailure;\n readonly attempted: ResolutionSource;\n };\n\nexport type ResolutionSource =\n | \"single-header\"\n | \"xff-rightmost-untrusted\"\n | \"xff-leftmost-explicit-insecure\"\n | \"forwarded-rightmost-untrusted\"\n | \"conn-info\"\n | \"none\";\n\nexport type ResolutionFailure =\n | \"no-header\"\n | \"header-empty\"\n | \"header-malformed\"\n | \"all-hops-trusted\"\n | \"no-untrusted-hop\"\n | \"conn-info-unavailable\"\n | \"header-too-large\"\n | \"too-many-entries\";\n\nexport const MAX_HEADER_BYTES = 8 * 1024;\nexport const MAX_CHAIN_ENTRIES = 50;\n",
9
+ "import type { Context } from \"hono\";\nimport type { Strategy } from \"./strategies.js\";\n\nexport const cloudflare = (): Strategy => ({\n kind: \"single-header\",\n header: \"cf-connecting-ip\",\n});\n\nexport const fly = (): Strategy => ({\n kind: \"single-header\",\n header: \"fly-client-ip\",\n});\n\nexport const vercel = (): Strategy => ({\n kind: \"single-header\",\n header: \"x-real-ip\",\n});\n\nexport const behindReverseProxy = (\n opts: {\n trustedProxies?: Strategy & { kind: \"xff-rightmost-untrusted\" } extends {\n trustedProxies: infer T;\n }\n ? T\n : never;\n } = {},\n): Strategy => ({\n kind: \"xff-rightmost-untrusted\",\n trustedProxies: opts.trustedProxies ?? [\"loopback\", \"uniquelocal\"],\n});\n\nexport const direct = (\n getConnInfo: (c: Context) => { remote?: { address?: string } },\n): Strategy => ({\n kind: \"conn-info\",\n getConnInfo,\n});\n",
10
+ "import { createMiddleware } from \"hono/factory\";\nimport type { Env, MiddlewareHandler } from \"hono\";\nimport { compileStrategy, type Strategy } from \"./strategies.js\";\nimport type { IpAddress, ResolutionOutcome } from \"./types.js\";\n\nexport interface IpMiddlewareOptions<K extends string = \"ip\"> {\n readonly strategy: Strategy;\n readonly variable?: K;\n readonly onFailure?: (\n outcome: Extract<ResolutionOutcome, { ok: false }>,\n ) => void;\n readonly required?: boolean;\n}\n\nexport type IpVariables<K extends string = \"ip\"> = {\n readonly [P in K]: IpAddress | null;\n} & {\n readonly [P in `${K}Outcome`]: ResolutionOutcome;\n};\n\nexport function ipMiddleware<K extends string = \"ip\">(\n opts: IpMiddlewareOptions<K>,\n): MiddlewareHandler<{ Variables: IpVariables<K> } & Env> {\n const variable = (opts.variable ?? \"ip\") as K;\n const outcomeVar = `${variable}Outcome` as const;\n const resolve = compileStrategy(opts.strategy);\n\n return createMiddleware<{ Variables: IpVariables<K> }>(async (c, next) => {\n const outcome = resolve(c);\n\n c.set(variable as never, (outcome.ok ? outcome.ip : null) as never);\n c.set(outcomeVar as never, outcome as never);\n\n if (!outcome.ok) {\n opts.onFailure?.(outcome);\n if (opts.required) {\n return c.text(\"Unable to determine client IP\", 400);\n }\n }\n\n await next();\n });\n}\n",
11
+ "import type { Context } from \"hono\";\nimport { parseIp } from \"./validate.js\";\nimport { parseXForwardedFor, parseForwarded } from \"./parsers.js\";\nimport {\n compileTrust,\n type TrustedProxiesInput,\n type TrustFn,\n} from \"./trust.js\";\nimport type { IpAddress, ResolutionOutcome } from \"./types.js\";\n\nexport type Strategy =\n | { readonly kind: \"single-header\"; readonly header: string }\n | {\n readonly kind: \"xff-rightmost-untrusted\";\n readonly trustedProxies: TrustedProxiesInput;\n }\n | { readonly kind: \"xff-leftmost-insecure\" }\n | {\n readonly kind: \"forwarded-rightmost-untrusted\";\n readonly trustedProxies: TrustedProxiesInput;\n }\n | {\n readonly kind: \"conn-info\";\n readonly getConnInfo: (c: Context) => { remote?: { address?: string } };\n }\n | { readonly kind: \"first-of\"; readonly strategies: readonly Strategy[] };\n\ntype Resolver = (c: Context) => ResolutionOutcome;\n\nexport function compileStrategy(strategy: Strategy): Resolver {\n switch (strategy.kind) {\n case \"single-header\":\n return resolveSingleHeader(strategy.header.toLowerCase());\n case \"xff-rightmost-untrusted\":\n return resolveXffTrusted(compileTrust(strategy.trustedProxies));\n case \"xff-leftmost-insecure\":\n return resolveXffLeftmost();\n case \"forwarded-rightmost-untrusted\":\n return resolveForwardedTrusted(compileTrust(strategy.trustedProxies));\n case \"conn-info\":\n return resolveConnInfo(strategy.getConnInfo);\n case \"first-of\": {\n const compiled = strategy.strategies.map(compileStrategy);\n return (c) => {\n let lastFailure: ResolutionOutcome = {\n ok: false,\n reason: \"no-header\",\n attempted: \"none\",\n };\n for (const r of compiled) {\n const out = r(c);\n if (out.ok) return out;\n lastFailure = out;\n }\n return lastFailure;\n };\n }\n }\n}\n\nfunction resolveSingleHeader(header: string): Resolver {\n return (c) => {\n const raw = c.req.header(header);\n if (!raw) {\n return { ok: false, reason: \"no-header\", attempted: \"single-header\" };\n }\n const ip = parseIp(raw);\n if (!ip) {\n return {\n ok: false,\n reason: \"header-malformed\",\n attempted: \"single-header\",\n };\n }\n return { ok: true, ip, source: \"single-header\" };\n };\n}\n\nfunction resolveXffTrusted(trust: TrustFn): Resolver {\n return (c) => {\n const result = parseXForwardedFor(c.req.header(\"x-forwarded-for\"));\n return walkChainTrusted(result, trust, \"xff-rightmost-untrusted\");\n };\n}\n\nfunction resolveForwardedTrusted(trust: TrustFn): Resolver {\n return (c) => {\n const result = parseForwarded(c.req.header(\"forwarded\"));\n return walkChainTrusted(result, trust, \"forwarded-rightmost-untrusted\");\n };\n}\n\nfunction walkChainTrusted(\n parsed: ReturnType<typeof parseXForwardedFor>,\n trust: TrustFn,\n source: \"xff-rightmost-untrusted\" | \"forwarded-rightmost-untrusted\",\n): ResolutionOutcome {\n if (!parsed.ok) {\n const reason =\n parsed.reason === \"too-large\"\n ? \"header-too-large\"\n : parsed.reason === \"too-many\"\n ? \"too-many-entries\"\n : \"header-empty\";\n return { ok: false, reason, attempted: source };\n }\n\n const { chain } = parsed;\n for (let i = chain.length - 1; i >= 0; i--) {\n const ip: IpAddress = chain[i] as IpAddress;\n if (!trust(ip)) {\n return { ok: true, ip, source, hopIndex: i };\n }\n }\n return { ok: false, reason: \"all-hops-trusted\", attempted: source };\n}\n\nfunction resolveXffLeftmost(): Resolver {\n return (c) => {\n const result = parseXForwardedFor(c.req.header(\"x-forwarded-for\"));\n if (!result.ok) {\n return {\n ok: false,\n reason: result.reason === \"empty\" ? \"header-empty\" : \"header-malformed\",\n attempted: \"xff-leftmost-explicit-insecure\",\n };\n }\n\n const [head] = result.chain;\n return {\n ok: true,\n ip: head,\n source: \"xff-leftmost-explicit-insecure\",\n hopIndex: 0,\n };\n };\n}\n\nfunction resolveConnInfo(\n getConnInfo: (c: Context) => { remote?: { address?: string } },\n): Resolver {\n return (c) => {\n let addr: string | undefined;\n try {\n addr = getConnInfo(c)?.remote?.address;\n } catch {\n return {\n ok: false,\n reason: \"conn-info-unavailable\",\n attempted: \"conn-info\",\n };\n }\n if (!addr) {\n return {\n ok: false,\n reason: \"conn-info-unavailable\",\n attempted: \"conn-info\",\n };\n }\n const ip = parseIp(addr);\n if (!ip) {\n return { ok: false, reason: \"header-malformed\", attempted: \"conn-info\" };\n }\n return { ok: true, ip, source: \"conn-info\" };\n };\n}\n"
5
12
  ],
6
- "mappings": "",
7
- "debugId": "211C0359C15CA00664756E2164756E21",
13
+ "mappings": "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",
14
+ "debugId": "76B7D6C1CC08A7D664756E2164756E21",
8
15
  "names": []
9
16
  }
package/package.json CHANGED
@@ -1,19 +1,12 @@
1
1
  {
2
2
  "name": "hono-ip",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Tiny and fast middleware for Hono that figures out your client's real IP address",
5
5
  "keywords": [
6
6
  "hono",
7
7
  "ip",
8
8
  "middleware",
9
- "client-ip",
10
- "x-forwarded-for",
11
- "forwarded",
12
- "rfc7239",
13
- "cloudflare",
14
- "proxy",
15
- "cidr",
16
- "trusted-proxies"
9
+ "client-ip"
17
10
  ],
18
11
  "type": "module",
19
12
  "main": "./dist/index.js",
@@ -26,7 +19,6 @@
26
19
  },
27
20
  "./package.json": "./package.json"
28
21
  },
29
- "sideEffects": false,
30
22
  "files": [
31
23
  "dist",
32
24
  "README.md",
@@ -60,9 +52,9 @@
60
52
  "ipaddr.js": "^2.4.0"
61
53
  },
62
54
  "devDependencies": {
63
- "@biomejs/biome": "2.4.14",
64
- "@types/bun": "^1.3.13",
65
- "hono": "^4.12.16",
55
+ "@biomejs/biome": "2.4.15",
56
+ "@types/bun": "^1.3.14",
57
+ "hono": "^4.12.18",
66
58
  "typescript": "^6.0.3"
67
59
  }
68
60
  }