@yielded/auth-persistence 0.1.0-beta.29 → 0.1.0-beta.31

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.
Files changed (65) hide show
  1. package/README.md +6 -6
  2. package/dist/Adapter.d.mts +1 -1
  3. package/dist/Testing.d.mts +44 -0
  4. package/dist/Testing.mjs +310 -0
  5. package/dist/Testing.mjs.map +1 -0
  6. package/dist/internal/configuration.d.mts +18 -8
  7. package/dist/internal/configuration.mjs.map +1 -1
  8. package/dist/internal/models/oauth-model.d.mts +10 -1
  9. package/dist/internal/models/oauth-model.mjs.map +1 -1
  10. package/dist/internal/models/password-model.d.mts +2 -1
  11. package/dist/internal/models/password-model.mjs.map +1 -1
  12. package/dist/internal/oauth/native-accounts.mjs +42 -1
  13. package/dist/internal/oauth/native-accounts.mjs.map +1 -1
  14. package/dist/internal/oauth/native-state.d.mts +1 -0
  15. package/dist/internal/oauth/native-state.mjs +2 -2
  16. package/dist/internal/oauth/native-state.mjs.map +1 -1
  17. package/dist/internal/passkey-managed.mjs +4 -2
  18. package/dist/internal/passkey-managed.mjs.map +1 -1
  19. package/dist/internal/password-native.mjs +14 -0
  20. package/dist/internal/password-native.mjs.map +1 -1
  21. package/dist/internal/password-registration-native.d.mts +1 -1
  22. package/dist/internal/persistence.d.mts +3 -0
  23. package/dist/internal/persistence.mjs +4 -6
  24. package/dist/internal/persistence.mjs.map +1 -1
  25. package/dist/internal/registration.mjs +17 -8
  26. package/dist/internal/registration.mjs.map +1 -1
  27. package/dist/internal/session-native-authority.mjs +2 -1
  28. package/dist/internal/session-native-authority.mjs.map +1 -1
  29. package/dist/internal/session-native-login.mjs +2 -1
  30. package/dist/internal/session-native-login.mjs.map +1 -1
  31. package/dist/internal/session-native-pending-read.mjs +1 -1
  32. package/dist/internal/session-native-pending-read.mjs.map +1 -1
  33. package/dist/internal/session-native-state.mjs +21 -8
  34. package/dist/internal/session-native-state.mjs.map +1 -1
  35. package/dist/internal/session-native-stateful.mjs +2 -1
  36. package/dist/internal/session-native-stateful.mjs.map +1 -1
  37. package/dist/internal/session-native-step-up.mjs +4 -2
  38. package/dist/internal/session-native-step-up.mjs.map +1 -1
  39. package/dist/internal/sql-change.mjs +11 -1
  40. package/dist/internal/sql-change.mjs.map +1 -1
  41. package/dist/internal/sqlite-policy-guard.mjs +23 -0
  42. package/dist/internal/sqlite-policy-guard.mjs.map +1 -0
  43. package/dist/internal/storage-mapping.d.mts +9 -5
  44. package/dist/internal/storage-mapping.mjs +16 -4
  45. package/dist/internal/storage-mapping.mjs.map +1 -1
  46. package/package.json +1 -1
  47. package/src/Testing.ts +652 -0
  48. package/src/internal/configuration.ts +26 -8
  49. package/src/internal/models/oauth-model.ts +10 -0
  50. package/src/internal/models/password-model.ts +2 -1
  51. package/src/internal/oauth/native-accounts.ts +72 -1
  52. package/src/internal/oauth/native-state.ts +6 -2
  53. package/src/internal/passkey-managed.ts +8 -2
  54. package/src/internal/password-native.ts +28 -2
  55. package/src/internal/persistence.ts +174 -164
  56. package/src/internal/registration.ts +53 -40
  57. package/src/internal/session-native-authority.ts +3 -1
  58. package/src/internal/session-native-login.ts +3 -1
  59. package/src/internal/session-native-pending-read.ts +1 -1
  60. package/src/internal/session-native-state.ts +29 -10
  61. package/src/internal/session-native-stateful.ts +3 -1
  62. package/src/internal/session-native-step-up.ts +5 -2
  63. package/src/internal/sql-change.ts +14 -1
  64. package/src/internal/sqlite-policy-guard.ts +34 -0
  65. package/src/internal/storage-mapping.ts +40 -4
