@daloyjs/core 0.30.0 → 0.34.0
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 +14 -1
- package/bin/daloy.mjs +0 -0
- package/dist/adapters/bun.d.ts.map +1 -1
- package/dist/adapters/bun.js +5 -1
- package/dist/adapters/bun.js.map +1 -1
- package/dist/adapters/node.d.ts.map +1 -1
- package/dist/adapters/node.js +7 -2
- package/dist/adapters/node.js.map +1 -1
- package/dist/app.d.ts +47 -36
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +229 -59
- package/dist/app.js.map +1 -1
- package/dist/banner.d.ts +2 -0
- package/dist/banner.d.ts.map +1 -1
- package/dist/banner.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +29 -31
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +10 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js.map +1 -1
- package/dist/compression.d.ts +2 -2
- package/dist/compression.js +2 -2
- package/dist/config.d.ts +2 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/conn-info.d.ts +5 -5
- package/dist/conn-info.js +4 -4
- package/dist/contract.d.ts +19 -0
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +10 -0
- package/dist/contract.js.map +1 -1
- package/dist/cookie.d.ts +15 -1
- package/dist/cookie.d.ts.map +1 -1
- package/dist/cookie.js +24 -4
- package/dist/cookie.js.map +1 -1
- package/dist/dependency.d.ts +1 -1
- package/dist/dependency.js +1 -1
- package/dist/discriminator.d.ts +9 -0
- package/dist/discriminator.d.ts.map +1 -1
- package/dist/discriminator.js.map +1 -1
- package/dist/docs.d.ts +49 -2
- package/dist/docs.d.ts.map +1 -1
- package/dist/docs.js +26 -2
- package/dist/docs.js.map +1 -1
- package/dist/errors.d.ts +89 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +148 -7
- package/dist/errors.js.map +1 -1
- package/dist/etag.d.ts +1 -1
- package/dist/etag.js +1 -1
- package/dist/fetch-guard.d.ts +163 -0
- package/dist/fetch-guard.d.ts.map +1 -0
- package/dist/fetch-guard.js +265 -0
- package/dist/fetch-guard.js.map +1 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/ip-restriction.d.ts +17 -0
- package/dist/ip-restriction.d.ts.map +1 -1
- package/dist/ip-restriction.js +6 -3
- package/dist/ip-restriction.js.map +1 -1
- package/dist/jwk.d.ts +1 -1
- package/dist/jwk.d.ts.map +1 -1
- package/dist/jwk.js +3 -3
- package/dist/jwt.d.ts +3 -3
- package/dist/jwt.d.ts.map +1 -1
- package/dist/jwt.js +19 -7
- package/dist/jwt.js.map +1 -1
- package/dist/load-shedding.d.ts +1 -1
- package/dist/load-shedding.js +1 -1
- package/dist/logger.d.ts +14 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +66 -4
- package/dist/logger.js.map +1 -1
- package/dist/middleware.d.ts +40 -15
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +18 -14
- package/dist/middleware.js.map +1 -1
- package/dist/multipart.d.ts +22 -0
- package/dist/multipart.d.ts.map +1 -1
- package/dist/multipart.js +69 -0
- package/dist/multipart.js.map +1 -1
- package/dist/openapi.d.ts +13 -0
- package/dist/openapi.d.ts.map +1 -1
- package/dist/openapi.js +5 -0
- package/dist/openapi.js.map +1 -1
- package/dist/router.d.ts +9 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +6 -0
- package/dist/router.js.map +1 -1
- package/dist/sbom.cdx.json +60 -0
- package/dist/sbom.spdx.json +42 -0
- package/dist/security-schemes.d.ts +29 -0
- package/dist/security-schemes.d.ts.map +1 -1
- package/dist/security-schemes.js +11 -0
- package/dist/security-schemes.js.map +1 -1
- package/dist/security.d.ts +53 -2
- package/dist/security.d.ts.map +1 -1
- package/dist/security.js +67 -2
- package/dist/security.js.map +1 -1
- package/dist/session.d.ts +4 -2
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +2 -2
- package/dist/session.js.map +1 -1
- package/dist/streaming.d.ts +8 -0
- package/dist/streaming.d.ts.map +1 -1
- package/dist/streaming.js.map +1 -1
- package/dist/subdomains.d.ts +1 -1
- package/dist/subdomains.js +1 -1
- package/dist/time-claims.d.ts +1 -2
- package/dist/time-claims.d.ts.map +1 -1
- package/dist/time-claims.js +1 -2
- package/dist/time-claims.js.map +1 -1
- package/dist/tracing.d.ts +10 -0
- package/dist/tracing.d.ts.map +1 -1
- package/dist/tracing.js +5 -0
- package/dist/tracing.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/websocket.d.ts +87 -0
- package/dist/websocket.d.ts.map +1 -1
- package/dist/websocket.js +81 -0
- package/dist/websocket.js.map +1 -1
- package/package.json +31 -10
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `fetchGuard()` — SSRF-hardened wrapper around the global `fetch` for
|
|
3
|
+
* outbound calls a handler makes on behalf of a user.
|
|
4
|
+
*
|
|
5
|
+
* The classic SSRF chain documented by the
|
|
6
|
+
* [Aikido write-up](https://www.aikido.dev/blog/how-a-startups-cloud-got-taken-over-by-a-simple-form-that-sends-an-email)
|
|
7
|
+
* starts with a handler that fetches a user-supplied URL (an email avatar,
|
|
8
|
+
* a webhook target, an "import from URL" feature) and ends with the
|
|
9
|
+
* attacker pivoting through the cloud metadata service
|
|
10
|
+
* (`http://169.254.169.254/...` on AWS/Azure/DigitalOcean,
|
|
11
|
+
* `http://100.100.100.200/...` on Alibaba, `http://192.0.0.192/...` on
|
|
12
|
+
* Oracle Cloud) to steal short-lived IAM credentials.
|
|
13
|
+
*
|
|
14
|
+
* `fetchGuard()` rejects requests that resolve to any of the following
|
|
15
|
+
* address ranges unless explicitly opted-in:
|
|
16
|
+
*
|
|
17
|
+
* - Loopback: `127.0.0.0/8`, `::1` (opt in: `allowLoopback`).
|
|
18
|
+
* - RFC1918 private: `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`
|
|
19
|
+
* (opt in: `allowPrivate`).
|
|
20
|
+
* - Link-local **including every documented cloud metadata IP**:
|
|
21
|
+
* `169.254.0.0/16`, `fe80::/10` (opt in: `allowLinkLocal`).
|
|
22
|
+
* - Unique-local IPv6: `fc00::/7` (opt in: `allowUniqueLocal`).
|
|
23
|
+
*
|
|
24
|
+
* Plus an always-deny floor that no flag can lift:
|
|
25
|
+
*
|
|
26
|
+
* - `0.0.0.0/8` (this-network), `100.64.0.0/10` (carrier-grade NAT — covers
|
|
27
|
+
* Alibaba `100.100.100.200`), `192.0.0.0/24` (covers Oracle Cloud
|
|
28
|
+
* `192.0.0.192`), `192.0.2.0/24`, `198.18.0.0/15`, `198.51.100.0/24`,
|
|
29
|
+
* `203.0.113.0/24` (IANA-reserved), `224.0.0.0/4` (multicast),
|
|
30
|
+
* `240.0.0.0/4` (reserved), `255.255.255.255` (broadcast).
|
|
31
|
+
* - IPv6: `::/128` (unspecified), `ff00::/8` (multicast), IPv4-mapped
|
|
32
|
+
* `::ffff:0:0/96` is re-checked against the embedded IPv4 address.
|
|
33
|
+
*
|
|
34
|
+
* Redirects are followed **manually** with re-validation at each hop so
|
|
35
|
+
* an attacker cannot bypass the check via a `302 → http://169.254...`.
|
|
36
|
+
* `non-http(s)` protocols (`file:`, `ftp:`, `gopher:`, `data:`) are
|
|
37
|
+
* rejected before any network call.
|
|
38
|
+
*
|
|
39
|
+
* @since 0.34.0
|
|
40
|
+
* @module
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* Reason an SSRF guard refused to dispatch a request. Surfaced on
|
|
44
|
+
* {@link SsrfBlockedError.reason} so callers can branch in tests / logs.
|
|
45
|
+
*
|
|
46
|
+
* @since 0.34.0
|
|
47
|
+
*/
|
|
48
|
+
export type SsrfBlockReason = "protocol-not-allowed" | "host-not-allowed" | "dns-resolution-failed" | "address-not-allowed" | "too-many-redirects" | "invalid-url";
|
|
49
|
+
/**
|
|
50
|
+
* Thrown by {@link fetchGuard} when an outbound request is refused. Never
|
|
51
|
+
* thrown for ordinary network failures — those bubble through unchanged
|
|
52
|
+
* so retry logic can distinguish "we refused" from "the network is sad".
|
|
53
|
+
*
|
|
54
|
+
* @since 0.34.0
|
|
55
|
+
*/
|
|
56
|
+
export declare class SsrfBlockedError extends Error {
|
|
57
|
+
readonly url: string;
|
|
58
|
+
readonly reason: SsrfBlockReason;
|
|
59
|
+
readonly address?: string;
|
|
60
|
+
constructor(url: string, reason: SsrfBlockReason, address?: string);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Options for {@link fetchGuard}. All defaults bias toward the safe
|
|
64
|
+
* posture: only public IPs reachable over `http:` / `https:` are allowed.
|
|
65
|
+
*
|
|
66
|
+
* @since 0.34.0
|
|
67
|
+
*/
|
|
68
|
+
export interface FetchGuardOptions {
|
|
69
|
+
/**
|
|
70
|
+
* URL schemes the guard will permit. Defaults to
|
|
71
|
+
* `["http:", "https:"]`. Anything else (`file:`, `data:`, `ftp:`,
|
|
72
|
+
* `gopher:`, `dict:`, `ldap:`) is rejected with
|
|
73
|
+
* `protocol-not-allowed`.
|
|
74
|
+
*/
|
|
75
|
+
allowProtocols?: readonly string[];
|
|
76
|
+
/**
|
|
77
|
+
* IP literals, IPv4/IPv6 addresses, or CIDR ranges that bypass the
|
|
78
|
+
* deny defaults. Use this for an explicit allowlist of public
|
|
79
|
+
* upstreams. Hostnames are matched case-insensitively against the
|
|
80
|
+
* post-DNS address set — pass an IP / CIDR, not a domain name.
|
|
81
|
+
*
|
|
82
|
+
* @example `["198.51.100.42", "2001:db8::/32"]`
|
|
83
|
+
*/
|
|
84
|
+
allowAddresses?: readonly string[];
|
|
85
|
+
/**
|
|
86
|
+
* Hostnames that bypass DNS-based checks entirely. Useful when the
|
|
87
|
+
* caller already verified the target out of band (e.g. internal
|
|
88
|
+
* services on a known DNS name). Compared case-insensitively against
|
|
89
|
+
* the URL hostname.
|
|
90
|
+
*/
|
|
91
|
+
allowHosts?: readonly string[];
|
|
92
|
+
/**
|
|
93
|
+
* Extra IP / CIDR matchers to deny on top of the default floor.
|
|
94
|
+
* Always wins against `allowAddresses`.
|
|
95
|
+
*/
|
|
96
|
+
denyAddresses?: readonly string[];
|
|
97
|
+
/**
|
|
98
|
+
* Allow loopback addresses (`127.0.0.0/8`, `::1`). Default `false`.
|
|
99
|
+
* Enable only for local-dev fixtures.
|
|
100
|
+
*/
|
|
101
|
+
allowLoopback?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Allow RFC1918 private ranges (`10.0.0.0/8`, `172.16.0.0/12`,
|
|
104
|
+
* `192.168.0.0/16`). Default `false`.
|
|
105
|
+
*/
|
|
106
|
+
allowPrivate?: boolean;
|
|
107
|
+
/**
|
|
108
|
+
* Allow link-local ranges (`169.254.0.0/16`, `fe80::/10`). Default
|
|
109
|
+
* `false`. **Leaving this off blocks every documented cloud
|
|
110
|
+
* metadata service IP** (AWS/Azure/DigitalOcean `169.254.169.254`,
|
|
111
|
+
* GCP `metadata.google.internal`).
|
|
112
|
+
*/
|
|
113
|
+
allowLinkLocal?: boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Allow IPv6 unique-local addresses (`fc00::/7`). Default `false`.
|
|
116
|
+
*/
|
|
117
|
+
allowUniqueLocal?: boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Maximum number of redirects to follow with re-validation. Default
|
|
120
|
+
* `5`. Set `0` to refuse all redirects (returns the 3xx response
|
|
121
|
+
* directly).
|
|
122
|
+
*/
|
|
123
|
+
maxRedirects?: number;
|
|
124
|
+
/**
|
|
125
|
+
* Underlying fetch implementation. Defaults to `globalThis.fetch`.
|
|
126
|
+
* Useful for tests or for layering on top of an instrumented client.
|
|
127
|
+
*/
|
|
128
|
+
fetch?: typeof fetch;
|
|
129
|
+
/**
|
|
130
|
+
* DNS resolver. Defaults to `node:dns/promises.lookup(host, { all: true })`.
|
|
131
|
+
* Provide a custom resolver on non-Node runtimes (Workers, Deno
|
|
132
|
+
* without `--allow-net`) or to enforce an in-memory test fixture.
|
|
133
|
+
*/
|
|
134
|
+
resolve?: (hostname: string) => Promise<readonly string[]>;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Wrap `fetch` with an SSRF-hardened guard. The returned function has
|
|
138
|
+
* the same call signature as the global `fetch` and throws
|
|
139
|
+
* {@link SsrfBlockedError} when an outbound request would target a
|
|
140
|
+
* dangerous internal address.
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```ts
|
|
144
|
+
* import { fetchGuard } from "@daloyjs/core";
|
|
145
|
+
*
|
|
146
|
+
* const safeFetch = fetchGuard();
|
|
147
|
+
*
|
|
148
|
+
* app.route({
|
|
149
|
+
* method: "POST", path: "/import", operationId: "import",
|
|
150
|
+
* request: { json: z.object({ url: z.string().url() }) },
|
|
151
|
+
* responses: { 200: { description: "ok" } },
|
|
152
|
+
* handler: async ({ request }) => {
|
|
153
|
+
* const { url } = await request.json();
|
|
154
|
+
* const upstream = await safeFetch(url); // refuses 169.254.169.254
|
|
155
|
+
* return { status: 200 as const, body: await upstream.text() };
|
|
156
|
+
* },
|
|
157
|
+
* });
|
|
158
|
+
* ```
|
|
159
|
+
*
|
|
160
|
+
* @since 0.34.0
|
|
161
|
+
*/
|
|
162
|
+
export declare function fetchGuard(options?: FetchGuardOptions): typeof fetch;
|
|
163
|
+
//# sourceMappingURL=fetch-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-guard.d.ts","sourceRoot":"","sources":["../src/fetch-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAKH;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GACvB,sBAAsB,GACtB,kBAAkB,GAClB,uBAAuB,GACvB,qBAAqB,GACrB,oBAAoB,GACpB,aAAa,CAAC;AAElB;;;;;;GAMG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;gBACd,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,MAAM;CAQnE;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B;;;OAGG;IACH,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;OAEG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;CAC5D;AAsBD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,KAAK,CAqHxE"}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `fetchGuard()` — SSRF-hardened wrapper around the global `fetch` for
|
|
3
|
+
* outbound calls a handler makes on behalf of a user.
|
|
4
|
+
*
|
|
5
|
+
* The classic SSRF chain documented by the
|
|
6
|
+
* [Aikido write-up](https://www.aikido.dev/blog/how-a-startups-cloud-got-taken-over-by-a-simple-form-that-sends-an-email)
|
|
7
|
+
* starts with a handler that fetches a user-supplied URL (an email avatar,
|
|
8
|
+
* a webhook target, an "import from URL" feature) and ends with the
|
|
9
|
+
* attacker pivoting through the cloud metadata service
|
|
10
|
+
* (`http://169.254.169.254/...` on AWS/Azure/DigitalOcean,
|
|
11
|
+
* `http://100.100.100.200/...` on Alibaba, `http://192.0.0.192/...` on
|
|
12
|
+
* Oracle Cloud) to steal short-lived IAM credentials.
|
|
13
|
+
*
|
|
14
|
+
* `fetchGuard()` rejects requests that resolve to any of the following
|
|
15
|
+
* address ranges unless explicitly opted-in:
|
|
16
|
+
*
|
|
17
|
+
* - Loopback: `127.0.0.0/8`, `::1` (opt in: `allowLoopback`).
|
|
18
|
+
* - RFC1918 private: `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`
|
|
19
|
+
* (opt in: `allowPrivate`).
|
|
20
|
+
* - Link-local **including every documented cloud metadata IP**:
|
|
21
|
+
* `169.254.0.0/16`, `fe80::/10` (opt in: `allowLinkLocal`).
|
|
22
|
+
* - Unique-local IPv6: `fc00::/7` (opt in: `allowUniqueLocal`).
|
|
23
|
+
*
|
|
24
|
+
* Plus an always-deny floor that no flag can lift:
|
|
25
|
+
*
|
|
26
|
+
* - `0.0.0.0/8` (this-network), `100.64.0.0/10` (carrier-grade NAT — covers
|
|
27
|
+
* Alibaba `100.100.100.200`), `192.0.0.0/24` (covers Oracle Cloud
|
|
28
|
+
* `192.0.0.192`), `192.0.2.0/24`, `198.18.0.0/15`, `198.51.100.0/24`,
|
|
29
|
+
* `203.0.113.0/24` (IANA-reserved), `224.0.0.0/4` (multicast),
|
|
30
|
+
* `240.0.0.0/4` (reserved), `255.255.255.255` (broadcast).
|
|
31
|
+
* - IPv6: `::/128` (unspecified), `ff00::/8` (multicast), IPv4-mapped
|
|
32
|
+
* `::ffff:0:0/96` is re-checked against the embedded IPv4 address.
|
|
33
|
+
*
|
|
34
|
+
* Redirects are followed **manually** with re-validation at each hop so
|
|
35
|
+
* an attacker cannot bypass the check via a `302 → http://169.254...`.
|
|
36
|
+
* `non-http(s)` protocols (`file:`, `ftp:`, `gopher:`, `data:`) are
|
|
37
|
+
* rejected before any network call.
|
|
38
|
+
*
|
|
39
|
+
* @since 0.34.0
|
|
40
|
+
* @module
|
|
41
|
+
*/
|
|
42
|
+
import { compileCidrMatcher, matchesMatcher, parseIp } from "./ip-restriction.js";
|
|
43
|
+
/**
|
|
44
|
+
* Thrown by {@link fetchGuard} when an outbound request is refused. Never
|
|
45
|
+
* thrown for ordinary network failures — those bubble through unchanged
|
|
46
|
+
* so retry logic can distinguish "we refused" from "the network is sad".
|
|
47
|
+
*
|
|
48
|
+
* @since 0.34.0
|
|
49
|
+
*/
|
|
50
|
+
export class SsrfBlockedError extends Error {
|
|
51
|
+
url;
|
|
52
|
+
reason;
|
|
53
|
+
address;
|
|
54
|
+
constructor(url, reason, address) {
|
|
55
|
+
const where = address ? ` -> ${address}` : "";
|
|
56
|
+
super(`SSRF blocked: ${url}${where} (${reason})`);
|
|
57
|
+
this.name = "SsrfBlockedError";
|
|
58
|
+
this.url = url;
|
|
59
|
+
this.reason = reason;
|
|
60
|
+
if (address !== undefined)
|
|
61
|
+
this.address = address;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Always-on deny matchers. No option flips these.
|
|
65
|
+
const ALWAYS_DENY = [
|
|
66
|
+
"0.0.0.0/8", // "this network"
|
|
67
|
+
"100.64.0.0/10", // CGNAT (Alibaba metadata 100.100.100.200)
|
|
68
|
+
"192.0.0.0/24", // IANA reserved (Oracle metadata 192.0.0.192)
|
|
69
|
+
"192.0.2.0/24", // TEST-NET-1
|
|
70
|
+
"198.18.0.0/15", // benchmarking
|
|
71
|
+
"198.51.100.0/24", // TEST-NET-2
|
|
72
|
+
"203.0.113.0/24", // TEST-NET-3
|
|
73
|
+
"224.0.0.0/4", // multicast
|
|
74
|
+
"240.0.0.0/4", // reserved (includes 255.255.255.255)
|
|
75
|
+
"::/128", // unspecified
|
|
76
|
+
"ff00::/8", // IPv6 multicast
|
|
77
|
+
];
|
|
78
|
+
const LOOPBACK = ["127.0.0.0/8", "::1/128"];
|
|
79
|
+
const LINK_LOCAL = ["169.254.0.0/16", "fe80::/10"];
|
|
80
|
+
const PRIVATE = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"];
|
|
81
|
+
const UNIQUE_LOCAL = ["fc00::/7"];
|
|
82
|
+
/**
|
|
83
|
+
* Wrap `fetch` with an SSRF-hardened guard. The returned function has
|
|
84
|
+
* the same call signature as the global `fetch` and throws
|
|
85
|
+
* {@link SsrfBlockedError} when an outbound request would target a
|
|
86
|
+
* dangerous internal address.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* import { fetchGuard } from "@daloyjs/core";
|
|
91
|
+
*
|
|
92
|
+
* const safeFetch = fetchGuard();
|
|
93
|
+
*
|
|
94
|
+
* app.route({
|
|
95
|
+
* method: "POST", path: "/import", operationId: "import",
|
|
96
|
+
* request: { json: z.object({ url: z.string().url() }) },
|
|
97
|
+
* responses: { 200: { description: "ok" } },
|
|
98
|
+
* handler: async ({ request }) => {
|
|
99
|
+
* const { url } = await request.json();
|
|
100
|
+
* const upstream = await safeFetch(url); // refuses 169.254.169.254
|
|
101
|
+
* return { status: 200 as const, body: await upstream.text() };
|
|
102
|
+
* },
|
|
103
|
+
* });
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* @since 0.34.0
|
|
107
|
+
*/
|
|
108
|
+
export function fetchGuard(options = {}) {
|
|
109
|
+
const allowProtocols = new Set((options.allowProtocols ?? ["http:", "https:"]).map((s) => s.toLowerCase()));
|
|
110
|
+
const denyMatchers = [];
|
|
111
|
+
const allowMatchers = [];
|
|
112
|
+
const allowHosts = new Set((options.allowHosts ?? []).map((h) => h.toLowerCase()));
|
|
113
|
+
const maxRedirects = options.maxRedirects ?? 5;
|
|
114
|
+
const baseFetch = options.fetch ?? globalThis.fetch;
|
|
115
|
+
if (typeof baseFetch !== "function") {
|
|
116
|
+
throw new Error("fetchGuard(): no global fetch available; pass options.fetch.");
|
|
117
|
+
}
|
|
118
|
+
const resolveFn = options.resolve ?? createDefaultResolver();
|
|
119
|
+
for (const c of ALWAYS_DENY)
|
|
120
|
+
denyMatchers.push(compileCidrMatcher(c));
|
|
121
|
+
if (!options.allowLoopback)
|
|
122
|
+
for (const c of LOOPBACK)
|
|
123
|
+
denyMatchers.push(compileCidrMatcher(c));
|
|
124
|
+
if (!options.allowPrivate)
|
|
125
|
+
for (const c of PRIVATE)
|
|
126
|
+
denyMatchers.push(compileCidrMatcher(c));
|
|
127
|
+
if (!options.allowLinkLocal)
|
|
128
|
+
for (const c of LINK_LOCAL)
|
|
129
|
+
denyMatchers.push(compileCidrMatcher(c));
|
|
130
|
+
if (!options.allowUniqueLocal) {
|
|
131
|
+
for (const c of UNIQUE_LOCAL)
|
|
132
|
+
denyMatchers.push(compileCidrMatcher(c));
|
|
133
|
+
}
|
|
134
|
+
for (const c of options.denyAddresses ?? [])
|
|
135
|
+
denyMatchers.push(compileCidrMatcher(c));
|
|
136
|
+
for (const c of options.allowAddresses ?? [])
|
|
137
|
+
allowMatchers.push(compileCidrMatcher(c));
|
|
138
|
+
function isAddressAllowed(parsed) {
|
|
139
|
+
if (allowMatchers.some((m) => matchesMatcher(parsed, m)))
|
|
140
|
+
return true;
|
|
141
|
+
return !denyMatchers.some((m) => matchesMatcher(parsed, m));
|
|
142
|
+
}
|
|
143
|
+
async function validateUrl(url) {
|
|
144
|
+
const proto = url.protocol.toLowerCase();
|
|
145
|
+
if (!allowProtocols.has(proto)) {
|
|
146
|
+
throw new SsrfBlockedError(url.toString(), "protocol-not-allowed");
|
|
147
|
+
}
|
|
148
|
+
// URL.hostname strips brackets from IPv6 literals — perfect for parseIp.
|
|
149
|
+
const hostname = url.hostname;
|
|
150
|
+
if (!hostname) {
|
|
151
|
+
throw new SsrfBlockedError(url.toString(), "invalid-url");
|
|
152
|
+
}
|
|
153
|
+
if (allowHosts.has(hostname.toLowerCase()))
|
|
154
|
+
return;
|
|
155
|
+
const literal = parseIp(hostname);
|
|
156
|
+
if (literal) {
|
|
157
|
+
if (!isAddressAllowed(literal)) {
|
|
158
|
+
throw new SsrfBlockedError(url.toString(), "address-not-allowed", hostname);
|
|
159
|
+
}
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
let addrs;
|
|
163
|
+
try {
|
|
164
|
+
addrs = await resolveFn(hostname);
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
throw new SsrfBlockedError(url.toString(), "dns-resolution-failed", hostname);
|
|
168
|
+
}
|
|
169
|
+
if (!addrs.length) {
|
|
170
|
+
throw new SsrfBlockedError(url.toString(), "dns-resolution-failed", hostname);
|
|
171
|
+
}
|
|
172
|
+
for (const a of addrs) {
|
|
173
|
+
const p = parseIp(a);
|
|
174
|
+
if (!p) {
|
|
175
|
+
throw new SsrfBlockedError(url.toString(), "dns-resolution-failed", a);
|
|
176
|
+
}
|
|
177
|
+
if (!isAddressAllowed(p)) {
|
|
178
|
+
throw new SsrfBlockedError(url.toString(), "address-not-allowed", a);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const guarded = async (input, init) => {
|
|
183
|
+
let request = new Request(input, init);
|
|
184
|
+
const userRedirect = (init?.redirect ?? request.redirect);
|
|
185
|
+
// Always dispatch underlying calls with redirect: "manual" so we can
|
|
186
|
+
// re-validate each Location ourselves.
|
|
187
|
+
let currentUrl;
|
|
188
|
+
try {
|
|
189
|
+
currentUrl = new URL(request.url);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
throw new SsrfBlockedError(String(input), "invalid-url");
|
|
193
|
+
}
|
|
194
|
+
for (let hop = 0;; hop++) {
|
|
195
|
+
await validateUrl(currentUrl);
|
|
196
|
+
const dispatchInit = { redirect: "manual" };
|
|
197
|
+
const dispatchReq = new Request(request, dispatchInit);
|
|
198
|
+
const res = await baseFetch(dispatchReq);
|
|
199
|
+
if (!isRedirect(res.status))
|
|
200
|
+
return res;
|
|
201
|
+
if (userRedirect === "error") {
|
|
202
|
+
throw new TypeError("fetchGuard: redirect refused (redirect: error)");
|
|
203
|
+
}
|
|
204
|
+
if (userRedirect === "manual" || maxRedirects === 0)
|
|
205
|
+
return res;
|
|
206
|
+
if (hop >= maxRedirects) {
|
|
207
|
+
throw new SsrfBlockedError(currentUrl.toString(), "too-many-redirects");
|
|
208
|
+
}
|
|
209
|
+
const loc = res.headers.get("location");
|
|
210
|
+
if (!loc)
|
|
211
|
+
return res;
|
|
212
|
+
let next;
|
|
213
|
+
try {
|
|
214
|
+
next = new URL(loc, currentUrl);
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
throw new SsrfBlockedError(loc, "invalid-url");
|
|
218
|
+
}
|
|
219
|
+
// Per fetch spec: 303 (and 301/302 for non-GET/HEAD in practice) downgrade to GET.
|
|
220
|
+
const method = request.method.toUpperCase();
|
|
221
|
+
const shouldDowngrade = res.status === 303 ||
|
|
222
|
+
((res.status === 301 || res.status === 302) && method !== "GET" && method !== "HEAD");
|
|
223
|
+
request = shouldDowngrade
|
|
224
|
+
? new Request(next, {
|
|
225
|
+
method: "GET",
|
|
226
|
+
headers: stripBodyHeaders(request.headers),
|
|
227
|
+
redirect: "manual",
|
|
228
|
+
credentials: request.credentials,
|
|
229
|
+
referrerPolicy: request.referrerPolicy,
|
|
230
|
+
})
|
|
231
|
+
: new Request(next, request);
|
|
232
|
+
currentUrl = next;
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
return guarded;
|
|
236
|
+
}
|
|
237
|
+
function isRedirect(status) {
|
|
238
|
+
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
239
|
+
}
|
|
240
|
+
function stripBodyHeaders(headers) {
|
|
241
|
+
const out = new Headers(headers);
|
|
242
|
+
out.delete("content-length");
|
|
243
|
+
out.delete("content-type");
|
|
244
|
+
out.delete("content-encoding");
|
|
245
|
+
out.delete("content-language");
|
|
246
|
+
out.delete("content-location");
|
|
247
|
+
return out;
|
|
248
|
+
}
|
|
249
|
+
function createDefaultResolver() {
|
|
250
|
+
let lookupPromise = null;
|
|
251
|
+
return async (host) => {
|
|
252
|
+
if (!lookupPromise) {
|
|
253
|
+
lookupPromise = import("node:dns/promises")
|
|
254
|
+
.then((m) => m.lookup)
|
|
255
|
+
.catch(() => null);
|
|
256
|
+
}
|
|
257
|
+
const lookup = await lookupPromise;
|
|
258
|
+
if (!lookup) {
|
|
259
|
+
throw new Error("fetchGuard: no DNS resolver available on this runtime. Pass options.resolve.");
|
|
260
|
+
}
|
|
261
|
+
const results = await lookup(host, { all: true, verbatim: true });
|
|
262
|
+
return results.map((r) => r.address);
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=fetch-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-guard.js","sourceRoot":"","sources":["../src/fetch-guard.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,11 +11,11 @@ export type { SubdomainsOptions, SubdomainsResult } from "./subdomains.js";
|
|
|
11
11
|
export { defineDependency, DEPENDENCY_MARKER } from "./dependency.js";
|
|
12
12
|
export type { DependencyHooks, DependencyOptions, } from "./dependency.js";
|
|
13
13
|
export type { RouteDefinition, HttpMethod, PathString, RequestSchemas, ResponsesMap, ResponseSpec, AuthSpec, Hooks, BaseContext, AppState, AuthScheme, AuthContext, HandlerReturn, InferRequest, ParamsOf, PathParams, CallbackDefinition, CallbackMap, CallbackOperation, RouteExample, RouteMeta, } from "./types.js";
|
|
14
|
-
export { HttpError, BadRequestError, ValidationError, NotFoundError, UnauthorizedError, ForbiddenError, MethodNotAllowedError, PayloadTooLargeError, UnsupportedMediaTypeError, TooManyRequestsError, RequestTimeoutError, InternalError, } from "./errors.js";
|
|
15
|
-
export type { ProblemDetails, ProblemRenderOptions } from "./errors.js";
|
|
14
|
+
export { HttpError, BadRequestError, ValidationError, NotFoundError, UnauthorizedError, ForbiddenError, MethodNotAllowedError, PayloadTooLargeError, UnsupportedMediaTypeError, TooManyRequestsError, RequestTimeoutError, InternalError, MessageLeakError, httpError, SAFE_CUSTOM_ERROR_RESPONSE_HEADERS, checkCustomErrorResponseHeaders, } from "./errors.js";
|
|
15
|
+
export type { ProblemDetails, ProblemRenderOptions, HttpErrorOptions } from "./errors.js";
|
|
16
16
|
export type { StandardSchemaV1 } from "./schema.js";
|
|
17
17
|
export { validate, isStandardSchema } from "./schema.js";
|
|
18
|
-
export { readBodyLimited, safeJsonParse, sanitizeHeaderName, sanitizeHeaderValue, timingSafeEqual, randomId, assertNoDuplicateSingletonHeaders, SMUGGLING_SINGLETON_HEADERS, verifyWebhookSignature, signWebhookPayload, assertStrongSecret, MIN_PROD_SECRET_BYTES, WEAK_SECRET_STRINGS, } from "./security.js";
|
|
18
|
+
export { readBodyLimited, safeJsonParse, isForbiddenObjectKey, sanitizeHeaderName, sanitizeHeaderValue, timingSafeEqual, randomId, assertNoDuplicateSingletonHeaders, assertNoReservedInternalHeaders, RESERVED_INBOUND_HEADER_PREFIXES, SMUGGLING_SINGLETON_HEADERS, verifyWebhookSignature, signWebhookPayload, assertStrongSecret, MIN_PROD_SECRET_BYTES, WEAK_SECRET_STRINGS, } from "./security.js";
|
|
19
19
|
export type { WebhookHmacAlgorithm } from "./security.js";
|
|
20
20
|
export { requestId, secureHeaders, SECURE_HEADERS_MARKER, cors, CORS_HOOK_MARKER, CORS_ORIGIN_ALLOW_MARKER, CORS_WILDCARD_ORIGIN_MARKER, rateLimit, loginThrottle, timing, bearerAuth, basicAuth, csrf, CSRF_HOOK_MARKER, requireScopes, REQUIRE_SCOPES_AGGREGATE_KEY, REQUIRE_SCOPES_HOOK_MARKER, _resetSharedRateLimitStoresForTests, } from "./middleware.js";
|
|
21
21
|
export { etag } from "./etag.js";
|
|
@@ -34,6 +34,8 @@ export { every, some, except } from "./combine.js";
|
|
|
34
34
|
export type { ExceptPredicate } from "./combine.js";
|
|
35
35
|
export { ipRestriction } from "./ip-restriction.js";
|
|
36
36
|
export type { IpRestrictionOptions } from "./ip-restriction.js";
|
|
37
|
+
export { fetchGuard, SsrfBlockedError } from "./fetch-guard.js";
|
|
38
|
+
export type { FetchGuardOptions, SsrfBlockReason } from "./fetch-guard.js";
|
|
37
39
|
export { loadShedding, LOAD_SHEDDING_MARKER } from "./load-shedding.js";
|
|
38
40
|
export type { LoadSheddingOptions, LoadSheddingSnapshot, } from "./load-shedding.js";
|
|
39
41
|
export { defineConfig, ConfigValidationError } from "./config.js";
|
|
@@ -57,6 +59,6 @@ export { fileField, multipartObject, isFileFieldSchema, isMultipartObjectSchema,
|
|
|
57
59
|
export type { FileFieldSchema, FileFieldOptions, FileMagicBytesOption, FileMagicBytesSignature, MultipartObjectOptions, MultipartShape, UploadedFile, } from "./multipart.js";
|
|
58
60
|
export { otelTracing, TRACING_SPAN_KIND_SERVER, TRACING_SPAN_STATUS_UNSET, TRACING_SPAN_STATUS_OK, TRACING_SPAN_STATUS_ERROR, } from "./tracing.js";
|
|
59
61
|
export type { OtelTracingOptions, TracingAttributes, TracingAttributeValue, TracingSpan, TracingStartSpanOptions, TracingTracer, } from "./tracing.js";
|
|
60
|
-
export { defineWebSocket, WebSocketRegistry, WebSocketProtocolError, WebSocketPayloadTooLargeError, WS_GUID, WS_READY_STATE, WS_OPCODE, WS_CLOSE_CODE, WS_MAX_CONTROL_PAYLOAD, DEFAULT_WS_BACKPRESSURE_LIMIT, DEFAULT_WS_MAX_PAYLOAD_LENGTH, DEFAULT_WS_IDLE_TIMEOUT_SECONDS, computeAcceptKey, parseSubprotocols, validateSelectedSubprotocol, validateUpgrade, parseFrame, encodeFrame, encodeClosePayload, decodeClosePayload, encodeSendPayload, normalizeWebSocketOptions, wsRateLimit, FrameSink, FRAME_INCOMPLETE, } from "./websocket.js";
|
|
62
|
+
export { defineWebSocket, WebSocketRegistry, WebSocketProtocolError, WebSocketPayloadTooLargeError, WS_GUID, WS_READY_STATE, WS_OPCODE, WS_CLOSE_CODE, WS_MAX_CONTROL_PAYLOAD, DEFAULT_WS_BACKPRESSURE_LIMIT, DEFAULT_WS_MAX_PAYLOAD_LENGTH, DEFAULT_WS_IDLE_TIMEOUT_SECONDS, computeAcceptKey, parseSubprotocols, validateSelectedSubprotocol, validateUpgrade, checkWebSocketOrigin, parseFrame, encodeFrame, encodeClosePayload, decodeClosePayload, encodeSendPayload, normalizeWebSocketOptions, wsRateLimit, FrameSink, FRAME_INCOMPLETE, } from "./websocket.js";
|
|
61
63
|
export type { WebSocketConnection, WebSocketContext, WebSocketHandler, WebSocketRouteEntry, NormalizedWebSocketOptions, WebSocketBeforeUpgrade, HandshakeResult, ParsedFrame, MessageEvent as WebSocketMessageEvent, FrameSinkEvents, } from "./websocket.js";
|
|
62
64
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,8BAA8B,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,iCAAiC,EAAE,MAAM,UAAU,CAAC;AAC7D,YAAY,EACV,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,aAAa,GACd,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACtE,YAAY,EACV,eAAe,EACf,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EACV,eAAe,EACf,UAAU,EACV,UAAU,EACV,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,KAAK,EACL,WAAW,EACX,QAAQ,EACR,UAAU,EACV,WAAW,EACX,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,kBAAkB,EAClB,WAAW,EACX,iBAAiB,EACjB,YAAY,EACZ,SAAS,GACV,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,SAAS,EACT,eAAe,EACf,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,yBAAyB,EACzB,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -6,9 +6,9 @@ export { _resetInsecureDefaultsLogForTests } from "./app.js";
|
|
|
6
6
|
export { getConnInfo, setConnInfo, assertBehindProxy, resolveClientIp, readRemoteAddress, readRemotePort, pickForwardedForByHops, } from "./conn-info.js";
|
|
7
7
|
export { subdomains, PSL_SNAPSHOT_DATE, PSL_PUBLIC_SUFFIXES, MAX_SNAPSHOT_AGE_DAYS, } from "./subdomains.js";
|
|
8
8
|
export { defineDependency, DEPENDENCY_MARKER } from "./dependency.js";
|
|
9
|
-
export { HttpError, BadRequestError, ValidationError, NotFoundError, UnauthorizedError, ForbiddenError, MethodNotAllowedError, PayloadTooLargeError, UnsupportedMediaTypeError, TooManyRequestsError, RequestTimeoutError, InternalError, } from "./errors.js";
|
|
9
|
+
export { HttpError, BadRequestError, ValidationError, NotFoundError, UnauthorizedError, ForbiddenError, MethodNotAllowedError, PayloadTooLargeError, UnsupportedMediaTypeError, TooManyRequestsError, RequestTimeoutError, InternalError, MessageLeakError, httpError, SAFE_CUSTOM_ERROR_RESPONSE_HEADERS, checkCustomErrorResponseHeaders, } from "./errors.js";
|
|
10
10
|
export { validate, isStandardSchema } from "./schema.js";
|
|
11
|
-
export { readBodyLimited, safeJsonParse, sanitizeHeaderName, sanitizeHeaderValue, timingSafeEqual, randomId, assertNoDuplicateSingletonHeaders, SMUGGLING_SINGLETON_HEADERS, verifyWebhookSignature, signWebhookPayload, assertStrongSecret, MIN_PROD_SECRET_BYTES, WEAK_SECRET_STRINGS, } from "./security.js";
|
|
11
|
+
export { readBodyLimited, safeJsonParse, isForbiddenObjectKey, sanitizeHeaderName, sanitizeHeaderValue, timingSafeEqual, randomId, assertNoDuplicateSingletonHeaders, assertNoReservedInternalHeaders, RESERVED_INBOUND_HEADER_PREFIXES, SMUGGLING_SINGLETON_HEADERS, verifyWebhookSignature, signWebhookPayload, assertStrongSecret, MIN_PROD_SECRET_BYTES, WEAK_SECRET_STRINGS, } from "./security.js";
|
|
12
12
|
export { requestId, secureHeaders, SECURE_HEADERS_MARKER, cors, CORS_HOOK_MARKER, CORS_ORIGIN_ALLOW_MARKER, CORS_WILDCARD_ORIGIN_MARKER, rateLimit, loginThrottle, timing, bearerAuth, basicAuth, csrf, CSRF_HOOK_MARKER, requireScopes, REQUIRE_SCOPES_AGGREGATE_KEY, REQUIRE_SCOPES_HOOK_MARKER, _resetSharedRateLimitStoresForTests, } from "./middleware.js";
|
|
13
13
|
export { etag } from "./etag.js";
|
|
14
14
|
export { compression, COMPRESSION_HOOK_MARKER, _resetCompressionRuntimeProbeForTests, } from "./compression.js";
|
|
@@ -18,6 +18,7 @@ export { serializeCookie, serializeClearCookie, assertCookieAttributes, readRequ
|
|
|
18
18
|
export { assertTemporalClaims, TemporalClaimError, } from "./time-claims.js";
|
|
19
19
|
export { every, some, except } from "./combine.js";
|
|
20
20
|
export { ipRestriction } from "./ip-restriction.js";
|
|
21
|
+
export { fetchGuard, SsrfBlockedError } from "./fetch-guard.js";
|
|
21
22
|
export { loadShedding, LOAD_SHEDDING_MARKER } from "./load-shedding.js";
|
|
22
23
|
export { defineConfig, ConfigValidationError } from "./config.js";
|
|
23
24
|
export { createLogger, noopLogger, DEFAULT_REDACT_KEYS } from "./logger.js";
|
|
@@ -28,5 +29,5 @@ export { discriminator, discriminatedUnion } from "./discriminator.js";
|
|
|
28
29
|
export { session, rotateSession, signValue, verifySignedValue, MemorySessionStore, SESSION_HOOK_MARKER, SESSION_SECRETS_MARKER, } from "./session.js";
|
|
29
30
|
export { fileField, multipartObject, isFileFieldSchema, isMultipartObjectSchema, } from "./multipart.js";
|
|
30
31
|
export { otelTracing, TRACING_SPAN_KIND_SERVER, TRACING_SPAN_STATUS_UNSET, TRACING_SPAN_STATUS_OK, TRACING_SPAN_STATUS_ERROR, } from "./tracing.js";
|
|
31
|
-
export { defineWebSocket, WebSocketRegistry, WebSocketProtocolError, WebSocketPayloadTooLargeError, WS_GUID, WS_READY_STATE, WS_OPCODE, WS_CLOSE_CODE, WS_MAX_CONTROL_PAYLOAD, DEFAULT_WS_BACKPRESSURE_LIMIT, DEFAULT_WS_MAX_PAYLOAD_LENGTH, DEFAULT_WS_IDLE_TIMEOUT_SECONDS, computeAcceptKey, parseSubprotocols, validateSelectedSubprotocol, validateUpgrade, parseFrame, encodeFrame, encodeClosePayload, decodeClosePayload, encodeSendPayload, normalizeWebSocketOptions, wsRateLimit, FrameSink, FRAME_INCOMPLETE, } from "./websocket.js";
|
|
32
|
+
export { defineWebSocket, WebSocketRegistry, WebSocketProtocolError, WebSocketPayloadTooLargeError, WS_GUID, WS_READY_STATE, WS_OPCODE, WS_CLOSE_CODE, WS_MAX_CONTROL_PAYLOAD, DEFAULT_WS_BACKPRESSURE_LIMIT, DEFAULT_WS_MAX_PAYLOAD_LENGTH, DEFAULT_WS_IDLE_TIMEOUT_SECONDS, computeAcceptKey, parseSubprotocols, validateSelectedSubprotocol, validateUpgrade, checkWebSocketOrigin, parseFrame, encodeFrame, encodeClosePayload, decodeClosePayload, encodeSendPayload, normalizeWebSocketOptions, wsRateLimit, FrameSink, FRAME_INCOMPLETE, } from "./websocket.js";
|
|
32
33
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,8BAA8B,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,iCAAiC,EAAE,MAAM,UAAU,CAAC;AAY7D,OAAO,EACL,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AA8BtE,OAAO,EACL,SAAS,EACT,eAAe,EACf,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,yBAAyB,EACzB,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/ip-restriction.d.ts
CHANGED
|
@@ -51,6 +51,17 @@ export interface IpRestrictionOptions {
|
|
|
51
51
|
*/
|
|
52
52
|
message?: string;
|
|
53
53
|
}
|
|
54
|
+
/** @internal Parsed IP address (shared with `fetchGuard()`). */
|
|
55
|
+
export interface ParsedIp {
|
|
56
|
+
bytes: Uint8Array;
|
|
57
|
+
family: 4 | 6;
|
|
58
|
+
}
|
|
59
|
+
/** @internal Compiled CIDR matcher (shared with `fetchGuard()`). */
|
|
60
|
+
export interface IpMatcher {
|
|
61
|
+
family: 4 | 6;
|
|
62
|
+
prefix: number;
|
|
63
|
+
bytes: Uint8Array;
|
|
64
|
+
}
|
|
54
65
|
/**
|
|
55
66
|
* Block or allow requests by source IP / CIDR range. In direct Web-standard
|
|
56
67
|
* runtimes, pass `resolveIp` from the adapter-specific connection metadata.
|
|
@@ -72,4 +83,10 @@ export interface IpRestrictionOptions {
|
|
|
72
83
|
* @since 0.19.0
|
|
73
84
|
*/
|
|
74
85
|
export declare function ipRestriction(opts: IpRestrictionOptions): Hooks;
|
|
86
|
+
/** @internal */
|
|
87
|
+
export declare function matchesMatcher(ip: ParsedIp, m: IpMatcher): boolean;
|
|
88
|
+
/** @internal */
|
|
89
|
+
export declare function compileCidrMatcher(input: string): IpMatcher;
|
|
90
|
+
/** @internal */
|
|
91
|
+
export declare function parseIp(input: string): ParsedIp | undefined;
|
|
75
92
|
//# sourceMappingURL=ip-restriction.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ip-restriction.d.ts","sourceRoot":"","sources":["../src/ip-restriction.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGrD;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,MAAM,GAAG,SAAS,CAAC;IAC/D;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;
|
|
1
|
+
{"version":3,"file":"ip-restriction.d.ts","sourceRoot":"","sources":["../src/ip-restriction.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGrD;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,MAAM,GAAG,SAAS,CAAC;IAC/D;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,gEAAgE;AAChE,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,UAAU,CAAC;IAClB,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;CACf;AAED,oEAAoE;AACpE,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,UAAU,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,KAAK,CAyB/D;AAaD,gBAAgB;AAChB,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,GAAG,OAAO,CAclE;AAED,gBAAgB;AAChB,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CA4B3D;AA4BD,gBAAgB;AAChB,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAI3D"}
|
package/dist/ip-restriction.js
CHANGED
|
@@ -64,7 +64,8 @@ function forwardedIpResolver(ctx) {
|
|
|
64
64
|
return forwarded.split(",")[0]?.trim();
|
|
65
65
|
return headers.get("x-real-ip") ?? undefined;
|
|
66
66
|
}
|
|
67
|
-
|
|
67
|
+
/** @internal */
|
|
68
|
+
export function matchesMatcher(ip, m) {
|
|
68
69
|
const candidate = normalizeFamily(ip, m.family);
|
|
69
70
|
if (!candidate)
|
|
70
71
|
return false;
|
|
@@ -82,7 +83,8 @@ function matchesMatcher(ip, m) {
|
|
|
82
83
|
const mask = 0xff << (8 - remaining);
|
|
83
84
|
return ((candidate[fullBytes] ^ expected[fullBytes]) & mask) === 0;
|
|
84
85
|
}
|
|
85
|
-
|
|
86
|
+
/** @internal */
|
|
87
|
+
export function compileCidrMatcher(input) {
|
|
86
88
|
let addr = input;
|
|
87
89
|
let prefixStr;
|
|
88
90
|
if (input.includes("/")) {
|
|
@@ -133,7 +135,8 @@ function applyPrefixMask(bytes, prefix) {
|
|
|
133
135
|
}
|
|
134
136
|
return out;
|
|
135
137
|
}
|
|
136
|
-
|
|
138
|
+
/** @internal */
|
|
139
|
+
export function parseIp(input) {
|
|
137
140
|
const trimmed = input.trim();
|
|
138
141
|
if (trimmed.includes(":"))
|
|
139
142
|
return parseIPv6(trimmed);
|