@seams/wallet-server 0.44.0 → 0.45.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 (35) hide show
  1. package/README.md +4 -4
  2. package/artifact-manifest.json +11 -11
  3. package/cloudflare-router-ab/build/deriver-a/build-stamp.json +1 -1
  4. package/cloudflare-router-ab/build/deriver-b/build-stamp.json +1 -1
  5. package/cloudflare-router-ab/build/router/build-stamp.json +1 -1
  6. package/cloudflare-router-ab/build/signing-worker/build-stamp.json +1 -1
  7. package/cloudflare-router-ab/build/tenant-root-control-plane/build-stamp.json +1 -1
  8. package/dist/esm/authorization/factorEvidence.js +37 -1
  9. package/dist/esm/authorization/voiceIdDeviceProof.js +32 -6
  10. package/dist/esm/hosted-wallet-gateway.js +1 -1
  11. package/dist/esm/router/cloudflare/d1/auth/d1RouterApiAuthService.js +1 -0
  12. package/dist/esm/router/cloudflare/d1/wallet/d1VoiceIdSessions.js +34 -1
  13. package/dist/esm/router/cloudflare.js +317 -100
  14. package/dist/esm/router/domains/ed25519Yao/export/routerAbEd25519YaoExport.js +181 -14
  15. package/dist/esm/router/domains/ed25519Yao/export/routerAbEd25519YaoExportRequestScopedCloudflare.js +21 -5
  16. package/dist/esm/router/domains/signingOperations/routerAbOperationStepUp.js +4 -0
  17. package/dist/esm/router/transport/fetch/routes/ecdsaOperationStepUpFactor.js +51 -1
  18. package/dist/esm/router/transport/fetch/routes/thresholdEcdsa.js +3 -1
  19. package/dist/esm/shared-ts/src/authorization/capabilityKinds.js +2 -1
  20. package/dist/esm/shared-ts/src/authorization/voiceIdDeviceAssertion.js +70 -1
  21. package/dist/esm/shared-ts/src/utils/routerAbEcdsaDerivation.js +18 -1
  22. package/dist/esm/shared-ts/src/utils/routerAbEd25519YaoDigests.js +8 -1
  23. package/dist/types/shared-ts/src/authorization/capabilityKinds.d.ts +2 -1
  24. package/dist/types/shared-ts/src/authorization/voiceIdDeviceAssertion.d.ts +30 -0
  25. package/dist/types/shared-ts/src/utils/routerAbEcdsaDerivation.d.ts +11 -1
  26. package/dist/types/shared-ts/src/utils/routerAbEd25519YaoDigests.d.ts +3 -0
  27. package/dist/types/wallet-server/src/authorization/domain.d.ts +3 -0
  28. package/dist/types/wallet-server/src/authorization/factorEvidence.d.ts +11 -1
  29. package/dist/types/wallet-server/src/authorization/voiceIdDeviceProof.d.ts +27 -1
  30. package/dist/types/wallet-server/src/router/cloudflare/d1/wallet/d1VoiceIdSessions.d.ts +3 -1
  31. package/dist/types/wallet-server/src/router/domains/ed25519Yao/export/routerAbEd25519YaoExport.d.ts +36 -2
  32. package/dist/types/wallet-server/src/router/domains/voiceId/voiceIdSessions.d.ts +23 -1
  33. package/dist/types/wallet-server/src/router/framework/authServicePort.d.ts +1 -0
  34. package/dist/types/wallet-server/src/router/transport/fetch/routes/ecdsaOperationStepUpFactor.d.ts +2 -1
  35. package/package.json +1 -1
package/README.md CHANGED
@@ -4,17 +4,17 @@ This package owns the reusable signer server surface: route adapters,
4
4
  WebAuthn verification policy, threshold signing services, signer storage
5
5
  adapters, and server wasm bindings.
6
6
 
7
- The package version is `@seams/wallet-server@0.44.0`. Pair it with
8
- `@seams/wallet@0.44.0` and matching hosted assets. Use `@seams/wallet-cli@0.29.0`.
7
+ The package version is `@seams/wallet-server@0.45.0`. Pair it with
8
+ `@seams/wallet@0.45.0` and matching hosted assets. Use `@seams/wallet-cli@0.29.0`.
9
9
  The wallet iframe protocol is **23.0.0**.
