@beignet/core 0.0.46 → 0.0.47
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/CHANGELOG.md +6 -0
- package/README.md +39 -22
- package/dist/server/context.d.ts +7 -0
- package/dist/server/context.d.ts.map +1 -1
- package/dist/server/context.js.map +1 -1
- package/dist/server/hooks/logging.d.ts +3 -0
- package/dist/server/hooks/logging.d.ts.map +1 -1
- package/dist/server/hooks/logging.js +18 -7
- package/dist/server/hooks/logging.js.map +1 -1
- package/dist/server/hooks/rate-limit.d.ts +7 -7
- package/dist/server/hooks/rate-limit.d.ts.map +1 -1
- package/dist/server/hooks/rate-limit.js +15 -9
- package/dist/server/hooks/rate-limit.js.map +1 -1
- package/dist/server/hooks/security.d.ts +4 -3
- package/dist/server/hooks/security.d.ts.map +1 -1
- package/dist/server/hooks/security.js +5 -3
- package/dist/server/hooks/security.js.map +1 -1
- package/dist/server/http.d.ts +12 -0
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/request-executor.d.ts +5 -2
- package/dist/server/request-executor.d.ts.map +1 -1
- package/dist/server/request-executor.js +21 -2
- package/dist/server/request-executor.js.map +1 -1
- package/dist/server/server-context.d.ts +2 -1
- package/dist/server/server-context.d.ts.map +1 -1
- package/dist/server/server-context.js +2 -1
- package/dist/server/server-context.js.map +1 -1
- package/dist/server/server.d.ts +9 -0
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +14 -2
- package/dist/server/server.js.map +1 -1
- package/dist/server/trusted-proxy-internal.d.ts +4 -0
- package/dist/server/trusted-proxy-internal.d.ts.map +1 -0
- package/dist/server/trusted-proxy-internal.js +27 -0
- package/dist/server/trusted-proxy-internal.js.map +1 -0
- package/dist/server/trusted-proxy.d.ts +11 -6
- package/dist/server/trusted-proxy.d.ts.map +1 -1
- package/dist/server/trusted-proxy.js +6 -10
- package/dist/server/trusted-proxy.js.map +1 -1
- package/package.json +1 -1
- package/skills/app-architecture/SKILL.md +5 -2
- package/src/server/context.ts +7 -0
- package/src/server/hooks/logging.ts +35 -7
- package/src/server/hooks/rate-limit.ts +25 -15
- package/src/server/hooks/security.ts +11 -7
- package/src/server/http.ts +18 -1
- package/src/server/request-executor.ts +43 -2
- package/src/server/server-context.ts +2 -1
- package/src/server/server.ts +30 -1
- package/src/server/trusted-proxy-internal.ts +41 -0
- package/src/server/trusted-proxy.ts +20 -17
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { TrustedProxyConfig } from "./trusted-proxy.js";
|
|
2
|
+
|
|
3
|
+
export function requireTrustedProxyHeaderName(
|
|
4
|
+
name: string,
|
|
5
|
+
optionName: string,
|
|
6
|
+
): string {
|
|
7
|
+
const header = name.trim();
|
|
8
|
+
if (!header) {
|
|
9
|
+
throw new Error(`${optionName} must be a non-empty header name.`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
new Headers().get(header);
|
|
14
|
+
} catch {
|
|
15
|
+
throw new Error(`${optionName} must be a valid HTTP header name.`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return header;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function assertValidTrustedProxyConfig(
|
|
22
|
+
config: TrustedProxyConfig,
|
|
23
|
+
): void {
|
|
24
|
+
if (!config) return;
|
|
25
|
+
|
|
26
|
+
if (config.hostHeader !== undefined && config.hostHeader !== false) {
|
|
27
|
+
requireTrustedProxyHeaderName(config.hostHeader, "trustedProxy.hostHeader");
|
|
28
|
+
}
|
|
29
|
+
if (config.protocolHeader !== undefined && config.protocolHeader !== false) {
|
|
30
|
+
requireTrustedProxyHeaderName(
|
|
31
|
+
config.protocolHeader,
|
|
32
|
+
"trustedProxy.protocolHeader",
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
if (typeof config.clientIp === "object") {
|
|
36
|
+
requireTrustedProxyHeaderName(
|
|
37
|
+
config.clientIp.header,
|
|
38
|
+
"trustedProxy.clientIp.header",
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { HttpRequestLike } from "./http.js";
|
|
2
|
+
import { requireTrustedProxyHeaderName } from "./trusted-proxy-internal.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Header source used to resolve a client IP after an app has explicitly opted
|
|
@@ -51,27 +52,32 @@ export interface TrustedRequestInfo {
|
|
|
51
52
|
/**
|
|
52
53
|
* URL as seen by the app or reconstructed from trusted proxy headers.
|
|
53
54
|
*/
|
|
54
|
-
url: URL
|
|
55
|
+
readonly url: Readonly<URL>;
|
|
55
56
|
/**
|
|
56
57
|
* External request origin.
|
|
57
58
|
*/
|
|
58
|
-
origin: string;
|
|
59
|
+
readonly origin: string;
|
|
59
60
|
/**
|
|
60
61
|
* External request protocol without a trailing colon.
|
|
61
62
|
*/
|
|
62
|
-
protocol: "http" | "https";
|
|
63
|
+
readonly protocol: "http" | "https";
|
|
63
64
|
/**
|
|
64
65
|
* External request host, including port when present.
|
|
65
66
|
*/
|
|
66
|
-
host: string;
|
|
67
|
+
readonly host: string;
|
|
67
68
|
/**
|
|
68
69
|
* Resolved client IP when a trusted client-IP source is configured.
|
|
69
70
|
*/
|
|
70
|
-
clientIp?: string;
|
|
71
|
+
readonly clientIp?: string;
|
|
72
|
+
/**
|
|
73
|
+
* Whether the server policy configured a trusted client-IP source. This can
|
|
74
|
+
* be true while `clientIp` is absent when the expected header is missing.
|
|
75
|
+
*/
|
|
76
|
+
readonly clientIpTrusted: boolean;
|
|
71
77
|
/**
|
|
72
78
|
* Whether forwarding headers were eligible to affect this result.
|
|
73
79
|
*/
|
|
74
|
-
trustedProxy: boolean;
|
|
80
|
+
readonly trustedProxy: boolean;
|
|
75
81
|
}
|
|
76
82
|
|
|
77
83
|
const DEFAULT_PROTOCOL_HEADER = "x-forwarded-proto";
|
|
@@ -92,14 +98,6 @@ function firstHeaderValue(
|
|
|
92
98
|
return splitForwardedHeader(req.headers.get(header))[0];
|
|
93
99
|
}
|
|
94
100
|
|
|
95
|
-
function requireHeaderName(name: string, optionName: string): string {
|
|
96
|
-
const header = name.trim();
|
|
97
|
-
if (!header) {
|
|
98
|
-
throw new Error(`${optionName} must be a non-empty header name.`);
|
|
99
|
-
}
|
|
100
|
-
return header;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
101
|
function normalizeProtocol(
|
|
104
102
|
value: string | undefined,
|
|
105
103
|
): "http" | "https" | undefined {
|
|
@@ -172,7 +170,10 @@ export function resolveTrustedClientIp(
|
|
|
172
170
|
if (typeof source === "object") {
|
|
173
171
|
return firstHeaderValue(
|
|
174
172
|
req,
|
|
175
|
-
|
|
173
|
+
requireTrustedProxyHeaderName(
|
|
174
|
+
source.header,
|
|
175
|
+
"trustedProxy.clientIp.header",
|
|
176
|
+
),
|
|
176
177
|
);
|
|
177
178
|
}
|
|
178
179
|
|
|
@@ -205,6 +206,7 @@ export function resolveTrustedRequest(
|
|
|
205
206
|
origin: baseUrl.origin,
|
|
206
207
|
protocol: baseProtocol,
|
|
207
208
|
host: baseHost,
|
|
209
|
+
clientIpTrusted: false,
|
|
208
210
|
trustedProxy: false,
|
|
209
211
|
};
|
|
210
212
|
}
|
|
@@ -212,14 +214,14 @@ export function resolveTrustedRequest(
|
|
|
212
214
|
const protocolHeader =
|
|
213
215
|
config.protocolHeader === false
|
|
214
216
|
? undefined
|
|
215
|
-
:
|
|
217
|
+
: requireTrustedProxyHeaderName(
|
|
216
218
|
config.protocolHeader ?? DEFAULT_PROTOCOL_HEADER,
|
|
217
219
|
"trustedProxy.protocolHeader",
|
|
218
220
|
);
|
|
219
221
|
const hostHeader =
|
|
220
222
|
config.hostHeader === false
|
|
221
223
|
? undefined
|
|
222
|
-
:
|
|
224
|
+
: requireTrustedProxyHeaderName(
|
|
223
225
|
config.hostHeader ?? DEFAULT_HOST_HEADER,
|
|
224
226
|
"trustedProxy.hostHeader",
|
|
225
227
|
);
|
|
@@ -244,6 +246,7 @@ export function resolveTrustedRequest(
|
|
|
244
246
|
protocol,
|
|
245
247
|
host,
|
|
246
248
|
...(clientIp !== undefined ? { clientIp } : {}),
|
|
249
|
+
clientIpTrusted: Boolean(config.clientIp),
|
|
247
250
|
trustedProxy: true,
|
|
248
251
|
};
|
|
249
252
|
}
|