@yielded/auth-persistence 0.1.0-beta.23 → 0.1.0-beta.25
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/README.md +11 -0
- package/dist/Adapter.d.mts +12 -6
- package/dist/Adapter.mjs +8 -3
- package/dist/OAuthPersistence.d.mts +87 -0
- package/dist/OAuthPersistence.mjs +125 -0
- package/dist/OAuthPersistence.mjs.map +1 -0
- package/dist/_virtual/_rolldown/runtime.mjs +13 -0
- package/dist/index.d.mts +3 -1
- package/dist/index.mjs +3 -1
- package/dist/internal/configuration.d.mts +1 -1
- package/dist/internal/configuration.mjs.map +1 -1
- package/dist/internal/email-kernel.d.mts +1 -1
- package/dist/internal/email-kernel.mjs +1 -1
- package/dist/internal/email-kernel.mjs.map +1 -1
- package/dist/internal/models/oauth-connected-model.d.mts +294 -0
- package/dist/internal/models/oauth-connected-model.mjs +22 -0
- package/dist/internal/models/oauth-connected-model.mjs.map +1 -0
- package/dist/internal/models/oauth-model.d.mts +467 -0
- package/dist/internal/models/oauth-model.mjs +49 -0
- package/dist/internal/models/oauth-model.mjs.map +1 -0
- package/dist/internal/models/password-model.d.mts +6 -48
- package/dist/internal/models/password-model.mjs +0 -1
- package/dist/internal/models/password-model.mjs.map +1 -1
- package/dist/internal/native-sql-table.d.mts +4 -0
- package/dist/internal/native-sql-table.mjs +7 -0
- package/dist/internal/native-sql-table.mjs.map +1 -1
- package/dist/internal/oauth/accounts.d.mts +8 -0
- package/dist/internal/oauth/accounts.mjs +379 -0
- package/dist/internal/oauth/accounts.mjs.map +1 -0
- package/dist/internal/oauth/connected-access.d.mts +9 -0
- package/dist/internal/oauth/connected-access.mjs +229 -0
- package/dist/internal/oauth/connected-access.mjs.map +1 -0
- package/dist/internal/oauth/connected-collection.d.mts +7 -0
- package/dist/internal/oauth/connected-collection.mjs +214 -0
- package/dist/internal/oauth/connected-collection.mjs.map +1 -0
- package/dist/internal/oauth/connected-custody.d.mts +6 -0
- package/dist/internal/oauth/connected-custody.mjs +165 -0
- package/dist/internal/oauth/connected-custody.mjs.map +1 -0
- package/dist/internal/oauth/connected-flow.d.mts +7 -0
- package/dist/internal/oauth/connected-flow.mjs +324 -0
- package/dist/internal/oauth/connected-flow.mjs.map +1 -0
- package/dist/internal/oauth/connected-input.mjs +122 -0
- package/dist/internal/oauth/connected-input.mjs.map +1 -0
- package/dist/internal/oauth/connected-keys.d.mts +2 -0
- package/dist/internal/oauth/connected-keys.mjs +22 -0
- package/dist/internal/oauth/connected-keys.mjs.map +1 -0
- package/dist/internal/oauth/connected-maintenance.d.mts +9 -0
- package/dist/internal/oauth/connected-maintenance.mjs +226 -0
- package/dist/internal/oauth/connected-maintenance.mjs.map +1 -0
- package/dist/internal/oauth/connected-management.d.mts +9 -0
- package/dist/internal/oauth/connected-management.mjs +243 -0
- package/dist/internal/oauth/connected-management.mjs.map +1 -0
- package/dist/internal/oauth/connected-reference.mjs +63 -0
- package/dist/internal/oauth/connected-reference.mjs.map +1 -0
- package/dist/internal/oauth/connected-settlement.d.mts +8 -0
- package/dist/internal/oauth/connected-settlement.mjs +141 -0
- package/dist/internal/oauth/connected-settlement.mjs.map +1 -0
- package/dist/internal/oauth/connected-sign-in.d.mts +10 -0
- package/dist/internal/oauth/connected-sign-in.mjs +281 -0
- package/dist/internal/oauth/connected-sign-in.mjs.map +1 -0
- package/dist/internal/oauth/connected-state.d.mts +14 -0
- package/dist/internal/oauth/connected-state.mjs +469 -0
- package/dist/internal/oauth/connected-state.mjs.map +1 -0
- package/dist/internal/oauth/connected-target.d.mts +21 -0
- package/dist/internal/oauth/connected-target.mjs +117 -0
- package/dist/internal/oauth/connected-target.mjs.map +1 -0
- package/dist/internal/oauth/flow.d.mts +5 -0
- package/dist/internal/oauth/flow.mjs +279 -0
- package/dist/internal/oauth/flow.mjs.map +1 -0
- package/dist/internal/oauth/input.mjs +127 -0
- package/dist/internal/oauth/input.mjs.map +1 -0
- package/dist/internal/oauth/owner.d.mts +10 -0
- package/dist/internal/oauth/owner.mjs +10 -0
- package/dist/internal/oauth/owner.mjs.map +1 -0
- package/dist/internal/oauth/query-compiler.d.mts +7 -0
- package/dist/internal/oauth/query-compiler.mjs +9 -0
- package/dist/internal/oauth/query-compiler.mjs.map +1 -0
- package/dist/internal/oauth/registration.d.mts +7 -0
- package/dist/internal/oauth/registration.mjs +393 -0
- package/dist/internal/oauth/registration.mjs.map +1 -0
- package/dist/internal/oauth/state.mjs +107 -0
- package/dist/internal/oauth/state.mjs.map +1 -0
- package/dist/internal/oauth/target.d.mts +31 -0
- package/dist/internal/oauth/target.mjs +273 -0
- package/dist/internal/oauth/target.mjs.map +1 -0
- package/dist/internal/oauth-kernel.d.mts +1423 -0
- package/dist/internal/oauth-kernel.mjs +187 -0
- package/dist/internal/oauth-kernel.mjs.map +1 -0
- package/dist/internal/oauth-proxy.d.mts +31 -0
- package/dist/internal/oauth-proxy.mjs +129 -0
- package/dist/internal/oauth-proxy.mjs.map +1 -0
- package/dist/internal/passkey/write-state.mjs +9 -1
- package/dist/internal/passkey/write-state.mjs.map +1 -1
- package/dist/internal/passkey-kernel.d.mts +9 -9
- package/dist/internal/{password-attempts.d.mts → password-credentials.d.mts} +3 -4
- package/dist/internal/password-credentials.mjs +121 -0
- package/dist/internal/password-credentials.mjs.map +1 -0
- package/dist/internal/password-kernel.d.mts +8 -24
- package/dist/internal/password-kernel.mjs +5 -43
- package/dist/internal/password-kernel.mjs.map +1 -1
- package/dist/internal/persistence.d.mts +1 -1
- package/dist/internal/persistence.mjs +2 -2
- package/dist/internal/persistence.mjs.map +1 -1
- package/dist/internal/query-operations.d.mts +2 -0
- package/dist/internal/session-kernel.d.mts +2 -2
- package/dist/internal/session-kernel.mjs +74 -18
- package/dist/internal/session-kernel.mjs.map +1 -1
- package/dist/internal/sql-oauth-connected-model.d.mts +29 -0
- package/dist/internal/sql-oauth-connected-model.mjs +7 -0
- package/dist/internal/sql-oauth-connected-model.mjs.map +1 -0
- package/dist/internal/sql-oauth-model.d.mts +60 -0
- package/dist/internal/sql-oauth-model.mjs +10 -0
- package/dist/internal/sql-oauth-model.mjs.map +1 -0
- package/dist/internal/sql-query.d.mts +12 -0
- package/dist/internal/sql-query.mjs +15 -18
- package/dist/internal/sql-query.mjs.map +1 -1
- package/dist/internal/sql-storage-validation.mjs +54 -0
- package/dist/internal/sql-storage-validation.mjs.map +1 -0
- package/dist/internal/storage-mapping.mjs +1 -37
- package/dist/internal/storage-mapping.mjs.map +1 -1
- package/dist/internal/storage-plans.d.mts +7 -0
- package/dist/internal/storage-plans.mjs +189 -0
- package/dist/internal/storage-plans.mjs.map +1 -0
- package/dist/internal/storage-tables.d.mts +0 -56
- package/dist/internal/storage-tables.mjs +0 -17
- package/dist/internal/storage-tables.mjs.map +1 -1
- package/dist/internal/storage-validation.d.mts +6 -1
- package/dist/internal/storage-validation.mjs +42 -1
- package/dist/internal/storage-validation.mjs.map +1 -1
- package/dist/internal/transaction-kernel.mjs +3 -2
- package/dist/internal/transaction-kernel.mjs.map +1 -1
- package/package.json +1 -1
- package/src/Adapter.ts +89 -5
- package/src/OAuthPersistence.ts +427 -0
- package/src/index.ts +3 -0
- package/src/internal/configuration.ts +1 -3
- package/src/internal/email-kernel.ts +2 -1
- package/src/internal/models/oauth-connected-model.ts +396 -0
- package/src/internal/models/oauth-model.ts +708 -0
- package/src/internal/models/password-model.ts +2 -57
- package/src/internal/native-sql-table.ts +14 -0
- package/src/internal/oauth/accounts.ts +839 -0
- package/src/internal/oauth/connected-access.ts +388 -0
- package/src/internal/oauth/connected-collection.ts +345 -0
- package/src/internal/oauth/connected-custody.ts +308 -0
- package/src/internal/oauth/connected-flow.ts +562 -0
- package/src/internal/oauth/connected-input.ts +147 -0
- package/src/internal/oauth/connected-keys.ts +31 -0
- package/src/internal/oauth/connected-maintenance.ts +379 -0
- package/src/internal/oauth/connected-management.ts +391 -0
- package/src/internal/oauth/connected-reference.ts +135 -0
- package/src/internal/oauth/connected-settlement.ts +278 -0
- package/src/internal/oauth/connected-sign-in.ts +472 -0
- package/src/internal/oauth/connected-state.ts +924 -0
- package/src/internal/oauth/connected-target.ts +307 -0
- package/src/internal/oauth/flow.ts +505 -0
- package/src/internal/oauth/input.ts +201 -0
- package/src/internal/oauth/owner.ts +22 -0
- package/src/internal/oauth/query-compiler.ts +15 -0
- package/src/internal/oauth/registration.ts +676 -0
- package/src/internal/oauth/state.ts +218 -0
- package/src/internal/oauth/target.ts +803 -0
- package/src/internal/oauth-kernel.ts +294 -0
- package/src/internal/oauth-proxy.ts +176 -0
- package/src/internal/passkey/write-state.ts +18 -4
- package/src/internal/password-credentials.ts +245 -0
- package/src/internal/password-kernel.ts +7 -99
- package/src/internal/persistence.ts +1 -1
- package/src/internal/query-operations.ts +2 -0
- package/src/internal/session-kernel.ts +143 -55
- package/src/internal/sql-oauth-connected-model.ts +145 -0
- package/src/internal/sql-oauth-model.ts +263 -0
- package/src/internal/sql-query.ts +16 -13
- package/src/internal/sql-storage-validation.ts +64 -0
- package/src/internal/storage-mapping.ts +0 -37
- package/src/internal/storage-plans.ts +218 -0
- package/src/internal/storage-tables.ts +0 -20
- package/src/internal/storage-validation.ts +58 -0
- package/src/internal/transaction-kernel.ts +6 -2
- package/dist/internal/password-attempts.mjs +0 -197
- package/dist/internal/password-attempts.mjs.map +0 -1
- package/src/internal/password-attempts.ts +0 -466
|
@@ -6,7 +6,7 @@ import { NativeSqlTables } from "./native-sql-table.mjs";
|
|
|
6
6
|
import { Context, DateTime, Effect } from "effect";
|
|
7
7
|
import { SubjectId } from "@yielded/auth/Schema";
|
|
8
8
|
import { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
9
|
-
import {
|
|
9
|
+
import { AuthenticationCapture, AuthenticationEvidence, PendingAuthentication, PendingAuthenticationInvalid, PendingConsumption, PrepareSessionCommit, SessionRepository, SessionStepUpPersistence, SessionUnavailable, SignedSessionValidity, StaleAuthentication, StatefulSessionPersistence } from "@yielded/auth/Sessions";
|
|
10
10
|
import { SqlClient } from "effect/sql/SqlClient";
|
|
11
11
|
import * as SqlError$1 from "effect/sql/SqlError";
|
|
12
12
|
//#region src/internal/session-kernel.d.ts
|
|
@@ -40,7 +40,7 @@ export interface SessionSqlOptions {
|
|
|
40
40
|
}
|
|
41
41
|
export declare const makeSessionKernel: (operations: QueryOperations, nativeTables?: (client: SqlClient, database: object) => NativeSqlTables) => {
|
|
42
42
|
makeSqlAuthenticationAuthority: <Claims>(mapping: AuthenticationAuthorityMapping<Claims, any, any, any, any, any>, options: SessionSqlOptions) => Effect.Effect<{
|
|
43
|
-
readonly capture: (subjectId: SubjectId, credentialIds: ReadonlyArray<string>) => Effect.Effect<
|
|
43
|
+
readonly capture: (subjectId: SubjectId, credentialIds: ReadonlyArray<string>) => Effect.Effect<AuthenticationCapture, StaleAuthentication | SessionUnavailable>;
|
|
44
44
|
readonly requirements: (evidence: AuthenticationEvidence) => Effect.Effect<import("@yielded/auth/Sessions").AuthenticationRequirement, StaleAuthentication | SessionUnavailable>;
|
|
45
45
|
readonly approve: <A>(input: {
|
|
46
46
|
readonly evidence: AuthenticationEvidence;
|
|
@@ -3,11 +3,20 @@ import { makeNativeSqlTables, sqlMapping } from "./native-sql-table.mjs";
|
|
|
3
3
|
import { NativeDatabase } from "./transaction-kernel.mjs";
|
|
4
4
|
import { makeAuthoritySnapshot } from "./authority-snapshot.mjs";
|
|
5
5
|
import { decodeStepUpIntent, encodeStepUpIntent, sameStepUpRevision, stepUpIntentLive, stepUpRotationMatches, validateStepUpPlan } from "./step-up-state.mjs";
|
|
6
|
+
import { canJoinTextColumns } from "./storage-validation.mjs";
|
|
6
7
|
import { Cause, Context, DateTime, Effect, Option, Schema } from "effect";
|
|
7
8
|
import { CurrentCommitJournal, LifecycleHooks, coordinateCommit, hasCommitScope } from "@yielded/auth/Hooks";
|
|
8
|
-
import { PendingAuthenticationInvalid, SessionConflict, SessionInvalid, SessionMetadata, SessionStepUpInvalid, SessionUnavailable, StaleAuthentication, assessAuthentication, pendingAuthenticationContext, snapshotPendingAuthenticationContext, snapshotSessionAuthenticationProvenance } from "@yielded/auth/Sessions";
|
|
9
|
+
import { AuthenticationCapture, PendingAuthenticationInvalid, SessionConflict, SessionInvalid, SessionMetadata, SessionStepUpInvalid, SessionUnavailable, StaleAuthentication, assessAuthentication, pendingAuthenticationContext, snapshotPendingAuthenticationContext, snapshotSessionAuthenticationProvenance } from "@yielded/auth/Sessions";
|
|
9
10
|
import { reportPersistenceFailure } from "@yielded/auth/Persistence";
|
|
10
11
|
//#region src/internal/session-kernel.ts
|
|
12
|
+
const decodeRevocationFlag = Schema.decodeUnknownEffect(Schema.Literals([0, 1]));
|
|
13
|
+
/** Reads need no transaction of their own. A caller-owned transaction still
|
|
14
|
+
* needs a savepoint so catching an SQL failure does not leave it aborted. */
|
|
15
|
+
const withVerificationSavepoint = Effect.fnUntraced(function* (effect) {
|
|
16
|
+
const { $client } = yield* NativeDatabase;
|
|
17
|
+
const transaction = yield* Effect.serviceOption($client.transactionService);
|
|
18
|
+
return yield* Option.isSome(transaction) ? $client.withTransaction(effect) : effect;
|
|
19
|
+
});
|
|
11
20
|
/** Native SQL authority for the current transaction or savepoint. */
|
|
12
21
|
var CurrentSessionSql = class extends Context.Service()("effect-auth/drizzle/CurrentSessionSql") {};
|
|
13
22
|
const makeSessionKernel = (operations, nativeTables = (client) => makeNativeSqlTables(client)) => {
|
|
@@ -191,7 +200,10 @@ const makeSessionKernel = (operations, nativeTables = (client) => makeNativeSqlT
|
|
|
191
200
|
const tables = yield* sqlMapping(() => nativeTables(sqlClient, root)).pipe(Effect.mapError(unavailable));
|
|
192
201
|
const readSnapshot = makeAuthoritySnapshot(tables, mapping);
|
|
193
202
|
const service = {
|
|
194
|
-
capture: (subjectId, credentialIds) => safeTransaction(readSnapshot(subjectId, credentialIds).pipe(Effect.
|
|
203
|
+
capture: (subjectId, credentialIds) => safeTransaction(readSnapshot(subjectId, credentialIds).pipe(Effect.flatMap((value) => Effect.flatMap(mapping.subject.decodeRequirement(value.subject), (requirement) => Schema.decodeEffect(AuthenticationCapture)({
|
|
204
|
+
revision: value.revision,
|
|
205
|
+
requirement
|
|
206
|
+
}))))),
|
|
195
207
|
requirements: (evidence) => safeTransaction(readSnapshot(evidence.revision.subjectId, evidence.revision.credentials.map((item) => item.credentialId)).pipe(Effect.flatMap((captured) => validateCapturedEvidence(mapping, evidence, captured)), Effect.map((value) => value.requirement))),
|
|
196
208
|
approve: (input, prepare) => owned(database, options, mapping.isConstraintConflict, Effect.gen(function* () {
|
|
197
209
|
const journal = yield* CurrentCommitJournal;
|
|
@@ -323,6 +335,18 @@ const makeSessionKernel = (operations, nativeTables = (client) => makeNativeSqlT
|
|
|
323
335
|
const tables = yield* sqlMapping(() => nativeTables(root.$client.withoutTransforms(), root)).pipe(Effect.mapError(unavailable));
|
|
324
336
|
const readSnapshot = makeAuthoritySnapshot(tables, mapping);
|
|
325
337
|
const c = sessionColumns(mapping);
|
|
338
|
+
const verification = yield* safeTransaction(Effect.gen(function* () {
|
|
339
|
+
const { session, subject } = yield* sqlMapping(() => ({
|
|
340
|
+
session: tables(mapping.session.table).as("auth_session"),
|
|
341
|
+
subject: tables(mapping.subject.table).as("auth_subject")
|
|
342
|
+
}));
|
|
343
|
+
const [sessionOwner, subjectOwner] = yield* sqlMapping(() => [session.unencodedTextColumn?.(mapping.session.subjectId), subject.unencodedTextColumn?.(mapping.subject.id)]);
|
|
344
|
+
return {
|
|
345
|
+
session,
|
|
346
|
+
subject,
|
|
347
|
+
canJoinOwner: yield* canJoinTextColumns(sessionOwner, subjectOwner)
|
|
348
|
+
};
|
|
349
|
+
}));
|
|
326
350
|
const persistence = {
|
|
327
351
|
establish: (input, prepare) => owned(database, options, mapping.isConstraintConflict, Effect.gen(function* () {
|
|
328
352
|
const transaction = yield* CurrentSessionSql;
|
|
@@ -330,8 +354,9 @@ const makeSessionKernel = (operations, nativeTables = (client) => makeNativeSqlT
|
|
|
330
354
|
const { nativeSubjectId, requirement } = yield* options.locking ? validateEvidenceIn(mapping, input.evidence, true) : Effect.flatMap(readSnapshot(input.evidence.revision.subjectId, input.evidence.revision.credentials.map((item) => item.credentialId)), (captured) => validateCapturedEvidence(mapping, input.evidence, captured));
|
|
331
355
|
let flowInsert;
|
|
332
356
|
let pendingExpiresAt;
|
|
333
|
-
if (input.pending === void 0)
|
|
334
|
-
|
|
357
|
+
if (input.pending === void 0) {
|
|
358
|
+
if (input.fresh !== true || input.handoffSourceSessionId !== void 0) flowInsert = yield* ensureDirectFlowAvailable(mapping, input.evidence, nativeSubjectId, input.session.absoluteExpiresAt);
|
|
359
|
+
} else {
|
|
335
360
|
if (mapping.pending === void 0) return yield* invalidPending();
|
|
336
361
|
const pending = yield* validatePending(mapping, input.pending);
|
|
337
362
|
if (!preservesRevision(input.evidence, pending.evidence)) return yield* invalidPending();
|
|
@@ -356,7 +381,7 @@ const makeSessionKernel = (operations, nativeTables = (client) => makeNativeSqlT
|
|
|
356
381
|
};
|
|
357
382
|
const receipt = prepare(record, journal);
|
|
358
383
|
if (flowInsert !== void 0) yield* transaction.insert(mapping.flow.table).values(flowInsert);
|
|
359
|
-
else yield* consumePending({
|
|
384
|
+
else if (input.pending !== void 0) yield* consumePending({
|
|
360
385
|
...mapping,
|
|
361
386
|
pending: mapping.pending
|
|
362
387
|
}, input.pending, input.session.absoluteExpiresAt);
|
|
@@ -368,14 +393,23 @@ const makeSessionKernel = (operations, nativeTables = (client) => makeNativeSqlT
|
|
|
368
393
|
if (DateTime.toEpochMillis(commitNow) < DateTime.toEpochMillis(record.issuedAt) || DateTime.toEpochMillis(commitNow) >= DateTime.toEpochMillis(record.expiresAt) || !(yield* assessAuthentication(input.evidence, requirement)).satisfied) return yield* stale();
|
|
369
394
|
return receipt;
|
|
370
395
|
}).pipe(normalizeMutation(mapping))),
|
|
371
|
-
verify: (input) => safeTransaction(
|
|
372
|
-
const
|
|
396
|
+
verify: (input) => safeTransaction(withVerificationSavepoint(Effect.gen(function* () {
|
|
397
|
+
const sql = root.$client.withoutTransforms();
|
|
398
|
+
const { session, subject, canJoinOwner } = verification;
|
|
399
|
+
const owner = canJoinOwner ? void 0 : (yield* database.select({ subjectId: c.subjectId }).from(mapping.session.table).where(eq(c.digest, input.digest)).limit(1))[0];
|
|
400
|
+
if (!canJoinOwner && owner === void 0) return yield* invalidSession();
|
|
401
|
+
const row = (yield* sqlMapping(() => sql`select ${session.fields("v_")}, ${subject.fields("s_")}
|
|
402
|
+
from ${session.name} inner join ${subject.name} on
|
|
403
|
+
${subject.column(mapping.subject.id)} = ${owner === void 0 ? session.column(mapping.session.subjectId) : subject.value(mapping.subject.id, owner.subjectId)}
|
|
404
|
+
where ${session.column(mapping.session.digest)} = ${session.value(mapping.session.digest, input.digest)}
|
|
405
|
+
limit 1`).pipe(Effect.flatten))[0];
|
|
373
406
|
if (row === void 0) return yield* invalidSession();
|
|
374
|
-
const
|
|
407
|
+
const sessionRow = yield* sqlMapping(() => session.decode(row, "v_"));
|
|
408
|
+
const subjectRow = yield* sqlMapping(() => subject.decode(row, "s_"));
|
|
409
|
+
const record = yield* mapping.session.decode(sessionRow);
|
|
375
410
|
const nativeSubjectId = yield* mapping.subjectId.toNative(record.subjectId);
|
|
376
|
-
const subject = (yield* readSubject(mapping, nativeSubjectId, false))[0];
|
|
377
411
|
const now = yield* freshNow;
|
|
378
|
-
if (
|
|
412
|
+
if (!mapping.subjectId.equals(nativeSubjectId, sessionRow[mapping.session.subjectId]) || !mapping.subjectId.equals(nativeSubjectId, subjectRow[mapping.subject.id]) || !mapping.subject.isActiveStatus(subjectRow[mapping.subject.status]) || subjectRow[mapping.subject.securityRevision] !== record.securityRevision || DateTime.toEpochMillis(now) >= DateTime.toEpochMillis(record.expiresAt) || DateTime.toEpochMillis(now) >= DateTime.toEpochMillis(record.absoluteExpiresAt)) return yield* invalidSession();
|
|
379
413
|
return record;
|
|
380
414
|
}))),
|
|
381
415
|
rotate: (input, prepare) => owned(database, options, mapping.isConstraintConflict, Effect.gen(function* () {
|
|
@@ -463,7 +497,7 @@ const makeSessionKernel = (operations, nativeTables = (client) => makeNativeSqlT
|
|
|
463
497
|
return {
|
|
464
498
|
statefulSessionPersistence: {
|
|
465
499
|
establish: (input, prepare) => persistence.establish(input, prepare).pipe(Effect.provideService(NativeDatabase, root), Effect.provideService(LifecycleHooks, hooks)),
|
|
466
|
-
verify: (input) => persistence.verify(input).pipe(Effect.provideService(LifecycleHooks, hooks)),
|
|
500
|
+
verify: (input) => persistence.verify(input).pipe(Effect.provideService(NativeDatabase, root), Effect.provideService(LifecycleHooks, hooks)),
|
|
467
501
|
rotate: (input, prepare) => persistence.rotate(input, prepare).pipe(Effect.provideService(LifecycleHooks, hooks)),
|
|
468
502
|
revokeDigest: (digest, prepare) => persistence.revokeDigest(digest, prepare).pipe(Effect.provideService(LifecycleHooks, hooks)),
|
|
469
503
|
revoke: (input, prepare) => persistence.revoke(input, prepare).pipe(Effect.provideService(LifecycleHooks, hooks)),
|
|
@@ -482,16 +516,38 @@ const makeSessionKernel = (operations, nativeTables = (client) => makeNativeSqlT
|
|
|
482
516
|
sessionId: column(mapping.tombstone.table, mapping.tombstone.sessionId),
|
|
483
517
|
absoluteExpiresAt: column(mapping.tombstone.table, mapping.tombstone.absoluteExpiresAt)
|
|
484
518
|
};
|
|
519
|
+
const root = yield* NativeDatabase;
|
|
520
|
+
const tables = yield* sqlMapping(() => nativeTables(root.$client.withoutTransforms(), root)).pipe(Effect.mapError(unavailable));
|
|
485
521
|
const service = {
|
|
486
|
-
verify: (session, _now) => safeTransaction(
|
|
487
|
-
const
|
|
522
|
+
verify: (session, _now) => safeTransaction(withVerificationSavepoint(Effect.gen(function* () {
|
|
523
|
+
const sql = root.$client.withoutTransforms();
|
|
488
524
|
const nativeSubjectId = yield* mapping.subjectId.toNative(session.subjectId);
|
|
489
525
|
const nativeSessionId = yield* mapping.sessionId.toNative(session.sessionId);
|
|
490
|
-
const
|
|
491
|
-
|
|
526
|
+
const readNow = yield* freshNow;
|
|
527
|
+
const { subjectTable, rows } = yield* sqlMapping(() => {
|
|
528
|
+
const subjectTable = tables(mapping.subject.table).as("auth_subject");
|
|
529
|
+
const revoked = tables(mapping.tombstone.table).as("auth_revocation");
|
|
530
|
+
return {
|
|
531
|
+
subjectTable,
|
|
532
|
+
rows: sql`
|
|
533
|
+
select ${subjectTable.fields("s_")},
|
|
534
|
+
case when exists (
|
|
535
|
+
select 1 from ${revoked.name}
|
|
536
|
+
where ${revoked.column(mapping.tombstone.subjectId)} = ${revoked.value(mapping.tombstone.subjectId, nativeSubjectId)}
|
|
537
|
+
and ${revoked.column(mapping.tombstone.sessionId)} = ${revoked.value(mapping.tombstone.sessionId, nativeSessionId)}
|
|
538
|
+
and ${revoked.column(mapping.tombstone.absoluteExpiresAt)} > ${revoked.value(mapping.tombstone.absoluteExpiresAt, mapping.tombstone.encodeInstant(readNow))}
|
|
539
|
+
) then 1 else 0 end as auth_revoked
|
|
540
|
+
from ${subjectTable.name}
|
|
541
|
+
where ${subjectTable.column(mapping.subject.id)} = ${subjectTable.value(mapping.subject.id, nativeSubjectId)}
|
|
542
|
+
limit 1`
|
|
543
|
+
};
|
|
544
|
+
});
|
|
545
|
+
const result = (yield* rows)[0];
|
|
546
|
+
if (result === void 0) return yield* invalidSession();
|
|
547
|
+
const row = yield* sqlMapping(() => subjectTable.decode(result, "s_"));
|
|
548
|
+
const revoked = yield* decodeRevocationFlag(result.auth_revoked);
|
|
492
549
|
const authoritativeNow = yield* freshNow;
|
|
493
|
-
if (DateTime.toEpochMillis(authoritativeNow) >= DateTime.toEpochMillis(session.expiresAt) || DateTime.toEpochMillis(authoritativeNow) >= DateTime.toEpochMillis(session.absoluteExpiresAt)) return yield* invalidSession();
|
|
494
|
-
if ((yield* read.select({ sessionId: tombstone.sessionId }).from(mapping.tombstone.table).where(and(eq(tombstone.subjectId, nativeSubjectId), eq(tombstone.sessionId, nativeSessionId), gt(tombstone.absoluteExpiresAt, mapping.tombstone.encodeInstant(authoritativeNow)))).limit(1)).length > 0) return yield* invalidSession();
|
|
550
|
+
if (!mapping.subjectId.equals(nativeSubjectId, row[mapping.subject.id]) || !mapping.subject.isActiveStatus(row[mapping.subject.status]) || row[mapping.subject.securityRevision] !== session.securityRevision || revoked === 1 || DateTime.toEpochMillis(authoritativeNow) >= DateTime.toEpochMillis(session.expiresAt) || DateTime.toEpochMillis(authoritativeNow) >= DateTime.toEpochMillis(session.absoluteExpiresAt)) return yield* invalidSession();
|
|
495
551
|
}))),
|
|
496
552
|
revoke: (input, prepare) => owned(database, options, mapping.isConstraintConflict, Effect.gen(function* () {
|
|
497
553
|
const transaction = yield* CurrentSessionSql;
|
|
@@ -527,7 +583,7 @@ const makeSessionKernel = (operations, nativeTables = (client) => makeNativeSqlT
|
|
|
527
583
|
}))
|
|
528
584
|
};
|
|
529
585
|
return {
|
|
530
|
-
verify: (session, now) => service.verify(session, now).pipe(Effect.provideService(LifecycleHooks, hooks)),
|
|
586
|
+
verify: (session, now) => service.verify(session, now).pipe(Effect.provideService(NativeDatabase, root), Effect.provideService(LifecycleHooks, hooks)),
|
|
531
587
|
revoke: (input, prepare) => service.revoke(input, prepare).pipe(Effect.provideService(LifecycleHooks, hooks)),
|
|
532
588
|
revokeAll: (input, prepare) => service.revokeAll(input, prepare).pipe(Effect.provideService(LifecycleHooks, hooks))
|
|
533
589
|
};
|