@seams/wallet-server 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/artifact-manifest.json +18 -13
  2. package/cloudflare-router-ab/build/deriver-a/build-stamp.json +1 -1
  3. package/cloudflare-router-ab/build/deriver-b/build-stamp.json +1 -1
  4. package/cloudflare-router-ab/build/router/build-stamp.json +1 -1
  5. package/cloudflare-router-ab/build/signing-worker/build-stamp.json +1 -1
  6. package/cloudflare-router-ab/build/tenant-root-control-plane/build-stamp.json +1 -1
  7. package/dist/esm/auth/externalAuthService.js +98 -0
  8. package/dist/esm/auth/externalAuthStore.js +217 -0
  9. package/dist/esm/authorization/domain.js +2 -2
  10. package/dist/esm/authorization/factorEvidence.js +1 -1
  11. package/dist/esm/authorization/service.js +2 -2
  12. package/dist/esm/authorization/vaultProxyUse.js +1 -1
  13. package/dist/esm/cloud-host.js +10 -9
  14. package/dist/esm/core/ThresholdService/validation.js +1 -1
  15. package/dist/esm/core/WebAuthnCredentialBindingStore.js +1 -1
  16. package/dist/esm/core/authService/webauthn.js +1 -1
  17. package/dist/esm/core/d1EcdsaSignerRead.js +1 -1
  18. package/dist/esm/core/d1WalletAuthMethodStore.js +2 -2
  19. package/dist/esm/core/d1WalletStore.js +1 -1
  20. package/dist/esm/core/deviceLinking/linkedDeviceEmailOtpGrant.js +1 -1
  21. package/dist/esm/core/deviceLinking/linkedDeviceManagement.js +1 -1
  22. package/dist/esm/core/deviceLinking/linkedDeviceSessionRecord.js +2 -2
  23. package/dist/esm/core/nearRelayerAccountProvisioning.js +1 -1
  24. package/dist/esm/hosted-wallet-gateway.js +3 -3
  25. package/dist/esm/index.js +1 -1
  26. package/dist/esm/router/auth/webAuthnCredentialCodecs.js +1 -1
  27. package/dist/esm/router/cloudflare/d1/auth/d1RouterApiAuthService.js +5 -2
  28. package/dist/esm/router/cloudflare/d1/authorization/d1AuthorizationStore.js +2 -2
  29. package/dist/esm/router/cloudflare/d1/authorization/d1VaultProxyStore.js +2 -2
  30. package/dist/esm/router/cloudflare/d1/deviceLinking/d1LinkedDeviceAuthorityInstallService.js +3 -3
  31. package/dist/esm/router/cloudflare/d1/deviceLinking/d1LinkedDeviceEd25519ExportRootStore.js +1 -1
  32. package/dist/esm/router/cloudflare/d1/deviceLinking/d1LinkedDeviceOwnerAuthorizationProvider.js +2 -2
  33. package/dist/esm/router/cloudflare/d1/deviceLinking/d1LinkedDeviceSessionStore.js +1 -1
  34. package/dist/esm/router/cloudflare/d1/deviceLinking/d1LinkedDeviceSourceContributionPreparationPlanner.js +1 -1
  35. package/dist/esm/router/cloudflare/d1/deviceLinking/d1LinkedDeviceTargetAuthenticatorStore.js +1 -1
  36. package/dist/esm/router/cloudflare/d1/deviceLinking/d1LinkedDeviceTargetCredentialProvider.js +1 -1
  37. package/dist/esm/router/cloudflare/d1/deviceLinking/d1LinkedDeviceTargetPlanner.js +1 -1
  38. package/dist/esm/router/cloudflare/d1/deviceLinking/d1LinkedDeviceVerifiedLinkBuilder.js +2 -2
  39. package/dist/esm/router/cloudflare/d1/deviceLinking/d1LinkedDeviceVerifiedLinkSourceReader.js +1 -1
  40. package/dist/esm/router/cloudflare/d1/ed25519Yao/d1Ed25519YaoCapabilityPersistence.js +1 -1
  41. package/dist/esm/router/cloudflare/d1/emailOtp/d1EmailOtpChallengeIssuer.js +1 -1
  42. package/dist/esm/router/cloudflare/d1/emailOtp/d1EmailOtpChallengeService.js +1 -1
  43. package/dist/esm/router/cloudflare/d1/emailOtp/d1EmailOtpChallengeStore.js +1 -1
  44. package/dist/esm/router/cloudflare/d1/emailOtp/d1EmailOtpRecords.js +2 -2
  45. package/dist/esm/router/cloudflare/d1/emailOtp/d1EmailOtpRecoveryService.js +2 -2
  46. package/dist/esm/router/cloudflare/d1/emailOtp/d1GoogleEmailOtpRegistrationAttemptStore.js +1 -1
  47. package/dist/esm/router/cloudflare/d1/emailOtp/d1GoogleEmailOtpSessionResolver.js +2 -2
  48. package/dist/esm/router/cloudflare/d1/oidc/d1OidcBoundary.js +7 -1
  49. package/dist/esm/router/cloudflare/d1/oidc/d1OidcVerificationService.js +1 -1
  50. package/dist/esm/router/cloudflare/d1/passkeyCustody/d1PasskeyCustodyRouteService.js +2 -2
  51. package/dist/esm/router/cloudflare/d1/passkeyCustody/d1WalletCustodyCommitStore.js +2 -2
  52. package/dist/esm/router/cloudflare/d1/passkeyCustody/d1WalletRecoveryGoogleEmailOtpRecords.js +1 -1
  53. package/dist/esm/router/cloudflare/d1/passkeyCustody/d1WalletRecoveryGoogleEmailOtpService.js +1 -1
  54. package/dist/esm/router/cloudflare/d1/registration/d1EvmFamilyEcdsaRegistrationBranch.js +1 -1
  55. package/dist/esm/router/cloudflare/d1/registration/d1RegistrationCeremonyRecords.js +2 -2
  56. package/dist/esm/router/cloudflare/d1/registration/d1RegistrationIntentService.js +1 -1
  57. package/dist/esm/router/cloudflare/d1/registration/d1WalletRegistrationCommitStore.js +1 -1
  58. package/dist/esm/router/cloudflare/d1/registration/d1WalletRegistrationService.js +3 -3
  59. package/dist/esm/router/cloudflare/d1/registration/walletRegistrationEstablishedSessionIssuer.js +1 -1
  60. package/dist/esm/router/cloudflare/d1/registration/walletRegistrationSessionCommitReceipt.js +1 -1
  61. package/dist/esm/router/cloudflare/d1/signingAdmission/d1RouterAbNormalSigningAdmissionStore.js +1 -1
  62. package/dist/esm/router/cloudflare/d1/wallet/authorizationSnapshotLayout.js +1 -0
  63. package/dist/esm/router/cloudflare/d1/wallet/d1VoiceIdWalletSessionChallenges.js +2 -2
  64. package/dist/esm/router/cloudflare/d1/wallet/d1WalletAuthMethodRevocationReplayStore.js +1 -1
  65. package/dist/esm/router/cloudflare/d1/wallet/d1WalletAuthMethodService.js +2 -2
  66. package/dist/esm/router/cloudflare/d1/wallet/d1WalletAuthorityStore.js +2 -2
  67. package/dist/esm/router/cloudflare/d1/wallet/d1WalletAuthorizationCleanup.js +2 -1
  68. package/dist/esm/router/cloudflare/d1/wallet/d1WalletAuthorizationIntake.js +1 -1
  69. package/dist/esm/router/cloudflare/d1/wallet/d1WalletAuthorizationSnapshot.js +1 -1
  70. package/dist/esm/router/cloudflare/d1/wallet/d1WalletRelocationChallenges.js +1 -1
  71. package/dist/esm/router/cloudflare/d1/wallet/d1WalletRelocationOwnerRequest.js +2 -2
  72. package/dist/esm/router/cloudflare/d1/webauthn/d1WebAuthnAuthService.js +2 -2
  73. package/dist/esm/router/cloudflare/d1/webauthn/d1WebAuthnRecords.js +2 -2
  74. package/dist/esm/router/cloudflare/runtime/staticWalletConsoleBinding.js +9 -0
  75. package/dist/esm/router/cloudflare/runtime/walletConsoleOpsClient.js +6 -0
  76. package/dist/esm/router/cloudflare-adaptor.js +1 -1
  77. package/dist/esm/router/cloudflare.js +4635 -4359
  78. package/dist/esm/router/domains/ecdsa/routerAbEcdsaStrictRegistration.js +1 -1
  79. package/dist/esm/router/domains/ed25519Yao/export/routerAbEd25519YaoExport.js +3 -3
  80. package/dist/esm/router/domains/ed25519Yao/recovery/routerAbEd25519YaoRecovery.js +2 -2
  81. package/dist/esm/router/domains/ed25519Yao/recovery/routerAbEd25519YaoRecoveryWalletSessionAuthorization.js +1 -1
  82. package/dist/esm/router/domains/ed25519Yao/registration/routerAbEd25519YaoHttpRegistrationBackend.js +1 -1
  83. package/dist/esm/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistration.js +1 -1
  84. package/dist/esm/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistrationIntentAuthorization.js +1 -1
  85. package/dist/esm/router/domains/emailOtp/emailOtpRouteHandlers.js +1 -1
  86. package/dist/esm/router/domains/signingOperations/routerAbEcdsaDerivationNormalSigningRoute.js +2 -2
  87. package/dist/esm/router/domains/signingOperations/routerAbEd25519NormalSigningRoute.js +2 -2
  88. package/dist/esm/router/domains/signingOperations/routerAbOperationStepUp.js +1 -1
  89. package/dist/esm/router/domains/tenantRoot/tenantRootIdentityResolution.js +1 -1
  90. package/dist/esm/router/domains/walletRegistration/walletRegistrationReservation.js +1 -1
  91. package/dist/esm/router/domains/walletRegistration/walletRegistrationRoutes.js +3 -3
  92. package/dist/esm/router/domains/walletUnlock/walletUnlockRouteHandlers.js +2 -2
  93. package/dist/esm/router/framework/http.js +1 -1
  94. package/dist/esm/router/framework/routeDefinitions.js +2 -1
  95. package/dist/esm/router/transport/fetch/createFetchRouter.js +5 -3
  96. package/dist/esm/router/transport/fetch/routes/auth.js +1 -1
  97. package/dist/esm/router/transport/fetch/routes/deviceLinking.js +3 -3
  98. package/dist/esm/router/transport/fetch/routes/deviceLinkingOwnerAuthorization.js +1 -1
  99. package/dist/esm/router/transport/fetch/routes/ecdsaOperationStepUpFactor.js +1 -1
  100. package/dist/esm/router/transport/fetch/routes/externalAuth.js +244 -0
  101. package/dist/esm/router/transport/fetch/routes/normalSigningRouterProxy.js +1 -1
  102. package/dist/esm/router/transport/fetch/routes/passkeyCustody.js +4 -4
  103. package/dist/esm/router/transport/fetch/routes/sessions.js +2 -2
  104. package/dist/esm/router/transport/fetch/routes/syncAccount.js +2 -2
  105. package/dist/esm/router/transport/fetch/routes/syncAccountBootstrap.js +1 -1
  106. package/dist/esm/router/transport/fetch/routes/thresholdEcdsa.js +4 -4
  107. package/dist/esm/router/transport/fetch/routes/thresholdEd25519.js +4 -4
  108. package/dist/esm/router/transport/fetch/routes/walletExecutionLanePreflight.js +2 -2
  109. package/dist/esm/router/transport/fetch/routes/walletRegistration.js +3 -3
  110. package/dist/esm/shared-ts/src/auth/externalAuth.js +45 -0
  111. package/dist/esm/shared-ts/src/authorization/voiceIdDeviceAssertion.js +1 -1
  112. package/dist/esm/shared-ts/src/authorization/walletAuthority.js +2 -2
  113. package/dist/esm/shared-ts/src/device-linking/delegatedActivationPlan.js +1 -1
  114. package/dist/esm/shared-ts/src/device-linking/digests.js +1 -1
  115. package/dist/esm/shared-ts/src/device-linking/ed25519ExportRoot.js +1 -1
  116. package/dist/esm/shared-ts/src/device-linking/parsers.js +2 -2
  117. package/dist/esm/shared-ts/src/device-linking/sourceContribution.js +1 -1
  118. package/dist/esm/shared-ts/src/device-linking/walletSessionCredentialDelivery.js +1 -1
  119. package/dist/esm/shared-ts/src/device-linking/wireFields.js +2 -2
  120. package/dist/esm/shared-ts/src/passkey-custody/custodyEnvelope.js +1 -1
  121. package/dist/esm/shared-ts/src/passkey-custody/custodySecretBinding.js +1 -1
  122. package/dist/esm/shared-ts/src/signing-lanes/ownerContinuity.js +1 -1
  123. package/dist/esm/shared-ts/src/utils/routerAbEcdsaDerivation.js +1 -1
  124. package/dist/esm/shared-ts/src/utils/walletAuthAuthority.js +1 -1
  125. package/dist/esm/shared-ts/src/wallet-recovery/walletRecoveryCommittedProjection.js +1 -1
  126. package/dist/esm/shared-ts/src/wallet-recovery/walletRecoveryEnvelopeSet.js +1 -1
  127. package/dist/esm/threshold/session/signingSessionSeal/crypto/cipher.js +1 -1
  128. package/dist/esm/threshold/session/signingSessionSeal/service.js +1 -1
  129. package/dist/esm/threshold/session/signingSessionSeal/transport/fetch.js +1 -1
  130. package/dist/esm/threshold/session/signingSessionSeal/transport/shared.js +1 -1
  131. package/dist/types/shared-ts/src/auth/externalAuth.d.ts +84 -0
  132. package/dist/types/wallet-server/src/auth/externalAuthService.d.ts +36 -0
  133. package/dist/types/wallet-server/src/auth/externalAuthStore.d.ts +61 -0
  134. package/dist/types/wallet-server/src/cloud-host.d.ts +2 -1
  135. package/dist/types/wallet-server/src/router/cloudflare/d1/oidc/d1OidcBoundary.d.ts +5 -0
  136. package/dist/types/wallet-server/src/router/cloudflare/d1/wallet/authorizationSnapshotLayout.d.ts +1 -1
  137. package/dist/types/wallet-server/src/router/cloudflare/runtime/staticWalletConsoleBinding.d.ts +2 -0
  138. package/dist/types/wallet-server/src/router/framework/apiCredentialPorts.d.ts +1 -0
  139. package/dist/types/wallet-server/src/router/framework/authServicePort.d.ts +1 -0
  140. package/dist/types/wallet-server/src/router/transport/fetch/routes/externalAuth.d.ts +5 -0
  141. package/migrations/d1-signer/0085_external_wallet_auth.sql +158 -0
  142. package/package.json +1 -1