@@ -1 +1 @@
1
- {"version":3,"file":"passkey-managed.mjs","names":[],"sources":["../../src/internal/passkey-managed.ts"],"sourcesContent":["import * as M from \"@yielded/auth/Passkey\";\nimport { Context, Effect, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql\";\nimport type { Fragment } from \"effect/sql/Statement\";\n\nimport {\n PersistenceConfigurationError,\n type MappingInput,\n type PasskeyFeature,\n} from \"./configuration\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport {\n requiredPasskeyCredentialConstraints,\n requiredPasskeyPersistenceConstraints,\n} from \"./models/passkey-model\";\nimport type { NativeSqlTables } from \"./native-sql-table\";\nimport { makeNativePasskeyServices } from \"./passkey-native\";\nimport type { PasskeyNativeMapping, PasskeyNativeRead } from \"./passkey-native-state\";\nimport {\n makePasskeyNativeManagement,\n type NativePasskeyManagementMapping,\n} from \"./passkey-native-write\";\nimport { anySqlCondition } from \"./sql-change\";\nimport { storageTables, type StorageRole } from \"./storage-tables\";\n\nexport interface ComposedPasskeyInput {\n readonly storage: MappingInput;\n readonly namespace: string;\n readonly dialect: \"pg\" | \"sqlite\";\n readonly features: ReadonlyArray<PasskeyFeature>;\n readonly passwordModules: ReadonlyArray<string>;\n}\n\nconst profileJson = Schema.fromJsonString(M.PasskeyProfile);\n\nconst credentialData = M.PasskeyCredential.mapFields(\n ({ revision: _revision, active: _active, requirement: _requirement, ...fields }) => fields,\n);\n\nconst configurationError = (reason: string) => PersistenceConfigurationError.make({ reason });\n\nconst mappings = Effect.fnUntraced(function* (\n storage: MappingInput,\n tables: NativeSqlTables,\n passwordModules: ReadonlyArray<string>,\n signInProfiles: ReadonlyArray<M.PasskeyProfile>,\n) {\n const sql = (yield* SqlClient.SqlClient).withoutTransforms();\n\n const table = (role: StorageRole) => {\n const value = storage.tables[role];\n\n if (value === undefined) throw configurationError(`Missing ${role} mapping`);\n\n return value;\n };\n\n const mapped = <Role extends StorageRole>(role: Role) => ({\n table: table(role),\n // Managed storage validation owns these physical column keys.\n ...(Object.fromEntries(Object.keys(storageTables[role].columns).map((key) => [key, key])) as {\n readonly [Key in keyof (typeof storageTables)[Role][\"columns\"]]: Key;\n }),\n });\n\n const t = (role: StorageRole) => tables(table(role));\n\n const eq = (role: StorageRole, key: string, value: unknown) =>\n sql`${t(role).column(key)} = ${t(role).value(key, value)}`;\n\n const s = storage.subjects;\n const subject = tables(s.table);\n const active = (value: unknown) => value === true;\n\n const read: PasskeyNativeRead = {\n subject: {\n table: s.table,\n id: s.id,\n status: s.status,\n securityRevision: s.securityRevision,\n decodeId: (row) => row[s.id],\n decodeRequirement: s.requirements,\n isActiveStatus: (value) => Object.is(value, s.activeValue),\n activeCondition: sql`${subject.column(s.status)} = ${subject.value(s.status, s.activeValue)}`,\n },\n credential: {\n ...mapped(\"passkeyCredentials\"),\n status: \"active\",\n decode: (row) =>\n Schema.decodeUnknownSync(credentialData)({\n ...row,\n profile: Schema.decodeUnknownSync(profileJson)(row.profile),\n }),\n decodeSubjectId: (row) => row.subjectId,\n isActiveStatus: active,\n activeCondition: eq(\"passkeyCredentials\", \"active\", true),\n },\n authority: {\n ...mapped(\"credentials\"),\n status: \"active\",\n isActiveStatus: active,\n activeCondition: eq(\"credentials\", \"active\", true),\n },\n subjectIds: { toNative: s.toNativeSync, toSubject: s.toSubjectSync, equals: Object.is },\n constraints: requiredPasskeyCredentialConstraints,\n };\n\n const base = (feature: PasskeyFeature): PasskeyNativeMapping => ({\n moduleId: feature.moduleId,\n read,\n flow: { ...mapped(\"passkeyFlows\"), encodeInsert: () => ({}) },\n clock: {\n encodeInstant: storage.encodeInstant,\n decodeInstant: storage.decodeInstantSync,\n engineNowMillis: sql.onDialectOrElse({\n pg: () => sql`cast(extract(epoch from clock_timestamp()) * 1000 as bigint)`,\n orElse: () => sql`cast(round((julianday('now') - 2440587.5) * 86400000) as integer)`,\n }),\n toMillis: (expression: Fragment) => expression,\n fromMillis: (expression: Fragment) => expression,\n },\n telemetry: {\n lastUsedAt: \"lastUsedAt\",\n encodeBackupEligible: (value) => value,\n encodeBackupState: (value) => value,\n },\n constraints: requiredPasskeyPersistenceConstraints,\n });\n\n const metadata = (nativeId: unknown) =>\n sql`exists(select 1 from ${subject.name} where ${subject.column(s.id)} = ${subject.value(s.id, nativeId)} and ${subject.column(s.status)} = ${subject.value(s.status, s.activeValue)})`;\n\n const management = (feature: PasskeyFeature): NativePasskeyManagementMapping => {\n const policy = feature.managementPolicy;\n\n if (policy === undefined)\n throw configurationError(`Missing passkey management policy for ${feature.moduleId}`);\n\n const c = t(\"passkeyCredentials\"),\n f = t(\"credentials\");\n\n return {\n ...base(feature),\n write: {\n credential: {\n name: \"name\",\n createdAt: \"createdAt\",\n encodeInsert: ({ credential, subjectId, summary, marker }) => ({\n credentialId: credential.credentialId,\n subjectId,\n rpId: credential.rpId,\n protocolCredentialId: credential.protocolCredentialId,\n userHandle: credential.userHandle,\n credentialKey: \"\",\n publicKey: credential.publicKey,\n algorithm: credential.algorithm,\n profile: Schema.encodeSync(profileJson)(credential.profile),\n credentialRevision: marker,\n active: true,\n primarySignIn: credential.primarySignIn,\n enrollmentUserVerified: credential.enrollmentUserVerified,\n backupEligible: credential.backupEligible,\n backupState: credential.backupState,\n counter: credential.counter,\n name: summary.name,\n createdAt: storage.encodeInstant(summary.createdAtMillis),\n }),\n encodePrimarySignIn: (value) => value,\n encodeEnrollmentUserVerified: (value) => value,\n encodeBackupEligible: (value) => value,\n activeStatus: true,\n removedStatus: false,\n },\n authority: {\n encodeInsert: ({ subjectId, credential, marker }) => ({\n subjectId,\n credentialId: credential.credentialId,\n revision: marker,\n active: true,\n }),\n activeStatus: true,\n removedStatus: false,\n },\n policy: {\n subjectColumns: subject.keys,\n management: () => policy,\n requirement: s.actionRequirements,\n metadata,\n action: metadata,\n remainingSignIn: (nativeId, excluded, row) =>\n Effect.gen(function* () {\n const requirement = yield* Schema.decodeEffect(M.PasskeyRequirement)(\n yield* s.requirements(row),\n );\n\n const alternatives: Fragment[] = [];\n\n if (\n requirement.alternatives.some(\n (alternative) =>\n alternative.minimumCredentials === 1 &&\n alternative.factors.every((factor) => factor === \"possession\"),\n )\n ) {\n alternatives.push(sql`exists(select 1 from ${c.name} join ${f.name} on ${f.column(\"credentialId\")} = ${c.column(\"credentialId\")} and ${f.column(\"subjectId\")} = ${f.value(\"subjectId\", nativeId)} and ${f.column(\"revision\")} = ${c.column(\"credentialRevision\")} and ${eq(\"credentials\", \"active\", true)}\n where ${eq(\"passkeyCredentials\", \"subjectId\", nativeId)} and ${c.column(\"credentialId\")} <> ${c.value(\"credentialId\", excluded)} and ${eq(\"passkeyCredentials\", \"active\", true)} and ${eq(\"passkeyCredentials\", \"primarySignIn\", true)} and ${eq(\"passkeyCredentials\", \"enrollmentUserVerified\", true)} and ${anySqlCondition(\n signInProfiles.map((profile) => eq(\"passkeyCredentials\", \"rpId\", profile.rpId)),\n )})`);\n }\n if (\n passwordModules.length > 0 &&\n requirement.alternatives.some(\n (alternative) =>\n alternative.minimumCredentials === 1 &&\n !alternative.userVerified &&\n !alternative.phishingResistant &&\n alternative.factors.every((factor) => factor === \"knowledge\"),\n )\n ) {\n const p = t(\"passwords\"),\n i = t(\"identifiers\");\n\n alternatives.push(sql`exists(select 1 from ${p.name} join ${f.name} on ${f.column(\"credentialId\")} = ${p.column(\"credentialId\")} and ${f.column(\"subjectId\")} = ${f.value(\"subjectId\", nativeId)} and ${f.column(\"revision\")} = ${p.column(\"credentialRevision\")} and ${eq(\"credentials\", \"active\", true)}\n join ${i.name} on ${eq(\"identifiers\", \"subjectId\", nativeId)} and ${eq(\"identifiers\", \"active\", true)} and ${eq(\"identifiers\", \"namespace\", \"email\")}\n where ${eq(\"passwords\", \"subjectId\", nativeId)} and ${p.column(\"credentialId\")} <> ${p.value(\"credentialId\", excluded)} and ${anySqlCondition(\n passwordModules.map((module) => eq(\"passwords\", \"moduleId\", module)),\n )})`);\n }\n\n return anySqlCondition(alternatives);\n }).pipe(\n Effect.mapError((cause) =>\n PersistenceMappingError.make({ operation: \"mapping\", cause }),\n ),\n ),\n },\n },\n invalidation: {\n window: {\n trigger: \"credential-change\",\n existingSessions: \"immediate\",\n maximumExposureMillis: 0,\n oldAuthenticationEvidence: \"rejected\",\n },\n mutations: [],\n postcondition: ({ subjectId, securityRevision }) =>\n sql`exists(select 1 from ${subject.name} where ${subject.column(s.id)} = ${subject.value(s.id, subjectId)} and ${subject.column(s.securityRevision)} = ${subject.value(s.securityRevision, securityRevision)})`,\n },\n };\n };\n\n return { base, management };\n});\n\n/** Managed and mapped tables feed the same native passkey statements. */\nexport const makeManagedPasskeys = Effect.fnUntraced(\n function* (input: ComposedPasskeyInput, tables: NativeSqlTables) {\n const policies = yield* Effect.forEach(input.features, (feature) =>\n Effect.map(feature.policy, (policy) => ({ feature, policy })),\n );\n\n const mapping = yield* mappings(\n input.storage,\n tables,\n input.passwordModules,\n policies.flatMap(({ feature, policy }) => (feature.management ? [] : policy.profiles)),\n );\n\n const services = new Map<\n string,\n Effect.Success<ReturnType<typeof makeNativePasskeyServices>>\n >();\n\n const managers = new Map<string, M.PasskeyManagementPersistence[\"Service\"]>();\n\n for (const feature of input.features) {\n const selected = feature.management ? mapping.management(feature) : mapping.base(feature);\n const base = yield* makeNativePasskeyServices(tables, selected);\n\n services.set(feature.moduleId, base);\n if (feature.management)\n managers.set(\n feature.moduleId,\n makePasskeyNativeManagement(base, mapping.management(feature))\n .passkeyManagementPersistence,\n );\n }\n\n const service = (moduleId: string) => {\n const value = services.get(moduleId);\n\n return value === undefined\n ? Effect.fail(M.PasskeyUnavailable.make({}))\n : Effect.succeed(value);\n };\n\n const manager = (moduleId: string) => {\n const value = managers.get(moduleId);\n\n return value === undefined\n ? Effect.fail(M.PasskeyUnavailable.make({}))\n : Effect.succeed(value);\n };\n\n const first = services.values().next().value;\n\n if (first === undefined) return yield* configurationError(\"A passkey module is required\");\n\n let context: Context.Context<never> = Context.make(M.PasskeyCredentials, {\n lookup: (input) => first.passkeyCredentials.lookup(input),\n listForSubject: (input) =>\n Effect.flatMap(service(input.moduleId), (value) =>\n value.passkeyCredentials.listForSubject(input),\n ),\n }).pipe(\n Context.add(M.PasskeyPersistence, {\n issue: (input, prepare) =>\n Effect.flatMap(service(input.ceremony.moduleId), (value) =>\n value.passkeyPersistence.issue(input, prepare),\n ),\n context: (input) =>\n Effect.flatMap(service(input.moduleId), (value) =>\n value.passkeyPersistence.context(input),\n ),\n consume: (input, prepare) =>\n Effect.flatMap(service(input.access.moduleId), (value) =>\n value.passkeyPersistence.consume(input, prepare),\n ),\n cleanup: (input, prepare) =>\n Effect.flatMap(service(input.moduleId), (value) =>\n value.passkeyPersistence.cleanup(input, prepare),\n ),\n }),\n );\n\n if (managers.size > 0)\n context = context.pipe(\n Context.add(M.PasskeyManagementPersistence, {\n completeEnrollment: (input, prepare) =>\n Effect.flatMap(manager(input.ceremony.moduleId), (value) =>\n value.completeEnrollment(input, prepare),\n ),\n list: (input) => Effect.flatMap(manager(input.moduleId), (value) => value.list(input)),\n inspectRemove: (input) =>\n Effect.flatMap(manager(input.moduleId), (value) => value.inspectRemove(input)),\n rename: (input, prepare) =>\n Effect.flatMap(manager(input.moduleId), (value) => value.rename(input, prepare)),\n remove: (input, prepare) =>\n Effect.flatMap(manager(input.moduleId), (value) => value.remove(input, prepare)),\n }),\n );\n\n return context;\n },\n Effect.mapError((error) =>\n Schema.is(PersistenceConfigurationError)(error)\n ? error\n : configurationError(\"Unable to configure passkey persistence\"),\n ),\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"passkey-managed.mjs","names":[],"sources":["../../src/internal/passkey-managed.ts"],"sourcesContent":["import * as M from \"@yielded/auth/Passkey\";\nimport { Context, Effect, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql\";\nimport type { Fragment } from \"effect/sql/Statement\";\n\nimport {\n PersistenceConfigurationError,\n type MappingInput,\n type PasskeyFeature,\n} from \"./configuration\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport {\n requiredPasskeyCredentialConstraints,\n requiredPasskeyPersistenceConstraints,\n} from \"./models/passkey-model\";\nimport type { NativeSqlTables } from \"./native-sql-table\";\nimport { makeBatchPasskeyServices, makeNativePasskeyServices } from \"./passkey-native\";\nimport type { PasskeyNativeMapping, PasskeyNativeRead } from \"./passkey-native-state\";\nimport {\n makePasskeyNativeManagement,\n type NativePasskeyManagementMapping,\n} from \"./passkey-native-write\";\nimport { anySqlCondition } from \"./sql-change\";\nimport { SqlBatchCommit } from \"./sql-commit\";\nimport { storageTables, type StorageRole } from \"./storage-tables\";\n\nexport interface ComposedPasskeyInput {\n readonly storage: MappingInput;\n readonly namespace: string;\n readonly dialect: \"pg\" | \"sqlite\";\n readonly features: ReadonlyArray<PasskeyFeature>;\n readonly passwordModules: ReadonlyArray<string>;\n}\n\nconst profileJson = Schema.fromJsonString(M.PasskeyProfile);\n\nconst credentialData = M.PasskeyCredential.mapFields(\n ({ revision: _revision, active: _active, requirement: _requirement, ...fields }) => fields,\n);\n\nconst configurationError = (reason: string) => PersistenceConfigurationError.make({ reason });\n\nconst mappings = Effect.fnUntraced(function* (\n storage: MappingInput,\n tables: NativeSqlTables,\n passwordModules: ReadonlyArray<string>,\n signInProfiles: ReadonlyArray<M.PasskeyProfile>,\n) {\n const sql = (yield* SqlClient.SqlClient).withoutTransforms();\n\n const table = (role: StorageRole) => {\n const value = storage.tables[role];\n\n if (value === undefined) throw configurationError(`Missing ${role} mapping`);\n\n return value;\n };\n\n const mapped = <Role extends StorageRole>(role: Role) => ({\n table: table(role),\n // Managed storage validation owns these physical column keys.\n ...(Object.fromEntries(Object.keys(storageTables[role].columns).map((key) => [key, key])) as {\n readonly [Key in keyof (typeof storageTables)[Role][\"columns\"]]: Key;\n }),\n });\n\n const t = (role: StorageRole) => tables(table(role));\n\n const eq = (role: StorageRole, key: string, value: unknown) =>\n sql`${t(role).column(key)} = ${t(role).value(key, value)}`;\n\n const s = storage.subjects;\n const subject = tables(s.table);\n const active = (value: unknown) => value === true;\n\n const read: PasskeyNativeRead = {\n subject: {\n table: s.table,\n id: s.id,\n status: s.status,\n securityRevision: s.securityRevision,\n decodeId: (row) => row[s.id],\n decodeRequirement: s.requirements,\n isActiveStatus: (value) => Object.is(value, s.activeValue),\n activeCondition: sql`${subject.column(s.status)} = ${subject.value(s.status, s.activeValue)}`,\n },\n credential: {\n ...mapped(\"passkeyCredentials\"),\n status: \"active\",\n decode: (row) =>\n Schema.decodeUnknownSync(credentialData)({\n ...row,\n profile: Schema.decodeUnknownSync(profileJson)(row.profile),\n }),\n decodeSubjectId: (row) => row.subjectId,\n isActiveStatus: active,\n activeCondition: eq(\"passkeyCredentials\", \"active\", true),\n },\n authority: {\n ...mapped(\"credentials\"),\n status: \"active\",\n isActiveStatus: active,\n activeCondition: eq(\"credentials\", \"active\", true),\n },\n subjectIds: { toNative: s.toNativeSync, toSubject: s.toSubjectSync, equals: Object.is },\n constraints: requiredPasskeyCredentialConstraints,\n };\n\n const base = (feature: PasskeyFeature): PasskeyNativeMapping => ({\n moduleId: feature.moduleId,\n read,\n flow: { ...mapped(\"passkeyFlows\"), encodeInsert: () => ({}) },\n clock: {\n encodeInstant: storage.encodeInstant,\n decodeInstant: storage.decodeInstantSync,\n engineNowMillis: sql.onDialectOrElse({\n pg: () => sql`cast(extract(epoch from clock_timestamp()) * 1000 as bigint)`,\n orElse: () => sql`cast(round((julianday('now') - 2440587.5) * 86400000) as integer)`,\n }),\n toMillis: (expression: Fragment) => expression,\n fromMillis: (expression: Fragment) => expression,\n },\n telemetry: {\n lastUsedAt: \"lastUsedAt\",\n encodeBackupEligible: (value) => value,\n encodeBackupState: (value) => value,\n },\n constraints: requiredPasskeyPersistenceConstraints,\n });\n\n const metadata = (nativeId: unknown) =>\n sql`exists(select 1 from ${subject.name} where ${subject.column(s.id)} = ${subject.value(s.id, nativeId)} and ${subject.column(s.status)} = ${subject.value(s.status, s.activeValue)})`;\n\n const management = (feature: PasskeyFeature): NativePasskeyManagementMapping => {\n const policy = feature.managementPolicy;\n\n if (policy === undefined)\n throw configurationError(`Missing passkey management policy for ${feature.moduleId}`);\n\n const c = t(\"passkeyCredentials\"),\n f = t(\"credentials\");\n\n return {\n ...base(feature),\n write: {\n credential: {\n name: \"name\",\n createdAt: \"createdAt\",\n encodeInsert: ({ credential, subjectId, summary, marker }) => ({\n credentialId: credential.credentialId,\n subjectId,\n rpId: credential.rpId,\n protocolCredentialId: credential.protocolCredentialId,\n userHandle: credential.userHandle,\n credentialKey: \"\",\n publicKey: credential.publicKey,\n algorithm: credential.algorithm,\n profile: Schema.encodeSync(profileJson)(credential.profile),\n credentialRevision: marker,\n active: true,\n primarySignIn: credential.primarySignIn,\n enrollmentUserVerified: credential.enrollmentUserVerified,\n backupEligible: credential.backupEligible,\n backupState: credential.backupState,\n counter: credential.counter,\n name: summary.name,\n createdAt: storage.encodeInstant(summary.createdAtMillis),\n }),\n encodePrimarySignIn: (value) => value,\n encodeEnrollmentUserVerified: (value) => value,\n encodeBackupEligible: (value) => value,\n activeStatus: true,\n removedStatus: false,\n },\n authority: {\n encodeInsert: ({ subjectId, credential, marker }) => ({\n subjectId,\n credentialId: credential.credentialId,\n revision: marker,\n active: true,\n }),\n activeStatus: true,\n removedStatus: false,\n },\n policy: {\n subjectColumns: subject.keys,\n management: () => policy,\n requirement: s.actionRequirements,\n metadata,\n action: metadata,\n remainingSignIn: (nativeId, excluded, row) =>\n Effect.gen(function* () {\n const requirement = yield* Schema.decodeEffect(M.PasskeyRequirement)(\n yield* s.requirements(row),\n );\n\n const alternatives: Fragment[] = [];\n\n if (\n requirement.alternatives.some(\n (alternative) =>\n alternative.minimumCredentials === 1 &&\n alternative.factors.every((factor) => factor === \"possession\"),\n )\n ) {\n alternatives.push(sql`exists(select 1 from ${c.name} join ${f.name} on ${f.column(\"credentialId\")} = ${c.column(\"credentialId\")} and ${f.column(\"subjectId\")} = ${f.value(\"subjectId\", nativeId)} and ${f.column(\"revision\")} = ${c.column(\"credentialRevision\")} and ${eq(\"credentials\", \"active\", true)}\n where ${eq(\"passkeyCredentials\", \"subjectId\", nativeId)} and ${c.column(\"credentialId\")} <> ${c.value(\"credentialId\", excluded)} and ${eq(\"passkeyCredentials\", \"active\", true)} and ${eq(\"passkeyCredentials\", \"primarySignIn\", true)} and ${eq(\"passkeyCredentials\", \"enrollmentUserVerified\", true)} and ${anySqlCondition(\n signInProfiles.map((profile) => eq(\"passkeyCredentials\", \"rpId\", profile.rpId)),\n )})`);\n }\n if (\n passwordModules.length > 0 &&\n requirement.alternatives.some(\n (alternative) =>\n alternative.minimumCredentials === 1 &&\n !alternative.userVerified &&\n !alternative.phishingResistant &&\n alternative.factors.every((factor) => factor === \"knowledge\"),\n )\n ) {\n const p = t(\"passwords\"),\n i = t(\"identifiers\");\n\n alternatives.push(sql`exists(select 1 from ${p.name} join ${f.name} on ${f.column(\"credentialId\")} = ${p.column(\"credentialId\")} and ${f.column(\"subjectId\")} = ${f.value(\"subjectId\", nativeId)} and ${f.column(\"revision\")} = ${p.column(\"credentialRevision\")} and ${eq(\"credentials\", \"active\", true)}\n join ${i.name} on ${eq(\"identifiers\", \"subjectId\", nativeId)} and ${eq(\"identifiers\", \"active\", true)} and ${eq(\"identifiers\", \"namespace\", \"email\")}\n where ${eq(\"passwords\", \"subjectId\", nativeId)} and ${p.column(\"credentialId\")} <> ${p.value(\"credentialId\", excluded)} and ${anySqlCondition(\n passwordModules.map((module) => eq(\"passwords\", \"moduleId\", module)),\n )})`);\n }\n\n return anySqlCondition(alternatives);\n }).pipe(\n Effect.mapError((cause) =>\n PersistenceMappingError.make({ operation: \"mapping\", cause }),\n ),\n ),\n },\n },\n invalidation: {\n window: {\n trigger: \"credential-change\",\n existingSessions: \"immediate\",\n maximumExposureMillis: 0,\n oldAuthenticationEvidence: \"rejected\",\n },\n mutations: [],\n postcondition: ({ subjectId, securityRevision }) =>\n sql`exists(select 1 from ${subject.name} where ${subject.column(s.id)} = ${subject.value(s.id, subjectId)} and ${subject.column(s.securityRevision)} = ${subject.value(s.securityRevision, securityRevision)})`,\n },\n };\n };\n\n return { base, management };\n});\n\n/** Managed and mapped tables feed the same native passkey statements. */\nexport const makeManagedPasskeys = Effect.fnUntraced(\n function* (input: ComposedPasskeyInput, tables: NativeSqlTables) {\n const batch = yield* SqlBatchCommit;\n\n const policies = yield* Effect.forEach(input.features, (feature) =>\n Effect.map(feature.policy, (policy) => ({ feature, policy })),\n );\n\n const mapping = yield* mappings(\n input.storage,\n tables,\n input.passwordModules,\n policies.flatMap(({ feature, policy }) => (feature.management ? [] : policy.profiles)),\n );\n\n const services = new Map<\n string,\n Effect.Success<ReturnType<typeof makeNativePasskeyServices>>\n >();\n\n const managers = new Map<string, M.PasskeyManagementPersistence[\"Service\"]>();\n\n for (const feature of input.features) {\n const selected = feature.management ? mapping.management(feature) : mapping.base(feature);\n\n const base = yield* batch === undefined\n ? makeNativePasskeyServices(tables, selected)\n : makeBatchPasskeyServices(tables, selected);\n\n services.set(feature.moduleId, base);\n if (feature.management)\n managers.set(\n feature.moduleId,\n makePasskeyNativeManagement(base, mapping.management(feature))\n .passkeyManagementPersistence,\n );\n }\n\n const service = (moduleId: string) => {\n const value = services.get(moduleId);\n\n return value === undefined\n ? Effect.fail(M.PasskeyUnavailable.make({}))\n : Effect.succeed(value);\n };\n\n const manager = (moduleId: string) => {\n const value = managers.get(moduleId);\n\n return value === undefined\n ? Effect.fail(M.PasskeyUnavailable.make({}))\n : Effect.succeed(value);\n };\n\n const first = services.values().next().value;\n\n if (first === undefined) return yield* configurationError(\"A passkey module is required\");\n\n let context: Context.Context<never> = Context.make(M.PasskeyCredentials, {\n lookup: (input) => first.passkeyCredentials.lookup(input),\n listForSubject: (input) =>\n Effect.flatMap(service(input.moduleId), (value) =>\n value.passkeyCredentials.listForSubject(input),\n ),\n }).pipe(\n Context.add(M.PasskeyPersistence, {\n issue: (input, prepare) =>\n Effect.flatMap(service(input.ceremony.moduleId), (value) =>\n value.passkeyPersistence.issue(input, prepare),\n ),\n context: (input) =>\n Effect.flatMap(service(input.moduleId), (value) =>\n value.passkeyPersistence.context(input),\n ),\n consume: (input, prepare) =>\n Effect.flatMap(service(input.access.moduleId), (value) =>\n value.passkeyPersistence.consume(input, prepare),\n ),\n cleanup: (input, prepare) =>\n Effect.flatMap(service(input.moduleId), (value) =>\n value.passkeyPersistence.cleanup(input, prepare),\n ),\n }),\n );\n\n if (managers.size > 0)\n context = context.pipe(\n Context.add(M.PasskeyManagementPersistence, {\n completeEnrollment: (input, prepare) =>\n Effect.flatMap(manager(input.ceremony.moduleId), (value) =>\n value.completeEnrollment(input, prepare),\n ),\n list: (input) => Effect.flatMap(manager(input.moduleId), (value) => value.list(input)),\n inspectRemove: (input) =>\n Effect.flatMap(manager(input.moduleId), (value) => value.inspectRemove(input)),\n rename: (input, prepare) =>\n Effect.flatMap(manager(input.moduleId), (value) => value.rename(input, prepare)),\n remove: (input, prepare) =>\n Effect.flatMap(manager(input.moduleId), (value) => value.remove(input, prepare)),\n }),\n );\n\n return context;\n },\n Effect.mapError((error) =>\n Schema.is(PersistenceConfigurationError)(error)\n ? error\n : configurationError(\"Unable to configure passkey persistence\"),\n ),\n);\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { PersistenceMappingError } from "./mapping-error.mjs";
2
+ import { nativeSqlAlias } from "./native-sql-table.mjs";
2
3
  import { sqlBatchAssertion } from "./d1-planning.mjs";
3
4
  import { exactSqlText, executeSqlChange } from "./sql-change.mjs";
4
5
  import { allocatePasswordNextSecurityRevision, allocatePasswordValue, passwordEvidenceSatisfiedAt, passwordProofRedemptionMatches, snapshotPasswordMutation, validatePasswordMutation } from "./password-policy.mjs";
@@ -6,7 +7,9 @@ import { requireStandalone } from "./standalone.mjs";
6
7
  import { CurrentSqlCommit, SqlBatchCommit, appendSqlBatchStatement, makeSqlCommitExecutor, registerSqlBatchPostcondition, registerSqlCommitReceipt, registerSqlPostcondition } from "./sql-commit.mjs";
7
8
  import { makeNativeProofStore } from "./proof-native.mjs";
8
9
  import { makePasswordCredentials, samePasswordCredentialSnapshot } from "./password-credentials.mjs";
10
+ import { guardSqlitePolicy } from "./sqlite-policy-guard.mjs";
9
11
  import { Crypto, DateTime, Effect, Option, Redacted, Schema } from "effect";
12
+ import { fragment, parameter } from "effect/sql/Statement";
10
13
  import { CurrentCommitJournal } from "@yielded/auth/Hooks";
11
14
  import * as P from "@yielded/auth/Password";
12
15
  import { ProofRedemptionInput } from "@yielded/auth/Proofs";
@@ -29,6 +32,7 @@ const makeNativePasswordServices = Effect.fnUntraced(function* (tables, mapping,
29
32
  const credential = tables(c.table).as("password_credential");
30
33
  const authority = tables(a.table).as("password_authority");
31
34
  const rawSubject = tables(s.table), rawPassword = tables(c.table), rawAuthority = tables(a.table);
35
+ const policyColumns = rawSubject.keys.filter((key) => key !== s.id && key !== s.status && key !== s.securityRevision);
32
36
  const now = tables.expression(mapping.clock.engineNowMillis);
33
37
  const lock = sql.onDialectOrElse({
34
38
  sqlite: () => sql``,
@@ -94,6 +98,10 @@ const makeNativePasswordServices = Effect.fnUntraced(function* (tables, mapping,
94
98
  return {
95
99
  nativeId,
96
100
  subjectRow,
101
+ policyValues: batch === void 0 ? [] : policyColumns.map((key) => ({
102
+ column: rawSubject.selectedColumn(key),
103
+ value: fragment([parameter(rows[0][nativeSqlAlias("password_subject_", rawSubject.keys.indexOf(key))])])
104
+ })),
97
105
  identifierRow,
98
106
  passwordRow,
99
107
  revision,
@@ -159,6 +167,12 @@ const makeNativePasswordServices = Effect.fnUntraced(function* (tables, mapping,
159
167
  const freshUntil = (requirement) => {
160
168
  return [...new Set(input.authorization.evidence.proofs.map((proof) => DateTime.toEpochMillis(proof.verifiedAt) + requirement.maximumAgeMillis))].filter((time) => time > state.now).sort((a, b) => a - b).find((time) => !passwordEvidenceSatisfiedAt(input.authorization.evidence, requirement, time));
161
169
  };
170
+ if (batch !== void 0) yield* guardSqlitePolicy({
171
+ name: "password-subject-policy",
172
+ table: rawSubject.name,
173
+ owner: subjectKey(rawSubject, s.id, nativeId),
174
+ values: state.policyValues
175
+ });
162
176
  const requestedDeadline = freshUntil(input.authorization.requirement), currentDeadline = freshUntil(requirement);
163
177
  ensure(requestedDeadline !== void 0 && currentDeadline !== void 0);
164
178
  const deadline = Math.min(requestedDeadline, currentDeadline);
@@ -1 +1 @@
1
- {"version":3,"file":"password-native.mjs","names":[],"sources":["../../src/internal/password-native.ts"],"sourcesContent":["import { CurrentCommitJournal, type LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport type { LoginIdentifier } from \"@yielded/auth/Identity\";\nimport * as P from \"@yielded/auth/Password\";\nimport { ProofRedemptionInput } from \"@yielded/auth/Proofs\";\nimport type { SubjectId } from \"@yielded/auth/Schema\";\nimport { SecurityRevision, type AuthenticationRequirement } from \"@yielded/auth/Sessions\";\nimport { DateTime, Effect, Option, Redacted, Schema, Crypto } from \"effect\";\nimport { SqlClient } from \"effect/sql/SqlClient\";\nimport type { Fragment } from \"effect/sql/Statement\";\n\nimport { sqlBatchAssertion } from \"./d1-planning\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport type { AnyPasswordPersistenceMapping } from \"./models/password-model\";\nimport type { AnyProofPersistenceMapping } from \"./models/proof-model\";\nimport type { NativeSqlTables, SqlTable } from \"./native-sql-table\";\nimport { makePasswordCredentials, samePasswordCredentialSnapshot } from \"./password-credentials\";\nimport {\n allocatePasswordNextSecurityRevision,\n allocatePasswordValue,\n passwordEvidenceSatisfiedAt,\n passwordProofRedemptionMatches,\n snapshotPasswordMutation,\n validatePasswordMutation,\n} from \"./password-policy\";\nimport { makeNativeProofStore } from \"./proof-native\";\nimport { exactSqlText, executeSqlChange } from \"./sql-change\";\nimport {\n appendSqlBatchStatement,\n CurrentSqlCommit,\n makeSqlCommitExecutor,\n registerSqlBatchPostcondition,\n registerSqlCommitReceipt,\n registerSqlPostcondition,\n SqlBatchCommit,\n} from \"./sql-commit\";\nimport { requireStandalone } from \"./standalone\";\n\nconst unavailable = () => P.PasswordUnavailable.make({});\n\nconst ensure: (condition: unknown) => asserts condition = (condition) => {\n if (!condition) throw unavailable();\n};\n\nexport const makeNativePasswordServices = Effect.fnUntraced(function* (\n tables: NativeSqlTables,\n mapping: AnyPasswordPersistenceMapping,\n proofs?: AnyProofPersistenceMapping,\n): Effect.fn.Return<\n { readonly passwordPersistence: P.PasswordPersistence[\"Service\"] },\n P.PasswordUnavailable,\n SqlClient | LifecycleHooks | Crypto.Crypto | SqlBatchCommit\n> {\n const batch = yield* SqlBatchCommit;\n const sql = (yield* SqlClient).withoutTransforms();\n const executor = yield* makeSqlCommitExecutor(unavailable);\n const crypto = yield* Crypto.Crypto;\n const parent = yield* Effect.serviceOption(CurrentSqlCommit);\n\n const s = mapping.subject,\n i = mapping.identifier,\n c = mapping.credential,\n a = mapping.authorityCredential;\n\n const subject = tables(s.table).as(\"password_subject\");\n const identifier = tables(i.table).as(\"password_identifier\");\n const credential = tables(c.table).as(\"password_credential\");\n const authority = tables(a.table).as(\"password_authority\");\n\n const rawSubject = tables(s.table),\n rawPassword = tables(c.table),\n rawAuthority = tables(a.table);\n\n const now = tables.expression(mapping.clock.engineNowMillis);\n const lock = sql.onDialectOrElse({ sqlite: () => sql``, orElse: () => sql`for update` });\n\n const exact = (table: SqlTable, key: string, value: unknown) =>\n exactSqlText(sql, table.column(key), table.value(key, value));\n\n const subjectKey = (table: SqlTable, key: string, nativeId: unknown) =>\n sql`${table.column(key)} = ${table.value(key, nativeId)}`;\n\n const run = <A, E, R>(work: Effect.Effect<A, E, R>) =>\n batch === undefined\n ? executor.run(work.pipe(Effect.provideService(Crypto.Crypto, crypto)))\n : executor\n .batch(work.pipe(Effect.provideService(Crypto.Crypto, crypto)))\n .pipe(Effect.provideService(SqlBatchCommit, batch));\n\n const read = Effect.fnUntraced(function* (\n moduleId: string,\n subjectId: SubjectId,\n wanted?: LoginIdentifier,\n locked?: Record<string, unknown>,\n ) {\n const nativeId = yield* mapping.subjectId.toNative(subjectId);\n\n // Without one wanted identifier, retired identifiers would multiply authority\n // rows; read authority separately so the result grows linearly.\n const joined = wanted !== undefined;\n\n const rows =\n yield* sql`select ${subject.fields(\"password_subject_\")}, ${identifier.fields(\"password_identifier_\")}, ${credential.fields(\"password_credential_\")}${joined ? sql`, ${authority.fields(\"password_authority_\")}` : sql``}, ${now} as engine_now\n from ${subject.name}\n left join ${identifier.name} on ${subjectKey(identifier, i.subjectId, nativeId)} ${wanted === undefined ? sql`` : sql`and ${exact(identifier, i.namespace, wanted.namespace)} and ${exact(identifier, i.value, wanted.value)}`}\n left join ${credential.name} on ${subjectKey(credential, c.subjectId, nativeId)} and ${exact(credential, c.moduleId, moduleId)}\n ${joined ? sql`left join ${authority.name} on ${subjectKey(authority, a.subjectId, nativeId)}` : sql``}\n where ${subjectKey(subject, s.id, nativeId)} order by ${identifier.column(i.namespace)}, ${identifier.column(i.value)}${joined ? sql`, ${authority.column(a.credentialId)}` : sql``} limit 4097`;\n\n const authorityRows = joined\n ? rows\n : yield* sql`select ${authority.fields(\"password_authority_\")} from ${authority.name} where ${subjectKey(authority, a.subjectId, nativeId)} order by ${authority.column(a.credentialId)} limit 4097`;\n\n ensure(rows.length <= 4096 && authorityRows.length <= 4096);\n if (rows[0] === undefined) return undefined;\n const subjectRow = subject.decode(rows[0], \"password_subject_\");\n const decodedId = yield* mapping.subjectId.toSubject(subjectRow[s.id]);\n\n ensure(\n decodedId === subjectId &&\n (locked === undefined || subjectRow[s.securityRevision] === locked[s.securityRevision]),\n );\n const password = credential.decode(rows[0], \"password_credential_\");\n const passwordRow = password[c.credentialId] === null ? undefined : password;\n\n const factors = new Map<\n string,\n {\n readonly credentialId: string;\n readonly revision: SecurityRevision;\n readonly active: boolean;\n }\n >();\n\n let identifierRow: Record<string, unknown> | undefined;\n\n for (const row of authorityRows) {\n const factor = authority.decode(row, \"password_authority_\");\n\n if (\n factor[a.credentialId] !== null &&\n (a.status === undefined || a.isActiveStatus?.(factor[a.status]) === true)\n ) {\n ensure(mapping.subjectId.equals(factor[a.subjectId], nativeId));\n const id = yield* Schema.decodeUnknownEffect(Schema.String)(factor[a.credentialId]);\n const revision = yield* Schema.decodeUnknownEffect(SecurityRevision)(factor[a.revision]);\n const old = factors.get(id);\n\n ensure(old === undefined || old.revision === revision);\n factors.set(id, { credentialId: id, revision, active: true });\n }\n }\n for (const row of rows) {\n const entry = identifier.decode(row, \"password_identifier_\");\n\n if (\n entry[i.namespace] !== null &&\n mapping.subjectId.equals(entry[i.subjectId], nativeId) &&\n mapping.identifier.isCurrent(entry)\n )\n identifierRow ??= entry;\n }\n ensure(factors.size <= 64);\n\n const revision = {\n subjectId,\n securityRevision: yield* Schema.decodeUnknownEffect(SecurityRevision)(\n subjectRow[s.securityRevision],\n ),\n credentials: [...factors.values()].map(({ credentialId, revision }) => ({\n credentialId,\n revision,\n })),\n };\n\n const snapshot =\n identifierRow === undefined || passwordRow === undefined\n ? undefined\n : yield* mapping.credential\n .decode({\n moduleId,\n subject: subjectRow,\n identifier: identifierRow,\n credential: passwordRow,\n })\n .pipe(Effect.flatMap(P.snapshotPasswordCredential));\n\n if (snapshot !== undefined)\n ensure(\n snapshot.revision.subjectId === subjectId &&\n snapshot.credentialId === passwordRow?.[c.credentialId],\n );\n\n return {\n nativeId,\n subjectRow,\n identifierRow,\n passwordRow,\n revision,\n snapshot: snapshot === undefined ? undefined : { ...snapshot, revision },\n now: yield* Schema.decodeEffect(Schema.Int)(Number(rows[0].engine_now)),\n };\n });\n\n const prepare = <V, A>(value: V, project: P.PreparePasswordCommit<V, A>) =>\n Effect.gen(function* () {\n const journal = yield* CurrentCommitJournal;\n\n const receipt = project(value, journal);\n\n ensure(receipt?._tag === \"PreparedCommit\" && Effect.isEffect(receipt.read));\n yield* registerSqlCommitReceipt(receipt);\n\n return receipt;\n });\n\n const mutation = <A>(\n original: P.PasswordMutationInput,\n action: P.PasswordAction,\n project: P.PreparePasswordCommit<P.PasswordMutationDecision, A>,\n redemption?: Parameters<P.PasswordPersistence[\"Service\"][\"resetWithProof\"]>[0][\"redemption\"],\n ) =>\n run(\n Effect.gen(function* () {\n const input = yield* snapshotPasswordMutation(original);\n const nativeId = yield* mapping.subjectId.toNative(input.expectedRevision.subjectId);\n\n const rows =\n yield* sql`select ${rawSubject.fields(\"password_lock_\")} from ${rawSubject.name} where ${subjectKey(rawSubject, s.id, nativeId)} limit 2 ${batch === undefined ? lock : sql``}`;\n\n if (rows.length === 0) return yield* prepare(\"rejected\" as const, project);\n ensure(rows.length === 1);\n const locked = rawSubject.decode(rows[0]!, \"password_lock_\");\n\n const state = yield* read(\n input.moduleId,\n input.expectedRevision.subjectId,\n input.credential?.identifier,\n locked,\n );\n\n if (state === undefined) return yield* prepare(\"rejected\" as const, project);\n const requirement = yield* s.decodeActionRequirement(state.subjectRow, action);\n\n const valid = yield* validatePasswordMutation(\n mapping,\n input,\n action,\n {\n subject: {\n active: s.isActiveStatus(state.subjectRow[s.status]),\n securityRevision: state.revision.securityRevision,\n },\n identifierCurrent: state.identifierRow !== undefined,\n credentials: state.revision.credentials.map((entry) => ({ ...entry, active: true })),\n snapshot: Effect.succeed(state.snapshot),\n requirement: Effect.succeed(requirement),\n },\n state.now,\n );\n\n if (\n valid === undefined ||\n (action === \"add-password\"\n ? state.passwordRow !== undefined\n : state.snapshot === undefined ||\n input.credential === undefined ||\n !samePasswordCredentialSnapshot(state.snapshot, input.credential))\n )\n return yield* prepare(\"rejected\" as const, project);\n let proofValidity = sql`1 = 1`;\n\n if (redemption !== undefined) {\n if (proofs === undefined) return yield* unavailable();\n\n const captured = {\n ...redemption,\n input: yield* Schema.decodeEffect(ProofRedemptionInput)(redemption.input),\n };\n\n if (!passwordProofRedemptionMatches({ ...input, redemption: captured }))\n return yield* prepare(\"rejected\" as const, project);\n // Inherit the physical owner; application owners retain the exact consumed\n // proof absence check after their callback.\n const proof = yield* makeNativeProofStore(tables, proofs, batch !== undefined);\n const redeemed = yield* proof.redeemLocked(captured.input);\n\n const proofReceipt = captured.prepare(\n redeemed.decision,\n yield* CurrentCommitJournal,\n (value) => value,\n );\n\n yield* registerSqlCommitReceipt(proofReceipt);\n if (redeemed.decision === \"rejected\") return yield* prepare(\"rejected\" as const, project);\n proofValidity = redeemed.validUntil;\n }\n const mode = \"interactive\";\n\n const credentialId =\n input.credential?.credentialId ??\n (yield* allocatePasswordValue(\n mode,\n mapping.allocateCredentialId,\n mapping.allocateCredentialIdSync,\n ));\n\n const credentialRevision = yield* allocatePasswordValue(\n mode,\n mapping.allocateRevision,\n mapping.allocateRevisionSync,\n );\n\n const verifierVersion = yield* allocatePasswordValue(\n mode,\n mapping.allocateRevision,\n mapping.allocateRevisionSync,\n );\n\n const nextSecurityRevision = yield* allocatePasswordNextSecurityRevision(\n mapping,\n mode,\n input.expectedRevision.securityRevision,\n );\n\n ensure(\n nextSecurityRevision !== input.expectedRevision.securityRevision &&\n credentialRevision !== input.credential?.credentialRevision &&\n verifierVersion !== input.credential?.verifierVersion,\n );\n\n const freshUntil = (requirement: AuthenticationRequirement) => {\n const deadlines = [\n ...new Set(\n input.authorization.evidence.proofs.map(\n (proof) => DateTime.toEpochMillis(proof.verifiedAt) + requirement.maximumAgeMillis,\n ),\n ),\n ]\n .filter((time) => time > state.now)\n .sort((a, b) => a - b);\n\n return deadlines.find(\n (time) => !passwordEvidenceSatisfiedAt(input.authorization.evidence, requirement, time),\n );\n };\n\n const requestedDeadline = freshUntil(input.authorization.requirement),\n currentDeadline = freshUntil(requirement);\n\n ensure(requestedDeadline !== undefined && currentDeadline !== undefined);\n const deadline = Math.min(requestedDeadline, currentDeadline);\n const freshness = sql`${now} >= ${state.now} and ${now} < ${deadline} and ${proofValidity}`;\n\n const stage = Effect.fnUntraced(function* (statement: Fragment) {\n if (batch === undefined) ensure((yield* executeSqlChange(sql, statement)) === 1);\n else {\n yield* appendSqlBatchStatement(sql`${statement}`);\n yield* appendSqlBatchStatement(sqlBatchAssertion(sql, sql`changes() = 1`));\n }\n });\n\n if (batch !== undefined) {\n if (\n s.d1ActiveStatusValue === undefined ||\n (a.status !== undefined && a.d1ActiveStatusValue === undefined)\n )\n return yield* unavailable();\n\n const factors = state.revision.credentials.map(\n (factor) =>\n sql`exists(select 1 from ${rawAuthority.name} where ${subjectKey(rawAuthority, a.subjectId, nativeId)} and ${exact(rawAuthority, a.credentialId, factor.credentialId)} and ${exact(rawAuthority, a.revision, factor.revision)} ${a.status === undefined ? sql`` : sql`and ${rawAuthority.column(a.status)} = ${rawAuthority.value(a.status, a.d1ActiveStatusValue)}`})`,\n );\n\n const active =\n a.status === undefined\n ? sql`1 = 1`\n : sql`${rawAuthority.column(a.status)} = ${rawAuthority.value(a.status, a.d1ActiveStatusValue)}`;\n\n const condition = sql.and([\n sql`exists(select 1 from ${rawSubject.name} where ${subjectKey(rawSubject, s.id, nativeId)} and ${exact(rawSubject, s.securityRevision, input.expectedRevision.securityRevision)} and ${rawSubject.column(s.status)} = ${rawSubject.value(s.status, s.d1ActiveStatusValue)})`,\n sql`(select count(*) from ${rawAuthority.name} where ${subjectKey(rawAuthority, a.subjectId, nativeId)} and ${active}) = ${factors.length}`,\n ...factors,\n freshness,\n ]);\n\n yield* appendSqlBatchStatement(sqlBatchAssertion(sql, condition));\n if (input.credential !== undefined) {\n if (i.d1CurrentCondition === undefined) return yield* unavailable();\n yield* appendSqlBatchStatement(\n sqlBatchAssertion(\n sql,\n sql`exists(select 1 from ${tables(i.table).name} where ${exact(tables(i.table), i.namespace, input.credential.identifier.namespace)} and ${exact(tables(i.table), i.value, input.credential.identifier.value)} and ${subjectKey(tables(i.table), i.subjectId, nativeId)} and ${tables.expression(i.d1CurrentCondition({ identifier: input.credential.identifier, nativeSubjectId: nativeId }))})`,\n ),\n );\n }\n }\n const revisions = { credentialId, credentialRevision, verifierVersion };\n\n if (input.credential === undefined) {\n yield* stage(\n sql`${rawPassword.insert(c.encodeInsert({ moduleId: input.moduleId, subjectId: nativeId, replacement: input.replacement, ...revisions }))}`,\n );\n yield* stage(\n sql`${rawAuthority.insert(a.encodeInsert({ subjectId: nativeId, credentialId, revision: credentialRevision }))}`,\n );\n } else {\n const old = input.credential;\n\n yield* stage(\n sql`${rawPassword.update(c.encodeReplacement({ replacement: input.replacement, credentialRevision, verifierVersion }))} where ${subjectKey(rawPassword, c.subjectId, nativeId)} and ${exact(rawPassword, c.moduleId, input.moduleId)} and ${exact(rawPassword, c.credentialId, old.credentialId)} and ${exact(rawPassword, c.credentialRevision, old.credentialRevision)} and ${exact(rawPassword, c.verifierVersion, old.verifierVersion)} and ${exact(rawPassword, c.verifier, Redacted.value(old.verifier))} and ${exact(rawPassword, c.normalization, old.normalization)} and ${freshness}`,\n );\n yield* stage(\n sql`${rawAuthority.update(a.encodeRevision(credentialRevision))} where ${subjectKey(rawAuthority, a.subjectId, nativeId)} and ${exact(rawAuthority, a.credentialId, old.credentialId)} and ${exact(rawAuthority, a.revision, old.credentialRevision)}`,\n );\n }\n\n const expectedFactors = state.revision.credentials\n .filter((factor) => factor.credentialId !== credentialId)\n .concat({ credentialId, revision: credentialRevision });\n\n const finalPassword = sql`exists(select 1 from ${rawPassword.name} where ${subjectKey(rawPassword, c.subjectId, nativeId)} and ${exact(rawPassword, c.moduleId, input.moduleId)} and ${exact(rawPassword, c.credentialId, credentialId)} and ${exact(rawPassword, c.credentialRevision, credentialRevision)} and ${exact(rawPassword, c.verifierVersion, verifierVersion)} and ${exact(rawPassword, c.verifier, Redacted.value(input.replacement.verifier))} and ${exact(rawPassword, c.normalization, input.replacement.normalization)})`;\n\n const canGuardResult =\n (a.status === undefined || a.d1ActiveStatusValue !== undefined) &&\n (input.credential === undefined || i.d1CurrentCondition !== undefined);\n\n let resultingState: Fragment | undefined;\n\n if (canGuardResult) {\n const active =\n a.status === undefined\n ? sql`1 = 1`\n : sql`${rawAuthority.column(a.status)} = ${rawAuthority.value(a.status, a.d1ActiveStatusValue)}`;\n\n const conditions: Array<Fragment> = [\n finalPassword,\n freshness,\n sql`(select count(*) from ${rawAuthority.name} where ${subjectKey(rawAuthority, a.subjectId, nativeId)} and ${active}) = ${expectedFactors.length}`,\n ...expectedFactors.map(\n (factor) =>\n sql`exists(select 1 from ${rawAuthority.name} where ${subjectKey(rawAuthority, a.subjectId, nativeId)} and ${exact(rawAuthority, a.credentialId, factor.credentialId)} and ${exact(rawAuthority, a.revision, factor.revision)} and ${active})`,\n ),\n ];\n\n if (input.credential !== undefined) {\n const expected = input.credential;\n const identifierTable = tables(i.table);\n\n ensure(i.d1CurrentCondition !== undefined);\n conditions.push(\n sql`exists(select 1 from ${identifierTable.name} where ${exact(identifierTable, i.namespace, expected.identifier.namespace)} and ${exact(identifierTable, i.value, expected.identifier.value)} and ${subjectKey(identifierTable, i.subjectId, nativeId)} and ${tables.expression(i.d1CurrentCondition({ identifier: expected.identifier, nativeSubjectId: nativeId }))})`,\n sql`exists(select 1 from ${identifierTable.name} where ${exact(identifierTable, i.namespace, expected.identifier.namespace)} and ${exact(identifierTable, i.value, expected.identifier.value)} and ${subjectKey(identifierTable, i.subjectId, nativeId)} and ${exact(identifierTable, i.bindingRevision, expected.identifierBindingRevision)} and ${expected.identifierVerifiedAtMillis === undefined ? sql`${identifierTable.column(i.verifiedAt)} is null` : sql`${identifierTable.column(i.verifiedAt)} = ${identifierTable.value(i.verifiedAt, mapping.clock.encodeInstant(expected.identifierVerifiedAtMillis))}`})`,\n );\n }\n resultingState = sql.and(conditions);\n }\n yield* stage(\n sql`${rawSubject.update({ [s.securityRevision]: nextSecurityRevision })} where ${subjectKey(rawSubject, s.id, nativeId)} and ${exact(rawSubject, s.securityRevision, input.expectedRevision.securityRevision)} and ${rawSubject.column(s.status)} = ${rawSubject.value(s.status, locked[s.status])} and ${freshness} and ${resultingState ?? sql`1 = 1`}`,\n );\n if (batch !== undefined) {\n ensure(resultingState !== undefined);\n yield* registerSqlBatchPostcondition({\n name: \"password-replacement-authority\",\n statement: sqlBatchAssertion(\n sql,\n sql.and([\n resultingState,\n sql`exists(select 1 from ${rawSubject.name} where ${subjectKey(rawSubject, s.id, nativeId)} and ${exact(rawSubject, s.securityRevision, nextSecurityRevision)} and ${rawSubject.column(s.status)} = ${rawSubject.value(s.status, s.d1ActiveStatusValue)})`,\n ]),\n ),\n });\n } else if (Option.isSome(parent) || resultingState === undefined)\n yield* registerSqlPostcondition({\n name: \"password-replacement-authority\",\n check: Effect.gen(function* () {\n const final = yield* read(\n input.moduleId,\n input.expectedRevision.subjectId,\n input.credential?.identifier,\n );\n\n ensure(\n final !== undefined &&\n s.isActiveStatus(final.subjectRow[s.status]) &&\n final.revision.securityRevision === nextSecurityRevision &&\n final.revision.credentials.length === expectedFactors.length &&\n expectedFactors.every((factor) =>\n final.revision.credentials.some(\n (entry) =>\n entry.credentialId === factor.credentialId &&\n entry.revision === factor.revision,\n ),\n ) &&\n final.now >= state.now &&\n final.now < deadline,\n );\n const password = final.passwordRow;\n\n ensure(\n password !== undefined &&\n password[c.credentialId] === credentialId &&\n password[c.credentialRevision] === credentialRevision &&\n password[c.verifierVersion] === verifierVersion &&\n password[c.verifier] === Redacted.value(input.replacement.verifier) &&\n password[c.normalization] === input.replacement.normalization,\n );\n if (input.credential !== undefined)\n ensure(\n final.snapshot !== undefined &&\n final.snapshot.identifierBindingRevision ===\n input.credential.identifierBindingRevision &&\n final.snapshot.identifierVerifiedAtMillis ===\n input.credential.identifierVerifiedAtMillis,\n );\n }).pipe(\n Effect.mapError((cause) =>\n PersistenceMappingError.make({ operation: \"decode\", cause }),\n ),\n ),\n });\n\n return yield* prepare(\"changed\" as const, project);\n }),\n );\n\n const credentials = yield* makePasswordCredentials(tables, mapping, {\n mode: \"interactive\",\n locking: false,\n coordinated: Option.isSome(parent),\n standaloneGuard: requireStandalone(unavailable, sql.transactionService),\n });\n\n const passwordPersistence: P.PasswordPersistence[\"Service\"] = {\n ...credentials,\n readForSubject: (input) =>\n executor.read(\n Effect.map(read(input.moduleId, input.subjectId), (state) =>\n state === undefined || !s.isActiveStatus(state.subjectRow[s.status])\n ? Option.none()\n : Option.fromUndefinedOr(state.snapshot),\n ),\n ),\n recoveryTarget: (input) =>\n executor.read(\n Effect.gen(function* () {\n const rows =\n yield* sql`select ${identifier.fields(\"password_recovery_\")} from ${identifier.name} where ${exact(identifier, i.namespace, input.identifier.namespace)} and ${exact(identifier, i.value, input.identifier.value)} limit 2`;\n\n if (rows.length === 0) return Option.none();\n ensure(rows.length === 1);\n const row = identifier.decode(rows[0]!, \"password_recovery_\");\n\n if (!i.isCurrent(row)) return Option.none();\n const subjectId = yield* mapping.subjectId.toSubject(row[i.subjectId]);\n const state = yield* read(input.moduleId, subjectId, input.identifier);\n\n return state === undefined ||\n !s.isActiveStatus(state.subjectRow[s.status]) ||\n state.snapshot?.identifierVerifiedAtMillis === undefined\n ? Option.none()\n : Option.some(state.snapshot);\n }),\n ),\n addIfAbsent: (input, project) => mutation(input, \"add-password\", project),\n replaceIfCurrent: (input, project) => mutation(input, \"change-password\", project),\n resetWithProof: (input, project) =>\n mutation(input, \"reset-password\", project, input.redemption),\n };\n\n return { passwordPersistence };\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"password-native.mjs","names":[],"sources":["../../src/internal/password-native.ts"],"sourcesContent":["import { CurrentCommitJournal, type LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport type { LoginIdentifier } from \"@yielded/auth/Identity\";\nimport * as P from \"@yielded/auth/Password\";\nimport { ProofRedemptionInput } from \"@yielded/auth/Proofs\";\nimport type { SubjectId } from \"@yielded/auth/Schema\";\nimport { SecurityRevision, type AuthenticationRequirement } from \"@yielded/auth/Sessions\";\nimport { DateTime, Effect, Option, Redacted, Schema, Crypto } from \"effect\";\nimport { SqlClient } from \"effect/sql/SqlClient\";\nimport { fragment, parameter, type Fragment } from \"effect/sql/Statement\";\n\nimport { sqlBatchAssertion } from \"./d1-planning\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport type { AnyPasswordPersistenceMapping } from \"./models/password-model\";\nimport type { AnyProofPersistenceMapping } from \"./models/proof-model\";\nimport { nativeSqlAlias, type NativeSqlTables, type SqlTable } from \"./native-sql-table\";\nimport { makePasswordCredentials, samePasswordCredentialSnapshot } from \"./password-credentials\";\nimport {\n allocatePasswordNextSecurityRevision,\n allocatePasswordValue,\n passwordEvidenceSatisfiedAt,\n passwordProofRedemptionMatches,\n snapshotPasswordMutation,\n validatePasswordMutation,\n} from \"./password-policy\";\nimport { makeNativeProofStore } from \"./proof-native\";\nimport { exactSqlText, executeSqlChange } from \"./sql-change\";\nimport {\n appendSqlBatchStatement,\n CurrentSqlCommit,\n makeSqlCommitExecutor,\n registerSqlBatchPostcondition,\n registerSqlCommitReceipt,\n registerSqlPostcondition,\n SqlBatchCommit,\n} from \"./sql-commit\";\nimport { guardSqlitePolicy } from \"./sqlite-policy-guard\";\nimport { requireStandalone } from \"./standalone\";\n\nconst unavailable = () => P.PasswordUnavailable.make({});\n\nconst ensure: (condition: unknown) => asserts condition = (condition) => {\n if (!condition) throw unavailable();\n};\n\nexport const makeNativePasswordServices = Effect.fnUntraced(function* (\n tables: NativeSqlTables,\n mapping: AnyPasswordPersistenceMapping,\n proofs?: AnyProofPersistenceMapping,\n): Effect.fn.Return<\n { readonly passwordPersistence: P.PasswordPersistence[\"Service\"] },\n P.PasswordUnavailable,\n SqlClient | LifecycleHooks | Crypto.Crypto | SqlBatchCommit\n> {\n const batch = yield* SqlBatchCommit;\n const sql = (yield* SqlClient).withoutTransforms();\n const executor = yield* makeSqlCommitExecutor(unavailable);\n const crypto = yield* Crypto.Crypto;\n const parent = yield* Effect.serviceOption(CurrentSqlCommit);\n\n const s = mapping.subject,\n i = mapping.identifier,\n c = mapping.credential,\n a = mapping.authorityCredential;\n\n const subject = tables(s.table).as(\"password_subject\");\n const identifier = tables(i.table).as(\"password_identifier\");\n const credential = tables(c.table).as(\"password_credential\");\n const authority = tables(a.table).as(\"password_authority\");\n\n const rawSubject = tables(s.table),\n rawPassword = tables(c.table),\n rawAuthority = tables(a.table);\n\n // Action policy may inspect any application column. Authority columns have\n // separate checks and securityRevision intentionally changes in this mutation.\n const policyColumns = rawSubject.keys.filter(\n (key) => key !== s.id && key !== s.status && key !== s.securityRevision,\n );\n\n const now = tables.expression(mapping.clock.engineNowMillis);\n const lock = sql.onDialectOrElse({ sqlite: () => sql``, orElse: () => sql`for update` });\n\n const exact = (table: SqlTable, key: string, value: unknown) =>\n exactSqlText(sql, table.column(key), table.value(key, value));\n\n const subjectKey = (table: SqlTable, key: string, nativeId: unknown) =>\n sql`${table.column(key)} = ${table.value(key, nativeId)}`;\n\n const run = <A, E, R>(work: Effect.Effect<A, E, R>) =>\n batch === undefined\n ? executor.run(work.pipe(Effect.provideService(Crypto.Crypto, crypto)))\n : executor\n .batch(work.pipe(Effect.provideService(Crypto.Crypto, crypto)))\n .pipe(Effect.provideService(SqlBatchCommit, batch));\n\n const read = Effect.fnUntraced(function* (\n moduleId: string,\n subjectId: SubjectId,\n wanted?: LoginIdentifier,\n locked?: Record<string, unknown>,\n ) {\n const nativeId = yield* mapping.subjectId.toNative(subjectId);\n\n // Without one wanted identifier, retired identifiers would multiply authority\n // rows; read authority separately so the result grows linearly.\n const joined = wanted !== undefined;\n\n const rows =\n yield* sql`select ${subject.fields(\"password_subject_\")}, ${identifier.fields(\"password_identifier_\")}, ${credential.fields(\"password_credential_\")}${joined ? sql`, ${authority.fields(\"password_authority_\")}` : sql``}, ${now} as engine_now\n from ${subject.name}\n left join ${identifier.name} on ${subjectKey(identifier, i.subjectId, nativeId)} ${wanted === undefined ? sql`` : sql`and ${exact(identifier, i.namespace, wanted.namespace)} and ${exact(identifier, i.value, wanted.value)}`}\n left join ${credential.name} on ${subjectKey(credential, c.subjectId, nativeId)} and ${exact(credential, c.moduleId, moduleId)}\n ${joined ? sql`left join ${authority.name} on ${subjectKey(authority, a.subjectId, nativeId)}` : sql``}\n where ${subjectKey(subject, s.id, nativeId)} order by ${identifier.column(i.namespace)}, ${identifier.column(i.value)}${joined ? sql`, ${authority.column(a.credentialId)}` : sql``} limit 4097`;\n\n const authorityRows = joined\n ? rows\n : yield* sql`select ${authority.fields(\"password_authority_\")} from ${authority.name} where ${subjectKey(authority, a.subjectId, nativeId)} order by ${authority.column(a.credentialId)} limit 4097`;\n\n ensure(rows.length <= 4096 && authorityRows.length <= 4096);\n if (rows[0] === undefined) return undefined;\n const subjectRow = subject.decode(rows[0], \"password_subject_\");\n const decodedId = yield* mapping.subjectId.toSubject(subjectRow[s.id]);\n\n ensure(\n decodedId === subjectId &&\n (locked === undefined || subjectRow[s.securityRevision] === locked[s.securityRevision]),\n );\n const password = credential.decode(rows[0], \"password_credential_\");\n const passwordRow = password[c.credentialId] === null ? undefined : password;\n\n const factors = new Map<\n string,\n {\n readonly credentialId: string;\n readonly revision: SecurityRevision;\n readonly active: boolean;\n }\n >();\n\n let identifierRow: Record<string, unknown> | undefined;\n\n for (const row of authorityRows) {\n const factor = authority.decode(row, \"password_authority_\");\n\n if (\n factor[a.credentialId] !== null &&\n (a.status === undefined || a.isActiveStatus?.(factor[a.status]) === true)\n ) {\n ensure(mapping.subjectId.equals(factor[a.subjectId], nativeId));\n const id = yield* Schema.decodeUnknownEffect(Schema.String)(factor[a.credentialId]);\n const revision = yield* Schema.decodeUnknownEffect(SecurityRevision)(factor[a.revision]);\n const old = factors.get(id);\n\n ensure(old === undefined || old.revision === revision);\n factors.set(id, { credentialId: id, revision, active: true });\n }\n }\n for (const row of rows) {\n const entry = identifier.decode(row, \"password_identifier_\");\n\n if (\n entry[i.namespace] !== null &&\n mapping.subjectId.equals(entry[i.subjectId], nativeId) &&\n mapping.identifier.isCurrent(entry)\n )\n identifierRow ??= entry;\n }\n ensure(factors.size <= 64);\n\n const revision = {\n subjectId,\n securityRevision: yield* Schema.decodeUnknownEffect(SecurityRevision)(\n subjectRow[s.securityRevision],\n ),\n credentials: [...factors.values()].map(({ credentialId, revision }) => ({\n credentialId,\n revision,\n })),\n };\n\n const snapshot =\n identifierRow === undefined || passwordRow === undefined\n ? undefined\n : yield* mapping.credential\n .decode({\n moduleId,\n subject: subjectRow,\n identifier: identifierRow,\n credential: passwordRow,\n })\n .pipe(Effect.flatMap(P.snapshotPasswordCredential));\n\n if (snapshot !== undefined)\n ensure(\n snapshot.revision.subjectId === subjectId &&\n snapshot.credentialId === passwordRow?.[c.credentialId],\n );\n\n return {\n nativeId,\n subjectRow,\n policyValues:\n batch === undefined\n ? []\n : policyColumns.map((key) => ({\n column: rawSubject.selectedColumn(key),\n value: fragment([\n parameter(\n rows[0][nativeSqlAlias(\"password_subject_\", rawSubject.keys.indexOf(key))],\n ),\n ]),\n })),\n identifierRow,\n passwordRow,\n revision,\n snapshot: snapshot === undefined ? undefined : { ...snapshot, revision },\n now: yield* Schema.decodeEffect(Schema.Int)(Number(rows[0].engine_now)),\n };\n });\n\n const prepare = <V, A>(value: V, project: P.PreparePasswordCommit<V, A>) =>\n Effect.gen(function* () {\n const journal = yield* CurrentCommitJournal;\n\n const receipt = project(value, journal);\n\n ensure(receipt?._tag === \"PreparedCommit\" && Effect.isEffect(receipt.read));\n yield* registerSqlCommitReceipt(receipt);\n\n return receipt;\n });\n\n const mutation = <A>(\n original: P.PasswordMutationInput,\n action: P.PasswordAction,\n project: P.PreparePasswordCommit<P.PasswordMutationDecision, A>,\n redemption?: Parameters<P.PasswordPersistence[\"Service\"][\"resetWithProof\"]>[0][\"redemption\"],\n ) =>\n run(\n Effect.gen(function* () {\n const input = yield* snapshotPasswordMutation(original);\n const nativeId = yield* mapping.subjectId.toNative(input.expectedRevision.subjectId);\n\n const rows =\n yield* sql`select ${rawSubject.fields(\"password_lock_\")} from ${rawSubject.name} where ${subjectKey(rawSubject, s.id, nativeId)} limit 2 ${batch === undefined ? lock : sql``}`;\n\n if (rows.length === 0) return yield* prepare(\"rejected\" as const, project);\n ensure(rows.length === 1);\n const locked = rawSubject.decode(rows[0]!, \"password_lock_\");\n\n const state = yield* read(\n input.moduleId,\n input.expectedRevision.subjectId,\n input.credential?.identifier,\n locked,\n );\n\n if (state === undefined) return yield* prepare(\"rejected\" as const, project);\n const requirement = yield* s.decodeActionRequirement(state.subjectRow, action);\n\n const valid = yield* validatePasswordMutation(\n mapping,\n input,\n action,\n {\n subject: {\n active: s.isActiveStatus(state.subjectRow[s.status]),\n securityRevision: state.revision.securityRevision,\n },\n identifierCurrent: state.identifierRow !== undefined,\n credentials: state.revision.credentials.map((entry) => ({ ...entry, active: true })),\n snapshot: Effect.succeed(state.snapshot),\n requirement: Effect.succeed(requirement),\n },\n state.now,\n );\n\n if (\n valid === undefined ||\n (action === \"add-password\"\n ? state.passwordRow !== undefined\n : state.snapshot === undefined ||\n input.credential === undefined ||\n !samePasswordCredentialSnapshot(state.snapshot, input.credential))\n )\n return yield* prepare(\"rejected\" as const, project);\n let proofValidity = sql`1 = 1`;\n\n if (redemption !== undefined) {\n if (proofs === undefined) return yield* unavailable();\n\n const captured = {\n ...redemption,\n input: yield* Schema.decodeEffect(ProofRedemptionInput)(redemption.input),\n };\n\n if (!passwordProofRedemptionMatches({ ...input, redemption: captured }))\n return yield* prepare(\"rejected\" as const, project);\n // Inherit the physical owner; application owners retain the exact consumed\n // proof absence check after their callback.\n const proof = yield* makeNativeProofStore(tables, proofs, batch !== undefined);\n const redeemed = yield* proof.redeemLocked(captured.input);\n\n const proofReceipt = captured.prepare(\n redeemed.decision,\n yield* CurrentCommitJournal,\n (value) => value,\n );\n\n yield* registerSqlCommitReceipt(proofReceipt);\n if (redeemed.decision === \"rejected\") return yield* prepare(\"rejected\" as const, project);\n proofValidity = redeemed.validUntil;\n }\n const mode = \"interactive\";\n\n const credentialId =\n input.credential?.credentialId ??\n (yield* allocatePasswordValue(\n mode,\n mapping.allocateCredentialId,\n mapping.allocateCredentialIdSync,\n ));\n\n const credentialRevision = yield* allocatePasswordValue(\n mode,\n mapping.allocateRevision,\n mapping.allocateRevisionSync,\n );\n\n const verifierVersion = yield* allocatePasswordValue(\n mode,\n mapping.allocateRevision,\n mapping.allocateRevisionSync,\n );\n\n const nextSecurityRevision = yield* allocatePasswordNextSecurityRevision(\n mapping,\n mode,\n input.expectedRevision.securityRevision,\n );\n\n ensure(\n nextSecurityRevision !== input.expectedRevision.securityRevision &&\n credentialRevision !== input.credential?.credentialRevision &&\n verifierVersion !== input.credential?.verifierVersion,\n );\n\n const freshUntil = (requirement: AuthenticationRequirement) => {\n const deadlines = [\n ...new Set(\n input.authorization.evidence.proofs.map(\n (proof) => DateTime.toEpochMillis(proof.verifiedAt) + requirement.maximumAgeMillis,\n ),\n ),\n ]\n .filter((time) => time > state.now)\n .sort((a, b) => a - b);\n\n return deadlines.find(\n (time) => !passwordEvidenceSatisfiedAt(input.authorization.evidence, requirement, time),\n );\n };\n\n if (batch !== undefined)\n yield* guardSqlitePolicy({\n name: \"password-subject-policy\",\n table: rawSubject.name,\n owner: subjectKey(rawSubject, s.id, nativeId),\n values: state.policyValues,\n });\n\n const requestedDeadline = freshUntil(input.authorization.requirement),\n currentDeadline = freshUntil(requirement);\n\n ensure(requestedDeadline !== undefined && currentDeadline !== undefined);\n const deadline = Math.min(requestedDeadline, currentDeadline);\n const freshness = sql`${now} >= ${state.now} and ${now} < ${deadline} and ${proofValidity}`;\n\n const stage = Effect.fnUntraced(function* (statement: Fragment) {\n if (batch === undefined) ensure((yield* executeSqlChange(sql, statement)) === 1);\n else {\n yield* appendSqlBatchStatement(sql`${statement}`);\n yield* appendSqlBatchStatement(sqlBatchAssertion(sql, sql`changes() = 1`));\n }\n });\n\n if (batch !== undefined) {\n if (\n s.d1ActiveStatusValue === undefined ||\n (a.status !== undefined && a.d1ActiveStatusValue === undefined)\n )\n return yield* unavailable();\n\n const factors = state.revision.credentials.map(\n (factor) =>\n sql`exists(select 1 from ${rawAuthority.name} where ${subjectKey(rawAuthority, a.subjectId, nativeId)} and ${exact(rawAuthority, a.credentialId, factor.credentialId)} and ${exact(rawAuthority, a.revision, factor.revision)} ${a.status === undefined ? sql`` : sql`and ${rawAuthority.column(a.status)} = ${rawAuthority.value(a.status, a.d1ActiveStatusValue)}`})`,\n );\n\n const active =\n a.status === undefined\n ? sql`1 = 1`\n : sql`${rawAuthority.column(a.status)} = ${rawAuthority.value(a.status, a.d1ActiveStatusValue)}`;\n\n const condition = sql.and([\n sql`exists(select 1 from ${rawSubject.name} where ${subjectKey(rawSubject, s.id, nativeId)} and ${exact(rawSubject, s.securityRevision, input.expectedRevision.securityRevision)} and ${rawSubject.column(s.status)} = ${rawSubject.value(s.status, s.d1ActiveStatusValue)})`,\n sql`(select count(*) from ${rawAuthority.name} where ${subjectKey(rawAuthority, a.subjectId, nativeId)} and ${active}) = ${factors.length}`,\n ...factors,\n freshness,\n ]);\n\n yield* appendSqlBatchStatement(sqlBatchAssertion(sql, condition));\n if (input.credential !== undefined) {\n if (i.d1CurrentCondition === undefined) return yield* unavailable();\n yield* appendSqlBatchStatement(\n sqlBatchAssertion(\n sql,\n sql`exists(select 1 from ${tables(i.table).name} where ${exact(tables(i.table), i.namespace, input.credential.identifier.namespace)} and ${exact(tables(i.table), i.value, input.credential.identifier.value)} and ${subjectKey(tables(i.table), i.subjectId, nativeId)} and ${tables.expression(i.d1CurrentCondition({ identifier: input.credential.identifier, nativeSubjectId: nativeId }))})`,\n ),\n );\n }\n }\n const revisions = { credentialId, credentialRevision, verifierVersion };\n\n if (input.credential === undefined) {\n yield* stage(\n sql`${rawPassword.insert(c.encodeInsert({ moduleId: input.moduleId, subjectId: nativeId, replacement: input.replacement, ...revisions }))}`,\n );\n yield* stage(\n sql`${rawAuthority.insert(a.encodeInsert({ subjectId: nativeId, credentialId, revision: credentialRevision }))}`,\n );\n } else {\n const old = input.credential;\n\n yield* stage(\n sql`${rawPassword.update(c.encodeReplacement({ replacement: input.replacement, credentialRevision, verifierVersion }))} where ${subjectKey(rawPassword, c.subjectId, nativeId)} and ${exact(rawPassword, c.moduleId, input.moduleId)} and ${exact(rawPassword, c.credentialId, old.credentialId)} and ${exact(rawPassword, c.credentialRevision, old.credentialRevision)} and ${exact(rawPassword, c.verifierVersion, old.verifierVersion)} and ${exact(rawPassword, c.verifier, Redacted.value(old.verifier))} and ${exact(rawPassword, c.normalization, old.normalization)} and ${freshness}`,\n );\n yield* stage(\n sql`${rawAuthority.update(a.encodeRevision(credentialRevision))} where ${subjectKey(rawAuthority, a.subjectId, nativeId)} and ${exact(rawAuthority, a.credentialId, old.credentialId)} and ${exact(rawAuthority, a.revision, old.credentialRevision)}`,\n );\n }\n\n const expectedFactors = state.revision.credentials\n .filter((factor) => factor.credentialId !== credentialId)\n .concat({ credentialId, revision: credentialRevision });\n\n const finalPassword = sql`exists(select 1 from ${rawPassword.name} where ${subjectKey(rawPassword, c.subjectId, nativeId)} and ${exact(rawPassword, c.moduleId, input.moduleId)} and ${exact(rawPassword, c.credentialId, credentialId)} and ${exact(rawPassword, c.credentialRevision, credentialRevision)} and ${exact(rawPassword, c.verifierVersion, verifierVersion)} and ${exact(rawPassword, c.verifier, Redacted.value(input.replacement.verifier))} and ${exact(rawPassword, c.normalization, input.replacement.normalization)})`;\n\n const canGuardResult =\n (a.status === undefined || a.d1ActiveStatusValue !== undefined) &&\n (input.credential === undefined || i.d1CurrentCondition !== undefined);\n\n let resultingState: Fragment | undefined;\n\n if (canGuardResult) {\n const active =\n a.status === undefined\n ? sql`1 = 1`\n : sql`${rawAuthority.column(a.status)} = ${rawAuthority.value(a.status, a.d1ActiveStatusValue)}`;\n\n const conditions: Array<Fragment> = [\n finalPassword,\n freshness,\n sql`(select count(*) from ${rawAuthority.name} where ${subjectKey(rawAuthority, a.subjectId, nativeId)} and ${active}) = ${expectedFactors.length}`,\n ...expectedFactors.map(\n (factor) =>\n sql`exists(select 1 from ${rawAuthority.name} where ${subjectKey(rawAuthority, a.subjectId, nativeId)} and ${exact(rawAuthority, a.credentialId, factor.credentialId)} and ${exact(rawAuthority, a.revision, factor.revision)} and ${active})`,\n ),\n ];\n\n if (input.credential !== undefined) {\n const expected = input.credential;\n const identifierTable = tables(i.table);\n\n ensure(i.d1CurrentCondition !== undefined);\n conditions.push(\n sql`exists(select 1 from ${identifierTable.name} where ${exact(identifierTable, i.namespace, expected.identifier.namespace)} and ${exact(identifierTable, i.value, expected.identifier.value)} and ${subjectKey(identifierTable, i.subjectId, nativeId)} and ${tables.expression(i.d1CurrentCondition({ identifier: expected.identifier, nativeSubjectId: nativeId }))})`,\n sql`exists(select 1 from ${identifierTable.name} where ${exact(identifierTable, i.namespace, expected.identifier.namespace)} and ${exact(identifierTable, i.value, expected.identifier.value)} and ${subjectKey(identifierTable, i.subjectId, nativeId)} and ${exact(identifierTable, i.bindingRevision, expected.identifierBindingRevision)} and ${expected.identifierVerifiedAtMillis === undefined ? sql`${identifierTable.column(i.verifiedAt)} is null` : sql`${identifierTable.column(i.verifiedAt)} = ${identifierTable.value(i.verifiedAt, mapping.clock.encodeInstant(expected.identifierVerifiedAtMillis))}`})`,\n );\n }\n resultingState = sql.and(conditions);\n }\n yield* stage(\n sql`${rawSubject.update({ [s.securityRevision]: nextSecurityRevision })} where ${subjectKey(rawSubject, s.id, nativeId)} and ${exact(rawSubject, s.securityRevision, input.expectedRevision.securityRevision)} and ${rawSubject.column(s.status)} = ${rawSubject.value(s.status, locked[s.status])} and ${freshness} and ${resultingState ?? sql`1 = 1`}`,\n );\n if (batch !== undefined) {\n ensure(resultingState !== undefined);\n yield* registerSqlBatchPostcondition({\n name: \"password-replacement-authority\",\n statement: sqlBatchAssertion(\n sql,\n sql.and([\n resultingState,\n sql`exists(select 1 from ${rawSubject.name} where ${subjectKey(rawSubject, s.id, nativeId)} and ${exact(rawSubject, s.securityRevision, nextSecurityRevision)} and ${rawSubject.column(s.status)} = ${rawSubject.value(s.status, s.d1ActiveStatusValue)})`,\n ]),\n ),\n });\n } else if (Option.isSome(parent) || resultingState === undefined)\n yield* registerSqlPostcondition({\n name: \"password-replacement-authority\",\n check: Effect.gen(function* () {\n const final = yield* read(\n input.moduleId,\n input.expectedRevision.subjectId,\n input.credential?.identifier,\n );\n\n ensure(\n final !== undefined &&\n s.isActiveStatus(final.subjectRow[s.status]) &&\n final.revision.securityRevision === nextSecurityRevision &&\n final.revision.credentials.length === expectedFactors.length &&\n expectedFactors.every((factor) =>\n final.revision.credentials.some(\n (entry) =>\n entry.credentialId === factor.credentialId &&\n entry.revision === factor.revision,\n ),\n ) &&\n final.now >= state.now &&\n final.now < deadline,\n );\n const password = final.passwordRow;\n\n ensure(\n password !== undefined &&\n password[c.credentialId] === credentialId &&\n password[c.credentialRevision] === credentialRevision &&\n password[c.verifierVersion] === verifierVersion &&\n password[c.verifier] === Redacted.value(input.replacement.verifier) &&\n password[c.normalization] === input.replacement.normalization,\n );\n if (input.credential !== undefined)\n ensure(\n final.snapshot !== undefined &&\n final.snapshot.identifierBindingRevision ===\n input.credential.identifierBindingRevision &&\n final.snapshot.identifierVerifiedAtMillis ===\n input.credential.identifierVerifiedAtMillis,\n );\n }).pipe(\n Effect.mapError((cause) =>\n PersistenceMappingError.make({ operation: \"decode\", cause }),\n ),\n ),\n });\n\n return yield* prepare(\"changed\" as const, project);\n }),\n );\n\n const credentials = yield* makePasswordCredentials(tables, mapping, {\n mode: \"interactive\",\n locking: false,\n coordinated: Option.isSome(parent),\n standaloneGuard: requireStandalone(unavailable, sql.transactionService),\n });\n\n const passwordPersistence: P.PasswordPersistence[\"Service\"] = {\n ...credentials,\n readForSubject: (input) =>\n executor.read(\n Effect.map(read(input.moduleId, input.subjectId), (state) =>\n state === undefined || !s.isActiveStatus(state.subjectRow[s.status])\n ? Option.none()\n : Option.fromUndefinedOr(state.snapshot),\n ),\n ),\n recoveryTarget: (input) =>\n executor.read(\n Effect.gen(function* () {\n const rows =\n yield* sql`select ${identifier.fields(\"password_recovery_\")} from ${identifier.name} where ${exact(identifier, i.namespace, input.identifier.namespace)} and ${exact(identifier, i.value, input.identifier.value)} limit 2`;\n\n if (rows.length === 0) return Option.none();\n ensure(rows.length === 1);\n const row = identifier.decode(rows[0]!, \"password_recovery_\");\n\n if (!i.isCurrent(row)) return Option.none();\n const subjectId = yield* mapping.subjectId.toSubject(row[i.subjectId]);\n const state = yield* read(input.moduleId, subjectId, input.identifier);\n\n return state === undefined ||\n !s.isActiveStatus(state.subjectRow[s.status]) ||\n state.snapshot?.identifierVerifiedAtMillis === undefined\n ? Option.none()\n : Option.some(state.snapshot);\n }),\n ),\n addIfAbsent: (input, project) => mutation(input, \"add-password\", project),\n replaceIfCurrent: (input, project) => mutation(input, \"change-password\", project),\n resetWithProof: (input, project) =>\n mutation(input, \"reset-password\", project, input.redemption),\n };\n\n return { passwordPersistence };\n});\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import "./mapping-error.mjs";
2
2
  import { AnyPasswordRegistrationMapping } from "./models/password-model.mjs";
3
3
  import { NativeSqlTables } from "./native-sql-table.mjs";
4
- import { PasswordRegistrationAuthority } from "./registration-contract.mjs";
5
4
  import "./sql-commit.mjs";
5
+ import { PasswordRegistrationAuthority } from "./registration-contract.mjs";
6
6
  import { Cause, Crypto, Effect, Schema } from "effect";
7
7
  import { Fragment } from "effect/sql/Statement";
8
8
  import { CurrentCommitJournal, LifecycleHooks } from "@yielded/auth/Hooks";
@@ -1,6 +1,7 @@
1
1
  import { StorageTable } from "./storage-tables.mjs";
2
2
  import { PersistenceApi, PersistenceConfigurationError } from "./configuration.mjs";
3
3
  import { NativeSqlTables } from "./native-sql-table.mjs";
4
+ import { SqlBatchCommit } from "./sql-commit.mjs";
4
5
  import { Effect } from "effect";
5
6
  import { SqlClient } from "effect/sql";
6
7
  //#region src/internal/persistence.d.ts
@@ -9,6 +10,8 @@ export interface Backend<T extends object, R, Database extends object = object>
9
10
  readonly describe: (table: T) => StorageTable;
10
11
  readonly acquire: Effect.Effect<Database, PersistenceConfigurationError, R | SqlClient.SqlClient>;
11
12
  readonly nativeTables: (database: Database) => NativeSqlTables;
13
+ /** Fixed atomic batches replace interactive transactions on backends such as D1. */
14
+ readonly batch?: (database: Database) => NonNullable<SqlBatchCommit["Service"]>;
12
15
  }
13
16
  export declare const createPersistence: <T extends object, R, Database extends object = object>(backend: Backend<T, R, Database>) => PersistenceApi<T, R>;
14
17
  //#endregion
@@ -122,11 +122,9 @@ const createPersistence = (backend) => {
122
122
  decodeInstantSync
123
123
  });
124
124
  };
125
- const services = Layer.effectContext(Effect.gen(function* () {
125
+ const services = Layer.effectContext(Effect.flatMap(backend.acquire, (database) => Effect.gen(function* () {
126
126
  const storage = yield* ConfigKey;
127
- const client = yield* SqlClient.SqlClient;
128
- const database = yield* backend.acquire;
129
- const dialect = client.onDialectOrElse({
127
+ const dialect = (yield* SqlClient.SqlClient).onDialectOrElse({
130
128
  pg: () => "pg",
131
129
  sqlite: () => "sqlite",
132
130
  orElse: () => void 0
@@ -152,8 +150,8 @@ const createPersistence = (backend) => {
152
150
  required: [[storage.subjects.id]]
153
151
  });
154
152
  yield* validateStorageBatch(dialect, validations);
155
- const mappings = yield* makeMappings(storage);
156
153
  const nativeTables = backend.nativeTables(database);
154
+ const mappings = yield* makeMappings(storage, nativeTables);
157
155
  const sessionMapping = mappings.sessions(auth.claims, auth.sessions.moduleId);
158
156
  const pendingMapping = mappings.pending(auth.claims, auth.sessions.moduleId);
159
157
  const sessionServices = yield* makeNativeStatefulSessionServices(nativeTables, sessionMapping);
@@ -200,7 +198,7 @@ const createPersistence = (backend) => {
200
198
  context = Context.merge(context, yield* services);
201
199
  }
202
200
  return context;
203
- }).pipe(Effect.provideService(SqlBatchCommit, void 0), withStorageValidation, Effect.mapError((error) => Schema.is(PersistenceConfigurationError)(error) ? error : configError("Cannot acquire SQL persistence")))).pipe(Layer.provide(hooksLayer));
201
+ }).pipe(Effect.provideService(SqlBatchCommit, backend.batch?.(database)))).pipe(withStorageValidation, Effect.mapError((error) => Schema.is(PersistenceConfigurationError)(error) ? error : configError("Cannot acquire SQL persistence")))).pipe(Layer.provide(hooksLayer));
204
202
  return {
205
203
  Config,
206
204
  Provisioning: ProvisioningKey,