@amodalai/runtime 0.3.70 → 0.3.72
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/dist/src/agent/local-server.js +7 -0
- package/dist/src/agent/local-server.js.map +1 -1
- package/dist/src/agent/local-server.test.js +96 -1
- package/dist/src/agent/local-server.test.js.map +1 -1
- package/dist/src/agent/routes/logs.d.ts +12 -0
- package/dist/src/agent/routes/logs.js +46 -0
- package/dist/src/agent/routes/logs.js.map +1 -0
- package/dist/src/agent/snapshot-server.js +4 -0
- package/dist/src/agent/snapshot-server.js.map +1 -1
- package/dist/src/auth/__fixtures__/custom-strategy.d.ts +8 -0
- package/dist/src/auth/__fixtures__/custom-strategy.js +27 -0
- package/dist/src/auth/__fixtures__/custom-strategy.js.map +1 -0
- package/dist/src/auth/compose.d.ts +55 -0
- package/dist/src/auth/compose.js +142 -0
- package/dist/src/auth/compose.js.map +1 -0
- package/dist/src/auth/compose.test.d.ts +6 -0
- package/dist/src/auth/compose.test.js +159 -0
- package/dist/src/auth/compose.test.js.map +1 -0
- package/dist/src/auth/config.d.ts +261 -0
- package/dist/src/auth/config.js +107 -0
- package/dist/src/auth/config.js.map +1 -0
- package/dist/src/auth/config.test.d.ts +6 -0
- package/dist/src/auth/config.test.js +85 -0
- package/dist/src/auth/config.test.js.map +1 -0
- package/dist/src/auth/factory.d.ts +19 -0
- package/dist/src/auth/factory.js +57 -0
- package/dist/src/auth/factory.js.map +1 -0
- package/dist/src/auth/factory.test.d.ts +6 -0
- package/dist/src/auth/factory.test.js +60 -0
- package/dist/src/auth/factory.test.js.map +1 -0
- package/dist/src/auth/index.d.ts +48 -0
- package/dist/src/auth/index.js +19 -0
- package/dist/src/auth/index.js.map +1 -0
- package/dist/src/auth/strategies/amodal.d.ts +36 -0
- package/dist/src/auth/strategies/amodal.js +28 -0
- package/dist/src/auth/strategies/amodal.js.map +1 -0
- package/dist/src/auth/strategies/api-key.d.ts +41 -0
- package/dist/src/auth/strategies/api-key.js +63 -0
- package/dist/src/auth/strategies/api-key.js.map +1 -0
- package/dist/src/auth/strategies/auth-modes.integration.test.d.ts +6 -0
- package/dist/src/auth/strategies/auth-modes.integration.test.js +363 -0
- package/dist/src/auth/strategies/auth-modes.integration.test.js.map +1 -0
- package/dist/src/auth/strategies/cookie.d.ts +41 -0
- package/dist/src/auth/strategies/cookie.js +84 -0
- package/dist/src/auth/strategies/cookie.js.map +1 -0
- package/dist/src/auth/strategies/custom-loader.d.ts +17 -0
- package/dist/src/auth/strategies/custom-loader.js +37 -0
- package/dist/src/auth/strategies/custom-loader.js.map +1 -0
- package/dist/src/auth/strategies/header.d.ts +35 -0
- package/dist/src/auth/strategies/header.js +42 -0
- package/dist/src/auth/strategies/header.js.map +1 -0
- package/dist/src/auth/strategies/jwks.d.ts +38 -0
- package/dist/src/auth/strategies/jwks.js +86 -0
- package/dist/src/auth/strategies/jwks.js.map +1 -0
- package/dist/src/auth/strategies/jwt-secret.d.ts +25 -0
- package/dist/src/auth/strategies/jwt-secret.js +82 -0
- package/dist/src/auth/strategies/jwt-secret.js.map +1 -0
- package/dist/src/auth/strategies/jwt-secret.test.d.ts +6 -0
- package/dist/src/auth/strategies/jwt-secret.test.js +75 -0
- package/dist/src/auth/strategies/jwt-secret.test.js.map +1 -0
- package/dist/src/auth/strategies/none.d.ts +37 -0
- package/dist/src/auth/strategies/none.js +31 -0
- package/dist/src/auth/strategies/none.js.map +1 -0
- package/dist/src/auth/strategies/oidc.d.ts +48 -0
- package/dist/src/auth/strategies/oidc.integration.test.d.ts +6 -0
- package/dist/src/auth/strategies/oidc.integration.test.js +290 -0
- package/dist/src/auth/strategies/oidc.integration.test.js.map +1 -0
- package/dist/src/auth/strategies/oidc.js +284 -0
- package/dist/src/auth/strategies/oidc.js.map +1 -0
- package/dist/src/auth/strategies/oidc.test.d.ts +6 -0
- package/dist/src/auth/strategies/oidc.test.js +111 -0
- package/dist/src/auth/strategies/oidc.test.js.map +1 -0
- package/dist/src/auth/strategies/strategies.test.d.ts +6 -0
- package/dist/src/auth/strategies/strategies.test.js +190 -0
- package/dist/src/auth/strategies/strategies.test.js.map +1 -0
- package/dist/src/auth/types.d.ts +95 -0
- package/dist/src/auth/types.js +7 -0
- package/dist/src/auth/types.js.map +1 -0
- package/dist/src/index.d.ts +4 -2
- package/dist/src/index.js +3 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/logger.d.ts +4 -3
- package/dist/src/logger.js +2 -1
- package/dist/src/logger.js.map +1 -1
- package/dist/src/logger.test.js +22 -1
- package/dist/src/logger.test.js.map +1 -1
- package/dist/src/runtime-log-store.d.ts +37 -0
- package/dist/src/runtime-log-store.js +132 -0
- package/dist/src/runtime-log-store.js.map +1 -0
- package/dist/src/server.js +7 -0
- package/dist/src/server.js.map +1 -1
- package/dist/src/session/manager.d.ts +1 -0
- package/dist/src/session/manager.js +18 -7
- package/dist/src/session/manager.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -4
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* End-to-end OIDC test driving the full auth-code+PKCE dance against an
|
|
8
|
+
* in-process `node-oidc-provider`. Boots a real IdP on a random port,
|
|
9
|
+
* mounts `OidcAuthStrategy` on a real Express app, and walks login →
|
|
10
|
+
* IdP /auth → interaction (auto-resolved) → callback → session cookie →
|
|
11
|
+
* protected route hit. Catches integration bugs that unit tests can't:
|
|
12
|
+
* cookie wiring, redirect handling, state/PKCE round-trip, callback URL
|
|
13
|
+
* matching.
|
|
14
|
+
*/
|
|
15
|
+
import http from 'node:http';
|
|
16
|
+
import { randomBytes } from 'node:crypto';
|
|
17
|
+
import express from 'express';
|
|
18
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
19
|
+
import Provider from 'oidc-provider';
|
|
20
|
+
import { OidcAuthStrategy } from './oidc.js';
|
|
21
|
+
import { authenticate, authRouter, getSession } from '../compose.js';
|
|
22
|
+
const TEST_USER = {
|
|
23
|
+
sub: 'user-42',
|
|
24
|
+
email: 'alice@example.com',
|
|
25
|
+
name: 'Alice Example',
|
|
26
|
+
};
|
|
27
|
+
async function resolveInteraction(provider, req, res) {
|
|
28
|
+
const details = await provider.interactionDetails(req, res);
|
|
29
|
+
if (details.prompt.name === 'login') {
|
|
30
|
+
await provider.interactionFinished(req, res, { login: { accountId: TEST_USER.sub } }, { mergeWithLastSubmission: false });
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
// consent prompt — grant everything requested
|
|
34
|
+
const grant = new provider.Grant({
|
|
35
|
+
accountId: TEST_USER.sub,
|
|
36
|
+
clientId: 'test-client',
|
|
37
|
+
});
|
|
38
|
+
const missingScopes = details.prompt.details['missingOIDCScope'];
|
|
39
|
+
if (Array.isArray(missingScopes)) {
|
|
40
|
+
for (const scope of missingScopes) {
|
|
41
|
+
if (typeof scope === 'string')
|
|
42
|
+
grant.addOIDCScope(scope);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const grantId = await grant.save();
|
|
46
|
+
await provider.interactionFinished(req, res, { consent: { grantId } }, { mergeWithLastSubmission: true });
|
|
47
|
+
}
|
|
48
|
+
async function reservePort() {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const s = http.createServer();
|
|
51
|
+
s.on('error', reject);
|
|
52
|
+
s.listen(0, '127.0.0.1', () => {
|
|
53
|
+
const addr = s.address();
|
|
54
|
+
s.close(() => resolve(addr.port));
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
async function startIdp(issuerUrl, redirectUri) {
|
|
59
|
+
const provider = new Provider(issuerUrl, {
|
|
60
|
+
clients: [
|
|
61
|
+
{
|
|
62
|
+
client_id: 'test-client',
|
|
63
|
+
client_secret: 'test-secret',
|
|
64
|
+
redirect_uris: [redirectUri],
|
|
65
|
+
grant_types: ['authorization_code'],
|
|
66
|
+
response_types: ['code'],
|
|
67
|
+
token_endpoint_auth_method: 'client_secret_basic',
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
pkce: { required: () => true },
|
|
71
|
+
findAccount: (_ctx, sub) => ({
|
|
72
|
+
accountId: sub,
|
|
73
|
+
claims: () => ({
|
|
74
|
+
sub,
|
|
75
|
+
email: TEST_USER.email,
|
|
76
|
+
name: TEST_USER.name,
|
|
77
|
+
}),
|
|
78
|
+
}),
|
|
79
|
+
cookies: {
|
|
80
|
+
keys: ['integration-test-cookie-key-please-rotate'],
|
|
81
|
+
},
|
|
82
|
+
// Most real IdPs (Okta, Auth0, Azure AD with optional claims) put
|
|
83
|
+
// scoped claims directly on the id_token. Match that behaviour so
|
|
84
|
+
// the strategy's `claims['email']` / `claims['name']` reads work.
|
|
85
|
+
conformIdTokenClaims: false,
|
|
86
|
+
claims: {
|
|
87
|
+
openid: ['sub'],
|
|
88
|
+
email: ['email', 'email_verified'],
|
|
89
|
+
profile: ['name', 'family_name', 'given_name', 'preferred_username'],
|
|
90
|
+
},
|
|
91
|
+
features: {
|
|
92
|
+
// The full IdP UI isn't relevant to us — we drive interactions via
|
|
93
|
+
// a custom resolver below.
|
|
94
|
+
devInteractions: { enabled: false },
|
|
95
|
+
},
|
|
96
|
+
// node-oidc-provider redirects to this URL when an interaction
|
|
97
|
+
// (login / consent) is required. The app provides routes there.
|
|
98
|
+
interactions: {
|
|
99
|
+
url: (_ctx, interaction) => `/interaction/${interaction.uid}`,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
const app = express();
|
|
103
|
+
app.set('trust proxy', true);
|
|
104
|
+
// Auto-resolve every interaction as "this user has logged in and consented."
|
|
105
|
+
// Saves us from rendering or POSTing a real form.
|
|
106
|
+
app.get('/interaction/:uid', (req, res, next) => {
|
|
107
|
+
void resolveInteraction(provider, req, res).catch(next);
|
|
108
|
+
});
|
|
109
|
+
const oidcCallback = provider.callback();
|
|
110
|
+
app.use((req, res, next) => {
|
|
111
|
+
void oidcCallback(req, res).catch(next);
|
|
112
|
+
});
|
|
113
|
+
// Surface internal failures so the test can print them.
|
|
114
|
+
app.use((err, _req, res, _next) => {
|
|
115
|
+
const detail = err instanceof Error ? err.stack ?? err.message : String(err);
|
|
116
|
+
process.stderr.write(`[idp error] ${detail}\n`);
|
|
117
|
+
res.status(500).json({ error: detail });
|
|
118
|
+
});
|
|
119
|
+
const idpUrl = new URL(issuerUrl);
|
|
120
|
+
return new Promise((resolve, reject) => {
|
|
121
|
+
const server = http.createServer(app);
|
|
122
|
+
server.on('error', reject);
|
|
123
|
+
server.listen(Number(idpUrl.port), idpUrl.hostname, () => {
|
|
124
|
+
resolve({
|
|
125
|
+
url: issuerUrl,
|
|
126
|
+
close: () => new Promise((closeResolve, closeReject) => {
|
|
127
|
+
server.close((err) => (err ? closeReject(err) : closeResolve()));
|
|
128
|
+
}),
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
async function startApp(strategy, port) {
|
|
134
|
+
const app = express();
|
|
135
|
+
app.use(authRouter(strategy));
|
|
136
|
+
app.get('/protected', authenticate(strategy), (_req, res) => {
|
|
137
|
+
const session = getSession(res);
|
|
138
|
+
res.json({ user: session?.user, method: session?.method });
|
|
139
|
+
});
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
const server = http.createServer(app);
|
|
142
|
+
server.on('error', reject);
|
|
143
|
+
server.listen(port, '127.0.0.1', () => {
|
|
144
|
+
resolve({
|
|
145
|
+
url: `http://127.0.0.1:${port}`,
|
|
146
|
+
close: () => new Promise((closeResolve, closeReject) => {
|
|
147
|
+
server.close((err) => (err ? closeReject(err) : closeResolve()));
|
|
148
|
+
}),
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
function makeCookieJar() {
|
|
154
|
+
const store = new Map();
|
|
155
|
+
return {
|
|
156
|
+
store,
|
|
157
|
+
header: () => [...store.entries()].map(([name, value]) => `${name}=${value}`).join('; '),
|
|
158
|
+
ingest(setCookie) {
|
|
159
|
+
if (!setCookie)
|
|
160
|
+
return;
|
|
161
|
+
const list = Array.isArray(setCookie) ? setCookie : [setCookie];
|
|
162
|
+
for (const raw of list) {
|
|
163
|
+
const [pair] = raw.split(';');
|
|
164
|
+
if (!pair)
|
|
165
|
+
continue;
|
|
166
|
+
const eq = pair.indexOf('=');
|
|
167
|
+
if (eq === -1)
|
|
168
|
+
continue;
|
|
169
|
+
const name = pair.slice(0, eq).trim();
|
|
170
|
+
const value = pair.slice(eq + 1).trim();
|
|
171
|
+
if (value === '') {
|
|
172
|
+
store.delete(name);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
store.set(name, value);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
async function followRedirects(start, jar, maxHops = 12) {
|
|
182
|
+
let current = start;
|
|
183
|
+
const trail = [];
|
|
184
|
+
for (let i = 0; i < maxHops; i++) {
|
|
185
|
+
const res = await fetch(current, {
|
|
186
|
+
redirect: 'manual',
|
|
187
|
+
headers: jar.store.size > 0 ? { cookie: jar.header() } : {},
|
|
188
|
+
});
|
|
189
|
+
const setCookie = res.headers.getSetCookie?.() ?? res.headers.get('set-cookie');
|
|
190
|
+
jar.ingest(setCookie ?? undefined);
|
|
191
|
+
trail.push(`${res.status} ${current}`);
|
|
192
|
+
if (res.status >= 300 && res.status < 400) {
|
|
193
|
+
const location = res.headers.get('location');
|
|
194
|
+
if (!location) {
|
|
195
|
+
return {
|
|
196
|
+
status: res.status,
|
|
197
|
+
url: current,
|
|
198
|
+
headers: headerObject(res.headers),
|
|
199
|
+
body: '',
|
|
200
|
+
trail,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
current = new URL(location, current).toString();
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
const body = await res.text();
|
|
207
|
+
return { status: res.status, url: current, headers: headerObject(res.headers), body, trail };
|
|
208
|
+
}
|
|
209
|
+
throw new Error(`Too many redirects starting at ${start}\n${trail.join('\n')}`);
|
|
210
|
+
}
|
|
211
|
+
function headerObject(h) {
|
|
212
|
+
const out = {};
|
|
213
|
+
h.forEach((value, key) => {
|
|
214
|
+
out[key] = value;
|
|
215
|
+
});
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
describe('OidcAuthStrategy — integration', () => {
|
|
219
|
+
let idp;
|
|
220
|
+
let app;
|
|
221
|
+
let strategy;
|
|
222
|
+
const sessionSecret = randomBytes(32).toString('hex');
|
|
223
|
+
beforeAll(async () => {
|
|
224
|
+
// Reserve both ports up front so we can pin issuer + callback URLs
|
|
225
|
+
// into both the IdP config and the strategy config before either
|
|
226
|
+
// starts listening.
|
|
227
|
+
const idpPort = await reservePort();
|
|
228
|
+
const appPort = await reservePort();
|
|
229
|
+
const issuerUrl = `http://127.0.0.1:${idpPort}`;
|
|
230
|
+
const callbackUrl = `http://127.0.0.1:${appPort}/auth/callback`;
|
|
231
|
+
idp = await startIdp(issuerUrl, callbackUrl);
|
|
232
|
+
strategy = new OidcAuthStrategy({
|
|
233
|
+
issuer: issuerUrl,
|
|
234
|
+
clientId: 'test-client',
|
|
235
|
+
clientSecret: 'test-secret',
|
|
236
|
+
callbackUrl,
|
|
237
|
+
sessionSecret,
|
|
238
|
+
allowInsecureRequests: true,
|
|
239
|
+
});
|
|
240
|
+
app = await startApp(strategy, appPort);
|
|
241
|
+
}, 30_000);
|
|
242
|
+
afterAll(async () => {
|
|
243
|
+
if (app)
|
|
244
|
+
await app.close();
|
|
245
|
+
if (idp)
|
|
246
|
+
await idp.close();
|
|
247
|
+
});
|
|
248
|
+
it('rejects an unauthenticated request', async () => {
|
|
249
|
+
const res = await fetch(`${app.url}/protected`);
|
|
250
|
+
expect(res.status).toBe(401);
|
|
251
|
+
});
|
|
252
|
+
it('discovery doc is reachable on the IdP', async () => {
|
|
253
|
+
const res = await fetch(`${idp.url}/.well-known/openid-configuration`);
|
|
254
|
+
expect(res.status).toBe(200);
|
|
255
|
+
const body = (await res.json());
|
|
256
|
+
expect(body.issuer).toBe(idp.url);
|
|
257
|
+
});
|
|
258
|
+
it('walks the full authorization-code + PKCE dance and authenticates', async () => {
|
|
259
|
+
const jar = makeCookieJar();
|
|
260
|
+
// /auth/login → IdP /auth → interaction (auto-resolved twice: login + consent)
|
|
261
|
+
// → IdP /auth/<uid> → our /auth/callback?code=... → 302 to returnTo ('/').
|
|
262
|
+
// The trail terminates on the app's '/' (404 here only because the test
|
|
263
|
+
// app didn't register one — that's fine; what matters is we got back to
|
|
264
|
+
// the app's domain and the session cookie was issued in the callback hop.
|
|
265
|
+
const final = await followRedirects(`${app.url}/auth/login`, jar, 20);
|
|
266
|
+
if (final.status >= 500) {
|
|
267
|
+
process.stderr.write(`[trail]\n${final.trail.join('\n')}\n[final body] ${final.body}\n`);
|
|
268
|
+
throw new Error(`Unexpected 5xx during OIDC dance: ${final.status}`);
|
|
269
|
+
}
|
|
270
|
+
expect(final.url.startsWith(app.url)).toBe(true);
|
|
271
|
+
// session cookie should now be set
|
|
272
|
+
expect(jar.store.has('amodal_session')).toBe(true);
|
|
273
|
+
// protected route should work with the session cookie
|
|
274
|
+
const res = await fetch(`${app.url}/protected`, {
|
|
275
|
+
headers: { cookie: jar.header() },
|
|
276
|
+
});
|
|
277
|
+
expect(res.status).toBe(200);
|
|
278
|
+
const body = (await res.json());
|
|
279
|
+
expect(body.user.id).toBe(TEST_USER.sub);
|
|
280
|
+
expect(body.user.email).toBe(TEST_USER.email);
|
|
281
|
+
expect(body.method).toBe('oidc');
|
|
282
|
+
}, 30_000);
|
|
283
|
+
it('rejects a request with a tampered session cookie', async () => {
|
|
284
|
+
const res = await fetch(`${app.url}/protected`, {
|
|
285
|
+
headers: { cookie: 'amodal_session=garbage.token.here' },
|
|
286
|
+
});
|
|
287
|
+
expect(res.status).toBe(401);
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
//# sourceMappingURL=oidc.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc.integration.test.js","sourceRoot":"","sources":["../../../../src/auth/strategies/oidc.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* OidcAuthStrategy — full OAuth2.1/OIDC dance via `openid-client`.
|
|
8
|
+
*
|
|
9
|
+
* Handles:
|
|
10
|
+
* - Discovery against the IdP's `.well-known/openid-configuration`
|
|
11
|
+
* - Authorization-code + PKCE login flow at `/auth/login`
|
|
12
|
+
* - Callback at `/auth/callback` — exchanges code for tokens, verifies
|
|
13
|
+
* the id_token, and issues an HMAC-signed session cookie
|
|
14
|
+
* - Per-request verification of the session cookie (via JWKS for the
|
|
15
|
+
* session JWT — actually HMAC since we sign it ourselves)
|
|
16
|
+
* - Optional `authorize(claims)` rule for group/role gating
|
|
17
|
+
*
|
|
18
|
+
* Covers Okta, Azure AD, Google Workspace, Auth0 OIDC, OneLogin,
|
|
19
|
+
* Authentik, Keycloak — anything OIDC-compliant.
|
|
20
|
+
*/
|
|
21
|
+
import { Router } from 'express';
|
|
22
|
+
import rateLimit from 'express-rate-limit';
|
|
23
|
+
import * as oidc from 'openid-client';
|
|
24
|
+
import { SignJWT, jwtVerify } from 'jose';
|
|
25
|
+
const STATE_COOKIE = 'amodal_oauth_state';
|
|
26
|
+
const STATE_TTL_SECONDS = 5 * 60;
|
|
27
|
+
export class OidcAuthStrategy {
|
|
28
|
+
name = 'oidc';
|
|
29
|
+
opts;
|
|
30
|
+
sessionKey;
|
|
31
|
+
discoveryPromise = null;
|
|
32
|
+
constructor(options) {
|
|
33
|
+
this.opts = {
|
|
34
|
+
issuer: options.issuer,
|
|
35
|
+
clientId: options.clientId,
|
|
36
|
+
clientSecret: options.clientSecret,
|
|
37
|
+
callbackUrl: options.callbackUrl,
|
|
38
|
+
scopes: options.scopes ?? ['openid', 'email', 'profile'],
|
|
39
|
+
sessionSecret: options.sessionSecret,
|
|
40
|
+
cookieName: options.cookieName ?? 'amodal_session',
|
|
41
|
+
sessionTtlSeconds: options.sessionTtlSeconds ?? 24 * 3600,
|
|
42
|
+
authMethod: options.authMethod ?? 'oidc',
|
|
43
|
+
allowInsecureRequests: options.allowInsecureRequests ?? false,
|
|
44
|
+
};
|
|
45
|
+
if (options.authorize)
|
|
46
|
+
this.opts.authorize = options.authorize;
|
|
47
|
+
this.sessionKey = new TextEncoder().encode(options.sessionSecret);
|
|
48
|
+
}
|
|
49
|
+
valid(req) {
|
|
50
|
+
return readCookie(req, this.opts.cookieName) !== null;
|
|
51
|
+
}
|
|
52
|
+
async authenticate(req) {
|
|
53
|
+
const cookie = readCookie(req, this.opts.cookieName);
|
|
54
|
+
if (!cookie)
|
|
55
|
+
return { kind: 'rejected', reason: 'No session cookie' };
|
|
56
|
+
let payload;
|
|
57
|
+
try {
|
|
58
|
+
const result = await jwtVerify(cookie, this.sessionKey, {
|
|
59
|
+
algorithms: ['HS256'],
|
|
60
|
+
issuer: 'amodal-runtime',
|
|
61
|
+
});
|
|
62
|
+
payload = result.payload;
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
66
|
+
return { kind: 'rejected', reason: `Session JWT invalid: ${detail}` };
|
|
67
|
+
}
|
|
68
|
+
const session = {
|
|
69
|
+
user: {
|
|
70
|
+
id: typeof payload['sub'] === 'string' ? payload['sub'] : '',
|
|
71
|
+
...(typeof payload['email'] === 'string' ? { email: payload['email'] } : {}),
|
|
72
|
+
...(typeof payload['name'] === 'string' ? { name: payload['name'] } : {}),
|
|
73
|
+
},
|
|
74
|
+
method: this.opts.authMethod,
|
|
75
|
+
claims: readClaims(payload['claims']),
|
|
76
|
+
};
|
|
77
|
+
return { kind: 'authenticated', session };
|
|
78
|
+
}
|
|
79
|
+
routes() {
|
|
80
|
+
const router = Router();
|
|
81
|
+
// Rate-limit the OAuth-dance endpoints. Both `/auth/login` and
|
|
82
|
+
// `/auth/callback` perform authorization side-effects (issuing
|
|
83
|
+
// signed cookies, exchanging codes with the IdP) and would
|
|
84
|
+
// otherwise be vulnerable to scrape / discovery flooding /
|
|
85
|
+
// credential-stuffing-adjacent abuse. Logout doesn't need to be
|
|
86
|
+
// rate-limited — it only clears a cookie.
|
|
87
|
+
const authLimiter = rateLimit({
|
|
88
|
+
windowMs: 15 * 60 * 1000,
|
|
89
|
+
max: 60,
|
|
90
|
+
standardHeaders: true,
|
|
91
|
+
legacyHeaders: false,
|
|
92
|
+
});
|
|
93
|
+
router.get('/auth/login', authLimiter, (req, res) => {
|
|
94
|
+
void this.handleLogin(req, res);
|
|
95
|
+
});
|
|
96
|
+
router.get('/auth/callback', authLimiter, (req, res) => {
|
|
97
|
+
void this.handleCallback(req, res);
|
|
98
|
+
});
|
|
99
|
+
router.post('/auth/logout', (_req, res) => {
|
|
100
|
+
clearCookie(res, this.opts.cookieName);
|
|
101
|
+
res.json({ ok: true });
|
|
102
|
+
});
|
|
103
|
+
return router;
|
|
104
|
+
}
|
|
105
|
+
// ---- internals ----------------------------------------------------------
|
|
106
|
+
async config() {
|
|
107
|
+
if (!this.discoveryPromise) {
|
|
108
|
+
this.discoveryPromise = oidc.discovery(new URL(this.opts.issuer), this.opts.clientId, this.opts.clientSecret, undefined, this.opts.allowInsecureRequests
|
|
109
|
+
? { execute: [oidc.allowInsecureRequests] }
|
|
110
|
+
: undefined);
|
|
111
|
+
}
|
|
112
|
+
return this.discoveryPromise;
|
|
113
|
+
}
|
|
114
|
+
async handleLogin(req, res) {
|
|
115
|
+
try {
|
|
116
|
+
const config = await this.config();
|
|
117
|
+
const codeVerifier = oidc.randomPKCECodeVerifier();
|
|
118
|
+
const codeChallenge = await oidc.calculatePKCECodeChallenge(codeVerifier);
|
|
119
|
+
const state = oidc.randomState();
|
|
120
|
+
const returnTo = typeof req.query['return_to'] === 'string' ? req.query['return_to'] : '/';
|
|
121
|
+
// Stash state + codeVerifier + return_to in a short-lived signed cookie
|
|
122
|
+
// so the callback can recover them without server-side state.
|
|
123
|
+
const stateCookie = await new SignJWT({
|
|
124
|
+
state,
|
|
125
|
+
codeVerifier,
|
|
126
|
+
returnTo,
|
|
127
|
+
})
|
|
128
|
+
.setProtectedHeader({ alg: 'HS256' })
|
|
129
|
+
.setIssuer('amodal-runtime')
|
|
130
|
+
.setIssuedAt()
|
|
131
|
+
.setExpirationTime(`${STATE_TTL_SECONDS}s`)
|
|
132
|
+
.sign(this.sessionKey);
|
|
133
|
+
setCookie(res, STATE_COOKIE, stateCookie, STATE_TTL_SECONDS);
|
|
134
|
+
const url = oidc.buildAuthorizationUrl(config, {
|
|
135
|
+
redirect_uri: this.opts.callbackUrl,
|
|
136
|
+
scope: this.opts.scopes.join(' '),
|
|
137
|
+
code_challenge: codeChallenge,
|
|
138
|
+
code_challenge_method: 'S256',
|
|
139
|
+
state,
|
|
140
|
+
});
|
|
141
|
+
res.redirect(url.href);
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
145
|
+
res.status(500).json({ error: { code: 'OIDC_LOGIN_FAILED', message } });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async handleCallback(req, res) {
|
|
149
|
+
try {
|
|
150
|
+
const stateCookie = readCookie(req, STATE_COOKIE);
|
|
151
|
+
if (!stateCookie) {
|
|
152
|
+
res.status(400).json({ error: { code: 'NO_STATE', message: 'OAuth state cookie missing' } });
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
let stateClaims;
|
|
156
|
+
try {
|
|
157
|
+
const verified = await jwtVerify(stateCookie, this.sessionKey, {
|
|
158
|
+
algorithms: ['HS256'],
|
|
159
|
+
issuer: 'amodal-runtime',
|
|
160
|
+
});
|
|
161
|
+
stateClaims = verified.payload;
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
165
|
+
res.status(400).json({ error: { code: 'BAD_STATE', message: `OAuth state invalid: ${detail}` } });
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
clearCookie(res, STATE_COOKIE);
|
|
169
|
+
const expectedState = typeof stateClaims['state'] === 'string' ? stateClaims['state'] : '';
|
|
170
|
+
const codeVerifier = typeof stateClaims['codeVerifier'] === 'string' ? stateClaims['codeVerifier'] : '';
|
|
171
|
+
const returnTo = typeof stateClaims['returnTo'] === 'string' ? stateClaims['returnTo'] : '/';
|
|
172
|
+
if (!expectedState || !codeVerifier) {
|
|
173
|
+
res.status(400).json({ error: { code: 'BAD_STATE', message: 'State payload malformed' } });
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const config = await this.config();
|
|
177
|
+
const fullUrl = new URL(req.originalUrl, `${req.protocol}://${req.get('host') ?? 'localhost'}`);
|
|
178
|
+
const tokens = await oidc.authorizationCodeGrant(config, fullUrl, {
|
|
179
|
+
pkceCodeVerifier: codeVerifier,
|
|
180
|
+
expectedState,
|
|
181
|
+
});
|
|
182
|
+
const claims = tokens.claims();
|
|
183
|
+
if (!claims) {
|
|
184
|
+
res.status(401).json({ error: { code: 'NO_CLAIMS', message: 'id_token missing claims' } });
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const user = await this.resolveUser(claims);
|
|
188
|
+
if (!user) {
|
|
189
|
+
res.status(403).json({ error: { code: 'FORBIDDEN', message: 'User not authorized for this agent' } });
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const sessionJwt = await new SignJWT({
|
|
193
|
+
sub: user.id,
|
|
194
|
+
...(user.email ? { email: user.email } : {}),
|
|
195
|
+
...(user.name ? { name: user.name } : {}),
|
|
196
|
+
claims: { ...claims },
|
|
197
|
+
})
|
|
198
|
+
.setProtectedHeader({ alg: 'HS256' })
|
|
199
|
+
.setIssuer('amodal-runtime')
|
|
200
|
+
.setSubject(user.id)
|
|
201
|
+
.setIssuedAt()
|
|
202
|
+
.setExpirationTime(`${this.opts.sessionTtlSeconds}s`)
|
|
203
|
+
.sign(this.sessionKey);
|
|
204
|
+
setCookie(res, this.opts.cookieName, sessionJwt, this.opts.sessionTtlSeconds);
|
|
205
|
+
res.redirect(returnTo);
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
209
|
+
res.status(500).json({ error: { code: 'OIDC_CALLBACK_FAILED', message } });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async resolveUser(claims) {
|
|
213
|
+
if (this.opts.authorize) {
|
|
214
|
+
const result = await this.opts.authorize(claims);
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
const id = typeof claims['sub'] === 'string' ? claims['sub'] : null;
|
|
218
|
+
if (!id)
|
|
219
|
+
return null;
|
|
220
|
+
const out = { id };
|
|
221
|
+
if (typeof claims['email'] === 'string')
|
|
222
|
+
out.email = claims['email'];
|
|
223
|
+
if (typeof claims['name'] === 'string')
|
|
224
|
+
out.name = claims['name'];
|
|
225
|
+
return out;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Defensive narrowing for the `claims` blob we round-trip through the
|
|
230
|
+
* session JWT. Anything other than a plain object yields an empty
|
|
231
|
+
* record; avoids a blanket `as Record<string, unknown>` cast on data
|
|
232
|
+
* that started life as JSON.
|
|
233
|
+
*/
|
|
234
|
+
function readClaims(raw) {
|
|
235
|
+
if (raw == null || typeof raw !== 'object' || Array.isArray(raw))
|
|
236
|
+
return {};
|
|
237
|
+
const out = {};
|
|
238
|
+
for (const [k, v] of Object.entries(raw))
|
|
239
|
+
out[k] = v;
|
|
240
|
+
return out;
|
|
241
|
+
}
|
|
242
|
+
function readCookie(req, name) {
|
|
243
|
+
const header = req.headers['cookie'];
|
|
244
|
+
if (typeof header !== 'string' || header.length === 0)
|
|
245
|
+
return null;
|
|
246
|
+
for (const pair of header.split(';')) {
|
|
247
|
+
const trimmed = pair.trim();
|
|
248
|
+
const eq = trimmed.indexOf('=');
|
|
249
|
+
if (eq === -1)
|
|
250
|
+
continue;
|
|
251
|
+
if (trimmed.slice(0, eq) !== name)
|
|
252
|
+
continue;
|
|
253
|
+
const value = trimmed.slice(eq + 1);
|
|
254
|
+
return value.length > 0 ? decodeURIComponent(value) : null;
|
|
255
|
+
}
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
function setCookie(res, name, value, ttlSeconds) {
|
|
259
|
+
const parts = [
|
|
260
|
+
`${name}=${encodeURIComponent(value)}`,
|
|
261
|
+
'Path=/',
|
|
262
|
+
`Max-Age=${ttlSeconds}`,
|
|
263
|
+
'HttpOnly',
|
|
264
|
+
'Secure',
|
|
265
|
+
'SameSite=Lax',
|
|
266
|
+
];
|
|
267
|
+
appendSetCookie(res, parts.join('; '));
|
|
268
|
+
}
|
|
269
|
+
function clearCookie(res, name) {
|
|
270
|
+
appendSetCookie(res, `${name}=; Path=/; Max-Age=0; HttpOnly; Secure; SameSite=Lax`);
|
|
271
|
+
}
|
|
272
|
+
function appendSetCookie(res, value) {
|
|
273
|
+
const existing = res.getHeader('Set-Cookie');
|
|
274
|
+
if (existing == null) {
|
|
275
|
+
res.setHeader('Set-Cookie', value);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (Array.isArray(existing)) {
|
|
279
|
+
res.setHeader('Set-Cookie', [...existing, value]);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
res.setHeader('Set-Cookie', [String(existing), value]);
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=oidc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc.js","sourceRoot":"","sources":["../../../../src/auth/strategies/oidc.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAC,MAAM,EAAC,MAAM,SAAS,CAAC;AAE/B,OAAO,SAAS,MAAM,oBAAoB,CAAC;AAC3C,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AACtC,OAAO,EAAC,OAAO,EAAE,SAAS,EAAC,MAAM,MAAM,CAAC;AA+BxC,MAAM,YAAY,GAAG,oBAAoB,CAAC;AAC1C,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,CAAC;AAEjC,MAAM,OAAO,gBAAgB;IAClB,IAAI,GAAG,MAAM,CAAC;IACN,IAAI,CAMnB;IACe,UAAU,CAAa;IAChC,gBAAgB,GAAuC,IAAI,CAAC;IAEpE,YAAY,OAAgC;QAC1C,IAAI,CAAC,IAAI,GAAG;YACV,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC;YACxD,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,gBAAgB;YAClD,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,IAAI,EAAE,GAAG,IAAI;YACzD,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,MAAM;YACxC,qBAAqB,EAAE,OAAO,CAAC,qBAAqB,IAAI,KAAK;SAC9D,CAAC;QACF,IAAI,OAAO,CAAC,SAAS;YAAE,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QAC/D,IAAI,CAAC,UAAU,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,GAAY;QAChB,OAAO,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,GAAY;QAC7B,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM;YAAE,OAAO,EAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,mBAAmB,EAAC,CAAC;QAEpE,IAAI,OAAmB,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE;gBACtD,UAAU,EAAE,CAAC,OAAO,CAAC;gBACrB,MAAM,EAAE,gBAAgB;aACzB,CAAC,CAAC;YACH,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAChE,OAAO,EAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,wBAAwB,MAAM,EAAE,EAAC,CAAC;QACtE,CAAC;QAED,MAAM,OAAO,GAAgB;YAC3B,IAAI,EAAE;gBACJ,EAAE,EAAE,OAAO,OAAO,CAAC,KAAK,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;gBAC5D,GAAG,CAAC,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1E,GAAG,CAAC,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;aACxE;YACD,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU;YAC5B,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;SACtC,CAAC;QACF,OAAO,EAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAC,CAAC;IAC1C,CAAC;IAED,MAAM;QACJ,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;QACxB,+DAA+D;QAC/D,+DAA+D;QAC/D,2DAA2D;QAC3D,2DAA2D;QAC3D,gEAAgE;QAChE,0CAA0C;QAC1C,MAAM,WAAW,GAAG,SAAS,CAAC;YAC5B,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI;YACxB,GAAG,EAAE,EAAE;YACP,eAAe,EAAE,IAAI;YACrB,aAAa,EAAE,KAAK;SACrB,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAClD,KAAK,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YACrD,KAAK,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;YACxC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACvC,GAAG,CAAC,IAAI,CAAC,EAAC,EAAE,EAAE,IAAI,EAAC,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,4EAA4E;IAEpE,KAAK,CAAC,MAAM;QAClB,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC3B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,SAAS,CACpC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAClB,IAAI,CAAC,IAAI,CAAC,YAAY,EACtB,SAAS,EACT,IAAI,CAAC,IAAI,CAAC,qBAAqB;gBAC7B,CAAC,CAAC,EAAC,OAAO,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,EAAC;gBACzC,CAAC,CAAC,SAAS,CACd,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,GAAY,EAAE,GAAa;QACnD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;YACnC,MAAM,YAAY,GAAG,IAAI,CAAC,sBAAsB,EAAE,CAAC;YACnD,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,0BAA0B,CAAC,YAAY,CAAC,CAAC;YAC1E,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YACjC,MAAM,QAAQ,GAAG,OAAO,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YAE3F,wEAAwE;YACxE,8DAA8D;YAC9D,MAAM,WAAW,GAAG,MAAM,IAAI,OAAO,CAAC;gBACpC,KAAK;gBACL,YAAY;gBACZ,QAAQ;aACT,CAAC;iBACC,kBAAkB,CAAC,EAAC,GAAG,EAAE,OAAO,EAAC,CAAC;iBAClC,SAAS,CAAC,gBAAgB,CAAC;iBAC3B,WAAW,EAAE;iBACb,iBAAiB,CAAC,GAAG,iBAAiB,GAAG,CAAC;iBAC1C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAEzB,SAAS,CAAC,GAAG,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,CAAC,CAAC;YAE7D,MAAM,GAAG,GAAG,IAAI,CAAC,qBAAqB,CAAC,MAAM,EAAE;gBAC7C,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW;gBACnC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;gBACjC,cAAc,EAAE,aAAa;gBAC7B,qBAAqB,EAAE,MAAM;gBAC7B,KAAK;aACN,CAAC,CAAC;YACH,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAC,KAAK,EAAE,EAAC,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAC,EAAC,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,GAAY,EAAE,GAAa;QACtD,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;YAClD,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAC,KAAK,EAAE,EAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,4BAA4B,EAAC,EAAC,CAAC,CAAC;gBACzF,OAAO;YACT,CAAC;YAED,IAAI,WAAuB,CAAC;YAC5B,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,UAAU,EAAE;oBAC7D,UAAU,EAAE,CAAC,OAAO,CAAC;oBACrB,MAAM,EAAE,gBAAgB;iBACzB,CAAC,CAAC;gBACH,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC;YACjC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAChE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAC,KAAK,EAAE,EAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,wBAAwB,MAAM,EAAE,EAAC,EAAC,CAAC,CAAC;gBAC9F,OAAO;YACT,CAAC;YAED,WAAW,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;YAE/B,MAAM,aAAa,GAAG,OAAO,WAAW,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3F,MAAM,YAAY,GAAG,OAAO,WAAW,CAAC,cAAc,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACxG,MAAM,QAAQ,GAAG,OAAO,WAAW,CAAC,UAAU,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YAC7F,IAAI,CAAC,aAAa,IAAI,CAAC,YAAY,EAAE,CAAC;gBACpC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAC,KAAK,EAAE,EAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,yBAAyB,EAAC,EAAC,CAAC,CAAC;gBACvF,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;YACnC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,QAAQ,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC;YAChG,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE;gBAChE,gBAAgB,EAAE,YAAY;gBAC9B,aAAa;aACd,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;YAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAC,KAAK,EAAE,EAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,yBAAyB,EAAC,EAAC,CAAC,CAAC;gBACvF,OAAO;YACT,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAC5C,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAC,KAAK,EAAE,EAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,oCAAoC,EAAC,EAAC,CAAC,CAAC;gBAClG,OAAO;YACT,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,IAAI,OAAO,CAAC;gBACnC,GAAG,EAAE,IAAI,CAAC,EAAE;gBACZ,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1C,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvC,MAAM,EAAE,EAAC,GAAG,MAAM,EAAC;aACpB,CAAC;iBACC,kBAAkB,CAAC,EAAC,GAAG,EAAE,OAAO,EAAC,CAAC;iBAClC,SAAS,CAAC,gBAAgB,CAAC;iBAC3B,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;iBACnB,WAAW,EAAE;iBACb,iBAAiB,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,GAAG,CAAC;iBACpD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAEzB,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAC9E,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAC,KAAK,EAAE,EAAC,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAC,EAAC,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,MAAkB;QAC1C,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACjD,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,MAAM,EAAE,GAAG,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACpE,IAAI,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QACrB,MAAM,GAAG,GAAwB,EAAC,EAAE,EAAC,CAAC;QACtC,IAAI,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,QAAQ;YAAE,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;QACrE,IAAI,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,QAAQ;YAAE,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAClE,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AAED;;;;;GAKG;AACH,SAAS,UAAU,CAAC,GAAY;IAC9B,IAAI,GAAG,IAAI,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAC5E,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACrD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,UAAU,CAAC,GAAY,EAAE,IAAY;IAC5C,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnE,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,EAAE,KAAK,CAAC,CAAC;YAAE,SAAS;QACxB,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI;YAAE,SAAS;QAC5C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QACpC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7D,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,SAAS,CAAC,GAAa,EAAE,IAAY,EAAE,KAAa,EAAE,UAAkB;IAC/E,MAAM,KAAK,GAAG;QACZ,GAAG,IAAI,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE;QACtC,QAAQ;QACR,WAAW,UAAU,EAAE;QACvB,UAAU;QACV,QAAQ;QACR,cAAc;KACf,CAAC;IACF,eAAe,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,WAAW,CAAC,GAAa,EAAE,IAAY;IAC9C,eAAe,CAAC,GAAG,EAAE,GAAG,IAAI,sDAAsD,CAAC,CAAC;AACtF,CAAC;AAED,SAAS,eAAe,CAAC,GAAa,EAAE,KAAa;IACnD,MAAM,QAAQ,GAAG,GAAG,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAC7C,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;QACrB,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;QACnC,OAAO;IACT,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;QAClD,OAAO;IACT,CAAC;IACD,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AACzD,CAAC"}
|