@seams/wallet-server 0.9.3 → 0.10.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/THIRD_PARTY_NOTICES.md +33 -1
- package/artifact-manifest.json +57 -37
- package/cloudflare-router-ab/build/deriver-a/build-stamp.json +1 -1
- package/cloudflare-router-ab/build/deriver-a/index.js +2 -2
- 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.js +2 -2
- 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.js +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.js +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.js +1 -1
- package/cloudflare-router-ab/build/tenant-root-control-plane/index_bg.wasm +0 -0
- package/cloudflare-router-ab/migrations/deriver-a/0020_registration_preparation.sql +7 -0
- package/cloudflare-router-ab/migrations/deriver-b/0020_registration_preparation.sql +7 -0
- package/dist/esm/cloud-host.js +9 -9
- package/dist/esm/core/d1Ed25519SignerRead.js +3 -19
- package/dist/esm/hosted-wallet-gateway.js +15 -1
- package/dist/esm/localHostedWalletGatewayHandler.js +1 -1
- package/dist/esm/router/cloudflare/d1/authorization/d1AuthorizationStore.js +26 -20
- package/dist/esm/router/cloudflare/d1/ed25519Yao/d1Ed25519YaoProductRegistrationPartitionedStateStore.js +1 -1
- package/dist/esm/router/cloudflare/d1/registration/d1RegistrationCeremonyRecords.js +21 -2
- package/dist/esm/router/cloudflare/d1/registration/d1RegistrationCeremonyStore.js +11 -4
- package/dist/esm/router/cloudflare/d1/registration/d1RegistrationSetupRateLimit.js +34 -0
- package/dist/esm/router/cloudflare/d1/registration/d1WalletRegistrationCommitStore.js +17 -16
- package/dist/esm/router/cloudflare/d1/registration/d1WalletRegistrationService.js +45 -65
- package/dist/esm/router/cloudflare/d1/registration/d1WalletRegistrationSetupExecution.js +87 -10
- package/dist/esm/router/cloudflare/d1/wallet/d1WalletAddSignerService.js +1 -1
- package/dist/esm/router/cloudflare/runtime/walletGateway.js +2 -0
- package/dist/esm/router/cloudflare-adaptor.js +7 -7
- package/dist/esm/router/cloudflare.js +8812 -8594
- package/dist/esm/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoCapabilityCommit.js +45 -24
- package/dist/esm/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistration.js +52 -3
- package/dist/esm/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistrationPartitionedStateStore.js +1 -1
- package/dist/esm/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistrationPartitioning.js +13 -5
- package/dist/esm/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistrationRequestScopedRuntime.js +41 -7
- package/dist/esm/router/domains/ed25519Yao/recovery/routerAbEd25519YaoRecoveryRequestScopedCloudflare.js +1 -1
- package/dist/esm/router/domains/ed25519Yao/registration/routerAbEd25519YaoHttpRegistrationBackend.js +24 -4
- package/dist/esm/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistration.js +24 -14
- package/dist/esm/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistrationIntentAuthorization.js +10 -1
- package/dist/esm/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistrationRequestScopedCloudflare.js +45 -5
- package/dist/esm/router/domains/walletRegistration/walletRegistrationRoutes.js +48 -8
- package/dist/esm/router/express.js +107 -16
- package/dist/esm/router/framework/registrationSetupDispatch.js +28 -2
- package/dist/esm/router/framework/registrationSetupRateLimit.js +0 -0
- package/dist/esm/router/transport/fetch/routes/walletRegistration.js +3 -2
- package/dist/esm/storage/d1Retry.js +38 -0
- package/dist/types/shared-ts/src/utils/walletManagementProtocol.d.ts +1 -1
- package/dist/types/wallet-server/src/core/RegistrationCeremonyStore.d.ts +12 -0
- package/dist/types/wallet-server/src/core/d1Ed25519SignerRead.d.ts +1 -4
- package/dist/types/wallet-server/src/core/threeRouteRegistrationContracts.d.ts +50 -6
- package/dist/types/wallet-server/src/hosted-wallet-gateway.d.ts +1 -1
- package/dist/types/wallet-server/src/router/cloudflare/d1/registration/d1RegistrationCeremonyStore.d.ts +7 -1
- package/dist/types/wallet-server/src/router/cloudflare/d1/registration/d1RegistrationSetupRateLimit.d.ts +7 -0
- package/dist/types/wallet-server/src/router/cloudflare/d1/registration/d1WalletRegistrationService.d.ts +1 -1
- package/dist/types/wallet-server/src/router/cloudflare/d1/registration/d1WalletRegistrationSetupExecution.d.ts +3 -0
- package/dist/types/wallet-server/src/router/cloudflare/runtime/walletGateway.d.ts +1 -1
- package/dist/types/wallet-server/src/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoCapabilityCommit.d.ts +18 -4
- package/dist/types/wallet-server/src/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistration.d.ts +35 -4
- package/dist/types/wallet-server/src/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistrationRequestScopedRuntime.d.ts +1 -1
- package/dist/types/wallet-server/src/router/domains/ed25519Yao/recovery/routerAbEd25519YaoRecovery.d.ts +7 -0
- package/dist/types/wallet-server/src/router/domains/ed25519Yao/recovery/routerAbEd25519YaoRecoveryRequestScopedCloudflare.d.ts +2 -2
- package/dist/types/wallet-server/src/router/domains/ed25519Yao/registration/routerAbEd25519YaoHttpRegistrationBackend.d.ts +5 -3
- package/dist/types/wallet-server/src/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistration.d.ts +18 -3
- package/dist/types/wallet-server/src/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistrationIntentAuthorization.d.ts +2 -0
- package/dist/types/wallet-server/src/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistrationRequestScopedCloudflare.d.ts +39 -0
- package/dist/types/wallet-server/src/router/domains/walletRegistration/walletRegistrationInputs.d.ts +6 -0
- package/dist/types/wallet-server/src/router/domains/walletRegistration/walletRegistrationReservation.d.ts +16 -2
- package/dist/types/wallet-server/src/router/domains/walletRegistration/walletRegistrationRoutes.d.ts +1 -0
- package/dist/types/wallet-server/src/router/framework/registrationSetupRateLimit.d.ts +11 -0
- package/dist/types/wallet-server/src/router/framework/routerApi.d.ts +1 -0
- package/dist/types/wallet-server/src/storage/d1Retry.d.ts +10 -0
- package/migrations/d1-signer/0079_tenant_lookup_indexes.sql +33 -0
- package/migrations/d1-signer/0080_registration_setup_rate_limits.sql +11 -0
- package/package.json +1 -1
- package/src/README.md +1 -1
package/dist/esm/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoCapabilityCommit.js
CHANGED
|
@@ -1,42 +1,63 @@
|
|
|
1
|
-
import { InMemoryRouterAbEd25519YaoRecoveryService, InMemoryRouterAbEd25519YaoRecoveryStateV1 } from "../recovery/routerAbEd25519YaoRecovery.js";
|
|
1
|
+
import { InMemoryRouterAbEd25519YaoRecoveryService, InMemoryRouterAbEd25519YaoRecoveryStateV1, resolveRouterAbEd25519YaoActiveCapability } from "../recovery/routerAbEd25519YaoRecovery.js";
|
|
2
2
|
//#region src/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoCapabilityCommit.ts
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Checks a registration's capability against its admission and its result.
|
|
5
|
+
* The signer row of the wallet commit holds the capability, so a registration
|
|
6
|
+
* reads and writes no recovery state.
|
|
7
|
+
*/
|
|
8
|
+
function validateRouterAbEd25519YaoRegistrationCapability(installation) {
|
|
9
|
+
return capabilityService(new InMemoryRouterAbEd25519YaoRecoveryStateV1()).installRegistrationFinalizeCapability(installation);
|
|
6
10
|
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Stores a signer row's capability in the recovery state, where a recovery
|
|
13
|
+
* admission suspends it.
|
|
14
|
+
*/
|
|
15
|
+
async function rehydrateRouterAbEd25519YaoCapability(store, capability) {
|
|
11
16
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
12
|
-
const
|
|
13
|
-
const state =
|
|
14
|
-
|
|
15
|
-
for (const [key, capabilityKey] of snapshot.value.recoveryIdentityCapabilities) state.identityCapabilities.set(key, capabilityKey);
|
|
16
|
-
const result = install(new InMemoryRouterAbEd25519YaoRecoveryService({
|
|
17
|
-
admitRecovery: rejectProtocolExecution,
|
|
18
|
-
resolveRecoveryDispatchRoot: rejectProtocolExecution,
|
|
19
|
-
executeRecovery: rejectProtocolExecution,
|
|
20
|
-
activateRecovery: rejectProtocolExecution
|
|
21
|
-
}, state));
|
|
17
|
+
const snapshot = await store.loadCapabilities();
|
|
18
|
+
const state = recoveryStateFromSnapshot(snapshot);
|
|
19
|
+
const result = capabilityService(state).installPersistedActiveCapability(capability);
|
|
22
20
|
if (!result.ok) return result;
|
|
23
21
|
if ((await store.commitCapabilities(snapshot, {
|
|
24
22
|
capabilities: state.capabilities,
|
|
25
23
|
identityCapabilities: state.identityCapabilities
|
|
26
|
-
},
|
|
24
|
+
}, null)).kind === "stored") return result;
|
|
27
25
|
}
|
|
28
26
|
throw new Error("Capability state remained contended after one reconciliation");
|
|
29
27
|
}
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
/**
|
|
29
|
+
* The active capability of a signer row, as the recovery state allows it: a
|
|
30
|
+
* capability that a recovery suspended is not active, and one that a recovery
|
|
31
|
+
* retired conflicts. Nothing is written.
|
|
32
|
+
*/
|
|
33
|
+
function resolveRouterAbEd25519YaoPersistedActiveCapability(snapshot, persisted, lookup) {
|
|
34
|
+
const state = recoveryStateFromSnapshot(snapshot);
|
|
35
|
+
const installed = capabilityService(state).installPersistedActiveCapability(persisted);
|
|
36
|
+
if (!installed.ok) return {
|
|
37
|
+
ok: false,
|
|
38
|
+
code: "capability_conflict",
|
|
39
|
+
message: installed.message
|
|
40
|
+
};
|
|
41
|
+
return resolveRouterAbEd25519YaoActiveCapability(state.capabilities, lookup);
|
|
42
|
+
}
|
|
43
|
+
function recoveryStateFromSnapshot(snapshot) {
|
|
44
|
+
const state = new InMemoryRouterAbEd25519YaoRecoveryStateV1();
|
|
45
|
+
for (const [key, capability] of snapshot.value.recoveryCapabilities) state.capabilities.set(key, capability);
|
|
46
|
+
for (const [key, capabilityKey] of snapshot.value.recoveryIdentityCapabilities) state.identityCapabilities.set(key, capabilityKey);
|
|
47
|
+
return state;
|
|
32
48
|
}
|
|
33
|
-
function
|
|
34
|
-
return
|
|
49
|
+
function capabilityService(state) {
|
|
50
|
+
return new InMemoryRouterAbEd25519YaoRecoveryService({
|
|
51
|
+
admitRecovery: rejectProtocolExecution,
|
|
52
|
+
resolveRecoveryDispatchRoot: rejectProtocolExecution,
|
|
53
|
+
executeRecovery: rejectProtocolExecution,
|
|
54
|
+
activateRecovery: rejectProtocolExecution
|
|
55
|
+
}, state);
|
|
35
56
|
}
|
|
36
57
|
function rejectProtocolExecution() {
|
|
37
58
|
throw new Error("A capability commit cannot execute a protocol");
|
|
38
59
|
}
|
|
39
60
|
//#endregion
|
|
40
|
-
export {
|
|
61
|
+
export { rehydrateRouterAbEd25519YaoCapability, resolveRouterAbEd25519YaoPersistedActiveCapability, validateRouterAbEd25519YaoRegistrationCapability };
|
|
41
62
|
|
|
42
63
|
//# sourceMappingURL=routerAbEd25519YaoCapabilityCommit.js.map
|
|
@@ -223,10 +223,10 @@ var RouterAbEd25519YaoProductRegistrationRuntime = class {
|
|
|
223
223
|
startRegistrationDispatchRoot() {
|
|
224
224
|
return null;
|
|
225
225
|
}
|
|
226
|
-
async bindAndAdmitVerifiedRegistration(input) {
|
|
226
|
+
async bindAndAdmitVerifiedRegistration(input, _companionWrite, _startedDispatchRoot, mintedSessionId) {
|
|
227
227
|
const bound = await this.input.authorization.bindAndAuthorizeAdmission(input);
|
|
228
228
|
if (!bound.ok) return bound;
|
|
229
|
-
const admitted = await this.input.registrationService.admit(bound.admissionRequest);
|
|
229
|
+
const admitted = await this.input.registrationService.admit(bound.admissionRequest, void 0, mintedSessionId);
|
|
230
230
|
if (!admitted.ok) return admitted;
|
|
231
231
|
return {
|
|
232
232
|
ok: true,
|
|
@@ -236,6 +236,33 @@ var RouterAbEd25519YaoProductRegistrationRuntime = class {
|
|
|
236
236
|
companionWrite: "not_committed"
|
|
237
237
|
};
|
|
238
238
|
}
|
|
239
|
+
/** This runtime issues a receipt at its admission only. */
|
|
240
|
+
async describeRegistrationAdmission() {
|
|
241
|
+
return {
|
|
242
|
+
ok: false,
|
|
243
|
+
status: 503,
|
|
244
|
+
code: "admission_failed",
|
|
245
|
+
message: "This runtime describes no admission before its proof"
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
/** This runtime executes through its registration route only. */
|
|
249
|
+
async executeAdmittedRegistration() {
|
|
250
|
+
return {
|
|
251
|
+
result: {
|
|
252
|
+
ok: false,
|
|
253
|
+
status: 503,
|
|
254
|
+
code: "execution_failed",
|
|
255
|
+
message: "This runtime executes a registration through its execute route"
|
|
256
|
+
},
|
|
257
|
+
timing: {
|
|
258
|
+
credentialDigestMs: 0,
|
|
259
|
+
d1AdmissionReadMs: 0,
|
|
260
|
+
routerExecutionMs: 0,
|
|
261
|
+
routerServerTiming: null,
|
|
262
|
+
resultReconstructionMs: 0
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
}
|
|
239
266
|
async consumeActivated(request) {
|
|
240
267
|
return await this.input.registrationService.consumeActivated(request);
|
|
241
268
|
}
|
|
@@ -245,6 +272,10 @@ var RouterAbEd25519YaoProductRegistrationRuntime = class {
|
|
|
245
272
|
async resolveActiveCapability(input) {
|
|
246
273
|
return await this.input.capabilityResolver.resolveActiveCapability(input);
|
|
247
274
|
}
|
|
275
|
+
/** This runtime's recovery state already holds every capability it resolves. */
|
|
276
|
+
async rehydrateActiveCapability(input) {
|
|
277
|
+
return await this.input.capabilityResolver.resolveActiveCapability(input);
|
|
278
|
+
}
|
|
248
279
|
};
|
|
249
280
|
/**
|
|
250
281
|
* Projects the Ed25519 Yao view of one exact Wallet Session. Issuance itself
|
|
@@ -314,6 +345,24 @@ function createRouterAbEd25519YaoMaterialActivationRefV1(input) {
|
|
|
314
345
|
});
|
|
315
346
|
}
|
|
316
347
|
/**
|
|
348
|
+
* Mints the Yao identity of a registration's NEAR branch: its material
|
|
349
|
+
* identity and the session of its admission. Setup stores it, and the
|
|
350
|
+
* admission that follows the proof is issued over it.
|
|
351
|
+
*/
|
|
352
|
+
function mintRouterAbEd25519YaoRegistrationIdentityV1(input) {
|
|
353
|
+
const sessionId = new Uint8Array(32);
|
|
354
|
+
do
|
|
355
|
+
globalThis.crypto.getRandomValues(sessionId);
|
|
356
|
+
while (sessionId.every(isZeroByte));
|
|
357
|
+
return {
|
|
358
|
+
materialActivation: createRouterAbEd25519YaoMaterialActivationRefV1(input),
|
|
359
|
+
sessionId: Array.from(sessionId)
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function isZeroByte(byte) {
|
|
363
|
+
return byte === 0;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
317
366
|
* Takes the authority *scope* rather than the authority because setup admits
|
|
318
367
|
* before the proof exists. Callers holding a verified authority
|
|
319
368
|
* pass `registrationEd25519AuthorityScopeFromAuthority(authority)`; setup
|
|
@@ -400,6 +449,6 @@ async function buildRouterAbEd25519YaoAddSignerAdmissionRequestV1(input) {
|
|
|
400
449
|
return parsed.value;
|
|
401
450
|
}
|
|
402
451
|
//#endregion
|
|
403
|
-
export { buildRouterAbEd25519YaoAddSignerAdmissionRequestV1, buildRouterAbEd25519YaoProductAdmissionRequestV1, createRouterAbEd25519YaoMaterialActivationRefV1, createRouterAbEd25519YaoProductRegistrationCompositionFromPortsV1, createRouterAbEd25519YaoProductRegistrationRuntimeV1, createRouterAbEd25519YaoProductRegistrationStateFromPartsV1, createRouterAbEd25519YaoProductRegistrationStateV1, parseRouterAbEd25519YaoProductRegistrationStateV1, projectRouterAbEd25519YaoExactWalletSession, routerAbEd25519YaoPersistedCapabilityMatchesLookupV1 };
|
|
452
|
+
export { buildRouterAbEd25519YaoAddSignerAdmissionRequestV1, buildRouterAbEd25519YaoProductAdmissionRequestV1, createRouterAbEd25519YaoMaterialActivationRefV1, createRouterAbEd25519YaoProductRegistrationCompositionFromPortsV1, createRouterAbEd25519YaoProductRegistrationRuntimeV1, createRouterAbEd25519YaoProductRegistrationStateFromPartsV1, createRouterAbEd25519YaoProductRegistrationStateV1, mintRouterAbEd25519YaoRegistrationIdentityV1, parseRouterAbEd25519YaoProductRegistrationStateV1, projectRouterAbEd25519YaoExactWalletSession, routerAbEd25519YaoPersistedCapabilityMatchesLookupV1 };
|
|
404
453
|
|
|
405
454
|
//# sourceMappingURL=routerAbEd25519YaoProductRegistration.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { buildRouterAbEd25519YaoRegistrationExecutionAuthorityV1 } from "../registration/routerAbEd25519YaoRegistrationExecutionRecord.js";
|
|
2
1
|
import { createRouterAbEd25519YaoProductRegistrationStateV1 } from "./routerAbEd25519YaoProductRegistration.js";
|
|
3
2
|
import { encodeRouterAbEd25519YaoProductRegistrationStateV1, parseRouterAbEd25519YaoProductRegistrationStateJsonV1 } from "./routerAbEd25519YaoProductRegistrationPersistence.js";
|
|
4
3
|
import { boundedRouterAbEd25519YaoProductRegistrationSharedStateV1, mergeRouterAbEd25519YaoProductRegistrationStatePartitionV1, partitionRouterAbEd25519YaoProductRegistrationStateV1 } from "./routerAbEd25519YaoProductRegistrationPartitioning.js";
|
|
4
|
+
import { buildRouterAbEd25519YaoRegistrationExecutionAuthorityV1 } from "../registration/routerAbEd25519YaoRegistrationExecutionRecord.js";
|
|
5
5
|
//#region src/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistrationPartitionedStateStore.ts
|
|
6
6
|
const ROUTER_AB_ED25519_YAO_SHARED_STATE_RECORD_KEY_V1 = "router-ab-ed25519-yao:shared";
|
|
7
7
|
const PARTITION_RECORD_CODEC_KIND = "router_ab_ed25519_yao_product_registration_partition_record_json_v1";
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { createRouterAbEd25519YaoProductRegistrationStateFromPartsV1 } from "./routerAbEd25519YaoProductRegistration.js";
|
|
2
2
|
//#region src/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistrationPartitioning.ts
|
|
3
|
-
|
|
3
|
+
/** A suspended capability belongs to a recovery in progress and has no other record. */
|
|
4
|
+
const MAX_SUSPENDED_RECOVERY_CAPABILITIES = 32;
|
|
5
|
+
/**
|
|
6
|
+
* An active or a retired capability repeats its signer row. A recovery stores
|
|
7
|
+
* one between its installation and its suspension, so only the newest few stay.
|
|
8
|
+
*/
|
|
9
|
+
const MAX_SETTLED_RECOVERY_CAPABILITIES = 4;
|
|
4
10
|
/**
|
|
5
11
|
* Projects the tenant-wide state into shared and lifecycle-owned records.
|
|
6
12
|
* Capability ownership and export nonce replay state deliberately stay in the
|
|
@@ -107,14 +113,16 @@ function boundedRouterAbEd25519YaoProductRegistrationSharedStateV1(source) {
|
|
|
107
113
|
};
|
|
108
114
|
}
|
|
109
115
|
function boundedRecoveryCapabilities(source) {
|
|
110
|
-
if (source.size <= MAX_SHARED_RECOVERY_CAPABILITIES) return new Map(source);
|
|
111
116
|
const entries = [...source.entries()];
|
|
112
117
|
const suspended = entries.filter(([, capability]) => capability.kind === "suspended");
|
|
113
118
|
const retained = /* @__PURE__ */ new Set();
|
|
114
|
-
for (const [key] of suspended.slice(-
|
|
115
|
-
|
|
119
|
+
for (const [key] of suspended.slice(-MAX_SUSPENDED_RECOVERY_CAPABILITIES)) retained.add(key);
|
|
120
|
+
let settled = 0;
|
|
121
|
+
for (let index = entries.length - 1; index >= 0 && settled < MAX_SETTLED_RECOVERY_CAPABILITIES; index -= 1) {
|
|
116
122
|
const entry = entries[index];
|
|
117
|
-
if (entry
|
|
123
|
+
if (!entry || entry[1].kind === "suspended") continue;
|
|
124
|
+
retained.add(entry[0]);
|
|
125
|
+
settled += 1;
|
|
118
126
|
}
|
|
119
127
|
const bounded = /* @__PURE__ */ new Map();
|
|
120
128
|
for (const [key, capability] of entries) if (retained.has(key)) bounded.set(key, capability);
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { InMemoryRouterAbEd25519YaoRegistrationService } from "../registration/routerAbEd25519YaoRegistration.js";
|
|
2
|
-
import { InMemoryRouterAbEd25519YaoRegistrationIntentAuthorizationAdapter } from "../registration/routerAbEd25519YaoRegistrationIntentAuthorization.js";
|
|
3
|
-
import { pinRouterAbEd25519YaoRegistrationDispatchRootV1, routerAbEd25519YaoRegistrationExecuteRequestFromRouterRequestJsonV1, routerAbEd25519YaoRegistrationResultFromRouterAnswerV1 } from "../registration/routerAbEd25519YaoRegistrationExecutionRecord.js";
|
|
1
|
+
import { InMemoryRouterAbEd25519YaoRegistrationService, describeRouterAbEd25519YaoRegistrationAdmissionV1 } from "../registration/routerAbEd25519YaoRegistration.js";
|
|
2
|
+
import { InMemoryRouterAbEd25519YaoRegistrationIntentAuthorizationAdapter, routerAbEd25519YaoCredentialDigestSha256HexV1 } from "../registration/routerAbEd25519YaoRegistrationIntentAuthorization.js";
|
|
4
3
|
import { resolveRouterAbEd25519YaoActiveCapability } from "../recovery/routerAbEd25519YaoRecovery.js";
|
|
5
4
|
import { routerAbEd25519YaoRegistrationSigningRootIdV1 } from "../routerAbEd25519YaoGatewayEnvelope.js";
|
|
6
5
|
import { routerAbEd25519YaoPersistedCapabilityMatchesLookupV1 } from "./routerAbEd25519YaoProductRegistration.js";
|
|
7
|
-
import { routerAbEd25519YaoAdmittedRegistrationAuthorityV1 } from "./routerAbEd25519YaoProductRegistrationPartitionedStateStore.js";
|
|
8
6
|
import { parseRouterAbEd25519YaoRegistrationRouterAnswerV1 } from "../registration/routerAbEd25519YaoHttpRegistrationBackend.js";
|
|
9
|
-
import {
|
|
7
|
+
import { pinRouterAbEd25519YaoRegistrationDispatchRootV1, routerAbEd25519YaoRegistrationExecuteRequestFromRouterRequestJsonV1, routerAbEd25519YaoRegistrationResultFromRouterAnswerV1 } from "../registration/routerAbEd25519YaoRegistrationExecutionRecord.js";
|
|
8
|
+
import { routerAbEd25519YaoAdmittedRegistrationAuthorityV1 } from "./routerAbEd25519YaoProductRegistrationPartitionedStateStore.js";
|
|
9
|
+
import { executeRouterAbEd25519YaoAdmittedRegistrationV1 } from "../registration/routerAbEd25519YaoRegistrationRequestScopedCloudflare.js";
|
|
10
|
+
import { rehydrateRouterAbEd25519YaoCapability, resolveRouterAbEd25519YaoPersistedActiveCapability } from "./routerAbEd25519YaoCapabilityCommit.js";
|
|
10
11
|
//#region src/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistrationRequestScopedRuntime.ts
|
|
11
12
|
const MAX_DETERMINISTIC_COMMIT_ATTEMPTS = 2;
|
|
12
13
|
/**
|
|
@@ -43,15 +44,33 @@ var RouterAbEd25519YaoProductRegistrationRequestScopedRuntime = class {
|
|
|
43
44
|
dispatchRoot
|
|
44
45
|
};
|
|
45
46
|
}
|
|
46
|
-
async bindAndAdmitVerifiedRegistration(input, companionWrite, startedDispatchRoot) {
|
|
47
|
+
async bindAndAdmitVerifiedRegistration(input, companionWrite, startedDispatchRoot, mintedSessionId) {
|
|
47
48
|
return await bindAndAdmitVerifiedRegistration({
|
|
48
49
|
input,
|
|
49
50
|
companionWrite,
|
|
50
51
|
startedDispatchRoot,
|
|
52
|
+
mintedSessionId,
|
|
51
53
|
store: this.input.store,
|
|
52
54
|
backend: this.input.registrationBackend
|
|
53
55
|
});
|
|
54
56
|
}
|
|
57
|
+
async describeRegistrationAdmission(request, mintedSessionId) {
|
|
58
|
+
return await describeRouterAbEd25519YaoRegistrationAdmissionV1({
|
|
59
|
+
backend: this.input.registrationBackend,
|
|
60
|
+
request,
|
|
61
|
+
mintedSessionId
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
async executeAdmittedRegistration(input) {
|
|
65
|
+
return await executeRouterAbEd25519YaoAdmittedRegistrationV1({
|
|
66
|
+
store: this.input.store,
|
|
67
|
+
backend: this.input.registrationBackend,
|
|
68
|
+
request: input.request,
|
|
69
|
+
credentialDigestSha256Hex: await routerAbEd25519YaoCredentialDigestSha256HexV1(input.credential),
|
|
70
|
+
credentialDigestMs: 0,
|
|
71
|
+
trace: input.trace
|
|
72
|
+
});
|
|
73
|
+
}
|
|
55
74
|
/**
|
|
56
75
|
* Consumes a registration's activation at the Router, which owns its
|
|
57
76
|
* execution: the first consumer binding wins, and the same binding
|
|
@@ -102,7 +121,21 @@ var RouterAbEd25519YaoProductRegistrationRequestScopedRuntime = class {
|
|
|
102
121
|
async installPersistedActiveCapability(input) {
|
|
103
122
|
return await rehydrateRouterAbEd25519YaoCapability(this.input.store, input);
|
|
104
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* The signer row holds a wallet's capability, and the recovery state says
|
|
126
|
+
* whether a recovery suspended it. Both are read together and nothing is
|
|
127
|
+
* written, so a lookup never contends with another wallet.
|
|
128
|
+
*/
|
|
105
129
|
async resolveActiveCapability(input) {
|
|
130
|
+
const invalid = resolveRouterAbEd25519YaoActiveCapability(NO_CAPABILITIES, input);
|
|
131
|
+
if (!invalid.ok && invalid.code === "invalid_lookup") return invalid;
|
|
132
|
+
const loadPersisted = this.input.loadPersistedActiveCapability;
|
|
133
|
+
const [loaded, persisted] = await Promise.all([this.input.store.loadCapabilities(), loadPersisted ? loadPersisted(input) : null]);
|
|
134
|
+
const result = resolveRouterAbEd25519YaoActiveCapability(loaded.value.recoveryCapabilities, input);
|
|
135
|
+
if (result.ok || result.code !== "unknown_capability" || !persisted || !routerAbEd25519YaoPersistedCapabilityMatchesLookupV1(persisted, input)) return result;
|
|
136
|
+
return resolveRouterAbEd25519YaoPersistedActiveCapability(loaded, persisted, input);
|
|
137
|
+
}
|
|
138
|
+
async rehydrateActiveCapability(input) {
|
|
106
139
|
const result = resolveRouterAbEd25519YaoActiveCapability((await this.input.store.loadCapabilities()).value.recoveryCapabilities, input);
|
|
107
140
|
if (result.ok || result.code !== "unknown_capability" || !this.input.loadPersistedActiveCapability) return result;
|
|
108
141
|
const persisted = await this.input.loadPersistedActiveCapability(input);
|
|
@@ -116,6 +149,7 @@ var RouterAbEd25519YaoProductRegistrationRequestScopedRuntime = class {
|
|
|
116
149
|
return resolveRouterAbEd25519YaoActiveCapability((await this.input.store.loadCapabilities()).value.recoveryCapabilities, input);
|
|
117
150
|
}
|
|
118
151
|
};
|
|
152
|
+
const NO_CAPABILITIES = /* @__PURE__ */ new Map();
|
|
119
153
|
/**
|
|
120
154
|
* Binds a verified intent and admits its registration. The tenant root the
|
|
121
155
|
* registration dispatches to is resolved once, for a fresh admission, and
|
|
@@ -161,7 +195,7 @@ async function bindAndAdmitVerifiedRegistration(input) {
|
|
|
161
195
|
}
|
|
162
196
|
}
|
|
163
197
|
if (backendResult === null) try {
|
|
164
|
-
backendResult = await input.backend.admit(bound.admissionRequest);
|
|
198
|
+
backendResult = await input.backend.admit(bound.admissionRequest, void 0, input.mintedSessionId);
|
|
165
199
|
} catch (error) {
|
|
166
200
|
return {
|
|
167
201
|
ok: false,
|
|
@@ -374,7 +374,7 @@ async function runRecoveryRequest(context, request) {
|
|
|
374
374
|
async function runAdmissionRequest(context, request) {
|
|
375
375
|
const first = await runAdmissionTwoPhase(context, request);
|
|
376
376
|
if (first.kind !== "rejected" || first.value.ok || first.value.code !== "unknown_capability") return mapAdmissionResult(first);
|
|
377
|
-
const resolved = await context.input.capabilities.
|
|
377
|
+
const resolved = await context.input.capabilities.rehydrateActiveCapability({
|
|
378
378
|
kind: "router_ab_ed25519_yao_active_capability_lookup_v1",
|
|
379
379
|
walletId: request.application_binding.wallet_id,
|
|
380
380
|
nearEd25519SigningKeyId: request.application_binding.near_ed25519_signing_key_id,
|
package/dist/esm/router/domains/ed25519Yao/registration/routerAbEd25519YaoHttpRegistrationBackend.js
CHANGED
|
@@ -88,6 +88,9 @@ function randomSession() {
|
|
|
88
88
|
while (isZero(bytes));
|
|
89
89
|
return Array.from(bytes);
|
|
90
90
|
}
|
|
91
|
+
function isSessionId(bytes) {
|
|
92
|
+
return bytes.length === 32 && bytes.every((byte) => Number.isInteger(byte) && byte >= 0 && byte <= 255) && bytes.some((byte) => byte !== 0);
|
|
93
|
+
}
|
|
91
94
|
function isZero(bytes) {
|
|
92
95
|
for (const byte of bytes) if (byte !== 0) return false;
|
|
93
96
|
return true;
|
|
@@ -415,8 +418,19 @@ var RouterAbEd25519YaoHttpRegistrationBackend = class {
|
|
|
415
418
|
this.lastRouterServerTiming = null;
|
|
416
419
|
return timing;
|
|
417
420
|
}
|
|
418
|
-
async
|
|
419
|
-
|
|
421
|
+
async prepareRegistrationPair(identity, request, receipt, expiresAtMs) {
|
|
422
|
+
const tenantRoot = await this.resolveRegistrationDispatchRoot(routerAbEd25519YaoRegistrationSigningRootIdV1(request));
|
|
423
|
+
if (!(await this.post("/router-ab/router/ed25519-yao/registration/prepare", identity, {
|
|
424
|
+
tenant_root: tenantRoot,
|
|
425
|
+
application: request.application_binding,
|
|
426
|
+
participant_ids: request.participant_ids,
|
|
427
|
+
binding: receipt.binding,
|
|
428
|
+
ownership_generation: identity.ownershipGeneration,
|
|
429
|
+
expires_at_ms: expiresAtMs
|
|
430
|
+
}, createRouterAbTraceContextV1().value, "exact")).ok) throw new Error("Registration pair preparation failed");
|
|
431
|
+
}
|
|
432
|
+
async admit(request, _traceContext, mintedSessionId) {
|
|
433
|
+
return await this.admitActivation(request, "registration", mintedSessionId);
|
|
420
434
|
}
|
|
421
435
|
async admitRecovery(request, _traceContext) {
|
|
422
436
|
return await this.admitActivation(request, "recovery");
|
|
@@ -477,7 +491,7 @@ var RouterAbEd25519YaoHttpRegistrationBackend = class {
|
|
|
477
491
|
signing_worker_recipient_public_key: this.config.signingWorkerRecipientPublicKey
|
|
478
492
|
};
|
|
479
493
|
}
|
|
480
|
-
async admitActivation(request, operation) {
|
|
494
|
+
async admitActivation(request, operation, mintedSessionId) {
|
|
481
495
|
if (request.scope.signing_worker_id !== this.config.signingWorkerId) return {
|
|
482
496
|
ok: false,
|
|
483
497
|
status: 400,
|
|
@@ -486,7 +500,13 @@ var RouterAbEd25519YaoHttpRegistrationBackend = class {
|
|
|
486
500
|
};
|
|
487
501
|
const stableContextBinding = await deriveRouterAbEd25519YaoStableContextBindingV1(request.application_binding, request.participant_ids);
|
|
488
502
|
const keyset = this.keyset();
|
|
489
|
-
|
|
503
|
+
if (mintedSessionId !== void 0 && !isSessionId(mintedSessionId)) return {
|
|
504
|
+
ok: false,
|
|
505
|
+
status: 500,
|
|
506
|
+
code: "admission_failed",
|
|
507
|
+
message: `${operation} minted session is invalid`
|
|
508
|
+
};
|
|
509
|
+
const sessionId = mintedSessionId === void 0 ? randomSession() : [...mintedSessionId];
|
|
490
510
|
switch (operation) {
|
|
491
511
|
case "registration": return {
|
|
492
512
|
ok: true,
|
|
@@ -42,6 +42,25 @@ function canonicalWireFingerprint(value) {
|
|
|
42
42
|
function encodeRouterAbEd25519YaoRegistrationAdmissionFingerprintV1(request) {
|
|
43
43
|
return canonicalWireFingerprint(request);
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* The receipt that `backend` issues for `request` over the session that setup
|
|
47
|
+
* minted, checked as an admission checks it. It stores nothing and admits
|
|
48
|
+
* nothing: the admission still follows the verified proof.
|
|
49
|
+
*/
|
|
50
|
+
async function describeRouterAbEd25519YaoRegistrationAdmissionV1(input) {
|
|
51
|
+
return admissionReceiptFromBackend(input.request, await input.backend.admit(input.request, void 0, input.mintedSessionId));
|
|
52
|
+
}
|
|
53
|
+
function admissionReceiptFromBackend(request, backendResult) {
|
|
54
|
+
if (!backendResult.ok) return backendFailure(backendResult, "admission_failed");
|
|
55
|
+
const parsed = parseRouterAbEd25519YaoRegistrationActivationAdmissionReceiptV1(backendResult.body);
|
|
56
|
+
if (!parsed.ok) return invalidBackendResponse(parsed.message);
|
|
57
|
+
if (!registrationScopeMatchesReceipt(request, parsed.value)) return invalidBackendResponse("registration admission receipt scope does not match request");
|
|
58
|
+
return {
|
|
59
|
+
ok: true,
|
|
60
|
+
status: 200,
|
|
61
|
+
value: parsed.value
|
|
62
|
+
};
|
|
63
|
+
}
|
|
45
64
|
function registrationScopeMatchesReceipt(request, receipt) {
|
|
46
65
|
const scope = request.scope;
|
|
47
66
|
const lifecycle = receipt.binding.lifecycle;
|
|
@@ -205,7 +224,7 @@ var InMemoryRouterAbEd25519YaoRegistrationService = class {
|
|
|
205
224
|
this.lifecycleSessions = state.lifecycleSessions;
|
|
206
225
|
this.admissionClaims = state.admissionClaims;
|
|
207
226
|
}
|
|
208
|
-
async admit(request, traceContext) {
|
|
227
|
+
async admit(request, traceContext, mintedSessionId) {
|
|
209
228
|
const preparation = this.prepareAdmit(request);
|
|
210
229
|
switch (preparation.kind) {
|
|
211
230
|
case "completed": return {
|
|
@@ -219,7 +238,7 @@ var InMemoryRouterAbEd25519YaoRegistrationService = class {
|
|
|
219
238
|
try {
|
|
220
239
|
outcome = {
|
|
221
240
|
kind: "backend_response",
|
|
222
|
-
result: await this.backend.admit(request, traceContext)
|
|
241
|
+
result: await this.backend.admit(request, traceContext, mintedSessionId)
|
|
223
242
|
};
|
|
224
243
|
} catch (error) {
|
|
225
244
|
outcome = {
|
|
@@ -290,19 +309,10 @@ var InMemoryRouterAbEd25519YaoRegistrationService = class {
|
|
|
290
309
|
code: "admission_uncertain",
|
|
291
310
|
message: input.outcome.message
|
|
292
311
|
};
|
|
293
|
-
const
|
|
294
|
-
if (!backendResult.ok) {
|
|
295
|
-
this.admissionClaims.delete(input.claim.lifecycleId);
|
|
296
|
-
return backendFailure(backendResult, "admission_failed");
|
|
297
|
-
}
|
|
298
|
-
const parsed = parseRouterAbEd25519YaoRegistrationActivationAdmissionReceiptV1(backendResult.body);
|
|
312
|
+
const parsed = admissionReceiptFromBackend(input.request, input.outcome.result);
|
|
299
313
|
if (!parsed.ok) {
|
|
300
314
|
this.admissionClaims.delete(input.claim.lifecycleId);
|
|
301
|
-
return
|
|
302
|
-
}
|
|
303
|
-
if (!registrationScopeMatchesReceipt(input.request, parsed.value)) {
|
|
304
|
-
this.admissionClaims.delete(input.claim.lifecycleId);
|
|
305
|
-
return invalidBackendResponse("registration admission receipt scope does not match request");
|
|
315
|
+
return parsed;
|
|
306
316
|
}
|
|
307
317
|
const key = registrationSessionKey(parsed.value);
|
|
308
318
|
if (this.states.has(key)) return {
|
|
@@ -551,6 +561,6 @@ var InMemoryRouterAbEd25519YaoRegistrationService = class {
|
|
|
551
561
|
}
|
|
552
562
|
};
|
|
553
563
|
//#endregion
|
|
554
|
-
export { InMemoryRouterAbEd25519YaoRegistrationService, InMemoryRouterAbEd25519YaoRegistrationStateV1, createRouterAbEd25519YaoRegistrationModule, encodeRouterAbEd25519YaoRegistrationAdmissionFingerprintV1, routerAbEd25519YaoExecutionMatchesAdmissionV1 };
|
|
564
|
+
export { InMemoryRouterAbEd25519YaoRegistrationService, InMemoryRouterAbEd25519YaoRegistrationStateV1, createRouterAbEd25519YaoRegistrationModule, describeRouterAbEd25519YaoRegistrationAdmissionV1, encodeRouterAbEd25519YaoRegistrationAdmissionFingerprintV1, routerAbEd25519YaoExecutionMatchesAdmissionV1 };
|
|
555
565
|
|
|
556
566
|
//# sourceMappingURL=routerAbEd25519YaoRegistration.js.map
|
|
@@ -65,6 +65,15 @@ async function routerAbEd25519YaoBearerCredentialDigestV1(request) {
|
|
|
65
65
|
function routerAbEd25519YaoCredentialDigestHexV1(digest) {
|
|
66
66
|
return bytesToHex(digest);
|
|
67
67
|
}
|
|
68
|
+
/** The digest that an admission binds for the credential of its registration intent. */
|
|
69
|
+
async function routerAbEd25519YaoCredentialDigestSha256HexV1(credential) {
|
|
70
|
+
const digest = await credentialDigestSha256(credential);
|
|
71
|
+
try {
|
|
72
|
+
return bytesToHex(digest);
|
|
73
|
+
} finally {
|
|
74
|
+
digest.fill(0);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
68
77
|
function bytesToHex(bytes) {
|
|
69
78
|
let encoded = "";
|
|
70
79
|
for (const byte of bytes) encoded += byte.toString(16).padStart(2, "0");
|
|
@@ -356,6 +365,6 @@ var InMemoryRouterAbEd25519YaoRegistrationIntentAuthorizationAdapter = class {
|
|
|
356
365
|
}
|
|
357
366
|
};
|
|
358
367
|
//#endregion
|
|
359
|
-
export { InMemoryRouterAbEd25519YaoRegistrationIntentAuthorizationAdapter, InMemoryRouterAbEd25519YaoRegistrationIntentAuthorizationStateV1, routerAbEd25519YaoBearerCredentialDigestV1, routerAbEd25519YaoCredentialDigestHexV1 };
|
|
368
|
+
export { InMemoryRouterAbEd25519YaoRegistrationIntentAuthorizationAdapter, InMemoryRouterAbEd25519YaoRegistrationIntentAuthorizationStateV1, routerAbEd25519YaoBearerCredentialDigestV1, routerAbEd25519YaoCredentialDigestHexV1, routerAbEd25519YaoCredentialDigestSha256HexV1 };
|
|
360
369
|
|
|
361
370
|
//# sourceMappingURL=routerAbEd25519YaoRegistrationIntentAuthorization.js.map
|
|
@@ -3,8 +3,8 @@ import { ROUTER_AB_TRACE_ID_HEADER_V1, createRouterAbTraceContextV1, parseRouter
|
|
|
3
3
|
import { json, readJson } from "../../../framework/http.js";
|
|
4
4
|
import { InMemoryRouterAbEd25519YaoRegistrationService, routerAbEd25519YaoExecutionMatchesAdmissionV1 } from "./routerAbEd25519YaoRegistration.js";
|
|
5
5
|
import { InMemoryRouterAbEd25519YaoRegistrationIntentAuthorizationAdapter, routerAbEd25519YaoBearerCredentialDigestV1 } from "./routerAbEd25519YaoRegistrationIntentAuthorization.js";
|
|
6
|
-
import { pinRouterAbEd25519YaoRegistrationDispatchRootV1, routerAbEd25519YaoRegistrationResultFromRouterAnswerV1 } from "./routerAbEd25519YaoRegistrationExecutionRecord.js";
|
|
7
6
|
import { routerAbEd25519YaoRegistrationSigningRootIdV1 } from "../routerAbEd25519YaoGatewayEnvelope.js";
|
|
7
|
+
import { pinRouterAbEd25519YaoRegistrationDispatchRootV1, routerAbEd25519YaoRegistrationResultFromRouterAnswerV1 } from "./routerAbEd25519YaoRegistrationExecutionRecord.js";
|
|
8
8
|
import { routerAbEd25519YaoAdmittedRegistrationAuthorityV1 } from "../capabilityLifecycle/routerAbEd25519YaoProductRegistrationPartitionedStateStore.js";
|
|
9
9
|
import { runRouterAbEd25519YaoRegistrationTwoPhaseV1 } from "./routerAbEd25519YaoRegistrationTwoPhaseRunner.js";
|
|
10
10
|
//#region src/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistrationRequestScopedCloudflare.ts
|
|
@@ -172,17 +172,41 @@ async function runAdmissionRequest(input, request, trace) {
|
|
|
172
172
|
* again, so a completed execution's answer outlives the root's lineage.
|
|
173
173
|
*/
|
|
174
174
|
async function runExecutionRequest(input, request, trace) {
|
|
175
|
-
const lifecycleId = request.binding.lifecycle.lifecycle_id;
|
|
176
175
|
const credentialStartedAt = performance.now();
|
|
177
176
|
const credential = await routerAbEd25519YaoBearerCredentialDigestV1(input.request);
|
|
177
|
+
const credentialDigestMs = elapsedMs(credentialStartedAt);
|
|
178
|
+
if (!credential.ok) return timedExecutionResult(credential.result, {
|
|
179
|
+
credentialDigestMs,
|
|
180
|
+
d1AdmissionReadMs: 0,
|
|
181
|
+
routerExecutionMs: 0,
|
|
182
|
+
routerServerTiming: null,
|
|
183
|
+
resultReconstructionMs: 0
|
|
184
|
+
});
|
|
185
|
+
return await executeRouterAbEd25519YaoAdmittedRegistrationV1({
|
|
186
|
+
store: input.store,
|
|
187
|
+
backend: input.backend,
|
|
188
|
+
request,
|
|
189
|
+
credentialDigestSha256Hex: credential.digestSha256Hex,
|
|
190
|
+
credentialDigestMs,
|
|
191
|
+
trace
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Runs one admitted registration for the holder of its credential. The
|
|
196
|
+
* execute route takes the credential from its bearer. A respond that carries
|
|
197
|
+
* the execute request takes it from the signed setup that it just verified.
|
|
198
|
+
*/
|
|
199
|
+
async function executeRouterAbEd25519YaoAdmittedRegistrationV1(input) {
|
|
200
|
+
const { request, trace } = input;
|
|
201
|
+
const credential = { digestSha256Hex: input.credentialDigestSha256Hex };
|
|
202
|
+
const lifecycleId = request.binding.lifecycle.lifecycle_id;
|
|
178
203
|
const timing = {
|
|
179
|
-
credentialDigestMs:
|
|
204
|
+
credentialDigestMs: input.credentialDigestMs,
|
|
180
205
|
d1AdmissionReadMs: 0,
|
|
181
206
|
routerExecutionMs: 0,
|
|
182
207
|
routerServerTiming: null,
|
|
183
208
|
resultReconstructionMs: 0
|
|
184
209
|
};
|
|
185
|
-
if (!credential.ok) return timedExecutionResult(credential.result, timing);
|
|
186
210
|
const admissionStartedAt = performance.now();
|
|
187
211
|
const authority = routerAbEd25519YaoAdmittedRegistrationAuthorityV1((await input.store.loadRegistration(lifecycleId)).state, lifecycleId);
|
|
188
212
|
const timingBeforeRouter = {
|
|
@@ -356,6 +380,22 @@ function registrationResultResponse(result, timing) {
|
|
|
356
380
|
}
|
|
357
381
|
return response;
|
|
358
382
|
}
|
|
383
|
+
/**
|
|
384
|
+
* The timing of one execution as Server-Timing entries, for a route that
|
|
385
|
+
* reports them in its own header: a respond that ran the execution.
|
|
386
|
+
*/
|
|
387
|
+
function routerAbEd25519YaoRegistrationExecutionTimingEntriesV1(timing) {
|
|
388
|
+
const entries = [
|
|
389
|
+
["yao_d1_admission_read", timing.d1AdmissionReadMs],
|
|
390
|
+
["yao_router_execution", timing.routerExecutionMs],
|
|
391
|
+
["yao_result_reconstruction", timing.resultReconstructionMs]
|
|
392
|
+
];
|
|
393
|
+
for (const metric of (timing.routerServerTiming ?? "").split(",")) {
|
|
394
|
+
const parsed = /^\s*([A-Za-z0-9_]+);dur=([0-9.]+)\s*$/u.exec(metric);
|
|
395
|
+
if (parsed?.[1] && parsed[2]) entries.push([parsed[1], Number(parsed[2])]);
|
|
396
|
+
}
|
|
397
|
+
return entries;
|
|
398
|
+
}
|
|
359
399
|
function registrationExecutionServerTiming(timing) {
|
|
360
400
|
const gatewayTiming = [
|
|
361
401
|
serverTimingMetric("yao_credential_digest", timing.credentialDigestMs),
|
|
@@ -413,6 +453,6 @@ function terminalStateConflictFailure(result) {
|
|
|
413
453
|
};
|
|
414
454
|
}
|
|
415
455
|
//#endregion
|
|
416
|
-
export { handleRouterAbEd25519YaoRegistrationRequestScopedCloudflareV1 };
|
|
456
|
+
export { executeRouterAbEd25519YaoAdmittedRegistrationV1, handleRouterAbEd25519YaoRegistrationRequestScopedCloudflareV1, routerAbEd25519YaoRegistrationExecutionTimingEntriesV1 };
|
|
417
457
|
|
|
418
458
|
//# sourceMappingURL=routerAbEd25519YaoRegistrationRequestScopedCloudflare.js.map
|
|
@@ -5,6 +5,7 @@ import { base64UrlDecode } from "../../../shared-ts/src/utils/base64.js";
|
|
|
5
5
|
import { parseDigestB64u } from "../../../shared-ts/src/utils/canonicalPrimitives.js";
|
|
6
6
|
import { base58Encode } from "../../../shared-ts/src/utils/base58.js";
|
|
7
7
|
import "../../../shared-ts/src/utils/encoders.js";
|
|
8
|
+
import { parseRouterAbEd25519YaoRegistrationActivationExecuteRequestV1 } from "../../../shared-ts/src/utils/routerAbEd25519Yao.js";
|
|
8
9
|
import { ecdsaClientRootPublicKey33B64uFromString } from "../../../shared-ts/src/threshold/ecdsaDerivationRoleLocalBootstrap.js";
|
|
9
10
|
import { normalizeRuntimePolicyScope } from "../../../shared-ts/src/threshold/signingRootScope.js";
|
|
10
11
|
import { parseRouterAbEcdsaRegistrationActivationRequestV1, parseRouterAbEcdsaRegistrationRequestV1 } from "../../../shared-ts/src/utils/routerAbEcdsaDerivation.js";
|
|
@@ -1603,6 +1604,22 @@ async function handleRouterApiWalletRegistrationSetup(input) {
|
|
|
1603
1604
|
});
|
|
1604
1605
|
if (!resolved.ok) return routeJson(resolved.status, resolved.body);
|
|
1605
1606
|
const principal = context.principal;
|
|
1607
|
+
if (input.services.registrationSetupRateLimit) try {
|
|
1608
|
+
if (!(await input.services.registrationSetupRateLimit({
|
|
1609
|
+
apiKeyId: principal.apiKeyId,
|
|
1610
|
+
orgId: principal.orgId,
|
|
1611
|
+
projectId: context.environment.projectId,
|
|
1612
|
+
envId: context.environment.key,
|
|
1613
|
+
sourceIp: input.sourceIp || "unknown"
|
|
1614
|
+
})).allowed) return routeJson(429, {
|
|
1615
|
+
ok: false,
|
|
1616
|
+
code: "rate_limited",
|
|
1617
|
+
message: "Too many registration attempts. Wait one minute and try again.",
|
|
1618
|
+
retryAfterMs: 6e4
|
|
1619
|
+
});
|
|
1620
|
+
} catch {
|
|
1621
|
+
return routeError(503, "internal", "Registration setup rate limit is unavailable");
|
|
1622
|
+
}
|
|
1606
1623
|
const runtimePolicyScope = {
|
|
1607
1624
|
orgId: principal.orgId,
|
|
1608
1625
|
projectId: context.environment.projectId,
|
|
@@ -1729,15 +1746,38 @@ function parseWalletRegistrationRespondRequest(body) {
|
|
|
1729
1746
|
const parsedAuthority = parseWalletRegistrationAuthorityProof(body);
|
|
1730
1747
|
if (!parsedAuthority.ok) return parsedAuthority;
|
|
1731
1748
|
const authority = parsedAuthority.value;
|
|
1732
|
-
if (planKind
|
|
1733
|
-
ok:
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
signedSetup,
|
|
1737
|
-
authority,
|
|
1738
|
-
planKind
|
|
1739
|
-
}
|
|
1749
|
+
if (planKind !== "near_ed25519" && body.ed25519Execution !== void 0) return {
|
|
1750
|
+
ok: false,
|
|
1751
|
+
code: "invalid_body",
|
|
1752
|
+
message: "only an Ed25519-only respond carries its Yao execution"
|
|
1740
1753
|
};
|
|
1754
|
+
if (planKind === "near_ed25519") {
|
|
1755
|
+
if (body.ed25519Execution === void 0) return {
|
|
1756
|
+
ok: true,
|
|
1757
|
+
value: {
|
|
1758
|
+
registrationCeremonyId,
|
|
1759
|
+
signedSetup,
|
|
1760
|
+
authority,
|
|
1761
|
+
planKind
|
|
1762
|
+
}
|
|
1763
|
+
};
|
|
1764
|
+
const ed25519Execution = parseRouterAbEd25519YaoRegistrationActivationExecuteRequestV1(body.ed25519Execution);
|
|
1765
|
+
if (!ed25519Execution.ok) return {
|
|
1766
|
+
ok: false,
|
|
1767
|
+
code: "invalid_body",
|
|
1768
|
+
message: ed25519Execution.message
|
|
1769
|
+
};
|
|
1770
|
+
return {
|
|
1771
|
+
ok: true,
|
|
1772
|
+
value: {
|
|
1773
|
+
registrationCeremonyId,
|
|
1774
|
+
signedSetup,
|
|
1775
|
+
authority,
|
|
1776
|
+
planKind,
|
|
1777
|
+
ed25519Execution: ed25519Execution.value
|
|
1778
|
+
}
|
|
1779
|
+
};
|
|
1780
|
+
}
|
|
1741
1781
|
const ecdsa = isPlainObject(body.ecdsa) ? body.ecdsa : null;
|
|
1742
1782
|
if (!ecdsa || ecdsa.kind !== "router_ab_ecdsa_registration_v1") return {
|
|
1743
1783
|
ok: false,
|