@opengeni/core 2.4.0-canary.2 → 2.5.2-canary.0
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/access/index.d.ts +2 -0
- package/dist/application/composer-submit.d.ts +24 -0
- package/dist/application/session-commands.d.ts +4 -2
- package/dist/canonical-human-identities.d.ts +7 -2
- package/dist/canonical-human-identities.js +17 -4
- package/dist/canonical-human-identities.js.map +1 -1
- package/dist/chunk-YGOMUGYS.js +226 -0
- package/dist/chunk-YGOMUGYS.js.map +1 -0
- package/dist/chunk-ZVZJTMSV.js +369 -0
- package/dist/chunk-ZVZJTMSV.js.map +1 -0
- package/dist/dependencies.d.ts +3 -0
- package/dist/domain/sessions.d.ts +4 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +134 -47
- package/dist/index.js.map +1 -1
- package/dist/managed-auth-session-sets.d.ts +113 -0
- package/dist/managed-auth-session-sets.js +49 -0
- package/dist/managed-auth-session-sets.js.map +1 -0
- package/dist/managed-session.d.ts +47 -3
- package/package.json +14 -10
- package/src/access/index.ts +8 -1
- package/src/application/composer-submit.ts +76 -0
- package/src/application/session-commands.ts +80 -48
- package/src/canonical-human-identities.ts +22 -3
- package/src/dependencies.ts +3 -0
- package/src/domain/sessions.ts +22 -0
- package/src/index.ts +14 -1
- package/src/managed-auth-session-sets.ts +344 -0
- package/src/managed-session.ts +488 -1
- package/dist/chunk-IBOEYG6N.js +0 -34
- package/dist/chunk-IBOEYG6N.js.map +0 -1
package/src/domain/sessions.ts
CHANGED
|
@@ -1204,6 +1204,8 @@ export async function postUserMessageTurn(input: {
|
|
|
1204
1204
|
annotations?: TimelineAnnotation[];
|
|
1205
1205
|
modelContext?: string | null;
|
|
1206
1206
|
resources: ResourceRef[];
|
|
1207
|
+
/** Actor-owned resources used only for the exact durable-draft fence. */
|
|
1208
|
+
composerDraftResources?: ResourceRef[];
|
|
1207
1209
|
model?: string | null;
|
|
1208
1210
|
reasoningEffort?: Settings["openaiReasoningEffort"] | null;
|
|
1209
1211
|
latencyMode?: "standard" | "priority" | "fast" | null;
|
|
@@ -1281,6 +1283,9 @@ export async function postUserMessageTurn(input: {
|
|
|
1281
1283
|
annotations: input.annotations ?? [],
|
|
1282
1284
|
modelContext: input.modelContext ?? null,
|
|
1283
1285
|
resources: input.resources,
|
|
1286
|
+
...(input.composerDraftResources
|
|
1287
|
+
? { composerDraftResources: input.composerDraftResources }
|
|
1288
|
+
: {}),
|
|
1284
1289
|
model: requestedModel,
|
|
1285
1290
|
reasoningEffort: requestedReasoningEffort,
|
|
1286
1291
|
latencyMode: input.latencyMode ?? null,
|
|
@@ -2429,6 +2434,8 @@ export async function acceptSessionUserMessageWithOutcome(
|
|
|
2429
2434
|
annotations?: SubmittedTimelineAnnotation[];
|
|
2430
2435
|
modelContext?: string | null;
|
|
2431
2436
|
resources?: ResourceRef[];
|
|
2437
|
+
/** Actor-owned resources used only for the exact durable-draft fence. */
|
|
2438
|
+
composerDraftResources?: ResourceRef[];
|
|
2432
2439
|
model?: string | null;
|
|
2433
2440
|
reasoningEffort?: ReasoningEffort | null;
|
|
2434
2441
|
latencyMode?: "standard" | "priority" | "fast" | null;
|
|
@@ -2497,6 +2504,20 @@ export async function acceptSessionUserMessageWithOutcome(
|
|
|
2497
2504
|
latencyModeSource: input.latencyMode == null ? "session" : "explicit",
|
|
2498
2505
|
});
|
|
2499
2506
|
const requestedResources = normalizeResources(input.resources ?? []);
|
|
2507
|
+
const composerDraftResources = input.composerDraftResources
|
|
2508
|
+
? normalizeResources(input.composerDraftResources)
|
|
2509
|
+
: undefined;
|
|
2510
|
+
if (composerDraftResources) {
|
|
2511
|
+
const acceptedResources = new Set(requestedResources.map((resource) => stableJson(resource)));
|
|
2512
|
+
const unacceptedDraftResource = composerDraftResources.find(
|
|
2513
|
+
(resource) => !acceptedResources.has(stableJson(resource)),
|
|
2514
|
+
);
|
|
2515
|
+
if (unacceptedDraftResource) {
|
|
2516
|
+
throw new HTTPException(422, {
|
|
2517
|
+
message: "composer draft resources must be included in the accepted resource set",
|
|
2518
|
+
});
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2500
2521
|
const annotations = await validateSubmittedTimelineAnnotations(
|
|
2501
2522
|
db,
|
|
2502
2523
|
workspaceId,
|
|
@@ -2585,6 +2606,7 @@ export async function acceptSessionUserMessageWithOutcome(
|
|
|
2585
2606
|
annotations,
|
|
2586
2607
|
modelContext: input.modelContext ?? null,
|
|
2587
2608
|
resources: requestedResources,
|
|
2609
|
+
...(composerDraftResources ? { composerDraftResources } : {}),
|
|
2588
2610
|
model: input.model ?? null,
|
|
2589
2611
|
reasoningEffort: input.reasoningEffort ?? null,
|
|
2590
2612
|
latencyMode: input.latencyMode ?? null,
|
package/src/index.ts
CHANGED
|
@@ -35,7 +35,19 @@ export * from "./workflow-wake-contract";
|
|
|
35
35
|
// structural TYPES live here.
|
|
36
36
|
export * from "./sandbox-types";
|
|
37
37
|
export * from "./managed-auth-type";
|
|
38
|
-
export
|
|
38
|
+
export {
|
|
39
|
+
getManagedAuthRequestActorAbortSignal,
|
|
40
|
+
getManagedAuthRequestActorAdmissionStamp,
|
|
41
|
+
getManagedAuthRequestActorEpoch,
|
|
42
|
+
getManagedAuthRequestActorLeaseStamp,
|
|
43
|
+
getManagedSession,
|
|
44
|
+
ManagedAuthActorLeaseOutcomeUnknownError,
|
|
45
|
+
markManagedAuthRequestActorTransitionApplied,
|
|
46
|
+
releaseManagedAuthRequestActorLease,
|
|
47
|
+
validateManagedAuthRequestActorLease,
|
|
48
|
+
type ManagedAuthActorAdmissionStamp,
|
|
49
|
+
type ManagedAuthActorMutationLeaseStamp,
|
|
50
|
+
} from "./managed-session";
|
|
39
51
|
export * from "./transcription";
|
|
40
52
|
|
|
41
53
|
// Sandbox fleet/routing service — the closure of `domain/sessions.ts`
|
|
@@ -87,6 +99,7 @@ export * from "./domain/video-generation";
|
|
|
87
99
|
export * from "./domain/video-generation-capabilities";
|
|
88
100
|
export * from "./domain/organization-membership-lifecycle";
|
|
89
101
|
export * from "./application/new-session-drafts";
|
|
102
|
+
export * from "./application/composer-submit";
|
|
90
103
|
export * from "./application/session-commands";
|
|
91
104
|
export * from "./application/session-tenancy";
|
|
92
105
|
export * from "./application/user-resource-grants";
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { createHash, createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import type {
|
|
3
|
+
ManagedAuthSessionSetMode,
|
|
4
|
+
ManagedAuthSessionSetProjection,
|
|
5
|
+
} from "@opengeni/contracts/managed-auth-session-sets";
|
|
6
|
+
import {
|
|
7
|
+
completeManagedAuthLoginTransaction,
|
|
8
|
+
getManagedAuthSessionSetOperationReceipt,
|
|
9
|
+
getManagedAuthSessionSetSnapshot,
|
|
10
|
+
type Database,
|
|
11
|
+
type ManagedAuthDatabaseProjection,
|
|
12
|
+
type ManagedAuthSelectedSession,
|
|
13
|
+
} from "@opengeni/db";
|
|
14
|
+
|
|
15
|
+
export const MANAGED_AUTH_SESSION_SET_COOKIE = "opengeni.session_set" as const;
|
|
16
|
+
export const MANAGED_AUTH_LOGIN_TRANSACTION_COOKIE = "opengeni.login_transaction" as const;
|
|
17
|
+
export const MANAGED_AUTH_CSRF_HEADER = "x-opengeni-session-csrf" as const;
|
|
18
|
+
export const MANAGED_AUTH_ACTOR_EPOCH_HEADER = "x-opengeni-actor-epoch" as const;
|
|
19
|
+
export const MANAGED_AUTH_LOGIN_TRANSACTION_COOKIE_PATH =
|
|
20
|
+
"/v1/auth/session-set/transactions" as const;
|
|
21
|
+
|
|
22
|
+
export type ManagedAuthResolvedSession = {
|
|
23
|
+
session: { id: string; userId: string; [key: string]: unknown };
|
|
24
|
+
user: {
|
|
25
|
+
id: string;
|
|
26
|
+
email: string;
|
|
27
|
+
name: string;
|
|
28
|
+
emailVerified: boolean;
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** Provider-neutral boundary; provider credentials and tokens never cross its output. */
|
|
34
|
+
export interface ManagedAuthSessionAdapter {
|
|
35
|
+
authenticate(input: {
|
|
36
|
+
provider: "email_password";
|
|
37
|
+
transactionId: string;
|
|
38
|
+
credentials: { email: string; password: string };
|
|
39
|
+
headers: Headers;
|
|
40
|
+
}): Promise<{ authSessionId: string }>;
|
|
41
|
+
/** Verify an ambient provider cookie without sliding expiry or emitting cookies. */
|
|
42
|
+
resolveAmbientSession(headers: Headers): Promise<ManagedAuthResolvedSession | null>;
|
|
43
|
+
resolveSelectedSession(
|
|
44
|
+
input: ManagedAuthSelectedSession,
|
|
45
|
+
): Promise<ManagedAuthResolvedSession | null>;
|
|
46
|
+
refreshSelectedSession(
|
|
47
|
+
input: ManagedAuthSelectedSession,
|
|
48
|
+
): Promise<ManagedAuthResolvedSession | null>;
|
|
49
|
+
revokeSession(input: { authSessionId: string }): Promise<void>;
|
|
50
|
+
/** Dual-mode exact selected-session cookie plus stale provider-cache invalidations. */
|
|
51
|
+
createLegacySelectedSessionCookies(
|
|
52
|
+
input: ManagedAuthSelectedSession | null,
|
|
53
|
+
currentCookieHeader?: string | null,
|
|
54
|
+
): Promise<string[]>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export class ManagedAuthActorChangeError extends Error {
|
|
58
|
+
readonly name = "ManagedAuthActorChangeError";
|
|
59
|
+
readonly code = "actor_change_required";
|
|
60
|
+
constructor() {
|
|
61
|
+
super("The selected browser actor changed");
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export class ManagedAuthRequestAdmissionError extends Error {
|
|
66
|
+
readonly name = "ManagedAuthRequestAdmissionError";
|
|
67
|
+
readonly code = "origin_rejected";
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export class ManagedAuthCompletionOutcomeUnknownError extends Error {
|
|
71
|
+
readonly name = "ManagedAuthCompletionOutcomeUnknownError";
|
|
72
|
+
readonly code = "operation_outcome_unknown";
|
|
73
|
+
constructor(options?: ErrorOptions) {
|
|
74
|
+
super("The managed authentication completion outcome is unknown", options);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function requireManagedAuthActorFence(input: {
|
|
79
|
+
mode: ManagedAuthSessionSetMode;
|
|
80
|
+
actorEpoch: string;
|
|
81
|
+
expectedActorEpoch: string | null;
|
|
82
|
+
selectedAuthSessionId: string | null;
|
|
83
|
+
legacyAmbientSessionId?: string | null;
|
|
84
|
+
}): void {
|
|
85
|
+
if (
|
|
86
|
+
(input.expectedActorEpoch !== null && input.expectedActorEpoch !== input.actorEpoch) ||
|
|
87
|
+
(input.expectedActorEpoch === null &&
|
|
88
|
+
(input.mode === "broker" ||
|
|
89
|
+
input.actorEpoch !== "1" ||
|
|
90
|
+
(input.selectedAuthSessionId !== null &&
|
|
91
|
+
input.legacyAmbientSessionId !== input.selectedAuthSessionId)))
|
|
92
|
+
) {
|
|
93
|
+
throw new ManagedAuthActorChangeError();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function managedAuthRandomAuthority(): string {
|
|
98
|
+
return randomBytes(32).toString("base64url");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function managedAuthSha256(value: string): string {
|
|
102
|
+
return createHash("sha256").update(value, "utf8").digest("hex");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function managedAuthCsrfHash(authority: string): string {
|
|
106
|
+
return managedAuthSha256(`opengeni:managed-auth:csrf-authority:v1\n${authority}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function managedAuthCsrfToken(
|
|
110
|
+
signingSecret: string,
|
|
111
|
+
authority: string,
|
|
112
|
+
generation: string,
|
|
113
|
+
): string {
|
|
114
|
+
return createHmac("sha256", signingSecret)
|
|
115
|
+
.update(`opengeni:managed-auth:csrf:v1\n${authority}\n${generation}`, "utf8")
|
|
116
|
+
.digest("base64url");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function managedAuthTransactionSecret(
|
|
120
|
+
signingSecret: string,
|
|
121
|
+
authority: string,
|
|
122
|
+
operationId: string,
|
|
123
|
+
): string {
|
|
124
|
+
return createHmac("sha256", signingSecret)
|
|
125
|
+
.update(`opengeni:managed-auth:transaction:v1\n${authority}\n${operationId}`, "utf8")
|
|
126
|
+
.digest("base64url");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function managedAuthDerivedUuid(namespace: string, value: string): string {
|
|
130
|
+
const bytes = createHash("sha256")
|
|
131
|
+
.update(`${namespace}\n${value}`, "utf8")
|
|
132
|
+
.digest()
|
|
133
|
+
.subarray(0, 16);
|
|
134
|
+
bytes[6] = (bytes[6]! & 0x0f) | 0x50;
|
|
135
|
+
bytes[8] = (bytes[8]! & 0x3f) | 0x80;
|
|
136
|
+
const hex = bytes.toString("hex");
|
|
137
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function canonicalJson(value: unknown): string {
|
|
141
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
142
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
143
|
+
return `{${Object.entries(value as Record<string, unknown>)
|
|
144
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
145
|
+
.map(([key, child]) => `${JSON.stringify(key)}:${canonicalJson(child)}`)
|
|
146
|
+
.join(",")}}`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function managedAuthRequestDigest(value: unknown): string {
|
|
150
|
+
return managedAuthSha256(canonicalJson(value));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function managedAuthSecretRequestDigest(signingSecret: string, value: unknown): string {
|
|
154
|
+
return createHmac("sha256", signingSecret)
|
|
155
|
+
.update(`opengeni:managed-auth:request:v1\n${canonicalJson(value)}`, "utf8")
|
|
156
|
+
.digest("hex");
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function withManagedAuthCsrfToken(
|
|
160
|
+
projection: ManagedAuthDatabaseProjection,
|
|
161
|
+
signingSecret: string,
|
|
162
|
+
authority: string,
|
|
163
|
+
): ManagedAuthSessionSetProjection {
|
|
164
|
+
return {
|
|
165
|
+
...projection,
|
|
166
|
+
csrfToken: managedAuthCsrfToken(signingSecret, authority, projection.generation),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function equalSecret(left: string, right: string): boolean {
|
|
171
|
+
const leftBytes = Buffer.from(left, "utf8");
|
|
172
|
+
const rightBytes = Buffer.from(right, "utf8");
|
|
173
|
+
return leftBytes.length === rightBytes.length && timingSafeEqual(leftBytes, rightBytes);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function requireManagedAuthMutationAdmission(input: {
|
|
177
|
+
request: Request;
|
|
178
|
+
allowedOrigins: readonly string[];
|
|
179
|
+
authority: string;
|
|
180
|
+
signingSecret: string;
|
|
181
|
+
expectedGeneration: string;
|
|
182
|
+
}): void {
|
|
183
|
+
const origin = input.request.headers.get("origin");
|
|
184
|
+
const fetchSite = input.request.headers.get("sec-fetch-site");
|
|
185
|
+
const contentType = input.request.headers.get("content-type")?.split(";", 1)[0]?.trim();
|
|
186
|
+
const csrf = input.request.headers.get(MANAGED_AUTH_CSRF_HEADER);
|
|
187
|
+
const allowed = new Set(input.allowedOrigins.map((candidate) => new URL(candidate).origin));
|
|
188
|
+
const expectedCsrf = managedAuthCsrfToken(
|
|
189
|
+
input.signingSecret,
|
|
190
|
+
input.authority,
|
|
191
|
+
input.expectedGeneration,
|
|
192
|
+
);
|
|
193
|
+
if (
|
|
194
|
+
!origin ||
|
|
195
|
+
!allowed.has(origin) ||
|
|
196
|
+
fetchSite !== "same-origin" ||
|
|
197
|
+
contentType !== "application/json" ||
|
|
198
|
+
!csrf ||
|
|
199
|
+
!equalSecret(csrf, expectedCsrf)
|
|
200
|
+
) {
|
|
201
|
+
throw new ManagedAuthRequestAdmissionError("Browser session-set mutation admission failed");
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export async function resolveManagedAuthSelectedSession(input: {
|
|
206
|
+
db: Database;
|
|
207
|
+
adapter: ManagedAuthSessionAdapter;
|
|
208
|
+
authority: string;
|
|
209
|
+
mode: ManagedAuthSessionSetMode;
|
|
210
|
+
expectedActorEpoch: string | null;
|
|
211
|
+
legacyAmbientSessionId?: string | null;
|
|
212
|
+
allowRecovery?: boolean;
|
|
213
|
+
}): Promise<{
|
|
214
|
+
session: ManagedAuthResolvedSession | null;
|
|
215
|
+
projection: ManagedAuthDatabaseProjection;
|
|
216
|
+
} | null> {
|
|
217
|
+
const snapshot = await getManagedAuthSessionSetSnapshot(input.db, {
|
|
218
|
+
authorityHash: managedAuthSha256(input.authority),
|
|
219
|
+
mode: input.mode,
|
|
220
|
+
includeInternal: true,
|
|
221
|
+
allowRecovery: input.allowRecovery ?? false,
|
|
222
|
+
readOnly: true,
|
|
223
|
+
});
|
|
224
|
+
if (!snapshot) return null;
|
|
225
|
+
if (snapshot.projection.state === "actor_change_required") {
|
|
226
|
+
throw new ManagedAuthActorChangeError();
|
|
227
|
+
}
|
|
228
|
+
requireManagedAuthActorFence({
|
|
229
|
+
mode: input.mode,
|
|
230
|
+
actorEpoch: snapshot.projection.actorEpoch,
|
|
231
|
+
expectedActorEpoch: input.expectedActorEpoch,
|
|
232
|
+
selectedAuthSessionId: snapshot.selected?.authSessionId ?? null,
|
|
233
|
+
legacyAmbientSessionId: input.legacyAmbientSessionId ?? null,
|
|
234
|
+
});
|
|
235
|
+
if (!snapshot.selected) return { session: null, projection: snapshot.projection };
|
|
236
|
+
const resolved = await input.adapter.resolveSelectedSession(snapshot.selected);
|
|
237
|
+
if (
|
|
238
|
+
!resolved ||
|
|
239
|
+
resolved.session.id !== snapshot.selected.authSessionId ||
|
|
240
|
+
resolved.user.id !== snapshot.selected.authUserId
|
|
241
|
+
) {
|
|
242
|
+
return { session: null, projection: snapshot.projection };
|
|
243
|
+
}
|
|
244
|
+
return { session: resolved, projection: snapshot.projection };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export async function authenticateAndAdoptManagedAuthSession(input: {
|
|
248
|
+
db: Database;
|
|
249
|
+
adapter: ManagedAuthSessionAdapter;
|
|
250
|
+
isolatedHeaders: Headers;
|
|
251
|
+
authority: string;
|
|
252
|
+
csrfHash: string;
|
|
253
|
+
operationId: string;
|
|
254
|
+
requestDigest: string;
|
|
255
|
+
expectedGeneration: string;
|
|
256
|
+
expectedActorEpoch: string;
|
|
257
|
+
transactionId: string;
|
|
258
|
+
transactionSecret: string;
|
|
259
|
+
email: string;
|
|
260
|
+
password: string;
|
|
261
|
+
mode: ManagedAuthSessionSetMode;
|
|
262
|
+
}): Promise<{ projection: ManagedAuthDatabaseProjection; returnIntent: string | null }> {
|
|
263
|
+
try {
|
|
264
|
+
const existing = await getManagedAuthSessionSetOperationReceipt(input.db, {
|
|
265
|
+
authorityHash: managedAuthSha256(input.authority),
|
|
266
|
+
operationId: input.operationId,
|
|
267
|
+
requestDigest: input.requestDigest,
|
|
268
|
+
});
|
|
269
|
+
if (existing) return existing;
|
|
270
|
+
} catch (error) {
|
|
271
|
+
// Provider authentication creates a durable session. Do not perform it
|
|
272
|
+
// while exact-replay reconciliation is unavailable.
|
|
273
|
+
throw new ManagedAuthCompletionOutcomeUnknownError({ cause: error });
|
|
274
|
+
}
|
|
275
|
+
const created = await input.adapter.authenticate({
|
|
276
|
+
provider: "email_password",
|
|
277
|
+
transactionId: input.transactionId,
|
|
278
|
+
credentials: { email: input.email, password: input.password },
|
|
279
|
+
headers: input.isolatedHeaders,
|
|
280
|
+
});
|
|
281
|
+
let completed: { projection: ManagedAuthDatabaseProjection; returnIntent: string | null };
|
|
282
|
+
try {
|
|
283
|
+
completed = await completeManagedAuthLoginTransaction(input.db, {
|
|
284
|
+
authorityHash: managedAuthSha256(input.authority),
|
|
285
|
+
csrfHash: input.csrfHash,
|
|
286
|
+
operationId: input.operationId,
|
|
287
|
+
requestDigest: input.requestDigest,
|
|
288
|
+
expectedGeneration: input.expectedGeneration,
|
|
289
|
+
expectedActorEpoch: input.expectedActorEpoch,
|
|
290
|
+
transactionId: input.transactionId,
|
|
291
|
+
transactionSecretHash: managedAuthSha256(input.transactionSecret),
|
|
292
|
+
authSessionId: created.authSessionId,
|
|
293
|
+
mode: input.mode,
|
|
294
|
+
});
|
|
295
|
+
} catch (error) {
|
|
296
|
+
let receipt: Awaited<ReturnType<typeof getManagedAuthSessionSetOperationReceipt>>;
|
|
297
|
+
try {
|
|
298
|
+
receipt = await getManagedAuthSessionSetOperationReceipt(input.db, {
|
|
299
|
+
authorityHash: managedAuthSha256(input.authority),
|
|
300
|
+
operationId: input.operationId,
|
|
301
|
+
requestDigest: input.requestDigest,
|
|
302
|
+
});
|
|
303
|
+
} catch (receiptError) {
|
|
304
|
+
throw new ManagedAuthCompletionOutcomeUnknownError({ cause: receiptError });
|
|
305
|
+
}
|
|
306
|
+
if (receipt) {
|
|
307
|
+
await reconcileCreatedManagedAuthSession(input, created.authSessionId);
|
|
308
|
+
return receipt;
|
|
309
|
+
}
|
|
310
|
+
await input.adapter.revokeSession(created).catch(() => undefined);
|
|
311
|
+
throw error;
|
|
312
|
+
}
|
|
313
|
+
try {
|
|
314
|
+
await reconcileCreatedManagedAuthSession(input, created.authSessionId);
|
|
315
|
+
} catch (error) {
|
|
316
|
+
throw new ManagedAuthCompletionOutcomeUnknownError({ cause: error });
|
|
317
|
+
}
|
|
318
|
+
return completed;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
async function reconcileCreatedManagedAuthSession(
|
|
322
|
+
input: Pick<
|
|
323
|
+
Parameters<typeof authenticateAndAdoptManagedAuthSession>[0],
|
|
324
|
+
"db" | "adapter" | "authority" | "mode"
|
|
325
|
+
>,
|
|
326
|
+
authSessionId: string,
|
|
327
|
+
): Promise<void> {
|
|
328
|
+
const snapshot = await getManagedAuthSessionSetSnapshot(input.db, {
|
|
329
|
+
authorityHash: managedAuthSha256(input.authority),
|
|
330
|
+
mode: input.mode,
|
|
331
|
+
includeInternal: true,
|
|
332
|
+
readOnly: true,
|
|
333
|
+
});
|
|
334
|
+
if (snapshot?.internalSlots.some((slot) => slot.authSessionId === authSessionId)) return;
|
|
335
|
+
await input.adapter.revokeSession({ authSessionId });
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export function isolatedManagedAuthHeaders(request: Request): Headers {
|
|
339
|
+
const headers = new Headers(request.headers);
|
|
340
|
+
headers.delete("cookie");
|
|
341
|
+
headers.delete("authorization");
|
|
342
|
+
headers.delete("x-forwarded-user");
|
|
343
|
+
return headers;
|
|
344
|
+
}
|