10
10
 
11
11
  ```sh
12
- pnpm add @seams/wallet-server@0.44.0
12
+ pnpm add @seams/wallet-server@0.45.0
13
13
  ```
14
14
 
15
15
  ## Google BYO authentication
16
16
 
17
- Version 0.44.0 verifies a configured application's signed session assertion or the app's Google ID token or exchanges it for a browser-bound handoff.
17
+ Version 0.45.0 verifies a configured application's signed session assertion or the app's Google ID token or exchanges it for a browser-bound handoff.
18
18
  An environment-specific Google client configuration and an owner-approved wallet association are required.
19
19
  Apply the packaged signer migrations before enabling the feature.
20
20
  External sessions grant settings reads and remain separate from owner and signing credentials.
@@ -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.44.0"
6
+ "version": "0.45.0"
7
7
  },
8
8
  "workers": {
9
9
  "router": {
10
10
  "entry": "cloudflare-router-ab/build/router/worker/shim.mjs",
11
- "fingerprint": "cf2212d5f30d0fde0fe50b670947f7e8dbd80bf030f331926b912a7c57b7dfe2",
11
+ "fingerprint": "be8ce147f8355f6b816a9b258f43f35766a4849bfe3de592510cc7a24aab3fdc",
12
12
  "files": [
13
13
  {
14
14
  "path": "cloudflare-router-ab/build/router/build-stamp.json",
15
15
  "bytes": 119,
16
- "sha256": "7b1fa64f9a3281415967f8c35e0a566f07acf0e0960d59def4e752c561b7c221"
16
+ "sha256": "c07f1d05db4e35c5f83ea6050c29b8139704dc980cdd29bf68951858043fc9bf"
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": "3f3a13d3006fb9cb12d0b65155d6606fe76ded40a473ab957e125f1d617fe1e1",
42
+ "fingerprint": "9fca6888b064b6236f198f3089090a48b6b96dcfcc892a0003e8b189769f287e",
43
43
  "files": [
44
44
  {
45
45
  "path": "cloudflare-router-ab/build/deriver-a/build-stamp.json",
46
46
  "bytes": 122,
47
- "sha256": "45128c4e72cb353d397042b5c4a3d4de21f849043703edcd13faa8f813449b00"
47
+ "sha256": "43f9c411ce83779b05ff77d0fbb31cfffaa23f209124f8432da8a08c442853f4"
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": "c3ec3bd81745c884753a0ccb49295a5b10babc5ab0411dfd4da3ae03a6f45047",
73
+ "fingerprint": "2c85d5ed88e0f1c061e6a16b823e7700d5d32033434f6cc8244662e15a1804f1",
74
74
  "files": [
75
75
  {
76
76
  "path": "cloudflare-router-ab/build/deriver-b/build-stamp.json",
77
77
  "bytes": 122,
78
- "sha256": "0dbf6fa12a10aa2d722f7aaf35d2736345e57fe13411bac6cb922165228389cc"
78
+ "sha256": "16be8837dffda937dfdd423f3b7c953b58e5d17783b6997c2f7a2cb1ef5713ea"
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": "0028ab8619605c142b848e0331ed03625089c4dd542c852f47188779b440c98a",
104
+ "fingerprint": "95977224fe44f68a6859881f6c13ca75e6deb4d5f60ed1cb6822ce5947ef29fe",
105
105
  "files": [
106
106
  {
107
107
  "path": "cloudflare-router-ab/build/signing-worker/build-stamp.json",
108
108
  "bytes": 127,
109
- "sha256": "ef39cd5434a138428ebdb31472a951b26c1588326ea1d4919a00ca35879068af"
109
+ "sha256": "ce8b46720c2326d1215658429c564f64d462bd32b0987ae4b011392ee6250435"
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": "585215abff0f2a149de5c2bd000e47945178212759bee3a93e36eb8f45dc3de6",
135
+ "fingerprint": "4376495623e35c9d5bc8be92d2e3d938e7f0ae0a31263c241b854f07b5ded7f8",
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": "8a24fdba7f01f7a45de6b8079a01cbf21a21649013d141fd7d4a7e148371f14c"
140
+ "sha256": "e4aa88373939f5fef93b42d05ebb7072ccb133b591c9572c05a4692d2489747a"
141
141
  },
142
142
  {
143
143
  "path": "cloudflare-router-ab/build/tenant-root-control-plane/index.js",
@@ -1 +1 @@
1
- {"profile":"release","wallet_objects":true,"features":"strict-worker-deriver-a-entrypoint","started_at_ms":1793711641836}
1
+ {"profile":"release","wallet_objects":true,"features":"strict-worker-deriver-a-entrypoint","started_at_ms":1793722189771}
@@ -1 +1 @@
1
- {"profile":"release","wallet_objects":true,"features":"strict-worker-deriver-b-entrypoint","started_at_ms":1793711793465}
1
+ {"profile":"release","wallet_objects":true,"features":"strict-worker-deriver-b-entrypoint","started_at_ms":1793722326306}
@@ -1 +1 @@
1
- {"profile":"release","wallet_objects":true,"features":"strict-worker-router-entrypoint","started_at_ms":1793711933065}
1
+ {"profile":"release","wallet_objects":true,"features":"strict-worker-router-entrypoint","started_at_ms":1793722456803}
@@ -1 +1 @@
1
- {"profile":"release","wallet_objects":true,"features":"strict-worker-signing-worker-entrypoint","started_at_ms":1793711405850}
1
+ {"profile":"release","wallet_objects":true,"features":"strict-worker-signing-worker-entrypoint","started_at_ms":1793721977789}
@@ -1 +1 @@
1
- {"profile":"release","wallet_objects":false,"features":"strict-worker-tenant-root-control-plane-entrypoint","started_at_ms":1793712096636}
1
+ {"profile":"release","wallet_objects":false,"features":"strict-worker-tenant-root-control-plane-entrypoint","started_at_ms":1793722608322}
@@ -61,6 +61,26 @@ function buildVerifiedWalletOperationEmailOtpFactorResult(fields) {
61
61
  ...fields
62
62
  };
63
63
  }
64
+ /** Only a verified operation statement yields this factor; its proof supplies the key and digest. */
65
+ function buildVerifiedWalletOperationVoiceIdFactorResult(fields) {
66
+ requireVerificationWindow(fields.verifiedAtMs, fields.expiresAtMs);
67
+ if (fields.expiresAtMs > fields.proof.statement.expiresAtMs) throw new Error("VoiceID factor cannot outlive its operation statement");
68
+ return {
69
+ kind: "verified_wallet_operation_voiceid_factor",
70
+ tenantId: fields.tenantId,
71
+ principalId: fields.principalId,
72
+ walletId: fields.walletId,
73
+ authorityRef: fields.authorityRef,
74
+ requestOrigin: fields.requestOrigin,
75
+ audience: fields.audience,
76
+ factorId: fields.factorId,
77
+ operation: fields.operation,
78
+ deviceKeyId: fields.proof.deviceKeyId,
79
+ assertionDigest: fields.proof.assertionDigest,
80
+ verifiedAtMs: fields.verifiedAtMs,
81
+ expiresAtMs: fields.expiresAtMs
82
+ };
83
+ }
64
84
  function buildVerifiedWalletSessionPasskeyFactorResult(fields) {
65
85
  requireVerificationWindow(fields.verifiedAtMs, fields.expiresAtMs);
66
86
  return {
@@ -242,6 +262,16 @@ async function buildWalletOperationFactorEvidence(evidenceId, factor) {
242
262
  verificationReceiptDigest: factor.verificationReceiptDigest
243
263
  })
244
264
  };
265
+ case "verified_wallet_operation_voiceid_factor": return {
266
+ evidenceId,
267
+ evidenceKind: AUTHORIZATION_EVIDENCE_KINDS.voiceIdDevice,
268
+ evidenceDigest: await digestCanonicalEvidence({
269
+ kind: factor.kind,
270
+ ...common,
271
+ deviceKeyId: factor.deviceKeyId,
272
+ assertionDigest: factor.assertionDigest
273
+ })
274
+ };
245
275
  }
246
276
  }
247
277
  async function buildOwnerProofFields(input) {
@@ -288,6 +318,7 @@ function ownerProofMethod(factor) {
288
318
  case "verified_wallet_operation_passkey_factor": return "passkey";
289
319
  case "verified_wallet_session_email_otp_factor":
290
320
  case "verified_wallet_operation_email_otp_factor": return "email_otp";
321
+ case "verified_wallet_operation_voiceid_factor": return "voiceid";
291
322
  }
292
323
  }
293
324
  function ownerProofAuthSource(factor) {
@@ -307,6 +338,10 @@ function ownerProofAuthSource(factor) {
307
338
  providerSubject: providerSubject.value
308
339
  };
309
340
  }
341
+ case "verified_wallet_operation_voiceid_factor": return {
342
+ kind: "voiceid",
343
+ deviceKeyId: factor.deviceKeyId
344
+ };
310
345
  }
311
346
  }
312
347
  function ownerProofReplayIdentity(factor) {
@@ -315,6 +350,7 @@ function ownerProofReplayIdentity(factor) {
315
350
  case "verified_wallet_operation_passkey_factor": return `passkey:${String(factor.factorId)}:${String(factor.assertionDigest)}`;
316
351
  case "verified_wallet_session_email_otp_factor":
317
352
  case "verified_wallet_operation_email_otp_factor": return `email_otp:${String(factor.factorId)}:${String(factor.challengeId)}:${String(factor.verificationReceiptDigest)}`;
353
+ case "verified_wallet_operation_voiceid_factor": return `voiceid:${String(factor.factorId)}:${String(factor.assertionDigest)}`;
318
354
  }
319
355
  }
320
356
  function requireOwnerProofFields(fields) {
@@ -347,6 +383,6 @@ function evidenceIdFromEvidence(evidence) {
347
383
  return evidence.evidenceId;
348
384
  }
349
385
  //#endregion
350
- export { buildVerifiedOwnerProof, buildVerifiedWalletOperationEmailOtpFactorResult, buildVerifiedWalletOperationFactorEvidenceSet, buildVerifiedWalletOperationPasskeyFactorResult, buildVerifiedWalletSessionEmailOtpFactorResult, buildVerifiedWalletSessionPasskeyFactorResult };
386
+ export { buildVerifiedOwnerProof, buildVerifiedWalletOperationEmailOtpFactorResult, buildVerifiedWalletOperationFactorEvidenceSet, buildVerifiedWalletOperationPasskeyFactorResult, buildVerifiedWalletOperationVoiceIdFactorResult, buildVerifiedWalletSessionEmailOtpFactorResult, buildVerifiedWalletSessionPasskeyFactorResult };
351
387
 
352
388
  //# sourceMappingURL=factorEvidence.js.map
@@ -1,6 +1,6 @@
1
1
  import { base64UrlDecode } from "../shared-ts/src/utils/base64.js";
2
2
  import { sha256DigestB64u } from "../shared-ts/src/utils/canonicalPrimitives.js";
3
- import { parseVoiceIdDeviceAssertion, voiceIdWalletSessionChallengeBytes } from "../shared-ts/src/authorization/voiceIdDeviceAssertion.js";
3
+ import { parseVoiceIdDeviceAssertion, parseVoiceIdOperationAssertion, voiceIdOperationStatementBytes, voiceIdWalletSessionChallengeBytes } from "../shared-ts/src/authorization/voiceIdDeviceAssertion.js";
4
4
  //#region src/authorization/voiceIdDeviceProof.ts
5
5
  var VerifiedVoiceIdWalletSessionProof = class {
6
6
  proofBrand = true;
@@ -19,14 +19,40 @@ async function verifyVoiceIdWalletSessionAssertion(input) {
19
19
  if (!Number.isSafeInteger(input.nowMs) || input.nowMs < challenge.issuedAtMs - 5e3 || input.nowMs >= challenge.expiresAtMs || challenge.walletId !== input.registered.walletId || challenge.walletAuthMethodId !== input.registered.walletAuthMethodId || challenge.walletAuthorityId !== input.registered.walletAuthorityId || challenge.deviceKeyId !== input.registered.deviceKeyId) throw new Error("VoiceID Wallet Session challenge is unavailable");
20
20
  const assertion = parseVoiceIdDeviceAssertion(input.assertion);
21
21
  if (!sameChallenge(assertion.challenge, challenge)) throw new Error("VoiceID assertion names a different challenge");
22
- const publicKeyBytes = base64UrlDecode(input.registered.publicKeyB64u);
23
- if (await sha256DigestB64u(publicKeyBytes) !== input.registered.deviceKeyId) throw new Error("VoiceID device key identity is invalid");
24
- const publicKey = await crypto.subtle.importKey("raw", publicKeyBytes, "Ed25519", false, ["verify"]);
25
- if (!await crypto.subtle.verify("Ed25519", publicKey, base64UrlDecode(assertion.signatureB64u), voiceIdWalletSessionChallengeBytes(challenge))) throw new Error("VoiceID device signature is invalid");
22
+ await requireRegisteredDeviceSignature(input.registered, assertion.signatureB64u, voiceIdWalletSessionChallengeBytes(challenge));
26
23
  if (!await input.consumeChallenge(challenge, input.nowMs)) throw new Error("VoiceID challenge was already consumed");
27
24
  return new VerifiedVoiceIdWalletSessionProof(challenge, input.registered.deviceKeyId);
28
25
  }
26
+ async function requireRegisteredDeviceSignature(registered, signatureB64u, signedBytes) {
27
+ const publicKeyBytes = base64UrlDecode(registered.publicKeyB64u);
28
+ if (await sha256DigestB64u(publicKeyBytes) !== registered.deviceKeyId) throw new Error("VoiceID device key identity is invalid");
29
+ const publicKey = await crypto.subtle.importKey("raw", publicKeyBytes, "Ed25519", false, ["verify"]);
30
+ if (!await crypto.subtle.verify("Ed25519", publicKey, base64UrlDecode(signatureB64u), signedBytes)) throw new Error("VoiceID device signature is invalid");
31
+ }
32
+ var VerifiedVoiceIdOperationStatementProof = class {
33
+ proofBrand = true;
34
+ constructor(statement, deviceKeyId, assertionDigest) {
35
+ this.statement = statement;
36
+ this.deviceKeyId = deviceKeyId;
37
+ this.assertionDigest = assertionDigest;
38
+ this.proofBrand;
39
+ }
40
+ };
41
+ /**
42
+ * Only this server boundary turns a signed operation statement into verified
43
+ * proof. The caller supplies the digest the operation expects and owns its
44
+ * single use, as it does for a passkey assertion over the same digest.
45
+ */
46
+ async function verifyVoiceIdOperationAssertion(input) {
47
+ const assertion = parseVoiceIdOperationAssertion(input.assertion);
48
+ const statement = assertion.statement;
49
+ if (!Number.isSafeInteger(input.nowMs) || input.nowMs < statement.issuedAtMs - 5e3 || input.nowMs >= statement.expiresAtMs || statement.walletId !== input.registered.walletId || statement.walletAuthMethodId !== input.registered.walletAuthMethodId || statement.walletAuthorityId !== input.registered.walletAuthorityId || statement.deviceKeyId !== input.registered.deviceKeyId || statement.operationKind !== input.operationKind || statement.operationChallenge !== input.operationChallenge || statement.requestOrigin !== input.requestOrigin) throw new Error("VoiceID operation statement does not match this operation");
50
+ const signedBytes = voiceIdOperationStatementBytes(statement);
51
+ await requireRegisteredDeviceSignature(input.registered, assertion.signatureB64u, signedBytes);
52
+ const assertionDigest = await sha256DigestB64u(new TextEncoder().encode(`${statement.operationChallenge}|${assertion.signatureB64u}`));
53
+ return new VerifiedVoiceIdOperationStatementProof(statement, input.registered.deviceKeyId, assertionDigest);
54
+ }
29
55
  //#endregion
30
- export { verifyVoiceIdWalletSessionAssertion };
56
+ export { verifyVoiceIdOperationAssertion, verifyVoiceIdWalletSessionAssertion };
31
57
 
32
58
  //# sourceMappingURL=voiceIdDeviceProof.js.map
@@ -834,7 +834,7 @@ function createStagingExportRequestScopedDependencies(env, service, tenantRootCu
834
834
  return {
835
835
  store: createStagingYaoPartitionedStateStore(env),
836
836
  backend: createStagingEd25519YaoBackend(env, createStagingTenantRootResolver(scope, tenantRootCustodyLineage, resolveActiveTenantRoot)),
837
- authorization: new RouterAbEd25519YaoExportOwnerProofAuthorizationAdapter(service.webAuthn, service.emailOtp, service.walletAuthMethods, service.authorizedOperations, service.walletRegistration.resolveEd25519MaterialActivation.bind(service.walletRegistration), authority.admitEstablishedHome.bind(authority)),
837
+ authorization: new RouterAbEd25519YaoExportOwnerProofAuthorizationAdapter(service.webAuthn, service.emailOtp, service.walletUnlock, service.walletAuthMethods, service.authorizedOperations, service.walletRegistration.resolveEd25519MaterialActivation.bind(service.walletRegistration), authority.admitEstablishedHome.bind(authority)),
838
838
  capabilities: createStagingYaoRequestScopedRuntime(env, registrationTenantRootResolver)
839
839
  };
840
840
  }
@@ -1238,6 +1238,7 @@ function createD1WalletUnlockRouteService(assembly) {
1238
1238
  return {
1239
1239
  issueVoiceIdChallenge: voiceIdSessions.issueChallenge.bind(voiceIdSessions),
1240
1240
  verifyAndIssueVoiceId: voiceIdSessions.verifyAndIssue.bind(voiceIdSessions),
1241
+ verifyVoiceIdOperation: voiceIdSessions.verifyOperation.bind(voiceIdSessions),
1241
1242
  createEmailOtpUnlockChallenge: assembly.emailOtpRecoveryService.createEmailOtpUnlockChallenge.bind(assembly.emailOtpRecoveryService),
1242
1243
  createWebAuthnLoginOptions: assembly.webAuthnAuthService.createWebAuthnLoginOptions.bind(assembly.webAuthnAuthService),
1243
1244
  markEmailOtpStrongAuthSatisfied: assembly.emailOtpRecoveryService.markEmailOtpStrongAuthSatisfied.bind(assembly.emailOtpRecoveryService),
@@ -1,6 +1,7 @@
1
1
  import { parsePrincipalId, parseTenantId } from "../../../../shared-ts/src/authorization/capabilityKinds.js";
2
+ import { buildVoiceIdWalletAuthAuthority } from "../../../../shared-ts/src/utils/walletAuthAuthority.js";
2
3
  import { isBillingCreditFailure } from "../../../../authorization/sessionRouting.js";
3
- import { verifyVoiceIdWalletSessionAssertion } from "../../../../authorization/voiceIdDeviceProof.js";
4
+ import { verifyVoiceIdOperationAssertion, verifyVoiceIdWalletSessionAssertion } from "../../../../authorization/voiceIdDeviceProof.js";
4
5
  import { isVoiceIdSeedEnvelope } from "../../../../shared-ts/src/passkey-custody/custodyEnvelope.js";
5
6
  import { DEFAULT_WALLET_SESSION_TTL_MS, LINKED_DEVICE_WALLET_SESSION_TTL_MS } from "../../../../shared-ts/src/threshold/sessionPolicy.js";
6
7
  import { isFullOwnerAuthorityV1 } from "./d1WalletAuthMethodService.js";
@@ -133,6 +134,38 @@ var D1VoiceIdSessions = class {
133
134
  custodyEnvelope: active.custodyEnvelope
134
135
  };
135
136
  }
137
+ /** Verifies a voice check for one operation; the operation's own claim makes it single use. */
138
+ async verifyOperation(input) {
139
+ const active = await this.resolveActiveMethod(input.walletId, input.walletAuthMethodId);
140
+ if (!active) return {
141
+ kind: "rejected",
142
+ code: "method_unavailable"
143
+ };
144
+ try {
145
+ return {
146
+ kind: "verified",
147
+ proof: await verifyVoiceIdOperationAssertion({
148
+ registered: active.registered,
149
+ assertion: input.assertion,
150
+ operationKind: input.operationKind,
151
+ operationChallenge: input.operationChallenge,
152
+ requestOrigin: input.requestOrigin,
153
+ nowMs: input.nowMs
154
+ }),
155
+ authority: buildVoiceIdWalletAuthAuthority({
156
+ walletId: input.walletId,
157
+ walletAuthMethodId: input.walletAuthMethodId,
158
+ deviceKeyId: active.authMethod.deviceKeyId
159
+ }),
160
+ custodyEnvelope: active.custodyEnvelope
161
+ };
162
+ } catch {
163
+ return {
164
+ kind: "rejected",
165
+ code: "invalid_assertion"
166
+ };
167
+ }
168
+ }
136
169
  };
137
170
  //#endregion
138
171
  export { D1VoiceIdSessions };