@seams/wallet-server 0.20.0 → 0.21.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/artifact-manifest.json +22 -21
- package/cloudflare-router-ab/build/deriver-a/build-stamp.json +1 -1
- package/cloudflare-router-ab/build/deriver-a/index_bg.wasm +0 -0
- package/cloudflare-router-ab/build/deriver-b/build-stamp.json +1 -1
- package/cloudflare-router-ab/build/deriver-b/index_bg.wasm +0 -0
- package/cloudflare-router-ab/build/local-tools/linux-x64/router_ab_local_init +0 -0
- package/cloudflare-router-ab/build/router/build-stamp.json +1 -1
- package/cloudflare-router-ab/build/router/index_bg.wasm +0 -0
- package/cloudflare-router-ab/build/signing-worker/build-stamp.json +1 -1
- package/cloudflare-router-ab/build/signing-worker/index_bg.wasm +0 -0
- package/cloudflare-router-ab/build/tenant-root-control-plane/build-stamp.json +1 -1
- package/cloudflare-router-ab/build/tenant-root-control-plane/index_bg.wasm +0 -0
- package/cloudflare-router-ab/scripts/prepare-local-runtime-config.mjs +16 -2
- package/dist/esm/core/deviceLinking/linkedDeviceManagement.js +11 -30
- package/dist/esm/core/emailOtpD1Statements.js +14 -2
- package/dist/esm/core/nearRelayerAccountProvisioning.js +2 -7
- package/dist/esm/hosted-wallet-gateway.js +10 -7
- package/dist/esm/router/auth/webAuthnCredentialCodecs.js +16 -1
- package/dist/esm/router/cloudflare/d1/auth/d1AuthorizationAssembly.js +1 -0
- package/dist/esm/router/cloudflare/d1/auth/d1RouterApiAuthService.js +0 -1
- package/dist/esm/router/cloudflare/d1/deviceLinking/d1LinkedDeviceEmailOtpTargetFactor.js +4 -1
- package/dist/esm/router/cloudflare/d1/deviceLinking/d1LinkedDeviceManagementService.js +6 -11
- package/dist/esm/router/cloudflare/d1/deviceLinking/d1LinkedDeviceRevocation.js +7 -0
- package/dist/esm/router/cloudflare/d1/emailOtp/d1EmailOtpGrantStore.js +5 -2
- package/dist/esm/router/cloudflare/d1/emailOtp/d1EmailOtpRateLimitStore.js +18 -0
- package/dist/esm/router/cloudflare/d1/emailOtp/d1EmailOtpRecoveryService.js +28 -8
- package/dist/esm/router/cloudflare/d1/emailOtp/d1EmailOtpServerSealRuntime.js +12 -8
- package/dist/esm/router/cloudflare/d1/oidc/d1OidcBoundary.js +1 -0
- package/dist/esm/router/cloudflare/d1/passkeyCustody/d1PasskeyCustodyRouteService.js +19 -5
- package/dist/esm/router/cloudflare/d1/passkeyCustody/d1WalletCustodyCommitStore.js +26 -10
- package/dist/esm/router/cloudflare/d1/passkeyCustody/d1WalletRecoveryGoogleEmailOtpService.js +4 -1
- package/dist/esm/router/cloudflare/d1/wallet/d1WalletAuthMethodService.js +6 -0
- package/dist/esm/router/cloudflare/d1/wallet/d1WalletRelocationApprovals.js +12 -0
- package/dist/esm/router/cloudflare.js +252 -150
- package/dist/esm/router/domains/ecdsa/routerAbEcdsaStrictRegistration.js +1 -1
- package/dist/esm/router/domains/passkeyCustody/passkeyCustodyEnvelopeRetrieval.js +4 -22
- package/dist/esm/router/domains/passkeyCustody/registrationCustodyOutcome.js +8 -2
- package/dist/esm/router/framework/routeDefinitions.js +3 -2
- package/dist/esm/router/transport/fetch/routes/auth.js +5 -0
- package/dist/esm/router/transport/fetch/routes/passkeyCustody.js +78 -88
- package/dist/esm/router/transport/fetch/routes/sessions.js +4 -1
- package/dist/esm/router/transport/fetch/routes/thresholdEd25519.js +4 -1
- package/dist/esm/router/transport/fetch/routes/walletCustodyRequestBoundary.js +80 -0
- package/dist/esm/shared-ts/src/passkey-custody/ceremonyCommitPayload.js +5 -1
- package/dist/esm/shared-ts/src/utils/evmRpcResults.js +5 -3
- package/dist/esm/shared-ts/src/utils/routerAbEcdsaDerivation.js +2 -1
- package/dist/esm/threshold/session/signingSessionSeal/crypto/cipher.js +160 -40
- package/dist/types/shared-ts/src/authorization/walletCustodyOperation.d.ts +1 -1
- package/dist/types/shared-ts/src/device-linking/contracts.d.ts +1 -7
- package/dist/types/shared-ts/src/passkey-custody/ceremonyCommitPayload.d.ts +5 -0
- package/dist/types/shared-ts/src/utils/evmRpcResults.d.ts +3 -3
- package/dist/types/shared-ts/src/utils/routerAbEcdsaDerivation.d.ts +1 -1
- package/dist/types/wallet-server/src/core/authService/emailOtpSeal.d.ts +5 -1
- package/dist/types/wallet-server/src/core/deviceLinking/linkedDeviceManagement.d.ts +1 -9
- package/dist/types/wallet-server/src/core/emailOtpD1Statements.d.ts +2 -1
- package/dist/types/wallet-server/src/hosted-wallet-gateway.d.ts +1 -0
- package/dist/types/wallet-server/src/router/auth/webAuthnCredentialCodecs.d.ts +1 -0
- package/dist/types/wallet-server/src/router/cloudflare/d1/deviceLinking/d1LinkedDeviceManagementService.d.ts +0 -3
- package/dist/types/wallet-server/src/router/cloudflare/d1/deviceLinking/d1LinkedDeviceRevocation.d.ts +1 -1
- package/dist/types/wallet-server/src/router/cloudflare/d1/emailOtp/d1EmailOtpGrantStore.d.ts +3 -1
- package/dist/types/wallet-server/src/router/cloudflare/d1/emailOtp/d1EmailOtpRateLimitStore.d.ts +15 -2
- package/dist/types/wallet-server/src/router/cloudflare/d1/emailOtp/d1EmailOtpServerSealRuntime.d.ts +3 -3
- package/dist/types/wallet-server/src/router/cloudflare/d1/passkeyCustody/d1PasskeyCustodyRouteService.d.ts +3 -0
- package/dist/types/wallet-server/src/router/cloudflare/d1/passkeyCustody/d1WalletCustodyCommitStore.d.ts +5 -6
- package/dist/types/wallet-server/src/router/domains/passkeyCustody/walletCustodyRegistrationCommit.d.ts +4 -6
- package/dist/types/wallet-server/src/router/framework/authServicePort.d.ts +7 -1
- package/dist/types/wallet-server/src/router/transport/fetch/routes/passkeyCustody.d.ts +1 -10
- package/dist/types/wallet-server/src/router/transport/fetch/routes/walletCustodyRequestBoundary.d.ts +28 -0
- package/dist/types/wallet-server/src/threshold/session/signingSessionSeal/crypto/cipher.d.ts +3 -0
- package/package.json +1 -1
- package/src/README.md +11 -4
|
@@ -73,6 +73,17 @@ function normalizeConfig(config) {
|
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
75
|
function encodeSigningSessionSealServerLockContext(input) {
|
|
76
|
+
return encodeSigningSessionHkdfTuple([
|
|
77
|
+
"seams/router-ab/signing-session-seal",
|
|
78
|
+
input.protocol.algorithm,
|
|
79
|
+
input.protocol.groupId,
|
|
80
|
+
input.keyVersion,
|
|
81
|
+
"server-lock/session/v1",
|
|
82
|
+
input.walletId,
|
|
83
|
+
input.thresholdSessionId
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
function encodeEmailOtpEnrollmentServerLockContext(input) {
|
|
76
87
|
return encodeSigningSessionHkdfTuple([
|
|
77
88
|
"seams/router-ab/signing-session-seal",
|
|
78
89
|
input.protocol.algorithm,
|
|
@@ -89,14 +100,14 @@ function defaultRuntime() {
|
|
|
89
100
|
destroyLockKeyHandle: destroySigningSessionSealLockKeyHandle
|
|
90
101
|
};
|
|
91
102
|
}
|
|
92
|
-
async function
|
|
103
|
+
async function deriveEmailOtpEnrollmentKeyHandles(input) {
|
|
93
104
|
const handles = /* @__PURE__ */ new Map();
|
|
94
105
|
try {
|
|
95
106
|
for (const keyVersion of input.config.acceptedWarmKeyVersions) {
|
|
96
107
|
const handle = await input.runtime.deriveLockKeyHandle({
|
|
97
108
|
groupId: input.config.protocol.groupId,
|
|
98
109
|
rootSecret32: input.config.rootSecret32,
|
|
99
|
-
context:
|
|
110
|
+
context: encodeEmailOtpEnrollmentServerLockContext({
|
|
100
111
|
protocol: input.config.protocol,
|
|
101
112
|
keyVersion
|
|
102
113
|
})
|
|
@@ -111,14 +122,14 @@ async function deriveAcceptedKeyHandles(input) {
|
|
|
111
122
|
input.config.rootSecret32.fill(0);
|
|
112
123
|
}
|
|
113
124
|
}
|
|
114
|
-
var
|
|
125
|
+
var EmailOtpEnrollmentKeyHandles = class {
|
|
115
126
|
initialization = null;
|
|
116
127
|
constructor(config, runtime) {
|
|
117
128
|
this.config = config;
|
|
118
129
|
this.runtime = runtime;
|
|
119
130
|
}
|
|
120
131
|
get() {
|
|
121
|
-
if (!this.initialization) this.initialization =
|
|
132
|
+
if (!this.initialization) this.initialization = deriveEmailOtpEnrollmentKeyHandles({
|
|
122
133
|
config: this.config,
|
|
123
134
|
runtime: this.runtime
|
|
124
135
|
});
|
|
@@ -132,50 +143,159 @@ function mapCipherError(error, defaultMessage) {
|
|
|
132
143
|
if (lowered.includes("ciphertext") || lowered.includes("base64url") || lowered.includes("group")) return failure("invalid_ciphertext", message);
|
|
133
144
|
return failure("internal", message);
|
|
134
145
|
}
|
|
135
|
-
function
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
146
|
+
function copyToArrayBuffer(bytes) {
|
|
147
|
+
const copy = new ArrayBuffer(bytes.length);
|
|
148
|
+
new Uint8Array(copy).set(bytes);
|
|
149
|
+
return copy;
|
|
150
|
+
}
|
|
151
|
+
async function importSigningSessionSealRootKey(rootSecret32) {
|
|
152
|
+
const rootCopy = copyToArrayBuffer(rootSecret32);
|
|
153
|
+
try {
|
|
154
|
+
return await crypto.subtle.importKey("raw", rootCopy, {
|
|
155
|
+
name: "HMAC",
|
|
156
|
+
hash: "SHA-256"
|
|
157
|
+
}, false, ["sign"]);
|
|
158
|
+
} finally {
|
|
159
|
+
rootSecret32.fill(0);
|
|
160
|
+
new Uint8Array(rootCopy).fill(0);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
async function deriveScopedSigningSessionHandle(input) {
|
|
164
|
+
const context = encodeSigningSessionSealServerLockContext({
|
|
165
|
+
protocol: input.state.config.protocol,
|
|
166
|
+
keyVersion: input.keyVersion,
|
|
167
|
+
walletId: input.walletId,
|
|
168
|
+
thresholdSessionId: input.thresholdSessionId
|
|
169
|
+
});
|
|
170
|
+
let sessionRoot32 = null;
|
|
171
|
+
try {
|
|
172
|
+
const rootKey = await input.state.rootKey;
|
|
173
|
+
sessionRoot32 = new Uint8Array(await crypto.subtle.sign("HMAC", rootKey, copyToArrayBuffer(context)));
|
|
174
|
+
return await input.state.runtime.deriveLockKeyHandle({
|
|
175
|
+
groupId: input.state.config.protocol.groupId,
|
|
176
|
+
rootSecret32: sessionRoot32,
|
|
177
|
+
context
|
|
178
|
+
});
|
|
179
|
+
} finally {
|
|
180
|
+
sessionRoot32?.fill(0);
|
|
181
|
+
context.fill(0);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async function acquireLockHandle(state, input, keyVersion) {
|
|
185
|
+
switch (state.kind) {
|
|
186
|
+
case "email_otp_enrollment": {
|
|
187
|
+
const handle = (await state.handles.get()).get(keyVersion);
|
|
188
|
+
if (handle === void 0) throw new Error("Email OTP enrollment lock key handle is unavailable");
|
|
189
|
+
return {
|
|
190
|
+
kind: "borrowed",
|
|
191
|
+
handle
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
case "signing_session": return {
|
|
195
|
+
kind: "owned",
|
|
196
|
+
handle: await deriveScopedSigningSessionHandle({
|
|
197
|
+
state,
|
|
198
|
+
keyVersion,
|
|
199
|
+
walletId: input.auth.userId,
|
|
200
|
+
thresholdSessionId: input.thresholdSessionId
|
|
201
|
+
})
|
|
202
|
+
};
|
|
203
|
+
default: return assertNeverShamir3PassCipherState(state);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function assertNeverShamir3PassCipherState(value) {
|
|
207
|
+
throw new Error(`Unsupported Shamir 3-pass cipher state: ${String(value)}`);
|
|
208
|
+
}
|
|
209
|
+
function assertNeverSigningSessionSealOperation(value) {
|
|
210
|
+
throw new Error(`Unsupported signing-session seal operation: ${String(value)}`);
|
|
211
|
+
}
|
|
212
|
+
async function runShamir3PassCipher(state, operation, input) {
|
|
213
|
+
if (state.kind === "signing_session") {
|
|
214
|
+
if (!normalizeOptionalTrimmedString(input.auth.userId) || !normalizeOptionalTrimmedString(input.thresholdSessionId)) return failure("invalid_scope", "Authenticated wallet and threshold session are required");
|
|
215
|
+
}
|
|
216
|
+
let keyVersion;
|
|
217
|
+
switch (operation) {
|
|
218
|
+
case "apply-server-seal": {
|
|
142
219
|
const requestedKeyVersion = normalizeOptionalTrimmedString(input.keyVersion);
|
|
143
|
-
if (requestedKeyVersion && requestedKeyVersion !== config.currentKeyVersion) return failure("invalid_key_version", `Requested keyVersion "${requestedKeyVersion}" does not match active keyVersion "${config.currentKeyVersion}"`);
|
|
220
|
+
if (requestedKeyVersion && requestedKeyVersion !== state.config.currentKeyVersion) return failure("invalid_key_version", `Requested keyVersion "${requestedKeyVersion}" does not match active keyVersion "${state.config.currentKeyVersion}"`);
|
|
221
|
+
keyVersion = state.config.currentKeyVersion;
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
case "remove-server-seal":
|
|
144
225
|
try {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return
|
|
148
|
-
ok: true,
|
|
149
|
-
ciphertext: await runtime.addLock({
|
|
150
|
-
handle,
|
|
151
|
-
ciphertextB64u: input.ciphertext
|
|
152
|
-
}),
|
|
153
|
-
keyVersion: config.currentKeyVersion
|
|
154
|
-
};
|
|
155
|
-
} catch (error) {
|
|
156
|
-
return mapCipherError(error, "Failed to apply server seal");
|
|
226
|
+
keyVersion = normalizeKeyVersion(input.keyVersion, "keyVersion");
|
|
227
|
+
} catch {
|
|
228
|
+
return failure("invalid_key_version", "keyVersion is invalid");
|
|
157
229
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
230
|
+
if (!state.config.acceptedWarmKeyVersions.includes(keyVersion)) return failure("invalid_key_version", `Unknown keyVersion "${keyVersion}"`);
|
|
231
|
+
break;
|
|
232
|
+
default: return assertNeverSigningSessionSealOperation(operation);
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
const lease = await acquireLockHandle(state, input, keyVersion);
|
|
236
|
+
try {
|
|
237
|
+
let ciphertext;
|
|
238
|
+
switch (operation) {
|
|
239
|
+
case "apply-server-seal":
|
|
240
|
+
ciphertext = await state.runtime.addLock({
|
|
241
|
+
handle: lease.handle,
|
|
168
242
|
ciphertextB64u: input.ciphertext
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
243
|
+
});
|
|
244
|
+
break;
|
|
245
|
+
case "remove-server-seal":
|
|
246
|
+
ciphertext = await state.runtime.removeLock({
|
|
247
|
+
handle: lease.handle,
|
|
248
|
+
ciphertextB64u: input.ciphertext
|
|
249
|
+
});
|
|
250
|
+
break;
|
|
251
|
+
default: return assertNeverSigningSessionSealOperation(operation);
|
|
174
252
|
}
|
|
253
|
+
return {
|
|
254
|
+
ok: true,
|
|
255
|
+
ciphertext,
|
|
256
|
+
keyVersion
|
|
257
|
+
};
|
|
258
|
+
} finally {
|
|
259
|
+
if (lease.kind === "owned") state.runtime.destroyLockKeyHandle(lease.handle);
|
|
175
260
|
}
|
|
261
|
+
} catch (error) {
|
|
262
|
+
return mapCipherError(error, "Failed to process server seal");
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function applyShamir3PassCipher(state, input) {
|
|
266
|
+
return runShamir3PassCipher(state, "apply-server-seal", input);
|
|
267
|
+
}
|
|
268
|
+
function removeShamir3PassCipher(state, input) {
|
|
269
|
+
return runShamir3PassCipher(state, "remove-server-seal", input);
|
|
270
|
+
}
|
|
271
|
+
function createShamir3PassCipherAdapter(state) {
|
|
272
|
+
return createSigningSessionSealCipherAdapter({
|
|
273
|
+
applyServerSeal: applyShamir3PassCipher.bind(null, state),
|
|
274
|
+
removeServerSeal: removeShamir3PassCipher.bind(null, state)
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
function createEmailOtpEnrollmentShamir3PassCipherAdapter(options) {
|
|
278
|
+
const config = normalizeConfig(options.config);
|
|
279
|
+
options.config.rootSecret32.fill(0);
|
|
280
|
+
const runtime = options.runtime ?? defaultRuntime();
|
|
281
|
+
return createShamir3PassCipherAdapter({
|
|
282
|
+
kind: "email_otp_enrollment",
|
|
283
|
+
config,
|
|
284
|
+
runtime,
|
|
285
|
+
handles: new EmailOtpEnrollmentKeyHandles(config, runtime)
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
function createSigningSessionSealShamir3PassCipherAdapter(options) {
|
|
289
|
+
const config = normalizeConfig(options.config);
|
|
290
|
+
options.config.rootSecret32.fill(0);
|
|
291
|
+
return createShamir3PassCipherAdapter({
|
|
292
|
+
kind: "signing_session",
|
|
293
|
+
config,
|
|
294
|
+
runtime: options.runtime ?? defaultRuntime(),
|
|
295
|
+
rootKey: importSigningSessionSealRootKey(config.rootSecret32)
|
|
176
296
|
});
|
|
177
297
|
}
|
|
178
298
|
//#endregion
|
|
179
|
-
export { createPassthroughSigningSessionSealCipherAdapter, createSigningSessionSealCipherAdapter, createSigningSessionSealShamir3PassCipherAdapter, encodeSigningSessionSealServerLockContext };
|
|
299
|
+
export { createEmailOtpEnrollmentShamir3PassCipherAdapter, createPassthroughSigningSessionSealCipherAdapter, createSigningSessionSealCipherAdapter, createSigningSessionSealShamir3PassCipherAdapter, encodeSigningSessionSealServerLockContext };
|
|
180
300
|
|
|
181
301
|
//# sourceMappingURL=cipher.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type DigestB64u } from '../utils/canonicalPrimitives';
|
|
2
|
-
export type WalletCustodyAdminOperation = 'credentials_list' | 'credential_label' | 'recovery_rotate' | 'recovery_read';
|
|
2
|
+
export type WalletCustodyAdminOperation = 'credentials_list' | 'credential_label' | 'recovery_rotate' | 'recovery_read' | 'recovery_status' | 'recovery_backup_acknowledge';
|
|
3
3
|
/** Public challenge digest for a single wallet-administration factor proof. */
|
|
4
4
|
export declare function computeWalletCustodyAdminChallengeDigest(input: {
|
|
5
5
|
readonly walletId: string;
|
|
@@ -429,13 +429,7 @@ export type LinkedOwnerCredentialMetadataV1 = {
|
|
|
429
429
|
} | {
|
|
430
430
|
readonly kind: 'email_otp';
|
|
431
431
|
readonly walletAuthMethodId: WalletAuthMethodId;
|
|
432
|
-
|
|
433
|
-
* The verified address behind this factor. The management projection is
|
|
434
|
-
* served only to an authenticated owner session, and the owner already
|
|
435
|
-
* knows the address they enrolled — this exists so the settings surface
|
|
436
|
-
* can name the factor. Local persistence keeps only the email hash.
|
|
437
|
-
*/
|
|
438
|
-
readonly email: VerifiedEmailAddress;
|
|
432
|
+
readonly email?: never;
|
|
439
433
|
readonly device?: never;
|
|
440
434
|
readonly credentialIdB64u?: never;
|
|
441
435
|
};
|
|
@@ -135,8 +135,10 @@ export type WalletCustodyRegistrationOutcome =
|
|
|
135
135
|
/** No custody payload rode this leg. Registration is unaffected. */
|
|
136
136
|
{
|
|
137
137
|
readonly status: 'not_requested';
|
|
138
|
+
readonly issuedAtMs?: never;
|
|
138
139
|
} | {
|
|
139
140
|
readonly status: 'committed';
|
|
141
|
+
readonly issuedAtMs: number;
|
|
140
142
|
}
|
|
141
143
|
/**
|
|
142
144
|
* A joining run: this key set's manifest digest, with no custody records
|
|
@@ -145,6 +147,7 @@ export type WalletCustodyRegistrationOutcome =
|
|
|
145
147
|
| {
|
|
146
148
|
readonly status: 'joined';
|
|
147
149
|
readonly keyManifestDigestB64u: string;
|
|
150
|
+
readonly issuedAtMs?: never;
|
|
148
151
|
}
|
|
149
152
|
/**
|
|
150
153
|
* Another ceremony established this wallet's custody first. The client must
|
|
@@ -152,11 +155,13 @@ export type WalletCustodyRegistrationOutcome =
|
|
|
152
155
|
*/
|
|
153
156
|
| {
|
|
154
157
|
readonly status: 'custody_already_established';
|
|
158
|
+
readonly issuedAtMs?: never;
|
|
155
159
|
}
|
|
156
160
|
/** The payload was refused. Nothing was written. */
|
|
157
161
|
| {
|
|
158
162
|
readonly status: 'rejected';
|
|
159
163
|
readonly reason: string;
|
|
164
|
+
readonly issuedAtMs?: never;
|
|
160
165
|
};
|
|
161
166
|
/**
|
|
162
167
|
* Reads a commit payload off the wire without judging it.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export type EvmTransactionReceipt = {
|
|
2
|
-
transactionHash
|
|
2
|
+
transactionHash: string;
|
|
3
3
|
from?: string | null;
|
|
4
|
-
blockNumber
|
|
5
|
-
status
|
|
4
|
+
blockNumber: string;
|
|
5
|
+
status: string;
|
|
6
6
|
gasUsed?: string | null;
|
|
7
7
|
effectiveGasPrice?: string | null;
|
|
8
8
|
gasPrice?: string | null;
|
|
@@ -441,7 +441,7 @@ type RouterAbEcdsaOperationStepUpWebAuthnCredentialV1Wire = {
|
|
|
441
441
|
readonly signature: string;
|
|
442
442
|
readonly userHandle: string | null;
|
|
443
443
|
};
|
|
444
|
-
readonly clientExtensionResults:
|
|
444
|
+
readonly clientExtensionResults: null;
|
|
445
445
|
};
|
|
446
446
|
export type RouterAbEcdsaOperationStepUpPreparationV1Wire = {
|
|
447
447
|
readonly wallet_id: string;
|
|
@@ -8,9 +8,13 @@ export type EmailOtpShamirCipherResult = {
|
|
|
8
8
|
readonly code: 'not_configured';
|
|
9
9
|
readonly message: string;
|
|
10
10
|
};
|
|
11
|
-
export type
|
|
11
|
+
export type EmailOtpServerSealApplyRequest = {
|
|
12
12
|
readonly wrappedCiphertext?: unknown;
|
|
13
13
|
};
|
|
14
|
+
export type EmailOtpServerSealRemoveRequest = {
|
|
15
|
+
readonly wrappedCiphertext?: unknown;
|
|
16
|
+
readonly enrollmentSealKeyVersion: string;
|
|
17
|
+
};
|
|
14
18
|
export type EmailOtpServerSealResult = {
|
|
15
19
|
ok: true;
|
|
16
20
|
ciphertext: string;
|
|
@@ -108,15 +108,6 @@ type LinkedDeviceManagementCredentialMetadataPortV1 = {
|
|
|
108
108
|
readonly walletId: WalletId;
|
|
109
109
|
readonly credentialIdB64u: string;
|
|
110
110
|
}): Promise<WebAuthnAuthenticatorDeviceInfo | null>;
|
|
111
|
-
/**
|
|
112
|
-
* The wallet's verified Email OTP address, from its canonical enrollment.
|
|
113
|
-
* Served only inside the owner-scoped management projection, which is why the
|
|
114
|
-
* plaintext address (not the hash) is acceptable here: the reader is the
|
|
115
|
-
* wallet owner who enrolled it.
|
|
116
|
-
*/
|
|
117
|
-
readEmailOtpAddressV1(input: {
|
|
118
|
-
readonly walletId: WalletId;
|
|
119
|
-
}): Promise<string | null>;
|
|
120
111
|
};
|
|
121
112
|
type LinkedDeviceManagementServiceOptionsV1 = {
|
|
122
113
|
readonly tenantId: TenantId;
|
|
@@ -151,5 +142,6 @@ export declare class LinkedDeviceManagementServiceV1 {
|
|
|
151
142
|
private buildLinkedDeviceSummaryV1;
|
|
152
143
|
private buildOwnerDeviceSummaryV1;
|
|
153
144
|
}
|
|
145
|
+
export declare const MAX_FRESH_REVOCATION_PROOF_AGE_MS_V1: number;
|
|
154
146
|
export {};
|
|
155
147
|
//# sourceMappingURL=linkedDeviceManagement.d.ts.map
|
|
@@ -11,7 +11,8 @@ export declare const emailOtpChallengeRows: {
|
|
|
11
11
|
/** Statements on `email_otp_grants`. */
|
|
12
12
|
export declare const emailOtpGrantRows: {
|
|
13
13
|
insert: (prepare: ScopedD1Prepare, record: EmailOtpGrantRecord) => D1PreparedStatementLike;
|
|
14
|
-
|
|
14
|
+
read: (prepare: ScopedD1Prepare, grantToken: string) => D1PreparedStatementLike;
|
|
15
|
+
consumeMatching: (prepare: ScopedD1Prepare, record: EmailOtpGrantRecord, nowMs: number) => D1PreparedStatementLike;
|
|
15
16
|
};
|
|
16
17
|
/** Statements on `email_otp_wallet_enrollments`. */
|
|
17
18
|
export declare const emailOtpWalletEnrollmentRows: {
|
|
@@ -52,6 +52,7 @@ export interface CloudflareD1GatewayBaseEnv extends Readonly<Record<string, unkn
|
|
|
52
52
|
readonly SIGNING_SESSION_SEAL_ROOT_SECRET_B64U?: string;
|
|
53
53
|
readonly SIGNING_SESSION_SEAL_CURRENT_KEY_VERSION?: string;
|
|
54
54
|
readonly SIGNING_SESSION_SEAL_ACCEPTED_WARM_KEY_VERSIONS?: string;
|
|
55
|
+
readonly EMAIL_OTP_SERVER_SEAL_ACCEPTED_WARM_KEY_VERSIONS?: string;
|
|
55
56
|
readonly EMAIL_OTP_DELIVERY_MODE?: string;
|
|
56
57
|
readonly EMAIL_OTP_RUNTIME_PROFILE?: string;
|
|
57
58
|
readonly EMAIL_OTP_PROVIDER?: string;
|
|
@@ -12,6 +12,7 @@ type WebAuthnClientDataJson = {
|
|
|
12
12
|
readonly origin: string;
|
|
13
13
|
readonly type: string;
|
|
14
14
|
};
|
|
15
|
+
export declare function unredactedWebAuthnExtensionField(input: unknown): string | null;
|
|
15
16
|
export declare function decodeWebAuthnBase64UrlOrBase64(input: string, fieldName: string): Uint8Array<ArrayBuffer>;
|
|
16
17
|
export declare function parseWebAuthnClientDataJsonBase64url(clientDataJSONB64u: string): WebAuthnClientDataJson;
|
|
17
18
|
export declare function webAuthnOriginHostnameOrEmpty(origin: string): string;
|
|
@@ -6,7 +6,6 @@ import type { OrdinaryInactiveSignerMaterialDeactivationPortV1 } from '../../../
|
|
|
6
6
|
import { D1WalletAuthorityStore, type D1WalletAuthorityStoreScope } from '../wallet/d1WalletAuthorityStore';
|
|
7
7
|
import { CloudflareD1WebAuthnStore } from '../webauthn/d1WebAuthnStore';
|
|
8
8
|
import type { CloudflareD1AuthorizationStore } from '../authorization/d1AuthorizationStore';
|
|
9
|
-
import type { CloudflareD1EmailOtpEnrollmentStore } from '../emailOtp/d1EmailOtpEnrollmentStore';
|
|
10
9
|
export declare function createD1LinkedDeviceManagementServiceV1(input: {
|
|
11
10
|
readonly scope: D1WalletAuthorityStoreScope;
|
|
12
11
|
readonly tenantId: TenantId;
|
|
@@ -15,8 +14,6 @@ export declare function createD1LinkedDeviceManagementServiceV1(input: {
|
|
|
15
14
|
readonly authorizationService: AuthorizationService;
|
|
16
15
|
readonly walletSessionAuthorizations: Pick<CloudflareD1AuthorizationStore, 'readActiveWalletSessionAuthorizationV2ByIdentity' | 'prepareRetireWalletSessionAuthorizationsV2ForAuthority'>;
|
|
17
16
|
readonly webAuthnStore: CloudflareD1WebAuthnStore;
|
|
18
|
-
/** Absent when Email OTP is not deployed; an email_otp method then fails closed. */
|
|
19
|
-
readonly emailOtpEnrollments?: Pick<CloudflareD1EmailOtpEnrollmentStore, 'readEnrollment'>;
|
|
20
17
|
readonly materialDeactivation?: OrdinaryInactiveSignerMaterialDeactivationPortV1;
|
|
21
18
|
}): LinkedDeviceManagementServiceV1;
|
|
22
19
|
//# sourceMappingURL=d1LinkedDeviceManagementService.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { LinkedDeviceRevokeRequestV1, LinkedDeviceRevokeResultV1 } from '../../../../../../shared-ts/src/device-linking/contracts';
|
|
2
2
|
import type { DigestB64u } from '../../../../../../shared-ts/src/utils/canonicalPrimitives';
|
|
3
3
|
import type { WalletAuthMethodId, WalletId } from '../../../../../../shared-ts/src/utils/domainIds';
|
|
4
|
-
import type
|
|
4
|
+
import { type LinkedDeviceManagementServiceV1, type LinkedDeviceManagementSourceV1 } from '../../../../core/deviceLinking/linkedDeviceManagement';
|
|
5
5
|
import type { D1WalletAuthMethodStore } from '../../../../core/d1WalletAuthMethodStore';
|
|
6
6
|
import type { DeviceLinkingAuthDeniedV1 } from '../../../transport/fetch/routes/deviceLinking';
|
|
7
7
|
import type { D1LinkedDeviceFreshRevokeProofV1, verifyD1LinkedDeviceFreshRevokeProofV1 } from '../wallet/d1WalletAuthMethodBoundary';
|
package/dist/types/wallet-server/src/router/cloudflare/d1/emailOtp/d1EmailOtpGrantStore.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { EmailOtpGrantRecord } from '../../../../core/EmailOtpStores';
|
|
2
2
|
import { type ScopedD1Prepare } from '../../../../core/emailOtpD1Statements';
|
|
3
|
+
import type { D1PreparedStatementLike } from '../../../../storage/tenantRoute';
|
|
3
4
|
export declare class CloudflareD1EmailOtpGrantStore {
|
|
4
5
|
private readonly prepare;
|
|
5
6
|
constructor(input: {
|
|
6
7
|
readonly prepare: ScopedD1Prepare;
|
|
7
8
|
});
|
|
8
9
|
put(record: EmailOtpGrantRecord): Promise<void>;
|
|
9
|
-
|
|
10
|
+
read(grantToken: string): Promise<EmailOtpGrantRecord | null>;
|
|
11
|
+
prepareConsumeMatching(record: EmailOtpGrantRecord, nowMs: number): D1PreparedStatementLike;
|
|
10
12
|
}
|
|
11
13
|
//# sourceMappingURL=d1EmailOtpGrantStore.d.ts.map
|
package/dist/types/wallet-server/src/router/cloudflare/d1/emailOtp/d1EmailOtpRateLimitStore.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { D1DatabaseLike } from '../../../../storage/tenantRoute';
|
|
1
|
+
import type { D1DatabaseLike, D1PreparedStatementLike } from '../../../../storage/tenantRoute';
|
|
2
2
|
import type { ScopedD1Prepare } from '../../../../core/emailOtpD1Statements';
|
|
3
3
|
import type { RateLimitResult } from '../../../../core/authService/rateLimits';
|
|
4
4
|
import type { EmailOtpRateLimitPolicy } from '../auth/d1RouterApiAuthConfig';
|
|
5
|
-
import { type EmailOtpRateLimitScope, type EmailOtpRateLimitConsumeInput } from './d1EmailOtpRecords';
|
|
5
|
+
import { emailOtpRateLimitExceeded, type EmailOtpRateLimitScope, type EmailOtpRateLimitConsumeInput } from './d1EmailOtpRecords';
|
|
6
6
|
type EmailOtpRateLimitPolicies = {
|
|
7
7
|
readonly [K in EmailOtpRateLimitScope]: EmailOtpRateLimitPolicy;
|
|
8
8
|
};
|
|
@@ -10,11 +10,24 @@ type EmailOtpRateLimitConsumeResult = Readonly<RateLimitResult>;
|
|
|
10
10
|
export declare class CloudflareD1EmailOtpRateLimitStore {
|
|
11
11
|
private readonly input;
|
|
12
12
|
constructor(input: {
|
|
13
|
+
readonly database: D1DatabaseLike;
|
|
13
14
|
readonly prepare: ScopedD1Prepare;
|
|
14
15
|
readonly batch: D1DatabaseLike['batch'];
|
|
15
16
|
readonly rateLimits: EmailOtpRateLimitPolicies;
|
|
16
17
|
});
|
|
17
18
|
consume(input: EmailOtpRateLimitConsumeInput): Promise<EmailOtpRateLimitConsumeResult>;
|
|
19
|
+
consumeVerifiedGrant(input: {
|
|
20
|
+
readonly grantDelete: D1PreparedStatementLike;
|
|
21
|
+
readonly rateLimit: EmailOtpRateLimitConsumeInput & {
|
|
22
|
+
readonly kind: 'wallet';
|
|
23
|
+
readonly scope: 'grant';
|
|
24
|
+
};
|
|
25
|
+
readonly nowMs: number;
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
readExceededGrantRateLimit(input: EmailOtpRateLimitConsumeInput & {
|
|
28
|
+
readonly kind: 'wallet';
|
|
29
|
+
readonly scope: 'grant';
|
|
30
|
+
}, nowMs: number): Promise<ReturnType<typeof emailOtpRateLimitExceeded> | null>;
|
|
18
31
|
private prepareConsume;
|
|
19
32
|
private readCounter;
|
|
20
33
|
}
|
package/dist/types/wallet-server/src/router/cloudflare/d1/emailOtp/d1EmailOtpServerSealRuntime.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { EmailOtpServerSealRuntimeConfig } from '../auth/d1RouterApiAuthConfig';
|
|
2
|
-
import type {
|
|
2
|
+
import type { EmailOtpServerSealApplyRequest, EmailOtpServerSealRemoveRequest, EmailOtpServerSealResult as CoreEmailOtpServerSealResult } from '../../../../core/authService/emailOtpSeal';
|
|
3
3
|
type EmailOtpServerSealResult = Readonly<CoreEmailOtpServerSealResult>;
|
|
4
4
|
export declare class CloudflareD1EmailOtpServerSealRuntime {
|
|
5
5
|
private readonly config;
|
|
6
6
|
private readonly cipherResult;
|
|
7
7
|
constructor(config: EmailOtpServerSealRuntimeConfig);
|
|
8
|
-
removeEmailOtpServerSeal(input:
|
|
9
|
-
applyEmailOtpServerSeal(input:
|
|
8
|
+
removeEmailOtpServerSeal(input: EmailOtpServerSealRemoveRequest): Promise<EmailOtpServerSealResult>;
|
|
9
|
+
applyEmailOtpServerSeal(input: EmailOtpServerSealApplyRequest): Promise<EmailOtpServerSealResult>;
|
|
10
10
|
private runServerSealOperation;
|
|
11
11
|
private createCipher;
|
|
12
12
|
}
|
|
@@ -236,11 +236,14 @@ export interface RouterApiPasskeyCustodyService {
|
|
|
236
236
|
*/
|
|
237
237
|
acknowledgeRecoveryBackup(request: {
|
|
238
238
|
readonly walletId: string;
|
|
239
|
+
readonly expectedIssuedAtMs: number;
|
|
239
240
|
}): Promise<{
|
|
240
241
|
kind: 'acknowledged';
|
|
241
242
|
issuedAtMs: number;
|
|
242
243
|
} | {
|
|
243
244
|
kind: 'no_recovery_set';
|
|
245
|
+
} | {
|
|
246
|
+
kind: 'conflict';
|
|
244
247
|
}>;
|
|
245
248
|
/**
|
|
246
249
|
* Replaces the wallet's recovery codes with a freshly wrapped set.
|
|
@@ -43,9 +43,11 @@ export type WalletRecoveryCodeLocatorRecord = {
|
|
|
43
43
|
*/
|
|
44
44
|
export type WalletCustodyRegistrationReservation = {
|
|
45
45
|
readonly kind: 'reserved';
|
|
46
|
+
readonly issuedAtMs: number;
|
|
46
47
|
readonly statements: readonly D1PreparedStatementLike[];
|
|
47
48
|
} | {
|
|
48
49
|
readonly kind: 'already_exists';
|
|
50
|
+
readonly issuedAtMs: number;
|
|
49
51
|
} | {
|
|
50
52
|
readonly kind: 'custody_already_established';
|
|
51
53
|
} | {
|
|
@@ -148,12 +150,9 @@ export declare class CloudflareD1WalletCustodyCommitStore {
|
|
|
148
150
|
*/
|
|
149
151
|
readBackupAcknowledgement(walletId: WalletId): Promise<WalletRecoveryBackupAcknowledgementV1 | null>;
|
|
150
152
|
/**
|
|
151
|
-
* Records that the owner confirmed saving
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
* cosmetic, a repeat acknowledgement is not a conflict worth surfacing to
|
|
155
|
-
* someone pressing a button, and it shares no record with the wraps a spend
|
|
156
|
-
* updates — which is exactly why it is a separate key.
|
|
153
|
+
* Records the issuance that the owner confirmed saving. The caller selects
|
|
154
|
+
* that issuance before this write, so a concurrent rotation cannot make this
|
|
155
|
+
* acknowledgement apply to newer codes the owner did not see.
|
|
157
156
|
*/
|
|
158
157
|
writeBackupAcknowledgement(record: WalletRecoveryBackupAcknowledgementV1): Promise<{
|
|
159
158
|
kind: 'stored';
|
|
@@ -3,6 +3,7 @@ export type { WalletCustodyCeremonyCommitPayload };
|
|
|
3
3
|
import type { CloudflareD1WalletCustodyCommitStore, WalletCustodyRegistrationReservation } from '../../cloudflare/d1/passkeyCustody/d1WalletCustodyCommitStore';
|
|
4
4
|
export type WalletCustodyRegistrationCommitOutcome = {
|
|
5
5
|
readonly kind: 'already_exists';
|
|
6
|
+
readonly issuedAtMs: number;
|
|
6
7
|
} | {
|
|
7
8
|
readonly kind: 'custody_already_established';
|
|
8
9
|
} | {
|
|
@@ -10,12 +11,9 @@ export type WalletCustodyRegistrationCommitOutcome = {
|
|
|
10
11
|
readonly reason: string;
|
|
11
12
|
};
|
|
12
13
|
/** The write that a reservation left for after the registration's wallet commit. */
|
|
13
|
-
export type WalletCustodyRegistrationReserved = {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
kind: 'reserved';
|
|
17
|
-
}>['statements'];
|
|
18
|
-
};
|
|
14
|
+
export type WalletCustodyRegistrationReserved = Extract<WalletCustodyRegistrationReservation, {
|
|
15
|
+
kind: 'reserved';
|
|
16
|
+
}>;
|
|
19
17
|
/**
|
|
20
18
|
* Builds the records and claims their recovery-code routes.
|
|
21
19
|
*
|
|
@@ -701,7 +701,13 @@ type RouterApiMethodTypes = {
|
|
|
701
701
|
readonly expiresAtMs: number;
|
|
702
702
|
} | RouterApiOkFailure;
|
|
703
703
|
};
|
|
704
|
-
removeEmailOtpServerSeal:
|
|
704
|
+
removeEmailOtpServerSeal: {
|
|
705
|
+
readonly input: {
|
|
706
|
+
readonly wrappedCiphertext?: unknown;
|
|
707
|
+
readonly enrollmentSealKeyVersion: string;
|
|
708
|
+
};
|
|
709
|
+
readonly result: RouterApiMethodTypes['applyEmailOtpServerSeal']['result'];
|
|
710
|
+
};
|
|
705
711
|
respondWalletAddSignerEcdsaDerivation: {
|
|
706
712
|
readonly input: WalletAddSignerEcdsaDerivationRespondRequest;
|
|
707
713
|
readonly result: WalletAddSignerEcdsaDerivationRespondResponse;
|
|
@@ -52,15 +52,6 @@ export declare function handleWalletRecoveryBackupAcknowledge(ctx: FetchRouterAp
|
|
|
52
52
|
*/
|
|
53
53
|
export declare function handleWalletRecoveryRotate(ctx: FetchRouterApiContext): Promise<Response | null>;
|
|
54
54
|
export declare function handleWalletRecoveryRead(ctx: FetchRouterApiContext): Promise<Response | null>;
|
|
55
|
-
/**
|
|
56
|
-
* Reporting recovery status to the wallet's owner.
|
|
57
|
-
*
|
|
58
|
-
* The wallet comes from the path. Origin binding keeps this count endpoint
|
|
59
|
-
* scoped to browser callers without exposing recovery identifiers.
|
|
60
|
-
*
|
|
61
|
-
* Counts only, never identifiers. Which codes remain is not something even
|
|
62
|
-
* the owner's browser needs, and a list would be one leak away from being
|
|
63
|
-
* useful to someone else.
|
|
64
|
-
*/
|
|
55
|
+
/** Reports current recovery-code counts after fresh owner proof. */
|
|
65
56
|
export declare function handleWalletRecoveryStatus(ctx: FetchRouterApiContext): Promise<Response | null>;
|
|
66
57
|
//# sourceMappingURL=passkeyCustody.d.ts.map
|
package/dist/types/wallet-server/src/router/transport/fetch/routes/walletCustodyRequestBoundary.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { WebAuthnAuthenticationCredential } from '../../../../core/types';
|
|
2
|
+
export type WalletCustodyOwnerProofWire = {
|
|
3
|
+
readonly kind: 'passkey';
|
|
4
|
+
readonly walletId: string;
|
|
5
|
+
readonly rpId: string;
|
|
6
|
+
readonly credentialIdB64u: string;
|
|
7
|
+
readonly challenge_digest: string;
|
|
8
|
+
readonly webauthn_authentication: WebAuthnAuthenticationCredential;
|
|
9
|
+
} | {
|
|
10
|
+
readonly kind: 'email_otp';
|
|
11
|
+
readonly provider_subject_id: string;
|
|
12
|
+
readonly challenge_id: string;
|
|
13
|
+
readonly otp_code: string;
|
|
14
|
+
readonly challenge_digest: string;
|
|
15
|
+
};
|
|
16
|
+
export declare function requireExactObjectFields(value: Record<string, unknown>, fields: readonly string[], label: string): void;
|
|
17
|
+
export declare function parseCustodyOwnerProof(value: unknown): WalletCustodyOwnerProofWire;
|
|
18
|
+
export declare function parseRecoveryBackupAcknowledgementRequest(body: unknown): {
|
|
19
|
+
readonly walletId: string;
|
|
20
|
+
readonly requestId: string;
|
|
21
|
+
readonly expectedIssuedAtMs: number;
|
|
22
|
+
readonly factorProof: unknown;
|
|
23
|
+
};
|
|
24
|
+
export declare function parseRecoveryStatusRequest(body: unknown): {
|
|
25
|
+
readonly requestId: string;
|
|
26
|
+
readonly factorProof: unknown;
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=walletCustodyRequestBoundary.d.ts.map
|
package/dist/types/wallet-server/src/threshold/session/signingSessionSeal/crypto/cipher.d.ts
CHANGED
|
@@ -39,7 +39,10 @@ export declare function createPassthroughSigningSessionSealCipherAdapter(): Sign
|
|
|
39
39
|
export declare function encodeSigningSessionSealServerLockContext(input: {
|
|
40
40
|
readonly protocol: SigningSessionSealProtocol;
|
|
41
41
|
readonly keyVersion: string;
|
|
42
|
+
readonly walletId: string;
|
|
43
|
+
readonly thresholdSessionId: string;
|
|
42
44
|
}): Uint8Array;
|
|
45
|
+
export declare function createEmailOtpEnrollmentShamir3PassCipherAdapter(options: CreateSigningSessionSealShamir3PassCipherAdapterOptions): SigningSessionSealCipherAdapter;
|
|
43
46
|
export declare function createSigningSessionSealShamir3PassCipherAdapter(options: CreateSigningSessionSealShamir3PassCipherAdapterOptions): SigningSessionSealCipherAdapter;
|
|
44
47
|
export {};
|
|
45
48
|
//# sourceMappingURL=cipher.d.ts.map
|