@yielded/auth-persistence 0.1.0-beta.25 → 0.1.0-beta.27
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 +6 -8
- package/dist/Adapter.d.mts +47 -33
- package/dist/Adapter.mjs +36 -23
- package/dist/OAuthPersistence.d.mts +35 -51
- package/dist/OAuthPersistence.mjs +60 -68
- package/dist/OAuthPersistence.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/internal/browser-login.d.mts +1 -1
- package/dist/internal/browser-login.mjs +29 -9
- package/dist/internal/browser-login.mjs.map +1 -1
- package/dist/internal/configuration.d.mts +13 -8
- package/dist/internal/configuration.mjs.map +1 -1
- package/dist/internal/crypto.d.mts +1 -0
- package/dist/internal/crypto.mjs +1 -1
- package/dist/internal/d1-planning.mjs +8 -0
- package/dist/internal/d1-planning.mjs.map +1 -0
- package/dist/internal/email-native-state.mjs +135 -0
- package/dist/internal/email-native-state.mjs.map +1 -0
- package/dist/internal/email-native.d.mts +17 -0
- package/dist/internal/email-native.mjs +245 -0
- package/dist/internal/email-native.mjs.map +1 -0
- package/dist/internal/email-policy.mjs +92 -0
- package/dist/internal/email-policy.mjs.map +1 -0
- package/dist/internal/email-registration-native.d.mts +38 -0
- package/dist/internal/email-registration-native.mjs +171 -0
- package/dist/internal/email-registration-native.mjs.map +1 -0
- package/dist/internal/models/email-model.d.mts +40 -104
- package/dist/internal/models/email-model.mjs +3 -5
- package/dist/internal/models/email-model.mjs.map +1 -1
- package/dist/internal/models/oauth-connected-model.d.mts +44 -213
- package/dist/internal/models/oauth-connected-model.mjs +6 -14
- package/dist/internal/models/oauth-connected-model.mjs.map +1 -1
- package/dist/internal/models/oauth-model.d.mts +95 -244
- package/dist/internal/models/oauth-model.mjs +28 -22
- package/dist/internal/models/oauth-model.mjs.map +1 -1
- package/dist/internal/models/passkey-model.d.mts +11 -147
- package/dist/internal/models/passkey-model.mjs +5 -24
- package/dist/internal/models/passkey-model.mjs.map +1 -1
- package/dist/internal/models/passkey-registration-ceremony-model.d.mts +5 -39
- package/dist/internal/models/passkey-write-model.d.mts +17 -75
- package/dist/internal/models/passkey-write-model.mjs +1 -7
- package/dist/internal/models/passkey-write-model.mjs.map +1 -1
- package/dist/internal/models/password-model.d.mts +14 -81
- package/dist/internal/models/password-model.mjs +1 -4
- package/dist/internal/models/password-model.mjs.map +1 -1
- package/dist/internal/models/phone-model.d.mts +86 -0
- package/dist/internal/models/phone-model.mjs +10 -0
- package/dist/internal/models/phone-model.mjs.map +1 -0
- package/dist/internal/models/proof-model.d.mts +43 -272
- package/dist/internal/models/proof-model.mjs +2 -10
- package/dist/internal/models/proof-model.mjs.map +1 -1
- package/dist/internal/models/session-model.d.mts +74 -93
- package/dist/internal/models/session-model.mjs +3 -11
- package/dist/internal/models/session-model.mjs.map +1 -1
- package/dist/internal/models/step-up-model.d.mts +12 -50
- package/dist/internal/models/step-up-model.mjs +2 -4
- package/dist/internal/models/step-up-model.mjs.map +1 -1
- package/dist/internal/models/totp-model.d.mts +76 -0
- package/dist/internal/models/totp-model.mjs +10 -0
- package/dist/internal/models/totp-model.mjs.map +1 -0
- package/dist/internal/native-sql-table.d.mts +21 -4
- package/dist/internal/native-sql-table.mjs +9 -5
- package/dist/internal/native-sql-table.mjs.map +1 -1
- package/dist/internal/oauth/native-accounts.d.mts +17 -0
- package/dist/internal/oauth/native-accounts.mjs +290 -0
- package/dist/internal/oauth/native-accounts.mjs.map +1 -0
- package/dist/internal/oauth/native-connected-state.d.mts +11 -0
- package/dist/internal/oauth/native-connected-state.mjs +146 -0
- package/dist/internal/oauth/native-connected-state.mjs.map +1 -0
- package/dist/internal/oauth/native-connected.d.mts +15 -0
- package/dist/internal/oauth/native-connected.mjs +462 -0
- package/dist/internal/oauth/native-connected.mjs.map +1 -0
- package/dist/internal/oauth/native-flow.mjs +138 -0
- package/dist/internal/oauth/native-flow.mjs.map +1 -0
- package/dist/internal/oauth/native-layers.d.mts +24 -0
- package/dist/internal/oauth/native-layers.mjs +13 -0
- package/dist/internal/oauth/native-layers.mjs.map +1 -0
- package/dist/internal/oauth/native-mutation.mjs +122 -0
- package/dist/internal/oauth/native-mutation.mjs.map +1 -0
- package/dist/internal/oauth/native-registration.d.mts +24 -0
- package/dist/internal/oauth/native-registration.mjs +328 -0
- package/dist/internal/oauth/native-registration.mjs.map +1 -0
- package/dist/internal/oauth/native-revocations.d.mts +17 -0
- package/dist/internal/oauth/native-revocations.mjs +106 -0
- package/dist/internal/oauth/native-revocations.mjs.map +1 -0
- package/dist/internal/oauth/native-sign-in.d.mts +17 -0
- package/dist/internal/oauth/native-sign-in.mjs +50 -0
- package/dist/internal/oauth/native-sign-in.mjs.map +1 -0
- package/dist/internal/oauth/native-state.d.mts +10 -0
- package/dist/internal/oauth/native-state.mjs +214 -0
- package/dist/internal/oauth/native-state.mjs.map +1 -0
- package/dist/internal/oauth/state.d.mts +10 -0
- package/dist/internal/oauth/state.mjs +3 -27
- package/dist/internal/oauth/state.mjs.map +1 -1
- package/dist/internal/passkey-actions.mjs +55 -0
- package/dist/internal/passkey-actions.mjs.map +1 -0
- package/dist/internal/passkey-inputs.mjs +73 -0
- package/dist/internal/passkey-inputs.mjs.map +1 -0
- package/dist/internal/passkey-managed.mjs +224 -0
- package/dist/internal/passkey-managed.mjs.map +1 -0
- package/dist/internal/passkey-native-ceremony.d.mts +35 -0
- package/dist/internal/passkey-native-ceremony.mjs +38 -0
- package/dist/internal/passkey-native-ceremony.mjs.map +1 -0
- package/dist/internal/passkey-native-flow.mjs +91 -0
- package/dist/internal/passkey-native-flow.mjs.map +1 -0
- package/dist/internal/passkey-native-registration.d.mts +10 -0
- package/dist/internal/passkey-native-registration.mjs +114 -0
- package/dist/internal/passkey-native-registration.mjs.map +1 -0
- package/dist/internal/passkey-native-state.d.mts +15 -0
- package/dist/internal/passkey-native-state.mjs +186 -0
- package/dist/internal/passkey-native-state.mjs.map +1 -0
- package/dist/internal/passkey-native-write.d.mts +82 -0
- package/dist/internal/passkey-native-write.mjs +330 -0
- package/dist/internal/passkey-native-write.mjs.map +1 -0
- package/dist/internal/passkey-native.d.mts +835 -0
- package/dist/internal/passkey-native.mjs +175 -0
- package/dist/internal/passkey-native.mjs.map +1 -0
- package/dist/internal/passkey-policy.mjs +115 -0
- package/dist/internal/passkey-policy.mjs.map +1 -0
- package/dist/internal/password-credentials.mjs +38 -9
- package/dist/internal/password-credentials.mjs.map +1 -1
- package/dist/internal/password-native.d.mts +14 -0
- package/dist/internal/password-native.mjs +292 -0
- package/dist/internal/password-native.mjs.map +1 -0
- package/dist/internal/password-policy.mjs +93 -0
- package/dist/internal/password-policy.mjs.map +1 -0
- package/dist/internal/password-registration-native.d.mts +22 -0
- package/dist/internal/password-registration-native.mjs +142 -0
- package/dist/internal/password-registration-native.mjs.map +1 -0
- package/dist/internal/persistence.d.mts +6 -19
- package/dist/internal/persistence.mjs +199 -166
- package/dist/internal/persistence.mjs.map +1 -1
- package/dist/internal/phone-composed.mjs +79 -0
- package/dist/internal/phone-composed.mjs.map +1 -0
- package/dist/internal/phone-native.d.mts +15 -0
- package/dist/internal/phone-native.mjs +354 -0
- package/dist/internal/phone-native.mjs.map +1 -0
- package/dist/internal/proof-native.d.mts +15 -0
- package/dist/internal/proof-native.mjs +289 -0
- package/dist/internal/proof-native.mjs.map +1 -0
- package/dist/internal/registration.mjs +50 -60
- package/dist/internal/registration.mjs.map +1 -1
- package/dist/internal/session-native-authority.d.mts +15 -0
- package/dist/internal/session-native-authority.mjs +91 -0
- package/dist/internal/session-native-authority.mjs.map +1 -0
- package/dist/internal/session-native-cleanup.d.mts +14 -0
- package/dist/internal/session-native-cleanup.mjs +48 -0
- package/dist/internal/session-native-cleanup.mjs.map +1 -0
- package/dist/internal/session-native-login.d.mts +15 -0
- package/dist/internal/session-native-login.mjs +87 -0
- package/dist/internal/session-native-login.mjs.map +1 -0
- package/dist/internal/session-native-pending-read.mjs +42 -0
- package/dist/internal/session-native-pending-read.mjs.map +1 -0
- package/dist/internal/session-native-pending.mjs +134 -0
- package/dist/internal/session-native-pending.mjs.map +1 -0
- package/dist/internal/session-native-record.mjs +79 -0
- package/dist/internal/session-native-record.mjs.map +1 -0
- package/dist/internal/session-native-state.mjs +130 -0
- package/dist/internal/session-native-state.mjs.map +1 -0
- package/dist/internal/session-native-stateful.d.mts +16 -0
- package/dist/internal/session-native-stateful.mjs +225 -0
- package/dist/internal/session-native-stateful.mjs.map +1 -0
- package/dist/internal/session-native-step-up.d.mts +15 -0
- package/dist/internal/session-native-step-up.mjs +212 -0
- package/dist/internal/session-native-step-up.mjs.map +1 -0
- package/dist/internal/session-native-validity.d.mts +15 -0
- package/dist/internal/session-native-validity.mjs +97 -0
- package/dist/internal/session-native-validity.mjs.map +1 -0
- package/dist/internal/session-policy.mjs +29 -0
- package/dist/internal/session-policy.mjs.map +1 -0
- package/dist/internal/sql-authority.d.mts +16 -0
- package/dist/internal/sql-authority.mjs +32 -0
- package/dist/internal/sql-authority.mjs.map +1 -0
- package/dist/internal/sql-change.mjs +21 -0
- package/dist/internal/sql-change.mjs.map +1 -0
- package/dist/internal/sql-cleanup.mjs +35 -0
- package/dist/internal/sql-cleanup.mjs.map +1 -0
- package/dist/internal/sql-commit.d.mts +72 -0
- package/dist/internal/sql-commit.mjs +176 -0
- package/dist/internal/sql-commit.mjs.map +1 -0
- package/dist/internal/sql-expression.d.mts +17 -0
- package/dist/internal/sql-expression.mjs +49 -0
- package/dist/internal/sql-expression.mjs.map +1 -0
- package/dist/internal/sql-oauth-connected-model.d.mts +7 -23
- package/dist/internal/sql-oauth-model.d.mts +27 -52
- package/dist/internal/sql-oauth-model.mjs +3 -4
- package/dist/internal/sql-oauth-model.mjs.map +1 -1
- package/dist/internal/sql-persistence.mjs +5 -9
- package/dist/internal/sql-persistence.mjs.map +1 -1
- package/dist/internal/sql-storage-validation.mjs +1 -2
- package/dist/internal/sql-storage-validation.mjs.map +1 -1
- package/dist/internal/sql-table.d.mts +3 -16
- package/dist/internal/sql-table.mjs +21 -42
- package/dist/internal/sql-table.mjs.map +1 -1
- package/dist/internal/standalone.mjs +2 -3
- package/dist/internal/standalone.mjs.map +1 -1
- package/dist/internal/step-up-state.mjs +5 -8
- package/dist/internal/step-up-state.mjs.map +1 -1
- package/dist/internal/storage-clock.mjs +44 -0
- package/dist/internal/storage-clock.mjs.map +1 -0
- package/dist/internal/storage-mapping.d.mts +11 -8
- package/dist/internal/storage-mapping.mjs +88 -302
- package/dist/internal/storage-mapping.mjs.map +1 -1
- package/dist/internal/storage-plans.mjs +15 -73
- package/dist/internal/storage-plans.mjs.map +1 -1
- package/dist/internal/storage-tables.d.mts +37 -520
- package/dist/internal/storage-tables.mjs +31 -211
- package/dist/internal/storage-tables.mjs.map +1 -1
- package/dist/internal/storage-validation.d.mts +1 -6
- package/dist/internal/storage-validation.mjs +1 -42
- package/dist/internal/storage-validation.mjs.map +1 -1
- package/dist/internal/table-model.d.mts +21 -0
- package/dist/internal/totp-native.d.mts +15 -0
- package/dist/internal/totp-native.mjs +401 -0
- package/dist/internal/totp-native.mjs.map +1 -0
- package/package.json +1 -1
- package/src/Adapter.ts +143 -199
- package/src/OAuthPersistence.ts +128 -271
- package/src/index.ts +1 -1
- package/src/internal/browser-login.ts +54 -24
- package/src/internal/configuration.ts +16 -31
- package/src/internal/d1-planning.ts +7 -0
- package/src/internal/email-native-state.ts +247 -0
- package/src/internal/email-native.ts +514 -0
- package/src/internal/email-policy.ts +235 -0
- package/src/internal/email-registration-native.ts +386 -0
- package/src/internal/models/email-model.ts +76 -214
- package/src/internal/models/oauth-connected-model.ts +50 -288
- package/src/internal/models/oauth-model.ts +147 -368
- package/src/internal/models/passkey-model.ts +11 -208
- package/src/internal/models/passkey-registration-ceremony-model.ts +6 -60
- package/src/internal/models/passkey-write-model.ts +14 -95
- package/src/internal/models/password-model.ts +26 -147
- package/src/internal/models/phone-model.ts +110 -0
- package/src/internal/models/proof-model.ts +48 -404
- package/src/internal/models/session-model.ts +102 -200
- package/src/internal/models/step-up-model.ts +17 -96
- package/src/internal/models/totp-model.ts +82 -0
- package/src/internal/native-sql-table.ts +32 -11
- package/src/internal/oauth/native-accounts.ts +576 -0
- package/src/internal/oauth/native-connected-state.ts +288 -0
- package/src/internal/oauth/native-connected.ts +888 -0
- package/src/internal/oauth/native-flow.ts +253 -0
- package/src/internal/oauth/native-layers.ts +83 -0
- package/src/internal/oauth/native-mutation.ts +222 -0
- package/src/internal/oauth/native-registration.ts +545 -0
- package/src/internal/oauth/native-revocations.ts +190 -0
- package/src/internal/oauth/native-sign-in.ts +111 -0
- package/src/internal/oauth/native-state.ts +346 -0
- package/src/internal/oauth/state.ts +2 -70
- package/src/internal/passkey-actions.ts +70 -0
- package/src/internal/passkey-inputs.ts +56 -0
- package/src/internal/passkey-managed.ts +360 -0
- package/src/internal/passkey-native-ceremony.ts +66 -0
- package/src/internal/passkey-native-flow.ts +140 -0
- package/src/internal/passkey-native-registration.ts +221 -0
- package/src/internal/passkey-native-state.ts +335 -0
- package/src/internal/passkey-native-write.ts +611 -0
- package/src/internal/passkey-native.ts +372 -0
- package/src/internal/passkey-policy.ts +246 -0
- package/src/internal/password-credentials.ts +52 -10
- package/src/internal/password-native.ts +571 -0
- package/src/internal/password-policy.ts +307 -0
- package/src/internal/password-registration-native.ts +322 -0
- package/src/internal/persistence.ts +336 -290
- package/src/internal/phone-composed.ts +86 -0
- package/src/internal/phone-native.ts +659 -0
- package/src/internal/proof-native.ts +448 -0
- package/src/internal/registration.ts +96 -143
- package/src/internal/session-native-authority.ts +247 -0
- package/src/internal/session-native-cleanup.ts +65 -0
- package/src/internal/session-native-login.ts +205 -0
- package/src/internal/session-native-pending-read.ts +68 -0
- package/src/internal/session-native-pending.ts +223 -0
- package/src/internal/session-native-record.ts +141 -0
- package/src/internal/session-native-state.ts +259 -0
- package/src/internal/session-native-stateful.ts +512 -0
- package/src/internal/session-native-step-up.ts +450 -0
- package/src/internal/session-native-validity.ts +208 -0
- package/src/internal/session-policy.ts +59 -0
- package/src/internal/sql-authority.ts +56 -0
- package/src/internal/sql-change.ts +38 -0
- package/src/internal/sql-cleanup.ts +56 -0
- package/src/internal/sql-commit.ts +435 -0
- package/src/internal/sql-expression.ts +94 -0
- package/src/internal/sql-metadata.ts +100 -0
- package/src/internal/sql-oauth-connected-model.ts +6 -95
- package/src/internal/sql-oauth-model.ts +31 -134
- package/src/internal/sql-persistence.ts +2 -6
- package/src/internal/sql-storage-validation.ts +1 -2
- package/src/internal/sql-table.ts +19 -52
- package/src/internal/standalone.ts +2 -11
- package/src/internal/step-up-state.ts +4 -17
- package/src/internal/storage-clock.ts +58 -0
- package/src/internal/storage-mapping.ts +125 -340
- package/src/internal/storage-plans.ts +14 -80
- package/src/internal/storage-tables.ts +28 -212
- package/src/internal/storage-validation.ts +0 -58
- package/src/internal/table-model.ts +24 -0
- package/src/internal/totp-native.ts +701 -0
- package/dist/internal/PasswordPreparedPostconditions.d.mts +0 -22
- package/dist/internal/PasswordPreparedPostconditions.mjs +0 -12
- package/dist/internal/PasswordPreparedPostconditions.mjs.map +0 -1
- package/dist/internal/authority-snapshot.mjs +0 -53
- package/dist/internal/authority-snapshot.mjs.map +0 -1
- package/dist/internal/email-kernel.d.mts +0 -276
- package/dist/internal/email-kernel.mjs +0 -497
- package/dist/internal/email-kernel.mjs.map +0 -1
- package/dist/internal/models/passkey-registration-ceremony-model.mjs +0 -18
- package/dist/internal/models/passkey-registration-ceremony-model.mjs.map +0 -1
- package/dist/internal/oauth/accounts.d.mts +0 -8
- package/dist/internal/oauth/accounts.mjs +0 -379
- package/dist/internal/oauth/accounts.mjs.map +0 -1
- package/dist/internal/oauth/connected-access.d.mts +0 -9
- package/dist/internal/oauth/connected-access.mjs +0 -229
- package/dist/internal/oauth/connected-access.mjs.map +0 -1
- package/dist/internal/oauth/connected-collection.d.mts +0 -7
- package/dist/internal/oauth/connected-collection.mjs +0 -214
- package/dist/internal/oauth/connected-collection.mjs.map +0 -1
- package/dist/internal/oauth/connected-custody.d.mts +0 -6
- package/dist/internal/oauth/connected-custody.mjs +0 -165
- package/dist/internal/oauth/connected-custody.mjs.map +0 -1
- package/dist/internal/oauth/connected-flow.d.mts +0 -7
- package/dist/internal/oauth/connected-flow.mjs +0 -324
- package/dist/internal/oauth/connected-flow.mjs.map +0 -1
- package/dist/internal/oauth/connected-input.mjs +0 -122
- package/dist/internal/oauth/connected-input.mjs.map +0 -1
- package/dist/internal/oauth/connected-keys.d.mts +0 -2
- package/dist/internal/oauth/connected-keys.mjs +0 -22
- package/dist/internal/oauth/connected-keys.mjs.map +0 -1
- package/dist/internal/oauth/connected-maintenance.d.mts +0 -9
- package/dist/internal/oauth/connected-maintenance.mjs +0 -226
- package/dist/internal/oauth/connected-maintenance.mjs.map +0 -1
- package/dist/internal/oauth/connected-management.d.mts +0 -9
- package/dist/internal/oauth/connected-management.mjs +0 -243
- package/dist/internal/oauth/connected-management.mjs.map +0 -1
- package/dist/internal/oauth/connected-reference.mjs +0 -63
- package/dist/internal/oauth/connected-reference.mjs.map +0 -1
- package/dist/internal/oauth/connected-settlement.d.mts +0 -8
- package/dist/internal/oauth/connected-settlement.mjs +0 -141
- package/dist/internal/oauth/connected-settlement.mjs.map +0 -1
- package/dist/internal/oauth/connected-sign-in.d.mts +0 -10
- package/dist/internal/oauth/connected-sign-in.mjs +0 -281
- package/dist/internal/oauth/connected-sign-in.mjs.map +0 -1
- package/dist/internal/oauth/connected-state.d.mts +0 -14
- package/dist/internal/oauth/connected-state.mjs +0 -469
- package/dist/internal/oauth/connected-state.mjs.map +0 -1
- package/dist/internal/oauth/connected-target.d.mts +0 -21
- package/dist/internal/oauth/connected-target.mjs +0 -117
- package/dist/internal/oauth/connected-target.mjs.map +0 -1
- package/dist/internal/oauth/flow.d.mts +0 -5
- package/dist/internal/oauth/flow.mjs +0 -279
- package/dist/internal/oauth/flow.mjs.map +0 -1
- package/dist/internal/oauth/input.mjs +0 -127
- package/dist/internal/oauth/input.mjs.map +0 -1
- package/dist/internal/oauth/owner.d.mts +0 -10
- package/dist/internal/oauth/owner.mjs +0 -10
- package/dist/internal/oauth/owner.mjs.map +0 -1
- package/dist/internal/oauth/query-compiler.d.mts +0 -7
- package/dist/internal/oauth/query-compiler.mjs +0 -9
- package/dist/internal/oauth/query-compiler.mjs.map +0 -1
- package/dist/internal/oauth/registration.d.mts +0 -7
- package/dist/internal/oauth/registration.mjs +0 -393
- package/dist/internal/oauth/registration.mjs.map +0 -1
- package/dist/internal/oauth/target.d.mts +0 -31
- package/dist/internal/oauth/target.mjs +0 -273
- package/dist/internal/oauth/target.mjs.map +0 -1
- package/dist/internal/oauth-kernel.d.mts +0 -1423
- package/dist/internal/oauth-kernel.mjs +0 -187
- package/dist/internal/oauth-kernel.mjs.map +0 -1
- package/dist/internal/passkey/admission.d.mts +0 -6
- package/dist/internal/passkey/admission.mjs +0 -220
- package/dist/internal/passkey/admission.mjs.map +0 -1
- package/dist/internal/passkey/credentials.d.mts +0 -14
- package/dist/internal/passkey/credentials.mjs +0 -249
- package/dist/internal/passkey/credentials.mjs.map +0 -1
- package/dist/internal/passkey/enrollment.mjs +0 -138
- package/dist/internal/passkey/enrollment.mjs.map +0 -1
- package/dist/internal/passkey/flow.d.mts +0 -21
- package/dist/internal/passkey/flow.mjs +0 -452
- package/dist/internal/passkey/flow.mjs.map +0 -1
- package/dist/internal/passkey/management.mjs +0 -231
- package/dist/internal/passkey/management.mjs.map +0 -1
- package/dist/internal/passkey/registration-ceremony.d.mts +0 -9
- package/dist/internal/passkey/registration-ceremony.mjs +0 -129
- package/dist/internal/passkey/registration-ceremony.mjs.map +0 -1
- package/dist/internal/passkey/registration-custody.d.mts +0 -2
- package/dist/internal/passkey/registration-custody.mjs +0 -52
- package/dist/internal/passkey/registration-custody.mjs.map +0 -1
- package/dist/internal/passkey/registration-write.mjs +0 -211
- package/dist/internal/passkey/registration-write.mjs.map +0 -1
- package/dist/internal/passkey/state.d.mts +0 -10
- package/dist/internal/passkey/state.mjs +0 -234
- package/dist/internal/passkey/state.mjs.map +0 -1
- package/dist/internal/passkey/target.d.mts +0 -20
- package/dist/internal/passkey/target.mjs +0 -200
- package/dist/internal/passkey/target.mjs.map +0 -1
- package/dist/internal/passkey/write-state.d.mts +0 -17
- package/dist/internal/passkey/write-state.mjs +0 -354
- package/dist/internal/passkey/write-state.mjs.map +0 -1
- package/dist/internal/passkey/write-target.mjs +0 -192
- package/dist/internal/passkey/write-target.mjs.map +0 -1
- package/dist/internal/passkey-kernel.d.mts +0 -6045
- package/dist/internal/passkey-kernel.mjs +0 -49
- package/dist/internal/passkey-kernel.mjs.map +0 -1
- package/dist/internal/passkeys.d.mts +0 -7
- package/dist/internal/passkeys.mjs +0 -387
- package/dist/internal/passkeys.mjs.map +0 -1
- package/dist/internal/password-credentials.d.mts +0 -11
- package/dist/internal/password-kernel.d.mts +0 -278
- package/dist/internal/password-kernel.mjs +0 -508
- package/dist/internal/password-kernel.mjs.map +0 -1
- package/dist/internal/phone-kernel.d.mts +0 -162
- package/dist/internal/phone-kernel.mjs +0 -437
- package/dist/internal/phone-kernel.mjs.map +0 -1
- package/dist/internal/proof-kernel.d.mts +0 -94
- package/dist/internal/proof-kernel.mjs +0 -624
- package/dist/internal/proof-kernel.mjs.map +0 -1
- package/dist/internal/query-operations.d.mts +0 -68
- package/dist/internal/session-kernel.d.mts +0 -62
- package/dist/internal/session-kernel.mjs +0 -820
- package/dist/internal/session-kernel.mjs.map +0 -1
- package/dist/internal/sql-oauth-connected-model.mjs +0 -7
- package/dist/internal/sql-oauth-connected-model.mjs.map +0 -1
- package/dist/internal/sql-query.d.mts +0 -12
- package/dist/internal/sql-query.mjs +0 -206
- package/dist/internal/sql-query.mjs.map +0 -1
- package/dist/internal/step-up-state.d.mts +0 -49
- package/dist/internal/transaction-execution-kernel.d.mts +0 -37
- package/dist/internal/transaction-execution-kernel.mjs +0 -120
- package/dist/internal/transaction-execution-kernel.mjs.map +0 -1
- package/dist/internal/transaction-kernel.d.mts +0 -81
- package/dist/internal/transaction-kernel.mjs +0 -264
- package/dist/internal/transaction-kernel.mjs.map +0 -1
- package/src/internal/PasswordPreparedPostconditions.ts +0 -30
- package/src/internal/authority-snapshot.ts +0 -91
- package/src/internal/email-kernel.ts +0 -1556
- package/src/internal/oauth/accounts.ts +0 -839
- package/src/internal/oauth/connected-access.ts +0 -388
- package/src/internal/oauth/connected-collection.ts +0 -345
- package/src/internal/oauth/connected-custody.ts +0 -308
- package/src/internal/oauth/connected-flow.ts +0 -562
- package/src/internal/oauth/connected-input.ts +0 -147
- package/src/internal/oauth/connected-keys.ts +0 -31
- package/src/internal/oauth/connected-maintenance.ts +0 -379
- package/src/internal/oauth/connected-management.ts +0 -391
- package/src/internal/oauth/connected-reference.ts +0 -135
- package/src/internal/oauth/connected-settlement.ts +0 -278
- package/src/internal/oauth/connected-sign-in.ts +0 -472
- package/src/internal/oauth/connected-state.ts +0 -924
- package/src/internal/oauth/connected-target.ts +0 -307
- package/src/internal/oauth/flow.ts +0 -505
- package/src/internal/oauth/input.ts +0 -201
- package/src/internal/oauth/owner.ts +0 -22
- package/src/internal/oauth/query-compiler.ts +0 -15
- package/src/internal/oauth/registration.ts +0 -676
- package/src/internal/oauth/target.ts +0 -803
- package/src/internal/oauth-kernel.ts +0 -294
- package/src/internal/passkey/admission.ts +0 -368
- package/src/internal/passkey/credentials.ts +0 -511
- package/src/internal/passkey/enrollment.ts +0 -326
- package/src/internal/passkey/flow.ts +0 -1062
- package/src/internal/passkey/management.ts +0 -426
- package/src/internal/passkey/registration-ceremony.ts +0 -283
- package/src/internal/passkey/registration-custody.ts +0 -91
- package/src/internal/passkey/registration-write.ts +0 -426
- package/src/internal/passkey/state.ts +0 -351
- package/src/internal/passkey/target.ts +0 -598
- package/src/internal/passkey/write-state.ts +0 -692
- package/src/internal/passkey/write-target.ts +0 -450
- package/src/internal/passkey-kernel.ts +0 -112
- package/src/internal/passkeys.ts +0 -652
- package/src/internal/password-kernel.ts +0 -1523
- package/src/internal/phone-kernel.ts +0 -872
- package/src/internal/proof-kernel.ts +0 -1992
- package/src/internal/query-operations.ts +0 -91
- package/src/internal/session-kernel.ts +0 -2406
- package/src/internal/sql-query.ts +0 -304
- package/src/internal/transaction-execution-kernel.ts +0 -335
- package/src/internal/transaction-kernel.ts +0 -603
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { sqlBatchAssertion } from "./d1-planning.mjs";
|
|
2
|
+
import { exactSqlText } from "./sql-change.mjs";
|
|
3
|
+
import { CurrentSqlCommit, SqlBatchCommit, makeSqlCommitExecutor, registerSqlBatchPostcondition, registerSqlCommitReceipt, registerSqlPostcondition } from "./sql-commit.mjs";
|
|
4
|
+
import { passkeyOperationInputs } from "./passkey-inputs.mjs";
|
|
5
|
+
import { passkeyAssertionPurposes, passkeyCredentialKey, passkeyMatchesAccess, validPasskeyCeremony } from "./passkey-policy.mjs";
|
|
6
|
+
import { makePasskeyNativeReadState, makePasskeyNativeState, passkeyNativeInvariant } from "./passkey-native-state.mjs";
|
|
7
|
+
import { Crypto, Effect, Option, Schema } from "effect";
|
|
8
|
+
import { CurrentCommitJournal } from "@yielded/auth/Hooks";
|
|
9
|
+
import * as M from "@yielded/auth/Passkey";
|
|
10
|
+
import { SqlError } from "effect/sql/SqlError";
|
|
11
|
+
//#region src/internal/passkey-native.ts
|
|
12
|
+
const unavailable = () => M.PasskeyUnavailable.make({});
|
|
13
|
+
const preparePasskeyNative = (value, prepare) => Effect.gen(function* () {
|
|
14
|
+
const receipt = prepare(value, yield* CurrentCommitJournal);
|
|
15
|
+
passkeyNativeInvariant(receipt?._tag === "PreparedCommit" && Effect.isEffect(receipt.read));
|
|
16
|
+
yield* registerSqlCommitReceipt(receipt);
|
|
17
|
+
return receipt;
|
|
18
|
+
});
|
|
19
|
+
const services = Effect.fnUntraced(function* (tables, mapping, batch) {
|
|
20
|
+
const boundOwner = yield* Effect.serviceOption(CurrentSqlCommit);
|
|
21
|
+
const state = yield* makePasskeyNativeState(tables, mapping);
|
|
22
|
+
const executor = yield* makeSqlCommitExecutor(unavailable);
|
|
23
|
+
const crypto = yield* Crypto.Crypto;
|
|
24
|
+
const { sql, ceremony: flow, credential } = state;
|
|
25
|
+
const read = mapping.read;
|
|
26
|
+
const provide = (effect) => Effect.provideService(effect, Crypto.Crypto, crypto);
|
|
27
|
+
const run = (effect, mode = "transaction") => batch === void 0 ? executor.run(provide(effect), mode) : executor.batch(provide(effect)).pipe(Effect.provideService(SqlBatchCommit, batch));
|
|
28
|
+
const advisory = (effect) => executor.read(provide(effect));
|
|
29
|
+
const issue = (original, prepare) => run(Effect.gen(function* () {
|
|
30
|
+
const ceremony = M.snapshotPasskeySync(passkeyOperationInputs.issue, original).ceremony;
|
|
31
|
+
if (!flow.validModule(ceremony.moduleId) || !validPasskeyCeremony(ceremony) || ceremony.purpose === "registration") return yield* preparePasskeyNative({ _tag: "Rejected" }, prepare);
|
|
32
|
+
const statement = flow.insert(ceremony);
|
|
33
|
+
let changed;
|
|
34
|
+
if (batch !== void 0) {
|
|
35
|
+
yield* flow.stage(statement, 1);
|
|
36
|
+
changed = 1;
|
|
37
|
+
} else changed = yield* flow.change(statement).pipe(Effect.catchIf((error) => Schema.is(SqlError)(error) && error.reason._tag === "UniqueViolation", () => Effect.succeed(0)));
|
|
38
|
+
return yield* preparePasskeyNative(changed === 1 ? {
|
|
39
|
+
_tag: "Issued",
|
|
40
|
+
ceremony
|
|
41
|
+
} : { _tag: "Rejected" }, prepare);
|
|
42
|
+
}), "statement");
|
|
43
|
+
const persistence = {
|
|
44
|
+
issue,
|
|
45
|
+
context: (original) => advisory(Effect.suspend(() => flow.context(M.snapshotPasskeySync(M.PasskeyAccess, original)))),
|
|
46
|
+
consume: (original, prepare) => run(Effect.gen(function* () {
|
|
47
|
+
const input = M.snapshotPasskeySync(passkeyOperationInputs.consume, original);
|
|
48
|
+
const captured = input.credential;
|
|
49
|
+
const revision = captured.revision.credentials.find((entry) => entry.credentialId === captured.credentialId);
|
|
50
|
+
const assertion = input.assertion;
|
|
51
|
+
if (!flow.validModule(input.access.moduleId) || !passkeyMatchesAccess(input.ceremony, input.access) || !passkeyAssertionPurposes.some((purpose) => purpose === input.ceremony.purpose) || !validPasskeyCeremony(input.ceremony) || revision === void 0 || !captured.active || captured.rpId !== input.ceremony.profile.rpId || assertion.protocolCredentialId !== captured.protocolCredentialId || assertion.backupEligible !== captured.backupEligible || assertion.userHandle !== void 0 && assertion.userHandle !== captured.userHandle) return yield* preparePasskeyNative("Rejected", prepare);
|
|
52
|
+
const consumed = flow.consume(input.access, input.ceremony);
|
|
53
|
+
if (batch === void 0) {
|
|
54
|
+
if ((yield* flow.change(consumed)) !== 1) return yield* preparePasskeyNative("Rejected", prepare);
|
|
55
|
+
} else yield* flow.stage(consumed, 1);
|
|
56
|
+
const key = yield* passkeyCredentialKey(captured.rpId, captured.protocolCredentialId);
|
|
57
|
+
const exact = (column, value) => exactSqlText(sql, credential.column(column), credential.value(column, value));
|
|
58
|
+
const counter = credential.column(read.credential.counter);
|
|
59
|
+
const next = credential.value(read.credential.counter, assertion.counter);
|
|
60
|
+
const merged = captured.backupEligible ? sql`case when ${counter} > ${next} then ${counter} else ${next} end` : next;
|
|
61
|
+
const identity = [
|
|
62
|
+
exact(read.credential.credentialId, captured.credentialId),
|
|
63
|
+
exact(read.credential.credentialKey, key),
|
|
64
|
+
exact(read.credential.credentialRevision, revision.revision),
|
|
65
|
+
sql`${credential.column(read.credential.backupEligible)} = ${credential.value(read.credential.backupEligible, mapping.telemetry.encodeBackupEligible(captured.backupEligible))}`,
|
|
66
|
+
state.active("credential")
|
|
67
|
+
];
|
|
68
|
+
const statement = sql`${credential.update({
|
|
69
|
+
[read.credential.counter]: merged,
|
|
70
|
+
[read.credential.backupState]: mapping.telemetry.encodeBackupState(assertion.backupState),
|
|
71
|
+
[mapping.telemetry.lastUsedAt]: state.storedNow
|
|
72
|
+
})} where ${sql.and([...identity, captured.backupEligible ? sql`true` : sql`((${counter} = 0 and ${next} = 0) or ${counter} < ${next})`])}`;
|
|
73
|
+
let changed;
|
|
74
|
+
if (batch === void 0) {
|
|
75
|
+
changed = yield* flow.change(statement);
|
|
76
|
+
if (changed === 0 && sql.onDialectOrElse({
|
|
77
|
+
mysql: () => true,
|
|
78
|
+
orElse: () => false
|
|
79
|
+
}) && (captured.backupEligible || assertion.counter === 0)) {
|
|
80
|
+
if ((yield* sql`select 1 as matched from ${credential.name} where ${sql.and(identity)} and ${captured.backupEligible ? sql`${counter} >= ${next}` : sql`${counter} = 0`} and ${credential.column(read.credential.backupState)} = ${credential.value(read.credential.backupState, mapping.telemetry.encodeBackupState(assertion.backupState))}`).length === 1) changed = 1;
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
yield* flow.stage(statement, 1);
|
|
84
|
+
changed = 1;
|
|
85
|
+
}
|
|
86
|
+
if (Option.isSome(boundOwner)) {
|
|
87
|
+
const acceptedCounter = captured.backupEligible ? sql`${counter} >= ${credential.value(read.credential.counter, Math.max(captured.counter, assertion.counter))}` : sql`${counter} = ${next}`;
|
|
88
|
+
const condition = sql.and([flow.absent(input.access), changed === 1 ? sql`exists(select 1 from ${credential.name} where ${sql.and(identity)} and ${acceptedCounter}
|
|
89
|
+
and ${credential.column(read.credential.backupState)} = ${credential.value(read.credential.backupState, mapping.telemetry.encodeBackupState(assertion.backupState))})` : sql`true`]);
|
|
90
|
+
if (batch === void 0) yield* registerSqlPostcondition({
|
|
91
|
+
name: "passkey-consume-preserved",
|
|
92
|
+
check: Effect.gen(function* () {
|
|
93
|
+
const rows = yield* sql`select 1 where ${condition}`;
|
|
94
|
+
passkeyNativeInvariant(rows.length === 1);
|
|
95
|
+
})
|
|
96
|
+
});
|
|
97
|
+
else yield* registerSqlBatchPostcondition({
|
|
98
|
+
name: "passkey-consume-preserved",
|
|
99
|
+
statement: sqlBatchAssertion(sql, condition)
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return yield* preparePasskeyNative(changed === 1 ? "Verified" : "Rejected", prepare);
|
|
103
|
+
})),
|
|
104
|
+
cleanup: (original, prepare) => run(Effect.gen(function* () {
|
|
105
|
+
const input = M.snapshotPasskeySync(passkeyOperationInputs.cleanup, original);
|
|
106
|
+
passkeyNativeInvariant(flow.validModule(input.moduleId));
|
|
107
|
+
return yield* preparePasskeyNative(yield* flow.cleanup(input.moduleId, input.limit, batch !== void 0), prepare);
|
|
108
|
+
}), "statement")
|
|
109
|
+
};
|
|
110
|
+
const credentials = makePasskeyNativeCredentialService(state, read, advisory);
|
|
111
|
+
return {
|
|
112
|
+
batch: batch !== void 0,
|
|
113
|
+
state,
|
|
114
|
+
executor,
|
|
115
|
+
run,
|
|
116
|
+
advisory,
|
|
117
|
+
passkeyPersistence: persistence,
|
|
118
|
+
passkeyCredentials: credentials
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
const makeNativePasskeyServices = (tables, mapping) => services(tables, mapping);
|
|
122
|
+
const makeBatchPasskeyServices = (tables, mapping) => Effect.flatMap(SqlBatchCommit, (batch) => services(tables, mapping, batch));
|
|
123
|
+
const makePasskeyNativeCredentialService = (state, read, advisory) => {
|
|
124
|
+
const { sql, joinedSubject: subject, joinedFactor: factor, joinedCredential: credential } = state;
|
|
125
|
+
return {
|
|
126
|
+
lookup: (original) => advisory(Effect.gen(function* () {
|
|
127
|
+
const input = M.snapshotPasskeySync(passkeyOperationInputs.lookup, original);
|
|
128
|
+
return yield* state.lookup(input.rpId, input.protocolCredentialId);
|
|
129
|
+
})),
|
|
130
|
+
listForSubject: (original) => advisory(Effect.gen(function* () {
|
|
131
|
+
const input = M.snapshotPasskeySync(passkeyOperationInputs.listForSubject, original);
|
|
132
|
+
const nativeId = state.native(input.subjectId);
|
|
133
|
+
const rows = yield* sql`select ${subject.fields("s_")}, ${factor.fields("f_")}, ${credential.fields("c_")}
|
|
134
|
+
from ${state.selected("subject", "passkey_subject")}
|
|
135
|
+
left join ${state.selected("authority", "passkey_factor")} on ${factor.column(read.authority.subjectId)} = ${factor.value(read.authority.subjectId, nativeId)}
|
|
136
|
+
left join ${state.selected("credential", "passkey_credential")} on ${credential.column(read.credential.subjectId)} = ${credential.value(read.credential.subjectId, nativeId)} and ${credential.column(read.credential.rpId)} = ${credential.value(read.credential.rpId, input.rpId)}
|
|
137
|
+
where ${subject.column(read.subject.id)} = ${subject.value(read.subject.id, nativeId)} limit 4097`;
|
|
138
|
+
if (rows.length === 0 || rows.length > 4096) return void 0;
|
|
139
|
+
const subjectRow = subject.decode(rows[0], "s_");
|
|
140
|
+
passkeyNativeInvariant(rows.every((selected) => {
|
|
141
|
+
const other = subject.decode(selected, "s_");
|
|
142
|
+
return state.sameId(read.subject.decodeId(other), nativeId) && other[read.subject.securityRevision] === subjectRow[read.subject.securityRevision];
|
|
143
|
+
}));
|
|
144
|
+
const revision = state.revision(subjectRow, rows.map((row) => factor.decode(row, "f_")));
|
|
145
|
+
passkeyNativeInvariant(revision.subjectId === input.subjectId);
|
|
146
|
+
const values = /* @__PURE__ */ new Map();
|
|
147
|
+
for (const selected of rows) {
|
|
148
|
+
const row = credential.decode(selected, "c_");
|
|
149
|
+
if (row[read.credential.credentialId] === null) continue;
|
|
150
|
+
const decoded = yield* state.decodeCredential(row, revision, subjectRow);
|
|
151
|
+
if (decoded !== void 0) values.set(decoded.credentialId, decoded);
|
|
152
|
+
}
|
|
153
|
+
const userHandle = values.values().next().value?.userHandle;
|
|
154
|
+
return M.snapshotPasskeySync(M.PasskeyEnrollmentSnapshot, {
|
|
155
|
+
revision,
|
|
156
|
+
...userHandle === void 0 ? {} : { userHandle },
|
|
157
|
+
credentials: [...values.values()].map((value) => ({
|
|
158
|
+
type: "public-key",
|
|
159
|
+
id: value.protocolCredentialId
|
|
160
|
+
}))
|
|
161
|
+
});
|
|
162
|
+
}))
|
|
163
|
+
};
|
|
164
|
+
};
|
|
165
|
+
const makeNativePasskeyCredentialServices = Effect.fnUntraced(function* (tables, mapping) {
|
|
166
|
+
const state = yield* makePasskeyNativeReadState(tables, mapping);
|
|
167
|
+
const executor = yield* makeSqlCommitExecutor(unavailable);
|
|
168
|
+
const crypto = yield* Crypto.Crypto;
|
|
169
|
+
const advisory = (effect) => executor.read(Effect.provideService(effect, Crypto.Crypto, crypto));
|
|
170
|
+
return { passkeyCredentials: makePasskeyNativeCredentialService(state, mapping, advisory) };
|
|
171
|
+
});
|
|
172
|
+
//#endregion
|
|
173
|
+
export { makeBatchPasskeyServices, makeNativePasskeyCredentialServices, makeNativePasskeyServices, preparePasskeyNative };
|
|
174
|
+
|
|
175
|
+
//# sourceMappingURL=passkey-native.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passkey-native.mjs","names":[],"sources":["../../src/internal/passkey-native.ts"],"sourcesContent":["import { CurrentCommitJournal } from \"@yielded/auth/Hooks\";\nimport * as M from \"@yielded/auth/Passkey\";\nimport { Crypto, Effect, Option, Schema } from \"effect\";\nimport { SqlError } from \"effect/sql/SqlError\";\n\nimport { sqlBatchAssertion } from \"./d1-planning\";\nimport type { NativeSqlTables } from \"./native-sql-table\";\nimport { passkeyOperationInputs } from \"./passkey-inputs\";\nimport {\n makePasskeyNativeReadState,\n makePasskeyNativeState,\n passkeyNativeInvariant,\n type PasskeyNativeMapping,\n type PasskeyNativeRead,\n type PasskeyNativeReadState,\n} from \"./passkey-native-state\";\nimport {\n passkeyAssertionPurposes,\n passkeyCredentialKey,\n passkeyMatchesAccess,\n validPasskeyCeremony,\n} from \"./passkey-policy\";\nimport { exactSqlText } from \"./sql-change\";\nimport {\n CurrentSqlCommit,\n makeSqlCommitExecutor,\n registerSqlCommitReceipt,\n registerSqlPostcondition,\n registerSqlBatchPostcondition,\n SqlBatchCommit,\n} from \"./sql-commit\";\n\nconst unavailable = () => M.PasskeyUnavailable.make({});\n\nexport const preparePasskeyNative = <Value, A>(\n value: Value,\n prepare: M.PreparePasskeyCommit<Value, A>,\n) =>\n Effect.gen(function* () {\n const journal = yield* CurrentCommitJournal;\n\n const receipt = prepare(value, journal);\n\n passkeyNativeInvariant(receipt?._tag === \"PreparedCommit\" && Effect.isEffect(receipt.read));\n yield* registerSqlCommitReceipt(receipt);\n\n return receipt;\n });\n\nconst services = Effect.fnUntraced(function* (\n tables: NativeSqlTables,\n mapping: PasskeyNativeMapping,\n batch?: SqlBatchCommit[\"Service\"],\n) {\n const boundOwner = yield* Effect.serviceOption(CurrentSqlCommit);\n const state = yield* makePasskeyNativeState(tables, mapping);\n const executor = yield* makeSqlCommitExecutor(unavailable);\n const crypto = yield* Crypto.Crypto;\n const { sql, ceremony: flow, credential } = state;\n const read = mapping.read;\n\n const provide = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n Effect.provideService(effect, Crypto.Crypto, crypto);\n\n const run = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n mode: \"transaction\" | \"statement\" = \"transaction\",\n ) =>\n batch === undefined\n ? executor.run(provide(effect), mode)\n : executor.batch(provide(effect)).pipe(Effect.provideService(SqlBatchCommit, batch));\n\n const advisory = <A, E, R>(effect: Effect.Effect<A, E, R>) => executor.read(provide(effect));\n\n const issue: M.PasskeyPersistence[\"Service\"][\"issue\"] = (original, prepare) =>\n run(\n Effect.gen(function* () {\n const input = M.snapshotPasskeySync(passkeyOperationInputs.issue, original);\n const ceremony = input.ceremony;\n\n if (\n !flow.validModule(ceremony.moduleId) ||\n !validPasskeyCeremony(ceremony) ||\n ceremony.purpose === \"registration\"\n )\n return yield* preparePasskeyNative({ _tag: \"Rejected\" }, prepare);\n const statement = flow.insert(ceremony);\n let changed: number;\n\n if (batch !== undefined) {\n yield* flow.stage(statement, 1);\n changed = 1;\n } else {\n changed = yield* flow.change(statement).pipe(\n Effect.catchIf(\n (error) => Schema.is(SqlError)(error) && error.reason._tag === \"UniqueViolation\",\n () => Effect.succeed(0),\n ),\n );\n }\n\n return yield* preparePasskeyNative(\n changed === 1 ? { _tag: \"Issued\", ceremony } : { _tag: \"Rejected\" },\n prepare,\n );\n }),\n \"statement\",\n );\n\n const persistence: M.PasskeyPersistence[\"Service\"] = {\n issue,\n context: (original) =>\n advisory(\n Effect.suspend(() => flow.context(M.snapshotPasskeySync(M.PasskeyAccess, original))),\n ),\n consume: (original, prepare) =>\n run(\n Effect.gen(function* () {\n const input = M.snapshotPasskeySync(passkeyOperationInputs.consume, original);\n const captured = input.credential;\n\n const revision = captured.revision.credentials.find(\n (entry) => entry.credentialId === captured.credentialId,\n );\n\n const assertion = input.assertion;\n\n if (\n !flow.validModule(input.access.moduleId) ||\n !passkeyMatchesAccess(input.ceremony, input.access) ||\n !passkeyAssertionPurposes.some((purpose) => purpose === input.ceremony.purpose) ||\n !validPasskeyCeremony(input.ceremony) ||\n revision === undefined ||\n !captured.active ||\n captured.rpId !== input.ceremony.profile.rpId ||\n assertion.protocolCredentialId !== captured.protocolCredentialId ||\n assertion.backupEligible !== captured.backupEligible ||\n (assertion.userHandle !== undefined && assertion.userHandle !== captured.userHandle)\n )\n return yield* preparePasskeyNative(\"Rejected\", prepare);\n const consumed = flow.consume(input.access, input.ceremony);\n\n if (batch === undefined) {\n if ((yield* flow.change(consumed)) !== 1)\n return yield* preparePasskeyNative(\"Rejected\", prepare);\n } else yield* flow.stage(consumed, 1);\n const key = yield* passkeyCredentialKey(captured.rpId, captured.protocolCredentialId);\n\n const exact = (column: string, value: unknown) =>\n exactSqlText(sql, credential.column(column), credential.value(column, value));\n\n const counter = credential.column(read.credential.counter);\n const next = credential.value(read.credential.counter, assertion.counter);\n\n const merged = captured.backupEligible\n ? sql`case when ${counter} > ${next} then ${counter} else ${next} end`\n : next;\n\n const identity = [\n exact(read.credential.credentialId, captured.credentialId),\n exact(read.credential.credentialKey, key),\n exact(read.credential.credentialRevision, revision.revision),\n sql`${credential.column(read.credential.backupEligible)} = ${credential.value(read.credential.backupEligible, mapping.telemetry.encodeBackupEligible(captured.backupEligible))}`,\n state.active(\"credential\"),\n ];\n\n const statement = sql`${credential.update({\n [read.credential.counter]: merged,\n [read.credential.backupState]: mapping.telemetry.encodeBackupState(\n assertion.backupState,\n ),\n [mapping.telemetry.lastUsedAt]: state.storedNow,\n })} where ${sql.and([\n ...identity,\n captured.backupEligible\n ? sql`true`\n : sql`((${counter} = 0 and ${next} = 0) or ${counter} < ${next})`,\n ])}`;\n\n let changed: number;\n\n if (batch === undefined) {\n changed = yield* flow.change(statement);\n if (\n changed === 0 &&\n sql.onDialectOrElse({ mysql: () => true, orElse: () => false }) &&\n (captured.backupEligible || assertion.counter === 0)\n ) {\n // mysql2 can disable FOUND_ROWS. The UPDATE still holds the row lock;\n // prove the unchanged telemetry matched this exact semantic key.\n const matched =\n yield* sql`select 1 as matched from ${credential.name} where ${sql.and(identity)} and ${captured.backupEligible ? sql`${counter} >= ${next}` : sql`${counter} = 0`} and ${credential.column(read.credential.backupState)} = ${credential.value(read.credential.backupState, mapping.telemetry.encodeBackupState(assertion.backupState))}`;\n\n if (matched.length === 1) changed = 1;\n }\n } else {\n yield* flow.stage(statement, 1);\n changed = 1;\n }\n\n if (Option.isSome(boundOwner)) {\n // Protect the accepted result from later bound application SQL. BE\n // retains the observed accepted floor; it does not compare an entire\n // telemetry snapshot or reject valid out-of-order assertions.\n const acceptedCounter = captured.backupEligible\n ? sql`${counter} >= ${credential.value(read.credential.counter, Math.max(captured.counter, assertion.counter))}`\n : sql`${counter} = ${next}`;\n\n const condition = sql.and([\n flow.absent(input.access),\n changed === 1\n ? sql`exists(select 1 from ${credential.name} where ${sql.and(identity)} and ${acceptedCounter}\n and ${credential.column(read.credential.backupState)} = ${credential.value(read.credential.backupState, mapping.telemetry.encodeBackupState(assertion.backupState))})`\n : sql`true`,\n ]);\n\n if (batch === undefined) {\n yield* registerSqlPostcondition({\n name: \"passkey-consume-preserved\",\n check: Effect.gen(function* () {\n const rows = yield* sql`select 1 where ${condition}`;\n\n passkeyNativeInvariant(rows.length === 1);\n }),\n });\n } else {\n yield* registerSqlBatchPostcondition({\n name: \"passkey-consume-preserved\",\n statement: sqlBatchAssertion(sql, condition),\n });\n }\n }\n\n return yield* preparePasskeyNative(changed === 1 ? \"Verified\" : \"Rejected\", prepare);\n }),\n ),\n cleanup: (original, prepare) =>\n run(\n Effect.gen(function* () {\n const input = M.snapshotPasskeySync(passkeyOperationInputs.cleanup, original);\n\n passkeyNativeInvariant(flow.validModule(input.moduleId));\n\n return yield* preparePasskeyNative(\n yield* flow.cleanup(input.moduleId, input.limit, batch !== undefined),\n prepare,\n );\n }),\n \"statement\",\n ),\n };\n\n const credentials = makePasskeyNativeCredentialService(state, read, advisory);\n\n return {\n batch: batch !== undefined,\n state,\n executor,\n run,\n advisory,\n passkeyPersistence: persistence,\n passkeyCredentials: credentials,\n };\n});\n\nexport const makeNativePasskeyServices = (tables: NativeSqlTables, mapping: PasskeyNativeMapping) =>\n services(tables, mapping);\n\nexport const makeBatchPasskeyServices = (tables: NativeSqlTables, mapping: PasskeyNativeMapping) =>\n Effect.flatMap(SqlBatchCommit, (batch) => services(tables, mapping, batch));\n\nexport type NativePasskeyServices = Effect.Success<ReturnType<typeof makeNativePasskeyServices>>;\n\nconst makePasskeyNativeCredentialService = (\n state: PasskeyNativeReadState,\n read: PasskeyNativeRead,\n advisory: <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n ) => Effect.Effect<\n A,\n M.PasskeyUnavailable,\n Exclude<\n Exclude<Exclude<R, Crypto.Crypto>, import(\"effect/sql/SqlClient\").SqlClient>,\n import(\"@yielded/auth/Hooks\").LifecycleHooks\n >\n >,\n) => {\n const { sql, joinedSubject: subject, joinedFactor: factor, joinedCredential: credential } = state;\n\n const credentials: M.PasskeyCredentials[\"Service\"] = {\n lookup: (original) =>\n advisory(\n Effect.gen(function* () {\n const input = M.snapshotPasskeySync(passkeyOperationInputs.lookup, original);\n\n return yield* state.lookup(input.rpId, input.protocolCredentialId);\n }),\n ),\n listForSubject: (original) =>\n advisory(\n Effect.gen(function* () {\n const input = M.snapshotPasskeySync(passkeyOperationInputs.listForSubject, original);\n\n const nativeId = state.native(input.subjectId);\n\n const rows =\n yield* sql`select ${subject.fields(\"s_\")}, ${factor.fields(\"f_\")}, ${credential.fields(\"c_\")}\n from ${state.selected(\"subject\", \"passkey_subject\")}\n left join ${state.selected(\"authority\", \"passkey_factor\")} on ${factor.column(read.authority.subjectId)} = ${factor.value(read.authority.subjectId, nativeId)}\n left join ${state.selected(\"credential\", \"passkey_credential\")} on ${credential.column(read.credential.subjectId)} = ${credential.value(read.credential.subjectId, nativeId)} and ${credential.column(read.credential.rpId)} = ${credential.value(read.credential.rpId, input.rpId)}\n where ${subject.column(read.subject.id)} = ${subject.value(read.subject.id, nativeId)} limit 4097`;\n\n if (rows.length === 0 || rows.length > 4096) return undefined;\n const subjectRow = subject.decode(rows[0]!, \"s_\");\n\n passkeyNativeInvariant(\n rows.every((selected) => {\n const other = subject.decode(selected, \"s_\");\n\n return (\n state.sameId(read.subject.decodeId(other), nativeId) &&\n other[read.subject.securityRevision] === subjectRow[read.subject.securityRevision]\n );\n }),\n );\n\n const revision = state.revision(\n subjectRow,\n rows.map((row) => factor.decode(row, \"f_\")),\n );\n\n passkeyNativeInvariant(revision.subjectId === input.subjectId);\n const values = new Map<string, M.PasskeyCredential>();\n\n for (const selected of rows) {\n const row = credential.decode(selected, \"c_\");\n\n if (row[read.credential.credentialId] === null) continue;\n const decoded = yield* state.decodeCredential(row, revision, subjectRow);\n\n if (decoded !== undefined) values.set(decoded.credentialId, decoded);\n }\n const userHandle = values.values().next().value?.userHandle;\n\n return M.snapshotPasskeySync(M.PasskeyEnrollmentSnapshot, {\n revision,\n ...(userHandle === undefined ? {} : { userHandle }),\n credentials: [...values.values()].map((value) => ({\n type: \"public-key\" as const,\n id: value.protocolCredentialId,\n })),\n });\n }),\n ),\n };\n\n return credentials;\n};\n\nexport const makeNativePasskeyCredentialServices = Effect.fnUntraced(function* (\n tables: NativeSqlTables,\n mapping: PasskeyNativeRead,\n) {\n const state = yield* makePasskeyNativeReadState(tables, mapping);\n const executor = yield* makeSqlCommitExecutor(unavailable);\n const crypto = yield* Crypto.Crypto;\n\n const advisory = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n executor.read(Effect.provideService(effect, Crypto.Crypto, crypto));\n\n return { passkeyCredentials: makePasskeyNativeCredentialService(state, mapping, advisory) };\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Crypto, DateTime, Effect, Schema } from "effect";
|
|
2
|
+
import { PasskeyCredential, PasskeyUnavailable, snapshotPasskeySync } from "@yielded/auth/Passkey";
|
|
3
|
+
//#region src/internal/passkey-policy.ts
|
|
4
|
+
const invariant = (value) => {
|
|
5
|
+
if (!value) throw PasskeyUnavailable.make({});
|
|
6
|
+
};
|
|
7
|
+
const encoder = new TextEncoder();
|
|
8
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
9
|
+
/** RP tuples have no collation-dependent string identity. */
|
|
10
|
+
const passkeyKey = Effect.fnUntraced(function* (kind, fields) {
|
|
11
|
+
const values = ["effect-auth/passkey/" + kind + "/v1", ...fields].map((field) => {
|
|
12
|
+
const bytes = encoder.encode(field);
|
|
13
|
+
invariant(decoder.decode(bytes) === field);
|
|
14
|
+
return bytes;
|
|
15
|
+
});
|
|
16
|
+
const packed = new Uint8Array(values.reduce((size, bytes) => size + 4 + bytes.length, 0));
|
|
17
|
+
const view = new DataView(packed.buffer);
|
|
18
|
+
let offset = 0;
|
|
19
|
+
for (const bytes of values) {
|
|
20
|
+
view.setUint32(offset, bytes.length, false);
|
|
21
|
+
packed.set(bytes, offset + 4);
|
|
22
|
+
offset += 4 + bytes.length;
|
|
23
|
+
}
|
|
24
|
+
const hashed = yield* (yield* Crypto.Crypto).digest("SHA-256", packed);
|
|
25
|
+
return "v1:" + Array.from(hashed, (value) => value.toString(16).padStart(2, "0")).join("");
|
|
26
|
+
});
|
|
27
|
+
const passkeyCredentialKey = (rpId, id) => passkeyKey("credential", [rpId, id]);
|
|
28
|
+
/** Private passkeyStorage is decoded Type data, never a consumer wire transform. */
|
|
29
|
+
const passkeyStorage = (schema, maximumBytes) => {
|
|
30
|
+
const codec = Schema.fromJsonString(Schema.toCodecJson(Schema.toType(schema)));
|
|
31
|
+
const encode = (value) => {
|
|
32
|
+
const text = "v1:" + Schema.encodeSync(codec)(snapshotPasskeySync(schema, value));
|
|
33
|
+
invariant(encoder.encode(text).length <= maximumBytes);
|
|
34
|
+
return text;
|
|
35
|
+
};
|
|
36
|
+
return {
|
|
37
|
+
encode,
|
|
38
|
+
decode: (text) => {
|
|
39
|
+
invariant(typeof text === "string" && text.startsWith("v1:"));
|
|
40
|
+
invariant(encoder.encode(text).length <= maximumBytes);
|
|
41
|
+
const value = snapshotPasskeySync(schema, Schema.decodeSync(codec)(text.slice(3)));
|
|
42
|
+
invariant(encode(value) === text);
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
const passkeyCredentialStorage = passkeyStorage(PasskeyCredential, 524288);
|
|
48
|
+
const samePasskeyCredential = (left, right) => {
|
|
49
|
+
const semantic = (value) => ({
|
|
50
|
+
...value,
|
|
51
|
+
counter: 0,
|
|
52
|
+
backupState: false,
|
|
53
|
+
revision: {
|
|
54
|
+
...value.revision,
|
|
55
|
+
credentials: []
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
return passkeyCredentialStorage.encode(semantic(left)) === passkeyCredentialStorage.encode(semantic(right));
|
|
59
|
+
};
|
|
60
|
+
const samePasskeyRevision = (left, right) => {
|
|
61
|
+
const pairs = new Map(left.credentials.map((item) => [item.credentialId, item.revision]));
|
|
62
|
+
return left.subjectId === right.subjectId && left.securityRevision === right.securityRevision && pairs.size === left.credentials.length && new Set(right.credentials.map((item) => item.credentialId)).size === right.credentials.length && pairs.size === right.credentials.length && right.credentials.every((item) => pairs.get(item.credentialId) === item.revision);
|
|
63
|
+
};
|
|
64
|
+
const passkeyAssertionPurposes = [
|
|
65
|
+
"sign-in",
|
|
66
|
+
"pending",
|
|
67
|
+
"step-up",
|
|
68
|
+
"action"
|
|
69
|
+
];
|
|
70
|
+
const contextPurpose = {
|
|
71
|
+
SignIn: "sign-in",
|
|
72
|
+
Pending: "pending",
|
|
73
|
+
StepUp: "step-up",
|
|
74
|
+
Action: "action",
|
|
75
|
+
Enrollment: "enrollment",
|
|
76
|
+
Registration: "registration"
|
|
77
|
+
};
|
|
78
|
+
const validPasskeyCeremony = (ceremony) => ceremony.expiresAtMillis > ceremony.issuedAtMillis && ceremony.expiresAtMillis <= ceremony.requestBindingExpiresAtMillis && contextPurpose[ceremony.context._tag] === ceremony.purpose && new Set(ceremony.allowedCredentials.map((item) => item.id)).size === ceremony.allowedCredentials.length;
|
|
79
|
+
const passkeyMatchesAccess = (ceremony, access) => ceremony.moduleId === access.moduleId && ceremony.purpose === access.purpose && ceremony.flowId === access.flowId && ceremony.requestBindingVerifier === access.requestBindingVerifier && ceremony.requestBindingExpiresAtMillis === access.requestBindingExpiresAtMillis;
|
|
80
|
+
/** Reject stale bindings before evaluating application requirements. */
|
|
81
|
+
const validPasskeyActionEvidence = (facts, authorization) => {
|
|
82
|
+
const { challenge, evidence } = authorization;
|
|
83
|
+
const { expected, revision, nowMillis: now } = facts;
|
|
84
|
+
if (challenge.moduleId !== facts.moduleId || challenge.action !== expected.action || challenge.commandId !== expected.commandId || challenge.flowId !== expected.flowId || challenge.bindingDigest !== expected.bindingDigest || evidence.flowId !== expected.flowId || evidence.bindingDigest !== expected.bindingDigest || !samePasskeyRevision(challenge.revision, expected.revision) || revision.subjectId !== expected.revision.subjectId || revision.securityRevision !== expected.revision.securityRevision || evidence.revision.subjectId !== revision.subjectId || evidence.revision.securityRevision !== revision.securityRevision) return false;
|
|
85
|
+
for (const requested of [expected.revision, evidence.revision]) if (requested.credentials.some((item) => !revision.credentials.some((current) => current.credentialId === item.credentialId && current.revision === item.revision))) return false;
|
|
86
|
+
if (evidence.proofs.some((proof) => DateTime.toEpochMillis(proof.verifiedAt) > now || !evidence.revision.credentials.some((item) => item.credentialId === proof.credentialId))) return false;
|
|
87
|
+
return true;
|
|
88
|
+
};
|
|
89
|
+
/** SQL policy predicates remain native. This authorizes the exact evidence and
|
|
90
|
+
* returns the deadline every backend must retain through its final commit. */
|
|
91
|
+
const assessPasskeyAction = (facts, authorization, policy) => {
|
|
92
|
+
if (!validPasskeyActionEvidence(facts, authorization)) return void 0;
|
|
93
|
+
const { evidence } = authorization;
|
|
94
|
+
const now = facts.nowMillis;
|
|
95
|
+
let expiresBefore = Infinity;
|
|
96
|
+
for (const requirement of [
|
|
97
|
+
authorization.requirement,
|
|
98
|
+
facts.currentRequirement,
|
|
99
|
+
...facts.originalRequirement === void 0 ? [] : [facts.originalRequirement]
|
|
100
|
+
]) {
|
|
101
|
+
const age = Math.min(policy.maximumEvidenceAgeMillis, requirement.maximumAgeMillis);
|
|
102
|
+
const fresh = evidence.proofs.filter((proof) => now - DateTime.toEpochMillis(proof.verifiedAt) < age);
|
|
103
|
+
const factors = new Set(fresh.flatMap((proof) => proof.factors));
|
|
104
|
+
if (!requirement.alternatives.some((alternative) => alternative.factors.every((factor) => factors.has(factor)) && new Set(fresh.map((proof) => proof.credentialId)).size >= alternative.minimumCredentials && fresh.some((proof) => (!alternative.userVerified || proof.userVerified) && (!alternative.phishingResistant || proof.phishingResistant)))) return void 0;
|
|
105
|
+
for (const proof of fresh) expiresBefore = Math.min(expiresBefore, DateTime.toEpochMillis(proof.verifiedAt) + age);
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
notBeforeMillis: now,
|
|
109
|
+
expiresBeforeMillis: expiresBefore
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
//#endregion
|
|
113
|
+
export { assessPasskeyAction, passkeyAssertionPurposes, passkeyCredentialKey, passkeyCredentialStorage, passkeyKey, passkeyMatchesAccess, passkeyStorage, samePasskeyCredential, samePasskeyRevision, validPasskeyActionEvidence, validPasskeyCeremony };
|
|
114
|
+
|
|
115
|
+
//# sourceMappingURL=passkey-policy.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passkey-policy.mjs","names":[],"sources":["../../src/internal/passkey-policy.ts"],"sourcesContent":["import {\n PasskeyUnavailable,\n type PasskeyCeremony,\n PasskeyCredential,\n type PasskeyRevision,\n snapshotPasskeySync,\n type PasskeyAccess,\n type PasskeyActionAuthorization,\n type PasskeyManagementPolicy,\n type PasskeyRequirement,\n} from \"@yielded/auth/Passkey\";\nimport { Crypto, DateTime, Effect, Schema } from \"effect\";\n\nconst invariant: (value: unknown) => asserts value = (value) => {\n if (!value) throw PasskeyUnavailable.make({});\n};\n\nconst encoder = new TextEncoder();\n\nconst decoder = new TextDecoder(\"utf-8\", { fatal: true });\n\n/** RP tuples have no collation-dependent string identity. */\nexport const passkeyKey = Effect.fnUntraced(function* (\n kind: string,\n fields: ReadonlyArray<string>,\n) {\n const values = [\"effect-auth/passkey/\" + kind + \"/v1\", ...fields].map((field) => {\n const bytes = encoder.encode(field);\n\n invariant(decoder.decode(bytes) === field);\n\n return bytes;\n });\n\n const packed = new Uint8Array(values.reduce((size, bytes) => size + 4 + bytes.length, 0));\n const view = new DataView(packed.buffer);\n let offset = 0;\n\n for (const bytes of values) {\n view.setUint32(offset, bytes.length, false);\n packed.set(bytes, offset + 4);\n offset += 4 + bytes.length;\n }\n\n const crypto = yield* Crypto.Crypto;\n const hashed = yield* crypto.digest(\"SHA-256\", packed);\n\n return \"v1:\" + Array.from(hashed, (value) => value.toString(16).padStart(2, \"0\")).join(\"\");\n});\n\nexport const passkeyCredentialKey = (rpId: string, id: string) =>\n passkeyKey(\"credential\", [rpId, id]);\n\n/** Private passkeyStorage is decoded Type data, never a consumer wire transform. */\nexport const passkeyStorage = <S extends Schema.Codec<unknown, unknown, never, never>>(\n schema: S,\n maximumBytes: number,\n) => {\n const codec = Schema.fromJsonString(Schema.toCodecJson(Schema.toType(schema)));\n\n const encode = (value: S[\"Type\"]) => {\n const text = \"v1:\" + Schema.encodeSync(codec)(snapshotPasskeySync(schema, value));\n\n invariant(encoder.encode(text).length <= maximumBytes);\n\n return text;\n };\n\n return {\n encode,\n decode: (text: unknown): S[\"Type\"] => {\n invariant(typeof text === \"string\" && text.startsWith(\"v1:\"));\n invariant(encoder.encode(text).length <= maximumBytes);\n const value = snapshotPasskeySync(schema, Schema.decodeSync(codec)(text.slice(3)));\n\n invariant(encode(value) === text);\n\n return value;\n },\n };\n};\n\n// Legal 32 x 16 x 2048 origins require more than one MiB before JSON escaping.\nexport const passkeyCredentialStorage = passkeyStorage(PasskeyCredential, 512 * 1024);\n\nexport const samePasskeyCredential = (left: PasskeyCredential, right: PasskeyCredential) => {\n const semantic = (value: PasskeyCredential) => ({\n ...value,\n counter: 0,\n backupState: false,\n revision: { ...value.revision, credentials: [] },\n });\n\n return (\n passkeyCredentialStorage.encode(semantic(left)) ===\n passkeyCredentialStorage.encode(semantic(right))\n );\n};\n\nexport const samePasskeyRevision = (\n left: typeof PasskeyRevision.Type,\n right: typeof PasskeyRevision.Type,\n) => {\n const pairs = new Map(left.credentials.map((item) => [item.credentialId, item.revision]));\n\n return (\n left.subjectId === right.subjectId &&\n left.securityRevision === right.securityRevision &&\n pairs.size === left.credentials.length &&\n new Set(right.credentials.map((item) => item.credentialId)).size === right.credentials.length &&\n pairs.size === right.credentials.length &&\n right.credentials.every((item) => pairs.get(item.credentialId) === item.revision)\n );\n};\n\nexport const passkeyAssertionPurposes = [\"sign-in\", \"pending\", \"step-up\", \"action\"] as const;\n\nconst contextPurpose = {\n SignIn: \"sign-in\",\n Pending: \"pending\",\n StepUp: \"step-up\",\n Action: \"action\",\n Enrollment: \"enrollment\",\n Registration: \"registration\",\n} as const;\n\nexport const validPasskeyCeremony = (ceremony: PasskeyCeremony) =>\n ceremony.expiresAtMillis > ceremony.issuedAtMillis &&\n ceremony.expiresAtMillis <= ceremony.requestBindingExpiresAtMillis &&\n contextPurpose[ceremony.context._tag] === ceremony.purpose &&\n new Set(ceremony.allowedCredentials.map((item) => item.id)).size ===\n ceremony.allowedCredentials.length;\n\nexport const passkeyMatchesAccess = (ceremony: PasskeyCeremony, access: PasskeyAccess) =>\n ceremony.moduleId === access.moduleId &&\n ceremony.purpose === access.purpose &&\n ceremony.flowId === access.flowId &&\n ceremony.requestBindingVerifier === access.requestBindingVerifier &&\n ceremony.requestBindingExpiresAtMillis === access.requestBindingExpiresAtMillis;\n\nexport interface PasskeyActionFacts {\n readonly moduleId: string;\n readonly revision: typeof PasskeyRevision.Type;\n readonly nowMillis: number;\n readonly currentRequirement: typeof PasskeyRequirement.Type;\n readonly expected: {\n readonly action: PasskeyActionAuthorization[\"challenge\"][\"action\"];\n readonly commandId: string;\n readonly flowId: string;\n readonly bindingDigest: string;\n readonly revision: typeof PasskeyRevision.Type;\n };\n readonly originalRequirement?: typeof PasskeyRequirement.Type;\n}\n\n/** Reject stale bindings before evaluating application requirements. */\nexport const validPasskeyActionEvidence = (\n facts: Pick<PasskeyActionFacts, \"moduleId\" | \"revision\" | \"expected\" | \"nowMillis\">,\n authorization: PasskeyActionAuthorization,\n) => {\n const { challenge, evidence } = authorization;\n const { expected, revision, nowMillis: now } = facts;\n\n if (\n challenge.moduleId !== facts.moduleId ||\n challenge.action !== expected.action ||\n challenge.commandId !== expected.commandId ||\n challenge.flowId !== expected.flowId ||\n challenge.bindingDigest !== expected.bindingDigest ||\n evidence.flowId !== expected.flowId ||\n evidence.bindingDigest !== expected.bindingDigest ||\n !samePasskeyRevision(challenge.revision, expected.revision) ||\n revision.subjectId !== expected.revision.subjectId ||\n revision.securityRevision !== expected.revision.securityRevision ||\n evidence.revision.subjectId !== revision.subjectId ||\n evidence.revision.securityRevision !== revision.securityRevision\n )\n return false;\n for (const requested of [expected.revision, evidence.revision])\n if (\n requested.credentials.some(\n (item) =>\n !revision.credentials.some(\n (current) =>\n current.credentialId === item.credentialId && current.revision === item.revision,\n ),\n )\n )\n return false;\n if (\n evidence.proofs.some(\n (proof) =>\n DateTime.toEpochMillis(proof.verifiedAt) > now ||\n !evidence.revision.credentials.some((item) => item.credentialId === proof.credentialId),\n )\n )\n return false;\n\n return true;\n};\n\n/** SQL policy predicates remain native. This authorizes the exact evidence and\n * returns the deadline every backend must retain through its final commit. */\nexport const assessPasskeyAction = (\n facts: PasskeyActionFacts,\n authorization: PasskeyActionAuthorization,\n policy: PasskeyManagementPolicy,\n) => {\n if (!validPasskeyActionEvidence(facts, authorization)) return undefined;\n const { evidence } = authorization;\n const now = facts.nowMillis;\n let expiresBefore = Infinity;\n\n for (const requirement of [\n authorization.requirement,\n facts.currentRequirement,\n ...(facts.originalRequirement === undefined ? [] : [facts.originalRequirement]),\n ]) {\n const age = Math.min(policy.maximumEvidenceAgeMillis, requirement.maximumAgeMillis);\n\n const fresh = evidence.proofs.filter(\n (proof) => now - DateTime.toEpochMillis(proof.verifiedAt) < age,\n );\n\n const factors = new Set(fresh.flatMap((proof) => proof.factors));\n\n if (\n !requirement.alternatives.some(\n (alternative) =>\n alternative.factors.every((factor) => factors.has(factor)) &&\n new Set(fresh.map((proof) => proof.credentialId)).size >=\n alternative.minimumCredentials &&\n fresh.some(\n (proof) =>\n (!alternative.userVerified || proof.userVerified) &&\n (!alternative.phishingResistant || proof.phishingResistant),\n ),\n )\n )\n return undefined;\n for (const proof of fresh)\n expiresBefore = Math.min(expiresBefore, DateTime.toEpochMillis(proof.verifiedAt) + age);\n }\n\n return { notBeforeMillis: now, expiresBeforeMillis: expiresBefore };\n};\n"],"mappings":"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"}
|
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import { sqlMapping } from "./native-sql-table.mjs";
|
|
2
|
-
import { NativeDatabase } from "./transaction-kernel.mjs";
|
|
3
2
|
import { Effect, Option, Redacted, Schema } from "effect";
|
|
3
|
+
import { SqlClient } from "effect/sql";
|
|
4
4
|
import { CurrentCommitJournal, hasCommitScope } from "@yielded/auth/Hooks";
|
|
5
|
-
import { reportPersistenceFailure } from "@yielded/auth/Persistence";
|
|
6
5
|
import { EncodedPasswordHash, PasswordUnavailable, snapshotPasswordCredential } from "@yielded/auth/Password";
|
|
6
|
+
import { reportPersistenceFailure } from "@yielded/auth/Persistence";
|
|
7
|
+
import { SecurityRevision } from "@yielded/auth/Sessions";
|
|
7
8
|
//#region src/internal/password-credentials.ts
|
|
8
9
|
const unavailable = () => PasswordUnavailable.make({});
|
|
9
10
|
const failure = (effect) => reportPersistenceFailure(effect, Schema.is(PasswordUnavailable)).pipe(Effect.mapError(unavailable));
|
|
10
11
|
const samePasswordCredentialSnapshot = (a, b) => a.moduleId === b.moduleId && a.revision.subjectId === b.revision.subjectId && a.revision.securityRevision === b.revision.securityRevision && a.revision.credentials.length === b.revision.credentials.length && new Set(a.revision.credentials.map((entry) => entry.credentialId)).size === a.revision.credentials.length && new Set(b.revision.credentials.map((entry) => entry.credentialId)).size === b.revision.credentials.length && a.revision.credentials.every((entry) => b.revision.credentials.some((other) => entry.credentialId === other.credentialId && entry.revision === other.revision)) && a.credentialId === b.credentialId && a.credentialRevision === b.credentialRevision && a.verifierVersion === b.verifierVersion && Redacted.value(a.verifier) === Redacted.value(b.verifier) && a.normalization === b.normalization && a.identifier.namespace === b.identifier.namespace && a.identifier.value === b.identifier.value && a.identifierBindingRevision === b.identifierBindingRevision && a.identifierVerifiedAtMillis === b.identifierVerifiedAtMillis;
|
|
11
12
|
/** Lookup is read-only; rehash is one conditional maintenance write, never authentication. */
|
|
12
13
|
const makePasswordCredentials = Effect.fnUntraced(function* (table, mapping, options) {
|
|
13
|
-
const sql = (yield*
|
|
14
|
+
const sql = (yield* SqlClient.SqlClient).withoutTransforms();
|
|
14
15
|
const parent = yield* Effect.serviceOption(CurrentCommitJournal);
|
|
15
|
-
const [s, i, c] = yield* sqlMapping(() => [
|
|
16
|
+
const [s, i, c, a] = yield* sqlMapping(() => [
|
|
16
17
|
table(mapping.subject.table),
|
|
17
18
|
table(mapping.identifier.table),
|
|
18
|
-
table(mapping.credential.table)
|
|
19
|
+
table(mapping.credential.table),
|
|
20
|
+
table(mapping.authorityCredential.table)
|
|
19
21
|
]).pipe(failure);
|
|
20
22
|
const standalone = Effect.gen(function* () {
|
|
21
23
|
if (options.coordinated) {
|
|
@@ -37,28 +39,55 @@ const makePasswordCredentials = Effect.fnUntraced(function* (table, mapping, opt
|
|
|
37
39
|
const subjectTable = s.as("password_subject");
|
|
38
40
|
const identifierTable = i.as("password_identifier");
|
|
39
41
|
const credentialTable = c.as("password_credential");
|
|
40
|
-
const
|
|
42
|
+
const authorityTable = a.as("password_authority");
|
|
43
|
+
const authority = mapping.authorityCredential;
|
|
44
|
+
const rows = yield* sqlMapping(() => sql`select ${subjectTable.fields("subject_")}, ${identifierTable.fields("identifier_")}, ${credentialTable.fields("credential_")}, ${authorityTable.fields("authority_")}
|
|
41
45
|
from ${subjectTable.name}
|
|
42
46
|
inner join ${identifierTable.name} on ${identifierTable.column(mapping.identifier.namespace)} = ${identifierTable.value(mapping.identifier.namespace, identifier.namespace)}
|
|
43
47
|
and ${identifierTable.column(mapping.identifier.value)} = ${identifierTable.value(mapping.identifier.value, identifier.value)}
|
|
44
48
|
and ${identifierTable.column(mapping.identifier.subjectId)} = ${identifierTable.value(mapping.identifier.subjectId, nativeId)}
|
|
45
49
|
inner join ${credentialTable.name} on ${credentialTable.column(mapping.credential.moduleId)} = ${credentialTable.value(mapping.credential.moduleId, moduleId)}
|
|
46
50
|
and ${credentialTable.column(mapping.credential.subjectId)} = ${credentialTable.value(mapping.credential.subjectId, nativeId)}
|
|
47
|
-
|
|
51
|
+
left join ${authorityTable.name} on ${authorityTable.column(authority.subjectId)} = ${authorityTable.value(authority.subjectId, nativeId)}
|
|
52
|
+
${authority.status === void 0 || authority.d1ActiveStatusValue === void 0 ? sql`` : sql`and ${authorityTable.column(authority.status)} = ${authorityTable.value(authority.status, authority.d1ActiveStatusValue)}`}
|
|
53
|
+
where ${subjectTable.column(mapping.subject.id)} = ${subjectTable.value(mapping.subject.id, nativeId)} order by ${authorityTable.column(authority.credentialId)} limit 4097
|
|
48
54
|
`).pipe(Effect.flatten);
|
|
49
|
-
if (rows.length
|
|
55
|
+
if (rows.length === 0) return void 0;
|
|
56
|
+
if (rows.length > 4096) return yield* unavailable();
|
|
50
57
|
const [subject, identifierRow, credential] = yield* sqlMapping(() => [
|
|
51
58
|
s.decode(rows[0], "subject_"),
|
|
52
59
|
i.decode(rows[0], "identifier_"),
|
|
53
60
|
c.decode(rows[0], "credential_")
|
|
54
61
|
]);
|
|
55
62
|
if (yield* sqlMapping(() => !mapping.subject.isActiveStatus(subject[mapping.subject.status]) || !mapping.identifier.isCurrent(identifierRow) || !mapping.subjectId.equals(nativeId, identifierRow[mapping.identifier.subjectId]) || !mapping.subjectId.equals(nativeId, subject[mapping.subject.id]) || !mapping.subjectId.equals(nativeId, credential[mapping.credential.subjectId]))) return void 0;
|
|
56
|
-
|
|
63
|
+
const captured = yield* sqlMapping(() => mapping.credential.decode({
|
|
57
64
|
moduleId,
|
|
58
65
|
subject,
|
|
59
66
|
identifier: identifierRow,
|
|
60
67
|
credential
|
|
61
68
|
})).pipe(Effect.flatten, Effect.flatMap(snapshotPasswordCredential));
|
|
69
|
+
const factors = /* @__PURE__ */ new Map();
|
|
70
|
+
for (const row of rows) {
|
|
71
|
+
const factor = yield* sqlMapping(() => a.decode(row, "authority_"));
|
|
72
|
+
if (factor[authority.credentialId] === null || factor[authority.credentialId] === void 0) continue;
|
|
73
|
+
if (!mapping.subjectId.equals(nativeId, factor[authority.subjectId])) return yield* unavailable();
|
|
74
|
+
if (authority.status !== void 0 && authority.isActiveStatus?.(factor[authority.status]) !== true) continue;
|
|
75
|
+
const credentialId = yield* Schema.decodeUnknownEffect(Schema.String)(factor[authority.credentialId]);
|
|
76
|
+
const revision = yield* Schema.decodeUnknownEffect(SecurityRevision)(factor[authority.revision]);
|
|
77
|
+
if (factors.has(credentialId)) return yield* unavailable();
|
|
78
|
+
factors.set(credentialId, revision);
|
|
79
|
+
}
|
|
80
|
+
if (factors.size > 64 || factors.get(captured.credentialId) !== captured.credentialRevision) return void 0;
|
|
81
|
+
return yield* snapshotPasswordCredential({
|
|
82
|
+
...captured,
|
|
83
|
+
revision: {
|
|
84
|
+
...captured.revision,
|
|
85
|
+
credentials: [...factors].map(([credentialId, revision]) => ({
|
|
86
|
+
credentialId,
|
|
87
|
+
revision
|
|
88
|
+
}))
|
|
89
|
+
}
|
|
90
|
+
});
|
|
62
91
|
});
|
|
63
92
|
return {
|
|
64
93
|
findCredential: (uncaptured) => Effect.gen(function* () {
|
|
@@ -1 +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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"}
|
|
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 { SecurityRevision } from \"@yielded/auth/Sessions\";\nimport { Effect, Option, Redacted, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql\";\n\nimport type { PersistenceMappingError } from \"./mapping-error\";\nimport type { AnyPasswordPersistenceMapping } from \"./models/password-model\";\nimport { sqlMapping, type SqlTable } from \"./native-sql-table\";\nimport type { PasswordWorkflowOptions } from \"./password-policy\";\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: PasswordWorkflowOptions,\n): Effect.fn.Return<\n Pick<PasswordPersistence[\"Service\"], \"findCredential\" | \"rehashIfCurrent\">,\n PasswordUnavailable,\n SqlClient.SqlClient\n> {\n const sql = (yield* SqlClient.SqlClient).withoutTransforms();\n const parent = yield* Effect.serviceOption(CurrentCommitJournal);\n\n const [s, i, c, a] = yield* sqlMapping(\n () =>\n [\n table(mapping.subject.table),\n table(mapping.identifier.table),\n table(mapping.credential.table),\n table(mapping.authorityCredential.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 const authorityTable = a.as(\"password_authority\");\n const authority = mapping.authorityCredential;\n\n const rows = yield* sqlMapping(\n () =>\n sql<Row>`select ${subjectTable.fields(\"subject_\")}, ${identifierTable.fields(\"identifier_\")}, ${credentialTable.fields(\"credential_\")}, ${authorityTable.fields(\"authority_\")}\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 left join ${authorityTable.name} on ${authorityTable.column(authority.subjectId)} = ${authorityTable.value(authority.subjectId, nativeId)}\n ${authority.status === undefined || authority.d1ActiveStatusValue === undefined ? sql`` : sql`and ${authorityTable.column(authority.status)} = ${authorityTable.value(authority.status, authority.d1ActiveStatusValue)}`}\n where ${subjectTable.column(mapping.subject.id)} = ${subjectTable.value(mapping.subject.id, nativeId)} order by ${authorityTable.column(authority.credentialId)} limit 4097\n `,\n ).pipe(Effect.flatten);\n\n if (rows.length === 0) return undefined;\n if (rows.length > 4096) return yield* unavailable();\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 const factors = new Map<string, SecurityRevision>();\n\n for (const row of rows) {\n const factor = yield* sqlMapping(() => a.decode(row, \"authority_\"));\n\n if (factor[authority.credentialId] === null || factor[authority.credentialId] === undefined)\n continue;\n if (!mapping.subjectId.equals(nativeId, factor[authority.subjectId]))\n return yield* unavailable();\n if (\n authority.status !== undefined &&\n authority.isActiveStatus?.(factor[authority.status]) !== true\n )\n continue;\n\n const credentialId = yield* Schema.decodeUnknownEffect(Schema.String)(\n factor[authority.credentialId],\n );\n\n const revision = yield* Schema.decodeUnknownEffect(SecurityRevision)(\n factor[authority.revision],\n );\n\n if (factors.has(credentialId)) return yield* unavailable();\n factors.set(credentialId, revision);\n }\n if (factors.size > 64 || factors.get(captured.credentialId) !== captured.credentialRevision)\n return undefined;\n\n return yield* snapshotPasswordCredential({\n ...captured,\n revision: {\n ...captured.revision,\n credentials: [...factors].map(([credentialId, revision]) => ({ credentialId, revision })),\n },\n });\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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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AnyProofPersistenceMapping } from "./models/proof-model.mjs";
|
|
2
|
+
import { AnyPasswordPersistenceMapping } from "./models/password-model.mjs";
|
|
3
|
+
import { NativeSqlTables } from "./native-sql-table.mjs";
|
|
4
|
+
import { SqlBatchCommit } from "./sql-commit.mjs";
|
|
5
|
+
import { Crypto, Effect } from "effect";
|
|
6
|
+
import { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
7
|
+
import * as P from "@yielded/auth/Password";
|
|
8
|
+
import { SqlClient } from "effect/sql/SqlClient";
|
|
9
|
+
//#region src/internal/password-native.d.ts
|
|
10
|
+
export declare const makeNativePasswordServices: (tables: NativeSqlTables, mapping: AnyPasswordPersistenceMapping, proofs?: AnyProofPersistenceMapping | undefined) => Effect.Effect<{
|
|
11
|
+
readonly passwordPersistence: P.PasswordPersistence["Service"];
|
|
12
|
+
}, P.PasswordUnavailable, Crypto.Crypto | LifecycleHooks | SqlBatchCommit | SqlClient>;
|
|
13
|
+
//#endregion
|
|
14
|
+
//# sourceMappingURL=password-native.d.mts.map
|