@yielded/auth-persistence 0.1.0-beta.22 → 0.1.0-beta.24
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 +13 -5
- package/dist/Adapter.mjs +9 -2
- 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/authority-snapshot.mjs +53 -0
- package/dist/internal/authority-snapshot.mjs.map +1 -0
- package/dist/internal/configuration.d.mts +1 -1
- package/dist/internal/configuration.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 +4 -97
- package/dist/internal/models/password-model.mjs +0 -3
- package/dist/internal/models/password-model.mjs.map +1 -1
- package/dist/internal/native-sql-table.d.mts +34 -0
- package/dist/internal/native-sql-table.mjs +111 -0
- package/dist/internal/native-sql-table.mjs.map +1 -0
- 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/target.d.mts +1 -1
- package/dist/internal/passkey-kernel.d.mts +5 -5
- package/dist/internal/passkeys.mjs +1 -1
- package/dist/internal/password-credentials.d.mts +11 -0
- package/dist/internal/password-credentials.mjs +121 -0
- package/dist/internal/password-credentials.mjs.map +1 -0
- package/dist/internal/password-kernel.d.mts +15 -28
- package/dist/internal/password-kernel.mjs +35 -236
- package/dist/internal/password-kernel.mjs.map +1 -1
- package/dist/internal/persistence.d.mts +2 -0
- package/dist/internal/persistence.mjs +5 -5
- package/dist/internal/persistence.mjs.map +1 -1
- package/dist/internal/query-operations.d.mts +2 -0
- package/dist/internal/session-kernel.d.mts +5 -3
- package/dist/internal/session-kernel.mjs +95 -29
- 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-persistence.mjs +3 -1
- package/dist/internal/sql-persistence.mjs.map +1 -1
- 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 +2 -67
- 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 -99
- package/dist/internal/storage-tables.mjs +0 -43
- 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-execution-kernel.d.mts +1 -1
- package/dist/internal/transaction-kernel.d.mts +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 +97 -8
- package/src/OAuthPersistence.ts +427 -0
- package/src/index.ts +3 -0
- package/src/internal/authority-snapshot.ts +91 -0
- package/src/internal/configuration.ts +1 -8
- 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 +0 -120
- package/src/internal/native-sql-table.ts +178 -0
- package/src/internal/oauth/accounts.ts +838 -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/password-credentials.ts +245 -0
- package/src/internal/password-kernel.ts +98 -712
- package/src/internal/persistence.ts +5 -10
- package/src/internal/query-operations.ts +2 -0
- package/src/internal/session-kernel.ts +231 -81
- package/src/internal/sql-oauth-connected-model.ts +145 -0
- package/src/internal/sql-oauth-model.ts +263 -0
- package/src/internal/sql-persistence.ts +2 -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 -66
- package/src/internal/storage-plans.ts +218 -0
- package/src/internal/storage-tables.ts +0 -35
- package/src/internal/storage-validation.ts +58 -0
- package/src/internal/transaction-kernel.ts +6 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-credentials.mjs","names":[],"sources":["../../src/internal/password-credentials.ts"],"sourcesContent":["import { CurrentCommitJournal, hasCommitScope } from \"@yielded/auth/Hooks\";\nimport type { LoginIdentifier } from \"@yielded/auth/Identity\";\nimport {\n EncodedPasswordHash,\n type PasswordPersistence,\n PasswordUnavailable,\n snapshotPasswordCredential,\n type PasswordCredentialSnapshot,\n} from \"@yielded/auth/Password\";\nimport { reportPersistenceFailure } from \"@yielded/auth/Persistence\";\nimport { Effect, Option, Redacted, Schema } from \"effect\";\n\nimport type { PersistenceMappingError } from \"./mapping-error\";\nimport type { AnyPasswordPersistenceMapping } from \"./models/password-model\";\nimport { sqlMapping, type SqlTable } from \"./native-sql-table\";\nimport type { PasswordSqlConfiguration } from \"./password-kernel\";\nimport { NativeDatabase } from \"./transaction-kernel\";\n\ntype Row = Readonly<Record<string, unknown>>;\nconst unavailable = () => PasswordUnavailable.make({});\n\nconst failure = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n reportPersistenceFailure(effect, Schema.is(PasswordUnavailable)).pipe(\n Effect.mapError(unavailable),\n );\n\nexport const samePasswordCredentialSnapshot = (\n a: PasswordCredentialSnapshot,\n b: PasswordCredentialSnapshot,\n) =>\n a.moduleId === b.moduleId &&\n a.revision.subjectId === b.revision.subjectId &&\n a.revision.securityRevision === b.revision.securityRevision &&\n a.revision.credentials.length === b.revision.credentials.length &&\n new Set(a.revision.credentials.map((entry) => entry.credentialId)).size ===\n a.revision.credentials.length &&\n new Set(b.revision.credentials.map((entry) => entry.credentialId)).size ===\n b.revision.credentials.length &&\n a.revision.credentials.every((entry) =>\n b.revision.credentials.some(\n (other) => entry.credentialId === other.credentialId && entry.revision === other.revision,\n ),\n ) &&\n a.credentialId === b.credentialId &&\n a.credentialRevision === b.credentialRevision &&\n a.verifierVersion === b.verifierVersion &&\n Redacted.value(a.verifier) === Redacted.value(b.verifier) &&\n a.normalization === b.normalization &&\n a.identifier.namespace === b.identifier.namespace &&\n a.identifier.value === b.identifier.value &&\n a.identifierBindingRevision === b.identifierBindingRevision &&\n a.identifierVerifiedAtMillis === b.identifierVerifiedAtMillis;\n\n/** Lookup is read-only; rehash is one conditional maintenance write, never authentication. */\nexport const makePasswordCredentials = Effect.fnUntraced(function* (\n table: (table: object) => SqlTable,\n mapping: AnyPasswordPersistenceMapping,\n options: PasswordSqlConfiguration,\n): Effect.fn.Return<\n Pick<PasswordPersistence[\"Service\"], \"findCredential\" | \"rehashIfCurrent\">,\n PasswordUnavailable,\n NativeDatabase\n> {\n const sql = (yield* NativeDatabase).$client.withoutTransforms();\n const parent = yield* Effect.serviceOption(CurrentCommitJournal);\n\n const [s, i, c] = yield* sqlMapping(\n () =>\n [\n table(mapping.subject.table),\n table(mapping.identifier.table),\n table(mapping.credential.table),\n ] as const,\n ).pipe(failure);\n\n const standalone = Effect.gen(function* () {\n if (options.coordinated) {\n const current = yield* Effect.serviceOption(CurrentCommitJournal);\n\n if (Option.isNone(parent) || Option.isNone(current) || parent.value !== current.value)\n return yield* unavailable();\n } else {\n if (yield* hasCommitScope) return yield* unavailable();\n yield* options.standaloneGuard;\n }\n });\n\n const allocate = <A>(\n asynchronous: Effect.Effect<A, PersistenceMappingError> | undefined,\n sync: (() => A) | undefined,\n ) => {\n if (options.mode !== \"synchronous\" && asynchronous !== undefined) return asynchronous;\n\n return sync === undefined\n ? Effect.fail(unavailable())\n : Effect.try({ try: sync, catch: unavailable });\n };\n\n // Bind each native ID through its own column codec. Physical encodings of the\n // same application ID need not match across subject, identifier and password.\n const snapshot = Effect.fnUntraced(function* (\n nativeId: unknown,\n moduleId: string,\n identifier: LoginIdentifier,\n ) {\n const subjectTable = s.as(\"password_subject\");\n const identifierTable = i.as(\"password_identifier\");\n const credentialTable = c.as(\"password_credential\");\n\n const rows = yield* sqlMapping(\n () =>\n sql<Row>`select ${subjectTable.fields(\"subject_\")}, ${identifierTable.fields(\"identifier_\")}, ${credentialTable.fields(\"credential_\")}\n from ${subjectTable.name}\n inner join ${identifierTable.name} on ${identifierTable.column(mapping.identifier.namespace)} = ${identifierTable.value(mapping.identifier.namespace, identifier.namespace)}\n and ${identifierTable.column(mapping.identifier.value)} = ${identifierTable.value(mapping.identifier.value, identifier.value)}\n and ${identifierTable.column(mapping.identifier.subjectId)} = ${identifierTable.value(mapping.identifier.subjectId, nativeId)}\n inner join ${credentialTable.name} on ${credentialTable.column(mapping.credential.moduleId)} = ${credentialTable.value(mapping.credential.moduleId, moduleId)}\n and ${credentialTable.column(mapping.credential.subjectId)} = ${credentialTable.value(mapping.credential.subjectId, nativeId)}\n where ${subjectTable.column(mapping.subject.id)} = ${subjectTable.value(mapping.subject.id, nativeId)}\n `,\n ).pipe(Effect.flatten);\n\n if (rows.length !== 1) return undefined;\n\n const [subject, identifierRow, credential] = yield* sqlMapping(\n () =>\n [\n s.decode(rows[0]!, \"subject_\"),\n i.decode(rows[0]!, \"identifier_\"),\n c.decode(rows[0]!, \"credential_\"),\n ] as const,\n );\n\n if (\n yield* sqlMapping(\n () =>\n !mapping.subject.isActiveStatus(subject[mapping.subject.status]) ||\n !mapping.identifier.isCurrent(identifierRow) ||\n !mapping.subjectId.equals(nativeId, identifierRow[mapping.identifier.subjectId]) ||\n !mapping.subjectId.equals(nativeId, subject[mapping.subject.id]) ||\n !mapping.subjectId.equals(nativeId, credential[mapping.credential.subjectId]),\n )\n )\n return undefined;\n\n const captured = yield* sqlMapping(() =>\n mapping.credential.decode({ moduleId, subject, identifier: identifierRow, credential }),\n ).pipe(Effect.flatten, Effect.flatMap(snapshotPasswordCredential));\n\n return captured;\n });\n\n return {\n findCredential: (uncaptured) =>\n Effect.gen(function* () {\n const input = { ...uncaptured, identifier: { ...uncaptured.identifier } };\n\n yield* standalone;\n\n const identifiers = yield* sqlMapping(\n () => sql<Row>`select ${i.fields(\"i_\")} from ${i.name}\n where ${i.column(mapping.identifier.namespace)} = ${i.value(mapping.identifier.namespace, input.identifier.namespace)}\n and ${i.column(mapping.identifier.value)} = ${i.value(mapping.identifier.value, input.identifier.value)}`,\n ).pipe(Effect.flatten);\n\n const identifier =\n identifiers.length === 1\n ? yield* sqlMapping(() => i.decode(identifiers[0]!, \"i_\"))\n : undefined;\n\n if (\n identifier === undefined ||\n !(yield* sqlMapping(() => mapping.identifier.isCurrent(identifier)))\n )\n return Option.none();\n\n const credential = yield* snapshot(\n identifier[mapping.identifier.subjectId],\n input.moduleId,\n input.identifier,\n );\n\n return credential === undefined ||\n (input.subjectId !== undefined && credential.revision.subjectId !== input.subjectId)\n ? Option.none()\n : Option.some(credential);\n }).pipe(failure),\n rehashIfCurrent: (input) =>\n Effect.gen(function* () {\n const nextVerifier = Redacted.make(\n yield* Schema.decodeEffect(EncodedPasswordHash)(Redacted.value(input.nextVerifier)),\n );\n\n const credential = yield* snapshotPasswordCredential(input.credential);\n\n yield* standalone;\n const nativeId = yield* mapping.subjectId.toNative(credential.revision.subjectId);\n const version = yield* allocate(mapping.allocateRevision, mapping.allocateRevisionSync);\n\n if (version === credential.verifierVersion) return yield* unavailable();\n yield* sqlMapping(() => {\n const encoded = mapping.credential.encodeVerifier(nextVerifier, version);\n\n // A custom encoder cannot turn maintenance into a semantic credential change.\n const values = {\n [mapping.credential.verifier]: encoded[mapping.credential.verifier],\n [mapping.credential.verifierVersion]: encoded[mapping.credential.verifierVersion],\n };\n\n if (Object.values(values).some((value) => value === undefined)) throw unavailable();\n\n // Ordinary identity predicates retain index use; the full CAS ignores text collation.\n const exact = sql.and(\n Object.entries({\n [mapping.credential.moduleId]: credential.moduleId,\n [mapping.credential.subjectId]: nativeId,\n [mapping.credential.credentialId]: credential.credentialId,\n [mapping.credential.credentialRevision]: credential.credentialRevision,\n [mapping.credential.verifierVersion]: credential.verifierVersion,\n [mapping.credential.verifier]: Redacted.value(credential.verifier),\n [mapping.credential.normalization]: credential.normalization,\n }).map(([key, value]) => {\n const column = c.column(key),\n bound = c.value(key, value);\n\n if (typeof value !== \"string\") return sql`${column} = ${bound}`;\n\n return sql.onDialectOrElse({\n mysql: () => sql`binary ${column} = binary ${bound}`,\n pg: () =>\n sql`convert_to(cast(${column} as text), 'UTF8') = convert_to(cast(${bound} as text), 'UTF8')`,\n orElse: () => sql`cast(${column} as blob) = cast(${bound} as blob)`,\n });\n }),\n );\n\n return sql`${c.update(values)}\n where ${c.column(mapping.credential.moduleId)} = ${c.value(mapping.credential.moduleId, credential.moduleId)}\n and ${c.column(mapping.credential.subjectId)} = ${c.value(mapping.credential.subjectId, nativeId)}\n and ${c.column(mapping.credential.credentialId)} = ${c.value(mapping.credential.credentialId, credential.credentialId)}\n and ${exact}`;\n }).pipe(Effect.flatten);\n }).pipe(failure),\n } satisfies Pick<PasswordPersistence[\"Service\"], \"findCredential\" | \"rehashIfCurrent\">;\n});\n"],"mappings":"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"}
|
|
@@ -3,12 +3,15 @@ import { NativeDatabase } from "./transaction-kernel.mjs";
|
|
|
3
3
|
import { QueryFailure, QueryOperations, SqlColumn, SqlFragment } from "./query-operations.mjs";
|
|
4
4
|
import { AnyPasswordPersistenceMapping } from "./models/password-model.mjs";
|
|
5
5
|
import { CurrentProofSql, ProofSqlConfiguration, makeProofKernel } from "./proof-kernel.mjs";
|
|
6
|
+
import { NativeSqlTables } from "./native-sql-table.mjs";
|
|
7
|
+
import { samePasswordCredentialSnapshot } from "./password-credentials.mjs";
|
|
6
8
|
import { Context, DateTime, Effect, Option, Redacted } from "effect";
|
|
7
9
|
import { CurrentCommitJournal, HookConfigurationError, LifecycleHooks, PreparedCommit } from "@yielded/auth/Hooks";
|
|
8
10
|
import { AuthenticationEvidence, AuthenticationRequirement, SecurityRevision } from "@yielded/auth/Sessions";
|
|
9
11
|
import { ProofCompletionInput, ProofCompletionPlan } from "@yielded/auth/Proofs";
|
|
10
|
-
import {
|
|
12
|
+
import { PasswordMutationDecision, PasswordMutationInput, PasswordUnavailable } from "@yielded/auth/Password";
|
|
11
13
|
import { LoginIdentifier } from "@yielded/auth/Identity";
|
|
14
|
+
import { SqlClient } from "effect/sql/SqlClient";
|
|
12
15
|
import * as SqlError$1 from "effect/sql/SqlError";
|
|
13
16
|
//#region src/internal/password-kernel.d.ts
|
|
14
17
|
type AdapterFailure = QueryFailure | PersistenceMappingError | SqlError$1.SqlError;
|
|
@@ -47,47 +50,31 @@ export interface PasswordSqlConfiguration {
|
|
|
47
50
|
};
|
|
48
51
|
}
|
|
49
52
|
type Database = PasswordSqlDatabase;
|
|
50
|
-
export declare const makePasswordKernel: <Fragment extends SqlFragment = SqlFragment, Column extends SqlColumn = SqlColumn>(operations: QueryOperations<Fragment, Column>, proofs: Pick<ReturnType<typeof makeProofKernel>, "completeProofPlanIn"
|
|
53
|
+
export declare const makePasswordKernel: <Fragment extends SqlFragment = SqlFragment, Column extends SqlColumn = SqlColumn>(operations: QueryOperations<Fragment, Column>, proofs: Pick<ReturnType<typeof makeProofKernel>, "completeProofPlanIn">, nativeTables?: (client: SqlClient, database: object) => NativeSqlTables) => {
|
|
51
54
|
makeSqlPasswordPersistence: (mapping: AnyPasswordPersistenceMapping<Fragment>, configuration: PasswordSqlConfiguration) => Effect.Effect<{
|
|
52
|
-
readonly
|
|
55
|
+
readonly findCredential: (input: {
|
|
53
56
|
readonly moduleId: string;
|
|
54
|
-
readonly action: "sign-in" | "change";
|
|
55
57
|
readonly identifier: LoginIdentifier;
|
|
56
58
|
readonly subjectId?: import("@yielded/auth/Schema").SubjectId;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
readonly
|
|
61
|
-
|
|
62
|
-
readonly captured?: PasswordCredentialSnapshot;
|
|
63
|
-
readonly outcome: PasswordAttemptDecision;
|
|
64
|
-
readonly rehash?: {
|
|
65
|
-
readonly expectedVersion: SecurityRevision;
|
|
66
|
-
readonly expectedVerifier: Redacted.Redacted<import("@yielded/auth/Password").EncodedPasswordHash>;
|
|
67
|
-
readonly nextVerifier: Redacted.Redacted<import("@yielded/auth/Password").EncodedPasswordHash>;
|
|
68
|
-
};
|
|
69
|
-
}, prepare: import("@yielded/auth/Password").PreparePasswordCommit<PasswordAttemptDecision, A>) => Effect.Effect<PreparedCommit<A>, PasswordUnavailable>;
|
|
59
|
+
}) => Effect.Effect<Option.Option<import("@yielded/auth/Password").PasswordCredentialSnapshot>, PasswordUnavailable>;
|
|
60
|
+
readonly rehashIfCurrent: (input: {
|
|
61
|
+
readonly credential: import("@yielded/auth/Password").PasswordCredentialSnapshot;
|
|
62
|
+
readonly nextVerifier: Redacted.Redacted<import("@yielded/auth/Password").EncodedPasswordHash>;
|
|
63
|
+
}) => Effect.Effect<void, PasswordUnavailable>;
|
|
70
64
|
readonly readForSubject: (input: {
|
|
71
65
|
readonly moduleId: string;
|
|
72
66
|
readonly subjectId: import("@yielded/auth/Schema").SubjectId;
|
|
73
|
-
}) => Effect.Effect<Option.Option<PasswordCredentialSnapshot>, PasswordUnavailable>;
|
|
67
|
+
}) => Effect.Effect<Option.Option<import("@yielded/auth/Password").PasswordCredentialSnapshot>, PasswordUnavailable>;
|
|
74
68
|
readonly recoveryTarget: (input: {
|
|
75
69
|
readonly moduleId: string;
|
|
76
70
|
readonly identifier: LoginIdentifier;
|
|
77
|
-
}) => Effect.Effect<Option.Option<PasswordCredentialSnapshot>, PasswordUnavailable>;
|
|
71
|
+
}) => Effect.Effect<Option.Option<import("@yielded/auth/Password").PasswordCredentialSnapshot>, PasswordUnavailable>;
|
|
78
72
|
readonly addIfAbsent: <A>(input: PasswordMutationInput, prepare: import("@yielded/auth/Password").PreparePasswordCommit<PasswordMutationDecision, A>) => Effect.Effect<PreparedCommit<A>, PasswordUnavailable>;
|
|
79
73
|
readonly replaceIfCurrent: <A>(input: PasswordMutationInput, prepare: import("@yielded/auth/Password").PreparePasswordCommit<PasswordMutationDecision, A>) => Effect.Effect<PreparedCommit<A>, PasswordUnavailable>;
|
|
80
74
|
readonly checkReset: (input: ProofCompletionInput) => Effect.Effect<boolean, PasswordUnavailable>;
|
|
81
75
|
readonly resetWithProof: <A>(input: PasswordMutationInput & {
|
|
82
76
|
readonly completion: ProofCompletionPlan;
|
|
83
77
|
}, prepare: import("@yielded/auth/Password").PreparePasswordCommit<PasswordMutationDecision, A>) => Effect.Effect<PreparedCommit<A>, PasswordUnavailable>;
|
|
84
|
-
readonly cleanupAttempts: <A>(input: {
|
|
85
|
-
readonly moduleId: string;
|
|
86
|
-
readonly limit: number;
|
|
87
|
-
}, prepare: import("@yielded/auth/Password").PreparePasswordCommit<{
|
|
88
|
-
readonly removed: number;
|
|
89
|
-
readonly hasMore: boolean;
|
|
90
|
-
}, A>) => Effect.Effect<PreparedCommit<A>, PasswordUnavailable>;
|
|
91
78
|
}, PasswordUnavailable, CurrentPasswordSql | LifecycleHooks | NativeDatabase>;
|
|
92
79
|
passwordSqlKernel: {
|
|
93
80
|
allocate: <A>(mode: PasswordSqlConfiguration["mode"], asyncValue: Effect.Effect<A, PersistenceMappingError> | undefined, syncValue: (() => A) | undefined) => Effect.Effect<A, PasswordUnavailable | PersistenceMappingError>;
|
|
@@ -203,8 +190,8 @@ export declare const makePasswordKernel: <Fragment extends SqlFragment = SqlFrag
|
|
|
203
190
|
nativeSubjectId: any;
|
|
204
191
|
subject: any;
|
|
205
192
|
identifier: any;
|
|
193
|
+
credential?: never;
|
|
206
194
|
snapshot?: never;
|
|
207
|
-
readonly credential?: never;
|
|
208
195
|
} | {
|
|
209
196
|
nativeSubjectId: any;
|
|
210
197
|
subject: any;
|
|
@@ -255,7 +242,7 @@ export declare const makePasswordKernel: <Fragment extends SqlFragment = SqlFrag
|
|
|
255
242
|
readonly nextSecurityRevision: SecurityRevision;
|
|
256
243
|
}, now: number) => Effect.Effect<boolean, AdapterFailure, CurrentPasswordSql>;
|
|
257
244
|
evidenceSatisfiedAt: (evidence: AuthenticationEvidence, requirement: AuthenticationRequirement, now: number) => boolean;
|
|
258
|
-
sameCredentialSnapshot:
|
|
245
|
+
sameCredentialSnapshot: typeof samePasswordCredentialSnapshot;
|
|
259
246
|
subjectColumns: (mapping: AnyPasswordPersistenceMapping<Fragment>) => {
|
|
260
247
|
id: Column;
|
|
261
248
|
status: Column;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { PersistenceMappingError } from "./mapping-error.mjs";
|
|
2
|
+
import { makeNativeSqlTables, sqlMapping } from "./native-sql-table.mjs";
|
|
3
|
+
import { NativeDatabase } from "./transaction-kernel.mjs";
|
|
4
|
+
import { CurrentPasswordPreparedTransaction, PasswordPreparedPostconditions } from "./PasswordPreparedPostconditions.mjs";
|
|
2
5
|
import { CurrentProofSql } from "./proof-kernel.mjs";
|
|
3
6
|
import { requiredPasswordConstraints } from "./models/password-model.mjs";
|
|
7
|
+
import { makePasswordCredentials, samePasswordCredentialSnapshot } from "./password-credentials.mjs";
|
|
4
8
|
import { Cause, Context, DateTime, Effect, Option, Redacted, Schema } from "effect";
|
|
5
9
|
import { CurrentCommitJournal, HookConfigurationError, LifecycleHooks, coordinateCommit, hasCommitScope } from "@yielded/auth/Hooks";
|
|
6
10
|
import { snapshotAuthenticationEvidence } from "@yielded/auth/Sessions";
|
|
@@ -9,8 +13,8 @@ import { ProofUnavailable } from "@yielded/auth/Proofs";
|
|
|
9
13
|
import { PasswordPersistence, PasswordUnavailable, snapshotPasswordCredential, snapshotPasswordRequirement, snapshotPasswordRevision } from "@yielded/auth/Password";
|
|
10
14
|
//#region src/internal/password-kernel.ts
|
|
11
15
|
var CurrentPasswordSql = class extends Context.Service()("effect-auth/CurrentPasswordSql") {};
|
|
12
|
-
const makePasswordKernel = (operations, proofs) => {
|
|
13
|
-
const { and, eq,
|
|
16
|
+
const makePasswordKernel = (operations, proofs, nativeTables = (client) => makeNativeSqlTables(client)) => {
|
|
17
|
+
const { and, eq, inArray, column, updateValues } = operations;
|
|
14
18
|
const { completeProofPlanIn } = proofs;
|
|
15
19
|
const unavailable = () => PasswordUnavailable.make({});
|
|
16
20
|
const translateFailure = (effect) => reportPersistenceFailure(effect, (error) => Schema.is(PasswordUnavailable)(error) || Schema.is(ProofUnavailable)(error) || Schema.is(HookConfigurationError)(error)).pipe(Effect.catchCause((cause) => Effect.failCause(Cause.map(cause, () => unavailable()))));
|
|
@@ -43,38 +47,6 @@ const makePasswordKernel = (operations, proofs) => {
|
|
|
43
47
|
credentialId: column(mapping.authorityCredential.table, mapping.authorityCredential.credentialId),
|
|
44
48
|
revision: column(mapping.authorityCredential.table, mapping.authorityCredential.revision)
|
|
45
49
|
});
|
|
46
|
-
const attemptColumns = (mapping) => ({
|
|
47
|
-
moduleId: column(mapping.attempt.table, mapping.attempt.moduleId),
|
|
48
|
-
action: column(mapping.attempt.table, mapping.attempt.action),
|
|
49
|
-
attemptId: column(mapping.attempt.table, mapping.attempt.attemptId),
|
|
50
|
-
identifierNamespace: column(mapping.attempt.table, mapping.attempt.identifierNamespace),
|
|
51
|
-
identifierValue: column(mapping.attempt.table, mapping.attempt.identifierValue),
|
|
52
|
-
subjectId: column(mapping.attempt.table, mapping.attempt.subjectId),
|
|
53
|
-
credentialId: column(mapping.attempt.table, mapping.attempt.credentialId),
|
|
54
|
-
securityRevision: column(mapping.attempt.table, mapping.attempt.securityRevision),
|
|
55
|
-
credentialRevision: column(mapping.attempt.table, mapping.attempt.credentialRevision),
|
|
56
|
-
verifierVersion: column(mapping.attempt.table, mapping.attempt.verifierVersion),
|
|
57
|
-
identifierBindingRevision: column(mapping.attempt.table, mapping.attempt.identifierBindingRevision),
|
|
58
|
-
admittedAt: column(mapping.attempt.table, mapping.attempt.admittedAt),
|
|
59
|
-
deadline: column(mapping.attempt.table, mapping.attempt.deadline),
|
|
60
|
-
retentionUntil: column(mapping.attempt.table, mapping.attempt.retentionUntil),
|
|
61
|
-
state: column(mapping.attempt.table, mapping.attempt.state)
|
|
62
|
-
});
|
|
63
|
-
const scopeColumns = (mapping) => ({
|
|
64
|
-
moduleId: column(mapping.rateScope.table, mapping.rateScope.moduleId),
|
|
65
|
-
action: column(mapping.rateScope.table, mapping.rateScope.action),
|
|
66
|
-
scopeKind: column(mapping.rateScope.table, mapping.rateScope.scopeKind),
|
|
67
|
-
scopeKey: column(mapping.rateScope.table, mapping.rateScope.scopeKey)
|
|
68
|
-
});
|
|
69
|
-
const chargeColumns = (mapping) => ({
|
|
70
|
-
moduleId: column(mapping.charge.table, mapping.charge.moduleId),
|
|
71
|
-
action: column(mapping.charge.table, mapping.charge.action),
|
|
72
|
-
scopeKind: column(mapping.charge.table, mapping.charge.scopeKind),
|
|
73
|
-
scopeKey: column(mapping.charge.table, mapping.charge.scopeKey),
|
|
74
|
-
attemptId: column(mapping.charge.table, mapping.charge.attemptId),
|
|
75
|
-
occurredAt: column(mapping.charge.table, mapping.charge.occurredAt),
|
|
76
|
-
retentionUntil: column(mapping.charge.table, mapping.charge.retentionUntil)
|
|
77
|
-
});
|
|
78
50
|
const commandColumns = (mapping) => ({
|
|
79
51
|
moduleId: column(mapping.command.table, mapping.command.moduleId),
|
|
80
52
|
commandId: column(mapping.command.table, mapping.command.commandId),
|
|
@@ -106,7 +78,6 @@ const makePasswordKernel = (operations, proofs) => {
|
|
|
106
78
|
return allocate(mode, asyncValue ?? mapping.allocateRevision, syncValue ?? mapping.allocateRevisionSync);
|
|
107
79
|
};
|
|
108
80
|
const sameIdentifier = (left, right) => left.namespace === right.namespace && left.value === right.value;
|
|
109
|
-
const sameCredentialSnapshot = (left, right) => left.moduleId === right.moduleId && left.revision.subjectId === right.revision.subjectId && left.revision.securityRevision === right.revision.securityRevision && left.credentialId === right.credentialId && left.credentialRevision === right.credentialRevision && left.verifierVersion === right.verifierVersion && left.normalization === right.normalization && left.identifierVerifiedAtMillis === right.identifierVerifiedAtMillis && left.revision.credentials.length === right.revision.credentials.length && left.revision.credentials.every((entry) => right.revision.credentials.some((other) => other.credentialId === entry.credentialId && other.revision === entry.revision)) && left.identifierBindingRevision === right.identifierBindingRevision && sameIdentifier(left.identifier, right.identifier) && Redacted.value(left.verifier) === Redacted.value(right.verifier);
|
|
110
81
|
const evidenceSatisfiedAt = (evidence, requirement, now) => {
|
|
111
82
|
if (evidence.proofs.length > 64 || evidence.revision.credentials.length > 64) return false;
|
|
112
83
|
const revisions = /* @__PURE__ */ new Map();
|
|
@@ -197,54 +168,6 @@ const makePasswordKernel = (operations, proofs) => {
|
|
|
197
168
|
}).pipe(Effect.flatMap(snapshotPasswordCredential))
|
|
198
169
|
};
|
|
199
170
|
});
|
|
200
|
-
const scopeEntries = (keys, policy) => {
|
|
201
|
-
const values = [{
|
|
202
|
-
kind: "action",
|
|
203
|
-
key: keys.action,
|
|
204
|
-
...policy.action
|
|
205
|
-
}, {
|
|
206
|
-
kind: "identifier",
|
|
207
|
-
key: keys.identifier,
|
|
208
|
-
...policy.identifier
|
|
209
|
-
}];
|
|
210
|
-
if (keys.subject !== void 0) values.push({
|
|
211
|
-
kind: "subject",
|
|
212
|
-
key: keys.subject,
|
|
213
|
-
...policy.subject
|
|
214
|
-
});
|
|
215
|
-
return values;
|
|
216
|
-
};
|
|
217
|
-
const lockScope = Effect.fn("DrizzlePassword.lockScope")(function* (mapping, configuration, moduleId, action, entry) {
|
|
218
|
-
const database = yield* CurrentPasswordSql;
|
|
219
|
-
const query = database.insert(mapping.rateScope.table).values(mapping.rateScope.encodeInsert({
|
|
220
|
-
moduleId,
|
|
221
|
-
action,
|
|
222
|
-
scopeKind: entry.kind,
|
|
223
|
-
scopeKey: entry.key
|
|
224
|
-
}));
|
|
225
|
-
yield* configuration.insertIfAbsent(query, mapping.rateScope.scopeKey, entry.key);
|
|
226
|
-
const c = scopeColumns(mapping);
|
|
227
|
-
yield* selectRows(database.select().from(mapping.rateScope.table).where(and(eq(c.moduleId, moduleId), eq(c.action, action), eq(c.scopeKind, entry.kind), eq(c.scopeKey, entry.key))).limit(1), configuration.locking);
|
|
228
|
-
});
|
|
229
|
-
const scopeAdmits = Effect.fn("DrizzlePassword.scopeAdmits")(function* (mapping, moduleId, action, entry, policy, identifier, nativeSubjectId, now) {
|
|
230
|
-
const database = yield* CurrentPasswordSql;
|
|
231
|
-
const c = chargeColumns(mapping);
|
|
232
|
-
if ((yield* selectRows(database.select({ attemptId: c.attemptId }).from(mapping.charge.table).where(and(eq(c.moduleId, moduleId), eq(c.action, action), eq(c.scopeKind, entry.kind), eq(c.scopeKey, entry.key), gte(c.occurredAt, mapping.encodeInstant(now - entry.windowMillis)))).limit(entry.limit), true)).length >= entry.limit) return false;
|
|
233
|
-
const a = attemptColumns(mapping);
|
|
234
|
-
const pendingWhere = and(entry.kind === "action" ? and(eq(a.moduleId, moduleId), eq(a.action, action)) : entry.kind === "identifier" ? and(eq(a.moduleId, moduleId), eq(a.action, action), eq(a.identifierNamespace, identifier.namespace), eq(a.identifierValue, identifier.value)) : and(eq(a.moduleId, moduleId), eq(a.action, action), eq(a.subjectId, nativeSubjectId)), eq(a.state, "pending"), gt(a.retentionUntil, mapping.encodeInstant(now)));
|
|
235
|
-
return (yield* selectRows(database.select({ attemptId: a.attemptId }).from(mapping.attempt.table).where(pendingWhere).limit(policy.maximumPending), true)).length < policy.maximumPending;
|
|
236
|
-
});
|
|
237
|
-
const insertCharge = Effect.fn("Drizzle.insertCharge")(function* (mapping, moduleId, action, entry, attemptId, now) {
|
|
238
|
-
return yield* (yield* CurrentPasswordSql).insert(mapping.charge.table).values(mapping.charge.encodeInsert({
|
|
239
|
-
moduleId,
|
|
240
|
-
action,
|
|
241
|
-
scopeKind: entry.kind,
|
|
242
|
-
scopeKey: entry.key,
|
|
243
|
-
attemptId,
|
|
244
|
-
occurredAtMillis: now,
|
|
245
|
-
retentionUntilMillis: now + entry.windowMillis
|
|
246
|
-
}));
|
|
247
|
-
});
|
|
248
171
|
const owned = (database, mapping, configuration, body) => {
|
|
249
172
|
if (!validConstraints(mapping)) return Effect.fail(unavailable());
|
|
250
173
|
const run = coordinateCommit(() => database.transaction((transaction) => body.pipe(Effect.provideService(CurrentPasswordSql, transaction), Effect.provideService(CurrentProofSql, transaction))), { mode: configuration.mode }).pipe(Effect.map((result) => result.value));
|
|
@@ -254,6 +177,15 @@ const makePasswordKernel = (operations, proofs) => {
|
|
|
254
177
|
return yield* run;
|
|
255
178
|
}) : run;
|
|
256
179
|
};
|
|
180
|
+
const registerFinal = Effect.fnUntraced(function* (check) {
|
|
181
|
+
const postconditions = yield* Effect.serviceOption(PasswordPreparedPostconditions);
|
|
182
|
+
if (Option.isNone(postconditions)) return;
|
|
183
|
+
const postcondition = Effect.gen(function* () {
|
|
184
|
+
const transaction = yield* CurrentPasswordPreparedTransaction;
|
|
185
|
+
if (!(yield* check.pipe(Effect.provideService(CurrentPasswordSql, transaction)))) return yield* unavailable();
|
|
186
|
+
}).pipe(translateFailure);
|
|
187
|
+
if (!postconditions.value.register(postcondition)) return yield* unavailable();
|
|
188
|
+
});
|
|
257
189
|
const safeRead = (database, configuration, body) => Effect.gen(function* () {
|
|
258
190
|
if (configuration.coordinated !== true) {
|
|
259
191
|
if (yield* hasCommitScope) return yield* unavailable();
|
|
@@ -317,7 +249,7 @@ const makePasswordKernel = (operations, proofs) => {
|
|
|
317
249
|
identifier,
|
|
318
250
|
credential
|
|
319
251
|
});
|
|
320
|
-
if (!
|
|
252
|
+
if (!samePasswordCredentialSnapshot(snapshot, input.credential)) return void 0;
|
|
321
253
|
}
|
|
322
254
|
const currentRequirement = yield* mapping.subject.decodeActionRequirement(row, action);
|
|
323
255
|
const now = yield* nowMillis;
|
|
@@ -383,10 +315,9 @@ const makePasswordKernel = (operations, proofs) => {
|
|
|
383
315
|
}));
|
|
384
316
|
yield* database.update(mapping.subject.table).set(updateValues([[mapping.subject.securityRevision, nextSecurityRevision]])).where(and(eq(subjectColumns(mapping).id, authority.nativeSubjectId), eq(subjectColumns(mapping).securityRevision, input.expectedRevision.securityRevision)));
|
|
385
317
|
yield* insertCommand(mapping, input, "add-password", commandNow ?? authority.now);
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
if (inserted === void 0 || inserted[mapping.credential.credentialId] !== credentialId || inserted[mapping.credential.credentialRevision] !== credentialRevision || inserted[mapping.credential.verifierVersion] !== verifierVersion || inserted[mapping.credential.verifier] !== Redacted.value(input.replacement.verifier) || inserted[mapping.credential.normalization] !== input.replacement.normalization || authorityInserted === void 0 || subjectUpdated === void 0 || !(yield* mutationPostconditions(mapping, input, authority.nativeSubjectId, subjectUpdated, authorityInserted, commandNow ?? authority.now))) return yield* unavailable();
|
|
318
|
+
const applied = checkMutationApplied(mapping, input, authority.nativeSubjectId, revisions, commandNow ?? authority.now);
|
|
319
|
+
if (!(yield* applied)) return yield* unavailable();
|
|
320
|
+
yield* registerFinal(applied);
|
|
390
321
|
return true;
|
|
391
322
|
});
|
|
392
323
|
const makeSqlPasswordPersistence = Effect.fn("makeSqlPasswordPersistence")(function* (mapping, configuration) {
|
|
@@ -396,96 +327,11 @@ const makePasswordKernel = (operations, proofs) => {
|
|
|
396
327
|
proof: configuration.proof?.mapping
|
|
397
328
|
}) ?? Effect.void).pipe(Effect.mapError(unavailable));
|
|
398
329
|
const hooks = yield* LifecycleHooks;
|
|
330
|
+
if (!validConstraints(mapping)) return yield* unavailable();
|
|
331
|
+
const root = yield* NativeDatabase;
|
|
332
|
+
const credentials = yield* makePasswordCredentials(yield* sqlMapping(() => nativeTables(root.$client.withoutTransforms(), root)).pipe(translateFailure), mapping, configuration);
|
|
399
333
|
return PasswordPersistence.of({
|
|
400
|
-
|
|
401
|
-
const attemptId = yield* allocate(configuration.mode, mapping.allocateAttemptId, mapping.allocateAttemptIdSync);
|
|
402
|
-
return yield* owned(database, mapping, configuration, Effect.gen(function* () {
|
|
403
|
-
const transaction = yield* CurrentPasswordSql;
|
|
404
|
-
const journal = yield* CurrentCommitJournal;
|
|
405
|
-
const resolved = yield* resolveCredential(mapping, input.moduleId, input.identifier, input.subjectId, configuration.locking);
|
|
406
|
-
const keys = mapping.scopeKeys({
|
|
407
|
-
moduleId: input.moduleId,
|
|
408
|
-
action: input.action,
|
|
409
|
-
identifier: input.identifier,
|
|
410
|
-
...resolved?.snapshot === void 0 ? {} : { subjectId: resolved.snapshot.revision.subjectId }
|
|
411
|
-
});
|
|
412
|
-
const scopes = scopeEntries(keys, input.policy);
|
|
413
|
-
const admitted = [];
|
|
414
|
-
yield* lockScope(mapping, configuration, input.moduleId, input.action, scopes[0]);
|
|
415
|
-
let currentNow = yield* nowMillis;
|
|
416
|
-
if (yield* scopeAdmits(mapping, input.moduleId, input.action, scopes[0], input.policy, input.identifier, resolved?.nativeSubjectId, currentNow)) admitted.push(scopes[0]);
|
|
417
|
-
if (admitted.length === 1) for (const entry of scopes.slice(1)) {
|
|
418
|
-
yield* lockScope(mapping, configuration, input.moduleId, input.action, entry);
|
|
419
|
-
currentNow = yield* nowMillis;
|
|
420
|
-
if (yield* scopeAdmits(mapping, input.moduleId, input.action, entry, input.policy, input.identifier, resolved?.nativeSubjectId, currentNow)) admitted.push(entry);
|
|
421
|
-
}
|
|
422
|
-
const now = yield* nowMillis;
|
|
423
|
-
for (const entry of admitted) yield* insertCharge(mapping, input.moduleId, input.action, entry, attemptId, now);
|
|
424
|
-
if (admitted.length !== scopes.length) return prepare({ _tag: "Denied" }, journal);
|
|
425
|
-
const snapshot = resolved?.snapshot;
|
|
426
|
-
const deadline = now + input.policy.attemptLifetimeMillis;
|
|
427
|
-
const retentionUntil = Math.max(deadline, ...scopes.map((entry) => now + entry.windowMillis));
|
|
428
|
-
yield* transaction.insert(mapping.attempt.table).values(mapping.attempt.encodeInsert({
|
|
429
|
-
moduleId: input.moduleId,
|
|
430
|
-
action: input.action,
|
|
431
|
-
attemptId,
|
|
432
|
-
identifier: input.identifier,
|
|
433
|
-
...snapshot === void 0 ? {} : {
|
|
434
|
-
subjectId: snapshot.revision.subjectId,
|
|
435
|
-
credentialId: snapshot.credentialId,
|
|
436
|
-
securityRevision: snapshot.revision.securityRevision,
|
|
437
|
-
credentialRevision: snapshot.credentialRevision,
|
|
438
|
-
verifierVersion: snapshot.verifierVersion,
|
|
439
|
-
identifierBindingRevision: snapshot.identifierBindingRevision
|
|
440
|
-
},
|
|
441
|
-
admittedAtMillis: now,
|
|
442
|
-
deadlineMillis: deadline,
|
|
443
|
-
retentionUntilMillis: retentionUntil
|
|
444
|
-
}, {
|
|
445
|
-
...resolved?.nativeSubjectId === void 0 ? {} : { nativeSubjectId: resolved.nativeSubjectId },
|
|
446
|
-
state: "pending"
|
|
447
|
-
}));
|
|
448
|
-
return prepare({
|
|
449
|
-
_tag: "Admitted",
|
|
450
|
-
attemptId,
|
|
451
|
-
...snapshot === void 0 ? {} : { credential: snapshot }
|
|
452
|
-
}, journal);
|
|
453
|
-
}));
|
|
454
|
-
}).pipe(Effect.provideService(CurrentPasswordSql, database), Effect.provideService(LifecycleHooks, hooks), translateFailure),
|
|
455
|
-
settleAttempt: (uncaptured, prepare) => Effect.gen(function* () {
|
|
456
|
-
const captured = uncaptured.captured === void 0 ? void 0 : yield* snapshotPasswordCredential(uncaptured.captured);
|
|
457
|
-
const input = {
|
|
458
|
-
...uncaptured,
|
|
459
|
-
...captured === void 0 ? {} : { captured }
|
|
460
|
-
};
|
|
461
|
-
return yield* owned(database, mapping, configuration, Effect.gen(function* () {
|
|
462
|
-
const transaction = yield* CurrentPasswordSql;
|
|
463
|
-
const journal = yield* CurrentCommitJournal;
|
|
464
|
-
const c = attemptColumns(mapping);
|
|
465
|
-
let row = (yield* selectRows(transaction.select().from(mapping.attempt.table).where(and(eq(c.moduleId, input.moduleId), eq(c.attemptId, input.attemptId))).limit(1), false))[0];
|
|
466
|
-
if (row === void 0 || row[mapping.attempt.state] !== "pending") return prepare("rejected", journal);
|
|
467
|
-
let decision = "rejected";
|
|
468
|
-
let current;
|
|
469
|
-
let attemptMatches = false;
|
|
470
|
-
if (input.outcome === "verified" && input.captured !== void 0) {
|
|
471
|
-
current = yield* resolveCredential(mapping, input.moduleId, input.captured.identifier, input.captured.revision.subjectId, configuration.locking);
|
|
472
|
-
attemptMatches = input.captured.moduleId === input.moduleId && row[mapping.attempt.identifierNamespace] === input.captured.identifier.namespace && row[mapping.attempt.identifierValue] === input.captured.identifier.value && mapping.subjectId.equals(row[mapping.attempt.subjectId], current?.nativeSubjectId) && row[mapping.attempt.credentialId] === input.captured.credentialId && row[mapping.attempt.securityRevision] === input.captured.revision.securityRevision && row[mapping.attempt.credentialRevision] === input.captured.credentialRevision && row[mapping.attempt.verifierVersion] === input.captured.verifierVersion && row[mapping.attempt.identifierBindingRevision] === input.captured.identifierBindingRevision;
|
|
473
|
-
}
|
|
474
|
-
row = (yield* selectRows(transaction.select().from(mapping.attempt.table).where(and(eq(c.moduleId, input.moduleId), eq(c.attemptId, input.attemptId))).limit(1), configuration.locking))[0];
|
|
475
|
-
if (row === void 0 || row[mapping.attempt.state] !== "pending") return prepare("rejected", journal);
|
|
476
|
-
const now = yield* nowMillis;
|
|
477
|
-
const deadline = yield* mapping.decodeInstant(row[mapping.attempt.deadline]);
|
|
478
|
-
if (attemptMatches && current?.snapshot !== void 0 && input.captured !== void 0 && deadline > now && sameCredentialSnapshot(current.snapshot, input.captured)) decision = "verified";
|
|
479
|
-
const prepared = prepare(decision, journal);
|
|
480
|
-
yield* transaction.update(mapping.attempt.table).set(updateValues([[mapping.attempt.state, decision]])).where(and(eq(c.moduleId, input.moduleId), eq(c.attemptId, input.attemptId), eq(c.state, "pending")));
|
|
481
|
-
if (decision === "verified" && input.rehash !== void 0 && current?.snapshot !== void 0) {
|
|
482
|
-
const cc = credentialColumns(mapping);
|
|
483
|
-
const nextVersion = yield* allocate(configuration.mode, mapping.allocateRevision, mapping.allocateRevisionSync);
|
|
484
|
-
yield* transaction.update(mapping.credential.table).set(mapping.credential.encodeVerifier(input.rehash.nextVerifier, nextVersion)).where(and(eq(cc.moduleId, input.moduleId), eq(cc.subjectId, current.nativeSubjectId), eq(cc.credentialId, current.snapshot.credentialId), eq(cc.credentialRevision, current.snapshot.credentialRevision), eq(cc.verifierVersion, input.rehash.expectedVersion), eq(cc.verifier, Redacted.value(input.rehash.expectedVerifier))));
|
|
485
|
-
}
|
|
486
|
-
return prepared;
|
|
487
|
-
}));
|
|
488
|
-
}).pipe(Effect.provideService(CurrentPasswordSql, database), Effect.provideService(LifecycleHooks, hooks), translateFailure),
|
|
334
|
+
...credentials,
|
|
489
335
|
readForSubject: (input) => safeRead(database, configuration, Effect.gen(function* () {
|
|
490
336
|
const transaction = yield* CurrentPasswordSql;
|
|
491
337
|
const locked = yield* lockSubject(mapping, input.subjectId, false);
|
|
@@ -565,72 +411,20 @@ const makePasswordKernel = (operations, proofs) => {
|
|
|
565
411
|
if (!(yield* currentExpectedCredential(mapping, input, authority.nativeSubjectId))) return prepare("rejected", journal);
|
|
566
412
|
let passwordReceipt;
|
|
567
413
|
yield* completeProofPlanIn(configuration.proof.mapping, configuration.proof.configuration, input.completion, Effect.gen(function* () {
|
|
568
|
-
|
|
414
|
+
const revisions = {
|
|
569
415
|
credentialRevision,
|
|
570
416
|
verifierVersion,
|
|
571
417
|
nextSecurityRevision
|
|
572
|
-
}
|
|
418
|
+
};
|
|
419
|
+
const applied = yield* writeReplacement(mapping, input, authority.nativeSubjectId, revisions, authority.now);
|
|
420
|
+
if (applied) yield* registerReplacement(mapping, input, authority.nativeSubjectId, revisions, authority.now);
|
|
421
|
+
return applied;
|
|
573
422
|
}), (decision) => {
|
|
574
423
|
passwordReceipt = prepare(decision === "completed" ? "changed" : "rejected", journal);
|
|
575
424
|
return decision;
|
|
576
425
|
});
|
|
577
426
|
return passwordReceipt ?? prepare("rejected", journal);
|
|
578
427
|
}));
|
|
579
|
-
})).pipe(Effect.provideService(CurrentPasswordSql, database), Effect.provideService(LifecycleHooks, hooks), translateFailure),
|
|
580
|
-
cleanupAttempts: (input, prepare) => owned(database, mapping, configuration, Effect.gen(function* () {
|
|
581
|
-
const transaction = yield* CurrentPasswordSql;
|
|
582
|
-
const journal = yield* CurrentCommitJournal;
|
|
583
|
-
const now = yield* nowMillis;
|
|
584
|
-
const nativeNow = mapping.encodeInstant(now);
|
|
585
|
-
let remaining = input.limit;
|
|
586
|
-
let hasMore = false;
|
|
587
|
-
const a = attemptColumns(mapping);
|
|
588
|
-
const c = chargeColumns(mapping);
|
|
589
|
-
const attempts = yield* selectRows(transaction.select({ attemptId: a.attemptId }).from(mapping.attempt.table).where(and(eq(a.moduleId, input.moduleId), lte(a.retentionUntil, nativeNow))).limit(remaining + 1), false);
|
|
590
|
-
if (attempts.length > remaining) hasMore = true;
|
|
591
|
-
const attemptCandidates = attempts.slice(0, remaining);
|
|
592
|
-
remaining -= attemptCandidates.length;
|
|
593
|
-
const charges = yield* selectRows(transaction.select({
|
|
594
|
-
action: c.action,
|
|
595
|
-
scopeKind: c.scopeKind,
|
|
596
|
-
scopeKey: c.scopeKey,
|
|
597
|
-
attemptId: c.attemptId
|
|
598
|
-
}).from(mapping.charge.table).where(and(eq(c.moduleId, input.moduleId), lte(c.retentionUntil, nativeNow))).limit(remaining + 1), false);
|
|
599
|
-
if (charges.length > remaining) hasMore = true;
|
|
600
|
-
const chargeCandidates = charges.slice(0, remaining);
|
|
601
|
-
remaining -= chargeCandidates.length;
|
|
602
|
-
const sc = scopeColumns(mapping);
|
|
603
|
-
const scopes = yield* selectRows(transaction.select({
|
|
604
|
-
action: sc.action,
|
|
605
|
-
scopeKind: sc.scopeKind,
|
|
606
|
-
scopeKey: sc.scopeKey
|
|
607
|
-
}).from(mapping.rateScope.table).where(and(eq(sc.moduleId, input.moduleId), notExists(transaction.select({ one: sql`1` }).from(mapping.charge.table).where(and(eq(c.moduleId, sc.moduleId), eq(c.action, sc.action), eq(c.scopeKind, sc.scopeKind), eq(c.scopeKey, sc.scopeKey)))))).limit(remaining + 1), remaining === 0 ? false : configuration.locking);
|
|
608
|
-
if (scopes.length > remaining) hasMore = true;
|
|
609
|
-
const selectedScopes = scopes.slice(0, remaining);
|
|
610
|
-
remaining -= selectedScopes.length;
|
|
611
|
-
const selectedCharges = [];
|
|
612
|
-
for (const candidate of chargeCandidates) {
|
|
613
|
-
const locked = yield* selectRows(transaction.select({
|
|
614
|
-
action: c.action,
|
|
615
|
-
scopeKind: c.scopeKind,
|
|
616
|
-
scopeKey: c.scopeKey,
|
|
617
|
-
attemptId: c.attemptId
|
|
618
|
-
}).from(mapping.charge.table).where(and(eq(c.moduleId, input.moduleId), eq(c.action, candidate.action), eq(c.scopeKind, candidate.scopeKind), eq(c.scopeKey, candidate.scopeKey), eq(c.attemptId, candidate.attemptId), lte(c.retentionUntil, nativeNow))).limit(1), configuration.locking);
|
|
619
|
-
if (locked[0] !== void 0) selectedCharges.push(locked[0]);
|
|
620
|
-
}
|
|
621
|
-
const selectedAttempts = [];
|
|
622
|
-
for (const candidate of attemptCandidates) {
|
|
623
|
-
const locked = yield* selectRows(transaction.select({ attemptId: a.attemptId }).from(mapping.attempt.table).where(and(eq(a.moduleId, input.moduleId), eq(a.attemptId, candidate.attemptId), lte(a.retentionUntil, nativeNow))).limit(1), configuration.locking);
|
|
624
|
-
if (locked[0] !== void 0) selectedAttempts.push(locked[0]);
|
|
625
|
-
}
|
|
626
|
-
const prepared = prepare({
|
|
627
|
-
removed: selectedAttempts.length + selectedCharges.length + selectedScopes.length,
|
|
628
|
-
hasMore
|
|
629
|
-
}, journal);
|
|
630
|
-
for (const row of selectedCharges) yield* transaction.delete(mapping.charge.table).where(and(eq(c.moduleId, input.moduleId), eq(c.action, row.action), eq(c.scopeKind, row.scopeKind), eq(c.scopeKey, row.scopeKey), eq(c.attemptId, row.attemptId), lte(c.retentionUntil, nativeNow)));
|
|
631
|
-
if (selectedAttempts.length > 0) yield* transaction.delete(mapping.attempt.table).where(and(eq(a.moduleId, input.moduleId), inArray(a.attemptId, selectedAttempts.map((row) => row.attemptId)), lte(a.retentionUntil, nativeNow)));
|
|
632
|
-
for (const row of selectedScopes) yield* transaction.delete(mapping.rateScope.table).where(and(eq(sc.moduleId, input.moduleId), eq(sc.action, row.action), eq(sc.scopeKind, row.scopeKind), eq(sc.scopeKey, row.scopeKey), notExists(transaction.select({ one: sql`1` }).from(mapping.charge.table).where(and(eq(c.moduleId, sc.moduleId), eq(c.action, sc.action), eq(c.scopeKind, sc.scopeKind), eq(c.scopeKey, sc.scopeKey))))));
|
|
633
|
-
return prepared;
|
|
634
428
|
})).pipe(Effect.provideService(CurrentPasswordSql, database), Effect.provideService(LifecycleHooks, hooks), translateFailure)
|
|
635
429
|
});
|
|
636
430
|
});
|
|
@@ -646,7 +440,7 @@ const makePasswordKernel = (operations, proofs) => {
|
|
|
646
440
|
const credential = (yield* database.select().from(mapping.credential.table).where(and(eq(c.moduleId, input.moduleId), eq(c.subjectId, nativeSubjectId), eq(c.credentialId, revisions.credentialId), eq(c.credentialRevision, revisions.credentialRevision), eq(c.verifierVersion, revisions.verifierVersion), eq(c.verifier, Redacted.value(input.replacement.verifier)), eq(c.normalization, input.replacement.normalization))).limit(1))[0];
|
|
647
441
|
const subject = (yield* database.select().from(mapping.subject.table).where(and(eq(s.id, nativeSubjectId), eq(s.securityRevision, revisions.nextSecurityRevision))).limit(1))[0];
|
|
648
442
|
const authorityCredential = (yield* database.select().from(mapping.authorityCredential.table).where(and(eq(authorityCredentialColumns(mapping).subjectId, nativeSubjectId), eq(authorityCredentialColumns(mapping).credentialId, revisions.credentialId), eq(authorityCredentialColumns(mapping).revision, revisions.credentialRevision))).limit(1))[0];
|
|
649
|
-
return credential !== void 0 && (yield* mutationPostconditions(mapping, input, nativeSubjectId, subject, authorityCredential, now));
|
|
443
|
+
return credential !== void 0 && credential[mapping.credential.credentialId] === revisions.credentialId && credential[mapping.credential.credentialRevision] === revisions.credentialRevision && credential[mapping.credential.verifierVersion] === revisions.verifierVersion && credential[mapping.credential.verifier] === Redacted.value(input.replacement.verifier) && credential[mapping.credential.normalization] === input.replacement.normalization && (yield* mutationPostconditions(mapping, input, nativeSubjectId, subject, authorityCredential, now));
|
|
650
444
|
});
|
|
651
445
|
const writeReplacement = Effect.fn("DrizzlePassword.writeReplacement")(function* (mapping, input, nativeSubjectId, revisions, now) {
|
|
652
446
|
const database = yield* CurrentPasswordSql;
|
|
@@ -665,6 +459,10 @@ const makePasswordKernel = (operations, proofs) => {
|
|
|
665
459
|
credentialId: input.credential.credentialId
|
|
666
460
|
}, now);
|
|
667
461
|
});
|
|
462
|
+
const registerReplacement = (mapping, input, nativeSubjectId, revisions, now) => registerFinal(checkMutationApplied(mapping, input, nativeSubjectId, {
|
|
463
|
+
...revisions,
|
|
464
|
+
credentialId: input.credential.credentialId
|
|
465
|
+
}, now));
|
|
668
466
|
const replaceIn = Effect.fn("Drizzle.replaceIn")(function* (mapping, configuration, input, action, revisions, prepare) {
|
|
669
467
|
const journal = yield* CurrentCommitJournal;
|
|
670
468
|
const authority = yield* validateMutationAuthority(mapping, configuration, input, action);
|
|
@@ -673,6 +471,7 @@ const makePasswordKernel = (operations, proofs) => {
|
|
|
673
471
|
if (!(yield* currentExpectedCredential(mapping, input, authority.nativeSubjectId))) return prepare("rejected", journal);
|
|
674
472
|
const prepared = prepare("changed", journal);
|
|
675
473
|
if (!(yield* writeReplacement(mapping, input, authority.nativeSubjectId, revisions, authority.now))) return yield* unavailable();
|
|
474
|
+
yield* registerReplacement(mapping, input, authority.nativeSubjectId, revisions, authority.now);
|
|
676
475
|
return prepared;
|
|
677
476
|
});
|
|
678
477
|
return {
|
|
@@ -694,7 +493,7 @@ const makePasswordKernel = (operations, proofs) => {
|
|
|
694
493
|
checkMutationApplied,
|
|
695
494
|
writeReplacement,
|
|
696
495
|
evidenceSatisfiedAt,
|
|
697
|
-
sameCredentialSnapshot,
|
|
496
|
+
sameCredentialSnapshot: samePasswordCredentialSnapshot,
|
|
698
497
|
subjectColumns,
|
|
699
498
|
identifierColumns,
|
|
700
499
|
credentialColumns,
|