@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 { parseChallengeSubjectId, parseEmailOtpChallengeId, parseOrgId, parseWalletId } from "../../shared-ts/src/utils/domainIds.js";
|
|
2
2
|
import { normalizeOptionalTrimmedString } from "../../shared-ts/src/utils/normalize.js";
|
|
3
3
|
import "../../shared-ts/src/utils/validation.js";
|
|
4
|
+
import { failure } from "../../shared-ts/src/utils/failure.js";
|
|
4
5
|
import { errorMessage } from "../../shared-ts/src/utils/errors.js";
|
|
5
6
|
import { EMAIL_OTP_CHANNEL, WALLET_EMAIL_OTP_ACTIONS } from "../../shared-ts/src/utils/emailOtpDomain.js";
|
|
6
7
|
import { pruneExpiredEmailOtpChallengesWithStore } from "./emailOtpChallenges.js";
|
|
@@ -19,11 +20,7 @@ async function verifyEmailOtpChallengeCode(input) {
|
|
|
19
20
|
const clientIp = normalizeOptionalTrimmedString(request.clientIp) || void 0;
|
|
20
21
|
const expectedAction = request.expectedAction;
|
|
21
22
|
const expectedOperation = request.expectedOperation;
|
|
22
|
-
if (expectedAction === WALLET_EMAIL_OTP_ACTIONS.registration && !request.registrationChallengeProof) return
|
|
23
|
-
ok: false,
|
|
24
|
-
code: "invalid_body",
|
|
25
|
-
message: "Email OTP registration verification requires registration challenge proof"
|
|
26
|
-
};
|
|
23
|
+
if (expectedAction === WALLET_EMAIL_OTP_ACTIONS.registration && !request.registrationChallengeProof) return failure("invalid_body", "Email OTP registration verification requires registration challenge proof");
|
|
27
24
|
const verificationIntent = emailOtpChallengeVerificationIntentFromRequest({
|
|
28
25
|
expectedAction,
|
|
29
26
|
...expectedOperation ? { expectedOperation } : {},
|
|
@@ -31,56 +28,16 @@ async function verifyEmailOtpChallengeCode(input) {
|
|
|
31
28
|
...request.allowRegistrationChallengeReroll ? { allowRegistrationChallengeReroll: true } : {}
|
|
32
29
|
});
|
|
33
30
|
const expectedPurpose = expectedEmailOtpStoredChallengePurpose(verificationIntent);
|
|
34
|
-
if (!challengeSubjectId.ok) return
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (!orgId.ok) return {
|
|
45
|
-
ok: false,
|
|
46
|
-
code: "invalid_body",
|
|
47
|
-
message: "Missing orgId"
|
|
48
|
-
};
|
|
49
|
-
if (!challengeId.ok) return {
|
|
50
|
-
ok: false,
|
|
51
|
-
code: "invalid_body",
|
|
52
|
-
message: "Missing challengeId"
|
|
53
|
-
};
|
|
54
|
-
if (request.registrationChallengeProof && request.registrationChallengeProof.challengeId !== challengeId.value) return {
|
|
55
|
-
ok: false,
|
|
56
|
-
code: "challenge_id_mismatch",
|
|
57
|
-
message: "Email OTP registration proof does not match challengeId"
|
|
58
|
-
};
|
|
59
|
-
if (request.registrationChallengeProof && request.registrationChallengeProof.finalWalletId !== walletId.value) return {
|
|
60
|
-
ok: false,
|
|
61
|
-
code: "challenge_wallet_mismatch",
|
|
62
|
-
message: "Email OTP registration proof does not match walletId"
|
|
63
|
-
};
|
|
64
|
-
if (request.registrationChallengeProof && request.registrationChallengeProof.orgId !== orgId.value) return {
|
|
65
|
-
ok: false,
|
|
66
|
-
code: "challenge_org_mismatch",
|
|
67
|
-
message: "Email OTP registration proof does not match orgId"
|
|
68
|
-
};
|
|
69
|
-
if (!otpCode) return {
|
|
70
|
-
ok: false,
|
|
71
|
-
code: "invalid_body",
|
|
72
|
-
message: "Missing otpCode"
|
|
73
|
-
};
|
|
74
|
-
if (otpChannel !== "email_otp") return {
|
|
75
|
-
ok: false,
|
|
76
|
-
code: "invalid_body",
|
|
77
|
-
message: "otpChannel must be email_otp"
|
|
78
|
-
};
|
|
79
|
-
if (!ownerProofBindingDigest) return {
|
|
80
|
-
ok: false,
|
|
81
|
-
code: "invalid_body",
|
|
82
|
-
message: "Missing ownerProofBindingDigest"
|
|
83
|
-
};
|
|
31
|
+
if (!challengeSubjectId.ok) return failure("invalid_body", "Missing challengeSubjectId");
|
|
32
|
+
if (!walletId.ok) return failure("invalid_body", "Missing walletId");
|
|
33
|
+
if (!orgId.ok) return failure("invalid_body", "Missing orgId");
|
|
34
|
+
if (!challengeId.ok) return failure("invalid_body", "Missing challengeId");
|
|
35
|
+
if (request.registrationChallengeProof && request.registrationChallengeProof.challengeId !== challengeId.value) return failure("challenge_id_mismatch", "Email OTP registration proof does not match challengeId");
|
|
36
|
+
if (request.registrationChallengeProof && request.registrationChallengeProof.finalWalletId !== walletId.value) return failure("challenge_wallet_mismatch", "Email OTP registration proof does not match walletId");
|
|
37
|
+
if (request.registrationChallengeProof && request.registrationChallengeProof.orgId !== orgId.value) return failure("challenge_org_mismatch", "Email OTP registration proof does not match orgId");
|
|
38
|
+
if (!otpCode) return failure("invalid_body", "Missing otpCode");
|
|
39
|
+
if (otpChannel !== "email_otp") return failure("invalid_body", "otpChannel must be email_otp");
|
|
40
|
+
if (!ownerProofBindingDigest) return failure("invalid_body", "Missing ownerProofBindingDigest");
|
|
84
41
|
const rateLimit = await input.consumeRateLimit({
|
|
85
42
|
scope: "verify",
|
|
86
43
|
action: expectedAction,
|
|
@@ -96,11 +53,7 @@ async function verifyEmailOtpChallengeCode(input) {
|
|
|
96
53
|
}) : null;
|
|
97
54
|
if (activeEnrollment && !activeEnrollment.ok) return activeEnrollment;
|
|
98
55
|
const enrollment = activeEnrollment?.ok ? activeEnrollment.enrollment : await input.walletEnrollmentStore.get(walletId.value);
|
|
99
|
-
if (enrollment && enrollment.orgId !== orgId.value) return
|
|
100
|
-
ok: false,
|
|
101
|
-
code: "tenant_scope_mismatch",
|
|
102
|
-
message: "Email OTP enrollment does not match the requested orgId"
|
|
103
|
-
};
|
|
56
|
+
if (enrollment && enrollment.orgId !== orgId.value) return failure("tenant_scope_mismatch", "Email OTP enrollment does not match the requested orgId");
|
|
104
57
|
const authStateResult = enrollment ? await input.readEnrollmentAuthState(enrollment) : {
|
|
105
58
|
ok: true,
|
|
106
59
|
state: null
|
|
@@ -142,21 +95,13 @@ async function verifyEmailOtpChallengeCode(input) {
|
|
|
142
95
|
otpChannel: EMAIL_OTP_CHANNEL,
|
|
143
96
|
action: expectedAction
|
|
144
97
|
});
|
|
145
|
-
return
|
|
146
|
-
ok: false,
|
|
147
|
-
code: "challenge_expired_or_invalid",
|
|
148
|
-
message: "Email OTP challenge expired or invalid"
|
|
149
|
-
};
|
|
98
|
+
return failure("challenge_expired_or_invalid", "Email OTP challenge expired or invalid");
|
|
150
99
|
}
|
|
151
100
|
}
|
|
152
101
|
if (nowMs > record.expiresAtMs) {
|
|
153
102
|
await challengeStore.del(record.challengeId);
|
|
154
103
|
input.memoryOutbox.delete(record.challengeId);
|
|
155
|
-
return
|
|
156
|
-
ok: false,
|
|
157
|
-
code: "challenge_expired_or_invalid",
|
|
158
|
-
message: "Email OTP challenge expired or invalid"
|
|
159
|
-
};
|
|
104
|
+
return failure("challenge_expired_or_invalid", "Email OTP challenge expired or invalid");
|
|
160
105
|
}
|
|
161
106
|
const storedPurpose = readEmailOtpStoredChallengePurpose(record);
|
|
162
107
|
const purposeMatches = emailOtpStoredChallengePurposeMatches({
|
|
@@ -205,11 +150,7 @@ async function verifyEmailOtpChallengeCode(input) {
|
|
|
205
150
|
expectedPurpose,
|
|
206
151
|
storedPurpose
|
|
207
152
|
});
|
|
208
|
-
return
|
|
209
|
-
ok: false,
|
|
210
|
-
code: mismatchCode,
|
|
211
|
-
message: "Email OTP challenge is not valid for the current owner proof binding"
|
|
212
|
-
};
|
|
153
|
+
return failure(mismatchCode, "Email OTP challenge is not valid for the current owner proof binding");
|
|
213
154
|
}
|
|
214
155
|
if (registrationChallengeCanFollowReroll) input.logger.info("[email-otp] registration reroll challenge validation", {
|
|
215
156
|
challengeId: record.challengeId,
|
|
@@ -283,11 +224,7 @@ async function verifyEmailOtpChallengeCode(input) {
|
|
|
283
224
|
});
|
|
284
225
|
}
|
|
285
226
|
const verifiedChallengeId = parseEmailOtpChallengeId(record.challengeId);
|
|
286
|
-
if (!verifiedChallengeId.ok) return
|
|
287
|
-
ok: false,
|
|
288
|
-
code: "internal",
|
|
289
|
-
message: "Email OTP challenge record has an invalid challenge id"
|
|
290
|
-
};
|
|
227
|
+
if (!verifiedChallengeId.ok) return failure("internal", "Email OTP challenge record has an invalid challenge id");
|
|
291
228
|
const successBase = {
|
|
292
229
|
challengeId: verifiedChallengeId.value,
|
|
293
230
|
challengeSubjectId: challengeSubjectId.value,
|
|
@@ -304,11 +241,7 @@ async function verifyEmailOtpChallengeCode(input) {
|
|
|
304
241
|
storedPurpose: readEmailOtpStoredChallengePurpose(record),
|
|
305
242
|
allowWalletReroll: verificationIntent.allowWalletReroll
|
|
306
243
|
});
|
|
307
|
-
if (!finalRegistrationChallengeProof) return
|
|
308
|
-
ok: false,
|
|
309
|
-
code: "challenge_purpose_mismatch",
|
|
310
|
-
message: "Email OTP challenge is not valid for registration"
|
|
311
|
-
};
|
|
244
|
+
if (!finalRegistrationChallengeProof) return failure("challenge_purpose_mismatch", "Email OTP challenge is not valid for registration");
|
|
312
245
|
return {
|
|
313
246
|
ok: true,
|
|
314
247
|
...successBase,
|
|
@@ -322,11 +255,7 @@ async function verifyEmailOtpChallengeCode(input) {
|
|
|
322
255
|
intent: verificationIntent.kind
|
|
323
256
|
};
|
|
324
257
|
} catch (e) {
|
|
325
|
-
return
|
|
326
|
-
ok: false,
|
|
327
|
-
code: "internal",
|
|
328
|
-
message: errorMessage(e) || "Failed to verify Email OTP challenge"
|
|
329
|
-
};
|
|
258
|
+
return failure("internal", errorMessage(e) || "Failed to verify Email OTP challenge");
|
|
330
259
|
}
|
|
331
260
|
}
|
|
332
261
|
//#endregion
|
|
@@ -2,6 +2,7 @@ import { base64UrlEncode } 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 { failure } from "../../shared-ts/src/utils/failure.js";
|
|
5
6
|
import { errorMessage } from "../../shared-ts/src/utils/errors.js";
|
|
6
7
|
import { EMAIL_OTP_CHANNEL, WALLET_EMAIL_OTP_ACTIONS, WALLET_EMAIL_OTP_REGISTRATION_OPERATION, WALLET_EMAIL_OTP_UNLOCK_OPERATION, isWalletEmailOtpLoginOperation } from "../../shared-ts/src/utils/emailOtpDomain.js";
|
|
7
8
|
import { randomNumericCode } from "./bytes.js";
|
|
@@ -70,31 +71,11 @@ async function createEmailOtpChallengeWithAction(input) {
|
|
|
70
71
|
action,
|
|
71
72
|
operationRaw: normalizeOptionalTrimmedString(request.operation)
|
|
72
73
|
});
|
|
73
|
-
if (!challengeSubjectId) return
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (!walletId) return {
|
|
79
|
-
ok: false,
|
|
80
|
-
code: "invalid_body",
|
|
81
|
-
message: "Missing walletId"
|
|
82
|
-
};
|
|
83
|
-
if (!orgId) return {
|
|
84
|
-
ok: false,
|
|
85
|
-
code: "invalid_body",
|
|
86
|
-
message: "Missing orgId"
|
|
87
|
-
};
|
|
88
|
-
if (otpChannel !== "email_otp") return {
|
|
89
|
-
ok: false,
|
|
90
|
-
code: "invalid_body",
|
|
91
|
-
message: "otpChannel must be email_otp"
|
|
92
|
-
};
|
|
93
|
-
if (!ownerProofBindingDigest) return {
|
|
94
|
-
ok: false,
|
|
95
|
-
code: "invalid_body",
|
|
96
|
-
message: "Missing ownerProofBindingDigest"
|
|
97
|
-
};
|
|
74
|
+
if (!challengeSubjectId) return failure("invalid_body", "Missing challengeSubjectId");
|
|
75
|
+
if (!walletId) return failure("invalid_body", "Missing walletId");
|
|
76
|
+
if (!orgId) return failure("invalid_body", "Missing orgId");
|
|
77
|
+
if (otpChannel !== "email_otp") return failure("invalid_body", "otpChannel must be email_otp");
|
|
78
|
+
if (!ownerProofBindingDigest) return failure("invalid_body", "Missing ownerProofBindingDigest");
|
|
98
79
|
const activeEnrollment = action !== WALLET_EMAIL_OTP_ACTIONS.registration ? await input.readActiveEnrollment({
|
|
99
80
|
walletId,
|
|
100
81
|
orgId
|
|
@@ -108,11 +89,7 @@ async function createEmailOtpChallengeWithAction(input) {
|
|
|
108
89
|
if (!existingAuthStateResult.ok) return existingAuthStateResult;
|
|
109
90
|
const existingAuthState = existingAuthStateResult.state;
|
|
110
91
|
const challengeEmail = action === WALLET_EMAIL_OTP_ACTIONS.registration ? email : existingEnrollment?.verifiedEmail || "";
|
|
111
|
-
if (!challengeEmail) return
|
|
112
|
-
ok: false,
|
|
113
|
-
code: "recovery_email_missing",
|
|
114
|
-
message: "Authenticated identity does not include a recovery email"
|
|
115
|
-
};
|
|
92
|
+
if (!challengeEmail) return failure("recovery_email_missing", "Authenticated identity does not include a recovery email");
|
|
116
93
|
if (existingAuthState?.otpLockedUntilMs && existingAuthState.otpLockedUntilMs > Date.now()) return {
|
|
117
94
|
ok: false,
|
|
118
95
|
code: "otp_locked_out",
|
|
@@ -163,11 +140,7 @@ async function createEmailOtpChallengeWithAction(input) {
|
|
|
163
140
|
clientIp
|
|
164
141
|
});
|
|
165
142
|
if (!rateLimit.ok) return rateLimit;
|
|
166
|
-
if (typeof crypto === "undefined" || typeof crypto.getRandomValues !== "function") return
|
|
167
|
-
ok: false,
|
|
168
|
-
code: "unsupported",
|
|
169
|
-
message: "crypto.getRandomValues is unavailable in this runtime"
|
|
170
|
-
};
|
|
143
|
+
if (typeof crypto === "undefined" || typeof crypto.getRandomValues !== "function") return failure("unsupported", "crypto.getRandomValues is unavailable in this runtime");
|
|
171
144
|
const otpConfig = input.resolveConfig();
|
|
172
145
|
const expiresAtMs = issuedAtMs + otpConfig.challengeTtlMs;
|
|
173
146
|
const challengeId = base64UrlEncode(crypto.getRandomValues(new Uint8Array(16)));
|
|
@@ -205,11 +178,7 @@ async function createEmailOtpChallengeWithAction(input) {
|
|
|
205
178
|
maxAttempts: otpConfig.maxAttempts
|
|
206
179
|
};
|
|
207
180
|
await input.challengeStore.put(challengeRecord);
|
|
208
|
-
if (!await input.challengeStore.get(challengeId)) return
|
|
209
|
-
ok: false,
|
|
210
|
-
code: "internal",
|
|
211
|
-
message: "Email OTP challenge could not be persisted"
|
|
212
|
-
};
|
|
181
|
+
if (!await input.challengeStore.get(challengeId)) return failure("internal", "Email OTP challenge could not be persisted");
|
|
213
182
|
const delivery = await input.deliverCode({
|
|
214
183
|
challengeId,
|
|
215
184
|
walletId,
|
|
@@ -247,11 +216,7 @@ async function createEmailOtpChallengeWithAction(input) {
|
|
|
247
216
|
}
|
|
248
217
|
};
|
|
249
218
|
} catch (e) {
|
|
250
|
-
return
|
|
251
|
-
ok: false,
|
|
252
|
-
code: "internal",
|
|
253
|
-
message: errorMessage(e) || "Failed to create Email OTP challenge"
|
|
254
|
-
};
|
|
219
|
+
return failure("internal", errorMessage(e) || "Failed to create Email OTP challenge");
|
|
255
220
|
}
|
|
256
221
|
}
|
|
257
222
|
//#endregion
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { normalizeOptionalTrimmedString } from "../../shared-ts/src/utils/normalize.js";
|
|
2
2
|
import "../../shared-ts/src/utils/validation.js";
|
|
3
|
+
import { failure } from "../../shared-ts/src/utils/failure.js";
|
|
3
4
|
//#region src/core/authService/emailOtpDelivery.ts
|
|
4
5
|
function logDevelopmentOtpCode(input) {
|
|
5
6
|
input.logger.warn("[email-otp] development OTP code", {
|
|
@@ -42,17 +43,9 @@ function logDevelopmentOtpDelivery(input) {
|
|
|
42
43
|
});
|
|
43
44
|
}
|
|
44
45
|
async function deliverEmailOtpCode(input) {
|
|
45
|
-
if (input.production && input.config.deliveryMode !== "email_provider") return {
|
|
46
|
-
ok: false,
|
|
47
|
-
code: "email_otp_delivery_not_allowed",
|
|
48
|
-
message: `Email OTP delivery mode ${input.config.deliveryMode} is disabled in production`
|
|
49
|
-
};
|
|
46
|
+
if (input.production && input.config.deliveryMode !== "email_provider") return failure("email_otp_delivery_not_allowed", `Email OTP delivery mode ${input.config.deliveryMode} is disabled in production`);
|
|
50
47
|
const emailHint = input.email;
|
|
51
|
-
if (input.config.deliveryMode === "email_provider") return
|
|
52
|
-
ok: false,
|
|
53
|
-
code: "not_implemented",
|
|
54
|
-
message: "Email OTP email_provider delivery is not implemented yet"
|
|
55
|
-
};
|
|
48
|
+
if (input.config.deliveryMode === "email_provider") return failure("not_implemented", "Email OTP email_provider delivery is not implemented yet");
|
|
56
49
|
if (input.config.deliveryMode === "memory") {
|
|
57
50
|
storeMemoryOtp({
|
|
58
51
|
memoryOutbox: input.memoryOutbox,
|
|
@@ -110,47 +103,19 @@ async function deliverEmailOtpCode(input) {
|
|
|
110
103
|
};
|
|
111
104
|
}
|
|
112
105
|
function readEmailOtpOutboxEntry(input) {
|
|
113
|
-
if (!input.config.devOutboxEnabled) return
|
|
114
|
-
ok: false,
|
|
115
|
-
code: "not_found",
|
|
116
|
-
message: "Email OTP dev outbox is not enabled"
|
|
117
|
-
};
|
|
106
|
+
if (!input.config.devOutboxEnabled) return failure("not_found", "Email OTP dev outbox is not enabled");
|
|
118
107
|
const challengeId = normalizeOptionalTrimmedString(input.request.challengeId);
|
|
119
108
|
const userId = normalizeOptionalTrimmedString(input.request.userId);
|
|
120
109
|
const walletId = normalizeOptionalTrimmedString(input.request.walletId);
|
|
121
|
-
if (!challengeId) return
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
message: "Missing challengeId"
|
|
125
|
-
};
|
|
126
|
-
if (!userId) return {
|
|
127
|
-
ok: false,
|
|
128
|
-
code: "invalid_body",
|
|
129
|
-
message: "Missing userId"
|
|
130
|
-
};
|
|
131
|
-
if (!walletId) return {
|
|
132
|
-
ok: false,
|
|
133
|
-
code: "invalid_body",
|
|
134
|
-
message: "Missing walletId"
|
|
135
|
-
};
|
|
110
|
+
if (!challengeId) return failure("invalid_body", "Missing challengeId");
|
|
111
|
+
if (!userId) return failure("invalid_body", "Missing userId");
|
|
112
|
+
if (!walletId) return failure("invalid_body", "Missing walletId");
|
|
136
113
|
const entry = input.memoryOutbox.get(challengeId);
|
|
137
|
-
if (!entry) return
|
|
138
|
-
|
|
139
|
-
code: "not_found",
|
|
140
|
-
message: "Email OTP outbox entry was not found"
|
|
141
|
-
};
|
|
142
|
-
if (entry.userId !== userId || entry.walletId !== walletId) return {
|
|
143
|
-
ok: false,
|
|
144
|
-
code: "not_found",
|
|
145
|
-
message: "Email OTP outbox entry was not found"
|
|
146
|
-
};
|
|
114
|
+
if (!entry) return failure("not_found", "Email OTP outbox entry was not found");
|
|
115
|
+
if (entry.userId !== userId || entry.walletId !== walletId) return failure("not_found", "Email OTP outbox entry was not found");
|
|
147
116
|
if (input.nowMs > entry.expiresAtMs) {
|
|
148
117
|
input.memoryOutbox.delete(challengeId);
|
|
149
|
-
return
|
|
150
|
-
ok: false,
|
|
151
|
-
code: "not_found",
|
|
152
|
-
message: "Email OTP outbox entry expired"
|
|
153
|
-
};
|
|
118
|
+
return failure("not_found", "Email OTP outbox entry expired");
|
|
154
119
|
}
|
|
155
120
|
return {
|
|
156
121
|
ok: true,
|
|
@@ -1,30 +1,15 @@
|
|
|
1
1
|
import { normalizeOptionalTrimmedString } from "../../shared-ts/src/utils/normalize.js";
|
|
2
2
|
import "../../shared-ts/src/utils/validation.js";
|
|
3
|
+
import { failure } from "../../shared-ts/src/utils/failure.js";
|
|
3
4
|
//#region src/core/authService/emailOtpEnrollment.ts
|
|
4
5
|
async function readEmailOtpEnrollmentWithStore(input) {
|
|
5
6
|
const walletId = normalizeOptionalTrimmedString(input.request.walletId);
|
|
6
7
|
const orgId = normalizeOptionalTrimmedString(input.request.orgId);
|
|
7
|
-
if (!walletId) return
|
|
8
|
-
|
|
9
|
-
code: "invalid_body",
|
|
10
|
-
message: "Missing walletId"
|
|
11
|
-
};
|
|
12
|
-
if (!orgId) return {
|
|
13
|
-
ok: false,
|
|
14
|
-
code: "invalid_body",
|
|
15
|
-
message: "Missing orgId"
|
|
16
|
-
};
|
|
8
|
+
if (!walletId) return failure("invalid_body", "Missing walletId");
|
|
9
|
+
if (!orgId) return failure("invalid_body", "Missing orgId");
|
|
17
10
|
const enrollment = await input.walletEnrollmentStore.get(walletId);
|
|
18
|
-
if (!enrollment) return
|
|
19
|
-
|
|
20
|
-
code: "not_found",
|
|
21
|
-
message: "Email OTP enrollment not found"
|
|
22
|
-
};
|
|
23
|
-
if (enrollment.orgId !== orgId) return {
|
|
24
|
-
ok: false,
|
|
25
|
-
code: "tenant_scope_mismatch",
|
|
26
|
-
message: "Email OTP enrollment does not match the requested orgId"
|
|
27
|
-
};
|
|
11
|
+
if (!enrollment) return failure("not_found", "Email OTP enrollment not found");
|
|
12
|
+
if (enrollment.orgId !== orgId) return failure("tenant_scope_mismatch", "Email OTP enrollment does not match the requested orgId");
|
|
28
13
|
return {
|
|
29
14
|
ok: true,
|
|
30
15
|
enrollment
|
|
@@ -34,11 +19,7 @@ async function readActiveEmailOtpEnrollmentWithStore(input) {
|
|
|
34
19
|
const result = await readEmailOtpEnrollmentWithStore(input);
|
|
35
20
|
if (!result.ok) return result;
|
|
36
21
|
const providerUserId = normalizeOptionalTrimmedString(input.request.providerUserId);
|
|
37
|
-
if (providerUserId && result.enrollment.providerUserId !== providerUserId) return
|
|
38
|
-
ok: false,
|
|
39
|
-
code: "provider_identity_mismatch",
|
|
40
|
-
message: "Email OTP enrollment does not match the requested provider user"
|
|
41
|
-
};
|
|
22
|
+
if (providerUserId && result.enrollment.providerUserId !== providerUserId) return failure("provider_identity_mismatch", "Email OTP enrollment does not match the requested provider user");
|
|
42
23
|
return result;
|
|
43
24
|
}
|
|
44
25
|
async function readEmailOtpAuthStateForEnrollmentWithStore(input) {
|
|
@@ -47,11 +28,7 @@ async function readEmailOtpAuthStateForEnrollmentWithStore(input) {
|
|
|
47
28
|
ok: true,
|
|
48
29
|
state: null
|
|
49
30
|
};
|
|
50
|
-
if (state.orgId !== input.enrollment.orgId || state.providerUserId !== input.enrollment.providerUserId) return
|
|
51
|
-
ok: false,
|
|
52
|
-
code: "auth_state_enrollment_mismatch",
|
|
53
|
-
message: "Email OTP auth state does not match the active enrollment"
|
|
54
|
-
};
|
|
31
|
+
if (state.orgId !== input.enrollment.orgId || state.providerUserId !== input.enrollment.providerUserId) return failure("auth_state_enrollment_mismatch", "Email OTP auth state does not match the active enrollment");
|
|
55
32
|
return {
|
|
56
33
|
ok: true,
|
|
57
34
|
state
|
|
@@ -79,11 +56,7 @@ async function putEmailOtpAuthStateForEnrollmentWithStore(input) {
|
|
|
79
56
|
}
|
|
80
57
|
async function isEmailOtpStrongAuthRequiredWithStores(input) {
|
|
81
58
|
const walletId = normalizeOptionalTrimmedString(input.request.walletId);
|
|
82
|
-
if (!walletId) return
|
|
83
|
-
ok: false,
|
|
84
|
-
code: "invalid_body",
|
|
85
|
-
message: "Missing walletId"
|
|
86
|
-
};
|
|
59
|
+
if (!walletId) return failure("invalid_body", "Missing walletId");
|
|
87
60
|
const enrollment = await input.walletEnrollmentStore.get(walletId);
|
|
88
61
|
if (!enrollment) return {
|
|
89
62
|
ok: true,
|
|
@@ -113,11 +86,7 @@ async function isEmailOtpStrongAuthRequiredWithStores(input) {
|
|
|
113
86
|
}
|
|
114
87
|
async function markEmailOtpStrongAuthSatisfiedWithStores(input) {
|
|
115
88
|
const walletId = normalizeOptionalTrimmedString(input.request.walletId);
|
|
116
|
-
if (!walletId) return
|
|
117
|
-
ok: false,
|
|
118
|
-
code: "invalid_body",
|
|
119
|
-
message: "Missing walletId"
|
|
120
|
-
};
|
|
89
|
+
if (!walletId) return failure("invalid_body", "Missing walletId");
|
|
121
90
|
const enrollment = await input.walletEnrollmentStore.get(walletId);
|
|
122
91
|
if (!enrollment) return {
|
|
123
92
|
ok: true,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { normalizeOptionalTrimmedString } from "../../shared-ts/src/utils/normalize.js";
|
|
2
2
|
import "../../shared-ts/src/utils/validation.js";
|
|
3
|
+
import { failure } from "../../shared-ts/src/utils/failure.js";
|
|
3
4
|
import { errorMessage } from "../../shared-ts/src/utils/errors.js";
|
|
4
5
|
import { EMAIL_OTP_CHANNEL, WALLET_EMAIL_OTP_ACTIONS } from "../../shared-ts/src/utils/emailOtpDomain.js";
|
|
5
6
|
//#region src/core/authService/emailOtpGrant.ts
|
|
@@ -11,31 +12,11 @@ async function consumeEmailOtpGrantWithStore(input) {
|
|
|
11
12
|
const orgId = normalizeOptionalTrimmedString(input.request.orgId) || "";
|
|
12
13
|
const otpChannel = normalizeOptionalTrimmedString(input.request.otpChannel);
|
|
13
14
|
const clientIp = normalizeOptionalTrimmedString(input.request.clientIp) || void 0;
|
|
14
|
-
if (!loginGrant) return
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (!userId) return {
|
|
20
|
-
ok: false,
|
|
21
|
-
code: "invalid_body",
|
|
22
|
-
message: "Missing userId"
|
|
23
|
-
};
|
|
24
|
-
if (!walletId) return {
|
|
25
|
-
ok: false,
|
|
26
|
-
code: "invalid_body",
|
|
27
|
-
message: "Missing walletId"
|
|
28
|
-
};
|
|
29
|
-
if (!orgId) return {
|
|
30
|
-
ok: false,
|
|
31
|
-
code: "invalid_body",
|
|
32
|
-
message: "Missing orgId"
|
|
33
|
-
};
|
|
34
|
-
if (otpChannel !== "email_otp") return {
|
|
35
|
-
ok: false,
|
|
36
|
-
code: "invalid_body",
|
|
37
|
-
message: "otpChannel must be email_otp"
|
|
38
|
-
};
|
|
15
|
+
if (!loginGrant) return failure("invalid_body", "Missing loginGrant");
|
|
16
|
+
if (!userId) return failure("invalid_body", "Missing userId");
|
|
17
|
+
if (!walletId) return failure("invalid_body", "Missing walletId");
|
|
18
|
+
if (!orgId) return failure("invalid_body", "Missing orgId");
|
|
19
|
+
if (otpChannel !== "email_otp") return failure("invalid_body", "otpChannel must be email_otp");
|
|
39
20
|
const rateLimit = await input.consumeRateLimit({
|
|
40
21
|
scope: "grant",
|
|
41
22
|
userId,
|
|
@@ -45,27 +26,15 @@ async function consumeEmailOtpGrantWithStore(input) {
|
|
|
45
26
|
});
|
|
46
27
|
if (!rateLimit.ok) return rateLimit;
|
|
47
28
|
const record = await input.grantStore.consume(loginGrant);
|
|
48
|
-
if (!record || input.nowMs > record.expiresAtMs || record.action !== WALLET_EMAIL_OTP_ACTIONS.unseal) return
|
|
49
|
-
|
|
50
|
-
code: "login_grant_invalid_or_expired",
|
|
51
|
-
message: "Login grant is invalid or expired"
|
|
52
|
-
};
|
|
53
|
-
if (record.userId !== userId || record.walletId !== walletId || record.otpChannel !== "email_otp" || record.orgId !== orgId) return {
|
|
54
|
-
ok: false,
|
|
55
|
-
code: "recovery_grant_binding_mismatch",
|
|
56
|
-
message: "Recovery grant is not valid for the current Email OTP authority"
|
|
57
|
-
};
|
|
29
|
+
if (!record || input.nowMs > record.expiresAtMs || record.action !== WALLET_EMAIL_OTP_ACTIONS.unseal) return failure("login_grant_invalid_or_expired", "Login grant is invalid or expired");
|
|
30
|
+
if (record.userId !== userId || record.walletId !== walletId || record.otpChannel !== "email_otp" || record.orgId !== orgId) return failure("recovery_grant_binding_mismatch", "Recovery grant is not valid for the current Email OTP authority");
|
|
58
31
|
return {
|
|
59
32
|
ok: true,
|
|
60
33
|
challengeId: record.challengeId,
|
|
61
34
|
otpChannel: EMAIL_OTP_CHANNEL
|
|
62
35
|
};
|
|
63
36
|
} catch (error) {
|
|
64
|
-
return
|
|
65
|
-
ok: false,
|
|
66
|
-
code: "internal",
|
|
67
|
-
message: errorMessage(error) || "Failed to consume Email OTP grant"
|
|
68
|
-
};
|
|
37
|
+
return failure("internal", errorMessage(error) || "Failed to consume Email OTP grant");
|
|
69
38
|
}
|
|
70
39
|
}
|
|
71
40
|
//#endregion
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { parseWalletId } from "../../shared-ts/src/utils/domainIds.js";
|
|
2
2
|
import { normalizeOptionalTrimmedString } from "../../shared-ts/src/utils/normalize.js";
|
|
3
3
|
import "../../shared-ts/src/utils/validation.js";
|
|
4
|
+
import { failure } from "../../shared-ts/src/utils/failure.js";
|
|
4
5
|
import { validateSecp256k1PublicKey33 } from "../ThresholdService/evmCryptoWasm.js";
|
|
5
6
|
import { WALLET_EMAIL_OTP_ACTIONS, emailOtpDeviceEnrollmentId } from "../../shared-ts/src/utils/emailOtpDomain.js";
|
|
6
7
|
import { validateEmailOtpEnrollmentMaterial } from "../../router/cloudflare/d1/emailOtp/d1EmailOtpRecords.js";
|
|
@@ -15,26 +16,10 @@ async function resolveEmailOtpRegistrationChallengeProof(input) {
|
|
|
15
16
|
switch (proofInput.kind) {
|
|
16
17
|
case "google_registration_attempt": {
|
|
17
18
|
const attempt = await input.registrationAttemptStore.get(proofInput.registrationAttemptId);
|
|
18
|
-
if (!attempt) return
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
};
|
|
23
|
-
if (attempt.providerSubject !== proofInput.providerSubject) return {
|
|
24
|
-
ok: false,
|
|
25
|
-
code: "challenge_subject_mismatch",
|
|
26
|
-
message: "Email OTP registration attempt does not match the provider subject"
|
|
27
|
-
};
|
|
28
|
-
if (attempt.expiresAtMs <= input.nowMs) return {
|
|
29
|
-
ok: false,
|
|
30
|
-
code: "registration_attempt_expired",
|
|
31
|
-
message: "Google Email OTP registration attempt expired"
|
|
32
|
-
};
|
|
33
|
-
if (attempt.walletId !== proofInput.walletId) return {
|
|
34
|
-
ok: false,
|
|
35
|
-
code: "wallet_identity_mismatch",
|
|
36
|
-
message: "registrationAttemptId does not match walletId"
|
|
37
|
-
};
|
|
19
|
+
if (!attempt) return failure("registration_attempt_missing", "Google Email OTP registration attempt expired or was not found");
|
|
20
|
+
if (attempt.providerSubject !== proofInput.providerSubject) return failure("challenge_subject_mismatch", "Email OTP registration attempt does not match the provider subject");
|
|
21
|
+
if (attempt.expiresAtMs <= input.nowMs) return failure("registration_attempt_expired", "Google Email OTP registration attempt expired");
|
|
22
|
+
if (attempt.walletId !== proofInput.walletId) return failure("wallet_identity_mismatch", "registrationAttemptId does not match walletId");
|
|
38
23
|
return {
|
|
39
24
|
ok: true,
|
|
40
25
|
proof: {
|
|
@@ -85,33 +70,17 @@ async function verifyEmailOtpEnrollment(input) {
|
|
|
85
70
|
});
|
|
86
71
|
if (!verified.ok) return verified;
|
|
87
72
|
const verifiedEmail = normalizeOptionalTrimmedString(verified.email)?.toLowerCase();
|
|
88
|
-
if (!verifiedEmail) return
|
|
89
|
-
ok: false,
|
|
90
|
-
code: "internal",
|
|
91
|
-
message: "Email OTP enrollment verification did not include a verified email"
|
|
92
|
-
};
|
|
73
|
+
if (!verifiedEmail) return failure("internal", "Email OTP enrollment verification did not include a verified email");
|
|
93
74
|
const enrollmentMaterial = await validateEmailOtpEnrollmentMaterial({
|
|
94
75
|
material: request,
|
|
95
76
|
validateSecp256k1PublicKey33
|
|
96
77
|
});
|
|
97
78
|
if (!enrollmentMaterial.ok) return enrollmentMaterial;
|
|
98
79
|
const orgId = normalizeOptionalTrimmedString(verified.orgId) || "";
|
|
99
|
-
if (!orgId) return
|
|
100
|
-
ok: false,
|
|
101
|
-
code: "invalid_body",
|
|
102
|
-
message: "Email OTP enrollment requires orgId tenant scope"
|
|
103
|
-
};
|
|
80
|
+
if (!orgId) return failure("invalid_body", "Email OTP enrollment requires orgId tenant scope");
|
|
104
81
|
const verifiedWalletId = parseWalletId(verified.walletId);
|
|
105
|
-
if (!verifiedWalletId.ok) return
|
|
106
|
-
|
|
107
|
-
code: "invalid_body",
|
|
108
|
-
message: "Email OTP enrollment verification returned an invalid walletId"
|
|
109
|
-
};
|
|
110
|
-
if (!await input.walletStore.getWallet({ walletId: verifiedWalletId.value })) return {
|
|
111
|
-
ok: false,
|
|
112
|
-
code: "wallet_registration_incomplete",
|
|
113
|
-
message: "Email OTP enrollment requires a canonical wallet created by /wallets/register/activate."
|
|
114
|
-
};
|
|
82
|
+
if (!verifiedWalletId.ok) return failure("invalid_body", "Email OTP enrollment verification returned an invalid walletId");
|
|
83
|
+
if (!await input.walletStore.getWallet({ walletId: verifiedWalletId.value })) return failure("wallet_registration_incomplete", "Email OTP enrollment requires a canonical wallet created by /wallets/register/activate.");
|
|
115
84
|
const existing = await input.walletEnrollmentStore.get(verified.walletId);
|
|
116
85
|
const existingState = await input.authStateStore.get(verified.walletId);
|
|
117
86
|
const nowMs = Date.now();
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import { normalizeOptionalTrimmedString } from "../../shared-ts/src/utils/normalize.js";
|
|
2
2
|
import "../../shared-ts/src/utils/validation.js";
|
|
3
|
+
import { failure } from "../../shared-ts/src/utils/failure.js";
|
|
3
4
|
import { errorMessage } from "../../shared-ts/src/utils/errors.js";
|
|
4
5
|
import { createSigningSessionSealShamir3PassCipherAdapter } from "../../threshold/session/signingSessionSeal/crypto/cipher.js";
|
|
5
6
|
import { parseSigningSessionSealRootConfig } from "../../threshold/session/signingSessionSeal/options.js";
|
|
6
7
|
import "../../threshold/session/signingSessionSeal/index.js";
|
|
7
8
|
//#region src/core/authService/emailOtpSeal.ts
|
|
8
9
|
function createEmailOtpShamirCipherFromConfig(input) {
|
|
9
|
-
if (!input.rootSecretB64u || !input.currentKeyVersion) return
|
|
10
|
-
ok: false,
|
|
11
|
-
code: "not_configured",
|
|
12
|
-
message: "Email OTP unseal requires a signing-session seal root and current key version"
|
|
13
|
-
};
|
|
10
|
+
if (!input.rootSecretB64u || !input.currentKeyVersion) return failure("not_configured", "Email OTP unseal requires a signing-session seal root and current key version");
|
|
14
11
|
try {
|
|
15
12
|
const config = parseSigningSessionSealRootConfig({
|
|
16
13
|
rootSecretB64u: input.rootSecretB64u,
|
|
@@ -23,11 +20,7 @@ function createEmailOtpShamirCipherFromConfig(input) {
|
|
|
23
20
|
cipher: createSigningSessionSealShamir3PassCipherAdapter({ config })
|
|
24
21
|
};
|
|
25
22
|
} catch (error) {
|
|
26
|
-
return
|
|
27
|
-
ok: false,
|
|
28
|
-
code: "not_configured",
|
|
29
|
-
message: errorMessage(error) || "Email OTP Shamir configuration is invalid"
|
|
30
|
-
};
|
|
23
|
+
return failure("not_configured", errorMessage(error) || "Email OTP Shamir configuration is invalid");
|
|
31
24
|
}
|
|
32
25
|
}
|
|
33
26
|
function emailOtpServerSealThresholdSessionId(operation) {
|
|
@@ -45,11 +38,7 @@ function emailOtpServerSealFailureMessage(operation) {
|
|
|
45
38
|
async function runEmailOtpServerSealOperation(input) {
|
|
46
39
|
try {
|
|
47
40
|
const wrappedCiphertext = normalizeOptionalTrimmedString(input.request.wrappedCiphertext);
|
|
48
|
-
if (!wrappedCiphertext) return
|
|
49
|
-
ok: false,
|
|
50
|
-
code: "invalid_body",
|
|
51
|
-
message: "Missing wrappedCiphertext"
|
|
52
|
-
};
|
|
41
|
+
if (!wrappedCiphertext) return failure("invalid_body", "Missing wrappedCiphertext");
|
|
53
42
|
if (!input.shamir.ok) return input.shamir;
|
|
54
43
|
const result = await input.shamir.cipher.run({
|
|
55
44
|
operation: input.operation,
|
|
@@ -65,11 +54,7 @@ async function runEmailOtpServerSealOperation(input) {
|
|
|
65
54
|
enrollmentSealKeyVersion: result.keyVersion || input.shamir.keyVersion
|
|
66
55
|
};
|
|
67
56
|
} catch (error) {
|
|
68
|
-
return
|
|
69
|
-
ok: false,
|
|
70
|
-
code: "internal",
|
|
71
|
-
message: errorMessage(error) || emailOtpServerSealFailureMessage(input.operation)
|
|
72
|
-
};
|
|
57
|
+
return failure("internal", errorMessage(error) || emailOtpServerSealFailureMessage(input.operation));
|
|
73
58
|
}
|
|
74
59
|
}
|
|
75
60
|
//#endregion
|