@opengeni/api-router 2.5.0 → 2.6.4
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/app.js +1 -1
- package/dist/auth/managed-auth-attempt-context.d.ts +5 -1
- package/dist/auth/managed-auth.d.ts +24 -1
- package/dist/{chunk-QESX7HDK.js → chunk-XTLI3CBH.js} +2236 -387
- package/dist/chunk-XTLI3CBH.js.map +1 -0
- package/dist/http/sse.d.ts +9 -0
- package/dist/index.js +104 -4
- package/dist/index.js.map +1 -1
- package/dist/interaction-metrics.d.ts +2 -0
- package/dist/mcp/company-brain-governed-writes.d.ts +1 -1
- package/dist/mcp/company-profile-agent-admin.d.ts +6 -6
- package/dist/mcp/remember.d.ts +2 -2
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/session-view.d.ts +1 -0
- package/dist/mcp/session-wait.d.ts +19 -0
- package/dist/routes/api-keys.d.ts +2 -0
- package/dist/routes/browser-sessions.d.ts +1 -0
- package/dist/routes/computer-sessions.d.ts +12 -0
- package/dist/routes/managed-auth-session-sets.d.ts +7 -0
- package/dist/routes/workspaces.d.ts +1 -1
- package/dist/sandbox/metrics-ingestion.d.ts +16 -0
- package/dist/workspace-delete-observability.d.ts +10 -0
- package/package.json +15 -15
- package/src/app.ts +172 -20
- package/src/auth/managed-auth-attempt-context.ts +40 -3
- package/src/auth/managed-auth-session-adapter.ts +1 -0
- package/src/auth/managed-auth.ts +164 -4
- package/src/http/sse.ts +279 -45
- package/src/integrations/oauth-client.ts +8 -1
- package/src/integrations/provider-oauth.ts +12 -2
- package/src/interaction-metrics.ts +30 -0
- package/src/mcp/company-brain-governed-writes.ts +38 -23
- package/src/mcp/company-profile-agent-admin.ts +7 -7
- package/src/mcp/remember.ts +19 -8
- package/src/mcp/server.ts +318 -26
- package/src/mcp/session-wait.ts +56 -8
- package/src/routes/api-integrations.ts +2 -2
- package/src/routes/api-keys.ts +149 -7
- package/src/routes/browser-sessions.ts +10 -2
- package/src/routes/capabilities.ts +3 -3
- package/src/routes/codex.ts +483 -74
- package/src/routes/company-profile.ts +64 -0
- package/src/routes/computer-sessions.ts +103 -1
- package/src/routes/integration-facets.ts +8 -5
- package/src/routes/interaction-resources.ts +7 -1
- package/src/routes/managed-auth-session-sets.ts +199 -2
- package/src/routes/organization-memberships.ts +28 -8
- package/src/routes/packs.ts +5 -5
- package/src/routes/plugins.ts +2 -2
- package/src/routes/scheduled-tasks.ts +9 -0
- package/src/routes/sessions.ts +3 -6
- package/src/routes/skills.ts +3 -3
- package/src/routes/workspaces.ts +293 -54
- package/src/sandbox/channel-a.ts +10 -4
- package/src/sandbox/machines.ts +13 -6
- package/src/sandbox/metrics-ingestion.ts +157 -3
- package/src/sandbox/viewer.ts +20 -1
- package/src/workspace-delete-observability.ts +75 -0
- package/dist/chunk-QESX7HDK.js.map +0 -1
package/src/auth/managed-auth.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { canonicalPublicOrigin, type Settings } from "@opengeni/config";
|
|
2
2
|
import {
|
|
3
3
|
type ManagedAuth,
|
|
4
4
|
type ManagedEmailMessage,
|
|
@@ -20,7 +20,9 @@ import { Pool } from "pg";
|
|
|
20
20
|
|
|
21
21
|
import { decideCanonicalHumanSessionAdmission } from "./canonical-human-session-admission";
|
|
22
22
|
import {
|
|
23
|
+
currentManagedAuthProviderId,
|
|
23
24
|
currentManagedAuthAttemptId,
|
|
25
|
+
recordCurrentManagedAuthSession,
|
|
24
26
|
shouldDiscardCurrentManagedAuthProviderSession,
|
|
25
27
|
} from "./managed-auth-attempt-context";
|
|
26
28
|
|
|
@@ -44,6 +46,21 @@ export function managedAuthUserCreateOverride(
|
|
|
44
46
|
return { data: { ...user, emailVerified: true } };
|
|
45
47
|
}
|
|
46
48
|
|
|
49
|
+
export function managedAuthUserCreateAdmission(
|
|
50
|
+
settings: Pick<Settings, "environment">,
|
|
51
|
+
user: { emailVerified: boolean } & Record<string, unknown>,
|
|
52
|
+
providerId: string,
|
|
53
|
+
): { data: typeof user } | false | undefined {
|
|
54
|
+
if (
|
|
55
|
+
managedAuthRequiresEmailVerification(settings) &&
|
|
56
|
+
providerId !== "credential" &&
|
|
57
|
+
!user.emailVerified
|
|
58
|
+
) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return managedAuthUserCreateOverride(settings, user);
|
|
62
|
+
}
|
|
63
|
+
|
|
47
64
|
/** Keep Better Auth password policy and storage format behind this boundary. */
|
|
48
65
|
export async function hashManagedAuthPassword(password: string): Promise<string> {
|
|
49
66
|
return await hashPassword(password);
|
|
@@ -165,6 +182,27 @@ export function createManagedAuth(
|
|
|
165
182
|
accountLinking: {
|
|
166
183
|
enabled: false,
|
|
167
184
|
},
|
|
185
|
+
encryptOAuthTokens: true,
|
|
186
|
+
storeStateStrategy: "database",
|
|
187
|
+
},
|
|
188
|
+
socialProviders: {
|
|
189
|
+
...(settings.managedAuthGoogleClientId && settings.managedAuthGoogleClientSecret
|
|
190
|
+
? {
|
|
191
|
+
google: {
|
|
192
|
+
clientId: settings.managedAuthGoogleClientId,
|
|
193
|
+
clientSecret: settings.managedAuthGoogleClientSecret,
|
|
194
|
+
prompt: "select_account" as const,
|
|
195
|
+
},
|
|
196
|
+
}
|
|
197
|
+
: {}),
|
|
198
|
+
...(settings.managedAuthGithubClientId && settings.managedAuthGithubClientSecret
|
|
199
|
+
? {
|
|
200
|
+
github: {
|
|
201
|
+
clientId: settings.managedAuthGithubClientId,
|
|
202
|
+
clientSecret: settings.managedAuthGithubClientSecret,
|
|
203
|
+
},
|
|
204
|
+
}
|
|
205
|
+
: {}),
|
|
168
206
|
},
|
|
169
207
|
verification: {
|
|
170
208
|
modelName: "auth_verifications",
|
|
@@ -229,6 +267,7 @@ export function createManagedAuth(
|
|
|
229
267
|
session: {
|
|
230
268
|
create: {
|
|
231
269
|
before: async (session) => {
|
|
270
|
+
const providerId = currentManagedAuthProviderId();
|
|
232
271
|
await ensureCanonicalHumanIdentityForAuthUser(db, session.userId);
|
|
233
272
|
const preflightProjection = await getCanonicalHumanIdentityProjection(
|
|
234
273
|
db,
|
|
@@ -242,7 +281,7 @@ export function createManagedAuth(
|
|
|
242
281
|
if (!preflight.allowed) {
|
|
243
282
|
const exactRecoveryBinding = await getCanonicalHumanExactLoginBindingForAuthUser(db, {
|
|
244
283
|
authUserId: session.userId,
|
|
245
|
-
providerId
|
|
284
|
+
providerId,
|
|
246
285
|
});
|
|
247
286
|
const recoveryBinding = preflightProjection.loginBindings.find(
|
|
248
287
|
(binding) =>
|
|
@@ -282,7 +321,7 @@ export function createManagedAuth(
|
|
|
282
321
|
const projection = await getCanonicalHumanIdentityProjection(db, session.userId);
|
|
283
322
|
const exactBinding = await getCanonicalHumanExactLoginBindingForAuthUser(db, {
|
|
284
323
|
authUserId: session.userId,
|
|
285
|
-
providerId
|
|
324
|
+
providerId,
|
|
286
325
|
});
|
|
287
326
|
const activeBinding = projection.loginBindings.find(
|
|
288
327
|
(binding) => binding.id === exactBinding.id,
|
|
@@ -318,6 +357,7 @@ export function createManagedAuth(
|
|
|
318
357
|
};
|
|
319
358
|
},
|
|
320
359
|
after: async (session) => {
|
|
360
|
+
recordCurrentManagedAuthSession(session.id);
|
|
321
361
|
if (!shouldDiscardCurrentManagedAuthProviderSession()) return;
|
|
322
362
|
await db.execute(sql`delete from auth_sessions where id = ${session.id}`);
|
|
323
363
|
},
|
|
@@ -325,7 +365,8 @@ export function createManagedAuth(
|
|
|
325
365
|
},
|
|
326
366
|
user: {
|
|
327
367
|
create: {
|
|
328
|
-
before: async (user) =>
|
|
368
|
+
before: async (user) =>
|
|
369
|
+
managedAuthUserCreateAdmission(settings, user, currentManagedAuthProviderId()),
|
|
329
370
|
after: async (user) => {
|
|
330
371
|
if (!user.emailVerified) return;
|
|
331
372
|
await ensureManagedAccessForUser(db, {
|
|
@@ -342,6 +383,125 @@ export function createManagedAuth(
|
|
|
342
383
|
}) as ManagedAuth;
|
|
343
384
|
}
|
|
344
385
|
|
|
386
|
+
export type ManagedAuthOAuthAttempt = {
|
|
387
|
+
transactionId: string;
|
|
388
|
+
provider: "google" | "github";
|
|
389
|
+
authorityHash: string;
|
|
390
|
+
transactionSecretHash: string;
|
|
391
|
+
expectedGeneration: string;
|
|
392
|
+
expectedActorEpoch: string;
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Resolve OpenGeni's server-only login transaction proof from Better Auth's
|
|
397
|
+
* database-backed OAuth state before the provider callback consumes it.
|
|
398
|
+
*/
|
|
399
|
+
export async function resolveManagedAuthOAuthAttempt(
|
|
400
|
+
auth: ManagedAuth,
|
|
401
|
+
request: Request,
|
|
402
|
+
provider: "google" | "github",
|
|
403
|
+
publicBaseUrl: string,
|
|
404
|
+
): Promise<ManagedAuthOAuthAttempt | null> {
|
|
405
|
+
const expectedOrigin = canonicalPublicOrigin(publicBaseUrl);
|
|
406
|
+
if (!expectedOrigin) return null;
|
|
407
|
+
const state = new URL(request.url).searchParams.get("state");
|
|
408
|
+
if (!state) return null;
|
|
409
|
+
const verification = await (await auth.$context).internalAdapter.findVerificationValue(state);
|
|
410
|
+
if (!verification?.value) return null;
|
|
411
|
+
let parsed: unknown;
|
|
412
|
+
try {
|
|
413
|
+
parsed = JSON.parse(verification.value);
|
|
414
|
+
} catch {
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
418
|
+
const stateData = parsed as Record<string, unknown>;
|
|
419
|
+
const proof = stateData.opengeniManagedAuth;
|
|
420
|
+
if (!proof || typeof proof !== "object") return null;
|
|
421
|
+
const value = proof as Record<string, unknown>;
|
|
422
|
+
if (
|
|
423
|
+
value.version !== 1 ||
|
|
424
|
+
value.provider !== provider ||
|
|
425
|
+
typeof value.transactionId !== "string" ||
|
|
426
|
+
typeof value.authorityHash !== "string" ||
|
|
427
|
+
typeof value.transactionSecretHash !== "string" ||
|
|
428
|
+
typeof value.expectedGeneration !== "string" ||
|
|
429
|
+
typeof value.expectedActorEpoch !== "string" ||
|
|
430
|
+
!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(
|
|
431
|
+
value.transactionId,
|
|
432
|
+
) ||
|
|
433
|
+
!/^[0-9a-f]{64}$/u.test(value.authorityHash) ||
|
|
434
|
+
!/^[0-9a-f]{64}$/u.test(value.transactionSecretHash) ||
|
|
435
|
+
!/^[1-9][0-9]*$/u.test(value.expectedGeneration) ||
|
|
436
|
+
!/^[1-9][0-9]*$/u.test(value.expectedActorEpoch)
|
|
437
|
+
) {
|
|
438
|
+
return null;
|
|
439
|
+
}
|
|
440
|
+
const callbackURL = typeof stateData.callbackURL === "string" ? stateData.callbackURL : null;
|
|
441
|
+
const errorURL = typeof stateData.errorURL === "string" ? stateData.errorURL : null;
|
|
442
|
+
if (
|
|
443
|
+
!callbackURL ||
|
|
444
|
+
!errorURL ||
|
|
445
|
+
!managedAuthOAuthReturnMatches(callbackURL, expectedOrigin, value.transactionId, "complete") ||
|
|
446
|
+
!managedAuthOAuthReturnMatches(errorURL, expectedOrigin, value.transactionId, "error")
|
|
447
|
+
) {
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
return {
|
|
451
|
+
transactionId: value.transactionId,
|
|
452
|
+
provider,
|
|
453
|
+
authorityHash: value.authorityHash,
|
|
454
|
+
transactionSecretHash: value.transactionSecretHash,
|
|
455
|
+
expectedGeneration: value.expectedGeneration,
|
|
456
|
+
expectedActorEpoch: value.expectedActorEpoch,
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
export async function isolatedManagedAuthOAuthCallbackRequest(
|
|
461
|
+
auth: ManagedAuth,
|
|
462
|
+
request: Request,
|
|
463
|
+
): Promise<{ request: Request; stateCookieName: string }> {
|
|
464
|
+
const context = await auth.$context;
|
|
465
|
+
const stateCookieName = context.createAuthCookie("state").name;
|
|
466
|
+
const headers = new Headers(request.headers);
|
|
467
|
+
const stateCookie = cookiePair(headers.get("cookie"), stateCookieName);
|
|
468
|
+
if (stateCookie) headers.set("cookie", stateCookie);
|
|
469
|
+
else headers.delete("cookie");
|
|
470
|
+
headers.delete("authorization");
|
|
471
|
+
headers.delete("x-forwarded-user");
|
|
472
|
+
return { request: new Request(request, { headers }), stateCookieName };
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
export function managedAuthOAuthReturnMatches(
|
|
476
|
+
raw: string,
|
|
477
|
+
expectedOrigin: string,
|
|
478
|
+
transactionId: string,
|
|
479
|
+
outcome: "complete" | "error",
|
|
480
|
+
): boolean {
|
|
481
|
+
try {
|
|
482
|
+
const url = new URL(raw);
|
|
483
|
+
return (
|
|
484
|
+
url.origin === expectedOrigin &&
|
|
485
|
+
url.pathname === "/account-auth" &&
|
|
486
|
+
url.searchParams.size === 2 &&
|
|
487
|
+
url.searchParams.get("transaction") === transactionId &&
|
|
488
|
+
url.searchParams.get("social") === outcome &&
|
|
489
|
+
!url.hash
|
|
490
|
+
);
|
|
491
|
+
} catch {
|
|
492
|
+
return false;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function cookiePair(header: string | null, name: string): string | null {
|
|
497
|
+
for (const part of header?.split(";") ?? []) {
|
|
498
|
+
const separator = part.indexOf("=");
|
|
499
|
+
if (separator < 0 || part.slice(0, separator).trim() !== name) continue;
|
|
500
|
+
return `${name}=${part.slice(separator + 1).trim()}`;
|
|
501
|
+
}
|
|
502
|
+
return null;
|
|
503
|
+
}
|
|
504
|
+
|
|
345
505
|
function betterAuthBaseUrl(settings: Settings) {
|
|
346
506
|
const allowedHosts = splitCsv(settings.betterAuthAllowedHosts);
|
|
347
507
|
if (allowedHosts.length === 0) {
|