@daloyjs/core 0.34.3 → 0.35.1
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 +151 -32
- package/dist/adapters/bun.d.ts +0 -1
- package/dist/adapters/bun.js +0 -1
- package/dist/adapters/cloudflare.d.ts +0 -1
- package/dist/adapters/cloudflare.js +0 -1
- package/dist/adapters/deno.d.ts +0 -1
- package/dist/adapters/deno.js +0 -1
- package/dist/adapters/fastly.d.ts +0 -1
- package/dist/adapters/fastly.js +0 -1
- package/dist/adapters/lambda.d.ts +0 -1
- package/dist/adapters/lambda.js +0 -1
- package/dist/adapters/node.d.ts +0 -1
- package/dist/adapters/node.js +175 -35
- package/dist/adapters/vercel.d.ts +0 -1
- package/dist/adapters/vercel.js +0 -1
- package/dist/app.d.ts +18 -1
- package/dist/app.js +396 -118
- package/dist/banner.d.ts +0 -1
- package/dist/banner.js +0 -1
- package/dist/cli.d.ts +32 -1
- package/dist/cli.js +62 -5
- package/dist/client.d.ts +0 -1
- package/dist/client.js +0 -1
- package/dist/combine.d.ts +0 -1
- package/dist/combine.js +0 -1
- package/dist/compression.d.ts +0 -1
- package/dist/compression.js +0 -1
- package/dist/config.d.ts +0 -1
- package/dist/config.js +0 -1
- package/dist/conn-info.d.ts +0 -1
- package/dist/conn-info.js +0 -1
- package/dist/contract.d.ts +0 -1
- package/dist/contract.js +0 -1
- package/dist/cookie.d.ts +0 -1
- package/dist/cookie.js +0 -1
- package/dist/dependency.d.ts +0 -1
- package/dist/dependency.js +0 -1
- package/dist/discriminator.d.ts +0 -1
- package/dist/discriminator.js +0 -1
- package/dist/docs.d.ts +0 -1
- package/dist/docs.js +0 -1
- package/dist/errors.d.ts +0 -1
- package/dist/errors.js +0 -1
- package/dist/etag.d.ts +0 -1
- package/dist/etag.js +0 -1
- package/dist/fetch-guard.d.ts +50 -6
- package/dist/fetch-guard.js +83 -18
- package/dist/hashing.d.ts +0 -1
- package/dist/hashing.js +0 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +3 -3
- package/dist/ip-restriction.d.ts +0 -1
- package/dist/ip-restriction.js +0 -1
- package/dist/jwk.d.ts +0 -1
- package/dist/jwk.js +0 -1
- package/dist/jwt.d.ts +15 -1
- package/dist/jwt.js +56 -3
- package/dist/load-shedding.d.ts +0 -1
- package/dist/load-shedding.js +0 -1
- package/dist/logger.d.ts +0 -1
- package/dist/logger.js +0 -1
- package/dist/middleware.d.ts +78 -1
- package/dist/middleware.js +150 -18
- package/dist/multipart.d.ts +0 -1
- package/dist/multipart.js +0 -1
- package/dist/openapi.d.ts +0 -1
- package/dist/openapi.js +0 -1
- package/dist/rate-limit-redis.d.ts +0 -1
- package/dist/rate-limit-redis.js +0 -1
- package/dist/router.d.ts +0 -1
- package/dist/router.js +0 -1
- package/dist/safe-redirect.d.ts +91 -0
- package/dist/safe-redirect.js +168 -0
- package/dist/sbom.cdx.json +13 -9
- package/dist/sbom.spdx.json +5 -5
- package/dist/schema.d.ts +0 -1
- package/dist/schema.js +0 -1
- package/dist/security-schemes.d.ts +0 -1
- package/dist/security-schemes.js +0 -1
- package/dist/security.d.ts +134 -3
- package/dist/security.js +265 -6
- package/dist/session.d.ts +0 -1
- package/dist/session.js +0 -1
- package/dist/streaming.d.ts +0 -1
- package/dist/streaming.js +0 -1
- package/dist/subdomains.d.ts +0 -1
- package/dist/subdomains.js +0 -1
- package/dist/time-claims.d.ts +0 -1
- package/dist/time-claims.js +0 -1
- package/dist/tracing.d.ts +0 -1
- package/dist/tracing.js +0 -1
- package/dist/types.d.ts +0 -1
- package/dist/types.js +0 -1
- package/dist/websocket.d.ts +0 -1
- package/dist/websocket.js +0 -1
- package/package.json +35 -15
- package/dist/adapters/bun.d.ts.map +0 -1
- package/dist/adapters/bun.js.map +0 -1
- package/dist/adapters/cloudflare.d.ts.map +0 -1
- package/dist/adapters/cloudflare.js.map +0 -1
- package/dist/adapters/deno.d.ts.map +0 -1
- package/dist/adapters/deno.js.map +0 -1
- package/dist/adapters/fastly.d.ts.map +0 -1
- package/dist/adapters/fastly.js.map +0 -1
- package/dist/adapters/lambda.d.ts.map +0 -1
- package/dist/adapters/lambda.js.map +0 -1
- package/dist/adapters/node.d.ts.map +0 -1
- package/dist/adapters/node.js.map +0 -1
- package/dist/adapters/vercel.d.ts.map +0 -1
- package/dist/adapters/vercel.js.map +0 -1
- package/dist/app.d.ts.map +0 -1
- package/dist/app.js.map +0 -1
- package/dist/banner.d.ts.map +0 -1
- package/dist/banner.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/combine.d.ts.map +0 -1
- package/dist/combine.js.map +0 -1
- package/dist/compression.d.ts.map +0 -1
- package/dist/compression.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/conn-info.d.ts.map +0 -1
- package/dist/conn-info.js.map +0 -1
- package/dist/contract.d.ts.map +0 -1
- package/dist/contract.js.map +0 -1
- package/dist/cookie.d.ts.map +0 -1
- package/dist/cookie.js.map +0 -1
- package/dist/dependency.d.ts.map +0 -1
- package/dist/dependency.js.map +0 -1
- package/dist/discriminator.d.ts.map +0 -1
- package/dist/discriminator.js.map +0 -1
- package/dist/docs.d.ts.map +0 -1
- package/dist/docs.js.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/etag.d.ts.map +0 -1
- package/dist/etag.js.map +0 -1
- package/dist/fetch-guard.d.ts.map +0 -1
- package/dist/fetch-guard.js.map +0 -1
- package/dist/hashing.d.ts.map +0 -1
- package/dist/hashing.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/ip-restriction.d.ts.map +0 -1
- package/dist/ip-restriction.js.map +0 -1
- package/dist/jwk.d.ts.map +0 -1
- package/dist/jwk.js.map +0 -1
- package/dist/jwt.d.ts.map +0 -1
- package/dist/jwt.js.map +0 -1
- package/dist/load-shedding.d.ts.map +0 -1
- package/dist/load-shedding.js.map +0 -1
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js.map +0 -1
- package/dist/middleware.d.ts.map +0 -1
- package/dist/middleware.js.map +0 -1
- package/dist/multipart.d.ts.map +0 -1
- package/dist/multipart.js.map +0 -1
- package/dist/openapi.d.ts.map +0 -1
- package/dist/openapi.js.map +0 -1
- package/dist/rate-limit-redis.d.ts.map +0 -1
- package/dist/rate-limit-redis.js.map +0 -1
- package/dist/router.d.ts.map +0 -1
- package/dist/router.js.map +0 -1
- package/dist/schema.d.ts.map +0 -1
- package/dist/schema.js.map +0 -1
- package/dist/security-schemes.d.ts.map +0 -1
- package/dist/security-schemes.js.map +0 -1
- package/dist/security.d.ts.map +0 -1
- package/dist/security.js.map +0 -1
- package/dist/session.d.ts.map +0 -1
- package/dist/session.js.map +0 -1
- package/dist/streaming.d.ts.map +0 -1
- package/dist/streaming.js.map +0 -1
- package/dist/subdomains.d.ts.map +0 -1
- package/dist/subdomains.js.map +0 -1
- package/dist/time-claims.d.ts.map +0 -1
- package/dist/time-claims.js.map +0 -1
- package/dist/tracing.d.ts.map +0 -1
- package/dist/tracing.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/websocket.d.ts.map +0 -1
- package/dist/websocket.js.map +0 -1
package/dist/banner.d.ts
CHANGED
|
@@ -37,4 +37,3 @@ export declare function formatStartupBanner(options: StartupBannerOptions): stri
|
|
|
37
37
|
* replace ad-hoc `console.log("listening on …")` calls in starter templates.
|
|
38
38
|
*/
|
|
39
39
|
export declare function printStartupBanner(options: StartupBannerOptions, write?: (s: string) => void): void;
|
|
40
|
-
//# sourceMappingURL=banner.d.ts.map
|
package/dist/banner.js
CHANGED
package/dist/cli.d.ts
CHANGED
|
@@ -71,6 +71,32 @@ export type DevRuntime = "node" | "bun" | "deno";
|
|
|
71
71
|
* @since 0.3.0
|
|
72
72
|
*/
|
|
73
73
|
export declare function detectRuntime(): DevRuntime;
|
|
74
|
+
/**
|
|
75
|
+
* Validate a CLI-supplied entry path before it is handed to `import()` or
|
|
76
|
+
* forwarded as a child-process argv element. Rejects NUL bytes, CR/LF, and
|
|
77
|
+
* leading `-` characters so a hostile caller (or a misparsed positional)
|
|
78
|
+
* cannot smuggle a `--eval=...`, `--inspect-brk=...`, or similar
|
|
79
|
+
* argv-injection payload past `spawn({ shell: false })` into Node, Bun, or
|
|
80
|
+
* Deno's own argv parser.
|
|
81
|
+
*
|
|
82
|
+
* This is defense-in-depth alongside {@link parseArgs}, which already
|
|
83
|
+
* rejects `-`-prefixed positionals. The check also runs in programmatic
|
|
84
|
+
* `runCli()` callers and tests so the invariant holds regardless of how the
|
|
85
|
+
* entry value was produced.
|
|
86
|
+
*
|
|
87
|
+
* @internal
|
|
88
|
+
*/
|
|
89
|
+
export declare function assertSafeEntryPath(entry: string, context: string): void;
|
|
90
|
+
/**
|
|
91
|
+
* Normalize a relative entry path so the host runtime always sees an
|
|
92
|
+
* unambiguous file path, never a possible flag. Absolute paths and paths
|
|
93
|
+
* already anchored with `./` or `../` are returned unchanged; bare relative
|
|
94
|
+
* paths like `src/server.ts` are rewritten to `./src/server.ts`. This is
|
|
95
|
+
* the second half of the {@link assertSafeEntryPath} defense.
|
|
96
|
+
*
|
|
97
|
+
* @internal
|
|
98
|
+
*/
|
|
99
|
+
export declare function normalizeEntryArg(entry: string): string;
|
|
74
100
|
/**
|
|
75
101
|
* Build the `(command, args)` pair `daloy dev` should spawn for the given
|
|
76
102
|
* runtime and entry file. Pure function so tests can assert exact argv
|
|
@@ -84,6 +110,12 @@ export declare function detectRuntime(): DevRuntime;
|
|
|
84
110
|
* reading the source tree; users who need more should run `deno run`
|
|
85
111
|
* directly).
|
|
86
112
|
*
|
|
113
|
+
* The entry is validated via {@link assertSafeEntryPath} and anchored with
|
|
114
|
+
* {@link normalizeEntryArg} so a future caller cannot smuggle a flag past
|
|
115
|
+
* `spawn({ shell: false })` into the runtime's argv parser. See
|
|
116
|
+
* `SECURITY.md` § "CLI threat model" for the full rationale (and why we
|
|
117
|
+
* are not vulnerable to the class of bug Snyk reported as CVE-2022-22984).
|
|
118
|
+
*
|
|
87
119
|
* @since 0.3.0
|
|
88
120
|
*/
|
|
89
121
|
export declare function buildDevCommand(runtime: DevRuntime, entry: string): {
|
|
@@ -114,4 +146,3 @@ export declare function runCli(argv: readonly string[], io: CliIO): Promise<CliR
|
|
|
114
146
|
* @since 0.14.0
|
|
115
147
|
*/
|
|
116
148
|
export declare function buildAiDump(app: App, opts: CliOptions): Record<string, unknown>;
|
|
117
|
-
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cli.js
CHANGED
|
@@ -115,6 +115,52 @@ export function detectRuntime() {
|
|
|
115
115
|
return "deno";
|
|
116
116
|
return "node";
|
|
117
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Validate a CLI-supplied entry path before it is handed to `import()` or
|
|
120
|
+
* forwarded as a child-process argv element. Rejects NUL bytes, CR/LF, and
|
|
121
|
+
* leading `-` characters so a hostile caller (or a misparsed positional)
|
|
122
|
+
* cannot smuggle a `--eval=...`, `--inspect-brk=...`, or similar
|
|
123
|
+
* argv-injection payload past `spawn({ shell: false })` into Node, Bun, or
|
|
124
|
+
* Deno's own argv parser.
|
|
125
|
+
*
|
|
126
|
+
* This is defense-in-depth alongside {@link parseArgs}, which already
|
|
127
|
+
* rejects `-`-prefixed positionals. The check also runs in programmatic
|
|
128
|
+
* `runCli()` callers and tests so the invariant holds regardless of how the
|
|
129
|
+
* entry value was produced.
|
|
130
|
+
*
|
|
131
|
+
* @internal
|
|
132
|
+
*/
|
|
133
|
+
export function assertSafeEntryPath(entry, context) {
|
|
134
|
+
if (typeof entry !== "string" || entry.length === 0) {
|
|
135
|
+
throw new Error(`${context}: entry path must be a non-empty string.`);
|
|
136
|
+
}
|
|
137
|
+
if (entry.includes("\0") || /[\r\n]/.test(entry)) {
|
|
138
|
+
throw new Error(`${context}: entry path must not contain NUL bytes or newlines (got: ${JSON.stringify(entry)}).`);
|
|
139
|
+
}
|
|
140
|
+
if (entry.startsWith("-")) {
|
|
141
|
+
throw new Error(`${context}: entry path must not start with "-" — runtimes parse leading dashes as flags ` +
|
|
142
|
+
`(got: ${JSON.stringify(entry)}). Prefix the path with "./" to disambiguate.`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Normalize a relative entry path so the host runtime always sees an
|
|
147
|
+
* unambiguous file path, never a possible flag. Absolute paths and paths
|
|
148
|
+
* already anchored with `./` or `../` are returned unchanged; bare relative
|
|
149
|
+
* paths like `src/server.ts` are rewritten to `./src/server.ts`. This is
|
|
150
|
+
* the second half of the {@link assertSafeEntryPath} defense.
|
|
151
|
+
*
|
|
152
|
+
* @internal
|
|
153
|
+
*/
|
|
154
|
+
export function normalizeEntryArg(entry) {
|
|
155
|
+
if (entry.startsWith("./") || entry.startsWith("../"))
|
|
156
|
+
return entry;
|
|
157
|
+
if (entry.startsWith("/"))
|
|
158
|
+
return entry;
|
|
159
|
+
// Windows drive letter (C:\, D:/, ...).
|
|
160
|
+
if (/^[A-Za-z]:[\\/]/.test(entry))
|
|
161
|
+
return entry;
|
|
162
|
+
return `./${entry}`;
|
|
163
|
+
}
|
|
118
164
|
/**
|
|
119
165
|
* Build the `(command, args)` pair `daloy dev` should spawn for the given
|
|
120
166
|
* runtime and entry file. Pure function so tests can assert exact argv
|
|
@@ -128,20 +174,28 @@ export function detectRuntime() {
|
|
|
128
174
|
* reading the source tree; users who need more should run `deno run`
|
|
129
175
|
* directly).
|
|
130
176
|
*
|
|
177
|
+
* The entry is validated via {@link assertSafeEntryPath} and anchored with
|
|
178
|
+
* {@link normalizeEntryArg} so a future caller cannot smuggle a flag past
|
|
179
|
+
* `spawn({ shell: false })` into the runtime's argv parser. See
|
|
180
|
+
* `SECURITY.md` § "CLI threat model" for the full rationale (and why we
|
|
181
|
+
* are not vulnerable to the class of bug Snyk reported as CVE-2022-22984).
|
|
182
|
+
*
|
|
131
183
|
* @since 0.3.0
|
|
132
184
|
*/
|
|
133
185
|
export function buildDevCommand(runtime, entry) {
|
|
186
|
+
assertSafeEntryPath(entry, "daloy dev");
|
|
187
|
+
const safe = normalizeEntryArg(entry);
|
|
134
188
|
switch (runtime) {
|
|
135
189
|
case "bun":
|
|
136
|
-
return { command: "bun", args: ["--hot",
|
|
190
|
+
return { command: "bun", args: ["--hot", safe] };
|
|
137
191
|
case "deno":
|
|
138
192
|
return {
|
|
139
193
|
command: "deno",
|
|
140
|
-
args: ["run", "--watch", "--allow-net", "--allow-env", "--allow-read",
|
|
194
|
+
args: ["run", "--watch", "--allow-net", "--allow-env", "--allow-read", safe],
|
|
141
195
|
};
|
|
142
196
|
case "node":
|
|
143
197
|
default:
|
|
144
|
-
return { command: "node", args: ["--import", "tsx", "--watch",
|
|
198
|
+
return { command: "node", args: ["--import", "tsx", "--watch", safe] };
|
|
145
199
|
}
|
|
146
200
|
}
|
|
147
201
|
/**
|
|
@@ -151,8 +205,10 @@ export function buildDevCommand(runtime, entry) {
|
|
|
151
205
|
* first candidate.
|
|
152
206
|
*/
|
|
153
207
|
async function resolveDevEntry(entry) {
|
|
154
|
-
if (entry)
|
|
208
|
+
if (entry) {
|
|
209
|
+
assertSafeEntryPath(entry, "daloy dev");
|
|
155
210
|
return entry;
|
|
211
|
+
}
|
|
156
212
|
try {
|
|
157
213
|
const fs = await import("node:fs");
|
|
158
214
|
const path = await import("node:path");
|
|
@@ -725,6 +781,8 @@ function aiSchema(schema) {
|
|
|
725
781
|
return {};
|
|
726
782
|
}
|
|
727
783
|
async function loadApp(entry, io) {
|
|
784
|
+
if (entry !== undefined)
|
|
785
|
+
assertSafeEntryPath(entry, "daloy inspect");
|
|
728
786
|
const candidates = entry ? [entry] : DEFAULT_ENTRIES.slice();
|
|
729
787
|
let lastErr;
|
|
730
788
|
for (const candidate of candidates) {
|
|
@@ -790,4 +848,3 @@ function isApp(value) {
|
|
|
790
848
|
typeof value.introspect === "function" &&
|
|
791
849
|
typeof value.fetch === "function");
|
|
792
850
|
}
|
|
793
|
-
//# sourceMappingURL=cli.js.map
|
package/dist/client.d.ts
CHANGED
package/dist/client.js
CHANGED
package/dist/combine.d.ts
CHANGED
package/dist/combine.js
CHANGED
package/dist/compression.d.ts
CHANGED
package/dist/compression.js
CHANGED
package/dist/config.d.ts
CHANGED
|
@@ -95,4 +95,3 @@ export interface DefineConfigOptions<S extends StandardSchemaV1> {
|
|
|
95
95
|
* @since 0.20.0
|
|
96
96
|
*/
|
|
97
97
|
export declare function defineConfig<S extends StandardSchemaV1>(opts: DefineConfigOptions<S>): Promise<StandardSchemaV1.InferOutput<S>>;
|
|
98
|
-
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.js
CHANGED
package/dist/conn-info.d.ts
CHANGED
package/dist/conn-info.js
CHANGED
package/dist/contract.d.ts
CHANGED
|
@@ -47,4 +47,3 @@ export interface ContractTestOptions {
|
|
|
47
47
|
* @returns A {@link ContractReport}. In CI, exit non-zero when `report.ok` is `false`.
|
|
48
48
|
*/
|
|
49
49
|
export declare function runContractTests(app: App, opts?: ContractTestOptions): Promise<ContractReport>;
|
|
50
|
-
//# sourceMappingURL=contract.d.ts.map
|
package/dist/contract.js
CHANGED
package/dist/cookie.d.ts
CHANGED
|
@@ -123,4 +123,3 @@ export declare function serializeClearCookie(name: string, attributes?: CookieAt
|
|
|
123
123
|
export declare function readRequestCookie(header: string | null | undefined, name: string): string | null;
|
|
124
124
|
/** @internal Re-exported for tests. */
|
|
125
125
|
export declare const __COOKIE_FRAMEWORK_PREFIX__ = "daloy.cookie";
|
|
126
|
-
//# sourceMappingURL=cookie.d.ts.map
|
package/dist/cookie.js
CHANGED
package/dist/dependency.d.ts
CHANGED
|
@@ -45,4 +45,3 @@ export interface DependencyHooks extends Hooks {
|
|
|
45
45
|
* @since 0.24.0
|
|
46
46
|
*/
|
|
47
47
|
export declare function defineDependency<TName extends string, TValue, TStateKey extends string = TName>(opts: DependencyOptions<TName, TValue, TStateKey>): DependencyHooks;
|
|
48
|
-
//# sourceMappingURL=dependency.d.ts.map
|
package/dist/dependency.js
CHANGED
package/dist/discriminator.d.ts
CHANGED
|
@@ -71,4 +71,3 @@ export type DiscriminatedUnion<V extends Record<string, StandardSchemaV1>> = Sta
|
|
|
71
71
|
*/
|
|
72
72
|
export declare function discriminatedUnion<P extends string, V extends Record<string, StandardSchemaV1>>(propertyName: P, variants: V, opts?: DiscriminatedUnionOptions): DiscriminatedUnion<V>;
|
|
73
73
|
export {};
|
|
74
|
-
//# sourceMappingURL=discriminator.d.ts.map
|
package/dist/discriminator.js
CHANGED
package/dist/docs.d.ts
CHANGED
|
@@ -153,4 +153,3 @@ export declare function docsContentSecurityPolicy(opts?: DocsContentSecurityPoli
|
|
|
153
153
|
* {@link docsContentSecurityPolicy} (or a caller-supplied override).
|
|
154
154
|
*/
|
|
155
155
|
export declare function htmlResponse(html: string, opts?: HtmlResponseOptions): Response;
|
|
156
|
-
//# sourceMappingURL=docs.d.ts.map
|
package/dist/docs.js
CHANGED
|
@@ -113,4 +113,3 @@ function scalarConfigurationAttr(specUrl, configuration) {
|
|
|
113
113
|
const { content: _content, fetch: _fetch, plugins: _plugins, sources: _sources, spec: _spec, url: _url, ...uiConfiguration } = configuration;
|
|
114
114
|
return ` data-configuration='${escapeHtml(JSON.stringify({ ...uiConfiguration, url: specUrl }))}'`;
|
|
115
115
|
}
|
|
116
|
-
//# sourceMappingURL=docs.js.map
|
package/dist/errors.d.ts
CHANGED
package/dist/errors.js
CHANGED
package/dist/etag.d.ts
CHANGED
package/dist/etag.js
CHANGED
package/dist/fetch-guard.d.ts
CHANGED
|
@@ -24,18 +24,63 @@
|
|
|
24
24
|
* Plus an always-deny floor that no flag can lift:
|
|
25
25
|
*
|
|
26
26
|
* - `0.0.0.0/8` (this-network), `100.64.0.0/10` (carrier-grade NAT — covers
|
|
27
|
-
* Alibaba `100.100.100.200`), `
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* `
|
|
31
|
-
*
|
|
27
|
+
* Alibaba `100.100.100.200`), `169.254.169.254/32` (AWS / Azure /
|
|
28
|
+
* DigitalOcean / GCP IMDS), `169.254.170.2/32` and `169.254.170.23/32`
|
|
29
|
+
* (AWS ECS task metadata / EKS Pod Identity), `192.0.0.0/24` (covers
|
|
30
|
+
* Oracle Cloud `192.0.0.192`), `192.0.2.0/24`, `198.18.0.0/15`,
|
|
31
|
+
* `198.51.100.0/24`, `203.0.113.0/24` (IANA-reserved), `224.0.0.0/4`
|
|
32
|
+
* (multicast), `240.0.0.0/4` (reserved), `255.255.255.255` (broadcast).
|
|
33
|
+
* - IPv6: `::/128` (unspecified), `ff00::/8` (multicast),
|
|
34
|
+
* `fd00:ec2::254/128` (AWS IMDSv2 IPv6), IPv4-mapped
|
|
32
35
|
* `::ffff:0:0/96` is re-checked against the embedded IPv4 address.
|
|
33
36
|
*
|
|
37
|
+
* The floor also picks up any user-supplied `denyAddresses` — these win
|
|
38
|
+
* over `allowAddresses` and over the soft-deny class flags, so an
|
|
39
|
+
* operator-pinned internal range is never accidentally re-exposed by a
|
|
40
|
+
* later `allowAddresses` carveout.
|
|
41
|
+
*
|
|
34
42
|
* Redirects are followed **manually** with re-validation at each hop so
|
|
35
43
|
* an attacker cannot bypass the check via a `302 → http://169.254...`.
|
|
36
44
|
* `non-http(s)` protocols (`file:`, `ftp:`, `gopher:`, `data:`) are
|
|
37
45
|
* rejected before any network call.
|
|
38
46
|
*
|
|
47
|
+
* ## Residual DNS-rebinding (TOCTOU) caveat
|
|
48
|
+
*
|
|
49
|
+
* `fetchGuard()` resolves the hostname, validates every returned address
|
|
50
|
+
* against the deny / allow set, and only then hands the original
|
|
51
|
+
* `Request` to the underlying `fetch`. The underlying `fetch` performs
|
|
52
|
+
* its **own** DNS lookup when it opens the socket. An attacker that
|
|
53
|
+
* controls a TTL=0 record can return a public IP at validation time and
|
|
54
|
+
* a `127.0.0.1` / `169.254.169.254` at connect time, slipping past the
|
|
55
|
+
* library-level check. This residual TOCTOU window cannot be closed at
|
|
56
|
+
* the `fetch()` boundary without injecting a custom HTTP dispatcher
|
|
57
|
+
* (e.g. `undici.Agent({ connect: { lookup } })`) — and Daloy
|
|
58
|
+
* deliberately ships **zero** runtime dependencies, so we do not bundle
|
|
59
|
+
* `undici`. To fully close the window:
|
|
60
|
+
*
|
|
61
|
+
* 1. **Operator-side** (recommended): block egress to RFC1918 /
|
|
62
|
+
* loopback / link-local at the VPC / firewall layer. This neutralises
|
|
63
|
+
* the rebinding even if the application is naïve.
|
|
64
|
+
* 2. **Caller-side, Node only**: install `undici` and pass a custom
|
|
65
|
+
* `fetch` that wires a dispatcher with a pinned-IP `connect.lookup`,
|
|
66
|
+
* e.g.
|
|
67
|
+
* ```ts
|
|
68
|
+
* import { Agent, fetch as undiciFetch } from "undici";
|
|
69
|
+
* import * as dns from "node:dns/promises";
|
|
70
|
+
* const safeFetch = fetchGuard({
|
|
71
|
+
* fetch: async (input, init) => {
|
|
72
|
+
* const url = new URL(typeof input === "string" ? input : input.url);
|
|
73
|
+
* const { address, family } = await dns.lookup(url.hostname, { verbatim: true });
|
|
74
|
+
* const dispatcher = new Agent({
|
|
75
|
+
* connect: { lookup: (_h, _o, cb) => cb(null, address, family) },
|
|
76
|
+
* });
|
|
77
|
+
* return undiciFetch(input, { ...init, dispatcher });
|
|
78
|
+
* },
|
|
79
|
+
* });
|
|
80
|
+
* ```
|
|
81
|
+
* The pre-resolved IP is what the socket connects to; TLS SNI /
|
|
82
|
+
* cert validation still uses the original hostname.
|
|
83
|
+
*
|
|
39
84
|
* @since 0.34.0
|
|
40
85
|
* @module
|
|
41
86
|
*/
|
|
@@ -160,4 +205,3 @@ export interface FetchGuardOptions {
|
|
|
160
205
|
* @since 0.34.0
|
|
161
206
|
*/
|
|
162
207
|
export declare function fetchGuard(options?: FetchGuardOptions): typeof fetch;
|
|
163
|
-
//# sourceMappingURL=fetch-guard.d.ts.map
|
package/dist/fetch-guard.js
CHANGED
|
@@ -24,18 +24,63 @@
|
|
|
24
24
|
* Plus an always-deny floor that no flag can lift:
|
|
25
25
|
*
|
|
26
26
|
* - `0.0.0.0/8` (this-network), `100.64.0.0/10` (carrier-grade NAT — covers
|
|
27
|
-
* Alibaba `100.100.100.200`), `
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* `
|
|
31
|
-
*
|
|
27
|
+
* Alibaba `100.100.100.200`), `169.254.169.254/32` (AWS / Azure /
|
|
28
|
+
* DigitalOcean / GCP IMDS), `169.254.170.2/32` and `169.254.170.23/32`
|
|
29
|
+
* (AWS ECS task metadata / EKS Pod Identity), `192.0.0.0/24` (covers
|
|
30
|
+
* Oracle Cloud `192.0.0.192`), `192.0.2.0/24`, `198.18.0.0/15`,
|
|
31
|
+
* `198.51.100.0/24`, `203.0.113.0/24` (IANA-reserved), `224.0.0.0/4`
|
|
32
|
+
* (multicast), `240.0.0.0/4` (reserved), `255.255.255.255` (broadcast).
|
|
33
|
+
* - IPv6: `::/128` (unspecified), `ff00::/8` (multicast),
|
|
34
|
+
* `fd00:ec2::254/128` (AWS IMDSv2 IPv6), IPv4-mapped
|
|
32
35
|
* `::ffff:0:0/96` is re-checked against the embedded IPv4 address.
|
|
33
36
|
*
|
|
37
|
+
* The floor also picks up any user-supplied `denyAddresses` — these win
|
|
38
|
+
* over `allowAddresses` and over the soft-deny class flags, so an
|
|
39
|
+
* operator-pinned internal range is never accidentally re-exposed by a
|
|
40
|
+
* later `allowAddresses` carveout.
|
|
41
|
+
*
|
|
34
42
|
* Redirects are followed **manually** with re-validation at each hop so
|
|
35
43
|
* an attacker cannot bypass the check via a `302 → http://169.254...`.
|
|
36
44
|
* `non-http(s)` protocols (`file:`, `ftp:`, `gopher:`, `data:`) are
|
|
37
45
|
* rejected before any network call.
|
|
38
46
|
*
|
|
47
|
+
* ## Residual DNS-rebinding (TOCTOU) caveat
|
|
48
|
+
*
|
|
49
|
+
* `fetchGuard()` resolves the hostname, validates every returned address
|
|
50
|
+
* against the deny / allow set, and only then hands the original
|
|
51
|
+
* `Request` to the underlying `fetch`. The underlying `fetch` performs
|
|
52
|
+
* its **own** DNS lookup when it opens the socket. An attacker that
|
|
53
|
+
* controls a TTL=0 record can return a public IP at validation time and
|
|
54
|
+
* a `127.0.0.1` / `169.254.169.254` at connect time, slipping past the
|
|
55
|
+
* library-level check. This residual TOCTOU window cannot be closed at
|
|
56
|
+
* the `fetch()` boundary without injecting a custom HTTP dispatcher
|
|
57
|
+
* (e.g. `undici.Agent({ connect: { lookup } })`) — and Daloy
|
|
58
|
+
* deliberately ships **zero** runtime dependencies, so we do not bundle
|
|
59
|
+
* `undici`. To fully close the window:
|
|
60
|
+
*
|
|
61
|
+
* 1. **Operator-side** (recommended): block egress to RFC1918 /
|
|
62
|
+
* loopback / link-local at the VPC / firewall layer. This neutralises
|
|
63
|
+
* the rebinding even if the application is naïve.
|
|
64
|
+
* 2. **Caller-side, Node only**: install `undici` and pass a custom
|
|
65
|
+
* `fetch` that wires a dispatcher with a pinned-IP `connect.lookup`,
|
|
66
|
+
* e.g.
|
|
67
|
+
* ```ts
|
|
68
|
+
* import { Agent, fetch as undiciFetch } from "undici";
|
|
69
|
+
* import * as dns from "node:dns/promises";
|
|
70
|
+
* const safeFetch = fetchGuard({
|
|
71
|
+
* fetch: async (input, init) => {
|
|
72
|
+
* const url = new URL(typeof input === "string" ? input : input.url);
|
|
73
|
+
* const { address, family } = await dns.lookup(url.hostname, { verbatim: true });
|
|
74
|
+
* const dispatcher = new Agent({
|
|
75
|
+
* connect: { lookup: (_h, _o, cb) => cb(null, address, family) },
|
|
76
|
+
* });
|
|
77
|
+
* return undiciFetch(input, { ...init, dispatcher });
|
|
78
|
+
* },
|
|
79
|
+
* });
|
|
80
|
+
* ```
|
|
81
|
+
* The pre-resolved IP is what the socket connects to; TLS SNI /
|
|
82
|
+
* cert validation still uses the original hostname.
|
|
83
|
+
*
|
|
39
84
|
* @since 0.34.0
|
|
40
85
|
* @module
|
|
41
86
|
*/
|
|
@@ -65,6 +110,9 @@ export class SsrfBlockedError extends Error {
|
|
|
65
110
|
const ALWAYS_DENY = [
|
|
66
111
|
"0.0.0.0/8", // "this network"
|
|
67
112
|
"100.64.0.0/10", // CGNAT (Alibaba metadata 100.100.100.200)
|
|
113
|
+
"169.254.169.254/32", // AWS / Azure / DigitalOcean / GCP IMDS — hard floor
|
|
114
|
+
"169.254.170.2/32", // AWS ECS task metadata v2 / EKS Pod Identity
|
|
115
|
+
"169.254.170.23/32", // AWS EKS Pod Identity (IPv4)
|
|
68
116
|
"192.0.0.0/24", // IANA reserved (Oracle metadata 192.0.0.192)
|
|
69
117
|
"192.0.2.0/24", // TEST-NET-1
|
|
70
118
|
"198.18.0.0/15", // benchmarking
|
|
@@ -74,6 +122,7 @@ const ALWAYS_DENY = [
|
|
|
74
122
|
"240.0.0.0/4", // reserved (includes 255.255.255.255)
|
|
75
123
|
"::/128", // unspecified
|
|
76
124
|
"ff00::/8", // IPv6 multicast
|
|
125
|
+
"fd00:ec2::254/128", // AWS IMDSv2 IPv6
|
|
77
126
|
];
|
|
78
127
|
const LOOPBACK = ["127.0.0.0/8", "::1/128"];
|
|
79
128
|
const LINK_LOCAL = ["169.254.0.0/16", "fe80::/10"];
|
|
@@ -107,7 +156,17 @@ const UNIQUE_LOCAL = ["fc00::/7"];
|
|
|
107
156
|
*/
|
|
108
157
|
export function fetchGuard(options = {}) {
|
|
109
158
|
const allowProtocols = new Set((options.allowProtocols ?? ["http:", "https:"]).map((s) => s.toLowerCase()));
|
|
110
|
-
|
|
159
|
+
// Hard-deny floor: ALWAYS_DENY (cloud metadata + reserved) plus any
|
|
160
|
+
// user-supplied `denyAddresses`. No allow flag, including
|
|
161
|
+
// `allowAddresses`, can lift these — this is what keeps a misconfigured
|
|
162
|
+
// egress allow-list from accidentally re-exposing 169.254.169.254 or
|
|
163
|
+
// an operator-pinned internal range.
|
|
164
|
+
const hardDenyMatchers = [];
|
|
165
|
+
// Soft-deny class defaults: loopback / private / link-local /
|
|
166
|
+
// unique-local. These reflect "off by default" classes that the
|
|
167
|
+
// matching `allow*` flag — or an explicit `allowAddresses` range —
|
|
168
|
+
// is allowed to opt into.
|
|
169
|
+
const softDenyMatchers = [];
|
|
111
170
|
const allowMatchers = [];
|
|
112
171
|
const allowHosts = new Set((options.allowHosts ?? []).map((h) => h.toLowerCase()));
|
|
113
172
|
const maxRedirects = options.maxRedirects ?? 5;
|
|
@@ -117,28 +176,35 @@ export function fetchGuard(options = {}) {
|
|
|
117
176
|
}
|
|
118
177
|
const resolveFn = options.resolve ?? createDefaultResolver();
|
|
119
178
|
for (const c of ALWAYS_DENY)
|
|
120
|
-
|
|
121
|
-
|
|
179
|
+
hardDenyMatchers.push(compileCidrMatcher(c));
|
|
180
|
+
for (const c of options.denyAddresses ?? [])
|
|
181
|
+
hardDenyMatchers.push(compileCidrMatcher(c));
|
|
182
|
+
if (!options.allowLoopback) {
|
|
122
183
|
for (const c of LOOPBACK)
|
|
123
|
-
|
|
124
|
-
|
|
184
|
+
softDenyMatchers.push(compileCidrMatcher(c));
|
|
185
|
+
}
|
|
186
|
+
if (!options.allowPrivate) {
|
|
125
187
|
for (const c of PRIVATE)
|
|
126
|
-
|
|
127
|
-
|
|
188
|
+
softDenyMatchers.push(compileCidrMatcher(c));
|
|
189
|
+
}
|
|
190
|
+
if (!options.allowLinkLocal) {
|
|
128
191
|
for (const c of LINK_LOCAL)
|
|
129
|
-
|
|
192
|
+
softDenyMatchers.push(compileCidrMatcher(c));
|
|
193
|
+
}
|
|
130
194
|
if (!options.allowUniqueLocal) {
|
|
131
195
|
for (const c of UNIQUE_LOCAL)
|
|
132
|
-
|
|
196
|
+
softDenyMatchers.push(compileCidrMatcher(c));
|
|
133
197
|
}
|
|
134
|
-
for (const c of options.denyAddresses ?? [])
|
|
135
|
-
denyMatchers.push(compileCidrMatcher(c));
|
|
136
198
|
for (const c of options.allowAddresses ?? [])
|
|
137
199
|
allowMatchers.push(compileCidrMatcher(c));
|
|
138
200
|
function isAddressAllowed(parsed) {
|
|
201
|
+
// Hard-deny wins over every allow knob — cloud metadata IPs and
|
|
202
|
+
// operator-pinned `denyAddresses` are non-negotiable.
|
|
203
|
+
if (hardDenyMatchers.some((m) => matchesMatcher(parsed, m)))
|
|
204
|
+
return false;
|
|
139
205
|
if (allowMatchers.some((m) => matchesMatcher(parsed, m)))
|
|
140
206
|
return true;
|
|
141
|
-
return !
|
|
207
|
+
return !softDenyMatchers.some((m) => matchesMatcher(parsed, m));
|
|
142
208
|
}
|
|
143
209
|
async function validateUrl(url) {
|
|
144
210
|
const proto = url.protocol.toLowerCase();
|
|
@@ -262,4 +328,3 @@ function createDefaultResolver() {
|
|
|
262
328
|
return results.map((r) => r.address);
|
|
263
329
|
};
|
|
264
330
|
}
|
|
265
|
-
//# sourceMappingURL=fetch-guard.js.map
|
package/dist/hashing.d.ts
CHANGED
package/dist/hashing.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -15,9 +15,9 @@ export { HttpError, BadRequestError, ValidationError, NotFoundError, Unauthorize
|
|
|
15
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, 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";
|
|
18
|
+
export { readBodyLimited, safeJsonParse, isForbiddenObjectKey, sanitizeHeaderName, sanitizeHeaderValue, timingSafeEqual, randomId, assertNoDuplicateSingletonHeaders, assertNoReservedInternalHeaders, RESERVED_INBOUND_HEADER_PREFIXES, SMUGGLING_SINGLETON_HEADERS, verifyWebhookSignature, signWebhookPayload, WEBHOOK_DEFAULT_TOLERANCE_SECONDS, assertStrongSecret, MIN_PROD_SECRET_BYTES, WEAK_SECRET_STRINGS, sanitizeFilename, assertSafeRelativePath, hasMongoOperatorKeys, assertNoMongoOperators, } from "./security.js";
|
|
19
19
|
export type { WebhookHmacAlgorithm } from "./security.js";
|
|
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";
|
|
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, fetchMetadata, requireScopes, REQUIRE_SCOPES_AGGREGATE_KEY, REQUIRE_SCOPES_HOOK_MARKER, _resetSharedRateLimitStoresForTests, } from "./middleware.js";
|
|
21
21
|
export { etag } from "./etag.js";
|
|
22
22
|
export type { ETagOptions } from "./etag.js";
|
|
23
23
|
export { compression, COMPRESSION_HOOK_MARKER, _resetCompressionRuntimeProbeForTests, } from "./compression.js";
|
|
@@ -36,11 +36,13 @@ export { ipRestriction } from "./ip-restriction.js";
|
|
|
36
36
|
export type { IpRestrictionOptions } from "./ip-restriction.js";
|
|
37
37
|
export { fetchGuard, SsrfBlockedError } from "./fetch-guard.js";
|
|
38
38
|
export type { FetchGuardOptions, SsrfBlockReason } from "./fetch-guard.js";
|
|
39
|
+
export { safeRedirect, OpenRedirectBlockedError } from "./safe-redirect.js";
|
|
40
|
+
export type { SafeRedirectOptions, SafeRedirectStatus, SafeRedirectBlockReason, } from "./safe-redirect.js";
|
|
39
41
|
export { loadShedding, LOAD_SHEDDING_MARKER } from "./load-shedding.js";
|
|
40
42
|
export type { LoadSheddingOptions, LoadSheddingSnapshot, } from "./load-shedding.js";
|
|
41
43
|
export { defineConfig, ConfigValidationError } from "./config.js";
|
|
42
44
|
export type { ConfigSource, DefineConfigOptions, } from "./config.js";
|
|
43
|
-
export type { RequestIdOptions, SecureHeadersOptions, CspDirectivesOptions, CorsOptions, CorsOriginAllow, RateLimitOptions, RateLimitStore, LoginThrottleOptions, CsrfOptions, CsrfCookieOptions, BasicAuthOptions, } from "./middleware.js";
|
|
45
|
+
export type { RequestIdOptions, SecureHeadersOptions, CspDirectivesOptions, CorsOptions, CorsOriginAllow, RateLimitOptions, RateLimitStore, LoginThrottleOptions, CsrfOptions, CsrfCookieOptions, FetchMetadataOptions, BasicAuthOptions, } from "./middleware.js";
|
|
44
46
|
export type { BearerAuthOptions, BearerAuthVerifyHook } from "./middleware.js";
|
|
45
47
|
export { createLogger, noopLogger, DEFAULT_REDACT_KEYS } from "./logger.js";
|
|
46
48
|
export type { Logger, LogLevel, ConsoleLoggerOptions, LoggerRedactionOptions, } from "./logger.js";
|
|
@@ -61,4 +63,3 @@ export { otelTracing, TRACING_SPAN_KIND_SERVER, TRACING_SPAN_STATUS_UNSET, TRACI
|
|
|
61
63
|
export type { OtelTracingOptions, TracingAttributes, TracingAttributeValue, TracingSpan, TracingStartSpanOptions, TracingTracer, } from "./tracing.js";
|
|
62
64
|
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";
|
|
63
65
|
export type { WebSocketConnection, WebSocketContext, WebSocketHandler, WebSocketRouteEntry, NormalizedWebSocketOptions, WebSocketBeforeUpgrade, HandshakeResult, ParsedFrame, MessageEvent as WebSocketMessageEvent, FrameSinkEvents, } from "./websocket.js";
|
|
64
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -8,8 +8,8 @@ export { subdomains, PSL_SNAPSHOT_DATE, PSL_PUBLIC_SUFFIXES, MAX_SNAPSHOT_AGE_DA
|
|
|
8
8
|
export { defineDependency, DEPENDENCY_MARKER } from "./dependency.js";
|
|
9
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, 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
|
-
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";
|
|
11
|
+
export { readBodyLimited, safeJsonParse, isForbiddenObjectKey, sanitizeHeaderName, sanitizeHeaderValue, timingSafeEqual, randomId, assertNoDuplicateSingletonHeaders, assertNoReservedInternalHeaders, RESERVED_INBOUND_HEADER_PREFIXES, SMUGGLING_SINGLETON_HEADERS, verifyWebhookSignature, signWebhookPayload, WEBHOOK_DEFAULT_TOLERANCE_SECONDS, assertStrongSecret, MIN_PROD_SECRET_BYTES, WEAK_SECRET_STRINGS, sanitizeFilename, assertSafeRelativePath, hasMongoOperatorKeys, assertNoMongoOperators, } from "./security.js";
|
|
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, fetchMetadata, 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";
|
|
15
15
|
export { createJwtSigner, createJwtVerifier, JwtError, DEFAULT_JWT_MAX_LIFETIME_SECONDS, } from "./jwt.js";
|
|
@@ -19,6 +19,7 @@ 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
21
|
export { fetchGuard, SsrfBlockedError } from "./fetch-guard.js";
|
|
22
|
+
export { safeRedirect, OpenRedirectBlockedError } from "./safe-redirect.js";
|
|
22
23
|
export { loadShedding, LOAD_SHEDDING_MARKER } from "./load-shedding.js";
|
|
23
24
|
export { defineConfig, ConfigValidationError } from "./config.js";
|
|
24
25
|
export { createLogger, noopLogger, DEFAULT_REDACT_KEYS } from "./logger.js";
|
|
@@ -30,4 +31,3 @@ export { session, rotateSession, signValue, verifySignedValue, MemorySessionStor
|
|
|
30
31
|
export { fileField, multipartObject, isFileFieldSchema, isMultipartObjectSchema, } from "./multipart.js";
|
|
31
32
|
export { otelTracing, TRACING_SPAN_KIND_SERVER, TRACING_SPAN_STATUS_UNSET, TRACING_SPAN_STATUS_OK, TRACING_SPAN_STATUS_ERROR, } from "./tracing.js";
|
|
32
33
|
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";
|
|
33
|
-
//# sourceMappingURL=index.js.map
|
package/dist/ip-restriction.d.ts
CHANGED
|
@@ -89,4 +89,3 @@ export declare function matchesMatcher(ip: ParsedIp, m: IpMatcher): boolean;
|
|
|
89
89
|
export declare function compileCidrMatcher(input: string): IpMatcher;
|
|
90
90
|
/** @internal */
|
|
91
91
|
export declare function parseIp(input: string): ParsedIp | undefined;
|
|
92
|
-
//# sourceMappingURL=ip-restriction.d.ts.map
|