edgeaegis 2026.10.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/LICENSE +202 -0
- package/NOTICE +10 -0
- package/README.md +215 -0
- package/config.yml +29 -0
- package/origin/cloudflare/app/config.yml +2 -0
- package/origin/cloudflare/app/index.js +4 -0
- package/origin/edgeone/app/config.yml +2 -0
- package/origin/edgeone/app/index.js +4 -0
- package/origin/esa/app/config.yml +2 -0
- package/origin/esa/app/index.js +4 -0
- package/origin/netlify/app/config.yml +2 -0
- package/origin/netlify/app/index.js +4 -0
- package/origin/vercel/app/config.yml +2 -0
- package/origin/vercel/app/index.js +4 -0
- package/package.json +123 -0
- package/respond/403.html +2 -0
- package/respond/403.json +1 -0
- package/rules/allowlist.yml +2 -0
- package/rules/emergency.conf +4 -0
- package/rules/local.conf +2 -0
- package/rules/seclang-bundle.json +360 -0
- package/rules/seclang-upstreams.json +14 -0
- package/rules/setup.conf +15 -0
- package/secret/credentials.example.yml +7 -0
- package/secret/relay-server.example.yml +10 -0
- package/tools/.build/scr/adapters/cloudflare/runtime.d.ts +18 -0
- package/tools/.build/scr/adapters/cloudflare/runtime.js +16 -0
- package/tools/.build/scr/adapters/cloudflare/runtime.js.map +1 -0
- package/tools/.build/scr/adapters/cloudflare/worker.js +25 -0
- package/tools/.build/scr/adapters/edgeone/worker.js +7 -0
- package/tools/.build/scr/adapters/esa/worker.js +5 -0
- package/tools/.build/scr/adapters/forward.d.ts +4 -0
- package/tools/.build/scr/adapters/forward.js +25 -0
- package/tools/.build/scr/adapters/forward.js.map +1 -0
- package/tools/.build/scr/adapters/handler.js +39 -0
- package/tools/.build/scr/adapters/ingress.d.ts +10 -0
- package/tools/.build/scr/adapters/ingress.js +62 -0
- package/tools/.build/scr/adapters/ingress.js.map +1 -0
- package/tools/.build/scr/adapters/netlify/worker.js +7 -0
- package/tools/.build/scr/adapters/runtime.d.ts +33 -0
- package/tools/.build/scr/adapters/runtime.js +50 -0
- package/tools/.build/scr/adapters/runtime.js.map +1 -0
- package/tools/.build/scr/adapters/vercel/worker.js +7 -0
- package/tools/.build/scr/cli/config.d.ts +2 -0
- package/tools/.build/scr/cli/config.js +23 -0
- package/tools/.build/scr/cli/config.js.map +1 -0
- package/tools/.build/scr/cli/deployment.d.ts +15 -0
- package/tools/.build/scr/cli/deployment.js +108 -0
- package/tools/.build/scr/cli/deployment.js.map +1 -0
- package/tools/.build/scr/cli/init.d.ts +2 -0
- package/tools/.build/scr/cli/init.js +62 -0
- package/tools/.build/scr/cli/init.js.map +1 -0
- package/tools/.build/scr/cli/main.d.ts +2 -0
- package/tools/.build/scr/cli/main.js +99 -0
- package/tools/.build/scr/cli/main.js.map +1 -0
- package/tools/.build/scr/cli/relay-serve.d.ts +1 -0
- package/tools/.build/scr/cli/relay-serve.js +48 -0
- package/tools/.build/scr/cli/relay-serve.js.map +1 -0
- package/tools/.build/scr/cli/responses.d.ts +2 -0
- package/tools/.build/scr/cli/responses.js +31 -0
- package/tools/.build/scr/cli/responses.js.map +1 -0
- package/tools/.build/scr/cli/serve.d.ts +1 -0
- package/tools/.build/scr/cli/serve.js +132 -0
- package/tools/.build/scr/cli/serve.js.map +1 -0
- package/tools/.build/scr/config.d.ts +39 -0
- package/tools/.build/scr/config.js +89 -0
- package/tools/.build/scr/config.js.map +1 -0
- package/tools/.build/scr/core/types.d.ts +27 -0
- package/tools/.build/scr/core/types.js +34 -0
- package/tools/.build/scr/core/types.js.map +1 -0
- package/tools/.build/scr/core/version.d.ts +1 -0
- package/tools/.build/scr/core/version.js +3 -0
- package/tools/.build/scr/core/version.js.map +1 -0
- package/tools/.build/scr/http-boundary/index.d.ts +19 -0
- package/tools/.build/scr/http-boundary/index.js +173 -0
- package/tools/.build/scr/http-boundary/index.js.map +1 -0
- package/tools/.build/scr/http-boundary/json.d.ts +2 -0
- package/tools/.build/scr/http-boundary/json.js +90 -0
- package/tools/.build/scr/http-boundary/json.js.map +1 -0
- package/tools/.build/scr/origin/relay.d.ts +20 -0
- package/tools/.build/scr/origin/relay.js +221 -0
- package/tools/.build/scr/origin/relay.js.map +1 -0
- package/tools/.build/scr/origin/replay-node.d.ts +8 -0
- package/tools/.build/scr/origin/replay-node.js +36 -0
- package/tools/.build/scr/origin/replay-node.js.map +1 -0
- package/tools/.build/scr/origin/types.d.ts +18 -0
- package/tools/.build/scr/origin/types.js +2 -0
- package/tools/.build/scr/origin/types.js.map +1 -0
- package/tools/.build/scr/runtime/allowlist.d.ts +21 -0
- package/tools/.build/scr/runtime/allowlist.js +84 -0
- package/tools/.build/scr/runtime/allowlist.js.map +1 -0
- package/tools/.build/scr/runtime/browser-cache.d.ts +7 -0
- package/tools/.build/scr/runtime/browser-cache.js +50 -0
- package/tools/.build/scr/runtime/browser-cache.js.map +1 -0
- package/tools/.build/scr/runtime/error-pages.d.ts +10 -0
- package/tools/.build/scr/runtime/error-pages.js +72 -0
- package/tools/.build/scr/runtime/error-pages.js.map +1 -0
- package/tools/.build/scr/runtime/index.d.ts +54 -0
- package/tools/.build/scr/runtime/index.js +355 -0
- package/tools/.build/scr/runtime/index.js.map +1 -0
- package/tools/.build/scr/runtime/node.d.ts +3 -0
- package/tools/.build/scr/runtime/node.js +97 -0
- package/tools/.build/scr/runtime/node.js.map +1 -0
- package/tools/.build/scr/runtime/proxy.d.ts +12 -0
- package/tools/.build/scr/runtime/proxy.js +177 -0
- package/tools/.build/scr/runtime/proxy.js.map +1 -0
- package/tools/.build/scr/runtime/stream.d.ts +8 -0
- package/tools/.build/scr/runtime/stream.js +72 -0
- package/tools/.build/scr/runtime/stream.js.map +1 -0
- package/tools/.build/scr/seclang/body.d.ts +13 -0
- package/tools/.build/scr/seclang/body.js +109 -0
- package/tools/.build/scr/seclang/body.js.map +1 -0
- package/tools/.build/scr/seclang/bytes.d.ts +5 -0
- package/tools/.build/scr/seclang/bytes.js +38 -0
- package/tools/.build/scr/seclang/bytes.js.map +1 -0
- package/tools/.build/scr/seclang/index.d.ts +166 -0
- package/tools/.build/scr/seclang/index.js +1519 -0
- package/tools/.build/scr/seclang/index.js.map +1 -0
- package/tools/.build/scr/seclang/json.d.ts +2 -0
- package/tools/.build/scr/seclang/json.js +87 -0
- package/tools/.build/scr/seclang/json.js.map +1 -0
- package/tools/.build/scr/seclang/libinjection.d.ts +9 -0
- package/tools/.build/scr/seclang/libinjection.js +59 -0
- package/tools/.build/scr/seclang/libinjection.js.map +1 -0
- package/tools/.build/scr/seclang/node.d.ts +22 -0
- package/tools/.build/scr/seclang/node.js +113 -0
- package/tools/.build/scr/seclang/node.js.map +1 -0
- package/tools/.build/scr/seclang/pcre2.d.ts +23 -0
- package/tools/.build/scr/seclang/pcre2.js +153 -0
- package/tools/.build/scr/seclang/pcre2.js.map +1 -0
- package/tools/.build/scr/seclang/sources.d.ts +6 -0
- package/tools/.build/scr/seclang/sources.js +59 -0
- package/tools/.build/scr/seclang/sources.js.map +1 -0
- package/tools/.build/scr/seclang/state.d.ts +17 -0
- package/tools/.build/scr/seclang/state.js +53 -0
- package/tools/.build/scr/seclang/state.js.map +1 -0
- package/tools/.build/scr/seclang/syntax.d.ts +9 -0
- package/tools/.build/scr/seclang/syntax.js +74 -0
- package/tools/.build/scr/seclang/syntax.js.map +1 -0
- package/tools/.build/scr/seclang/transforms.d.ts +3 -0
- package/tools/.build/scr/seclang/transforms.js +157 -0
- package/tools/.build/scr/seclang/transforms.js.map +1 -0
- package/tools/.build/scr/seclang/unicode.d.ts +2 -0
- package/tools/.build/scr/seclang/unicode.js +19 -0
- package/tools/.build/scr/seclang/unicode.js.map +1 -0
- package/tools/.build/scr/seclang/vendor/LIBINJECTION-LICENSE +33 -0
- package/tools/.build/scr/seclang/vendor/PCRE2-NOTICE +47 -0
- package/tools/.build/scr/seclang/vendor/PCRE2-WRAPPER-LICENSE +21 -0
- package/tools/.build/scr/seclang/vendor/UNICODE-DATA-NOTICE +6 -0
- package/tools/.build/scr/seclang/vendor/libinjection.json +7 -0
- package/tools/.build/scr/seclang/vendor/libinjection.wasm +0 -0
- package/tools/.build/scr/seclang/vendor/pcre2.json +7 -0
- package/tools/.build/scr/seclang/vendor/pcre2.wasm +0 -0
- package/tools/.build/scr/seclang/vendor/unicode.json +378 -0
- package/tools/build-platform.mjs +199 -0
- package/tools/platform-command.mjs +59 -0
- package/tools/sync-native-seclang.mjs +155 -0
- package/tools/verify-full-crs.mjs +118 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SHIELD_VERSION = "2026.10.1";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../../scr/core/version.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,MAAM,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { parseStrictJson } from "./json.js";
|
|
2
|
+
export interface BoundaryLimits {
|
|
3
|
+
maxBodyBytes: number;
|
|
4
|
+
maxUrlBytes: number;
|
|
5
|
+
maxHeaderBytes: number;
|
|
6
|
+
maxHeaders: number;
|
|
7
|
+
bodyTimeoutMs: number;
|
|
8
|
+
}
|
|
9
|
+
export declare const defaultLimits: BoundaryLimits;
|
|
10
|
+
export declare function limitsWith(input?: Partial<BoundaryLimits>): BoundaryLimits;
|
|
11
|
+
/** Must run BEFORE constructing a URL/Request when the host exposes the original target. */
|
|
12
|
+
export declare function canonicalPath(target: string): string;
|
|
13
|
+
/** Raw framing inspection is available ONLY to the local Node adapter, not to Web Request. */
|
|
14
|
+
export declare function checkRawHeaders(raw: readonly string[]): void;
|
|
15
|
+
export declare function checkBoundary(request: Request, limits: BoundaryLimits, publicHosts: readonly string[], rawTarget?: string, mode?: "http" | "websocket"): {
|
|
16
|
+
url: URL;
|
|
17
|
+
path: string;
|
|
18
|
+
};
|
|
19
|
+
export declare function readBody(request: Request, limits: BoundaryLimits): Promise<Uint8Array>;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { requireInteger, ShieldError } from "../core/types.js";
|
|
2
|
+
export { parseStrictJson } from "./json.js";
|
|
3
|
+
export const defaultLimits = {
|
|
4
|
+
maxBodyBytes: 262144,
|
|
5
|
+
maxUrlBytes: 8192,
|
|
6
|
+
maxHeaderBytes: 16384,
|
|
7
|
+
maxHeaders: 64,
|
|
8
|
+
bodyTimeoutMs: 5000,
|
|
9
|
+
};
|
|
10
|
+
export function limitsWith(input = {}) {
|
|
11
|
+
const limits = { ...defaultLimits, ...input };
|
|
12
|
+
requireInteger(limits.maxBodyBytes, 0, 16_777_216, "maxBodyBytes");
|
|
13
|
+
requireInteger(limits.maxUrlBytes, 256, 65536, "maxUrlBytes");
|
|
14
|
+
requireInteger(limits.maxHeaderBytes, 256, 65536, "maxHeaderBytes");
|
|
15
|
+
requireInteger(limits.maxHeaders, 1, 256, "maxHeaders");
|
|
16
|
+
requireInteger(limits.bodyTimeoutMs, 1, 60000, "bodyTimeoutMs");
|
|
17
|
+
return limits;
|
|
18
|
+
}
|
|
19
|
+
/** Must run BEFORE constructing a URL/Request when the host exposes the original target. */
|
|
20
|
+
export function canonicalPath(target) {
|
|
21
|
+
const path = target.split("?", 1)[0] ?? "";
|
|
22
|
+
if (!path.startsWith("/") || path.startsWith("//") || /[\\;#\u0000-\u0020\u007f]/.test(path))
|
|
23
|
+
throw new ShieldError("ambiguous-path");
|
|
24
|
+
if (/%(?:2f|5c|25|2e|00|3f|23|3b)/i.test(path))
|
|
25
|
+
throw new ShieldError("ambiguous-path-encoding");
|
|
26
|
+
let decoded;
|
|
27
|
+
try {
|
|
28
|
+
decoded = decodeURIComponent(path);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
throw new ShieldError("invalid-path-encoding");
|
|
32
|
+
}
|
|
33
|
+
if (decoded.includes("//") ||
|
|
34
|
+
/(?:^|\/)\.{1,2}(?:\/|$)/.test(decoded) ||
|
|
35
|
+
/[\\;#?\u0000-\u0020\u007f]/.test(decoded) ||
|
|
36
|
+
decoded !== decoded.normalize("NFC"))
|
|
37
|
+
throw new ShieldError("ambiguous-path");
|
|
38
|
+
return decoded;
|
|
39
|
+
}
|
|
40
|
+
/** Raw framing inspection is available ONLY to the local Node adapter, not to Web Request. */
|
|
41
|
+
export function checkRawHeaders(raw) {
|
|
42
|
+
if (raw.length > 128)
|
|
43
|
+
throw new ShieldError("too-many-raw-headers", 431);
|
|
44
|
+
const seen = new Set();
|
|
45
|
+
for (let i = 0; i < raw.length; i += 2) {
|
|
46
|
+
const name = (raw[i] ?? "").toLowerCase();
|
|
47
|
+
const value = raw[i + 1] ?? "";
|
|
48
|
+
if (!/^[!#$%&'*+.^_`|~0-9a-z-]+$/.test(name) ||
|
|
49
|
+
/[\u0000-\u0008\u000a-\u001f\u007f]/.test(value))
|
|
50
|
+
throw new ShieldError("invalid-raw-header");
|
|
51
|
+
if (seen.has(name) &&
|
|
52
|
+
["host", "content-length", "transfer-encoding", "authorization"].includes(name))
|
|
53
|
+
throw new ShieldError("duplicate-security-header");
|
|
54
|
+
seen.add(name);
|
|
55
|
+
}
|
|
56
|
+
if (seen.has("content-length") && seen.has("transfer-encoding"))
|
|
57
|
+
throw new ShieldError("ambiguous-framing");
|
|
58
|
+
}
|
|
59
|
+
export function checkBoundary(request, limits, publicHosts, rawTarget, mode = "http") {
|
|
60
|
+
if (new TextEncoder().encode(request.url).length > limits.maxUrlBytes)
|
|
61
|
+
throw new ShieldError("url-too-large", 414);
|
|
62
|
+
const url = new URL(request.url);
|
|
63
|
+
if (!["https:", "http:"].includes(url.protocol) ||
|
|
64
|
+
url.username ||
|
|
65
|
+
url.password ||
|
|
66
|
+
!publicHosts.includes(url.host))
|
|
67
|
+
throw new ShieldError("untrusted-host", 421);
|
|
68
|
+
if (request.headers.has("host") && request.headers.get("host") !== url.host)
|
|
69
|
+
throw new ShieldError("host-mismatch", 421);
|
|
70
|
+
if (rawTarget !== undefined)
|
|
71
|
+
canonicalPath(rawTarget);
|
|
72
|
+
const path = canonicalPath(url.pathname);
|
|
73
|
+
try {
|
|
74
|
+
decodeURIComponent(url.search);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
throw new ShieldError("invalid-query-encoding");
|
|
78
|
+
}
|
|
79
|
+
if ([...url.searchParams].length > 128)
|
|
80
|
+
throw new ShieldError("too-many-query-fields");
|
|
81
|
+
let headerBytes = 0;
|
|
82
|
+
let headerCount = 0;
|
|
83
|
+
for (const [name, value] of request.headers) {
|
|
84
|
+
headerCount++;
|
|
85
|
+
headerBytes += new TextEncoder().encode(name + value).length + 4;
|
|
86
|
+
if (/[\u0000-\u0008\u000a-\u001f\u007f]/.test(value))
|
|
87
|
+
throw new ShieldError("invalid-header");
|
|
88
|
+
}
|
|
89
|
+
if (headerBytes > limits.maxHeaderBytes || headerCount > limits.maxHeaders)
|
|
90
|
+
throw new ShieldError("headers-too-large", 431);
|
|
91
|
+
const cl = request.headers.get("content-length");
|
|
92
|
+
const te = request.headers.get("transfer-encoding");
|
|
93
|
+
if (request.headers.has("expect") || request.headers.has("trailer"))
|
|
94
|
+
throw new ShieldError("unsupported-expect-or-trailers", 417);
|
|
95
|
+
if (["GET", "HEAD"].includes(request.method) && (te !== null || Number(cl ?? "0") > 0))
|
|
96
|
+
throw new ShieldError("body-not-allowed-for-method");
|
|
97
|
+
if (te && (cl !== null || te.toLowerCase() !== "chunked"))
|
|
98
|
+
throw new ShieldError("ambiguous-framing");
|
|
99
|
+
if (cl !== null && (!/^(0|[1-9][0-9]*)$/.test(cl) || !Number.isSafeInteger(Number(cl))))
|
|
100
|
+
throw new ShieldError("invalid-content-length");
|
|
101
|
+
if (cl !== null && Number(cl) > limits.maxBodyBytes)
|
|
102
|
+
throw new ShieldError("body-too-large", 413);
|
|
103
|
+
const connection = request.headers.get("connection");
|
|
104
|
+
if (connection
|
|
105
|
+
?.split(",")
|
|
106
|
+
.some((s) => !["close", "keep-alive", ...(mode === "websocket" ? ["upgrade"] : [])].includes(s.trim().toLowerCase())))
|
|
107
|
+
throw new ShieldError("unsafe-connection-header");
|
|
108
|
+
if ((request.headers.has("upgrade") && mode !== "websocket") ||
|
|
109
|
+
request.method === "CONNECT" ||
|
|
110
|
+
request.method === "TRACE")
|
|
111
|
+
throw new ShieldError("unsupported-protocol", 405);
|
|
112
|
+
if (mode === "websocket" &&
|
|
113
|
+
(request.method !== "GET" ||
|
|
114
|
+
request.headers.get("upgrade")?.toLowerCase() !== "websocket" ||
|
|
115
|
+
request.headers.get("sec-websocket-version") !== "13" ||
|
|
116
|
+
!/^[A-Za-z0-9+/]{22}==$/.test(request.headers.get("sec-websocket-key") ?? "") ||
|
|
117
|
+
te !== null ||
|
|
118
|
+
Number(cl ?? "0") !== 0))
|
|
119
|
+
throw new ShieldError("invalid-websocket-handshake", 400);
|
|
120
|
+
if (request.headers.has("content-encoding") &&
|
|
121
|
+
request.headers.get("content-encoding") !== "identity")
|
|
122
|
+
throw new ShieldError("unsupported-content-encoding", 415);
|
|
123
|
+
return { url, path };
|
|
124
|
+
}
|
|
125
|
+
export async function readBody(request, limits) {
|
|
126
|
+
if (!request.body) {
|
|
127
|
+
if (Number(request.headers.get("content-length") ?? "0") !== 0)
|
|
128
|
+
throw new ShieldError("body-length-mismatch");
|
|
129
|
+
return new Uint8Array();
|
|
130
|
+
}
|
|
131
|
+
const reader = request.body.getReader();
|
|
132
|
+
let timer;
|
|
133
|
+
const chunks = [];
|
|
134
|
+
let size = 0;
|
|
135
|
+
try {
|
|
136
|
+
const timeout = new Promise((_, reject) => {
|
|
137
|
+
timer = setTimeout(() => reject(new ShieldError("body-timeout", 408)), limits.bodyTimeoutMs);
|
|
138
|
+
});
|
|
139
|
+
await Promise.race([
|
|
140
|
+
(async () => {
|
|
141
|
+
while (true) {
|
|
142
|
+
const item = await reader.read();
|
|
143
|
+
if (item.done)
|
|
144
|
+
break;
|
|
145
|
+
size += item.value.byteLength;
|
|
146
|
+
if (size > limits.maxBodyBytes)
|
|
147
|
+
throw new ShieldError("body-too-large", 413);
|
|
148
|
+
chunks.push(item.value.slice());
|
|
149
|
+
}
|
|
150
|
+
})(),
|
|
151
|
+
timeout,
|
|
152
|
+
]);
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
void reader.cancel().catch(() => { });
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
finally {
|
|
159
|
+
if (timer)
|
|
160
|
+
clearTimeout(timer);
|
|
161
|
+
}
|
|
162
|
+
const cl = request.headers.get("content-length");
|
|
163
|
+
if (cl !== null && Number(cl) !== size)
|
|
164
|
+
throw new ShieldError("body-length-mismatch");
|
|
165
|
+
const body = new Uint8Array(size);
|
|
166
|
+
let offset = 0;
|
|
167
|
+
for (const chunk of chunks) {
|
|
168
|
+
body.set(chunk, offset);
|
|
169
|
+
offset += chunk.byteLength;
|
|
170
|
+
}
|
|
171
|
+
return body;
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../scr/http-boundary/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { ShieldError } from "../core/types.js";
|
|
2
|
+
/** Reject parser differentials: duplicate object keys, non-finite numbers and excessive nesting. */
|
|
3
|
+
export function parseStrictJson(text) {
|
|
4
|
+
let offset = 0;
|
|
5
|
+
let nodes = 0;
|
|
6
|
+
const ws = () => {
|
|
7
|
+
while (/[\x20\t\r\n]/.test(text[offset] ?? "!"))
|
|
8
|
+
offset++;
|
|
9
|
+
};
|
|
10
|
+
const fail = () => {
|
|
11
|
+
throw new ShieldError("ambiguous-or-invalid-json");
|
|
12
|
+
};
|
|
13
|
+
function string() {
|
|
14
|
+
const start = offset;
|
|
15
|
+
if (text[offset++] !== '"')
|
|
16
|
+
return fail();
|
|
17
|
+
while (offset < text.length) {
|
|
18
|
+
const c = text[offset++];
|
|
19
|
+
if (c === '"') {
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(text.slice(start, offset));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return fail();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (c === "\\")
|
|
28
|
+
offset++;
|
|
29
|
+
}
|
|
30
|
+
return fail();
|
|
31
|
+
}
|
|
32
|
+
function value(depth) {
|
|
33
|
+
if (depth > 32 || ++nodes > 16384)
|
|
34
|
+
fail();
|
|
35
|
+
ws();
|
|
36
|
+
const c = text[offset];
|
|
37
|
+
if (c === '"') {
|
|
38
|
+
string();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (c === "{" || c === "[") {
|
|
42
|
+
const object = c === "{";
|
|
43
|
+
const close = object ? "}" : "]";
|
|
44
|
+
const keys = new Set();
|
|
45
|
+
offset++;
|
|
46
|
+
ws();
|
|
47
|
+
if (text[offset] === close) {
|
|
48
|
+
offset++;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
while (true) {
|
|
52
|
+
if (object) {
|
|
53
|
+
ws();
|
|
54
|
+
const key = string();
|
|
55
|
+
if (keys.has(key))
|
|
56
|
+
fail();
|
|
57
|
+
keys.add(key);
|
|
58
|
+
ws();
|
|
59
|
+
if (text[offset++] !== ":")
|
|
60
|
+
fail();
|
|
61
|
+
}
|
|
62
|
+
value(depth + 1);
|
|
63
|
+
ws();
|
|
64
|
+
if (text[offset] === close) {
|
|
65
|
+
offset++;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (text[offset++] !== ",")
|
|
69
|
+
fail();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const token = /^(?:true|false|null|-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?)/.exec(text.slice(offset))?.[0];
|
|
73
|
+
if (!token)
|
|
74
|
+
throw new ShieldError("ambiguous-or-invalid-json");
|
|
75
|
+
if (/^-?[0-9]/.test(token) && !Number.isFinite(Number(token)))
|
|
76
|
+
fail();
|
|
77
|
+
offset += token.length;
|
|
78
|
+
}
|
|
79
|
+
value(0);
|
|
80
|
+
ws();
|
|
81
|
+
if (offset !== text.length)
|
|
82
|
+
fail();
|
|
83
|
+
try {
|
|
84
|
+
return JSON.parse(text);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return fail();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../../../scr/http-boundary/json.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ReplayStore {
|
|
2
|
+
claim(id: string, expiresAt: number): Promise<boolean>;
|
|
3
|
+
}
|
|
4
|
+
export declare function createRelayTransport(options: {
|
|
5
|
+
endpoint: string;
|
|
6
|
+
serverPublicKey: JsonWebKey;
|
|
7
|
+
authenticationKey: string;
|
|
8
|
+
maxBytes?: number;
|
|
9
|
+
fetch?: typeof fetch;
|
|
10
|
+
now?: () => number;
|
|
11
|
+
}): Promise<(input: RequestInfo | URL, init?: RequestInit) => Promise<Response>>;
|
|
12
|
+
export declare function createRelayServer(options: {
|
|
13
|
+
serverPrivateKey: JsonWebKey;
|
|
14
|
+
authenticationKey: string;
|
|
15
|
+
originToken: string;
|
|
16
|
+
business: (request: Request) => Promise<Response>;
|
|
17
|
+
replay: ReplayStore;
|
|
18
|
+
maxBytes?: number;
|
|
19
|
+
now?: () => number;
|
|
20
|
+
}): Promise<(request: Request) => Promise<Response>>;
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { stableJson } from "../core/types.js";
|
|
2
|
+
const encoder = new TextEncoder(), decoder = new TextDecoder("utf-8", { fatal: true });
|
|
3
|
+
const bytes = (value) => value;
|
|
4
|
+
function b64(value) {
|
|
5
|
+
let text = "";
|
|
6
|
+
for (let i = 0; i < value.length; i += 8192)
|
|
7
|
+
text += String.fromCharCode(...value.subarray(i, i + 8192));
|
|
8
|
+
return btoa(text).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
9
|
+
}
|
|
10
|
+
function unb64(value, limit) {
|
|
11
|
+
if (typeof value !== "string" ||
|
|
12
|
+
value.length > Math.ceil((limit * 4) / 3) + 4 ||
|
|
13
|
+
!/^[\w-]*$/.test(value))
|
|
14
|
+
throw new Error("Invalid relay encoding");
|
|
15
|
+
const binary = atob(value.replaceAll("-", "+").replaceAll("_", "/"));
|
|
16
|
+
if (binary.length > limit)
|
|
17
|
+
throw new Error("Relay value exceeds limit");
|
|
18
|
+
return Uint8Array.from(binary, (c) => c.charCodeAt(0));
|
|
19
|
+
}
|
|
20
|
+
async function readBytes(response, limit) {
|
|
21
|
+
if (!response.body)
|
|
22
|
+
return new Uint8Array();
|
|
23
|
+
const reader = response.body.getReader(), chunks = [];
|
|
24
|
+
let length = 0;
|
|
25
|
+
let timer;
|
|
26
|
+
const timeout = new Promise((_, reject) => {
|
|
27
|
+
timer = setTimeout(() => reject(new Error("Relay read deadline exceeded")), 10000);
|
|
28
|
+
});
|
|
29
|
+
try {
|
|
30
|
+
while (true) {
|
|
31
|
+
const item = await Promise.race([reader.read(), timeout]);
|
|
32
|
+
if (item.done)
|
|
33
|
+
break;
|
|
34
|
+
length += item.value.length;
|
|
35
|
+
if (length > limit)
|
|
36
|
+
throw new Error("Relay body exceeds limit");
|
|
37
|
+
chunks.push(item.value);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
void reader.cancel().catch(() => { });
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
clearTimeout(timer);
|
|
46
|
+
}
|
|
47
|
+
const result = new Uint8Array(length);
|
|
48
|
+
let offset = 0;
|
|
49
|
+
for (const chunk of chunks) {
|
|
50
|
+
result.set(chunk, offset);
|
|
51
|
+
offset += chunk.length;
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
function bodyLimit(value) {
|
|
56
|
+
const limit = value ?? 8 * 1024 * 1024;
|
|
57
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 16 * 1024 * 1024)
|
|
58
|
+
throw new Error("Relay byte limit must be 1..16777216");
|
|
59
|
+
return limit;
|
|
60
|
+
}
|
|
61
|
+
function exact(value, length) {
|
|
62
|
+
const decoded = unb64(value, length);
|
|
63
|
+
if (decoded.length !== length)
|
|
64
|
+
throw new Error("Invalid relay field length");
|
|
65
|
+
return decoded;
|
|
66
|
+
}
|
|
67
|
+
async function macKey(secret) {
|
|
68
|
+
if (!/^[\w-]{43,256}$/.test(secret))
|
|
69
|
+
throw new Error("Relay authentication key must be random base64url");
|
|
70
|
+
return crypto.subtle.importKey("raw", bytes(unb64(secret, 192)), { name: "HMAC", hash: "SHA-256" }, false, ["sign", "verify"]);
|
|
71
|
+
}
|
|
72
|
+
async function publicKey(jwk) {
|
|
73
|
+
if (jwk?.kty !== "EC" || jwk.crv !== "P-256" || jwk.d !== undefined)
|
|
74
|
+
throw new Error("Relay requires a public P-256 key");
|
|
75
|
+
return crypto.subtle.importKey("jwk", jwk, { name: "ECDH", namedCurve: "P-256" }, false, []);
|
|
76
|
+
}
|
|
77
|
+
async function keys(privateKey, publicKey, salt) {
|
|
78
|
+
const shared = await crypto.subtle.deriveBits({ name: "ECDH", public: publicKey }, privateKey, 256);
|
|
79
|
+
const material = await crypto.subtle.importKey("raw", shared, "HKDF", false, ["deriveKey"]);
|
|
80
|
+
const derive = (direction) => crypto.subtle.deriveKey({
|
|
81
|
+
name: "HKDF",
|
|
82
|
+
hash: "SHA-256",
|
|
83
|
+
salt: bytes(salt),
|
|
84
|
+
info: bytes(encoder.encode(`edgeshield-relay:v1:${direction}`)),
|
|
85
|
+
}, material, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
|
|
86
|
+
return { request: await derive("request"), response: await derive("response") };
|
|
87
|
+
}
|
|
88
|
+
function headers(input) {
|
|
89
|
+
return [...input]
|
|
90
|
+
.filter(([key]) => key !== "set-cookie")
|
|
91
|
+
.concat(input.getSetCookie().map((value) => ["set-cookie", value]));
|
|
92
|
+
}
|
|
93
|
+
export async function createRelayTransport(options) {
|
|
94
|
+
const endpoint = new URL(options.endpoint);
|
|
95
|
+
if (endpoint.protocol !== "https:" || endpoint.username || endpoint.password || endpoint.hash)
|
|
96
|
+
throw new Error("Relay requires an exact HTTPS endpoint");
|
|
97
|
+
const server = await publicKey(options.serverPublicKey), authentication = await macKey(options.authenticationKey), limit = bodyLimit(options.maxBytes), transport = options.fetch ?? fetch, now = options.now ?? Date.now;
|
|
98
|
+
return async (input, init) => {
|
|
99
|
+
const request = new Request(input, init), target = new URL(request.url);
|
|
100
|
+
if (target.origin !== "https://origin.internal")
|
|
101
|
+
throw new Error("Relay target is outside the private business origin");
|
|
102
|
+
const pair = await crypto.subtle.generateKey({ name: "ECDH", namedCurve: "P-256" }, true, [
|
|
103
|
+
"deriveBits",
|
|
104
|
+
]);
|
|
105
|
+
const salt = crypto.getRandomValues(new Uint8Array(32)), session = await keys(pair.privateKey, server, salt);
|
|
106
|
+
const meta = {
|
|
107
|
+
v: 1,
|
|
108
|
+
id: crypto.randomUUID(),
|
|
109
|
+
at: now(),
|
|
110
|
+
epk: await crypto.subtle.exportKey("jwk", pair.publicKey),
|
|
111
|
+
salt: b64(salt),
|
|
112
|
+
};
|
|
113
|
+
const aad = encoder.encode(stableJson(meta)), nonce = crypto.getRandomValues(new Uint8Array(12));
|
|
114
|
+
const plain = encoder.encode(JSON.stringify({
|
|
115
|
+
method: request.method,
|
|
116
|
+
target: target.pathname + target.search,
|
|
117
|
+
headers: headers(request.headers),
|
|
118
|
+
body: b64(await readBytes(request, limit)),
|
|
119
|
+
}));
|
|
120
|
+
if (plain.length > limit * 2 + 65536)
|
|
121
|
+
throw new Error("Relay payload exceeds limit");
|
|
122
|
+
const ciphertext = new Uint8Array(await crypto.subtle.encrypt({ name: "AES-GCM", iv: bytes(nonce), additionalData: bytes(aad) }, session.request, bytes(plain)));
|
|
123
|
+
const packet = { ...meta, nonce: b64(nonce), body: b64(ciphertext) };
|
|
124
|
+
const signature = b64(new Uint8Array(await crypto.subtle.sign("HMAC", authentication, bytes(encoder.encode(stableJson(packet))))));
|
|
125
|
+
const response = await transport(endpoint, {
|
|
126
|
+
method: "POST",
|
|
127
|
+
redirect: "manual",
|
|
128
|
+
signal: request.signal,
|
|
129
|
+
headers: { "content-type": "application/vnd.edgeshield.relay+json" },
|
|
130
|
+
body: JSON.stringify({ ...packet, signature }),
|
|
131
|
+
});
|
|
132
|
+
if (!response.ok)
|
|
133
|
+
throw new Error(`Relay endpoint rejected request (${response.status})`);
|
|
134
|
+
const envelope = JSON.parse(decoder.decode(await readBytes(response, limit * 3 + 262144)));
|
|
135
|
+
if (envelope.v !== 1 || envelope.id !== meta.id)
|
|
136
|
+
throw new Error("Relay response binding mismatch");
|
|
137
|
+
const decoded = await crypto.subtle.decrypt({
|
|
138
|
+
name: "AES-GCM",
|
|
139
|
+
iv: bytes(exact(envelope.nonce, 12)),
|
|
140
|
+
additionalData: bytes(encoder.encode(stableJson({ v: 1, id: meta.id, direction: "response" }))),
|
|
141
|
+
}, session.response, bytes(unb64(envelope.body, limit * 2 + 65536)));
|
|
142
|
+
const result = JSON.parse(decoder.decode(decoded));
|
|
143
|
+
if (!Number.isInteger(result.status) ||
|
|
144
|
+
result.status < 200 ||
|
|
145
|
+
result.status > 599 ||
|
|
146
|
+
!Array.isArray(result.headers))
|
|
147
|
+
throw new Error("Invalid relay response");
|
|
148
|
+
const body = unb64(result.body, limit);
|
|
149
|
+
return new Response(request.method === "HEAD" || [204, 205, 304].includes(result.status)
|
|
150
|
+
? null
|
|
151
|
+
: body, { status: result.status, headers: result.headers });
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
export async function createRelayServer(options) {
|
|
155
|
+
const privateKey = await crypto.subtle.importKey("jwk", options.serverPrivateKey, { name: "ECDH", namedCurve: "P-256" }, false, ["deriveBits"]), authentication = await macKey(options.authenticationKey), limit = bodyLimit(options.maxBytes), now = options.now ?? Date.now;
|
|
156
|
+
return async (request) => {
|
|
157
|
+
try {
|
|
158
|
+
if (request.method !== "POST")
|
|
159
|
+
return new Response(null, { status: 405 });
|
|
160
|
+
const packet = JSON.parse(decoder.decode(await readBytes(request, limit * 3 + 262144)));
|
|
161
|
+
const { signature, ...signed } = packet;
|
|
162
|
+
if (packet.v !== 1 ||
|
|
163
|
+
typeof packet.id !== "string" ||
|
|
164
|
+
!/^[a-f\d-]{36}$/i.test(packet.id) ||
|
|
165
|
+
!Number.isSafeInteger(packet.at) ||
|
|
166
|
+
Math.abs(now() - packet.at) > 30000 ||
|
|
167
|
+
Object.keys(packet).some((key) => !["v", "id", "at", "epk", "salt", "nonce", "body", "signature"].includes(key)))
|
|
168
|
+
throw new Error("Invalid relay envelope");
|
|
169
|
+
if (!(await crypto.subtle.verify("HMAC", authentication, bytes(exact(signature, 32)), bytes(encoder.encode(stableJson(signed))))))
|
|
170
|
+
throw new Error("Relay authentication failed");
|
|
171
|
+
if (!(await options.replay.claim(packet.id, packet.at + 60000)))
|
|
172
|
+
throw new Error("Relay request replayed");
|
|
173
|
+
const meta = { v: 1, id: packet.id, at: packet.at, epk: packet.epk, salt: packet.salt }, session = await keys(privateKey, await publicKey(packet.epk), exact(packet.salt, 32));
|
|
174
|
+
const plain = await crypto.subtle.decrypt({
|
|
175
|
+
name: "AES-GCM",
|
|
176
|
+
iv: bytes(exact(packet.nonce, 12)),
|
|
177
|
+
additionalData: bytes(encoder.encode(stableJson(meta))),
|
|
178
|
+
}, session.request, bytes(unb64(packet.body, limit * 2 + 65536)));
|
|
179
|
+
const decoded = JSON.parse(decoder.decode(plain));
|
|
180
|
+
if (typeof decoded.method !== "string" ||
|
|
181
|
+
!["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"].includes(decoded.method) ||
|
|
182
|
+
typeof decoded.target !== "string" ||
|
|
183
|
+
!decoded.target.startsWith("/") ||
|
|
184
|
+
decoded.target.startsWith("//") ||
|
|
185
|
+
/[\r\n#]/.test(decoded.target) ||
|
|
186
|
+
!Array.isArray(decoded.headers) ||
|
|
187
|
+
decoded.headers.length > 128)
|
|
188
|
+
throw new Error("Invalid relay request target");
|
|
189
|
+
const target = new URL(decoded.target, "https://origin.internal");
|
|
190
|
+
if (target.origin !== "https://origin.internal")
|
|
191
|
+
throw new Error("Invalid relay authority");
|
|
192
|
+
const payload = unb64(decoded.body, limit), requestHeaders = new Headers(decoded.headers);
|
|
193
|
+
const expected = await crypto.subtle.digest("SHA-256", bytes(encoder.encode(options.originToken))), provided = await crypto.subtle.digest("SHA-256", bytes(encoder.encode(requestHeaders.get("x-shield-origin-auth") ?? "")));
|
|
194
|
+
if (b64(new Uint8Array(expected)) !== b64(new Uint8Array(provided)))
|
|
195
|
+
throw new Error("Untrusted relay origin credential");
|
|
196
|
+
const response = await options.business(new Request(target, {
|
|
197
|
+
method: decoded.method,
|
|
198
|
+
headers: requestHeaders,
|
|
199
|
+
...(!["GET", "HEAD"].includes(decoded.method) && payload.length
|
|
200
|
+
? { body: payload }
|
|
201
|
+
: {}),
|
|
202
|
+
}));
|
|
203
|
+
const body = encoder.encode(JSON.stringify({
|
|
204
|
+
status: response.status,
|
|
205
|
+
headers: headers(response.headers),
|
|
206
|
+
body: b64(await readBytes(response, limit)),
|
|
207
|
+
}));
|
|
208
|
+
const nonce = crypto.getRandomValues(new Uint8Array(12));
|
|
209
|
+
const cipher = await crypto.subtle.encrypt({
|
|
210
|
+
name: "AES-GCM",
|
|
211
|
+
iv: bytes(nonce),
|
|
212
|
+
additionalData: bytes(encoder.encode(stableJson({ v: 1, id: packet.id, direction: "response" }))),
|
|
213
|
+
}, session.response, bytes(body));
|
|
214
|
+
return Response.json({ v: 1, id: packet.id, nonce: b64(nonce), body: b64(new Uint8Array(cipher)) }, { headers: { "cache-control": "no-store" } });
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
return Response.json({ error: "relay_request_rejected" }, { status: 403, headers: { "cache-control": "no-store" } });
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=relay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay.js","sourceRoot":"","sources":["../../../../scr/origin/relay.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { DatabaseSync } from "node:sqlite";
|
|
2
|
+
export class SqliteReplayStore {
|
|
3
|
+
capacity;
|
|
4
|
+
now;
|
|
5
|
+
database;
|
|
6
|
+
constructor(path, capacity = 4096, now = Date.now) {
|
|
7
|
+
this.capacity = capacity;
|
|
8
|
+
this.now = now;
|
|
9
|
+
this.database = new DatabaseSync(path);
|
|
10
|
+
this.database.exec("PRAGMA journal_mode=WAL; CREATE TABLE IF NOT EXISTS replay (id TEXT PRIMARY KEY, expires INTEGER NOT NULL); CREATE INDEX IF NOT EXISTS expiry ON replay(expires)");
|
|
11
|
+
}
|
|
12
|
+
async claim(id, expiresAt) {
|
|
13
|
+
this.database.exec("BEGIN IMMEDIATE");
|
|
14
|
+
try {
|
|
15
|
+
this.database.prepare("DELETE FROM replay WHERE expires <= ?").run(this.now());
|
|
16
|
+
if (this.database.prepare("SELECT id FROM replay WHERE id=?").get(id)) {
|
|
17
|
+
this.database.exec("COMMIT");
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
const count = this.database.prepare("SELECT count(*) AS n FROM replay").get();
|
|
21
|
+
if (count.n >= this.capacity)
|
|
22
|
+
throw new Error("Relay replay store capacity exceeded");
|
|
23
|
+
this.database.prepare("INSERT INTO replay VALUES (?,?)").run(id, expiresAt);
|
|
24
|
+
this.database.exec("COMMIT");
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
this.database.exec("ROLLBACK");
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
close() {
|
|
33
|
+
this.database.close();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=replay-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay-node.js","sourceRoot":"","sources":["../../../../scr/origin/replay-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,MAAM,OAAO,iBAAiB;IAIlB,QAAQ;IACR,GAAG;IAJL,QAAQ,CAAe;IAC/B,YACE,IAAY,EACJ,QAAQ,GAAG,IAAI,EACf,GAAG,GAAG,IAAI,CAAC,GAAG;wBADd,QAAQ;mBACR,GAAG;QAEX,IAAI,CAAC,QAAQ,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAChB,kKAAkK,CACnK,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,KAAK,CAAC,EAAU,EAAE,SAAiB;QACvC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACtC,IAAI,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;YAC/E,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBACtE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC7B,OAAO,KAAK,CAAC;YACf,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC,GAAG,EAE1E,CAAC;YACF,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ;gBAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;YACtF,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;YAC5E,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/B,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IACD,KAAK;QACH,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;CACF"}
|