@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.
- package/README.md +4 -4
- package/artifact-manifest.json +11 -11
- package/cloudflare-router-ab/build/deriver-a/build-stamp.json +1 -1
- package/cloudflare-router-ab/build/deriver-b/build-stamp.json +1 -1
- package/cloudflare-router-ab/build/router/build-stamp.json +1 -1
- package/cloudflare-router-ab/build/signing-worker/build-stamp.json +1 -1
- package/cloudflare-router-ab/build/tenant-root-control-plane/build-stamp.json +1 -1
- package/dist/esm/authorization/factorEvidence.js +37 -1
- package/dist/esm/authorization/voiceIdDeviceProof.js +32 -6
- package/dist/esm/hosted-wallet-gateway.js +1 -1
- package/dist/esm/router/cloudflare/d1/auth/d1RouterApiAuthService.js +1 -0
- package/dist/esm/router/cloudflare/d1/wallet/d1VoiceIdSessions.js +34 -1
- package/dist/esm/router/cloudflare.js +317 -100
- package/dist/esm/router/domains/ed25519Yao/export/routerAbEd25519YaoExport.js +181 -14
- package/dist/esm/router/domains/ed25519Yao/export/routerAbEd25519YaoExportRequestScopedCloudflare.js +21 -5
- package/dist/esm/router/domains/signingOperations/routerAbOperationStepUp.js +4 -0
- package/dist/esm/router/transport/fetch/routes/ecdsaOperationStepUpFactor.js +51 -1
- package/dist/esm/router/transport/fetch/routes/thresholdEcdsa.js +3 -1
- package/dist/esm/shared-ts/src/authorization/capabilityKinds.js +2 -1
- package/dist/esm/shared-ts/src/authorization/voiceIdDeviceAssertion.js +70 -1
- package/dist/esm/shared-ts/src/utils/routerAbEcdsaDerivation.js +18 -1
- package/dist/esm/shared-ts/src/utils/routerAbEd25519YaoDigests.js +8 -1
- package/dist/types/shared-ts/src/authorization/capabilityKinds.d.ts +2 -1
- package/dist/types/shared-ts/src/authorization/voiceIdDeviceAssertion.d.ts +30 -0
- package/dist/types/shared-ts/src/utils/routerAbEcdsaDerivation.d.ts +11 -1
- package/dist/types/shared-ts/src/utils/routerAbEd25519YaoDigests.d.ts +3 -0
- package/dist/types/wallet-server/src/authorization/domain.d.ts +3 -0
- package/dist/types/wallet-server/src/authorization/factorEvidence.d.ts +11 -1
- package/dist/types/wallet-server/src/authorization/voiceIdDeviceProof.d.ts +27 -1
- package/dist/types/wallet-server/src/router/cloudflare/d1/wallet/d1VoiceIdSessions.d.ts +3 -1
- package/dist/types/wallet-server/src/router/domains/ed25519Yao/export/routerAbEd25519YaoExport.d.ts +36 -2
- package/dist/types/wallet-server/src/router/domains/voiceId/voiceIdSessions.d.ts +23 -1
- package/dist/types/wallet-server/src/router/framework/authServicePort.d.ts +1 -0
- package/dist/types/wallet-server/src/router/transport/fetch/routes/ecdsaOperationStepUpFactor.d.ts +2 -1
- 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.
|
|
8
|
-
`@seams/wallet@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.
|
|
12
|
+
pnpm add @seams/wallet-server@0.45.0
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Google BYO authentication
|
|
16
16
|
|
|
17
|
-
Version 0.
|
|
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.
|
package/artifact-manifest.json
CHANGED
|
@@ -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.
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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
|
-
|
|
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 };
|