@yielded/auth-persistence-drizzle 0.1.0-beta.18 → 0.1.0-beta.20
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 +8 -1
- package/dist/D1.d.mts +8 -8
- package/dist/Libsql.d.mts +38 -38
- package/dist/Mysql2.d.mts +51 -51
- package/dist/Pglite.d.mts +51 -51
- package/dist/Postgres.d.mts +38 -38
- package/dist/SqliteBun.d.mts +51 -51
- package/dist/SqliteDo.d.mts +112 -134
- package/dist/SqliteDo.mjs +30 -45
- package/dist/SqliteDo.mjs.map +1 -1
- package/dist/SqliteNode.d.mts +44 -44
- package/dist/SqliteWasm.d.mts +38 -38
- package/dist/drizzle/crypto.mjs +11 -0
- package/dist/drizzle/crypto.mjs.map +1 -0
- package/dist/drizzle/d1-identity.mjs +2 -2
- package/dist/drizzle/d1-identity.mjs.map +1 -1
- package/dist/drizzle/d1-oauth.d.mts +11 -11
- package/dist/drizzle/d1-oauth.mjs.map +1 -1
- package/dist/drizzle/d1-passkey.d.mts +6 -6
- package/dist/drizzle/d1-passkey.mjs.map +1 -1
- package/dist/drizzle/d1-passwords.d.mts +1 -1
- package/dist/drizzle/d1-phone.d.mts +3 -3
- package/dist/drizzle/d1-phone.mjs.map +1 -1
- package/dist/drizzle/d1-proofs.d.mts +1 -1
- package/dist/drizzle/d1-sessions.d.mts +1 -1
- package/dist/drizzle/d1-totp.d.mts +3 -3
- package/dist/drizzle/d1-totp.mjs.map +1 -1
- package/dist/drizzle/mysql-identity.mjs +2 -2
- package/dist/drizzle/mysql-identity.mjs.map +1 -1
- package/dist/drizzle/oauth-accounts.mjs +9 -8
- package/dist/drizzle/oauth-accounts.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-collection.mjs +1 -1
- package/dist/drizzle/oauth-connected-collection.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-custody.mjs +5 -4
- package/dist/drizzle/oauth-connected-custody.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-drivers.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-flow.mjs +8 -7
- package/dist/drizzle/oauth-connected-flow.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-management.mjs +3 -2
- package/dist/drizzle/oauth-connected-management.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-reference.mjs +8 -4
- package/dist/drizzle/oauth-connected-reference.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-settlement.mjs +4 -4
- package/dist/drizzle/oauth-connected-settlement.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-sign-in.mjs +11 -10
- package/dist/drizzle/oauth-connected-sign-in.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-state.d.mts +13 -13
- package/dist/drizzle/oauth-connected-state.mjs +23 -20
- package/dist/drizzle/oauth-connected-state.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-target.d.mts +9 -9
- package/dist/drizzle/oauth-connected-target.mjs.map +1 -1
- package/dist/drizzle/oauth-drivers.mjs.map +1 -1
- package/dist/drizzle/oauth-flow.mjs +1 -1
- package/dist/drizzle/oauth-flow.mjs.map +1 -1
- package/dist/drizzle/oauth-model.d.mts +4 -4
- package/dist/drizzle/oauth-model.mjs.map +1 -1
- package/dist/drizzle/oauth-registration.mjs +2 -2
- package/dist/drizzle/oauth-registration.mjs.map +1 -1
- package/dist/drizzle/oauth-state.mjs +11 -12
- package/dist/drizzle/oauth-state.mjs.map +1 -1
- package/dist/drizzle/oauth-target.d.mts +4 -4
- package/dist/drizzle/oauth-target.mjs.map +1 -1
- package/dist/drizzle/passkey-drivers.mjs.map +1 -1
- package/dist/drizzle/passkey-write-drivers.mjs.map +1 -1
- package/dist/drizzle/passkey-write-target.d.mts +1 -1
- package/dist/drizzle/password-prepared-state.mjs +1 -1
- package/dist/drizzle/pg-identity.mjs +2 -2
- package/dist/drizzle/pg-identity.mjs.map +1 -1
- package/dist/drizzle/phone-model.d.mts +2 -2
- package/dist/drizzle/phone-model.mjs +3 -3
- package/dist/drizzle/phone-model.mjs.map +1 -1
- package/dist/drizzle/phone-target.d.mts +1 -1
- package/dist/drizzle/phone-target.mjs +2 -2
- package/dist/drizzle/phone-target.mjs.map +1 -1
- package/dist/drizzle/sqlite-do-database.d.mts +29 -0
- package/dist/drizzle/sqlite-do-database.mjs +45 -0
- package/dist/drizzle/sqlite-do-database.mjs.map +1 -0
- package/dist/drizzle/sqlite-emails.mjs.map +1 -1
- package/dist/drizzle/sqlite-identity.mjs +2 -2
- package/dist/drizzle/sqlite-identity.mjs.map +1 -1
- package/dist/drizzle/sqlite-passwords.mjs.map +1 -1
- package/dist/drizzle/sqlite-proofs.mjs.map +1 -1
- package/dist/drizzle/sqlite-sessions.mjs.map +1 -1
- package/dist/drizzle/storage-validation.mjs +17 -9
- package/dist/drizzle/storage-validation.mjs.map +1 -1
- package/dist/drizzle/totp-state.mjs +8 -8
- package/dist/drizzle/totp-state.mjs.map +1 -1
- package/dist/drizzle/totp-target.d.mts +1 -1
- package/dist/drizzle/totp-target.mjs +2 -2
- package/dist/drizzle/totp-target.mjs.map +1 -1
- package/package.json +1 -1
- package/src/SqliteDo.ts +63 -70
- package/src/drizzle/crypto.ts +14 -0
- package/src/drizzle/d1-identity.ts +2 -2
- package/src/drizzle/d1-oauth.ts +14 -5
- package/src/drizzle/d1-passkey.ts +5 -1
- package/src/drizzle/d1-phone.ts +2 -1
- package/src/drizzle/d1-totp.ts +6 -2
- package/src/drizzle/mysql-identity.ts +2 -2
- package/src/drizzle/oauth-accounts.ts +14 -13
- package/src/drizzle/oauth-connected-collection.ts +1 -1
- package/src/drizzle/oauth-connected-custody.ts +8 -6
- package/src/drizzle/oauth-connected-drivers.ts +9 -3
- package/src/drizzle/oauth-connected-flow.ts +6 -6
- package/src/drizzle/oauth-connected-management.ts +1 -1
- package/src/drizzle/oauth-connected-reference.ts +14 -9
- package/src/drizzle/oauth-connected-settlement.ts +4 -4
- package/src/drizzle/oauth-connected-sign-in.ts +11 -10
- package/src/drizzle/oauth-connected-state.ts +40 -25
- package/src/drizzle/oauth-connected-target.ts +9 -5
- package/src/drizzle/oauth-drivers.ts +13 -5
- package/src/drizzle/oauth-flow.ts +1 -1
- package/src/drizzle/oauth-model.ts +4 -4
- package/src/drizzle/oauth-registration.ts +2 -2
- package/src/drizzle/oauth-state.ts +17 -15
- package/src/drizzle/oauth-target.ts +11 -3
- package/src/drizzle/passkey-drivers.ts +7 -3
- package/src/drizzle/passkey-write-drivers.ts +11 -2
- package/src/drizzle/pg-identity.ts +2 -2
- package/src/drizzle/phone-model.ts +3 -3
- package/src/drizzle/phone-target.ts +11 -4
- package/src/drizzle/sqlite-do-database.ts +87 -0
- package/src/drizzle/sqlite-emails.ts +1 -1
- package/src/drizzle/sqlite-identity.ts +2 -2
- package/src/drizzle/sqlite-passwords.ts +1 -1
- package/src/drizzle/sqlite-proofs.ts +2 -2
- package/src/drizzle/sqlite-sessions.ts +2 -2
- package/src/drizzle/storage-validation.ts +15 -6
- package/src/drizzle/totp-state.ts +8 -8
- package/src/drizzle/totp-target.ts +11 -5
|
@@ -45,7 +45,7 @@ export const pending = Effect.fn("oauthConnected.pending")(function* (
|
|
|
45
45
|
row[f.flowId] === c.flowId &&
|
|
46
46
|
row[f.commandId] === c.commandId &&
|
|
47
47
|
mapping.subjectId.equals(native, row[f.subjectId]) &&
|
|
48
|
-
row[f.clientKey] === S.clientKey(S.configuration(flow)) &&
|
|
48
|
+
row[f.clientKey] === (yield* S.clientKey(S.configuration(flow))) &&
|
|
49
49
|
row[f.stateDigest] === c.stateDigest &&
|
|
50
50
|
mapping.clock.decodeInstant(row[f.expiresAt]) === c.expiresAtMillis &&
|
|
51
51
|
mapping.clock.decodeInstant(row[f.retentionUntil]) === flow.retentionUntilMillis,
|
|
@@ -238,7 +238,7 @@ export const inspectPrepared = Effect.fn("oauthConnected.inspectPrepared")(funct
|
|
|
238
238
|
row[f.flowId] === c.flowId &&
|
|
239
239
|
row[f.commandId] === c.commandId &&
|
|
240
240
|
mapping.subjectId.equals(found.nativeId, row[f.subjectId]) &&
|
|
241
|
-
row[f.clientKey] === S.clientKey(S.configuration(flow)) &&
|
|
241
|
+
row[f.clientKey] === (yield* S.clientKey(S.configuration(flow))) &&
|
|
242
242
|
row[f.stateDigest] === c.stateDigest &&
|
|
243
243
|
mapping.clock.decodeInstant(row[f.expiresAt]) === c.expiresAtMillis &&
|
|
244
244
|
mapping.clock.decodeInstant(row[f.retentionUntil]) === flow.retentionUntilMillis,
|
|
@@ -356,7 +356,7 @@ export const claim = Effect.fn("oauthConnected.claim")(function* (
|
|
|
356
356
|
{
|
|
357
357
|
[f.state]: "Claimed",
|
|
358
358
|
[f.claimId]: claimed.claimId,
|
|
359
|
-
[f.claimDigest]: digest(S.claimStorage.encode(claimed)),
|
|
359
|
+
[f.claimDigest]: yield* digest(S.claimStorage.encode(claimed)),
|
|
360
360
|
[f.claimOrder]: mapping.order.encode(order),
|
|
361
361
|
[f.claimedAt]: mapping.clock.encodeInstant(now),
|
|
362
362
|
[f.claimExpiresAt]: mapping.clock.encodeInstant(expires),
|
|
@@ -392,7 +392,7 @@ export const exact = Effect.fn("oauthConnected.exactClaim")(function* (
|
|
|
392
392
|
row === undefined ||
|
|
393
393
|
row[f.work] !== "Unresolved" ||
|
|
394
394
|
row[f.claimId] !== claim.claimId ||
|
|
395
|
-
row[f.claimDigest] !== digest(S.claimStorage.encode(claim))
|
|
395
|
+
row[f.claimDigest] !== (yield* digest(S.claimStorage.encode(claim)))
|
|
396
396
|
)
|
|
397
397
|
return undefined;
|
|
398
398
|
const native = yield* mapping.subjectId.toNative(c.revision.subjectId);
|
|
@@ -403,7 +403,7 @@ export const exact = Effect.fn("oauthConnected.exactClaim")(function* (
|
|
|
403
403
|
row[f.stateDigest] === c.stateDigest &&
|
|
404
404
|
mapping.clock.decodeInstant(row[f.expiresAt]) === c.expiresAtMillis &&
|
|
405
405
|
mapping.clock.decodeInstant(row[f.retentionUntil]) === claim.flow.retentionUntilMillis &&
|
|
406
|
-
row[f.clientKey] === S.clientKey(S.configuration(claim.flow)) &&
|
|
406
|
+
row[f.clientKey] === (yield* S.clientKey(S.configuration(claim.flow))) &&
|
|
407
407
|
S.nativeOrder(mapping, row[f.claimOrder]) === S.orderNumber(claim.order) &&
|
|
408
408
|
mapping.clock.decodeInstant(row[f.claimedAt]) === claim.claimedAtMillis &&
|
|
409
409
|
mapping.clock.decodeInstant(row[f.claimExpiresAt]) === claim.claimExpiresAtMillis,
|
|
@@ -448,7 +448,7 @@ export const inspectTuple = Effect.fn("oauthConnected.inspectTuple")(function* (
|
|
|
448
448
|
const owner = yield* CurrentOAuthTransaction;
|
|
449
449
|
|
|
450
450
|
const t = mapping.ownership.tuple,
|
|
451
|
-
key = oauthIdentityKey(identity);
|
|
451
|
+
key = yield* oauthIdentityKey(identity);
|
|
452
452
|
|
|
453
453
|
const read = yield* owner.read(t.table, equal(t.table, { [t.identityKey]: key }), { limit: 1 });
|
|
454
454
|
const row = read.rows[0];
|
|
@@ -341,7 +341,7 @@ export const disconnect = Effect.fn("oauthConnected.disconnect")(function* (
|
|
|
341
341
|
[d.grantId]: token.grantId,
|
|
342
342
|
[d.intent]: S.commandStorage.encode({
|
|
343
343
|
context: token,
|
|
344
|
-
originalDigest: digest(S.disconnectStorage.encode(input.grant)),
|
|
344
|
+
originalDigest: yield* digest(S.disconnectStorage.encode(input.grant)),
|
|
345
345
|
...(input.revocation === undefined
|
|
346
346
|
? {}
|
|
347
347
|
: { revocationJobId: input.revocation.context.jobId }),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { eq, is, sql, type SQL, type Table } from "drizzle-orm";
|
|
2
2
|
import { MySqlTable } from "drizzle-orm/mysql-core/table";
|
|
3
3
|
import { PgTable } from "drizzle-orm/pg-core/table";
|
|
4
|
+
import { Effect } from "effect";
|
|
4
5
|
|
|
5
6
|
import type { OAuthConnectedMapping } from "./oauth-connected-model";
|
|
6
7
|
import { scopeKey, type Mapping } from "./oauth-connected-state";
|
|
@@ -52,15 +53,19 @@ export const oauthConnectedOwnershipReferences = <
|
|
|
52
53
|
table: c.table,
|
|
53
54
|
orderBy: c.clientKey,
|
|
54
55
|
condition: (input) =>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
Effect.gen(function* () {
|
|
57
|
+
const key = yield* scopeKey(input.identity.provider, input.identity.issuer);
|
|
58
|
+
|
|
59
|
+
return both(
|
|
60
|
+
equal(c.table, {
|
|
61
|
+
[c.clientKey]: key,
|
|
62
|
+
[c.counter]: mapping.order.encode(0),
|
|
63
|
+
}),
|
|
64
|
+
exactText(c.table, c.provider, input.identity.provider),
|
|
65
|
+
exactText(c.table, c.issuer, input.identity.issuer),
|
|
66
|
+
exactText(c.table, c.clientRegistrationId, ""),
|
|
67
|
+
);
|
|
68
|
+
}),
|
|
64
69
|
}),
|
|
65
70
|
],
|
|
66
71
|
connectedReference: (input) => connectedReferenceCondition(mapping, input.identityKey),
|
|
@@ -46,9 +46,9 @@ export const activateGrant = Effect.fn("oauthConnected.activateGrant")(function*
|
|
|
46
46
|
const owner = yield* CurrentOAuthTransaction;
|
|
47
47
|
const token = grant.context;
|
|
48
48
|
const g = mapping.grant;
|
|
49
|
-
const identityKey = oauthIdentityKey(token.identity);
|
|
50
|
-
const clientKey = S.clientKey(token.configuration);
|
|
51
|
-
const cohortKey = S.cohortKey(clientKey, identityKey);
|
|
49
|
+
const identityKey = yield* oauthIdentityKey(token.identity);
|
|
50
|
+
const clientKey = yield* S.clientKey(token.configuration);
|
|
51
|
+
const cohortKey = yield* S.cohortKey(clientKey, identityKey);
|
|
52
52
|
|
|
53
53
|
const values = {
|
|
54
54
|
...g.encodeInsert({
|
|
@@ -143,7 +143,7 @@ export const settle = Effect.fn("oauthConnected.settle")(function* (
|
|
|
143
143
|
token.grantId === c.grantId &&
|
|
144
144
|
token.identity.provider === c.provider &&
|
|
145
145
|
token.identity.issuer === c.issuer &&
|
|
146
|
-
S.clientKey(token.configuration) === cl.id &&
|
|
146
|
+
(yield* S.clientKey(token.configuration)) === cl.id &&
|
|
147
147
|
S.tokenContextStorage.encode({
|
|
148
148
|
...token,
|
|
149
149
|
configuration: S.configuration(input.claim.flow),
|
|
@@ -83,7 +83,7 @@ export const claimSignIn = Effect.fn("oauthConnected.claimSignIn")(function* (
|
|
|
83
83
|
[f.stateDigest]: c.stateDigest,
|
|
84
84
|
[f.snapshot]: null,
|
|
85
85
|
[f.claimId]: claim.claimId,
|
|
86
|
-
[f.claimDigest]: digest(reservationStorage.encode(reservation)),
|
|
86
|
+
[f.claimDigest]: yield* digest(reservationStorage.encode(reservation)),
|
|
87
87
|
[f.claimOrder]: mapping.order.encode(order),
|
|
88
88
|
[f.claimedAt]: mapping.clock.encodeInstant(claim.claimedAtMillis),
|
|
89
89
|
[f.claimExpiresAt]: mapping.clock.encodeInstant(claim.claimExpiresAtMillis),
|
|
@@ -116,13 +116,13 @@ const exact = Effect.fn("oauthConnected.exactSignIn")(function* (
|
|
|
116
116
|
row === undefined ||
|
|
117
117
|
row[f.work] !== "Unresolved" ||
|
|
118
118
|
row[f.claimId] !== reservation.claim.claimId ||
|
|
119
|
-
row[f.claimDigest] !== digest(reservationStorage.encode(reservation))
|
|
119
|
+
row[f.claimDigest] !== (yield* digest(reservationStorage.encode(reservation)))
|
|
120
120
|
)
|
|
121
121
|
return undefined;
|
|
122
122
|
invariant(
|
|
123
123
|
row[f.subjectId] === null &&
|
|
124
124
|
row[f.commandId] === c.commandId &&
|
|
125
|
-
row[f.clientKey] === S.clientKey(reservation.configuration) &&
|
|
125
|
+
row[f.clientKey] === (yield* S.clientKey(reservation.configuration)) &&
|
|
126
126
|
S.nativeOrder(mapping, row[f.claimOrder]) === S.orderNumber(reservation.order),
|
|
127
127
|
);
|
|
128
128
|
const now = yield* owner.now(mapping.clock);
|
|
@@ -164,7 +164,7 @@ const credential = Effect.fn("oauthConnected.signInCredential")(function* (
|
|
|
164
164
|
[c.moduleId]: context.moduleId,
|
|
165
165
|
[c.credentialId]: input.credentialId,
|
|
166
166
|
[c.subjectId]: found.nativeId,
|
|
167
|
-
[c.identityKey]: oauthIdentityKey(input.identity),
|
|
167
|
+
[c.identityKey]: yield* oauthIdentityKey(input.identity),
|
|
168
168
|
[c.credentialRevision]: input.credentialRevision,
|
|
169
169
|
}),
|
|
170
170
|
c.activeCondition,
|
|
@@ -242,18 +242,19 @@ const slot = Effect.fn("oauthConnected.signInSlot")(function* (
|
|
|
242
242
|
|
|
243
243
|
/** Orders belong to one client registration. Moving a profile to another client
|
|
244
244
|
* requires a newer profile generation; retired clients cannot replace it later. */
|
|
245
|
-
const canReplace = (
|
|
245
|
+
const canReplace = Effect.fnUntraced(function* (
|
|
246
246
|
reservation: M.OAuthSignInAccessClaim,
|
|
247
247
|
previous: M.OAuthConnectedTokenContext,
|
|
248
|
-
)
|
|
248
|
+
) {
|
|
249
249
|
const generation = reservation.configuration.profile.generation;
|
|
250
250
|
const oldGeneration = previous.configuration.profile.generation;
|
|
251
251
|
|
|
252
|
-
return S.clientKey(reservation.configuration) ===
|
|
252
|
+
return (yield* S.clientKey(reservation.configuration)) ===
|
|
253
|
+
(yield* S.clientKey(previous.configuration))
|
|
253
254
|
? generation >= oldGeneration &&
|
|
254
255
|
S.orderNumber(reservation.order) > S.orderNumber(previous.exchangeOrder)
|
|
255
256
|
: generation > oldGeneration;
|
|
256
|
-
};
|
|
257
|
+
});
|
|
257
258
|
|
|
258
259
|
export const inspectSignIn = Effect.fn("oauthConnected.inspectSignIn")(function* (
|
|
259
260
|
mapping: S.Mapping,
|
|
@@ -293,7 +294,7 @@ export const inspectSignIn = Effect.fn("oauthConnected.inspectSignIn")(function*
|
|
|
293
294
|
co.blocked ||
|
|
294
295
|
S.orderNumber(r.order) <= co.cutoff ||
|
|
295
296
|
previous?.row[mapping.grant.refreshWork] === "Unresolved" ||
|
|
296
|
-
(previous !== undefined && !canReplace(r, previous.context));
|
|
297
|
+
(previous !== undefined && !(yield* canReplace(r, previous.context)));
|
|
297
298
|
|
|
298
299
|
return snapshotOAuthSync(M.OAuthSignInAccessInspection, {
|
|
299
300
|
_tag: quarantine ? "Quarantine" : "Target",
|
|
@@ -377,7 +378,7 @@ export const settleSignIn = Effect.fn("oauthConnected.settleSignIn")(function* (
|
|
|
377
378
|
F.sameTarget(out.previous, previous.context) &&
|
|
378
379
|
sameIdentity(previous.context.identity, token.identity) &&
|
|
379
380
|
previous.row[mapping.grant.refreshWork] !== "Unresolved" &&
|
|
380
|
-
canReplace(r, previous.context);
|
|
381
|
+
(yield* canReplace(r, previous.context));
|
|
381
382
|
|
|
382
383
|
const previousSafe = yield* C.noFormerOwner(mapping, tuple.key, cl.id, native);
|
|
383
384
|
|
|
@@ -107,11 +107,11 @@ export const nativeOrder = (mapping: Authority, value: unknown) =>
|
|
|
107
107
|
const encoder = new TextEncoder();
|
|
108
108
|
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
109
109
|
|
|
110
|
-
const key = (domain: string, fields: ReadonlyArray<string>)
|
|
110
|
+
const key = Effect.fnUntraced(function* (domain: string, fields: ReadonlyArray<string>) {
|
|
111
111
|
for (const value of fields) invariant(decoder.decode(encoder.encode(value)) === value);
|
|
112
112
|
|
|
113
|
-
return "v1:" + digest(strings.encode([domain, ...fields]));
|
|
114
|
-
};
|
|
113
|
+
return "v1:" + (yield* digest(strings.encode([domain, ...fields])));
|
|
114
|
+
});
|
|
115
115
|
|
|
116
116
|
export const clientKey = (configuration: M.OAuthConnectedConfiguration) =>
|
|
117
117
|
key("effect-auth/oauth-connected-client/v1", [
|
|
@@ -124,7 +124,9 @@ export const cohortKey = (client: string, identity: string) =>
|
|
|
124
124
|
key("effect-auth/oauth-connected-cohort/v1", [client, identity]);
|
|
125
125
|
|
|
126
126
|
export const initialGeneration = (cohort: string) =>
|
|
127
|
-
|
|
127
|
+
digest(cohort).pipe(
|
|
128
|
+
Effect.map((value) => M.OAuthConnectedTarget.fields.cohortGeneration.make("initial:" + value)),
|
|
129
|
+
);
|
|
128
130
|
|
|
129
131
|
export const configuration = (flow: M.OAuthConnectedPendingFlow): M.OAuthConnectedConfiguration =>
|
|
130
132
|
snapshotOAuthSync(M.OAuthConnectedConfiguration, flow.context);
|
|
@@ -254,9 +256,9 @@ export const action = Effect.fn("oauthConnected.action")(function* (
|
|
|
254
256
|
? "connected-disconnect"
|
|
255
257
|
: "connected-complete";
|
|
256
258
|
|
|
257
|
-
const intentDigest = digest(expected.intent);
|
|
259
|
+
const intentDigest = yield* digest(expected.intent);
|
|
258
260
|
|
|
259
|
-
const binding = digest(
|
|
261
|
+
const binding = yield* digest(
|
|
260
262
|
strings.encode([
|
|
261
263
|
"effect-auth/oauth-connected-action/v1",
|
|
262
264
|
expected.moduleId,
|
|
@@ -364,7 +366,9 @@ export const useAuthority = Effect.fn("oauthConnected.useAuthority")(function* (
|
|
|
364
366
|
});
|
|
365
367
|
|
|
366
368
|
export const scopeKey = (provider: string, issuer: string) =>
|
|
367
|
-
|
|
369
|
+
key("effect-auth/oauth-connected-provider-issuer/v1", [provider, issuer]).pipe(
|
|
370
|
+
Effect.map((value) => "scope:" + value),
|
|
371
|
+
);
|
|
368
372
|
|
|
369
373
|
export interface ScopeAnchor {
|
|
370
374
|
readonly id: string;
|
|
@@ -412,7 +416,7 @@ export const scope = Effect.fn("oauthConnected.scope")(function* (
|
|
|
412
416
|
const owner = yield* CurrentOAuthTransaction;
|
|
413
417
|
|
|
414
418
|
const c = mapping.client,
|
|
415
|
-
id = scopeKey(config.provider, config.issuer),
|
|
419
|
+
id = yield* scopeKey(config.provider, config.issuer),
|
|
416
420
|
cache = yield* anchors(scopeCache, c.table);
|
|
417
421
|
|
|
418
422
|
const existing = cache.get(id);
|
|
@@ -497,7 +501,7 @@ export const readScope = Effect.fn("oauthConnected.readScope")(function* (
|
|
|
497
501
|
const owner = yield* CurrentOAuthTransaction;
|
|
498
502
|
|
|
499
503
|
const c = mapping.client,
|
|
500
|
-
id = scopeKey(provider, issuer),
|
|
504
|
+
id = yield* scopeKey(provider, issuer),
|
|
501
505
|
cache = yield* anchors(scopeCache, c.table),
|
|
502
506
|
cached = cache.get(id);
|
|
503
507
|
|
|
@@ -549,12 +553,12 @@ export const lockClientById = Effect.fn("oauthConnected.lockClientById")(functio
|
|
|
549
553
|
row !== undefined &&
|
|
550
554
|
row[c.clientRegistrationId] !== "" &&
|
|
551
555
|
id ===
|
|
552
|
-
key("effect-auth/oauth-connected-client/v1", [
|
|
556
|
+
(yield* key("effect-auth/oauth-connected-client/v1", [
|
|
553
557
|
row[c.provider],
|
|
554
558
|
row[c.issuer],
|
|
555
559
|
row[c.clientRegistrationId],
|
|
556
|
-
]) &&
|
|
557
|
-
scope.id === scopeKey(row[c.provider], row[c.issuer]),
|
|
560
|
+
])) &&
|
|
561
|
+
scope.id === (yield* scopeKey(row[c.provider], row[c.issuer])),
|
|
558
562
|
);
|
|
559
563
|
const found = { id, row, counter: nativeOrder(mapping, row[c.counter]), scope };
|
|
560
564
|
|
|
@@ -563,10 +567,15 @@ export const lockClientById = Effect.fn("oauthConnected.lockClientById")(functio
|
|
|
563
567
|
return found;
|
|
564
568
|
});
|
|
565
569
|
|
|
566
|
-
export const heldScope = (
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
+
export const heldScope = Effect.fnUntraced(function* (
|
|
571
|
+
mapping: Authority,
|
|
572
|
+
provider: string,
|
|
573
|
+
issuer: string,
|
|
574
|
+
) {
|
|
575
|
+
const cache = yield* anchors(scopeCache, mapping.client.table);
|
|
576
|
+
|
|
577
|
+
return cache.get(yield* scopeKey(provider, issuer));
|
|
578
|
+
});
|
|
570
579
|
|
|
571
580
|
/** Cleanup obtains every scope then every client before entering any tuple. */
|
|
572
581
|
export const prelockClients = Effect.fn("oauthConnected.prelockClients")(function* (
|
|
@@ -583,7 +592,7 @@ export const prelockClients = Effect.fn("oauthConnected.prelockClients")(functio
|
|
|
583
592
|
const scopes = new Map<string, { provider: string; issuer: string; required: boolean }>();
|
|
584
593
|
|
|
585
594
|
for (const value of releaseScopes)
|
|
586
|
-
scopes.set(scopeKey(value.provider, value.issuer), { ...value, required: false });
|
|
595
|
+
scopes.set(yield* scopeKey(value.provider, value.issuer), { ...value, required: false });
|
|
587
596
|
for (const id of unique) {
|
|
588
597
|
const read = yield* owner.read(c.table, equal(c.table, { [c.clientKey]: id }), {
|
|
589
598
|
limit: 1,
|
|
@@ -593,7 +602,7 @@ export const prelockClients = Effect.fn("oauthConnected.prelockClients")(functio
|
|
|
593
602
|
row = read.rows[0];
|
|
594
603
|
|
|
595
604
|
invariant(row !== undefined);
|
|
596
|
-
scopes.set(scopeKey(row[c.provider], row[c.issuer]), {
|
|
605
|
+
scopes.set(yield* scopeKey(row[c.provider], row[c.issuer]), {
|
|
597
606
|
provider: row[c.provider],
|
|
598
607
|
issuer: row[c.issuer],
|
|
599
608
|
required: true,
|
|
@@ -629,7 +638,7 @@ export const client = Effect.fn("oauthConnected.client")(function* (
|
|
|
629
638
|
const owner = yield* CurrentOAuthTransaction;
|
|
630
639
|
|
|
631
640
|
const c = mapping.client,
|
|
632
|
-
id = clientKey(config),
|
|
641
|
+
id = yield* clientKey(config),
|
|
633
642
|
where = { [c.clientKey]: id };
|
|
634
643
|
|
|
635
644
|
const heldScope = yield* scope(mapping, config, create);
|
|
@@ -723,7 +732,7 @@ export const cohort = Effect.fn("oauthConnected.cohort")(function* (
|
|
|
723
732
|
const owner = yield* CurrentOAuthTransaction;
|
|
724
733
|
|
|
725
734
|
const c = mapping.cohort,
|
|
726
|
-
id = cohortKey(clientId, identityId),
|
|
735
|
+
id = yield* cohortKey(clientId, identityId),
|
|
727
736
|
where = { [c.cohortKey]: id };
|
|
728
737
|
|
|
729
738
|
let read = yield* owner.read(c.table, equal(c.table, where), { limit: 1 });
|
|
@@ -755,7 +764,7 @@ export const cohort = Effect.fn("oauthConnected.cohort")(function* (
|
|
|
755
764
|
...where,
|
|
756
765
|
[c.clientKey]: clientId,
|
|
757
766
|
[c.identityKey]: identityId,
|
|
758
|
-
[c.generation]: initialGeneration(id),
|
|
767
|
+
[c.generation]: yield* initialGeneration(id),
|
|
759
768
|
[c.cutoff]: mapping.order.encode(0),
|
|
760
769
|
[c.state]: "Open",
|
|
761
770
|
[c.version]: owner.marker,
|
|
@@ -769,7 +778,13 @@ export const cohort = Effect.fn("oauthConnected.cohort")(function* (
|
|
|
769
778
|
const row = read.rows[0];
|
|
770
779
|
|
|
771
780
|
if (row === undefined)
|
|
772
|
-
return {
|
|
781
|
+
return {
|
|
782
|
+
id,
|
|
783
|
+
row: undefined,
|
|
784
|
+
generation: yield* initialGeneration(id),
|
|
785
|
+
cutoff: 0,
|
|
786
|
+
blocked: false,
|
|
787
|
+
};
|
|
773
788
|
invariant(
|
|
774
789
|
row[c.clientKey] === clientId &&
|
|
775
790
|
row[c.identityKey] === identityId &&
|
|
@@ -816,9 +831,9 @@ export const readGrant = Effect.fn("oauthConnected.readGrant")(function* (
|
|
|
816
831
|
context.moduleId === moduleId &&
|
|
817
832
|
context.grantId === grantId &&
|
|
818
833
|
mapping.subjectId.equals(native, row[g.subjectId]) &&
|
|
819
|
-
row[g.identityKey] === oauthIdentityKey(context.identity) &&
|
|
820
|
-
row[g.clientKey] === clientKey(context.configuration) &&
|
|
821
|
-
row[g.cohortKey] === cohortKey(row[g.clientKey], row[g.identityKey]) &&
|
|
834
|
+
row[g.identityKey] === (yield* oauthIdentityKey(context.identity)) &&
|
|
835
|
+
row[g.clientKey] === (yield* clientKey(context.configuration)) &&
|
|
836
|
+
row[g.cohortKey] === (yield* cohortKey(row[g.clientKey], row[g.identityKey])) &&
|
|
822
837
|
row[g.profileKey] === context.configuration.profile.key &&
|
|
823
838
|
row[g.grantVersion] === context.grantVersion &&
|
|
824
839
|
row[g.tokenVersion] === context.tokenVersion &&
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
type PrepareOAuthCommit,
|
|
9
9
|
} from "@yielded/auth/OAuth";
|
|
10
10
|
/* oxlint-disable no-explicit-any -- concrete adapters retain the native database, table and ID types. */
|
|
11
|
-
import { Effect, Layer, Schema } from "effect";
|
|
11
|
+
import { type Crypto, Effect, Layer, type PlatformError, Schema } from "effect";
|
|
12
12
|
import type { Statement } from "effect/sql/Statement";
|
|
13
13
|
|
|
14
14
|
import type { PersistenceMappingError } from "./model";
|
|
@@ -94,8 +94,10 @@ const mutation =
|
|
|
94
94
|
input: Input,
|
|
95
95
|
) => Effect.Effect<
|
|
96
96
|
Value,
|
|
97
|
-
import("@yielded/auth/OAuth").OAuthUnavailable
|
|
98
|
-
|
|
97
|
+
| import("@yielded/auth/OAuth").OAuthUnavailable
|
|
98
|
+
| PersistenceMappingError
|
|
99
|
+
| PlatformError.PlatformError,
|
|
100
|
+
CurrentOAuthTransaction | Crypto.Crypto
|
|
99
101
|
>,
|
|
100
102
|
schema: Schema.Codec<Value, Encoded, never, never>,
|
|
101
103
|
) =>
|
|
@@ -111,8 +113,10 @@ const read =
|
|
|
111
113
|
input: Input,
|
|
112
114
|
) => Effect.Effect<
|
|
113
115
|
Value,
|
|
114
|
-
import("@yielded/auth/OAuth").OAuthUnavailable
|
|
115
|
-
|
|
116
|
+
| import("@yielded/auth/OAuth").OAuthUnavailable
|
|
117
|
+
| PersistenceMappingError
|
|
118
|
+
| PlatformError.PlatformError,
|
|
119
|
+
CurrentOAuthTransaction | Crypto.Crypto
|
|
116
120
|
>,
|
|
117
121
|
) =>
|
|
118
122
|
(input: Input) =>
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
OAuthSignInPersistence,
|
|
7
7
|
} from "@yielded/auth/OAuth";
|
|
8
8
|
import type { Table } from "drizzle-orm";
|
|
9
|
-
import { Effect, Context } from "effect";
|
|
9
|
+
import { type Crypto, Effect, Context } from "effect";
|
|
10
10
|
|
|
11
11
|
import { nativeDatabase } from "./native-database";
|
|
12
12
|
import { makeOAuthConnectedTarget } from "./oauth-connected-drivers";
|
|
@@ -70,6 +70,7 @@ export const makeOAuthTarget = <
|
|
|
70
70
|
A,
|
|
71
71
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
72
72
|
| (Synchronous extends true ? never : Exclude<R, OAuthSignInPersistence>)
|
|
73
|
+
| Crypto.Crypto
|
|
73
74
|
| LifecycleHooks
|
|
74
75
|
| DatabaseRequirements
|
|
75
76
|
>;
|
|
@@ -103,6 +104,7 @@ export const makeOAuthTarget = <
|
|
|
103
104
|
A,
|
|
104
105
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
105
106
|
| (Synchronous extends true ? never : Exclude<R, OAuthSignInPersistence | TxId>)
|
|
107
|
+
| Crypto.Crypto
|
|
106
108
|
| LifecycleHooks
|
|
107
109
|
| DatabaseRequirements
|
|
108
110
|
>;
|
|
@@ -131,7 +133,7 @@ export const makeOAuthTarget = <
|
|
|
131
133
|
): Effect.Effect<
|
|
132
134
|
A,
|
|
133
135
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
134
|
-
Exclude<R, OAuthSignInPersistence> | LifecycleHooks | DatabaseRequirements
|
|
136
|
+
Exclude<R, OAuthSignInPersistence> | Crypto.Crypto | LifecycleHooks | DatabaseRequirements
|
|
135
137
|
> {
|
|
136
138
|
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
137
139
|
coordinateTargetOAuthSignIn<
|
|
@@ -183,6 +185,7 @@ export const makeOAuthTarget = <
|
|
|
183
185
|
A,
|
|
184
186
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
185
187
|
| (Synchronous extends true ? never : Exclude<R, OAuthRegistrationIntents>)
|
|
188
|
+
| Crypto.Crypto
|
|
186
189
|
| LifecycleHooks
|
|
187
190
|
| DatabaseRequirements
|
|
188
191
|
>;
|
|
@@ -218,6 +221,7 @@ export const makeOAuthTarget = <
|
|
|
218
221
|
A,
|
|
219
222
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
220
223
|
| (Synchronous extends true ? never : Exclude<R, OAuthRegistrationIntents | TxId>)
|
|
224
|
+
| Crypto.Crypto
|
|
221
225
|
| LifecycleHooks
|
|
222
226
|
| DatabaseRequirements
|
|
223
227
|
>;
|
|
@@ -248,7 +252,7 @@ export const makeOAuthTarget = <
|
|
|
248
252
|
): Effect.Effect<
|
|
249
253
|
A,
|
|
250
254
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
251
|
-
Exclude<R, OAuthRegistrationIntents> | LifecycleHooks | DatabaseRequirements
|
|
255
|
+
Exclude<R, OAuthRegistrationIntents> | Crypto.Crypto | LifecycleHooks | DatabaseRequirements
|
|
252
256
|
> {
|
|
253
257
|
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
254
258
|
coordinateTargetOAuthRegistrationIntents<
|
|
@@ -304,6 +308,7 @@ export const makeOAuthTarget = <
|
|
|
304
308
|
A,
|
|
305
309
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
306
310
|
| (Synchronous extends true ? never : Exclude<R, OAuthAccountsPersistence>)
|
|
311
|
+
| Crypto.Crypto
|
|
307
312
|
| LifecycleHooks
|
|
308
313
|
| DatabaseRequirements
|
|
309
314
|
>;
|
|
@@ -339,6 +344,7 @@ export const makeOAuthTarget = <
|
|
|
339
344
|
A,
|
|
340
345
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
341
346
|
| (Synchronous extends true ? never : Exclude<R, OAuthAccountsPersistence | TxId>)
|
|
347
|
+
| Crypto.Crypto
|
|
342
348
|
| LifecycleHooks
|
|
343
349
|
| DatabaseRequirements
|
|
344
350
|
>;
|
|
@@ -369,7 +375,7 @@ export const makeOAuthTarget = <
|
|
|
369
375
|
): Effect.Effect<
|
|
370
376
|
A,
|
|
371
377
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
372
|
-
Exclude<R, OAuthAccountsPersistence> | LifecycleHooks | DatabaseRequirements
|
|
378
|
+
Exclude<R, OAuthAccountsPersistence> | Crypto.Crypto | LifecycleHooks | DatabaseRequirements
|
|
373
379
|
> {
|
|
374
380
|
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
375
381
|
coordinateTargetOAuthAccounts<
|
|
@@ -428,6 +434,7 @@ export const makeOAuthTarget = <
|
|
|
428
434
|
A,
|
|
429
435
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
430
436
|
| (Synchronous extends true ? never : Exclude<R, TargetId>)
|
|
437
|
+
| Crypto.Crypto
|
|
431
438
|
| LifecycleHooks
|
|
432
439
|
| DatabaseRequirements
|
|
433
440
|
>;
|
|
@@ -462,6 +469,7 @@ export const makeOAuthTarget = <
|
|
|
462
469
|
A,
|
|
463
470
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
464
471
|
| (Synchronous extends true ? never : Exclude<R, TargetId | TxId>)
|
|
472
|
+
| Crypto.Crypto
|
|
465
473
|
| LifecycleHooks
|
|
466
474
|
| DatabaseRequirements
|
|
467
475
|
>;
|
|
@@ -495,7 +503,7 @@ export const makeOAuthTarget = <
|
|
|
495
503
|
): Effect.Effect<
|
|
496
504
|
A,
|
|
497
505
|
OAuthCoordinatorError<E> | DatabaseError,
|
|
498
|
-
Exclude<R, TargetId> | LifecycleHooks | DatabaseRequirements
|
|
506
|
+
Exclude<R, TargetId> | Crypto.Crypto | LifecycleHooks | DatabaseRequirements
|
|
499
507
|
> {
|
|
500
508
|
return Effect.flatMap(nativeDatabase(acquire), (database) =>
|
|
501
509
|
coordinateTargetOAuthRegistration<
|
|
@@ -301,7 +301,7 @@ export const currentSubject = (mapping: any, nativeId: unknown) =>
|
|
|
301
301
|
export const discoverOwned = (mapping: any, identity: OAuthVerifiedExternalIdentity["identity"]) =>
|
|
302
302
|
Effect.flatMap(CurrentOAuthTransaction, (owner) =>
|
|
303
303
|
Effect.gen(function* () {
|
|
304
|
-
const key = oauthIdentityKey(identity),
|
|
304
|
+
const key = yield* oauthIdentityKey(identity),
|
|
305
305
|
o = mapping.ownership;
|
|
306
306
|
|
|
307
307
|
const where = both(eq(col(o.table, o.identityKey), key), o.ownedCondition);
|
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
import type { AuthenticationFactor } from "@yielded/auth/Operations";
|
|
9
9
|
import type { AuthenticationRequirement, SecurityRevision } from "@yielded/auth/Sessions";
|
|
10
10
|
import type { InferInsertModel, InferSelectModel, SQL, Table } from "drizzle-orm";
|
|
11
|
-
import type { Effect } from "effect";
|
|
11
|
+
import type { Crypto, Effect, PlatformError } from "effect";
|
|
12
12
|
|
|
13
13
|
import type { PersistenceMappingError, SubjectIdCodec } from "./model";
|
|
14
14
|
|
|
@@ -506,8 +506,8 @@ export const oauthCleanupTable = <T extends Table, N>(
|
|
|
506
506
|
Object.freeze({ table: input.table, subjectId: input.subjectId, condition: input.condition });
|
|
507
507
|
|
|
508
508
|
/** A stable application/reference lock acquired before an ownership target.
|
|
509
|
-
* Missing rows retain ownership. Conditions
|
|
510
|
-
*
|
|
509
|
+
* Missing rows retain ownership. Conditions use detached native IDs; every
|
|
510
|
+
* writer of the guarded reference follows the same order. */
|
|
511
511
|
export interface OAuthReferenceGuardTable<T extends Table, N> {
|
|
512
512
|
readonly table: T;
|
|
513
513
|
readonly orderBy: Column<T>;
|
|
@@ -515,7 +515,7 @@ export interface OAuthReferenceGuardTable<T extends Table, N> {
|
|
|
515
515
|
readonly identity: typeof OAuthExternalIdentity.Type;
|
|
516
516
|
readonly identityKey: string;
|
|
517
517
|
readonly subjectId: N;
|
|
518
|
-
}) => SQL
|
|
518
|
+
}) => SQL | Effect.Effect<SQL, PlatformError.PlatformError, Crypto.Crypto>;
|
|
519
519
|
}
|
|
520
520
|
|
|
521
521
|
export interface OAuthReferenceGuardDescriptor<N> {
|
|
@@ -40,7 +40,7 @@ export const readTuple = (ownership: any, identity: typeof OAuthExternalIdentity
|
|
|
40
40
|
Effect.flatMap(CurrentOAuthTransaction, (owner) =>
|
|
41
41
|
Effect.gen(function* () {
|
|
42
42
|
const t = ownership.tuple,
|
|
43
|
-
key = oauthIdentityKey(identity);
|
|
43
|
+
key = yield* oauthIdentityKey(identity);
|
|
44
44
|
|
|
45
45
|
const where = { [t.identityKey]: key };
|
|
46
46
|
const observed = yield* owner.read(t.table, equal(t.table, where), { limit: 1 });
|
|
@@ -259,7 +259,7 @@ export const inspectIntent = (
|
|
|
259
259
|
row[i.reference] === intent.reference &&
|
|
260
260
|
row[i.flowId] === c.flowId &&
|
|
261
261
|
row[i.claimId] === intent.claimId &&
|
|
262
|
-
row[i.identityKey] === oauthIdentityKey(intent.identity) &&
|
|
262
|
+
row[i.identityKey] === (yield* oauthIdentityKey(intent.identity)) &&
|
|
263
263
|
mapping.clock.decodeInstant(row[i.expiresAt]) === intent.expiresAtMillis &&
|
|
264
264
|
mapping.clock.decodeInstant(row[i.retentionUntil]) === intent.retentionUntilMillis,
|
|
265
265
|
);
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
// oxlint-disable-next-line import/extensions -- Noble exposes only its explicit .js subpath.
|
|
2
|
-
import { sha256 } from "@noble/hashes/sha2.js";
|
|
3
|
-
// oxlint-disable-next-line import/extensions -- Noble exposes only its explicit .js subpath.
|
|
4
|
-
import { randomBytes } from "@noble/hashes/utils.js";
|
|
5
1
|
import {
|
|
6
2
|
type OAuthActionAuthorization,
|
|
7
3
|
type OAuthAccountRevision,
|
|
@@ -10,9 +6,12 @@ import {
|
|
|
10
6
|
snapshotOAuthSync,
|
|
11
7
|
} from "@yielded/auth/OAuth";
|
|
12
8
|
import type { AuthenticationRequirement } from "@yielded/auth/Sessions";
|
|
13
|
-
import { DateTime, Effect, Schema } from "effect";
|
|
9
|
+
import { Crypto, DateTime, Effect, Schema } from "effect";
|
|
14
10
|
import { Base64Url } from "effect/encoding";
|
|
15
11
|
|
|
12
|
+
import { digest, randomId } from "./crypto";
|
|
13
|
+
export { digest } from "./crypto";
|
|
14
|
+
|
|
16
15
|
const encoder = new TextEncoder();
|
|
17
16
|
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
18
17
|
|
|
@@ -22,8 +21,7 @@ export const invariant: (value: unknown) => asserts value = (value) => {
|
|
|
22
21
|
if (!value) throw unavailable();
|
|
23
22
|
};
|
|
24
23
|
|
|
25
|
-
export const nonce =
|
|
26
|
-
export const digest = (value: string) => Base64Url.encode(sha256(encoder.encode(value)));
|
|
24
|
+
export const nonce = randomId;
|
|
27
25
|
|
|
28
26
|
/** Capture configuration/callback references while preserving Drizzle table, SQL
|
|
29
27
|
* and Effect objects. Never freeze or mutate the consumer's original graph. */
|
|
@@ -57,7 +55,9 @@ export const captureOAuthMapping = <A>(input: A): A => {
|
|
|
57
55
|
|
|
58
56
|
/** Versioned length-delimited UTF-8 tuple; the module is deliberately excluded.
|
|
59
57
|
* Reject ill-formed UTF-16 rather than letting UTF-8 replacement alias identities. */
|
|
60
|
-
export const oauthIdentityKey = (
|
|
58
|
+
export const oauthIdentityKey = Effect.fnUntraced(function* (
|
|
59
|
+
input: typeof OAuthExternalIdentity.Type,
|
|
60
|
+
) {
|
|
61
61
|
const identity = snapshotOAuthSync(OAuthExternalIdentity, input);
|
|
62
62
|
|
|
63
63
|
const fields = [
|
|
@@ -85,8 +85,10 @@ export const oauthIdentityKey = (input: typeof OAuthExternalIdentity.Type): stri
|
|
|
85
85
|
offset += 4 + value.length;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
const crypto = yield* Crypto.Crypto;
|
|
89
|
+
|
|
90
|
+
return "v1:" + Base64Url.encode(yield* crypto.digest("SHA-256", packed));
|
|
91
|
+
});
|
|
90
92
|
|
|
91
93
|
export const sameIdentity = (
|
|
92
94
|
left: typeof OAuthExternalIdentity.Type,
|
|
@@ -148,7 +150,7 @@ export const satisfies = (
|
|
|
148
150
|
);
|
|
149
151
|
};
|
|
150
152
|
|
|
151
|
-
export const validAction = (
|
|
153
|
+
export const validAction = Effect.fnUntraced(function* (
|
|
152
154
|
authorization: OAuthActionAuthorization,
|
|
153
155
|
expected: {
|
|
154
156
|
readonly moduleId: string;
|
|
@@ -161,12 +163,12 @@ export const validAction = (
|
|
|
161
163
|
currentRequirement: AuthenticationRequirement,
|
|
162
164
|
now: number,
|
|
163
165
|
maximumAgeMillis: number,
|
|
164
|
-
)
|
|
166
|
+
) {
|
|
165
167
|
const challenge = authorization.challenge;
|
|
166
168
|
const evidence = authorization.evidence;
|
|
167
|
-
const intentDigest = digest(expected.intent);
|
|
169
|
+
const intentDigest = yield* digest(expected.intent);
|
|
168
170
|
|
|
169
|
-
const binding = digest(
|
|
171
|
+
const binding = yield* digest(
|
|
170
172
|
// oxlint-disable-next-line no-restricted-properties -- Fixed private action fingerprint format shared with the core verifier.
|
|
171
173
|
JSON.stringify([
|
|
172
174
|
"effect-auth/oauth-action/v1",
|
|
@@ -213,4 +215,4 @@ export const validAction = (
|
|
|
213
215
|
|
|
214
216
|
return satisfies(fresh, requirement);
|
|
215
217
|
});
|
|
216
|
-
};
|
|
218
|
+
});
|