@@ -3,17 +3,17 @@
3
3
  "walletSecurityPolicy": "scoped_seals_and_owner_proofs_v1",
4
4
  "package": {
5
5
  "name": "@seams/wallet-server",
6
- "version": "0.27.0"
6
+ "version": "0.28.0"
7
7
  },
8
8
  "workers": {
9
9
  "router": {
10
10
  "entry": "cloudflare-router-ab/build/router/worker/shim.mjs",
11
- "fingerprint": "f4d14f9f1a23c8f98f5d12085061337aaf6e80fd79def737d2142527872d29dc",
11
+ "fingerprint": "9354a23aa130d53ead7ac72f4101910e46f52e992519f44bb50f1804c3563808",
12
12
  "files": [
13
13
  {
14
14
  "path": "cloudflare-router-ab/build/router/build-stamp.json",
15
15
  "bytes": 119,
16
- "sha256": "ed5b9ff7628a165828660dbff6765db796f0a6bd4ca3292805d08a2ade9c9365"
16
+ "sha256": "fb89fa2ce50c5af95cb5464754523d31cbc827d780e3cc5767f55df49170f171"
17
17
  },
18
18
  {
19
19
  "path": "cloudflare-router-ab/build/router/index.js",
@@ -39,12 +39,12 @@
39
39
  },
40
40
  "deriver-a": {
41
41
  "entry": "cloudflare-router-ab/build/deriver-a/worker/shim.mjs",
42
- "fingerprint": "3ec071d957795f9ff6d0f20a0c5b33e1e5713b777733a2beb68c0b2b1391bcab",
42
+ "fingerprint": "9aa8706dd8d77691a8afa8096f3295b1e94d6a92f67c4106d8edd950ff838bbd",
43
43
  "files": [
44
44
  {
45
45
  "path": "cloudflare-router-ab/build/deriver-a/build-stamp.json",
46
46
  "bytes": 122,
47
- "sha256": "e54fb17f4c621cef06421c00e4d46714210336eb8a740476704bcebeae36f325"
47
+ "sha256": "b61d9f995aa1e168b0d04ccc55e41ca2adc45aac5139ec5bbca8c097b340d3dd"
48
48
  },
49
49
  {
50
50
  "path": "cloudflare-router-ab/build/deriver-a/index.js",
@@ -70,12 +70,12 @@
70
70
  },
71
71
  "deriver-b": {
72
72
  "entry": "cloudflare-router-ab/build/deriver-b/worker/shim.mjs",
73
- "fingerprint": "b56cb2596e6673329b2fc4cbfa7386fc9f4620cc56c3ed6e2485de66ec2bee13",
73
+ "fingerprint": "ff8f66cca668aba7d4d2adf0f6183731098149012461d03880f43d2155fc04e5",
74
74
  "files": [
75
75
  {
76
76
  "path": "cloudflare-router-ab/build/deriver-b/build-stamp.json",
77
77
  "bytes": 122,
78
- "sha256": "37a251c69a161ada391e28bf6585b512f3074adfef3b160ea6e847bc9fb99b5c"
78
+ "sha256": "a0a83b79b96f30cc6b5c97f933d921a4c8842a2c138b1548971f1b09f8a58980"
79
79
  },
80
80
  {
81
81
  "path": "cloudflare-router-ab/build/deriver-b/index.js",
@@ -101,12 +101,12 @@
101
101
  },
102
102
  "signing-worker": {
103
103
  "entry": "cloudflare-router-ab/build/signing-worker/worker/shim.mjs",
104
- "fingerprint": "62f97b4156ded53b921aa1f7ff4406c89b08666bb3ba17bca90e2460f5333c87",
104
+ "fingerprint": "7970e31e74739d47eebd1ee17d5ddde2a43c12eca8f9682cf65acd491eb4823a",
105
105
  "files": [
106
106
  {
107
107
  "path": "cloudflare-router-ab/build/signing-worker/build-stamp.json",
108
108
  "bytes": 127,
109
- "sha256": "6a85061edaecf85c36190d0fdceac7e0674f74f6646924d21ecc839b23e51505"
109
+ "sha256": "ce676751103f5b0457884cecf38a1ecda5af7033e3c93e71d17bb8f7eecbbb7e"
110
110
  },
111
111
  {
112
112
  "path": "cloudflare-router-ab/build/signing-worker/index.js",
@@ -132,12 +132,12 @@
132
132
  },
133
133
  "tenant-root-control-plane": {
134
134
  "entry": "cloudflare-router-ab/build/tenant-root-control-plane/worker/shim.mjs",
135
- "fingerprint": "c4214e28c3296088b1150f3c56d1fe7536a32dd2e107dc32fe319236cd2cbad5",
135
+ "fingerprint": "70f00da01cea7d89aca4c051a85344fd72ec553bb92a63d0d54db2171a59c2c2",
136
136
  "files": [
137
137
  {
138
138
  "path": "cloudflare-router-ab/build/tenant-root-control-plane/build-stamp.json",
139
139
  "bytes": 139,
140
- "sha256": "91362b12400759dc63b6893896e2fca6a9d2f3d3c3dad46fb71354119861119c"
140
+ "sha256": "9782d8c4537c51cbd99632eca61ead34f7137b7fd18ea4feafd4db6f27df5255"
141
141
  },
142
142
  {
143
143
  "path": "cloudflare-router-ab/build/tenant-root-control-plane/index.js",
@@ -165,8 +165,8 @@
165
165
  "migrations": {
166
166
  "signer": {
167
167
  "directory": "migrations/d1-signer",
168
- "head": "0084_voiceid_wallet_auth_methods.sql",
169
- "fingerprint": "724414d2bc4d41dd761541a0dc465145957275303a1c49610f1fbdc1e60c0316",
168
+ "head": "0085_external_wallet_auth.sql",
169
+ "fingerprint": "a73558668541d4d00f06178f690a239cff675b118fe39c2e8ea2b5c5ec36cc86",
170
170
  "files": [
171
171
  {
172
172
  "path": "migrations/d1-signer/0001_signer_d1_initial.sql",
@@ -587,6 +587,11 @@
587
587
  "path": "migrations/d1-signer/0084_voiceid_wallet_auth_methods.sql",
588
588
  "bytes": 17185,
589
589
  "sha256": "01af96f95131fb6ce8e42301bfdc2bd99ead260c817833b6b03a501f836d34a9"
590
+ },
591
+ {
592
+ "path": "migrations/d1-signer/0085_external_wallet_auth.sql",
593
+ "bytes": 9757,
594
+ "sha256": "62e98c8200f18cc1d6bc399891f2fd7c57e5b0639f251d10ad6cf7d7b5e30461"
590
595
  }
591
596
  ]
592
597
  },
@@ -1 +1 @@
1
- {"profile":"release","wallet_objects":true,"features":"strict-worker-deriver-a-entrypoint","started_at_ms":1793201442665}
1
+ {"profile":"release","wallet_objects":true,"features":"strict-worker-deriver-a-entrypoint","started_at_ms":1793281741952}
@@ -1 +1 @@
1
- {"profile":"release","wallet_objects":true,"features":"strict-worker-deriver-b-entrypoint","started_at_ms":1793201567116}
1
+ {"profile":"release","wallet_objects":true,"features":"strict-worker-deriver-b-entrypoint","started_at_ms":1793281927715}
@@ -1 +1 @@
1
- {"profile":"release","wallet_objects":true,"features":"strict-worker-router-entrypoint","started_at_ms":1793201683620}
1
+ {"profile":"release","wallet_objects":true,"features":"strict-worker-router-entrypoint","started_at_ms":1793282099467}
@@ -1 +1 @@
1
- {"profile":"release","wallet_objects":true,"features":"strict-worker-signing-worker-entrypoint","started_at_ms":1793201252625}
1
+ {"profile":"release","wallet_objects":true,"features":"strict-worker-signing-worker-entrypoint","started_at_ms":1793281450811}
@@ -1 +1 @@
1
- {"profile":"release","wallet_objects":false,"features":"strict-worker-tenant-root-control-plane-entrypoint","started_at_ms":1793201821080}
1
+ {"profile":"release","wallet_objects":false,"features":"strict-worker-tenant-root-control-plane-entrypoint","started_at_ms":1793282301221}
@@ -0,0 +1,98 @@
1
+ import { base64UrlEncode } from "../shared-ts/src/utils/base64.js";
2
+ import { sha256HexUtf8 } from "../shared-ts/src/utils/digests.js";
3
+ import { externalAuthFailure } from "../shared-ts/src/auth/externalAuth.js";
4
+ import { verifyGoogleOidcToken } from "../router/cloudflare/d1/oidc/googleOidcToken.js";
5
+ //#region src/auth/externalAuthService.ts
6
+ var ExternalAuthService = class {
7
+ constructor(store, wallets, methods) {
8
+ this.store = store;
9
+ this.wallets = wallets;
10
+ this.methods = methods;
11
+ }
12
+ async verifyGoogle(trust, idToken) {
13
+ const proof = await verifyGoogleOidcToken(trust.clientId, idToken);
14
+ if (!proof.ok) return externalAuthFailure(proof.code === "expired" ? "expired" : "invalid_credential");
15
+ if (proof.audienceCount > 1 && proof.authorizedParty === null || proof.authorizedParty !== null && proof.authorizedParty !== trust.clientId) return externalAuthFailure("invalid_credential");
16
+ return {
17
+ ok: true,
18
+ value: {
19
+ subject: proof.sub,
20
+ expiresAtMs: proof.expiresAtMs,
21
+ trust
22
+ }
23
+ };
24
+ }
25
+ async prepare(input) {
26
+ const attemptId = crypto.randomUUID();
27
+ const expiresAtMs = Date.now() + 12e4;
28
+ await this.store.prepareAttempt({
29
+ attemptId,
30
+ walletId: input.walletId,
31
+ originBinding: input.originBinding,
32
+ bindingHash: await sha256HexUtf8(input.binding),
33
+ sessionTokenHash: await sha256HexUtf8(input.sessionToken),
34
+ expiresAtMs
35
+ });
36
+ return {
37
+ ok: true,
38
+ value: {
39
+ attemptId,
40
+ walletId: input.walletId,
41
+ expiresAtMs
42
+ }
43
+ };
44
+ }
45
+ async exchange(input) {
46
+ const verified = await this.verifyGoogle(input.trust, input.idToken);
47
+ if (!verified.ok) return verified;
48
+ const code = base64UrlEncode(crypto.getRandomValues(new Uint8Array(32)));
49
+ const nowMs = Date.now();
50
+ return await this.store.verifyAttempt({
51
+ attemptId: input.attemptId,
52
+ walletId: input.walletId,
53
+ subject: verified.value.subject,
54
+ trust: verified.value.trust,
55
+ codeHash: await sha256HexUtf8(code),
56
+ nowMs,
57
+ sessionExpiresAtMs: Math.min(nowMs + 36e5, verified.value.expiresAtMs)
58
+ }) ? {
59
+ ok: true,
60
+ value: { code }
61
+ } : externalAuthFailure("access_denied");
62
+ }
63
+ async settings(authentication) {
64
+ const walletId = authentication.walletId;
65
+ const [ed25519, ecdsa, methods, devices] = await Promise.all([
66
+ this.wallets.listEd25519SignersForWallet({ walletId }),
67
+ this.wallets.listEcdsaSignersForWallet({ walletId }),
68
+ this.methods.listForWalletV2({ walletId }),
69
+ this.store.devices(walletId)
70
+ ]);
71
+ const accounts = [];
72
+ for (const signer of ed25519) accounts.push({
73
+ family: "ed25519",
74
+ address: signer.nearAccountId,
75
+ publicKey: signer.publicKey
76
+ });
77
+ for (const signer of ecdsa) accounts.push({
78
+ family: "ecdsa",
79
+ address: signer.walletKey.thresholdOwnerAddress,
80
+ publicKey: signer.walletKey.thresholdEcdsaPublicKeyB64u
81
+ });
82
+ const summaries = [];
83
+ for (const method of methods) if (method.status === "active") summaries.push({
84
+ id: method.walletAuthMethodId,
85
+ kind: method.kind
86
+ });
87
+ return {
88
+ authentication,
89
+ accounts,
90
+ methods: summaries,
91
+ devices
92
+ };
93
+ }
94
+ };
95
+ //#endregion
96
+ export { ExternalAuthService };
97
+
98
+ //# sourceMappingURL=externalAuthService.js.map
@@ -0,0 +1,217 @@
1
+ import { requireCanonicalString } from "../shared-ts/src/utils/validation.js";
2
+ import { parseUnixMs } from "../shared-ts/src/passkey-custody/primitives.js";
3
+ import { parseExternalWalletAuthentication } from "../shared-ts/src/auth/externalAuth.js";
4
+ import { d1ChangedRows } from "../storage/d1Sql.js";
5
+ import { prepareD1TenantStatement } from "../core/d1TenantStore.js";
6
+ //#region src/auth/externalAuthStore.ts
7
+ const SCOPE = "namespace = ?1 AND org_id = ?2 AND project_id = ?3 AND env_id = ?4";
8
+ const ACTIVE_HOME = `EXISTS (SELECT 1 FROM wallet_execution_generations home
9
+ WHERE home.namespace = a.namespace AND home.org_id = a.org_id
10
+ AND home.project_id = a.project_id AND home.env_id = a.env_id
11
+ AND home.wallet_id = a.wallet_id AND home.state = 'active'
12
+ AND NOT EXISTS (SELECT 1 FROM wallet_relocation_write_blocks block
13
+ WHERE block.namespace = home.namespace AND block.org_id = home.org_id
14
+ AND block.project_id = home.project_id AND block.env_id = home.env_id
15
+ AND block.wallet_id = home.wallet_id AND block.source_generation = home.generation
16
+ AND block.state != 'released'))`;
17
+ const LIVE_ASSOCIATION = `EXISTS (
18
+ SELECT 1 FROM external_auth_associations a
19
+ JOIN wallet_authorities w ON w.namespace = a.namespace AND w.org_id = a.org_id
20
+ AND w.project_id = a.project_id AND w.env_id = a.env_id
21
+ AND w.authority_id = a.authority_id AND w.wallet_id = a.wallet_id
22
+ WHERE a.namespace = external_auth_attempts.namespace
23
+ AND a.org_id = external_auth_attempts.org_id
24
+ AND a.project_id = external_auth_attempts.project_id
25
+ AND a.env_id = external_auth_attempts.env_id
26
+ AND a.association_id = external_auth_attempts.association_id
27
+ AND a.wallet_id = external_auth_attempts.wallet_id AND a.status = 'active'
28
+ AND w.lifecycle_state = 'active' AND w.revocation_epoch = a.authority_epoch
29
+ AND ${ACTIVE_HOME}
30
+ )`;
31
+ var ExternalAuthStore = class {
32
+ constructor(database, scope) {
33
+ this.database = database;
34
+ this.scope = scope;
35
+ }
36
+ prepare(sql, values = []) {
37
+ return prepareD1TenantStatement(this.database, this.scope, sql, values);
38
+ }
39
+ async consumeAuthenticationAllowance(rateKey, nowMs) {
40
+ return d1ChangedRows(await this.prepare(`INSERT INTO external_auth_rate_limits
41
+ (namespace, org_id, project_id, env_id, rate_key, consumed_count, reset_at_ms)
42
+ VALUES (?1, ?2, ?3, ?4, ?5, 1, ?7)
43
+ ON CONFLICT(namespace, org_id, project_id, env_id, rate_key) DO UPDATE SET
44
+ consumed_count = CASE WHEN reset_at_ms <= ?6 THEN 1 ELSE consumed_count + 1 END,
45
+ reset_at_ms = CASE WHEN reset_at_ms <= ?6 THEN ?7 ELSE reset_at_ms END
46
+ WHERE reset_at_ms <= ?6 OR consumed_count < 120`, [
47
+ rateKey,
48
+ nowMs,
49
+ nowMs + 6e4
50
+ ]).run()) === 1;
51
+ }
52
+ async associate(input) {
53
+ const revokePriorAuthority = this.prepare(`UPDATE external_auth_associations SET status = 'revoked'
54
+ WHERE ${SCOPE} AND wallet_id = ?5 AND provider_subject = ?6 AND status = 'active'
55
+ AND (authority_id != ?7 OR authority_epoch != ?8)
56
+ AND EXISTS (SELECT 1 FROM wallet_authorities WHERE ${SCOPE}
57
+ AND wallet_id = ?5 AND authority_id = ?7 AND lifecycle_state = 'active'
58
+ AND revocation_epoch = ?8)`, [
59
+ input.walletId,
60
+ input.subject,
61
+ input.authorityId,
62
+ input.authorityEpoch
63
+ ]);
64
+ const createAssociation = this.prepare(`INSERT INTO external_auth_associations
65
+ (namespace, org_id, project_id, env_id, association_id, wallet_id,
66
+ provider_subject, authority_id, authority_epoch, status)
67
+ SELECT ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, 'active'
68
+ WHERE EXISTS (SELECT 1 FROM wallet_authorities WHERE ${SCOPE}
69
+ AND authority_id = ?8 AND wallet_id = ?6 AND lifecycle_state = 'active'
70
+ AND revocation_epoch = ?9)
71
+ ON CONFLICT(namespace, org_id, project_id, env_id, wallet_id, provider_subject)
72
+ WHERE status = 'active' DO NOTHING`, [
73
+ crypto.randomUUID(),
74
+ input.walletId,
75
+ input.subject,
76
+ input.authorityId,
77
+ input.authorityEpoch
78
+ ]);
79
+ const [revoked, inserted] = await this.database.batch([revokePriorAuthority, createAssociation]);
80
+ if (!revoked?.success || !inserted?.success) throw new Error("Association update failed");
81
+ if (d1ChangedRows(inserted) === 1) return true;
82
+ return await this.prepare(`SELECT association_id FROM external_auth_associations WHERE ${SCOPE}
83
+ AND wallet_id = ?5 AND provider_subject = ?6 AND authority_id = ?7
84
+ AND authority_epoch = ?8 AND status = 'active'
85
+ AND EXISTS (SELECT 1 FROM wallet_authorities WHERE ${SCOPE}
86
+ AND wallet_id = ?5 AND authority_id = ?7 AND lifecycle_state = 'active'
87
+ AND revocation_epoch = ?8)`, [
88
+ input.walletId,
89
+ input.subject,
90
+ input.authorityId,
91
+ input.authorityEpoch
92
+ ]).first() !== null;
93
+ }
94
+ async revokeAssociation(walletId, associationId) {
95
+ await this.prepare(`UPDATE external_auth_associations SET status = 'revoked'
96
+ WHERE ${SCOPE} AND wallet_id = ?5 AND association_id = ?6`, [walletId, associationId]).run();
97
+ }
98
+ async prepareAttempt(input) {
99
+ const nowMs = Date.now();
100
+ await this.database.batch([this.database.prepare(`DELETE FROM external_auth_attempts WHERE rowid IN (
101
+ SELECT rowid FROM external_auth_attempts
102
+ WHERE expires_at_ms <= ? AND (session_expires_at_ms IS NULL OR session_expires_at_ms <= ?) LIMIT 100
103
+ )`).bind(nowMs, nowMs), this.database.prepare(`DELETE FROM external_auth_rate_limits WHERE rowid IN (
104
+ SELECT rowid FROM external_auth_rate_limits WHERE reset_at_ms <= ? LIMIT 100
105
+ )`).bind(nowMs)]);
106
+ await this.prepare(`INSERT INTO external_auth_attempts
107
+ (namespace, org_id, project_id, env_id, attempt_id, wallet_id, origin,
108
+ binding_hash, session_token_hash, expires_at_ms, status)
109
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, 'prepared')`, [
110
+ input.attemptId,
111
+ input.walletId,
112
+ input.originBinding,
113
+ input.bindingHash,
114
+ input.sessionTokenHash,
115
+ input.expiresAtMs
116
+ ]).run();
117
+ }
118
+ async verifyAttempt(input) {
119
+ return d1ChangedRows(await this.prepare(`UPDATE external_auth_attempts SET status = 'verified',
120
+ association_id = (SELECT a.association_id FROM external_auth_associations a
121
+ JOIN wallet_authorities w ON w.namespace = a.namespace AND w.org_id = a.org_id
122
+ AND w.project_id = a.project_id AND w.env_id = a.env_id
123
+ AND w.authority_id = a.authority_id AND w.wallet_id = a.wallet_id
124
+ WHERE a.namespace = ?1 AND a.org_id = ?2 AND a.project_id = ?3 AND a.env_id = ?4
125
+ AND a.wallet_id = ?6 AND a.provider_subject = ?7 AND a.status = 'active'
126
+ AND w.lifecycle_state = 'active' AND w.revocation_epoch = a.authority_epoch
127
+ AND ${ACTIVE_HOME}),
128
+ trust_revision = ?8, code_hash = ?9, session_expires_at_ms = ?11
129
+ WHERE ${SCOPE} AND attempt_id = ?5 AND wallet_id = ?6
130
+ AND status = 'prepared' AND expires_at_ms > ?10
131
+ AND EXISTS (SELECT 1 FROM external_auth_associations a
132
+ JOIN wallet_authorities w ON w.namespace = a.namespace AND w.org_id = a.org_id
133
+ AND w.project_id = a.project_id AND w.env_id = a.env_id
134
+ AND w.authority_id = a.authority_id AND w.wallet_id = a.wallet_id
135
+ WHERE a.namespace = ?1 AND a.org_id = ?2 AND a.project_id = ?3 AND a.env_id = ?4
136
+ AND a.wallet_id = ?6 AND a.provider_subject = ?7 AND a.status = 'active'
137
+ AND w.lifecycle_state = 'active' AND w.revocation_epoch = a.authority_epoch
138
+ AND ${ACTIVE_HOME})`, [
139
+ input.attemptId,
140
+ input.walletId,
141
+ input.subject,
142
+ input.trust.revision,
143
+ input.codeHash,
144
+ input.nowMs,
145
+ input.sessionExpiresAtMs
146
+ ]).run()) === 1;
147
+ }
148
+ async redeem(input) {
149
+ await this.prepare(`UPDATE external_auth_attempts SET status = 'consumed'
150
+ WHERE ${SCOPE} AND attempt_id = ?5 AND wallet_id = ?6 AND origin = ?7
151
+ AND binding_hash = ?8 AND session_token_hash = ?9 AND code_hash = ?10
152
+ AND status = 'verified' AND expires_at_ms > ?11 AND session_expires_at_ms > ?11
153
+ AND trust_revision = ?12 AND ${LIVE_ASSOCIATION}`, [
154
+ input.attemptId,
155
+ input.walletId,
156
+ input.originBinding,
157
+ input.bindingHash,
158
+ input.sessionTokenHash,
159
+ input.codeHash,
160
+ input.nowMs,
161
+ input.trustRevision
162
+ ]).run();
163
+ const row = await this.prepare(`SELECT attempt_id, association_id, wallet_id, session_expires_at_ms
164
+ FROM external_auth_attempts WHERE ${SCOPE} AND attempt_id = ?5 AND wallet_id = ?6
165
+ AND origin = ?7 AND binding_hash = ?8 AND session_token_hash = ?9 AND code_hash = ?10
166
+ AND status = 'consumed' AND session_expires_at_ms > ?11 AND trust_revision = ?12 AND ${LIVE_ASSOCIATION}`, [
167
+ input.attemptId,
168
+ input.walletId,
169
+ input.originBinding,
170
+ input.bindingHash,
171
+ input.sessionTokenHash,
172
+ input.codeHash,
173
+ input.nowMs,
174
+ input.trustRevision
175
+ ]).first();
176
+ return row ? this.authentication(row) : null;
177
+ }
178
+ async readSession(input) {
179
+ const row = await this.prepare(`SELECT attempt_id, association_id, wallet_id, session_expires_at_ms
180
+ FROM external_auth_attempts WHERE ${SCOPE} AND session_token_hash = ?5 AND origin = ?6
181
+ AND status = 'consumed' AND session_expires_at_ms > ?7
182
+ AND trust_revision = ?8 AND ${LIVE_ASSOCIATION}`, [
183
+ input.tokenHash,
184
+ input.originBinding,
185
+ input.nowMs,
186
+ input.trustRevision
187
+ ]).first();
188
+ return row ? this.authentication(row) : null;
189
+ }
190
+ async revokeSession(tokenHash, originBinding) {
191
+ await this.prepare(`UPDATE external_auth_attempts SET status = 'revoked'
192
+ WHERE ${SCOPE} AND session_token_hash = ?5 AND origin = ?6`, [tokenHash, originBinding]).run();
193
+ }
194
+ async devices(walletId) {
195
+ const result = await this.prepare(`SELECT DISTINCT device_id FROM wallet_authorities WHERE ${SCOPE}
196
+ AND wallet_id = ?5 AND lifecycle_state = 'active' ORDER BY device_id`, [walletId]).all();
197
+ const devices = [];
198
+ for (const row of result.results || []) devices.push({ id: requireCanonicalString(row.device_id, "device_id") });
199
+ return devices;
200
+ }
201
+ authentication(row) {
202
+ return parseExternalWalletAuthentication({
203
+ kind: "external_authenticated",
204
+ walletId: row.wallet_id,
205
+ sessionId: row.attempt_id,
206
+ associationId: row.association_id,
207
+ environmentId: this.scope.envId,
208
+ provider: "google",
209
+ permission: "wallet_settings_read",
210
+ expiresAtMs: parseUnixMs(row.session_expires_at_ms, "session expiry")
211
+ });
212
+ }
213
+ };
214
+ //#endregion
215
+ export { ExternalAuthStore };
216
+
217
+ //# sourceMappingURL=externalAuthStore.js.map
@@ -1,11 +1,11 @@
1
1
  import { mpcMaterialActivationRefsEqual, parseMpcMaterialActivationRef, parseWalletAuthMethodId, parseWalletAuthorityId, parseWalletId } from "../shared-ts/src/utils/domainIds.js";
2
- import { parseMpcWalletSigningQuotaId, parsePrincipalId, parseTenantId, parseWalletSessionAuthorizationId, parseWalletSessionId, parseWalletSessionMintId } from "../shared-ts/src/authorization/capabilityKinds.js";
3
2
  import { base64UrlEncode } from "../shared-ts/src/utils/base64.js";
4
3
  import { alphabetizeStringify, sha256BytesUtf8 } from "../shared-ts/src/utils/digests.js";
5
4
  import { parseDigestB64u } from "../shared-ts/src/utils/canonicalPrimitives.js";
5
+ import "../shared-ts/src/utils/encoders.js";
6
+ import { parseMpcWalletSigningQuotaId, parsePrincipalId, parseTenantId, parseWalletSessionAuthorizationId, parseWalletSessionId, parseWalletSessionMintId } from "../shared-ts/src/authorization/capabilityKinds.js";
6
7
  import { parseActiveWalletSessionV1, parseWalletSessionHome } from "../shared-ts/src/device-linking/activeWalletSession.js";
7
8
  import { computeCapabilityOperationFingerprintDigest } from "../shared-ts/src/authorization/operationFingerprint.js";
8
- import "../shared-ts/src/utils/encoders.js";
9
9
  import "../shared-ts/src/device-linking/index.js";
10
10
  //#region src/authorization/domain.ts
11
11
  function buildExactWalletSessionQuotaProjectionV1(fields) {
@@ -1,7 +1,7 @@
1
1
  import { parseProviderSubject } from "../shared-ts/src/utils/domainIds.js";
2
- import { AUTHORIZATION_EVIDENCE_KINDS } from "../shared-ts/src/authorization/capabilityKinds.js";
3
2
  import { alphabetizeStringify } from "../shared-ts/src/utils/digests.js";
4
3
  import { sha256Utf8DigestB64u } from "../shared-ts/src/utils/canonicalPrimitives.js";
4
+ import { AUTHORIZATION_EVIDENCE_KINDS } from "../shared-ts/src/authorization/capabilityKinds.js";
5
5
  import { computeCapabilityOperationFingerprintDigest } from "../shared-ts/src/authorization/operationFingerprint.js";
6
6
  //#region src/authorization/factorEvidence.ts
7
7
  const FACTOR_EVIDENCE_DIGEST_DOMAIN_V1 = "seams:authorization:factor-evidence:v1";
@@ -1,9 +1,9 @@
1
- import { parseHostedWalletSessionExchangeCodeId, parseMpcWalletSigningQuotaId, parseWalletSessionAuthorizationId, parseWalletSessionId } from "../shared-ts/src/authorization/capabilityKinds.js";
2
1
  import { base64UrlEncode } from "../shared-ts/src/utils/base64.js";
3
2
  import { sha256BytesUtf8 } from "../shared-ts/src/utils/digests.js";
4
3
  import { parseDigestB64u } from "../shared-ts/src/utils/canonicalPrimitives.js";
5
- import { parseWalletSessionOperationCredentialV1 } from "../shared-ts/src/device-linking/activeWalletSession.js";
6
4
  import "../shared-ts/src/utils/encoders.js";
5
+ import { parseHostedWalletSessionExchangeCodeId, parseMpcWalletSigningQuotaId, parseWalletSessionAuthorizationId, parseWalletSessionId } from "../shared-ts/src/authorization/capabilityKinds.js";
6
+ import { parseWalletSessionOperationCredentialV1 } from "../shared-ts/src/device-linking/activeWalletSession.js";
7
7
  import { buildActiveWalletSessionQuota, buildPersistedActiveWalletSessionAuthorizationV2, buildWalletSessionAuthorizationV2, buildWalletSessionCapabilitySubjectsV1, parseHostedWalletSeamsSessionExchangeCode, parseHostedWalletSeamsSessionExchangeNonce, parseHostedWalletSessionCredentialId, parseHostedWalletSessionOperationCredentialV1, parsePrimaryWalletSessionOperationCredentialToken, walletSessionCapabilitySubjectsV1Equal } from "./domain.js";
8
8
  import { buildVerifiedOwnerProof, buildVerifiedWalletOperationFactorEvidenceSet } from "./factorEvidence.js";
9
9
  import { secureRandomBase64Url } from "../shared-ts/src/utils/secureRandomId.js";
@@ -1,6 +1,6 @@
1
- import { buildVaultOperationRef, parseAuthorizationAuditEventId, parseAuthorizedOperationId, parseCapabilityId, parseCapabilityOperationId, parsePrincipalId, parseTenantId, parseVaultId, parseVaultItemId } from "../shared-ts/src/authorization/capabilityKinds.js";
2
1
  import { alphabetizeStringify } from "../shared-ts/src/utils/digests.js";
3
2
  import { parseDigestB64u, sha256Utf8DigestB64u } from "../shared-ts/src/utils/canonicalPrimitives.js";
3
+ import { buildVaultOperationRef, parseAuthorizationAuditEventId, parseAuthorizedOperationId, parseCapabilityId, parseCapabilityOperationId, parsePrincipalId, parseTenantId, parseVaultId, parseVaultItemId } from "../shared-ts/src/authorization/capabilityKinds.js";
4
4
  import { buildCapabilityOperationEnvelope } from "../shared-ts/src/authorization/operationFingerprint.js";
5
5
  import { AUTHORIZED_OPERATION_REPLAY_BODY_MAX_BYTES, authorizedOperationReplayBodyInit } from "./domain.js";
6
6
  import { hasExactKeys } from "../shared-ts/src/utils/exactKeys.js";