@seams/wallet-server 0.7.1 → 0.7.3
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/THIRD_PARTY_NOTICES.md +1 -105
- package/artifact-manifest.json +21 -21
- package/cloudflare-router-ab/build/deriver-a/build-stamp.json +1 -1
- package/cloudflare-router-ab/build/deriver-a/index_bg.wasm +0 -0
- package/cloudflare-router-ab/build/deriver-b/build-stamp.json +1 -1
- package/cloudflare-router-ab/build/deriver-b/index_bg.wasm +0 -0
- package/cloudflare-router-ab/build/local-tools/darwin-arm64/router_ab_local_init +0 -0
- package/cloudflare-router-ab/build/local-tools/darwin-x64/router_ab_local_init +0 -0
- package/cloudflare-router-ab/build/local-tools/linux-x64/router_ab_local_init +0 -0
- package/cloudflare-router-ab/build/router/build-stamp.json +1 -1
- package/cloudflare-router-ab/build/router/index_bg.wasm +0 -0
- package/cloudflare-router-ab/build/signing-worker/build-stamp.json +1 -1
- package/cloudflare-router-ab/build/signing-worker/index_bg.wasm +0 -0
- package/cloudflare-router-ab/build/tenant-root-control-plane/build-stamp.json +1 -1
- package/cloudflare-router-ab/build/tenant-root-control-plane/index_bg.wasm +0 -0
- package/dist/esm/authorization/service.js +8 -0
- package/dist/esm/authorization/vaultProxyUse.js +2 -6
- package/dist/esm/cloud-host.js +4 -4
- package/dist/esm/core/IdentityStore.js +23 -110
- package/dist/esm/core/SessionService.js +7 -30
- package/dist/esm/core/ThresholdService/routerAbNormalSigningPolicy.js +3 -10
- package/dist/esm/core/ThresholdService/stores/WalletSessionStore.js +21 -97
- package/dist/esm/core/ThresholdService/stores/exportReplayGuard.js +7 -0
- package/dist/esm/core/WalletStore.js +4 -6
- package/dist/esm/core/authService/bytes.js +1 -4
- package/dist/esm/core/authService/emailOtpChallengeOperations.js +2 -5
- package/dist/esm/core/authService/emailOtpChallengeProof.js +9 -40
- package/dist/esm/core/authService/emailOtpChallengeVerification.js +19 -90
- package/dist/esm/core/authService/emailOtpChallenges.js +10 -45
- package/dist/esm/core/authService/emailOtpDelivery.js +10 -45
- package/dist/esm/core/authService/emailOtpEnrollment.js +9 -40
- package/dist/esm/core/authService/emailOtpGrant.js +9 -40
- package/dist/esm/core/authService/emailOtpRegistrationEnrollment.js +9 -40
- package/dist/esm/core/authService/emailOtpSeal.js +5 -20
- package/dist/esm/core/authService/emailOtpUnlock.js +20 -110
- package/dist/esm/core/authService/googleEmailOtpRegistration.js +28 -115
- package/dist/esm/core/authService/identity.js +5 -20
- package/dist/esm/core/authService/nearPublicKeyMetadata.js +6 -25
- package/dist/esm/core/authService/oidcVerification.js +22 -34
- package/dist/esm/core/authService/rateLimits.js +2 -5
- package/dist/esm/core/authService/thresholdEcdsaKeyInventory.js +2 -1
- package/dist/esm/core/authService/webauthn.js +37 -191
- package/dist/esm/core/authService/webauthnVerificationOutcomes.js +5 -24
- package/dist/esm/core/d1EcdsaSignerRead.js +76 -0
- package/dist/esm/core/d1IdentityStore.js +16 -75
- package/dist/esm/core/d1TenantStore.js +1 -1
- package/dist/esm/core/d1WalletStore.js +15 -25
- package/dist/esm/core/deviceLinking/linkedDeviceEmailOtpGrant.js +1 -5
- package/dist/esm/core/deviceLinking/linkedDeviceSessionApproval.js +1 -3
- package/dist/esm/core/deviceLinking/linkedDeviceSessionRecord.js +2 -8
- package/dist/esm/core/deviceLinking/requestProof.js +13 -4
- package/dist/esm/core/ecdsaMaterialReadSnapshot.js +85 -0
- package/dist/esm/core/nearRelayerAccountProvisioning.js +2 -5
- package/dist/esm/core/signingLanes/WalletExecutionLaneProjection.js +3 -6
- package/dist/esm/core/signingMaterial/ordinaryInactiveSignerMaterialReservation.js +2 -5
- package/dist/esm/core/storeBackends.js +1 -1
- package/dist/esm/core/thresholdEcdsaChainTarget.js +1 -3
- package/dist/esm/hosted-wallet-gateway.js +2 -2
- package/dist/esm/localHostedWalletGatewayHandler.js +13 -0
- package/dist/esm/localIntendedMaterialAdmissionFault.js +176 -0
- package/dist/esm/localIntendedPresignCancellation.js +44 -0
- package/dist/esm/router/auth/commonRouterUtils.js +24 -10
- package/dist/esm/router/auth/walletSessionFailure.js +2 -5
- package/dist/esm/router/auth/webAuthnCredentialCodecs.js +4 -15
- package/dist/esm/router/cloudflare/d1/auth/d1AuthorizedOperationRouteService.js +1 -0
- package/dist/esm/router/cloudflare/d1/auth/d1RouterApiAuthBoundary.js +2 -6
- package/dist/esm/router/cloudflare/d1/auth/d1RouterApiAuthService.js +5 -27
- package/dist/esm/router/cloudflare/d1/auth/walletSessionCredentialReaders.js +76 -0
- package/dist/esm/router/cloudflare/d1/authorization/authorizedOperationStatements.js +28 -21
- package/dist/esm/router/cloudflare/d1/authorization/d1AuthorizationStore.js +209 -44
- package/dist/esm/router/cloudflare/d1/authorization/d1VaultProxyStore.js +8 -12
- package/dist/esm/router/cloudflare/d1/deviceLinking/d1LinkedDeviceAuthorityInstallService.js +50 -8
- package/dist/esm/router/cloudflare/d1/deviceLinking/d1LinkedDeviceTargetCredentialProvider.js +1 -1
- package/dist/esm/router/cloudflare/d1/deviceLinking/index.js +3 -3
- package/dist/esm/router/cloudflare/d1/emailOtp/d1EmailOtpChallengeIssuer.js +12 -55
- package/dist/esm/router/cloudflare/d1/emailOtp/d1EmailOtpChallengeService.js +17 -80
- package/dist/esm/router/cloudflare/d1/emailOtp/d1EmailOtpDeliveryRuntime.js +6 -25
- package/dist/esm/router/cloudflare/d1/emailOtp/d1EmailOtpRecords.js +12 -47
- package/dist/esm/router/cloudflare/d1/emailOtp/d1EmailOtpRecoveryService.js +24 -85
- package/dist/esm/router/cloudflare/d1/emailOtp/d1EmailOtpRegistrationEnrollmentFinalizer.js +7 -30
- package/dist/esm/router/cloudflare/d1/emailOtp/d1EmailOtpServerSealRuntime.js +5 -20
- package/dist/esm/router/cloudflare/d1/emailOtp/d1GoogleEmailOtpSessionResolver.js +23 -110
- package/dist/esm/router/cloudflare/d1/identity/d1IdentityService.js +9 -40
- package/dist/esm/router/cloudflare/d1/near/d1NearPublicKeyStore.js +3 -10
- package/dist/esm/router/cloudflare/d1/oidc/d1OidcBoundary.js +18 -91
- package/dist/esm/router/cloudflare/d1/oidc/d1OidcVerificationService.js +6 -30
- package/dist/esm/router/cloudflare/d1/passkeyCustody/d1PasskeyCustodyRouteService.js +4 -15
- package/dist/esm/router/cloudflare/d1/passkeyCustody/d1WalletCustodyCommitStore.js +2 -7
- package/dist/esm/router/cloudflare/d1/passkeyCustody/d1WalletRecoveryGoogleEmailOtpRecords.js +9 -13
- package/dist/esm/router/cloudflare/d1/passkeyCustody/d1WalletRecoveryGoogleEmailOtpService.js +11 -50
- package/dist/esm/router/cloudflare/d1/registration/d1EvmFamilyEcdsaRegistrationBranch.js +5 -20
- package/dist/esm/router/cloudflare/d1/registration/d1RegistrationCeremonyRecordStore.js +4 -7
- package/dist/esm/router/cloudflare/d1/registration/d1RegistrationCeremonyRecords.js +2 -1
- package/dist/esm/router/cloudflare/d1/registration/d1RegistrationIntentService.js +7 -30
- package/dist/esm/router/cloudflare/d1/registration/d1WalletRegistrationService.js +32 -22
- package/dist/esm/router/cloudflare/d1/registration/walletRegistrationSessionCommitReceipt.js +1 -4
- package/dist/esm/router/cloudflare/d1/signingAdmission/d1RouterAbNormalSigningAdmissionStore.js +119 -25
- package/dist/esm/router/cloudflare/d1/webauthn/d1WebAuthnAuthService.js +31 -168
- package/dist/esm/router/cloudflare/d1/webauthn/d1WebAuthnRecords.js +6 -9
- package/dist/esm/router/cloudflare/durableObjects/thresholdStore.js +59 -66
- package/dist/esm/router/cloudflare/runtime/routerAbPrewarm.js +2 -2
- package/dist/esm/router/cloudflare/runtime/staticWalletConsoleBinding.js +5 -20
- package/dist/esm/router/cloudflare/runtime/tenantRootCreationGrant.js +2 -9
- package/dist/esm/router/cloudflare/runtime/walletControlOps.js +2 -1
- package/dist/esm/router/cloudflare/signingLanes/cloudflareLaneCurveExecution.js +2 -1
- package/dist/esm/router/cloudflare/signingLanes/cloudflareLaneProtocolCommitter.js +2 -2
- package/dist/esm/router/cloudflare.js +2146 -1802
- package/dist/esm/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistrationPersistence.js +5 -8
- package/dist/esm/router/domains/ed25519Yao/recovery/routerAbEd25519YaoRecoveryWalletSessionAuthorization.js +3 -6
- package/dist/esm/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistrationIntentAuthorization.js +6 -25
- package/dist/esm/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistrationSideEffectBoundary.js +39 -55
- package/dist/esm/router/domains/emailOtp/emailOtpRouteHandlers.js +15 -62
- package/dist/esm/router/domains/signingOperations/routerAbEcdsaDerivationNormalSigningRoute.js +83 -74
- package/dist/esm/router/domains/signingOperations/routerAbNormalSigningAdmission.js +1 -0
- package/dist/esm/router/domains/signingOperations/routerAbOperationStepUp.js +1 -0
- package/dist/esm/router/domains/signingOperations/walletExecutionAdmission.js +1 -4
- package/dist/esm/router/domains/tenantRoot/tenantRootIdentityResolution.js +7 -13
- package/dist/esm/router/domains/walletUnlock/walletUnlockRouteHandlers.js +41 -200
- package/dist/esm/router/express.js +317 -699
- package/dist/esm/router/framework/http.js +5 -1
- package/dist/esm/router/framework/runtimeSnapshotConsumer.js +8 -35
- package/dist/esm/router/transport/fetch/createFetchRouter.js +3 -6
- package/dist/esm/router/transport/fetch/routes/auth.js +9 -41
- package/dist/esm/router/transport/fetch/routes/deviceLinkingOwnerAuthorization.js +5 -22
- package/dist/esm/router/transport/fetch/routes/nearPublicKeys.js +4 -16
- package/dist/esm/router/transport/fetch/routes/sessions.js +1 -0
- package/dist/esm/router/transport/fetch/routes/syncAccount.js +8 -36
- package/dist/esm/router/transport/fetch/routes/thresholdEcdsa.js +27 -79
- package/dist/esm/router/transport/fetch/routes/walletExecutionLanePreflight.js +4 -1
- package/dist/esm/router/transport/fetch/routes/webauthnAuthenticators.js +4 -16
- package/dist/esm/shared-ts/src/authorization/walletSignerActivationEquality.js +12 -0
- package/dist/esm/shared-ts/src/device-linking/committedSignerPackages.js +2 -5
- package/dist/esm/shared-ts/src/device-linking/delegatedActivationPlan.js +1 -5
- package/dist/esm/shared-ts/src/device-linking/ed25519ExportRoot.js +12 -16
- package/dist/esm/shared-ts/src/device-linking/sourceContribution.js +5 -8
- package/dist/esm/shared-ts/src/passkey-custody/primitives.js +5 -1
- package/dist/esm/shared-ts/src/signing-lanes/ownerContinuity.js +4 -8
- package/dist/esm/shared-ts/src/tenant-root/tenantRootIdentifier.js +12 -0
- package/dist/esm/shared-ts/src/tenant-root/tenantRootIdentity.js +2 -9
- package/dist/esm/shared-ts/src/tenant-root/tenantRootOperationRecord.js +1 -4
- package/dist/esm/shared-ts/src/utils/ecdsaKeyFactsInventory.js +2 -4
- package/dist/esm/shared-ts/src/utils/ecdsaServerTiming.js +0 -1
- package/dist/esm/shared-ts/src/utils/emailOtpDomain.js +3 -1
- package/dist/esm/shared-ts/src/utils/exactKeys.js +17 -0
- package/dist/esm/shared-ts/src/utils/failure.js +20 -0
- package/dist/esm/shared-ts/src/utils/registrationIntent.js +3 -12
- package/dist/esm/shared-ts/src/utils/registrationSignerPlan.js +2 -5
- package/dist/esm/shared-ts/src/utils/routerAbEcdsaDerivation.js +1 -1
- package/dist/esm/shared-ts/src/utils/routerAbEd25519Yao.js +1 -1
- package/dist/esm/shared-ts/src/utils/thresholdEcdsaChainTarget.js +9 -0
- package/dist/esm/shared-ts/src/wallet-recovery/walletRecoveryCommittedProjection.js +1 -4
- package/dist/esm/threshold/session/signingSessionSeal/crypto/cipher.js +10 -32
- package/dist/esm/threshold/session/signingSessionSeal/idempotencyBackends.js +3 -3
- package/dist/esm/threshold/session/signingSessionSeal/idempotencyRecords.js +3 -9
- package/dist/esm/threshold/session/signingSessionSeal/service.js +8 -35
- package/dist/esm/threshold/session/signingSessionSeal/transport/express.js +18 -94
- package/dist/esm/threshold/session/signingSessionSeal/transport/fetch.js +6 -30
- package/dist/esm/threshold/session/signingSessionSeal/transport/shared.js +5 -20
- package/dist/esm/wasm/evm_crypto/pkg/evm_crypto_bg.wasm +0 -0
- package/dist/esm/wasm/near_signer/pkg/wasm_signer_worker_bg.wasm +0 -0
- package/dist/types/shared-ts/src/authorization/delegatedAuthority.d.ts +2 -1
- package/dist/types/shared-ts/src/authorization/walletSessionIssuance.d.ts +9 -2
- package/dist/types/shared-ts/src/authorization/walletSignerActivationEquality.d.ts +4 -0
- package/dist/types/shared-ts/src/device-linking/committedSignerPackages.d.ts +3 -4
- package/dist/types/shared-ts/src/device-linking/contracts.d.ts +5 -63
- package/dist/types/shared-ts/src/device-linking/sourceContribution.d.ts +2 -0
- package/dist/types/shared-ts/src/passkey-custody/custodyEnvelope.d.ts +5 -12
- package/dist/types/shared-ts/src/passkey-custody/primitives.d.ts +9 -0
- package/dist/types/shared-ts/src/signing-lanes/execution.d.ts +11 -1
- package/dist/types/shared-ts/src/signing-lanes/ids.d.ts +1 -10
- package/dist/types/shared-ts/src/signing-lanes/rotation.d.ts +3 -5
- package/dist/types/shared-ts/src/tenant-root/tenantRootIdentifier.d.ts +3 -0
- package/dist/types/shared-ts/src/tenant-root/tenantRootOperationRecord.d.ts +2 -1
- package/dist/types/shared-ts/src/threshold/ecdsaDerivationRoleLocalBootstrap.d.ts +6 -0
- package/dist/types/shared-ts/src/threshold/signingRootScope.d.ts +1 -0
- package/dist/types/shared-ts/src/utils/ecdsaKeyFactsInventory.d.ts +2 -11
- package/dist/types/shared-ts/src/utils/eip1559TxWasmJson.d.ts +16 -0
- package/dist/types/shared-ts/src/utils/emailOtpDomain.d.ts +2 -0
- package/dist/types/shared-ts/src/utils/exactKeys.d.ts +11 -0
- package/dist/types/shared-ts/src/utils/failure.d.ts +12 -0
- package/dist/types/shared-ts/src/utils/jsonRpc.d.ts +3 -4
- package/dist/types/shared-ts/src/utils/nearRpcResults.d.ts +1 -0
- package/dist/types/shared-ts/src/utils/registrationAuthMethodInput.d.ts +3 -8
- package/dist/types/shared-ts/src/utils/registrationSignerPlan.d.ts +7 -19
- package/dist/types/shared-ts/src/utils/routerAbEcdsaDerivation.d.ts +3 -1
- package/dist/types/shared-ts/src/utils/routerAbEd25519Yao.d.ts +1 -0
- package/dist/types/shared-ts/src/utils/routerAbEd25519YaoDigests.d.ts +3 -4
- package/dist/types/shared-ts/src/utils/routerAbNormalSigningIdentity.d.ts +30 -8
- package/dist/types/shared-ts/src/utils/routerApiKeyAuth.d.ts +2 -0
- package/dist/types/shared-ts/src/utils/signingSessionSeal.d.ts +10 -11
- package/dist/types/shared-ts/src/utils/thresholdEcdsaChainTarget.d.ts +25 -0
- package/dist/types/shared-ts/src/utils/variant.d.ts +18 -0
- package/dist/types/shared-ts/src/utils/walletAuthMethodRecord.d.ts +3 -6
- package/dist/types/shared-ts/src/utils/webauthnDeviceInfo.d.ts +4 -2
- package/dist/types/shared-ts/src/wallet-recovery/recoveryEnvelopes.d.ts +3 -16
- package/dist/types/shared-ts/src/wallet-recovery/walletRecoveryPreparation.d.ts +15 -0
- package/dist/types/shared-ts/src/wallet-recovery/walletRecoveryTarget.d.ts +3 -4
- package/dist/types/wallet-server/src/authorization/domain.d.ts +13 -2
- package/dist/types/wallet-server/src/authorization/ecdsaWalletSessionAdmission.d.ts +27 -3
- package/dist/types/wallet-server/src/authorization/service.d.ts +19 -0
- package/dist/types/wallet-server/src/core/ThresholdService/stores/SessionStore.d.ts +2 -2
- package/dist/types/wallet-server/src/core/ThresholdService/stores/WalletSessionStore.d.ts +1 -1
- package/dist/types/wallet-server/src/core/ThresholdService/stores/exportReplayGuard.d.ts +3 -0
- package/dist/types/wallet-server/src/core/ThresholdService/validation.d.ts +8 -101
- package/dist/types/wallet-server/src/core/WebAuthnAuthenticatorStore.d.ts +8 -0
- package/dist/types/wallet-server/src/core/authService/bytes.d.ts +0 -1
- package/dist/types/wallet-server/src/core/authService/emailOtpChallenges.d.ts +2 -10
- package/dist/types/wallet-server/src/core/authService/emailOtpSeal.d.ts +1 -1
- package/dist/types/wallet-server/src/core/authService/emailOtpUnlock.d.ts +3 -10
- package/dist/types/wallet-server/src/core/d1EcdsaSignerRead.d.ts +39 -0
- package/dist/types/wallet-server/src/core/d1WalletStore.d.ts +10 -0
- package/dist/types/wallet-server/src/core/deviceLinking/linkedDeviceSessionRecord.d.ts +3 -4
- package/dist/types/wallet-server/src/core/ecdsaMaterialReadSnapshot.d.ts +19 -0
- package/dist/types/wallet-server/src/core/routerAbSigning/RouterAbNormalSigningRuntime.d.ts +3 -5
- package/dist/types/wallet-server/src/core/rpcClients/near/NearClient.d.ts +1 -2
- package/dist/types/wallet-server/src/core/signingLanes/WalletExecutionLaneProjection.d.ts +2 -11
- package/dist/types/wallet-server/src/core/signingLanes/signingWorkerLaneMaterialIdentity.d.ts +2 -19
- package/dist/types/wallet-server/src/core/thresholdEcdsaChainTarget.d.ts +3 -11
- package/dist/types/wallet-server/src/core/types.d.ts +2 -6
- package/dist/types/wallet-server/src/localIntendedMaterialAdmissionFault.d.ts +38 -0
- package/dist/types/wallet-server/src/localIntendedPresignCancellation.d.ts +4 -0
- package/dist/types/wallet-server/src/router/auth/authRequestValidation.d.ts +4 -9
- package/dist/types/wallet-server/src/router/auth/commonRouterUtils.d.ts +15 -1
- package/dist/types/wallet-server/src/router/cloudflare/d1/auth/d1RouterApiAuthBoundary.d.ts +0 -1
- package/dist/types/wallet-server/src/router/cloudflare/d1/auth/d1RouterApiAuthService.d.ts +1 -1
- package/dist/types/wallet-server/src/router/cloudflare/d1/auth/walletSessionCredentialReaders.d.ts +9 -0
- package/dist/types/wallet-server/src/router/cloudflare/d1/authorization/authorizedOperationStatements.d.ts +4 -0
- package/dist/types/wallet-server/src/router/cloudflare/d1/authorization/d1AuthorizationStore.d.ts +10 -1
- package/dist/types/wallet-server/src/router/cloudflare/d1/deviceLinking/d1LinkedDeviceAuthorityInstallService.d.ts +19 -2
- package/dist/types/wallet-server/src/router/cloudflare/d1/deviceLinking/d1LinkedDeviceSessionStore.d.ts +2 -6
- package/dist/types/wallet-server/src/router/cloudflare/d1/deviceLinking/d1LinkedDeviceTargetCredentialProvider.d.ts +5 -8
- package/dist/types/wallet-server/src/router/cloudflare/d1/emailOtp/d1EmailOtpEnrollmentStore.d.ts +2 -8
- package/dist/types/wallet-server/src/router/cloudflare/d1/emailOtp/d1EmailOtpRateLimitStore.d.ts +2 -9
- package/dist/types/wallet-server/src/router/cloudflare/d1/emailOtp/d1EmailOtpRecords.d.ts +5 -5
- package/dist/types/wallet-server/src/router/cloudflare/d1/emailOtp/d1EmailOtpServerSealRuntime.d.ts +4 -14
- package/dist/types/wallet-server/src/router/cloudflare/d1/registration/d1RegistrationCeremonyRecordStore.d.ts +2 -6
- package/dist/types/wallet-server/src/router/cloudflare/d1/registration/d1WalletRegistrationService.d.ts +8 -6
- package/dist/types/wallet-server/src/router/cloudflare/d1/signingAdmission/d1RouterAbNormalSigningAdmissionStore.d.ts +14 -1
- package/dist/types/wallet-server/src/router/cloudflare/d1/webauthn/d1WebAuthnRecords.d.ts +10 -39
- package/dist/types/wallet-server/src/router/cloudflare/runtime/walletConsoleOps.d.ts +8 -34
- package/dist/types/wallet-server/src/router/domains/ecdsa/thresholdEcdsaRequestValidation.d.ts +3 -15
- package/dist/types/wallet-server/src/router/domains/ed25519Yao/session/routerAbEd25519YaoWalletSession.d.ts +9 -50
- package/dist/types/wallet-server/src/router/domains/passkeyCustody/walletRecoveryKeyManifest.d.ts +1 -13
- package/dist/types/wallet-server/src/router/domains/signingOperations/routerAbEcdsaDerivationNormalSigningRoute.d.ts +8 -9
- package/dist/types/wallet-server/src/router/domains/signingOperations/routerAbNormalSigningAdmission.d.ts +13 -0
- package/dist/types/wallet-server/src/router/domains/signingOperations/routerAbOperationStepUp.d.ts +3 -4
- package/dist/types/wallet-server/src/router/domains/signingOperations/routerAbPrivateSigningWorker.d.ts +7 -16
- package/dist/types/wallet-server/src/router/domains/syncAccount/syncAccountRequestValidation.d.ts +2 -7
- package/dist/types/wallet-server/src/router/framework/apiCredentialPorts.d.ts +3 -1
- package/dist/types/wallet-server/src/router/framework/authServicePort.d.ts +25 -4
- package/dist/types/wallet-server/src/router/framework/http.d.ts +1 -0
- package/dist/types/wallet-server/src/router/framework/ror/normalize.d.ts +1 -9
- package/dist/types/wallet-server/src/router/transport/fetch/routes/deviceLinkingOwnerAuthorization.d.ts +3 -6
- package/dist/types/wallet-server/src/router/transport/fetch/routes/syncAccountBootstrap.d.ts +3 -5
- package/dist/types/wallet-server/src/router/transport/fetch/routes/thresholdEcdsa.d.ts +0 -1
- package/dist/types/wallet-server/src/threshold/session/signingSessionSeal/idempotencyRecords.d.ts +1 -2
- package/dist/types/wallet-server/src/threshold/session/signingSessionSeal/signingSessionSeal.types.d.ts +6 -8
- package/package.json +1 -1
- package/dist/esm/wasm/router_ab_ecdsa_signing_worker/pkg/router_ab_ecdsa_signing_worker_bg.wasm +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { normalizeOptionalTrimmedString } from "../../../../shared-ts/src/utils/normalize.js";
|
|
2
2
|
import "../../../../shared-ts/src/utils/validation.js";
|
|
3
3
|
import { secureRandomBase64Url } from "../../../../shared-ts/src/utils/secureRandomId.js";
|
|
4
|
+
import { failure } from "../../../../shared-ts/src/utils/failure.js";
|
|
4
5
|
import { EMAIL_OTP_CHANNEL, WALLET_EMAIL_OTP_ACTIONS } from "../../../../shared-ts/src/utils/emailOtpDomain.js";
|
|
5
6
|
import { emailOtpChallengePurposeIsValid, emailOtpChallengeRecord, generateNumericOtp } from "./d1EmailOtpRecords.js";
|
|
6
7
|
//#region src/router/cloudflare/d1/emailOtp/d1EmailOtpChallengeIssuer.ts
|
|
@@ -8,18 +9,10 @@ function errorMessage(error) {
|
|
|
8
9
|
return error instanceof Error ? error.message : String(error || "");
|
|
9
10
|
}
|
|
10
11
|
function emailOtpEnrollmentTenantMismatch() {
|
|
11
|
-
return
|
|
12
|
-
ok: false,
|
|
13
|
-
code: "tenant_scope_mismatch",
|
|
14
|
-
message: "Email OTP enrollment does not match the requested orgId"
|
|
15
|
-
};
|
|
12
|
+
return failure("tenant_scope_mismatch", "Email OTP enrollment does not match the requested orgId");
|
|
16
13
|
}
|
|
17
14
|
function emailOtpProviderIdentityMismatch() {
|
|
18
|
-
return
|
|
19
|
-
ok: false,
|
|
20
|
-
code: "provider_identity_mismatch",
|
|
21
|
-
message: "Email OTP enrollment does not match the requested provider user"
|
|
22
|
-
};
|
|
15
|
+
return failure("provider_identity_mismatch", "Email OTP enrollment does not match the requested provider user");
|
|
23
16
|
}
|
|
24
17
|
var CloudflareD1EmailOtpChallengeIssuer = class {
|
|
25
18
|
constructor(input) {
|
|
@@ -40,39 +33,15 @@ var CloudflareD1EmailOtpChallengeIssuer = class {
|
|
|
40
33
|
const clientIp = normalizeOptionalTrimmedString(input.clientIp);
|
|
41
34
|
const action = input.action;
|
|
42
35
|
const operation = input.operation;
|
|
43
|
-
if (!userId) return
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (!walletId) return {
|
|
49
|
-
ok: false,
|
|
50
|
-
code: "invalid_body",
|
|
51
|
-
message: "Missing walletId"
|
|
52
|
-
};
|
|
53
|
-
if (!orgId) return {
|
|
54
|
-
ok: false,
|
|
55
|
-
code: "invalid_body",
|
|
56
|
-
message: "Missing orgId"
|
|
57
|
-
};
|
|
58
|
-
if (otpChannel !== "email_otp") return {
|
|
59
|
-
ok: false,
|
|
60
|
-
code: "invalid_body",
|
|
61
|
-
message: "otpChannel must be email_otp"
|
|
62
|
-
};
|
|
63
|
-
if (!ownerProofBindingDigest) return {
|
|
64
|
-
ok: false,
|
|
65
|
-
code: "invalid_body",
|
|
66
|
-
message: "Missing ownerProofBindingDigest"
|
|
67
|
-
};
|
|
36
|
+
if (!userId) return failure("invalid_body", "Missing userId");
|
|
37
|
+
if (!walletId) return failure("invalid_body", "Missing walletId");
|
|
38
|
+
if (!orgId) return failure("invalid_body", "Missing orgId");
|
|
39
|
+
if (otpChannel !== "email_otp") return failure("invalid_body", "otpChannel must be email_otp");
|
|
40
|
+
if (!ownerProofBindingDigest) return failure("invalid_body", "Missing ownerProofBindingDigest");
|
|
68
41
|
if (!emailOtpChallengePurposeIsValid({
|
|
69
42
|
action,
|
|
70
43
|
operation
|
|
71
|
-
})) return
|
|
72
|
-
ok: false,
|
|
73
|
-
code: "invalid_body",
|
|
74
|
-
message: "Email OTP challenge action does not match operation"
|
|
75
|
-
};
|
|
44
|
+
})) return failure("invalid_body", "Email OTP challenge action does not match operation");
|
|
76
45
|
let challengeEmail = email;
|
|
77
46
|
if (action !== WALLET_EMAIL_OTP_ACTIONS.registration && action !== WALLET_EMAIL_OTP_ACTIONS.recoveryBootstrap) {
|
|
78
47
|
const enrollment = await this.readActiveEnrollment({
|
|
@@ -91,11 +60,7 @@ var CloudflareD1EmailOtpChallengeIssuer = class {
|
|
|
91
60
|
};
|
|
92
61
|
challengeEmail = enrollment.enrollment.verifiedEmail;
|
|
93
62
|
}
|
|
94
|
-
if (!challengeEmail) return
|
|
95
|
-
ok: false,
|
|
96
|
-
code: "recovery_email_missing",
|
|
97
|
-
message: "Authenticated identity does not include a recovery email"
|
|
98
|
-
};
|
|
63
|
+
if (!challengeEmail) return failure("recovery_email_missing", "Authenticated identity does not include a recovery email");
|
|
99
64
|
const nowMs = Date.now();
|
|
100
65
|
await this.emailOtpChallenges.pruneExpired(nowMs);
|
|
101
66
|
if (input.reuseActiveChallenge === true) {
|
|
@@ -188,20 +153,12 @@ var CloudflareD1EmailOtpChallengeIssuer = class {
|
|
|
188
153
|
delivery: delivery.delivery
|
|
189
154
|
};
|
|
190
155
|
} catch (error) {
|
|
191
|
-
return
|
|
192
|
-
ok: false,
|
|
193
|
-
code: "internal",
|
|
194
|
-
message: errorMessage(error) || "Failed to create Email OTP challenge"
|
|
195
|
-
};
|
|
156
|
+
return failure("internal", errorMessage(error) || "Failed to create Email OTP challenge");
|
|
196
157
|
}
|
|
197
158
|
}
|
|
198
159
|
async readActiveEnrollment(input) {
|
|
199
160
|
const enrollment = await this.emailOtpEnrollments.readEnrollment(input.walletId);
|
|
200
|
-
if (!enrollment) return
|
|
201
|
-
ok: false,
|
|
202
|
-
code: "not_found",
|
|
203
|
-
message: "Email OTP enrollment not found"
|
|
204
|
-
};
|
|
161
|
+
if (!enrollment) return failure("not_found", "Email OTP enrollment not found");
|
|
205
162
|
if (enrollment.orgId !== input.orgId) return emailOtpEnrollmentTenantMismatch();
|
|
206
163
|
if (enrollment.providerUserId !== input.providerUserId) return emailOtpProviderIdentityMismatch();
|
|
207
164
|
return {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { normalizeOptionalTrimmedString } from "../../../../shared-ts/src/utils/normalize.js";
|
|
2
2
|
import "../../../../shared-ts/src/utils/validation.js";
|
|
3
3
|
import { secureRandomBase64Url } from "../../../../shared-ts/src/utils/secureRandomId.js";
|
|
4
|
+
import { failure } from "../../../../shared-ts/src/utils/failure.js";
|
|
4
5
|
import { EMAIL_OTP_CHANNEL, WALLET_EMAIL_OTP_ACTIONS, WALLET_EMAIL_OTP_REGISTRATION_OPERATION, WALLET_EMAIL_OTP_UNLOCK_OPERATION } from "../../../../shared-ts/src/utils/emailOtpDomain.js";
|
|
5
6
|
import { emailOtpGrantRecord, maskEmail, parseEmailOtpLoginOperation } from "./d1EmailOtpRecords.js";
|
|
6
7
|
//#region src/router/cloudflare/d1/emailOtp/d1EmailOtpChallengeService.ts
|
|
@@ -89,26 +90,10 @@ var CloudflareD1EmailOtpChallengeService = class {
|
|
|
89
90
|
const orgId = normalizeOptionalTrimmedString(input.orgId);
|
|
90
91
|
const challengeId = normalizeOptionalTrimmedString(input.challengeId);
|
|
91
92
|
const registrationAttemptId = normalizeOptionalTrimmedString(input.googleEmailOtpRegistrationAttemptId);
|
|
92
|
-
if (!providerSubject) return
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
};
|
|
97
|
-
if (!walletId) return {
|
|
98
|
-
ok: false,
|
|
99
|
-
code: "invalid_body",
|
|
100
|
-
message: "Email OTP registration requires walletId"
|
|
101
|
-
};
|
|
102
|
-
if (!orgId) return {
|
|
103
|
-
ok: false,
|
|
104
|
-
code: "invalid_body",
|
|
105
|
-
message: "Email OTP registration requires orgId"
|
|
106
|
-
};
|
|
107
|
-
if (!challengeId) return {
|
|
108
|
-
ok: false,
|
|
109
|
-
code: "invalid_body",
|
|
110
|
-
message: "Email OTP registration requires challengeId"
|
|
111
|
-
};
|
|
93
|
+
if (!providerSubject) return failure("invalid_body", "Email OTP registration requires providerSubject");
|
|
94
|
+
if (!walletId) return failure("invalid_body", "Email OTP registration requires walletId");
|
|
95
|
+
if (!orgId) return failure("invalid_body", "Email OTP registration requires orgId");
|
|
96
|
+
if (!challengeId) return failure("invalid_body", "Email OTP registration requires challengeId");
|
|
112
97
|
const proofEmail = await this.resolveRegistrationProofEmail({
|
|
113
98
|
explicitProofEmail: input.proofEmail,
|
|
114
99
|
providerSubject,
|
|
@@ -129,11 +114,7 @@ var CloudflareD1EmailOtpChallengeService = class {
|
|
|
129
114
|
});
|
|
130
115
|
if (!verified.ok) return verified;
|
|
131
116
|
const verifiedEmail = normalizeOptionalTrimmedString(verified.email)?.toLowerCase() || "";
|
|
132
|
-
if (!verifiedEmail) return
|
|
133
|
-
ok: false,
|
|
134
|
-
code: "internal",
|
|
135
|
-
message: "Email OTP enrollment verification did not include a verified email"
|
|
136
|
-
};
|
|
117
|
+
if (!verifiedEmail) return failure("internal", "Email OTP enrollment verification did not include a verified email");
|
|
137
118
|
const persisted = await this.finalizer.persistVerifiedEnrollment({
|
|
138
119
|
walletId: verified.walletId,
|
|
139
120
|
orgId: verified.orgId,
|
|
@@ -151,11 +132,7 @@ var CloudflareD1EmailOtpChallengeService = class {
|
|
|
151
132
|
enrollment: persisted.enrollment
|
|
152
133
|
};
|
|
153
134
|
} catch (error) {
|
|
154
|
-
return
|
|
155
|
-
ok: false,
|
|
156
|
-
code: "internal",
|
|
157
|
-
message: errorMessage(error) || "Failed to verify Email OTP enrollment"
|
|
158
|
-
};
|
|
135
|
+
return failure("internal", errorMessage(error) || "Failed to verify Email OTP enrollment");
|
|
159
136
|
}
|
|
160
137
|
}
|
|
161
138
|
async verifyEmailOtpChallenge(input) {
|
|
@@ -232,41 +209,21 @@ var CloudflareD1EmailOtpChallengeService = class {
|
|
|
232
209
|
};
|
|
233
210
|
}
|
|
234
211
|
async readEmailOtpOutboxEntry(input) {
|
|
235
|
-
if (!this.devOutboxEnabled) return
|
|
236
|
-
ok: false,
|
|
237
|
-
code: "not_found",
|
|
238
|
-
message: "Email OTP dev outbox is not enabled"
|
|
239
|
-
};
|
|
212
|
+
if (!this.devOutboxEnabled) return failure("not_found", "Email OTP dev outbox is not enabled");
|
|
240
213
|
const challengeId = normalizeOptionalTrimmedString(input.challengeId);
|
|
241
214
|
const userId = normalizeOptionalTrimmedString(input.userId);
|
|
242
215
|
const walletId = normalizeOptionalTrimmedString(input.walletId);
|
|
243
|
-
if (!userId) return
|
|
244
|
-
|
|
245
|
-
code: "invalid_body",
|
|
246
|
-
message: "Missing userId"
|
|
247
|
-
};
|
|
248
|
-
if (!walletId) return {
|
|
249
|
-
ok: false,
|
|
250
|
-
code: "invalid_body",
|
|
251
|
-
message: "Missing walletId"
|
|
252
|
-
};
|
|
216
|
+
if (!userId) return failure("invalid_body", "Missing userId");
|
|
217
|
+
if (!walletId) return failure("invalid_body", "Missing walletId");
|
|
253
218
|
const record = challengeId ? await this.challenges.read(challengeId) : await this.challenges.readLatestActiveForSubjectWallet({
|
|
254
219
|
challengeSubjectId: userId,
|
|
255
220
|
walletId,
|
|
256
221
|
nowMs: Date.now()
|
|
257
222
|
});
|
|
258
|
-
if (!record || record.challengeSubjectId !== userId || record.walletId !== walletId) return
|
|
259
|
-
ok: false,
|
|
260
|
-
code: "not_found",
|
|
261
|
-
message: "Email OTP outbox entry was not found"
|
|
262
|
-
};
|
|
223
|
+
if (!record || record.challengeSubjectId !== userId || record.walletId !== walletId) return failure("not_found", "Email OTP outbox entry was not found");
|
|
263
224
|
if (Date.now() > record.expiresAtMs) {
|
|
264
225
|
await this.challenges.delete(challengeId);
|
|
265
|
-
return
|
|
266
|
-
ok: false,
|
|
267
|
-
code: "not_found",
|
|
268
|
-
message: "Email OTP outbox entry expired"
|
|
269
|
-
};
|
|
226
|
+
return failure("not_found", "Email OTP outbox entry expired");
|
|
270
227
|
}
|
|
271
228
|
return {
|
|
272
229
|
ok: true,
|
|
@@ -286,33 +243,13 @@ var CloudflareD1EmailOtpChallengeService = class {
|
|
|
286
243
|
ok: true,
|
|
287
244
|
email: proofEmail
|
|
288
245
|
};
|
|
289
|
-
return
|
|
290
|
-
ok: false,
|
|
291
|
-
code: "invalid_body",
|
|
292
|
-
message: "Email OTP registration requires proofEmail"
|
|
293
|
-
};
|
|
246
|
+
return failure("invalid_body", "Email OTP registration requires proofEmail");
|
|
294
247
|
}
|
|
295
248
|
const attempt = await this.registrationAttempts.read(input.registrationAttemptId);
|
|
296
|
-
if (!attempt) return
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
};
|
|
301
|
-
if (attempt.providerSubject !== input.providerSubject) return {
|
|
302
|
-
ok: false,
|
|
303
|
-
code: "challenge_subject_mismatch",
|
|
304
|
-
message: "Email OTP registration attempt does not match the provider subject"
|
|
305
|
-
};
|
|
306
|
-
if (attempt.expiresAtMs <= Date.now()) return {
|
|
307
|
-
ok: false,
|
|
308
|
-
code: "registration_attempt_expired",
|
|
309
|
-
message: "Google Email OTP registration attempt expired"
|
|
310
|
-
};
|
|
311
|
-
if (attempt.walletId !== input.walletId) return {
|
|
312
|
-
ok: false,
|
|
313
|
-
code: "wallet_identity_mismatch",
|
|
314
|
-
message: "registrationAttemptId does not match walletId"
|
|
315
|
-
};
|
|
249
|
+
if (!attempt) return failure("registration_attempt_missing", "Google Email OTP registration attempt expired or was not found");
|
|
250
|
+
if (attempt.providerSubject !== input.providerSubject) return failure("challenge_subject_mismatch", "Email OTP registration attempt does not match the provider subject");
|
|
251
|
+
if (attempt.expiresAtMs <= Date.now()) return failure("registration_attempt_expired", "Google Email OTP registration attempt expired");
|
|
252
|
+
if (attempt.walletId !== input.walletId) return failure("wallet_identity_mismatch", "registrationAttemptId does not match walletId");
|
|
316
253
|
proofEmail = attempt.email.toLowerCase();
|
|
317
254
|
return {
|
|
318
255
|
ok: true,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { failure } from "../../../../shared-ts/src/utils/failure.js";
|
|
1
2
|
import { EMAIL_OTP_CHANNEL } from "../../../../shared-ts/src/utils/emailOtpDomain.js";
|
|
2
3
|
import { maskEmail } from "./d1EmailOtpRecords.js";
|
|
3
4
|
//#region src/router/cloudflare/d1/emailOtp/d1EmailOtpDeliveryRuntime.ts
|
|
@@ -24,11 +25,7 @@ var CloudflareD1EmailOtpDeliveryRuntime = class {
|
|
|
24
25
|
return this.resolveDelivery(record, requestOrigin, "reused");
|
|
25
26
|
}
|
|
26
27
|
async deliverEmailOtpCode(record, requestOrigin) {
|
|
27
|
-
if (this.config.production && this.config.deliveryMode !== "email_provider" && this.config.deliveryMode !== "provider_and_demo_code" && this.config.deliveryMode !== "demo_code_response") return {
|
|
28
|
-
ok: false,
|
|
29
|
-
code: "email_otp_delivery_not_allowed",
|
|
30
|
-
message: `Email OTP delivery mode ${this.config.deliveryMode} is disabled in production`
|
|
31
|
-
};
|
|
28
|
+
if (this.config.production && this.config.deliveryMode !== "email_provider" && this.config.deliveryMode !== "provider_and_demo_code" && this.config.deliveryMode !== "demo_code_response") return failure("email_otp_delivery_not_allowed", `Email OTP delivery mode ${this.config.deliveryMode} is disabled in production`);
|
|
32
29
|
const emailHint = maskEmail(record.email);
|
|
33
30
|
switch (this.config.deliveryMode) {
|
|
34
31
|
case "provider_and_demo_code": {
|
|
@@ -58,11 +55,7 @@ var CloudflareD1EmailOtpDeliveryRuntime = class {
|
|
|
58
55
|
}
|
|
59
56
|
async dispatchProviderEmail(record, emailHint) {
|
|
60
57
|
const provider = this.config.deliveryProvider;
|
|
61
|
-
if (!provider) return
|
|
62
|
-
ok: false,
|
|
63
|
-
code: "email_otp_delivery_not_configured",
|
|
64
|
-
message: "Email OTP email_provider delivery is not configured"
|
|
65
|
-
};
|
|
58
|
+
if (!provider) return failure("email_otp_delivery_not_configured", "Email OTP email_provider delivery is not configured");
|
|
66
59
|
const result = await provider.deliver({
|
|
67
60
|
challengeId: record.challengeId,
|
|
68
61
|
walletId: record.walletId,
|
|
@@ -86,11 +79,7 @@ var CloudflareD1EmailOtpDeliveryRuntime = class {
|
|
|
86
79
|
const emailHint = maskEmail(record.email);
|
|
87
80
|
switch (this.config.deliveryMode) {
|
|
88
81
|
case "email_provider":
|
|
89
|
-
if (!this.config.deliveryProvider) return
|
|
90
|
-
ok: false,
|
|
91
|
-
code: "email_otp_delivery_not_configured",
|
|
92
|
-
message: "Email OTP email_provider delivery is not configured"
|
|
93
|
-
};
|
|
82
|
+
if (!this.config.deliveryProvider) return failure("email_otp_delivery_not_configured", "Email OTP email_provider delivery is not configured");
|
|
94
83
|
return {
|
|
95
84
|
ok: true,
|
|
96
85
|
delivery: {
|
|
@@ -101,11 +90,7 @@ var CloudflareD1EmailOtpDeliveryRuntime = class {
|
|
|
101
90
|
}
|
|
102
91
|
};
|
|
103
92
|
case "provider_and_demo_code":
|
|
104
|
-
if (!this.config.deliveryProvider) return
|
|
105
|
-
ok: false,
|
|
106
|
-
code: "email_otp_delivery_not_configured",
|
|
107
|
-
message: "Email OTP email_provider delivery is not configured"
|
|
108
|
-
};
|
|
93
|
+
if (!this.config.deliveryProvider) return failure("email_otp_delivery_not_configured", "Email OTP email_provider delivery is not configured");
|
|
109
94
|
return this.resolveDemoCodeDelivery(record, requestOrigin, status, emailHint);
|
|
110
95
|
case "log":
|
|
111
96
|
case "dev_d1_outbox":
|
|
@@ -124,11 +109,7 @@ var CloudflareD1EmailOtpDeliveryRuntime = class {
|
|
|
124
109
|
}
|
|
125
110
|
resolveDemoCodeDelivery(record, requestOrigin, status, emailHint) {
|
|
126
111
|
const origin = typeof requestOrigin === "string" ? requestOrigin.trim() : "";
|
|
127
|
-
if (!this.config.demoAllowedOrigins.includes(origin)) return
|
|
128
|
-
ok: false,
|
|
129
|
-
code: "email_otp_demo_origin_not_allowed",
|
|
130
|
-
message: "Email OTP demo code delivery is not allowed for this origin"
|
|
131
|
-
};
|
|
112
|
+
if (!this.config.demoAllowedOrigins.includes(origin)) return failure("email_otp_demo_origin_not_allowed", "Email OTP demo code delivery is not allowed for this origin");
|
|
132
113
|
if (this.config.deliveryMode === "provider_and_demo_code") return {
|
|
133
114
|
ok: true,
|
|
134
115
|
delivery: {
|
|
@@ -2,6 +2,8 @@ import { base64UrlDecode } from "../../../../shared-ts/src/utils/base64.js";
|
|
|
2
2
|
import "../../../../shared-ts/src/utils/encoders.js";
|
|
3
3
|
import { normalizeOptionalTrimmedString } from "../../../../shared-ts/src/utils/normalize.js";
|
|
4
4
|
import "../../../../shared-ts/src/utils/validation.js";
|
|
5
|
+
import { hasExactKeys } from "../../../../shared-ts/src/utils/exactKeys.js";
|
|
6
|
+
import { failure } from "../../../../shared-ts/src/utils/failure.js";
|
|
5
7
|
import { EMAIL_OTP_CHANNEL, WALLET_EMAIL_OTP_ACTIONS, WALLET_EMAIL_OTP_DEVICE_LINK_OPERATION, WALLET_EMAIL_OTP_REGISTRATION_OPERATION, WALLET_EMAIL_OTP_UNLOCK_OPERATION, isWalletEmailOtpLoginOperation } from "../../../../shared-ts/src/utils/emailOtpDomain.js";
|
|
6
8
|
import { isB64uString, nonNegativeSafeInteger, parseJsonObject, positiveSafeInteger } from "../auth/d1RouterApiAuthBoundary.js";
|
|
7
9
|
import { parseCurrentEmailOtpChallengeRow, parseCurrentEmailOtpGrantRow, parseCurrentEmailOtpUnlockChallengeRow } from "../../../../core/EmailOtpRecords.js";
|
|
@@ -165,7 +167,7 @@ function parseEmailOtpChallengeRow(row) {
|
|
|
165
167
|
}
|
|
166
168
|
function parseEmailOtpRegistrationVerificationReceiptV1(input) {
|
|
167
169
|
const record = parseJsonObject(input);
|
|
168
|
-
if (!record || !
|
|
170
|
+
if (!record || !hasExactKeys(record, [
|
|
169
171
|
"version",
|
|
170
172
|
"requestFingerprint",
|
|
171
173
|
"verified",
|
|
@@ -176,7 +178,7 @@ function parseEmailOtpRegistrationVerificationReceiptV1(input) {
|
|
|
176
178
|
const verified = parseJsonObject(record.verified);
|
|
177
179
|
const verifiedAtMs = positiveSafeInteger(record.verifiedAtMs);
|
|
178
180
|
const expiresAtMs = positiveSafeInteger(record.expiresAtMs);
|
|
179
|
-
if (!requestFingerprint || !isB64uString(requestFingerprint) || !verified || !
|
|
181
|
+
if (!requestFingerprint || !isB64uString(requestFingerprint) || !verified || !hasExactKeys(verified, [
|
|
180
182
|
"challengeId",
|
|
181
183
|
"challengeSubjectId",
|
|
182
184
|
"walletId",
|
|
@@ -284,11 +286,7 @@ function emailOtpRegistrationChallengeBindingMismatchCode(input) {
|
|
|
284
286
|
return null;
|
|
285
287
|
}
|
|
286
288
|
function emailOtpChallengeInvalidOrExpired() {
|
|
287
|
-
return
|
|
288
|
-
ok: false,
|
|
289
|
-
code: "challenge_expired_or_invalid",
|
|
290
|
-
message: "Email OTP challenge expired or invalid"
|
|
291
|
-
};
|
|
289
|
+
return failure("challenge_expired_or_invalid", "Email OTP challenge expired or invalid");
|
|
292
290
|
}
|
|
293
291
|
function emailOtpGrantRecord(input) {
|
|
294
292
|
return {
|
|
@@ -330,49 +328,21 @@ async function validateEmailOtpEnrollmentMaterial(input) {
|
|
|
330
328
|
const clientUnlockPublicKeyB64u = normalizeOptionalTrimmedString(input.material.clientUnlockPublicKeyB64u);
|
|
331
329
|
const unlockKeyVersion = normalizeOptionalTrimmedString(input.material.unlockKeyVersion);
|
|
332
330
|
const serverSealedFactorCiphertextB64u = normalizeOptionalTrimmedString(input.material.serverSealedFactorCiphertextB64u);
|
|
333
|
-
if (!enrollmentSealKeyVersion) return
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
};
|
|
338
|
-
if (!clientUnlockPublicKeyB64u) return {
|
|
339
|
-
ok: false,
|
|
340
|
-
code: "invalid_body",
|
|
341
|
-
message: "clientUnlockPublicKeyB64u is required"
|
|
342
|
-
};
|
|
343
|
-
if (!unlockKeyVersion) return {
|
|
344
|
-
ok: false,
|
|
345
|
-
code: "invalid_body",
|
|
346
|
-
message: "unlockKeyVersion is required"
|
|
347
|
-
};
|
|
348
|
-
if (!serverSealedFactorCiphertextB64u) return {
|
|
349
|
-
ok: false,
|
|
350
|
-
code: "invalid_body",
|
|
351
|
-
message: "serverSealedFactorCiphertextB64u is required"
|
|
352
|
-
};
|
|
331
|
+
if (!enrollmentSealKeyVersion) return failure("invalid_body", "enrollmentSealKeyVersion is required");
|
|
332
|
+
if (!clientUnlockPublicKeyB64u) return failure("invalid_body", "clientUnlockPublicKeyB64u is required");
|
|
333
|
+
if (!unlockKeyVersion) return failure("invalid_body", "unlockKeyVersion is required");
|
|
334
|
+
if (!serverSealedFactorCiphertextB64u) return failure("invalid_body", "serverSealedFactorCiphertextB64u is required");
|
|
353
335
|
let unlockPublicKeyBytes;
|
|
354
336
|
try {
|
|
355
337
|
unlockPublicKeyBytes = base64UrlDecode(clientUnlockPublicKeyB64u);
|
|
356
338
|
} catch {
|
|
357
|
-
return
|
|
358
|
-
ok: false,
|
|
359
|
-
code: "invalid_body",
|
|
360
|
-
message: "clientUnlockPublicKeyB64u must be valid base64url"
|
|
361
|
-
};
|
|
339
|
+
return failure("invalid_body", "clientUnlockPublicKeyB64u must be valid base64url");
|
|
362
340
|
}
|
|
363
|
-
if (unlockPublicKeyBytes.length !== 33) return
|
|
364
|
-
ok: false,
|
|
365
|
-
code: "invalid_body",
|
|
366
|
-
message: "clientUnlockPublicKeyB64u must decode to 33 bytes (compressed secp256k1 pubkey)"
|
|
367
|
-
};
|
|
341
|
+
if (unlockPublicKeyBytes.length !== 33) return failure("invalid_body", "clientUnlockPublicKeyB64u must decode to 33 bytes (compressed secp256k1 pubkey)");
|
|
368
342
|
try {
|
|
369
343
|
await input.validateSecp256k1PublicKey33(unlockPublicKeyBytes);
|
|
370
344
|
} catch {
|
|
371
|
-
return
|
|
372
|
-
ok: false,
|
|
373
|
-
code: "invalid_body",
|
|
374
|
-
message: "clientUnlockPublicKeyB64u is not a valid secp256k1 public key"
|
|
375
|
-
};
|
|
345
|
+
return failure("invalid_body", "clientUnlockPublicKeyB64u is not a valid secp256k1 public key");
|
|
376
346
|
}
|
|
377
347
|
return {
|
|
378
348
|
ok: true,
|
|
@@ -421,11 +391,6 @@ function optionalNonNegativeSafeIntegerField(record, field) {
|
|
|
421
391
|
function hasRecordField(record, field) {
|
|
422
392
|
return Object.prototype.hasOwnProperty.call(record, field);
|
|
423
393
|
}
|
|
424
|
-
function hasExactRecordFields(record, expectedFields) {
|
|
425
|
-
const actualFields = Object.keys(record).sort();
|
|
426
|
-
const expected = [...expectedFields].sort();
|
|
427
|
-
return actualFields.length === expected.length && actualFields.every((field, index) => field === expected[index]);
|
|
428
|
-
}
|
|
429
394
|
function patchedPositiveAuthStateValue(current, patch) {
|
|
430
395
|
if (patch === null) return void 0;
|
|
431
396
|
if (patch === void 0) return current;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { normalizeOptionalTrimmedString } from "../../../../shared-ts/src/utils/normalize.js";
|
|
2
2
|
import "../../../../shared-ts/src/utils/validation.js";
|
|
3
3
|
import { secureRandomBase64Url } from "../../../../shared-ts/src/utils/secureRandomId.js";
|
|
4
|
+
import { failedVerification, failure } from "../../../../shared-ts/src/utils/failure.js";
|
|
4
5
|
import { validateSecp256k1PublicKey33, verifySecp256k1RecoverableSignatureAgainstPublicKey33 } from "../../../../core/ThresholdService/evmCryptoWasm.js";
|
|
5
6
|
import { EMAIL_OTP_CHANNEL, WALLET_EMAIL_OTP_ACTIONS } from "../../../../shared-ts/src/utils/emailOtpDomain.js";
|
|
6
7
|
import { parseD1BoundaryWalletIdResult } from "../auth/d1RouterApiAuthBoundary.js";
|
|
@@ -61,32 +62,16 @@ function normalizeEmailOtpStrongAuthInput(input) {
|
|
|
61
62
|
};
|
|
62
63
|
}
|
|
63
64
|
function invalidEmailOtpEnrollmentReadBody(message) {
|
|
64
|
-
return
|
|
65
|
-
ok: false,
|
|
66
|
-
code: "invalid_body",
|
|
67
|
-
message
|
|
68
|
-
};
|
|
65
|
+
return failure("invalid_body", message);
|
|
69
66
|
}
|
|
70
67
|
function invalidActiveEmailOtpEnrollmentReadBody(message) {
|
|
71
|
-
return
|
|
72
|
-
ok: false,
|
|
73
|
-
code: "invalid_body",
|
|
74
|
-
message
|
|
75
|
-
};
|
|
68
|
+
return failure("invalid_body", message);
|
|
76
69
|
}
|
|
77
70
|
function invalidEmailOtpStrongAuthBody(message) {
|
|
78
|
-
return
|
|
79
|
-
ok: false,
|
|
80
|
-
code: "invalid_body",
|
|
81
|
-
message
|
|
82
|
-
};
|
|
71
|
+
return failure("invalid_body", message);
|
|
83
72
|
}
|
|
84
73
|
function emailOtpEnrollmentTenantMismatch() {
|
|
85
|
-
return
|
|
86
|
-
ok: false,
|
|
87
|
-
code: "tenant_scope_mismatch",
|
|
88
|
-
message: "Email OTP enrollment does not match the requested orgId"
|
|
89
|
-
};
|
|
74
|
+
return failure("tenant_scope_mismatch", "Email OTP enrollment does not match the requested orgId");
|
|
90
75
|
}
|
|
91
76
|
var CloudflareD1EmailOtpRecoveryService = class {
|
|
92
77
|
constructor(input) {
|
|
@@ -99,11 +84,7 @@ var CloudflareD1EmailOtpRecoveryService = class {
|
|
|
99
84
|
const parsed = normalizeEmailOtpEnrollmentReadInput(input);
|
|
100
85
|
if (!parsed.ok) return parsed.result;
|
|
101
86
|
const enrollment = await this.emailOtpEnrollments.readEnrollment(parsed.value.walletId);
|
|
102
|
-
if (!enrollment) return
|
|
103
|
-
ok: false,
|
|
104
|
-
code: "not_found",
|
|
105
|
-
message: "Email OTP enrollment not found"
|
|
106
|
-
};
|
|
87
|
+
if (!enrollment) return failure("not_found", "Email OTP enrollment not found");
|
|
107
88
|
if (enrollment.orgId !== parsed.value.orgId) return emailOtpEnrollmentTenantMismatch();
|
|
108
89
|
return {
|
|
109
90
|
ok: true,
|
|
@@ -118,11 +99,7 @@ var CloudflareD1EmailOtpRecoveryService = class {
|
|
|
118
99
|
orgId: parsed.value.orgId
|
|
119
100
|
});
|
|
120
101
|
if (!enrollment.ok) return enrollment;
|
|
121
|
-
if (parsed.value.providerUserId && enrollment.enrollment.providerUserId !== parsed.value.providerUserId) return
|
|
122
|
-
ok: false,
|
|
123
|
-
code: "provider_identity_mismatch",
|
|
124
|
-
message: "Email OTP enrollment does not match the requested provider user"
|
|
125
|
-
};
|
|
102
|
+
if (parsed.value.providerUserId && enrollment.enrollment.providerUserId !== parsed.value.providerUserId) return failure("provider_identity_mismatch", "Email OTP enrollment does not match the requested provider user");
|
|
126
103
|
return enrollment;
|
|
127
104
|
}
|
|
128
105
|
async isEmailOtpStrongAuthRequired(input) {
|
|
@@ -198,11 +175,7 @@ var CloudflareD1EmailOtpRecoveryService = class {
|
|
|
198
175
|
unlockKeyVersion: enrollment.enrollment.unlockKeyVersion
|
|
199
176
|
};
|
|
200
177
|
} catch (error) {
|
|
201
|
-
return
|
|
202
|
-
ok: false,
|
|
203
|
-
code: "internal",
|
|
204
|
-
message: errorMessage(error) || "Failed to create Email OTP unlock challenge"
|
|
205
|
-
};
|
|
178
|
+
return failure("internal", errorMessage(error) || "Failed to create Email OTP unlock challenge");
|
|
206
179
|
}
|
|
207
180
|
}
|
|
208
181
|
async verifyEmailOtpUnlockProof(input) {
|
|
@@ -210,31 +183,31 @@ var CloudflareD1EmailOtpRecoveryService = class {
|
|
|
210
183
|
const parsed = normalizeUnlockProofInput(input);
|
|
211
184
|
if (!parsed.ok) return parsed.result;
|
|
212
185
|
const challenge = await this.emailOtpChallenges.consumeUnlock(parsed.value.challengeId);
|
|
213
|
-
if (!challenge || Date.now() > challenge.expiresAtMs) return
|
|
214
|
-
if (challenge.walletId !== parsed.value.walletId) return
|
|
186
|
+
if (!challenge || Date.now() > challenge.expiresAtMs) return failedVerification("challenge_expired_or_invalid", "Email OTP unlock challenge expired or invalid");
|
|
187
|
+
if (challenge.walletId !== parsed.value.walletId) return failedVerification("challenge_binding_mismatch", "Email OTP unlock challenge is not valid for this walletId");
|
|
215
188
|
const enrollment = await this.readActiveEmailOtpEnrollment({
|
|
216
189
|
walletId: parsed.value.walletId,
|
|
217
190
|
orgId: parsed.value.orgId
|
|
218
191
|
});
|
|
219
|
-
if (!enrollment.ok) return
|
|
220
|
-
if (challenge.userId !== enrollment.enrollment.providerUserId || challenge.orgId !== enrollment.enrollment.orgId) return
|
|
192
|
+
if (!enrollment.ok) return failedVerification(enrollment.code, enrollment.message);
|
|
193
|
+
if (challenge.userId !== enrollment.enrollment.providerUserId || challenge.orgId !== enrollment.enrollment.orgId) return failedVerification("challenge_binding_mismatch", "Email OTP unlock challenge is not valid for this enrollment");
|
|
221
194
|
const publicKey = decodeFixedBase64Url(parsed.value.publicKeyB64u, 33);
|
|
222
|
-
if (!publicKey) return
|
|
195
|
+
if (!publicKey) return failedVerification("invalid_body", "unlockProof.publicKey must decode to 33 bytes");
|
|
223
196
|
try {
|
|
224
197
|
await validateSecp256k1PublicKey33(publicKey);
|
|
225
198
|
} catch {
|
|
226
|
-
return
|
|
199
|
+
return failedVerification("invalid_body", "unlockProof.publicKey is not a valid secp256k1 public key");
|
|
227
200
|
}
|
|
228
201
|
const signature = decodeFixedBase64Url(parsed.value.signatureB64u, 65);
|
|
229
|
-
if (!signature) return
|
|
202
|
+
if (!signature) return failedVerification("invalid_body", "unlockProof.signature must decode to 65 bytes");
|
|
230
203
|
const enrolledPublicKey = decodeFixedBase64Url(enrollment.enrollment.clientUnlockPublicKeyB64u, 33);
|
|
231
|
-
if (!enrolledPublicKey || !bytesEqual(enrolledPublicKey, publicKey)) return
|
|
204
|
+
if (!enrolledPublicKey || !bytesEqual(enrolledPublicKey, publicKey)) return failedVerification("invalid_unlock_proof", "unlockProof.publicKey does not match the enrolled clientUnlockPublicKeyB64u");
|
|
232
205
|
const challengeDigest = decodeFixedBase64Url(challenge.challengeB64u, 32);
|
|
233
|
-
if (!challengeDigest) return
|
|
206
|
+
if (!challengeDigest) return failedVerification("internal", "Stored unlock challenge digest must decode to 32 bytes");
|
|
234
207
|
try {
|
|
235
208
|
await verifySecp256k1RecoverableSignatureAgainstPublicKey33(challengeDigest, signature, publicKey);
|
|
236
209
|
} catch {
|
|
237
|
-
return
|
|
210
|
+
return failedVerification("invalid_unlock_proof", "unlockProof.signature did not verify against unlockProof.publicKey");
|
|
238
211
|
}
|
|
239
212
|
await this.emailOtpEnrollments.putAuthStateForEnrollment(enrollment.enrollment, { lastEmailOtpLoginAtMs: Date.now() });
|
|
240
213
|
return {
|
|
@@ -249,12 +222,7 @@ var CloudflareD1EmailOtpRecoveryService = class {
|
|
|
249
222
|
unlockKeyVersion: enrollment.enrollment.unlockKeyVersion
|
|
250
223
|
};
|
|
251
224
|
} catch (error) {
|
|
252
|
-
return
|
|
253
|
-
ok: false,
|
|
254
|
-
verified: false,
|
|
255
|
-
code: "internal",
|
|
256
|
-
message: errorMessage(error) || "Failed to verify Email OTP unlock proof"
|
|
257
|
-
};
|
|
225
|
+
return failedVerification("internal", errorMessage(error) || "Failed to verify Email OTP unlock proof");
|
|
258
226
|
}
|
|
259
227
|
}
|
|
260
228
|
async consumeEmailOtpGrant(input) {
|
|
@@ -279,11 +247,7 @@ var CloudflareD1EmailOtpRecoveryService = class {
|
|
|
279
247
|
otpChannel: EMAIL_OTP_CHANNEL
|
|
280
248
|
};
|
|
281
249
|
} catch (error) {
|
|
282
|
-
return
|
|
283
|
-
ok: false,
|
|
284
|
-
code: "internal",
|
|
285
|
-
message: errorMessage(error) || "Failed to consume Email OTP grant"
|
|
286
|
-
};
|
|
250
|
+
return failure("internal", errorMessage(error) || "Failed to consume Email OTP grant");
|
|
287
251
|
}
|
|
288
252
|
}
|
|
289
253
|
};
|
|
@@ -353,48 +317,23 @@ function emailOtpGrantBindingMismatch(record, input) {
|
|
|
353
317
|
function invalidUnlockChallengeBody(message) {
|
|
354
318
|
return {
|
|
355
319
|
ok: false,
|
|
356
|
-
result:
|
|
357
|
-
ok: false,
|
|
358
|
-
code: "invalid_body",
|
|
359
|
-
message
|
|
360
|
-
}
|
|
320
|
+
result: failure("invalid_body", message)
|
|
361
321
|
};
|
|
362
322
|
}
|
|
363
323
|
function invalidUnlockProofBody(message) {
|
|
364
324
|
return {
|
|
365
325
|
ok: false,
|
|
366
|
-
result:
|
|
367
|
-
ok: false,
|
|
368
|
-
verified: false,
|
|
369
|
-
code: "invalid_body",
|
|
370
|
-
message
|
|
371
|
-
}
|
|
326
|
+
result: failedVerification("invalid_body", message)
|
|
372
327
|
};
|
|
373
328
|
}
|
|
374
329
|
function invalidGrantConsumptionBody(message) {
|
|
375
330
|
return {
|
|
376
331
|
ok: false,
|
|
377
|
-
result:
|
|
378
|
-
ok: false,
|
|
379
|
-
code: "invalid_body",
|
|
380
|
-
message
|
|
381
|
-
}
|
|
332
|
+
result: failure("invalid_body", message)
|
|
382
333
|
};
|
|
383
334
|
}
|
|
384
335
|
function emailOtpGrantInvalidOrExpired() {
|
|
385
|
-
return
|
|
386
|
-
ok: false,
|
|
387
|
-
code: "grant_invalid_or_expired",
|
|
388
|
-
message: "Email OTP grant is invalid or expired"
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
function emailOtpUnlockProofRejected(code, message) {
|
|
392
|
-
return {
|
|
393
|
-
ok: false,
|
|
394
|
-
verified: false,
|
|
395
|
-
code,
|
|
396
|
-
message
|
|
397
|
-
};
|
|
336
|
+
return failure("grant_invalid_or_expired", "Email OTP grant is invalid or expired");
|
|
398
337
|
}
|
|
399
338
|
//#endregion
|
|
400
339
|
export { CloudflareD1EmailOtpRecoveryService };
|