@nifrajs/middleware 3.5.0 → 4.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/README.md +11 -6
- package/dist/_ip.d.ts +17 -0
- package/dist/_ip.d.ts.map +1 -0
- package/dist/_ip.js +91 -0
- package/dist/_ip.js.map +1 -0
- package/dist/_utils.d.ts +16 -0
- package/dist/_utils.d.ts.map +1 -1
- package/dist/_utils.js +33 -0
- package/dist/_utils.js.map +1 -1
- package/dist/basic-auth.d.ts.map +1 -1
- package/dist/basic-auth.js +2 -2
- package/dist/basic-auth.js.map +1 -1
- package/dist/body-limit.js +2 -2
- package/dist/body-limit.js.map +1 -1
- package/dist/cache.js +1 -1
- package/dist/cache.js.map +1 -1
- package/dist/compression.d.ts.map +1 -1
- package/dist/compression.js +13 -2
- package/dist/compression.js.map +1 -1
- package/dist/cors.d.ts.map +1 -1
- package/dist/cors.js +50 -5
- package/dist/cors.js.map +1 -1
- package/dist/csrf.d.ts +21 -2
- package/dist/csrf.d.ts.map +1 -1
- package/dist/csrf.js +99 -10
- package/dist/csrf.js.map +1 -1
- package/dist/etag.d.ts.map +1 -1
- package/dist/etag.js +7 -1
- package/dist/etag.js.map +1 -1
- package/dist/idempotency.d.ts +9 -1
- package/dist/idempotency.d.ts.map +1 -1
- package/dist/idempotency.js +24 -8
- package/dist/idempotency.js.map +1 -1
- package/dist/ip-restriction.d.ts +12 -7
- package/dist/ip-restriction.d.ts.map +1 -1
- package/dist/ip-restriction.js +25 -72
- package/dist/ip-restriction.js.map +1 -1
- package/dist/jwt.d.ts.map +1 -1
- package/dist/jwt.js +3 -3
- package/dist/jwt.js.map +1 -1
- package/dist/language.d.ts.map +1 -1
- package/dist/language.js +4 -1
- package/dist/language.js.map +1 -1
- package/dist/multipart.d.ts.map +1 -1
- package/dist/multipart.js +6 -1
- package/dist/multipart.js.map +1 -1
- package/dist/pretty-json.d.ts.map +1 -1
- package/dist/pretty-json.js +63 -7
- package/dist/pretty-json.js.map +1 -1
- package/dist/problem-details.d.ts.map +1 -1
- package/dist/problem-details.js +8 -1
- package/dist/problem-details.js.map +1 -1
- package/dist/range.d.ts.map +1 -1
- package/dist/range.js +5 -2
- package/dist/range.js.map +1 -1
- package/dist/rate-limit.d.ts +11 -10
- package/dist/rate-limit.d.ts.map +1 -1
- package/dist/rate-limit.js +29 -19
- package/dist/rate-limit.js.map +1 -1
- package/dist/request-id.d.ts +8 -1
- package/dist/request-id.d.ts.map +1 -1
- package/dist/request-id.js +6 -3
- package/dist/request-id.js.map +1 -1
- package/dist/security-headers.d.ts +4 -0
- package/dist/security-headers.d.ts.map +1 -1
- package/dist/security-headers.js +7 -1
- package/dist/security-headers.js.map +1 -1
- package/dist/token-auth.d.ts.map +1 -1
- package/dist/token-auth.js +3 -5
- package/dist/token-auth.js.map +1 -1
- package/package.json +6 -3
- package/src/_ip.ts +87 -0
- package/src/_utils.ts +37 -0
- package/src/basic-auth.ts +2 -1
- package/src/body-limit.ts +2 -2
- package/src/cache.ts +1 -1
- package/src/compression.ts +13 -2
- package/src/cors.ts +51 -7
- package/src/csrf.ts +115 -10
- package/src/etag.ts +11 -1
- package/src/idempotency.ts +28 -8
- package/src/ip-restriction.ts +38 -75
- package/src/jwt.ts +4 -2
- package/src/language.ts +5 -1
- package/src/multipart.ts +6 -1
- package/src/pretty-json.ts +56 -7
- package/src/problem-details.ts +8 -1
- package/src/range.ts +6 -3
- package/src/rate-limit.ts +48 -31
- package/src/request-id.ts +16 -4
- package/src/security-headers.ts +7 -1
- package/src/token-auth.ts +3 -5
package/dist/range.js
CHANGED
|
@@ -52,11 +52,14 @@ function ifRangeMatches(value, options) {
|
|
|
52
52
|
const item = value.trim();
|
|
53
53
|
if (options.etag !== undefined)
|
|
54
54
|
return !item.startsWith("W/") && item === options.etag;
|
|
55
|
+
// A date validator must match Last-Modified exactly (RFC 9110 section 13.1.5), not merely be later:
|
|
56
|
+
// a representation replaced by one with an older timestamp would otherwise splice foreign bytes
|
|
57
|
+
// into a resumed download.
|
|
55
58
|
if (options.lastModified === undefined)
|
|
56
59
|
return false;
|
|
57
60
|
const time = Date.parse(item);
|
|
58
61
|
return (Number.isFinite(time) &&
|
|
59
|
-
Math.floor(time / 1000)
|
|
62
|
+
Math.floor(time / 1000) === Math.floor(options.lastModified.getTime() / 1000));
|
|
60
63
|
}
|
|
61
64
|
function shouldReturnNotModified(request, options) {
|
|
62
65
|
if (request.method !== "GET" && request.method !== "HEAD")
|
|
@@ -78,7 +81,7 @@ function shouldReturnNotModified(request, options) {
|
|
|
78
81
|
Math.floor(Date.parse(ifModifiedSince) / 1000) >= Math.floor(lastModified / 1000));
|
|
79
82
|
}
|
|
80
83
|
function responseBody(bytes, request) {
|
|
81
|
-
return request.method === "HEAD" ? null : bytes;
|
|
84
|
+
return request.method === "HEAD" ? null : new Uint8Array(bytes);
|
|
82
85
|
}
|
|
83
86
|
function multipartBytes(bytes, ranges, size, contentType, boundary) {
|
|
84
87
|
const chunks = [];
|
package/dist/range.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"range.js","sourceRoot":"","sources":["../src/range.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"range.js","sourceRoot":"","sources":["../src/range.ts"],"names":[],"mappings":"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"}
|
package/dist/rate-limit.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Middleware } from "@nifrajs/core/server";
|
|
1
|
+
import type { Middleware, Platform } from "@nifrajs/core/server";
|
|
2
2
|
export interface RateLimitResult {
|
|
3
3
|
/** Hits recorded in the current window, including this one. */
|
|
4
4
|
readonly count: number;
|
|
@@ -55,7 +55,8 @@ export interface RateLimitOptions {
|
|
|
55
55
|
readonly windowMs: number;
|
|
56
56
|
/**
|
|
57
57
|
* How many trusted reverse proxies sit in front of the app and append to `X-Forwarded-For`.
|
|
58
|
-
* Default `0`.
|
|
58
|
+
* Default `0`. Prefer the app-level `server({ clientIp: { trustedHops } })` declaration, which the
|
|
59
|
+
* default key already honors; this option is for a limiter that must read XFF on its own.
|
|
59
60
|
*
|
|
60
61
|
* The default key reads the client IP from `X-Forwarded-For` as the address your **edge** proxy
|
|
61
62
|
* observed - the entry `trustedProxies` from the right (1 proxy → the rightmost hop; 2 → the
|
|
@@ -65,23 +66,23 @@ export interface RateLimitOptions {
|
|
|
65
66
|
* ⚠️ With the default `0`, `X-Forwarded-For` is treated as fully client-controlled and **ignored**.
|
|
66
67
|
* Reading the
|
|
67
68
|
* *first* XFF hop - the old behavior - let any client mint a fresh bucket per request and defeat the
|
|
68
|
-
* limiter.
|
|
69
|
-
* trusted single-IP {@link header}, or supply a custom {@link key} (e.g. an authenticated user id).
|
|
69
|
+
* limiter.
|
|
70
70
|
*/
|
|
71
71
|
readonly trustedProxies?: number;
|
|
72
72
|
/** Exact trusted single-IP header, e.g. an infra-set `x-real-ip`. Not read unless configured. */
|
|
73
73
|
readonly header?: string;
|
|
74
74
|
/**
|
|
75
|
-
*
|
|
76
|
-
* client consume the quota for everyone. Enable only for intentional
|
|
75
|
+
* One shared bucket for every request that {@link header}/{@link trustedProxies} cannot key. Off by
|
|
76
|
+
* default because it lets one client consume the quota for everyone. Enable only for intentional
|
|
77
|
+
* global throttles; with neither `header` nor `trustedProxies` set, every request shares the bucket.
|
|
77
78
|
*/
|
|
78
79
|
readonly allowGlobalKey?: boolean;
|
|
79
80
|
/**
|
|
80
|
-
* Bucket key for a request. Overrides the default
|
|
81
|
-
*
|
|
82
|
-
*
|
|
81
|
+
* Bucket key for a request. Overrides the default key entirely - e.g. an authenticated user id.
|
|
82
|
+
* `platform.clientIp` is the caller the app's `clientIp` trust declaration derived (the socket peer
|
|
83
|
+
* when none is declared).
|
|
83
84
|
*/
|
|
84
|
-
readonly key?: (req: Request) => string;
|
|
85
|
+
readonly key?: (req: Request, platform?: Platform) => string;
|
|
85
86
|
}
|
|
86
87
|
/**
|
|
87
88
|
* Rate limiting as a {@link Middleware}. Runs in `onRequest` (before routing, so it
|
package/dist/rate-limit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EAGV,QAAQ,EACT,MAAM,sBAAsB,CAAA;AAI7B,MAAM,WAAW,eAAe;IAC9B,+DAA+D;IAC/D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,+CAA+C;IAC/C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;CAC7D;AAED,MAAM,WAAW,kBAAkB;IACjC,mHAAmH;IACnH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;IACpC;mFAC+E;IAC/E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,2FAA2F;IAC3F,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAClC;AAOD;;;;;;;;GAQG;AACH,qBAAa,WAAY,YAAW,cAAc;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwD;IAChF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAQ;IACxC,OAAO,CAAC,SAAS,CAAI;IACrB,OAAO,CAAC,aAAa,CAAI;IAEzB;;yGAEqG;IACrG,IAAI,iBAAiB,IAAI,MAAM,CAE9B;gBAEW,OAAO,GAAE,kBAAuB;IAiB5C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAmB5D,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,cAAc;CAuBvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAA;IAC9B,uCAAuC;IACvC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,sCAAsC;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;IAChC,iGAAiG;IACjG,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAA;IACjC;;;;OAIG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,QAAQ,KAAK,MAAM,CAAA;CAC7D;AAkED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,UAAU,CAiG/D"}
|
package/dist/rate-limit.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NIFRA_ASSURANCE, withRouteAssurance } from "@nifrajs/core/assurance";
|
|
2
|
-
import {
|
|
2
|
+
import { ipBucket } from "./_ip.js";
|
|
3
|
+
import { guardName, setNodeHeader, withHeaders } from "./_utils.js";
|
|
3
4
|
/** Max entries scanned (oldest-first) per eviction looking for an expired victim before falling back
|
|
4
5
|
* to evicting the oldest-inserted. Bounds eviction to O(1) per insertion instead of a full O(n) sweep
|
|
5
6
|
* under a distinct-key flood - the abuse the key cap defends against. */
|
|
@@ -90,11 +91,21 @@ export class MemoryStore {
|
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
|
-
|
|
94
|
+
/**
|
|
95
|
+
* The default bucket key. With nothing configured it is the caller IP the server resolved into
|
|
96
|
+
* `platform.clientIp` - the raw socket peer, or the app's `clientIp` trust declaration applied to the
|
|
97
|
+
* forwarding chain. `null` (no adapter-observed peer, e.g. a synthetic `app.fetch`) fails closed.
|
|
98
|
+
* Every IP-derived key goes through {@link ipBucket}: an IPv6 caller counts by its /64.
|
|
99
|
+
*/
|
|
100
|
+
function defaultKey(req, platform, trustedProxies, header, allowGlobalKey) {
|
|
101
|
+
if (header === undefined && trustedProxies === 0 && !allowGlobalKey) {
|
|
102
|
+
const peer = platform?.clientIp;
|
|
103
|
+
return peer ? ipBucket(peer) : null;
|
|
104
|
+
}
|
|
94
105
|
if (header !== undefined) {
|
|
95
106
|
const ip = req.headers.get(header);
|
|
96
107
|
if (ip !== null && ip.trim() !== "")
|
|
97
|
-
return ip.trim();
|
|
108
|
+
return ipBucket(ip.trim());
|
|
98
109
|
}
|
|
99
110
|
if (trustedProxies > 0) {
|
|
100
111
|
const xff = req.headers.get("x-forwarded-for");
|
|
@@ -105,7 +116,7 @@ function defaultKey(req, trustedProxies, header, allowGlobalKey) {
|
|
|
105
116
|
// index skips. A chain shorter than `trustedProxies` (misconfig) → undefined → fall through.
|
|
106
117
|
const ip = parts[parts.length - trustedProxies]?.trim();
|
|
107
118
|
if (ip !== undefined && ip !== "")
|
|
108
|
-
return ip;
|
|
119
|
+
return ipBucket(ip);
|
|
109
120
|
}
|
|
110
121
|
}
|
|
111
122
|
// No trusted proxy (or XFF absent/too-short): XFF isn't trustworthy, so don't derive a per-client key
|
|
@@ -113,11 +124,15 @@ function defaultKey(req, trustedProxies, header, allowGlobalKey) {
|
|
|
113
124
|
return allowGlobalKey ? "global" : null;
|
|
114
125
|
}
|
|
115
126
|
/** {@link defaultKey} against the allocation-light native request view - same logic, same order. */
|
|
116
|
-
function nativeKey(req, trustedProxies, header, allowGlobalKey) {
|
|
127
|
+
function nativeKey(req, platform, trustedProxies, header, allowGlobalKey) {
|
|
128
|
+
if (header === undefined && trustedProxies === 0 && !allowGlobalKey) {
|
|
129
|
+
const peer = platform?.clientIp;
|
|
130
|
+
return peer ? ipBucket(peer) : null;
|
|
131
|
+
}
|
|
117
132
|
if (header !== undefined) {
|
|
118
133
|
const ip = req.header(header);
|
|
119
134
|
if (ip !== null && ip.trim() !== "")
|
|
120
|
-
return ip.trim();
|
|
135
|
+
return ipBucket(ip.trim());
|
|
121
136
|
}
|
|
122
137
|
if (trustedProxies > 0) {
|
|
123
138
|
const xff = req.header("x-forwarded-for");
|
|
@@ -125,7 +140,7 @@ function nativeKey(req, trustedProxies, header, allowGlobalKey) {
|
|
|
125
140
|
const parts = xff.split(",");
|
|
126
141
|
const ip = parts[parts.length - trustedProxies]?.trim();
|
|
127
142
|
if (ip !== undefined && ip !== "")
|
|
128
|
-
return ip;
|
|
143
|
+
return ipBucket(ip);
|
|
129
144
|
}
|
|
130
145
|
}
|
|
131
146
|
return allowGlobalKey ? "global" : null;
|
|
@@ -150,13 +165,8 @@ export function rateLimit(options) {
|
|
|
150
165
|
if (header !== undefined && header.trim() === "")
|
|
151
166
|
throw new Error("rateLimit: header is empty");
|
|
152
167
|
const allowGlobalKey = options.allowGlobalKey === true;
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
trustedProxies === 0 &&
|
|
156
|
-
!allowGlobalKey) {
|
|
157
|
-
throw new Error("rateLimit: configure key, header, or trustedProxies; pass allowGlobalKey: true only for an intentional shared bucket");
|
|
158
|
-
}
|
|
159
|
-
const keyOf = options.key ?? ((req) => defaultKey(req, trustedProxies, header, allowGlobalKey));
|
|
168
|
+
const keyOf = options.key ??
|
|
169
|
+
((req, platform) => defaultKey(req, platform, trustedProxies, header, allowGlobalKey));
|
|
160
170
|
const quota = new WeakMap();
|
|
161
171
|
// State for the Node twins, keyed by the NodeRequestContext identity (the same object is passed
|
|
162
172
|
// to the request and response twins - the core identity contract that replaces `Request` keying).
|
|
@@ -180,9 +190,9 @@ export function rateLimit(options) {
|
|
|
180
190
|
return { info, reject: undefined };
|
|
181
191
|
};
|
|
182
192
|
const middleware = {
|
|
183
|
-
name: "rate-limit",
|
|
184
|
-
async onRequest(req) {
|
|
185
|
-
const outcome = await hitStore(keyOf(req));
|
|
193
|
+
name: guardName("rate-limit"),
|
|
194
|
+
async onRequest(req, platform) {
|
|
195
|
+
const outcome = await hitStore(keyOf(req, platform));
|
|
186
196
|
if (outcome instanceof Response)
|
|
187
197
|
return outcome;
|
|
188
198
|
quota.set(req, outcome.info);
|
|
@@ -203,8 +213,8 @@ export function rateLimit(options) {
|
|
|
203
213
|
// takes a real `Request`, which is exactly the object the native lane avoids building.
|
|
204
214
|
...(options.key === undefined
|
|
205
215
|
? {
|
|
206
|
-
onNodeRequest: async (req) => {
|
|
207
|
-
const outcome = await hitStore(nativeKey(req, trustedProxies, header, allowGlobalKey));
|
|
216
|
+
onNodeRequest: async (req, platform) => {
|
|
217
|
+
const outcome = await hitStore(nativeKey(req, platform, trustedProxies, header, allowGlobalKey));
|
|
208
218
|
if (outcome instanceof Response)
|
|
209
219
|
return outcome;
|
|
210
220
|
nativeQuota.set(req, outcome.info);
|
package/dist/rate-limit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;
|
|
1
|
+
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"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"}
|
package/dist/request-id.d.ts
CHANGED
|
@@ -2,8 +2,15 @@ import { type ContextPlugin } from "@nifrajs/core/server";
|
|
|
2
2
|
export interface RequestIdOptions {
|
|
3
3
|
/** Header read for an inbound id (trace propagation) + echoed on the response. Default `"x-request-id"`. */
|
|
4
4
|
readonly header?: string;
|
|
5
|
-
/** Generate an id when the inbound header is absent. Default `crypto.randomUUID()`. */
|
|
5
|
+
/** Generate an id when the inbound header is absent or not accepted. Default `crypto.randomUUID()`. */
|
|
6
6
|
readonly generate?: () => string;
|
|
7
|
+
/**
|
|
8
|
+
* Whether an inbound id is used. The id is client-supplied and lands in logs, traces, and the
|
|
9
|
+
* response, so the default accepts 1-200 visible ASCII characters - no spaces, no control
|
|
10
|
+
* characters (a terminal escape sequence), no unbounded length. A refused id is replaced by a
|
|
11
|
+
* generated one.
|
|
12
|
+
*/
|
|
13
|
+
readonly accept?: (id: string) => boolean;
|
|
7
14
|
}
|
|
8
15
|
/**
|
|
9
16
|
* A {@link defineContextPlugin} plugin that gives every request a stable id: it reuses an inbound
|
package/dist/request-id.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-id.d.ts","sourceRoot":"","sources":["../src/request-id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAuB,MAAM,sBAAsB,CAAA;AAG9E,MAAM,WAAW,gBAAgB;IAC/B,4GAA4G;IAC5G,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,
|
|
1
|
+
{"version":3,"file":"request-id.d.ts","sourceRoot":"","sources":["../src/request-id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAuB,MAAM,sBAAsB,CAAA;AAG9E,MAAM,WAAW,gBAAgB;IAC/B,4GAA4G;IAC5G,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,uGAAuG;IACvG,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,MAAM,CAAA;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAA;CAC1C;AAID;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,aAAa,CAAC;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CA2D9F"}
|
package/dist/request-id.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defineContextPlugin } from "@nifrajs/core/server";
|
|
2
2
|
import { setNodeHeader, withHeaders } from "./_utils.js";
|
|
3
|
+
const INBOUND_ID = /^[\x21-\x7e]{1,200}$/;
|
|
3
4
|
/**
|
|
4
5
|
* A {@link defineContextPlugin} plugin that gives every request a stable id: it reuses an inbound
|
|
5
6
|
* `x-request-id` (or generates one), exposes it on the handler context as **`c.requestId`** (typed,
|
|
@@ -21,6 +22,8 @@ export function requestId(options = {}) {
|
|
|
21
22
|
// the response twin's "already echoed?" probe and the derive's write must agree on it.
|
|
22
23
|
const wireHeader = header.toLowerCase();
|
|
23
24
|
const generate = options.generate ?? (() => crypto.randomUUID());
|
|
25
|
+
const acceptable = options.accept ?? ((id) => INBOUND_ID.test(id));
|
|
26
|
+
const inboundOf = (id) => id !== null && acceptable(id) ? id : null;
|
|
24
27
|
// Web-lane derive-to-response pairing for GENERATED ids (an inbound one is re-readable from the
|
|
25
28
|
// request in onResponse). Entries are deleted in onResponse; a Node-lane derive also writes here
|
|
26
29
|
// but its id travels via the `c.set` write into the outcome record, and the weakly-held entry is
|
|
@@ -44,7 +47,7 @@ export function requestId(options = {}) {
|
|
|
44
47
|
return res;
|
|
45
48
|
// The id the derive generated; else the inbound header, then a fresh id - so a response
|
|
46
49
|
// no derive saw (a 404, an earlier middleware's short-circuit) is still covered.
|
|
47
|
-
const echo = id ?? req.headers.get(header) ?? generate();
|
|
50
|
+
const echo = id ?? inboundOf(req.headers.get(header)) ?? generate();
|
|
48
51
|
return withHeaders(res, (headers) => {
|
|
49
52
|
headers.set(header, echo);
|
|
50
53
|
});
|
|
@@ -55,7 +58,7 @@ export function requestId(options = {}) {
|
|
|
55
58
|
// short-circuit - gets the inbound id or a fresh one here.
|
|
56
59
|
if (res.headers?.[wireHeader] !== undefined)
|
|
57
60
|
return;
|
|
58
|
-
setNodeHeader(res, wireHeader, req.header(header) ?? generate());
|
|
61
|
+
setNodeHeader(res, wireHeader, inboundOf(req.header(header)) ?? generate());
|
|
59
62
|
},
|
|
60
63
|
})
|
|
61
64
|
.derive((c) => {
|
|
@@ -65,7 +68,7 @@ export function requestId(options = {}) {
|
|
|
65
68
|
// carries it into a framework-rendered result on every lane - on Node-direct, into the
|
|
66
69
|
// outcome record, where the response twin sees it as already echoed. Header and
|
|
67
70
|
// `c.requestId` are therefore the same value everywhere with a single generation.
|
|
68
|
-
const inbound = c.header(header);
|
|
71
|
+
const inbound = inboundOf(c.header(header));
|
|
69
72
|
const id = inbound ?? generate();
|
|
70
73
|
if (inbound === null)
|
|
71
74
|
ids.set(c.req, id);
|
package/dist/request-id.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-id.js","sourceRoot":"","sources":["../src/request-id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC9E,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"request-id.js","sourceRoot":"","sources":["../src/request-id.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,6 +33,10 @@ export interface SecurityHeadersOptions {
|
|
|
33
33
|
* Every value is fixed at construction, so these are declared statically rather than written by a
|
|
34
34
|
* response hook: an app whose response middleware is only this keeps the fused native lanes. A route
|
|
35
35
|
* that sets one of these names itself keeps its own value.
|
|
36
|
+
*
|
|
37
|
+
* A group can apply its own configuration over the app's: `group.use(securityHeaders({ ... }))`
|
|
38
|
+
* replaces the app's value of each header it sets, on the group's routes only. Applying the same
|
|
39
|
+
* configuration twice is a no-op.
|
|
36
40
|
*/
|
|
37
41
|
export declare function securityHeaders(options?: SecurityHeadersOptions): Middleware;
|
|
38
42
|
//# sourceMappingURL=security-headers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../src/security-headers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAEtD,MAAM,WAAW,sBAAsB;IACrC,+FAA+F;IAC/F,QAAQ,CAAC,IAAI,CAAC,EAAE;QACd,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;QACvB,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;QACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAC3B,CAAA;IACD,sEAAsE;IACtE,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAA;IACvC,2CAA2C;IAC3C,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,YAAY,CAAA;IAC7C,kDAAkD;IAClD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;IAChC;sFACkF;IAClF,QAAQ,CAAC,uBAAuB,CAAC,EAAE,aAAa,GAAG,0BAA0B,GAAG,aAAa,CAAA;IAC7F;sFACkF;IAClF,QAAQ,CAAC,yBAAyB,CAAC,EAAE,cAAc,GAAG,gBAAgB,GAAG,aAAa,CAAA;IACtF;uCACmC;IACnC,QAAQ,CAAC,yBAAyB,CAAC,EAAE,aAAa,GAAG,WAAW,GAAG,cAAc,CAAA;IACjF,qGAAqG;IACrG,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CACpC;AAED
|
|
1
|
+
{"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../src/security-headers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAEtD,MAAM,WAAW,sBAAsB;IACrC,+FAA+F;IAC/F,QAAQ,CAAC,IAAI,CAAC,EAAE;QACd,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;QACvB,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;QACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAC3B,CAAA;IACD,sEAAsE;IACtE,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAA;IACvC,2CAA2C;IAC3C,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,YAAY,CAAA;IAC7C,kDAAkD;IAClD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;IAChC;sFACkF;IAClF,QAAQ,CAAC,uBAAuB,CAAC,EAAE,aAAa,GAAG,0BAA0B,GAAG,aAAa,CAAA;IAC7F;sFACkF;IAClF,QAAQ,CAAC,yBAAyB,CAAC,EAAE,cAAc,GAAG,gBAAgB,GAAG,aAAa,CAAA;IACtF;uCACmC;IACnC,QAAQ,CAAC,yBAAyB,CAAC,EAAE,aAAa,GAAG,WAAW,GAAG,cAAc,CAAA;IACjF,qGAAqG;IACrG,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CACpC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,sBAA2B,GAAG,UAAU,CA8ChF"}
|
package/dist/security-headers.js
CHANGED
|
@@ -8,6 +8,10 @@ import { NIFRA_ASSURANCE, withRouteAssurance } from "@nifrajs/core/assurance";
|
|
|
8
8
|
* Every value is fixed at construction, so these are declared statically rather than written by a
|
|
9
9
|
* response hook: an app whose response middleware is only this keeps the fused native lanes. A route
|
|
10
10
|
* that sets one of these names itself keeps its own value.
|
|
11
|
+
*
|
|
12
|
+
* A group can apply its own configuration over the app's: `group.use(securityHeaders({ ... }))`
|
|
13
|
+
* replaces the app's value of each header it sets, on the group's routes only. Applying the same
|
|
14
|
+
* configuration twice is a no-op.
|
|
11
15
|
*/
|
|
12
16
|
export function securityHeaders(options = {}) {
|
|
13
17
|
const frameOptions = options.frameOptions ?? "DENY";
|
|
@@ -44,7 +48,9 @@ export function securityHeaders(options = {}) {
|
|
|
44
48
|
declared["permissions-policy"] = options.permissionsPolicy;
|
|
45
49
|
}
|
|
46
50
|
return withRouteAssurance({
|
|
47
|
-
name:
|
|
51
|
+
// The configuration is part of the name: the same one applied twice dedupes, while a group's
|
|
52
|
+
// different configuration applies over its parent's instead of being skipped as a repeat.
|
|
53
|
+
name: `security-headers:${JSON.stringify(declared)}`,
|
|
48
54
|
responseHeaders: declared,
|
|
49
55
|
}, {
|
|
50
56
|
id: NIFRA_ASSURANCE.SECURITY_HEADERS,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-headers.js","sourceRoot":"","sources":["../src/security-headers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AA6B7E
|
|
1
|
+
{"version":3,"file":"security-headers.js","sourceRoot":"","sources":["../src/security-headers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AA6B7E;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,eAAe,CAAC,UAAkC,EAAE;IAClE,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,MAAM,CAAA;IACnD,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,aAAa,CAAA;IAC9D,MAAM,GAAG,GAAG,OAAO,CAAC,qBAAqB,CAAA;IAEzC,IAAI,SAA6B,CAAA;IACjC,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,CAAC,WAAW,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;QAChD,IAAI,OAAO,CAAC,IAAI,CAAC,iBAAiB;YAAE,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;QACnE,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC/C,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC9B,CAAC;IAED,MAAM,QAAQ,GAA2B;QACvC,wBAAwB,EAAE,SAAS;QACnC,iBAAiB,EAAE,YAAY;QAC/B,iBAAiB,EAAE,cAAc;KAClC,CAAA;IACD,IAAI,SAAS,KAAK,SAAS;QAAE,QAAQ,CAAC,2BAA2B,CAAC,GAAG,SAAS,CAAA;IAC9E,IAAI,GAAG,KAAK,SAAS;QAAE,QAAQ,CAAC,yBAAyB,CAAC,GAAG,GAAG,CAAA;IAChE,IAAI,OAAO,CAAC,uBAAuB,KAAK,SAAS,EAAE,CAAC;QAClD,QAAQ,CAAC,4BAA4B,CAAC,GAAG,OAAO,CAAC,uBAAuB,CAAA;IAC1E,CAAC;IACD,IAAI,OAAO,CAAC,yBAAyB,KAAK,SAAS,EAAE,CAAC;QACpD,QAAQ,CAAC,8BAA8B,CAAC,GAAG,OAAO,CAAC,yBAAyB,CAAA;IAC9E,CAAC;IACD,IAAI,OAAO,CAAC,yBAAyB,KAAK,SAAS,EAAE,CAAC;QACpD,QAAQ,CAAC,8BAA8B,CAAC,GAAG,OAAO,CAAC,yBAAyB,CAAA;IAC9E,CAAC;IACD,IAAI,OAAO,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;QAC5C,QAAQ,CAAC,oBAAoB,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAA;IAC5D,CAAC;IAED,OAAO,kBAAkB,CACvB;QACE,6FAA6F;QAC7F,0FAA0F;QAC1F,IAAI,EAAE,oBAAoB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE;QACpD,eAAe,EAAE,QAAQ;KAC1B,EACD;QACE,EAAE,EAAE,eAAe,CAAC,gBAAgB;QACpC,MAAM,EAAE,kBAAkB;QAC1B,KAAK,EAAE,QAAQ;KAChB,CACF,CAAA;AACH,CAAC"}
|
package/dist/token-auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-auth.d.ts","sourceRoot":"","sources":["../src/token-auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"token-auth.d.ts","sourceRoot":"","sources":["../src/token-auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAGhF,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;AAErC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,cAAc,GAAG;IAC3C,gGAAgG;IAChG,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,CAAC,GAAG,IAAI,CAAA;IACrC,4EAA4E;IAC5E,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,CAAC,CAAA;CACtC,CAAA;AAqDD,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B;uGACmG;IACnG,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,YAAY,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;IACtE,yGAAyG;IACzG,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAC3B,mFAAmF;IACnF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CASlE;AAED,MAAM,WAAW,mBAAmB,CAAC,CAAC;IACpC,sFAAsF;IACtF,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,YAAY,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;IACpE,sDAAsD;IACtD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC;0EACsE;IACtE,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAC5B;AAoCD;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,mBAAmB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;AACxE,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAA"}
|
package/dist/token-auth.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NIFRA_ASSURANCE, withRouteAssurance } from "@nifrajs/core/assurance";
|
|
2
2
|
import { defineIdentityPlugin } from "@nifrajs/core/server";
|
|
3
|
+
import { bearerToken, guardName } from "./_utils.js";
|
|
3
4
|
function createTokenAuth(config) {
|
|
4
5
|
// Per-request principal cache: verify runs once (in beforeHandle), reads are free + can't desync.
|
|
5
6
|
const store = new WeakMap();
|
|
@@ -7,7 +8,7 @@ function createTokenAuth(config) {
|
|
|
7
8
|
status: 401,
|
|
8
9
|
headers: config.challenge !== undefined ? { "www-authenticate": config.challenge } : {},
|
|
9
10
|
});
|
|
10
|
-
const plugin = defineIdentityPlugin(config.name, (app) => app.beforeHandle(async (c) => {
|
|
11
|
+
const plugin = defineIdentityPlugin(guardName(config.name), (app) => app.beforeHandle(async (c) => {
|
|
11
12
|
const token = config.extract(c.req);
|
|
12
13
|
// Empty string is treated as "no credential" - never passed to verify.
|
|
13
14
|
const principal = token !== undefined && token !== "" ? await config.verify(token) : null;
|
|
@@ -43,10 +44,7 @@ export function bearer(options) {
|
|
|
43
44
|
const realm = options.realm ?? "api";
|
|
44
45
|
return createTokenAuth({
|
|
45
46
|
name: "bearer",
|
|
46
|
-
extract: (request) =>
|
|
47
|
-
const header = request.headers.get("authorization");
|
|
48
|
-
return header?.startsWith("Bearer ") === true ? header.slice(7).trim() : undefined;
|
|
49
|
-
},
|
|
47
|
+
extract: (request) => bearerToken(request.headers.get("authorization")) ?? undefined,
|
|
50
48
|
verify: options.verify,
|
|
51
49
|
optional: options.optional === true,
|
|
52
50
|
challenge: `Bearer realm="${realm}"`,
|
package/dist/token-auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-auth.js","sourceRoot":"","sources":["../src/token-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC7E,OAAO,EAAE,oBAAoB,EAAuB,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"token-auth.js","sourceRoot":"","sources":["../src/token-auth.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nifrajs/middleware",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.2",
|
|
4
4
|
"description": "Composable middleware for nifra - auth, CSRF, JWT/JWKS, IP restriction, CORS, body limits, response cache, timing, and operational helpers.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bun",
|
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
"security-headers"
|
|
19
19
|
],
|
|
20
20
|
"type": "module",
|
|
21
|
+
"nifra": {
|
|
22
|
+
"environment": "library"
|
|
23
|
+
},
|
|
21
24
|
"main": "./dist/index.js",
|
|
22
25
|
"module": "./dist/index.js",
|
|
23
26
|
"types": "./dist/index.d.ts",
|
|
@@ -46,10 +49,10 @@
|
|
|
46
49
|
"access": "public"
|
|
47
50
|
},
|
|
48
51
|
"dependencies": {
|
|
49
|
-
"@nifrajs/schema": "
|
|
52
|
+
"@nifrajs/schema": "4.0.2"
|
|
50
53
|
},
|
|
51
54
|
"peerDependencies": {
|
|
52
|
-
"@nifrajs/core": "^
|
|
55
|
+
"@nifrajs/core": "^4.0.2"
|
|
53
56
|
},
|
|
54
57
|
"devDependencies": {
|
|
55
58
|
"@nifrajs/core": "workspace:*",
|
package/src/_ip.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export interface ParsedIp {
|
|
2
|
+
readonly version: 4 | 6
|
|
3
|
+
readonly value: bigint
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function parseIPv4(input: string): bigint | null {
|
|
7
|
+
const parts = input.split(".")
|
|
8
|
+
if (parts.length !== 4) return null
|
|
9
|
+
let out = 0n
|
|
10
|
+
for (const part of parts) {
|
|
11
|
+
if (!/^\d{1,3}$/.test(part)) return null
|
|
12
|
+
const n = Number(part)
|
|
13
|
+
if (n > 255) return null
|
|
14
|
+
out = (out << 8n) | BigInt(n)
|
|
15
|
+
}
|
|
16
|
+
return out
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function parseIPv6(input: string): bigint | null {
|
|
20
|
+
if (input.includes("%")) return null
|
|
21
|
+
let source = input.toLowerCase()
|
|
22
|
+
if (source.includes(".")) {
|
|
23
|
+
const lastColon = source.lastIndexOf(":")
|
|
24
|
+
if (lastColon < 0) return null
|
|
25
|
+
const ipv4 = parseIPv4(source.slice(lastColon + 1))
|
|
26
|
+
if (ipv4 === null) return null
|
|
27
|
+
const hi = Number((ipv4 >> 16n) & 0xffffn).toString(16)
|
|
28
|
+
const lo = Number(ipv4 & 0xffffn).toString(16)
|
|
29
|
+
source = `${source.slice(0, lastColon)}:${hi}:${lo}`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const halves = source.split("::")
|
|
33
|
+
if (halves.length > 2) return null
|
|
34
|
+
const left = halves[0] === "" ? [] : halves[0]!.split(":")
|
|
35
|
+
const right = halves.length === 1 || halves[1] === "" ? [] : halves[1]!.split(":")
|
|
36
|
+
const groups = [...left, ...right]
|
|
37
|
+
if (groups.some((g) => !/^[0-9a-f]{1,4}$/.test(g))) return null
|
|
38
|
+
|
|
39
|
+
const missing = 8 - groups.length
|
|
40
|
+
if (halves.length === 1) {
|
|
41
|
+
if (missing !== 0) return null
|
|
42
|
+
} else if (missing < 1) return null
|
|
43
|
+
|
|
44
|
+
const expanded =
|
|
45
|
+
halves.length === 1
|
|
46
|
+
? groups
|
|
47
|
+
: [...left, ...Array.from({ length: missing }, () => "0"), ...right]
|
|
48
|
+
let out = 0n
|
|
49
|
+
for (const group of expanded) out = (out << 16n) | BigInt(Number.parseInt(group, 16))
|
|
50
|
+
return out
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* An IPv4 or IPv6 address, bracketed or not. An IPv4-mapped IPv6 address (`::ffff:a.b.c.d`) is the
|
|
55
|
+
* IPv4 address it carries: Bun and Node report every IPv4 peer that way on their default dual-stack
|
|
56
|
+
* listener, and IPv4 rules must still match it.
|
|
57
|
+
*/
|
|
58
|
+
export function parseIp(input: string): ParsedIp | null {
|
|
59
|
+
const trimmed = input.trim()
|
|
60
|
+
const unbracketed =
|
|
61
|
+
trimmed.startsWith("[") && trimmed.endsWith("]") ? trimmed.slice(1, -1) : trimmed
|
|
62
|
+
const v4 = parseIPv4(unbracketed)
|
|
63
|
+
if (v4 !== null) return { version: 4, value: v4 }
|
|
64
|
+
const v6 = parseIPv6(unbracketed)
|
|
65
|
+
if (v6 === null) return null
|
|
66
|
+
return v6 >> 32n === 0xffffn ? { version: 4, value: v6 & 0xffffffffn } : { version: 6, value: v6 }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The rate-limit bucket for a client address: an IPv4 address as itself (unmapped), an IPv6 address
|
|
71
|
+
* as its /64. One subscriber is routinely assigned a whole /64 and can send every request from a new
|
|
72
|
+
* address inside it, so a per-address bucket never fills. Anything that is not an address is kept.
|
|
73
|
+
*/
|
|
74
|
+
export function ipBucket(ip: string): string {
|
|
75
|
+
if (!ip.includes(":")) return ip
|
|
76
|
+
// Every IPv4 peer of a default Bun or Node listener: skip the full parse on that per-request path.
|
|
77
|
+
if (ip.startsWith("::ffff:") && ip.includes(".", 7) && ip.indexOf(":", 7) === -1)
|
|
78
|
+
return ip.slice(7)
|
|
79
|
+
const parsed = parseIp(ip)
|
|
80
|
+
if (parsed === null) return ip
|
|
81
|
+
const value = parsed.value
|
|
82
|
+
if (parsed.version === 4) {
|
|
83
|
+
return `${(value >> 24n) & 255n}.${(value >> 16n) & 255n}.${(value >> 8n) & 255n}.${value & 255n}`
|
|
84
|
+
}
|
|
85
|
+
const prefix = (value >> 64n).toString(16).padStart(16, "0")
|
|
86
|
+
return `${prefix.slice(0, 4)}:${prefix.slice(4, 8)}:${prefix.slice(8, 12)}:${prefix.slice(12)}::/64`
|
|
87
|
+
}
|