@seams/wallet 0.5.1 → 0.5.2
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/LICENSE.md +201 -0
- package/THIRD_PARTY_NOTICES.md +15095 -0
- package/dist/.build-inputs.sha256 +1 -1
- package/dist/esm/SeamsWeb/signingSurface/BrowserSigningSurface.js +7 -14
- package/dist/esm/core/signingEngine/session/identity/exactWalletSessionReader.js +2 -27
- package/dist/esm/react/SeamsWeb/signingSurface/BrowserSigningSurface.js +7 -14
- package/dist/esm/react/core/signingEngine/session/identity/exactWalletSessionReader.js +2 -27
- package/dist/esm/sdk/export-private-key-viewer.js +8804 -55
- package/dist/esm/sdk/halo-border.js +8887 -8
- package/dist/esm/sdk/{host-BqwEYhX0.js → host-DNmO0eve.js} +2 -2
- package/dist/esm/sdk/passkey-halo-loading.js +8850 -27
- package/dist/{public/sdk/registrationPreparationPreload-u3ruCmpF.js → esm/sdk/registrationPreparationPreload-CwUkRwVz.js} +1 -1
- package/dist/esm/sdk/router_ab_ed25519_yao_client_bg.wasm +0 -0
- package/dist/{public/sdk/runtime-auth-Da9yQyaD.js → esm/sdk/runtime-auth-dpoaCtkK.js} +2 -2
- package/dist/esm/sdk/{runtime-device-link-DNlzlwrr.js → runtime-device-link-C75epnbj.js} +1 -1
- package/dist/{public/sdk/runtime-ecdsa-tempo-B7dBVcCI.js → esm/sdk/runtime-ecdsa-tempo-CV-E-iZG.js} +1 -1
- package/dist/{public/sdk/runtime-email-otp-CckVQZJC.js → esm/sdk/runtime-email-otp-V0mdMD_t.js} +1 -1
- package/dist/{public/sdk/runtime-export-WAiBwZL_.js → esm/sdk/runtime-export-C4HO5ysH.js} +1 -1
- package/dist/esm/sdk/{runtime-near-DBJ4KfFv.js → runtime-near-DlviFQWy.js} +1 -1
- package/dist/{public/sdk/runtime-preferences-DmH7eMHH.js → esm/sdk/runtime-preferences-DyJidFuf.js} +1 -1
- package/dist/esm/sdk/{runtime-recovery-kPgl9nTT.js → runtime-recovery-CHDE5gl0.js} +1 -1
- package/dist/esm/sdk/{runtimeContext-BorCgXo5.js → runtimeContext-D_TkUM6Z.js} +6 -38
- package/dist/esm/sdk/{runtimeLoader-BKQjNgXO.js → runtimeLoader-DxiLgXPm.js} +9 -9
- package/dist/esm/sdk/tx-confirm-ui.js +9568 -206
- package/dist/esm/sdk/w3a-tx-confirmer.js +8335 -206
- package/dist/esm/sdk/wallet-iframe-host-ecdsa.js +1 -1
- package/dist/esm/sdk/wallet-iframe-host-full.js +1 -1
- package/dist/esm/sdk/wallet-iframe-host-near.js +1 -1
- package/dist/esm/sdk/wallet-iframe-host-runtime.js +1 -1
- package/dist/esm/wasm/near_signer/pkg/wasm_signer_worker.js +4 -4
- package/dist/esm/wasm/near_signer/pkg/wasm_signer_worker_bg.wasm +0 -0
- package/dist/esm/wasm/router_ab_ecdsa_client/pkg/router_ab_ecdsa_client_bg.wasm +0 -0
- package/dist/esm/wasm/router_ab_ed25519_yao_client/pkg/router_ab_ed25519_yao_client_bg.wasm +0 -0
- package/dist/public/headers.manifest.json +1 -1
- package/dist/public/sdk/export-private-key-viewer.js +8804 -55
- package/dist/public/sdk/halo-border.js +8887 -8
- package/dist/public/sdk/{host-BqwEYhX0.js → host-DNmO0eve.js} +2 -2
- package/dist/public/sdk/passkey-halo-loading.js +8850 -27
- package/dist/{esm/sdk/registrationPreparationPreload-u3ruCmpF.js → public/sdk/registrationPreparationPreload-CwUkRwVz.js} +1 -1
- package/dist/public/sdk/router_ab_ed25519_yao_client_bg.wasm +0 -0
- package/dist/{esm/sdk/runtime-auth-Da9yQyaD.js → public/sdk/runtime-auth-dpoaCtkK.js} +2 -2
- package/dist/public/sdk/{runtime-device-link-DNlzlwrr.js → runtime-device-link-C75epnbj.js} +1 -1
- package/dist/{esm/sdk/runtime-ecdsa-tempo-B7dBVcCI.js → public/sdk/runtime-ecdsa-tempo-CV-E-iZG.js} +1 -1
- package/dist/{esm/sdk/runtime-email-otp-CckVQZJC.js → public/sdk/runtime-email-otp-V0mdMD_t.js} +1 -1
- package/dist/{esm/sdk/runtime-export-WAiBwZL_.js → public/sdk/runtime-export-C4HO5ysH.js} +1 -1
- package/dist/public/sdk/{runtime-near-DBJ4KfFv.js → runtime-near-DlviFQWy.js} +1 -1
- package/dist/{esm/sdk/runtime-preferences-DmH7eMHH.js → public/sdk/runtime-preferences-DyJidFuf.js} +1 -1
- package/dist/public/sdk/{runtime-recovery-kPgl9nTT.js → runtime-recovery-CHDE5gl0.js} +1 -1
- package/dist/public/sdk/{runtimeContext-BorCgXo5.js → runtimeContext-D_TkUM6Z.js} +6 -38
- package/dist/public/sdk/{runtimeLoader-BKQjNgXO.js → runtimeLoader-DxiLgXPm.js} +9 -9
- package/dist/public/sdk/tx-confirm-ui.js +9568 -206
- package/dist/public/sdk/w3a-tx-confirmer.js +8335 -206
- package/dist/public/sdk/wallet-iframe-host-ecdsa.js +1 -1
- package/dist/public/sdk/wallet-iframe-host-full.js +1 -1
- package/dist/public/sdk/wallet-iframe-host-near.js +1 -1
- package/dist/public/sdk/wallet-iframe-host-runtime.js +1 -1
- package/dist/public/sdk/workers/device-linking-key.worker.js +8603 -3
- package/dist/public/sdk/workers/ecdsa-derivation-client.worker.js +12320 -1
- package/dist/public/sdk/workers/ecdsa-online-client.worker.js +623 -1
- package/dist/public/sdk/workers/ecdsa-presign-client.worker.js +1276 -1
- package/dist/public/sdk/workers/email-otp.worker.js +15653 -7
- package/dist/public/sdk/workers/email_otp_runtime.js +39 -3
- package/dist/public/sdk/workers/email_otp_runtime_bg.wasm +0 -0
- package/dist/public/sdk/workers/evm-crypto.worker.js +1157 -5
- package/dist/public/sdk/workers/evm_crypto.wasm +0 -0
- package/dist/public/sdk/workers/evm_crypto_bg.wasm +0 -0
- package/dist/public/sdk/workers/near-signer.worker.js +1631 -2
- package/dist/public/sdk/workers/near_signer.wasm +0 -0
- package/dist/public/sdk/workers/passkey-confirm.worker.js +606 -1
- package/dist/public/sdk/workers/passkey-mpc-export.worker.js +5406 -2
- package/dist/public/sdk/workers/passkey-mpc-session.worker.js +1717 -1
- package/dist/public/sdk/workers/router_ab_ecdsa_client_bg.wasm +0 -0
- package/dist/public/sdk/workers/router_ab_ed25519_yao_client_bg.wasm +0 -0
- package/dist/public/sdk/workers/shamir3pass.worker.js +874 -4
- package/dist/public/sdk/workers/shamir3pass_runtime.js +84 -31
- package/dist/public/sdk/workers/shamir3pass_runtime_bg.wasm +0 -0
- package/dist/public/sdk/workers/tempo-signer.worker.js +987 -5
- package/dist/public/sdk/workers/tempo_signer.wasm +0 -0
- package/dist/public/sdk/workers/tempo_signer_bg.wasm +0 -0
- package/dist/public/sdk/workers/wallet-custody-ceremony.worker.js +55 -1244
- package/dist/public/sdk/workers/wallet_custody_ceremony_bg.wasm +0 -0
- package/dist/public/sdk/workers/wasm_signer_worker_bg.wasm +0 -0
- package/dist/public/wallet-assets.manifest.json +32 -32
- package/dist/types/wallet/src/SeamsWeb/signingSurface/BrowserSigningSurface.d.ts +4 -4
- package/dist/types/wallet/src/core/signingEngine/session/identity/exactWalletSessionReader.d.ts +1 -9
- package/dist/workers/device-linking-key.worker.js +8603 -3
- package/dist/workers/ecdsa-derivation-client.worker.js +12320 -1
- package/dist/workers/ecdsa-online-client.worker.js +623 -1
- package/dist/workers/ecdsa-presign-client.worker.js +1276 -1
- package/dist/workers/email-otp.worker.js +15653 -7
- package/dist/workers/email_otp_runtime.js +39 -3
- package/dist/workers/email_otp_runtime_bg.wasm +0 -0
- package/dist/workers/evm-crypto.worker.js +1157 -5
- package/dist/workers/evm_crypto.wasm +0 -0
- package/dist/workers/evm_crypto_bg.wasm +0 -0
- package/dist/workers/near-signer.worker.js +1631 -2
- package/dist/workers/near_signer.wasm +0 -0
- package/dist/workers/passkey-confirm.worker.js +606 -1
- package/dist/workers/passkey-mpc-export.worker.js +5406 -2
- package/dist/workers/passkey-mpc-session.worker.js +1717 -1
- package/dist/workers/router_ab_ecdsa_client_bg.wasm +0 -0
- package/dist/workers/router_ab_ed25519_yao_client_bg.wasm +0 -0
- package/dist/workers/shamir3pass.worker.js +874 -4
- package/dist/workers/shamir3pass_runtime.js +84 -31
- package/dist/workers/shamir3pass_runtime_bg.wasm +0 -0
- package/dist/workers/tempo-signer.worker.js +987 -5
- package/dist/workers/tempo_signer.wasm +0 -0
- package/dist/workers/tempo_signer_bg.wasm +0 -0
- package/dist/workers/wallet-custody-ceremony.worker.js +55 -1244
- package/dist/workers/wallet_custody_ceremony_bg.wasm +0 -0
- package/dist/workers/wasm_signer_worker_bg.wasm +0 -0
- package/package.json +5 -2
- package/LICENSE +0 -21
|
@@ -1 +1,1717 @@
|
|
|
1
|
-
function F0($,J){if($==null)return{ok:!1,error:{code:"missing",message:`${J} is required`}};if(typeof $!=="string")return{ok:!1,error:{code:"invalid",message:`${J} must be a string`}};let X=$.trim();if(!X)return{ok:!1,error:{code:"missing",message:`${J} is required`}};return{ok:!0,value:X}}function i($){return F0($,"thresholdSessionId")}function s($){return typeof $==="object"&&$!==null?$:null}function B0($){let J=s($);if(!J)return null;if(J.kind==="all")return{kind:"all"};if(J.kind!=="session")return null;let X=i(J.thresholdSessionId);if(!X.ok)return null;return{kind:"session",thresholdSessionId:X.value}}function r($){let J=s($);if(!J||J.kind!=="clear_volatile_warm_material")return null;if(J.durableRecord!=null||J.resolvedIdentity!=null||J.deleteReason!=null)return null;let X=B0(J.scope);if(!X)return null;return{kind:"clear_volatile_warm_material",scope:X}}function a($){return`0x${Array.from($).map((J)=>J.toString(16).padStart(2,"0")).join("")}`}var z0=($)=>{let J=ArrayBuffer.isView($)?new Uint8Array($.buffer,$.byteOffset,$.byteLength):new Uint8Array($),X="";for(let Y=0;Y<J.length;Y++)X+=String.fromCharCode(J[Y]);return btoa(X)};var e=($)=>{return z0($).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")};var $0=32;function E0($=$0,J="secure random bytes"){let X=Math.max(1,Math.floor(Number($)||0)),Y=globalThis.crypto;if(typeof Y?.getRandomValues!=="function")throw new Error(`WebCrypto getRandomValues is required for ${J}`);return Y.getRandomValues(new Uint8Array(X))}function J0($=$0,J="secure random id"){return e(E0($,J))}var f="rfc2409-group2";var X0="/wallet-session/seal",O8=new Uint8Array([64,12,49,139,102,149,151,54,89,161,105,138,229,128,223,216,0,29,153,81,186,50,198,149,230,52,153,71,80,79,63,132]),F8=new Uint8Array([38,218,80,229,172,150,74,126,160,132,82,127,182,71,246,51,11,50,222,81,169,175,70,82,75,0,109,143,127,231,244,209]);function Y0($){return typeof $==="string"?$:""}function P($){return Y0($).trim()}function w($){return String($??"").trim()}function U($){return w($)||void 0}function A0($){let J=typeof $==="number"?$:Number($);if(!Number.isFinite(J))return null;return J}function v($){let J=A0($);if(J==null)return null;return Math.trunc(J)}function p($){let J=v($);if(J==null||J<=0)return null;return J}function u($){let J=v($);if(J==null||J<0)return null;return J}function Z0($){return String($??"").replace(/\/+$/,"")}function Q0($){let J=w($);if(!J)return"";return J.startsWith("/")?J:`/${J}`}function C0($,J){let X=Z0(w($)),Y=Q0(w(J));if(!X)throw new Error("Missing base URL");return`${X}${Y}`}function D0(){if(typeof window==="undefined")return;let $=window,J=$.__W3A_WALLET_SDK_BASE__;return typeof J==="string"&&J.length>0?J:void 0}function o(){return typeof self!=="undefined"?self??null:null}function _0(){return o()?.location?.href}function x0(){return o()?.location?.origin}function V0($,J,X){if(X)return new URL($,X);if(typeof process!=="undefined"&&process.env?.WASM_BASE_URL)return new URL($,process.env.WASM_BASE_URL);let Y=J.toUpperCase().replace(/[^A-Z]/g,"_")+"_WASM_BASE_URL";if(typeof process!=="undefined"&&process.env?.[Y])return new URL($,process.env[Y]);let Z=o();if(Z?.WASM_BASE_URL)return new URL($,Z.WASM_BASE_URL);try{let Q=D0();if(Q)return new URL(`workers/${$}`,Q)}catch{}try{let Q=null;try{Q=typeof import.meta!=="undefined"&&import.meta?.url?import.meta.url:null}catch{Q=null}if(Q){let V=new URL(Q,_0());if(V.protocol==="http:"||V.protocol==="https:"){let _=V.pathname.indexOf("/sdk/");if(_>=0){let C=V.pathname.slice(0,_+5);return new URL(`${C}workers/${$}`,V.origin)}}return new URL(`./${$}`,V)}let D=_0()||"/";return new URL(`./${$}`,D)}catch{return new URL(`/sdk/workers/${$}`,x0()||"/")}}function k0($){if($.length>=255)throw new TypeError("Alphabet too long");let J=new Uint8Array(256);for(let C=0;C<J.length;C++)J[C]=255;for(let C=0;C<$.length;C++){let G=$.charAt(C),q=G.charCodeAt(0);if(J[q]!==255)throw new TypeError(G+" is ambiguous");J[q]=C}let X=$.length,Y=$.charAt(0),Z=Math.log(X)/Math.log(256),Q=Math.log(256)/Math.log(X);function D(C){if(C instanceof Uint8Array);else if(ArrayBuffer.isView(C))C=new Uint8Array(C.buffer,C.byteOffset,C.byteLength);else if(Array.isArray(C))C=Uint8Array.from(C);if(!(C instanceof Uint8Array))throw new TypeError("Expected Uint8Array");if(C.length===0)return"";let G=0,q=0,N=0,W=C.length;while(N!==W&&C[N]===0)N++,G++;let K=(W-N)*Q+1>>>0,M=new Uint8Array(K);while(N!==W){let T=C[N],j=0;for(let R=K-1;(T!==0||j<q)&&R!==-1;R--,j++)T+=256*M[R]>>>0,M[R]=T%X>>>0,T=T/X>>>0;if(T!==0)throw new Error("Non-zero carry");q=j,N++}let H=K-q;while(H!==K&&M[H]===0)H++;let B=Y.repeat(G);for(;H<K;++H)B+=$.charAt(M[H]);return B}function V(C){if(typeof C!=="string")throw new TypeError("Expected String");if(C.length===0)return new Uint8Array;let G=0,q=0,N=0;while(C[G]===Y)q++,G++;let W=(C.length-G)*Z+1>>>0,K=new Uint8Array(W);while(G<C.length){let T=C.charCodeAt(G);if(T>255)return;let j=J[T];if(j===255)return;let R=0;for(let I=W-1;(j!==0||R<N)&&I!==-1;I--,R++)j+=X*K[I]>>>0,K[I]=j%256>>>0,j=j/256>>>0;if(j!==0)throw new Error("Non-zero carry");N=R,G++}let M=W-N;while(M!==W&&K[M]===0)M++;let H=new Uint8Array(q+(W-M)),B=q;while(M!==W)H[B++]=K[M++];return H}function _(C){let G=V(C);if(G)return G;throw new Error("Non-base"+X+" character")}return{encode:D,decodeUnsafe:V,decode:_}}var G0=k0;var I0="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",b0=G0(I0);function W0($,J,X="is required"){let Y=P($);if(!Y)throw new Error(`${J} ${X}`);return Y}var g=null,y=null,L0=0,E=new Map,q0=15000;function m($,J){return W0($,J,"must be a non-empty string")}function K0($){return typeof $==="object"&&$!==null}function S0($){if(!K0($))throw new Error("Invalid Shamir3Pass key handle response");return{keyHandle:m($.keyHandle,"keyHandle")}}function f0($){let J=String($.code||"").trim(),X=m($.error,"error");return new Error(J?`[shamir3pass-worker] ${J}: ${X}`:`[shamir3pass-worker] ${X}`)}function w0($){if(!K0($))return null;let J=String($.id||"").trim();if(!J||typeof $.ok!=="boolean")return null;if($.ok)return{id:J,ok:!0,result:$.result};return{id:J,ok:!1,error:String($.error||"Worker request failed"),...String($.code||"").trim()?{code:String($.code).trim()}:{}}}function y0(){return L0+=1,`shamir3pass-${Date.now()}-${L0}`}function m0($){let J=Array.from(E.values());E.clear();for(let X of J){clearTimeout(X.timeoutId);try{X.reject(new Error($))}catch{}}}function H0($){let J=y;if(y=null,J)try{J.terminate()}catch{}m0($)}function h0(){let $=globalThis.Worker;if(typeof $!=="function")throw new Error("Shamir3Pass worker is unavailable in this runtime");return $}function p0(){if(y)return y;let $=h0(),J=V0("shamir3pass.worker.js","Shamir3Pass Worker"),X=new $(J,{type:"module",name:"shamir3pass-worker"});return X.onmessage=(Y)=>{let Z=w0(Y.data);if(!Z)return;let Q=E.get(Z.id);if(!Q)return;if(E.delete(Z.id),clearTimeout(Q.timeoutId),Z.ok){Q.resolve(Z.result);return}Q.reject(f0(Z))},X.onerror=(Y)=>{let Z=String(Y?.message||"Unknown worker error").trim();H0(`[shamir3pass-worker] ${Z||"Worker crashed"}`)},X.onmessageerror=()=>{H0("[shamir3pass-worker] Failed to deserialize worker message")},y=X,X}function k($,J,X){let Y=y0(),Z=p0();return new Promise((Q,D)=>{let V=setTimeout(()=>{E.delete(Y),D(new Error(`[shamir3pass-worker] Request timed out after ${q0}ms`))},q0);E.set(Y,{resolve:Q,reject:D,timeoutId:V});let _={id:Y,type:$,payload:J};try{Z.postMessage(_,X||[])}catch(C){let G=E.get(Y);if(G)E.delete(Y),clearTimeout(G.timeoutId);D(C instanceof Error?C:new Error(String(C||"Worker postMessage failed")))}})}function g0(){return{createClientKeyHandle:async({groupId:$})=>S0(await k("createClientKeyHandle",{groupId:$})),destroyClientKeyHandle:async({keyHandle:$})=>{await k("destroyClientKeyHandle",{keyHandle:$})},addClientSealWithKeyHandle:async({ciphertextB64u:$,keyHandle:J})=>m(await k("addClientSealWithKeyHandle",{ciphertextB64u:$,keyHandle:J}),"ciphertextB64u"),addClientSealBytesWithKeyHandle:async({ciphertext:$,keyHandle:J})=>{let X=$.slice();return m(await k("addClientSealBytesWithKeyHandle",{ciphertext:X.buffer,keyHandle:J},[X.buffer]),"ciphertextB64u")},removeClientSealWithKeyHandle:async({ciphertextB64u:$,keyHandle:J})=>m(await k("removeClientSealWithKeyHandle",{ciphertextB64u:$,keyHandle:J}),"ciphertextB64u"),removeClientSealWithKeyHandleToBytes:async({ciphertextB64u:$,keyHandle:J})=>{let X=await k("removeClientSealWithKeyHandleToBytes",{ciphertextB64u:$,keyHandle:J});if(!(X instanceof ArrayBuffer))throw new Error("ciphertext bytes response must be an ArrayBuffer");return new Uint8Array(X)}}}async function N0(){let $=performance.now();try{return await k("warmup",{}),{kind:"succeeded",elapsedMs:Math.max(0,Math.round(performance.now()-$))}}catch{return{kind:"failed",elapsedMs:Math.max(0,Math.round(performance.now()-$))}}}async function n(){if(!g)g=Promise.resolve(g0()).catch(($)=>{throw g=null,$});return g}var c0=32,x=new Map,b=new Map,z=new Map,t=new Map,d=new Map,v0=X0,M0=15000;function u0($){$.abort("timeout")}function o0($){return typeof $==="string"?P($)||void 0:void 0}function O($){if(typeof $!=="string")return null;return P($)||null}function S($){return typeof $==="number"&&Number.isSafeInteger($)?$:null}function n0($){if(!Array.isArray($))return null;let J=Object.keys($);if(J.length!==$.length||J.some((Y)=>!/^\d+$/.test(Y)))return null;let X=[];for(let Y=0;Y<$.length;Y+=1){let Z=O($[Y]);if(!Z)return null;X.push(Z)}return X}function t0($){if($===null||typeof $!=="object"||Array.isArray($))return null;let J=Object.keys($);if(J.some((_)=>!["thresholdSessionId","prfFirstB64u","expiresAtMs","remainingUses","transport"].includes(_))||!["thresholdSessionId","prfFirstB64u","expiresAtMs","remainingUses"].every((_)=>J.includes(_)))return null;let X=O(Reflect.get($,"thresholdSessionId")),Y=O(Reflect.get($,"prfFirstB64u")),Z=S(Reflect.get($,"expiresAtMs")),Q=S(Reflect.get($,"remainingUses")),D=J.includes("transport"),V=D?l(Reflect.get($,"transport")):void 0;if(!X||!Y||Z===null||Q===null||D&&!V)return null;return{thresholdSessionId:X,prfFirstB64u:Y,expiresAtMs:Z,remainingUses:Q,...V?{transport:V}:{}}}function d0($){if($===null||typeof $!=="object"||Array.isArray($))return null;let J=Object.keys($);if(J.length!==1||J[0]!=="thresholdSessionId")return null;let X=O(Reflect.get($,"thresholdSessionId"));return X?{thresholdSessionId:X}:null}function l0($){if($===null||typeof $!=="object"||Array.isArray($))return null;let J=Object.keys($);if(J.length!==1||J[0]!=="thresholdSessionIds")return null;let X=n0(Reflect.get($,"thresholdSessionIds"));return X?{thresholdSessionIds:X}:null}function i0($){if($===null||typeof $!=="object"||Array.isArray($))return null;let J=Object.keys($);if(J.some((C)=>!["thresholdSessionId","uses","consume","curve"].includes(C))||!J.includes("thresholdSessionId"))return null;let X=O(Reflect.get($,"thresholdSessionId")),Z=J.includes("uses")?S(Reflect.get($,"uses")):1,D=J.includes("consume")?Reflect.get($,"consume"):!0,_=J.includes("curve")?Reflect.get($,"curve"):void 0;if(!X||Z===null||Z<1||typeof D!=="boolean"||_!==void 0&&_!=="ed25519"&&_!=="ecdsa")return null;return{thresholdSessionId:X,uses:Z,consume:D,..._!==void 0?{curve:_}:{}}}function s0($){if($===null||typeof $!=="object"||Array.isArray($))return null;let J=Object.keys($);if(J.some((V)=>!["thresholdSessionId","uses","curve"].includes(V))||!J.includes("thresholdSessionId"))return null;let X=O(Reflect.get($,"thresholdSessionId")),Z=J.includes("uses")?S(Reflect.get($,"uses")):1,D=J.includes("curve")?Reflect.get($,"curve"):void 0;if(!X||Z===null||Z<1||D!==void 0&&D!=="ed25519"&&D!=="ecdsa")return null;return{thresholdSessionId:X,uses:Z,...D!==void 0?{curve:D}:{}}}function r0($){if($===null||typeof $!=="object"||Array.isArray($))return null;let J=Object.keys($);if(J.length!==2||!J.includes("thresholdSessionId")||!J.includes("transport"))return null;let X=O(Reflect.get($,"thresholdSessionId")),Y=l(Reflect.get($,"transport"));return X&&Y?{thresholdSessionId:X,transport:Y}:null}function a0($){if($===null||typeof $!=="object"||Array.isArray($))return null;let J=Object.keys($),X=["thresholdSessionId","sealedSecretB64u","expiresAtMs","remainingUses","transport"];if(J.some((G)=>![...X,"signingSessionSealKeyVersion"].includes(G))||X.some((G)=>!J.includes(G)))return null;let Y=O(Reflect.get($,"thresholdSessionId")),Z=O(Reflect.get($,"sealedSecretB64u")),Q=S(Reflect.get($,"expiresAtMs")),D=S(Reflect.get($,"remainingUses")),V=l(Reflect.get($,"transport")),_=J.includes("signingSessionSealKeyVersion"),C=_?O(Reflect.get($,"signingSessionSealKeyVersion")):void 0;if(!Y||!Z||Q===null||D===null||!V||_&&!C)return null;return{thresholdSessionId:Y,sealedSecretB64u:Z,expiresAtMs:Q,remainingUses:D,...C?{keyVersion:C}:{},transport:V}}function e0($){if($===null||typeof $!=="object"||Array.isArray($))return{kind:"unknown",type:void 0};let J=Object.keys($);if(J.some((D)=>!["id","type","payload"].includes(D))||!J.includes("type"))return{kind:"unknown",type:Reflect.get($,"type")};let X=J.includes("id")?o0(Reflect.get($,"id")):void 0;if(J.includes("id")&&X===void 0)return{kind:"unknown",type:Reflect.get($,"type")};let Y=Reflect.get($,"type"),Z=J.includes("payload"),Q=Z?Reflect.get($,"payload"):void 0;switch(Y){case"PING":return J.length===(J.includes("id")?2:1)?{kind:"ping",...X?{id:X}:{}}:{kind:"unknown",id:X,type:Y};case"PREWARM_SHAMIR3PASS":if(!Z||Q===null||typeof Q!=="object"||Array.isArray(Q))return{kind:"unknown",id:X,type:Y};if(Object.keys(Q).length!==0)return{kind:"unknown",id:X,type:Y};return{kind:"prewarm",...X?{id:X}:{}};case"WARM_SESSION_MATERIAL_PUT":return{kind:"material_put",...X?{id:X}:{},payload:Z?t0(Q):null};case"WARM_SESSION_STATUS_READ":return{kind:"status_read",...X?{id:X}:{},payload:Z?d0(Q):null};case"WARM_SESSION_STATUS_BATCH_READ":return{kind:"status_batch_read",...X?{id:X}:{},payload:Z?l0(Q):null};case"WARM_SESSION_MATERIAL_CLAIM":return{kind:"material_claim",...X?{id:X}:{},payload:Z?i0(Q):null};case"WARM_SESSION_MATERIAL_CONSUME":return{kind:"material_consume",...X?{id:X}:{},payload:Z?s0(Q):null};case"WARM_SESSION_VOLATILE_MATERIAL_CLEAR":return Z?{kind:"volatile_clear",...X?{id:X}:{},payload:Q}:{kind:"unknown",id:X,type:Y};case"WARM_SESSION_VOLATILE_MATERIAL_CLEAR_ALL":return Z?{kind:"volatile_clear_all",...X?{id:X}:{},payload:Q}:{kind:"unknown",id:X,type:Y};case"WARM_SESSION_SEAL_AND_PERSIST":return{kind:"seal_and_persist",...X?{id:X}:{},payload:Z?r0(Q):null};case"WARM_SESSION_REHYDRATE":return{kind:"rehydrate",...X?{id:X}:{},payload:Z?a0(Q):null};default:return{kind:"unknown",id:X,type:Y}}}function F(){return Date.now()}function $8($){return Math.max(0,Math.round(performance.now()-$))}function J8(){return{runtimeSetupMs:0,clientSealMs:0,serverSealRouteMs:0,clientUnsealMs:0,policyUpdateMs:0}}function h($){$.diagnostics[$.bucket]+=$8($.startedAt)}function X8($){return`${String($||"").trim()||"session"}:${J0(32,"passkey confirm worker session IDs")}`}function Y8($){let J=P($.prfFirstB64u),X=Math.floor(Number($.expiresAtMs)||0);if(!J||X<=F())throw new Error("Invalid passkey PRF material handle input");let Y=X8("passkey-prf-first");return b.set(Y,{prfFirstB64u:J,expiresAtMs:X}),Y}async function Z8($){let J=await crypto.subtle.digest("SHA-256",new TextEncoder().encode($));return a(new Uint8Array(J))}async function Q8($){let J=P($.prfFirstB64u),X=P($.relayerUrl),Y=U($.keyVersion),Z=$.cacheScope;if(!J||!X||!Y||!Z)return null;let Q=await Z8(J);return["passkey-server-sealed-secret-v1",X,Y,f,Z.walletId,Z.credentialIdB64u,Z.walletSessionId,Z.quotaId,Q].join("|")}function U0(){let $=F();for(let[J,X]of z)if(X.expiresAtMs<=$)z.delete(J);while(z.size>c0){let J=z.keys().next().value;if(typeof J!=="string")return;z.delete(J)}}function C8($){if(!$)return null;U0();let J=z.get($);if(!J||J.expiresAtMs<=F()){if(J)z.delete($);return null}return J}function D8($){if(!$.cacheKey)return;let J=P($.sealedSecretB64u),X=Math.floor(Number($.expiresAtMs)||0);if(!J||X<=F())return;z.set($.cacheKey,{sealedSecretB64u:J,expiresAtMs:X}),U0()}function A($){let J=x.get($);if(J)b.delete(J.prfFirstHandle);x.delete($)}function _8(){x.clear(),b.clear(),z.clear()}function R0($){let J=P($.thresholdSessionId),X=Math.floor(Number($.remainingUses)||0),Y=Math.floor(Number($.expiresAtMs)||0);if(!J||X<=0||Y<=F())throw new Error("Invalid warm-session PRF handle input");A(J);let Q={prfFirstHandle:Y8({prfFirstB64u:$.prfFirstB64u,expiresAtMs:Y}),expiresAtMs:Y,remainingUses:X};return x.set(J,Q),Q}function V8($,J,X){let Y={prfFirstHandle:J.prfFirstHandle,remainingUses:X.remainingUses,expiresAtMs:X.expiresAtMs},Z=b.get(J.prfFirstHandle);if(Z)b.set(J.prfFirstHandle,{prfFirstB64u:Z.prfFirstB64u,expiresAtMs:X.expiresAtMs});return x.set($,Y),Y}function l($){if($===null||typeof $!=="object"||Array.isArray($))return null;let J=Reflect.get($,"curve"),X=Reflect.get($,"authMethod"),Y=J==="ed25519"?["curve","authMethod","walletId","relayerUrl","walletSessionToken","ed25519Restore"]:J==="ecdsa"?["curve","authMethod","walletId","chainTarget","relayerUrl","walletSessionToken","ecdsaRestore"]:[],Z=["signingSessionSealKeyVersion","groupId","serverSealedSecretCacheScope"],Q=Object.keys($);if(J!=="ed25519"&&J!=="ecdsa"||X!=="passkey"||Q.some((H)=>![...Y,...Z].includes(H))||Y.some((H)=>!Q.includes(H)))return null;let D=O(Reflect.get($,"walletId")),V=U(Reflect.get($,"relayerUrl")),_=U(Reflect.get($,"walletSessionToken")),C=Reflect.get($,J==="ed25519"?"ed25519Restore":"ecdsaRestore"),G=J==="ecdsa"?Reflect.get($,"chainTarget"):void 0,q=Reflect.get($,"signingSessionSealKeyVersion"),N=Q.includes("signingSessionSealKeyVersion"),W=U(q),K=Q.includes("serverSealedSecretCacheScope"),M=G8(Reflect.get($,"serverSealedSecretCacheScope"));if(!D||!V||!_||C===null||typeof C!=="object"||Array.isArray(C)||J==="ecdsa"&&(G===null||typeof G!=="object"||Array.isArray(G))||N&&!W||K&&!M)return null;return{relayerUrl:V,walletSessionToken:_,...N&&W?{keyVersion:W}:{},...M?{serverSealedSecretCacheScope:M}:{}}}function G8($){if($===null||typeof $!=="object"||Array.isArray($))return;let J=Object.keys($);if(J.length!==5||!["kind","walletId","credentialIdB64u","walletSessionId","quotaId"].every((D)=>J.includes(D))||Reflect.get($,"kind")!=="passkey_registration")return;let X=U(Reflect.get($,"walletId")),Y=U(Reflect.get($,"credentialIdB64u")),Z=U(Reflect.get($,"walletSessionId")),Q=U(Reflect.get($,"quotaId"));if(!X||!Y||!Z||!Q)return;return{kind:"passkey_registration",walletId:X,credentialIdB64u:Y,walletSessionId:Z,quotaId:Q}}function W8($){if($===null||typeof $!=="object"||Array.isArray($))return{ok:!1,code:"invalid_response",message:"Invalid signing-session seal response"};let J=Reflect.get($,"ok");if(typeof J!=="boolean")return{ok:!1,code:"invalid_response",message:"Invalid signing-session seal response"};let X=Object.keys($),Y=J?["ok","ciphertext","keyVersion","expiresAtMs","remainingUses"]:["ok","code","message"];if(X.some((_)=>!Y.includes(_)))return{ok:!1,code:"invalid_response",message:"Invalid signing-session seal response"};if(!J){let _=Reflect.get($,"code"),C=Reflect.get($,"message");return{ok:!1,code:typeof _==="string"?_:"request_failed",message:typeof C==="string"?C:"Signing-session seal request failed"}}let Z=P(Reflect.get($,"ciphertext")),Q=U(Reflect.get($,"keyVersion")),D=p(Reflect.get($,"expiresAtMs")),V=u(Reflect.get($,"remainingUses"));if(!Z)return{ok:!1,code:"invalid_response",message:"Missing ciphertext in signing-session seal response"};return{ok:!0,ciphertext:Z,...Q?{keyVersion:Q}:{},...D!=null?{expiresAtMs:D}:{},...V!=null?{remainingUses:V}:{}}}function T0($){let J=$.operation==="apply-server-seal"?"apply-server-seal":"remove-server-seal",X=P($.thresholdSessionId)||"",Y=P($.relayerUrl)||"",Z=U($.keyVersion)||"",Q=U($.payloadKey)||"";return`${J}|${X}|${Y}|${Z}|${f}|${Q}`}async function j0($){let J=$.operation==="apply-server-seal"?"apply-server-seal":"remove-server-seal",X=C0($.transport.relayerUrl,`${v0}/${J}`),Y=new AbortController,Z=setTimeout(u0,M0,Y);try{let Q={"Content-Type":"application/json"},D=U($.keyVersion);Q.Authorization=`Bearer ${$.transport.walletSessionToken}`;let V=await fetch(X,{method:"POST",credentials:"omit",headers:Q,signal:Y.signal,body:JSON.stringify({thresholdSessionId:$.thresholdSessionId,ciphertext:$.ciphertext,...D?{keyVersion:D}:{}})}),_=await V.json().catch(()=>null),C=W8(_);if(!V.ok&&C.ok)return{ok:!1,code:"http_error",message:`Signing-session seal route returned HTTP ${V.status}`};if(!C.ok)return C;return C}catch(Q){return{ok:!1,code:Y.signal.aborted?"timeout":"network_error",message:Y.signal.aborted?`Signing-session seal request timed out after ${M0}ms`:Q instanceof Error?Q.message:String(Q||"Signing-session seal request failed")}}finally{clearTimeout(Z)}}function O0($){let J=Math.max(0,Math.floor(Number($.localRemainingUses)||0)),X=Math.max(0,Math.floor(Number($.localExpiresAtMs)||0)),Y=u($.serverRemainingUses)??J,Z=p($.serverExpiresAtMs)||X,Q=Math.min(J,Y),D=Math.min(X,Z);if(Q<=0)return{ok:!1,code:"exhausted",message:"Warm-session material exhausted for threshold session"};if(D<=F())return{ok:!1,code:"expired",message:"Warm-session material expired for threshold session"};return{ok:!0,remainingUses:Q,expiresAtMs:D}}function c($){if(!$)return{ok:!1,code:"invalid_args",message:"Missing threshold sessionId"};let J=x.get($);if(!J)return{ok:!1,code:"not_found",message:"Warm-session material is not available for threshold session"};if(F()>=J.expiresAtMs)return A($),{ok:!1,code:"expired",message:"Warm-session material expired for threshold session"};if(J.remainingUses<=0)return A($),{ok:!1,code:"exhausted",message:"Warm-session material exhausted for threshold session"};let X=b.get(J.prfFirstHandle);if(!X||F()>=X.expiresAtMs)return A($),{ok:!1,code:"not_found",message:"Warm-session material handle is not available for threshold session"};return{ok:!0,entry:J,secret:X,remainingUses:J.remainingUses,expiresAtMs:J.expiresAtMs}}function P0($){let J=c($);if(!J.ok)return J;return{ok:!0,remainingUses:J.remainingUses,expiresAtMs:J.expiresAtMs}}function L8($,J,X){let Y=c($);if(!Y.ok)return Y;let Z=Y.entry,Q=Math.max(1,Math.floor(Number(J)||1));if(Z.remainingUses<Q)return{ok:!1,code:"exhausted",message:"Warm-session material exhausted for threshold session"};if(X)if(Z.remainingUses-=Q,Z.remainingUses<=0)A($);else x.set($,Z);return{ok:!0,prfFirstB64u:Y.secret.prfFirstB64u,remainingUses:Z.remainingUses,expiresAtMs:Z.expiresAtMs}}function q8($,J){let X=c($);if(!X.ok)return X;let Y=X.entry,Z=Math.max(1,Math.floor(Number(J)||1));if(Y.remainingUses<Z)return{ok:!1,code:"exhausted",message:"Warm-session material exhausted for threshold session"};if(Y.remainingUses-=Z,Y.remainingUses<=0)A($);else x.set($,Y);return{ok:!0,remainingUses:Y.remainingUses,expiresAtMs:Y.expiresAtMs}}async function H8($){let J=P($.thresholdSessionId);if(!J)return{ok:!1,code:"invalid_args",message:"Missing threshold sessionId"};let X=c(J);if(!X.ok)return X;let Y=X.entry,Z=T0({operation:"apply-server-seal",thresholdSessionId:J,relayerUrl:$.transport.relayerUrl,keyVersion:$.transport.keyVersion,payloadKey:Y.prfFirstHandle}),Q=t.get(Z);if(Q)return await Q;let D=(async()=>{let V=J8();try{let _=performance.now(),C=await n(),G=await C.createClientKeyHandle({groupId:f});h({diagnostics:V,bucket:"runtimeSetupMs",startedAt:_});try{let q=performance.now(),N=await C.addClientSealWithKeyHandle({ciphertextB64u:X.secret.prfFirstB64u,keyHandle:G.keyHandle});h({diagnostics:V,bucket:"clientSealMs",startedAt:q});let W=performance.now(),K=await j0({operation:"apply-server-seal",transport:$.transport,thresholdSessionId:J,ciphertext:N,keyVersion:$.transport.keyVersion});if(h({diagnostics:V,bucket:"serverSealRouteMs",startedAt:W}),!K.ok)return K;let M=performance.now(),H=O0({localRemainingUses:Y.remainingUses,localExpiresAtMs:Y.expiresAtMs,serverRemainingUses:K.remainingUses,serverExpiresAtMs:K.expiresAtMs});if(!H.ok)return A(J),H;V8(J,Y,H),h({diagnostics:V,bucket:"policyUpdateMs",startedAt:M});let B=U(K.keyVersion)||U($.transport.keyVersion),T=B?await Q8({prfFirstB64u:X.secret.prfFirstB64u,relayerUrl:$.transport.relayerUrl,keyVersion:B,cacheScope:$.transport.serverSealedSecretCacheScope}):null,R=C8(T)?.sealedSecretB64u||"";if(!R){let I=performance.now();R=await C.removeClientSealWithKeyHandle({ciphertextB64u:K.ciphertext,keyHandle:G.keyHandle}),h({diagnostics:V,bucket:"clientUnsealMs",startedAt:I}),D8({cacheKey:T,sealedSecretB64u:R,expiresAtMs:H.expiresAtMs})}return{ok:!0,sealedSecretB64u:R,...B?{keyVersion:B}:{},remainingUses:H.remainingUses,expiresAtMs:H.expiresAtMs,diagnostics:V}}finally{await C.destroyClientKeyHandle({keyHandle:G.keyHandle}).catch(()=>{return})}}catch(_){return{ok:!1,code:"internal",message:_ instanceof Error?_.message:String(_||"Failed to apply server seal")}}})().finally(()=>{t.delete(Z)});return t.set(Z,D),await D}async function K8($){let J=P($.thresholdSessionId);if(!J)return{ok:!1,code:"invalid_args",message:"Missing threshold sessionId"};let X=P($.sealedSecretB64u);if(!X)return{ok:!1,code:"invalid_args",message:"Missing sealedSecretB64u"};let Y=Math.max(0,Math.floor(Number($.remainingUses)||0)),Z=Math.max(0,Math.floor(Number($.expiresAtMs)||0));if(Y<=0)return{ok:!1,code:"exhausted",message:"Warm-session material exhausted for threshold session"};if(Z<=F())return{ok:!1,code:"expired",message:"Warm-session material expired for threshold session"};let Q=T0({operation:"remove-server-seal",thresholdSessionId:J,relayerUrl:$.transport.relayerUrl,keyVersion:$.keyVersion||$.transport.keyVersion,payloadKey:X}),D=d.get(Q);if(D)return await D;let V=(async()=>{try{let _=await n(),C=await _.createClientKeyHandle({groupId:f});try{let G=await _.addClientSealWithKeyHandle({ciphertextB64u:X,keyHandle:C.keyHandle}),q=await j0({operation:"remove-server-seal",transport:$.transport,thresholdSessionId:J,ciphertext:G,keyVersion:U($.keyVersion)||$.transport.keyVersion});if(!q.ok)return q;let N=await _.removeClientSealWithKeyHandle({ciphertextB64u:q.ciphertext,keyHandle:C.keyHandle}),W=O0({localRemainingUses:Y,localExpiresAtMs:Z,serverRemainingUses:q.remainingUses,serverExpiresAtMs:q.expiresAtMs});if(!W.ok)return W;return R0({thresholdSessionId:J,prfFirstB64u:N,remainingUses:W.remainingUses,expiresAtMs:W.expiresAtMs}),W}finally{await _.destroyClientKeyHandle({keyHandle:C.keyHandle}).catch(()=>{return})}}catch(_){return{ok:!1,code:"internal",message:_ instanceof Error?_.message:String(_||"Failed to remove server seal")}}})().finally(()=>{d.delete(Q)});return d.set(Q,V),await V}function L($,J){let X=J.success?{...typeof $==="string"&&$.trim()?{id:$.trim()}:{},success:!0,data:J.data}:{...typeof $==="string"&&$.trim()?{id:$.trim()}:{},success:!1,error:J.error};try{self.postMessage(X)}catch{}}self.onmessage=($)=>{let J=e0($.data);switch(J.kind){case"ping":L(J.id,{success:!0,data:{ok:!0}});return;case"prewarm":(async()=>{let X=await N0();L(J.id,{success:!0,data:X})})();return;case"material_put":{try{let X=J.payload;if(!X){L(J.id,{success:!0,data:{ok:!1,code:"invalid_args",message:"Invalid WARM_SESSION_MATERIAL_PUT payload"}});return}let{thresholdSessionId:Y,prfFirstB64u:Z,expiresAtMs:Q,remainingUses:D}=X;if(Q<=F()||D<=0){L(J.id,{success:!0,data:{ok:!1,code:"invalid_args",message:"Invalid expiresAtMs or remainingUses"}});return}R0({thresholdSessionId:Y,prfFirstB64u:Z,expiresAtMs:Q,remainingUses:D}),L(J.id,{success:!0,data:{ok:!0,remainingUses:D,expiresAtMs:Q}})}catch(X){let Y=X instanceof Error?X.message:String(X);L(J.id,{success:!1,error:Y})}return}case"status_read":if(!J.payload){L(J.id,{success:!1,error:"Invalid WARM_SESSION_STATUS_READ payload"});return}L(J.id,{success:!0,data:P0(J.payload.thresholdSessionId)});return;case"status_batch_read":if(!J.payload){L(J.id,{success:!1,error:"Invalid WARM_SESSION_STATUS_BATCH_READ payload"});return}L(J.id,{success:!0,data:{results:Array.from(new Set(J.payload.thresholdSessionIds)).map((X)=>({thresholdSessionId:X,result:P0(X)}))}});return;case"material_claim":if(!J.payload){L(J.id,{success:!1,error:"Invalid WARM_SESSION_MATERIAL_CLAIM payload"});return}L(J.id,{success:!0,data:L8(J.payload.thresholdSessionId,J.payload.uses,J.payload.consume)});return;case"material_consume":if(!J.payload){L(J.id,{success:!1,error:"Invalid WARM_SESSION_MATERIAL_CONSUME payload"});return}L(J.id,{success:!0,data:q8(J.payload.thresholdSessionId,J.payload.uses)});return;case"volatile_clear":{let X=r(J.payload);if(X?.scope.kind==="session")A(String(X.scope.thresholdSessionId));L(J.id,{success:!0,data:{ok:!0}});return}case"volatile_clear_all":_8(),L(J.id,{success:!0,data:{ok:!0}});return;case"seal_and_persist":(async()=>{let X=J.payload;if(!X){L(J.id,{success:!0,data:{ok:!1,code:"invalid_args",message:"Invalid WARM_SESSION_SEAL_AND_PERSIST payload"}});return}let Y=await H8(X);L(J.id,{success:!0,data:Y})})();return;case"rehydrate":(async()=>{let X=J.payload;if(!X){L(J.id,{success:!0,data:{ok:!1,code:"invalid_args",message:"Invalid WARM_SESSION_REHYDRATE payload"}});return}let Y=await K8(X);L(J.id,{success:!0,data:Y})})();return;case"unknown":if(J.id)L(J.id,{success:!1,error:`Unsupported Passkey MPC session worker message type: ${String(J.type)}`});return}};self.onerror=($)=>{console.error("[passkey-mpc-session-worker] error:",$)};self.onunhandledrejection=($)=>{console.error("[passkey-mpc-session-worker] Unhandled promise rejection:",$.reason),$.preventDefault()};
|
|
1
|
+
// ../shared-ts/src/utils/domainIds.ts
|
|
2
|
+
function parseDomainId(raw, fieldName) {
|
|
3
|
+
if (raw == null) {
|
|
4
|
+
return {
|
|
5
|
+
ok: false,
|
|
6
|
+
error: {
|
|
7
|
+
code: "missing",
|
|
8
|
+
message: `${fieldName} is required`
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
if (typeof raw !== "string") {
|
|
13
|
+
return {
|
|
14
|
+
ok: false,
|
|
15
|
+
error: {
|
|
16
|
+
code: "invalid",
|
|
17
|
+
message: `${fieldName} must be a string`
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const value = raw.trim();
|
|
22
|
+
if (!value) {
|
|
23
|
+
return {
|
|
24
|
+
ok: false,
|
|
25
|
+
error: {
|
|
26
|
+
code: "missing",
|
|
27
|
+
message: `${fieldName} is required`
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return { ok: true, value };
|
|
32
|
+
}
|
|
33
|
+
function parseThresholdSessionId(raw) {
|
|
34
|
+
return parseDomainId(raw, "thresholdSessionId");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/core/signingEngine/session/warmCapabilities/volatileWarmMaterialCommands.ts
|
|
38
|
+
function asRecord(value) {
|
|
39
|
+
return typeof value === "object" && value !== null ? value : null;
|
|
40
|
+
}
|
|
41
|
+
function parseVolatileWarmSessionScope(value) {
|
|
42
|
+
const raw = asRecord(value);
|
|
43
|
+
if (!raw)
|
|
44
|
+
return null;
|
|
45
|
+
if (raw.kind === "all")
|
|
46
|
+
return { kind: "all" };
|
|
47
|
+
if (raw.kind !== "session")
|
|
48
|
+
return null;
|
|
49
|
+
const thresholdSessionId = parseThresholdSessionId(raw.thresholdSessionId);
|
|
50
|
+
if (!thresholdSessionId.ok)
|
|
51
|
+
return null;
|
|
52
|
+
return {
|
|
53
|
+
kind: "session",
|
|
54
|
+
thresholdSessionId: thresholdSessionId.value
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function parseClearVolatileWarmMaterialCommand(value) {
|
|
58
|
+
const raw = asRecord(value);
|
|
59
|
+
if (!raw || raw.kind !== "clear_volatile_warm_material")
|
|
60
|
+
return null;
|
|
61
|
+
if (raw.durableRecord != null || raw.resolvedIdentity != null || raw.deleteReason != null) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
const scope = parseVolatileWarmSessionScope(raw.scope);
|
|
65
|
+
if (!scope)
|
|
66
|
+
return null;
|
|
67
|
+
return {
|
|
68
|
+
kind: "clear_volatile_warm_material",
|
|
69
|
+
scope
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/core/signingEngine/chains/evm/bytes.ts
|
|
74
|
+
function bytesToHex(bytes) {
|
|
75
|
+
return `0x${Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ../shared-ts/src/utils/base64.ts
|
|
79
|
+
var base64Encode = (value) => {
|
|
80
|
+
const bytes = ArrayBuffer.isView(value) ? new Uint8Array(value.buffer, value.byteOffset, value.byteLength) : new Uint8Array(value);
|
|
81
|
+
let binary = "";
|
|
82
|
+
for (let i = 0;i < bytes.length; i++) {
|
|
83
|
+
binary += String.fromCharCode(bytes[i]);
|
|
84
|
+
}
|
|
85
|
+
return btoa(binary);
|
|
86
|
+
};
|
|
87
|
+
var base64UrlEncode = (value) => {
|
|
88
|
+
return base64Encode(value).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// ../shared-ts/src/utils/secureRandomId.ts
|
|
92
|
+
var DEFAULT_SECURE_RANDOM_ID_BYTES = 32;
|
|
93
|
+
function secureRandomBytes(length = DEFAULT_SECURE_RANDOM_ID_BYTES, label = "secure random bytes") {
|
|
94
|
+
const byteLength = Math.max(1, Math.floor(Number(length) || 0));
|
|
95
|
+
const cryptoApi = globalThis.crypto;
|
|
96
|
+
if (typeof cryptoApi?.getRandomValues !== "function") {
|
|
97
|
+
throw new Error(`WebCrypto getRandomValues is required for ${label}`);
|
|
98
|
+
}
|
|
99
|
+
return cryptoApi.getRandomValues(new Uint8Array(byteLength));
|
|
100
|
+
}
|
|
101
|
+
function secureRandomBase64Url(byteLength = DEFAULT_SECURE_RANDOM_ID_BYTES, label = "secure random id") {
|
|
102
|
+
return base64UrlEncode(secureRandomBytes(byteLength, label));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ../shared-ts/src/utils/signingSessionSeal.ts
|
|
106
|
+
var SIGNING_SESSION_SEAL_GROUP_ID = "rfc2409-group2";
|
|
107
|
+
var WALLET_SESSION_SEAL_BASE_PATH = "/wallet-session/seal";
|
|
108
|
+
var PASSKEY_PRF_FIRST_SALT_V1 = new Uint8Array([
|
|
109
|
+
64,
|
|
110
|
+
12,
|
|
111
|
+
49,
|
|
112
|
+
139,
|
|
113
|
+
102,
|
|
114
|
+
149,
|
|
115
|
+
151,
|
|
116
|
+
54,
|
|
117
|
+
89,
|
|
118
|
+
161,
|
|
119
|
+
105,
|
|
120
|
+
138,
|
|
121
|
+
229,
|
|
122
|
+
128,
|
|
123
|
+
223,
|
|
124
|
+
216,
|
|
125
|
+
0,
|
|
126
|
+
29,
|
|
127
|
+
153,
|
|
128
|
+
81,
|
|
129
|
+
186,
|
|
130
|
+
50,
|
|
131
|
+
198,
|
|
132
|
+
149,
|
|
133
|
+
230,
|
|
134
|
+
52,
|
|
135
|
+
153,
|
|
136
|
+
71,
|
|
137
|
+
80,
|
|
138
|
+
79,
|
|
139
|
+
63,
|
|
140
|
+
132
|
|
141
|
+
]);
|
|
142
|
+
var PASSKEY_PRF_SECOND_SALT_V1 = new Uint8Array([
|
|
143
|
+
38,
|
|
144
|
+
218,
|
|
145
|
+
80,
|
|
146
|
+
229,
|
|
147
|
+
172,
|
|
148
|
+
150,
|
|
149
|
+
74,
|
|
150
|
+
126,
|
|
151
|
+
160,
|
|
152
|
+
132,
|
|
153
|
+
82,
|
|
154
|
+
127,
|
|
155
|
+
182,
|
|
156
|
+
71,
|
|
157
|
+
246,
|
|
158
|
+
51,
|
|
159
|
+
11,
|
|
160
|
+
50,
|
|
161
|
+
222,
|
|
162
|
+
81,
|
|
163
|
+
169,
|
|
164
|
+
175,
|
|
165
|
+
70,
|
|
166
|
+
82,
|
|
167
|
+
75,
|
|
168
|
+
0,
|
|
169
|
+
109,
|
|
170
|
+
143,
|
|
171
|
+
127,
|
|
172
|
+
231,
|
|
173
|
+
244,
|
|
174
|
+
209
|
|
175
|
+
]);
|
|
176
|
+
|
|
177
|
+
// ../shared-ts/src/utils/normalize.ts
|
|
178
|
+
function normalizeOptionalString(value) {
|
|
179
|
+
return typeof value === "string" ? value : "";
|
|
180
|
+
}
|
|
181
|
+
function normalizeOptionalTrimmedString(value) {
|
|
182
|
+
return normalizeOptionalString(value).trim();
|
|
183
|
+
}
|
|
184
|
+
function normalizeTrimmedString(value) {
|
|
185
|
+
return String(value ?? "").trim();
|
|
186
|
+
}
|
|
187
|
+
function normalizeOptionalNonEmptyString(value) {
|
|
188
|
+
const normalized = normalizeTrimmedString(value);
|
|
189
|
+
return normalized || undefined;
|
|
190
|
+
}
|
|
191
|
+
function normalizeFiniteNumber(value) {
|
|
192
|
+
const normalized = typeof value === "number" ? value : Number(value);
|
|
193
|
+
if (!Number.isFinite(normalized))
|
|
194
|
+
return null;
|
|
195
|
+
return normalized;
|
|
196
|
+
}
|
|
197
|
+
function normalizeInteger(value) {
|
|
198
|
+
const normalized = normalizeFiniteNumber(value);
|
|
199
|
+
if (normalized == null)
|
|
200
|
+
return null;
|
|
201
|
+
return Math.trunc(normalized);
|
|
202
|
+
}
|
|
203
|
+
function normalizePositiveInteger(value) {
|
|
204
|
+
const normalized = normalizeInteger(value);
|
|
205
|
+
if (normalized == null || normalized <= 0)
|
|
206
|
+
return null;
|
|
207
|
+
return normalized;
|
|
208
|
+
}
|
|
209
|
+
function normalizeNonNegativeInteger(value) {
|
|
210
|
+
const normalized = normalizeInteger(value);
|
|
211
|
+
if (normalized == null || normalized < 0)
|
|
212
|
+
return null;
|
|
213
|
+
return normalized;
|
|
214
|
+
}
|
|
215
|
+
function stripTrailingSlashes(value) {
|
|
216
|
+
return String(value ?? "").replace(/\/+$/, "");
|
|
217
|
+
}
|
|
218
|
+
function ensureLeadingSlash(value) {
|
|
219
|
+
const trimmed = normalizeTrimmedString(value);
|
|
220
|
+
if (!trimmed)
|
|
221
|
+
return "";
|
|
222
|
+
return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
223
|
+
}
|
|
224
|
+
function joinNormalizedUrl(baseUrlRaw, pathRaw) {
|
|
225
|
+
const baseUrl = stripTrailingSlashes(normalizeTrimmedString(baseUrlRaw));
|
|
226
|
+
const path = ensureLeadingSlash(normalizeTrimmedString(pathRaw));
|
|
227
|
+
if (!baseUrl)
|
|
228
|
+
throw new Error("Missing base URL");
|
|
229
|
+
return `${baseUrl}${path}`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// src/core/walletRuntimePaths/base.ts
|
|
233
|
+
var W3A_WALLET_SDK_BASE_KEY = "__W3A_WALLET_SDK_BASE__";
|
|
234
|
+
function getEmbeddedBase() {
|
|
235
|
+
if (typeof window === "undefined")
|
|
236
|
+
return;
|
|
237
|
+
const w = window;
|
|
238
|
+
const v = w[W3A_WALLET_SDK_BASE_KEY];
|
|
239
|
+
return typeof v === "string" && v.length > 0 ? v : undefined;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// src/core/walletRuntimePaths/wasm-loader.ts
|
|
243
|
+
function getGlobalSelf() {
|
|
244
|
+
return typeof self !== "undefined" ? self ?? null : null;
|
|
245
|
+
}
|
|
246
|
+
function getGlobalLocationHref() {
|
|
247
|
+
return getGlobalSelf()?.location?.href;
|
|
248
|
+
}
|
|
249
|
+
function getGlobalLocationOrigin() {
|
|
250
|
+
return getGlobalSelf()?.location?.origin;
|
|
251
|
+
}
|
|
252
|
+
function resolveWasmUrl(wasmFilename, workerName, customBaseUrl) {
|
|
253
|
+
if (customBaseUrl) {
|
|
254
|
+
return new URL(wasmFilename, customBaseUrl);
|
|
255
|
+
}
|
|
256
|
+
if (typeof process !== "undefined" && process.env?.WASM_BASE_URL) {
|
|
257
|
+
return new URL(wasmFilename, process.env.WASM_BASE_URL);
|
|
258
|
+
}
|
|
259
|
+
const workerEnvVar = workerName.toUpperCase().replace(/[^A-Z]/g, "_") + "_WASM_BASE_URL";
|
|
260
|
+
if (typeof process !== "undefined" && process.env?.[workerEnvVar]) {
|
|
261
|
+
return new URL(wasmFilename, process.env[workerEnvVar]);
|
|
262
|
+
}
|
|
263
|
+
const globalSelf = getGlobalSelf();
|
|
264
|
+
if (globalSelf?.WASM_BASE_URL) {
|
|
265
|
+
return new URL(wasmFilename, globalSelf.WASM_BASE_URL);
|
|
266
|
+
}
|
|
267
|
+
try {
|
|
268
|
+
const embeddedBase = getEmbeddedBase();
|
|
269
|
+
if (embeddedBase) {
|
|
270
|
+
return new URL(`workers/${wasmFilename}`, embeddedBase);
|
|
271
|
+
}
|
|
272
|
+
} catch {}
|
|
273
|
+
try {
|
|
274
|
+
let metaUrl = null;
|
|
275
|
+
try {
|
|
276
|
+
metaUrl = typeof import.meta !== "undefined" && import.meta?.url ? import.meta.url : null;
|
|
277
|
+
} catch {
|
|
278
|
+
metaUrl = null;
|
|
279
|
+
}
|
|
280
|
+
if (metaUrl) {
|
|
281
|
+
const meta = new URL(metaUrl, getGlobalLocationHref());
|
|
282
|
+
if (meta.protocol === "http:" || meta.protocol === "https:") {
|
|
283
|
+
const sdkSegmentIndex = meta.pathname.indexOf("/sdk/");
|
|
284
|
+
if (sdkSegmentIndex >= 0) {
|
|
285
|
+
const sdkBasePath = meta.pathname.slice(0, sdkSegmentIndex + "/sdk/".length);
|
|
286
|
+
return new URL(`${sdkBasePath}workers/${wasmFilename}`, meta.origin);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return new URL(`./${wasmFilename}`, meta);
|
|
290
|
+
}
|
|
291
|
+
const baseUrl = getGlobalLocationHref() || "/";
|
|
292
|
+
return new URL(`./${wasmFilename}`, baseUrl);
|
|
293
|
+
} catch {
|
|
294
|
+
return new URL(`/sdk/workers/${wasmFilename}`, getGlobalLocationOrigin() || "/");
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// ../../node_modules/base-x/src/esm/index.js
|
|
299
|
+
function base(ALPHABET) {
|
|
300
|
+
if (ALPHABET.length >= 255) {
|
|
301
|
+
throw new TypeError("Alphabet too long");
|
|
302
|
+
}
|
|
303
|
+
const BASE_MAP = new Uint8Array(256);
|
|
304
|
+
for (let j = 0;j < BASE_MAP.length; j++) {
|
|
305
|
+
BASE_MAP[j] = 255;
|
|
306
|
+
}
|
|
307
|
+
for (let i = 0;i < ALPHABET.length; i++) {
|
|
308
|
+
const x = ALPHABET.charAt(i);
|
|
309
|
+
const xc = x.charCodeAt(0);
|
|
310
|
+
if (BASE_MAP[xc] !== 255) {
|
|
311
|
+
throw new TypeError(x + " is ambiguous");
|
|
312
|
+
}
|
|
313
|
+
BASE_MAP[xc] = i;
|
|
314
|
+
}
|
|
315
|
+
const BASE = ALPHABET.length;
|
|
316
|
+
const LEADER = ALPHABET.charAt(0);
|
|
317
|
+
const FACTOR = Math.log(BASE) / Math.log(256);
|
|
318
|
+
const iFACTOR = Math.log(256) / Math.log(BASE);
|
|
319
|
+
function encode(source) {
|
|
320
|
+
if (source instanceof Uint8Array) {} else if (ArrayBuffer.isView(source)) {
|
|
321
|
+
source = new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
|
|
322
|
+
} else if (Array.isArray(source)) {
|
|
323
|
+
source = Uint8Array.from(source);
|
|
324
|
+
}
|
|
325
|
+
if (!(source instanceof Uint8Array)) {
|
|
326
|
+
throw new TypeError("Expected Uint8Array");
|
|
327
|
+
}
|
|
328
|
+
if (source.length === 0) {
|
|
329
|
+
return "";
|
|
330
|
+
}
|
|
331
|
+
let zeroes = 0;
|
|
332
|
+
let length = 0;
|
|
333
|
+
let pbegin = 0;
|
|
334
|
+
const pend = source.length;
|
|
335
|
+
while (pbegin !== pend && source[pbegin] === 0) {
|
|
336
|
+
pbegin++;
|
|
337
|
+
zeroes++;
|
|
338
|
+
}
|
|
339
|
+
const size = (pend - pbegin) * iFACTOR + 1 >>> 0;
|
|
340
|
+
const b58 = new Uint8Array(size);
|
|
341
|
+
while (pbegin !== pend) {
|
|
342
|
+
let carry = source[pbegin];
|
|
343
|
+
let i = 0;
|
|
344
|
+
for (let it1 = size - 1;(carry !== 0 || i < length) && it1 !== -1; it1--, i++) {
|
|
345
|
+
carry += 256 * b58[it1] >>> 0;
|
|
346
|
+
b58[it1] = carry % BASE >>> 0;
|
|
347
|
+
carry = carry / BASE >>> 0;
|
|
348
|
+
}
|
|
349
|
+
if (carry !== 0) {
|
|
350
|
+
throw new Error("Non-zero carry");
|
|
351
|
+
}
|
|
352
|
+
length = i;
|
|
353
|
+
pbegin++;
|
|
354
|
+
}
|
|
355
|
+
let it2 = size - length;
|
|
356
|
+
while (it2 !== size && b58[it2] === 0) {
|
|
357
|
+
it2++;
|
|
358
|
+
}
|
|
359
|
+
let str = LEADER.repeat(zeroes);
|
|
360
|
+
for (;it2 < size; ++it2) {
|
|
361
|
+
str += ALPHABET.charAt(b58[it2]);
|
|
362
|
+
}
|
|
363
|
+
return str;
|
|
364
|
+
}
|
|
365
|
+
function decodeUnsafe(source) {
|
|
366
|
+
if (typeof source !== "string") {
|
|
367
|
+
throw new TypeError("Expected String");
|
|
368
|
+
}
|
|
369
|
+
if (source.length === 0) {
|
|
370
|
+
return new Uint8Array;
|
|
371
|
+
}
|
|
372
|
+
let psz = 0;
|
|
373
|
+
let zeroes = 0;
|
|
374
|
+
let length = 0;
|
|
375
|
+
while (source[psz] === LEADER) {
|
|
376
|
+
zeroes++;
|
|
377
|
+
psz++;
|
|
378
|
+
}
|
|
379
|
+
const size = (source.length - psz) * FACTOR + 1 >>> 0;
|
|
380
|
+
const b256 = new Uint8Array(size);
|
|
381
|
+
while (psz < source.length) {
|
|
382
|
+
const charCode = source.charCodeAt(psz);
|
|
383
|
+
if (charCode > 255) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
let carry = BASE_MAP[charCode];
|
|
387
|
+
if (carry === 255) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
let i = 0;
|
|
391
|
+
for (let it3 = size - 1;(carry !== 0 || i < length) && it3 !== -1; it3--, i++) {
|
|
392
|
+
carry += BASE * b256[it3] >>> 0;
|
|
393
|
+
b256[it3] = carry % 256 >>> 0;
|
|
394
|
+
carry = carry / 256 >>> 0;
|
|
395
|
+
}
|
|
396
|
+
if (carry !== 0) {
|
|
397
|
+
throw new Error("Non-zero carry");
|
|
398
|
+
}
|
|
399
|
+
length = i;
|
|
400
|
+
psz++;
|
|
401
|
+
}
|
|
402
|
+
let it4 = size - length;
|
|
403
|
+
while (it4 !== size && b256[it4] === 0) {
|
|
404
|
+
it4++;
|
|
405
|
+
}
|
|
406
|
+
const vch = new Uint8Array(zeroes + (size - it4));
|
|
407
|
+
let j = zeroes;
|
|
408
|
+
while (it4 !== size) {
|
|
409
|
+
vch[j++] = b256[it4++];
|
|
410
|
+
}
|
|
411
|
+
return vch;
|
|
412
|
+
}
|
|
413
|
+
function decode(string) {
|
|
414
|
+
const buffer = decodeUnsafe(string);
|
|
415
|
+
if (buffer) {
|
|
416
|
+
return buffer;
|
|
417
|
+
}
|
|
418
|
+
throw new Error("Non-base" + BASE + " character");
|
|
419
|
+
}
|
|
420
|
+
return {
|
|
421
|
+
encode,
|
|
422
|
+
decodeUnsafe,
|
|
423
|
+
decode
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
var esm_default = base;
|
|
427
|
+
|
|
428
|
+
// ../../node_modules/bs58/src/esm/index.js
|
|
429
|
+
var ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
430
|
+
var esm_default2 = esm_default(ALPHABET);
|
|
431
|
+
|
|
432
|
+
// ../shared-ts/src/utils/validation.ts
|
|
433
|
+
function requireTrimmedString(value, label, message = "is required") {
|
|
434
|
+
const parsed = normalizeOptionalTrimmedString(value);
|
|
435
|
+
if (!parsed)
|
|
436
|
+
throw new Error(`${label} ${message}`);
|
|
437
|
+
return parsed;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// src/core/signingEngine/workerManager/workers/shamir3pass/runtime.ts
|
|
441
|
+
var runtimeSingletonPromise = null;
|
|
442
|
+
var shamirWorkerSingleton = null;
|
|
443
|
+
var requestCounter = 0;
|
|
444
|
+
var pendingByRequestId = new Map;
|
|
445
|
+
var WORKER_REQUEST_TIMEOUT_MS = 15000;
|
|
446
|
+
function normalizeNonEmptyString(input, label) {
|
|
447
|
+
return requireTrimmedString(input, label, "must be a non-empty string");
|
|
448
|
+
}
|
|
449
|
+
function isObjectRecord(value) {
|
|
450
|
+
return typeof value === "object" && value !== null;
|
|
451
|
+
}
|
|
452
|
+
function normalizeClientKeyHandle(value) {
|
|
453
|
+
if (!isObjectRecord(value)) {
|
|
454
|
+
throw new Error("Invalid Shamir3Pass key handle response");
|
|
455
|
+
}
|
|
456
|
+
return {
|
|
457
|
+
keyHandle: normalizeNonEmptyString(value.keyHandle, "keyHandle")
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
function toWorkerError(response) {
|
|
461
|
+
const code = String(response.code || "").trim();
|
|
462
|
+
const message = normalizeNonEmptyString(response.error, "error");
|
|
463
|
+
return new Error(code ? `[shamir3pass-worker] ${code}: ${message}` : `[shamir3pass-worker] ${message}`);
|
|
464
|
+
}
|
|
465
|
+
function normalizeWorkerResponse(value) {
|
|
466
|
+
if (!isObjectRecord(value))
|
|
467
|
+
return null;
|
|
468
|
+
const id = String(value.id || "").trim();
|
|
469
|
+
if (!id || typeof value.ok !== "boolean")
|
|
470
|
+
return null;
|
|
471
|
+
if (value.ok) {
|
|
472
|
+
return { id, ok: true, result: value.result };
|
|
473
|
+
}
|
|
474
|
+
return {
|
|
475
|
+
id,
|
|
476
|
+
ok: false,
|
|
477
|
+
error: String(value.error || "Worker request failed"),
|
|
478
|
+
...String(value.code || "").trim() ? { code: String(value.code).trim() } : {}
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
function nextRequestId() {
|
|
482
|
+
requestCounter += 1;
|
|
483
|
+
return `shamir3pass-${Date.now()}-${requestCounter}`;
|
|
484
|
+
}
|
|
485
|
+
function rejectAllPending(reason) {
|
|
486
|
+
const pending = Array.from(pendingByRequestId.values());
|
|
487
|
+
pendingByRequestId.clear();
|
|
488
|
+
for (const entry of pending) {
|
|
489
|
+
clearTimeout(entry.timeoutId);
|
|
490
|
+
try {
|
|
491
|
+
entry.reject(new Error(reason));
|
|
492
|
+
} catch {}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
function resetWorker(reason) {
|
|
496
|
+
const worker = shamirWorkerSingleton;
|
|
497
|
+
shamirWorkerSingleton = null;
|
|
498
|
+
if (worker) {
|
|
499
|
+
try {
|
|
500
|
+
worker.terminate();
|
|
501
|
+
} catch {}
|
|
502
|
+
}
|
|
503
|
+
rejectAllPending(reason);
|
|
504
|
+
}
|
|
505
|
+
function resolveWorkerConstructor() {
|
|
506
|
+
const workerCtor = globalThis.Worker;
|
|
507
|
+
if (typeof workerCtor !== "function") {
|
|
508
|
+
throw new Error("Shamir3Pass worker is unavailable in this runtime");
|
|
509
|
+
}
|
|
510
|
+
return workerCtor;
|
|
511
|
+
}
|
|
512
|
+
function getOrCreateShamirWorker() {
|
|
513
|
+
if (shamirWorkerSingleton)
|
|
514
|
+
return shamirWorkerSingleton;
|
|
515
|
+
const WorkerCtor = resolveWorkerConstructor();
|
|
516
|
+
const workerUrl = resolveWasmUrl("shamir3pass.worker.js", "Shamir3Pass Worker");
|
|
517
|
+
const worker = new WorkerCtor(workerUrl, { type: "module", name: "shamir3pass-worker" });
|
|
518
|
+
worker.onmessage = (event) => {
|
|
519
|
+
const parsed = normalizeWorkerResponse(event.data);
|
|
520
|
+
if (!parsed)
|
|
521
|
+
return;
|
|
522
|
+
const pending = pendingByRequestId.get(parsed.id);
|
|
523
|
+
if (!pending)
|
|
524
|
+
return;
|
|
525
|
+
pendingByRequestId.delete(parsed.id);
|
|
526
|
+
clearTimeout(pending.timeoutId);
|
|
527
|
+
if (parsed.ok) {
|
|
528
|
+
pending.resolve(parsed.result);
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
pending.reject(toWorkerError(parsed));
|
|
532
|
+
};
|
|
533
|
+
worker.onerror = (event) => {
|
|
534
|
+
const message = String(event?.message || "Unknown worker error").trim();
|
|
535
|
+
resetWorker(`[shamir3pass-worker] ${message || "Worker crashed"}`);
|
|
536
|
+
};
|
|
537
|
+
worker.onmessageerror = () => {
|
|
538
|
+
resetWorker("[shamir3pass-worker] Failed to deserialize worker message");
|
|
539
|
+
};
|
|
540
|
+
shamirWorkerSingleton = worker;
|
|
541
|
+
return worker;
|
|
542
|
+
}
|
|
543
|
+
function sendWorkerRequest(type, payload, transfer) {
|
|
544
|
+
const requestId = nextRequestId();
|
|
545
|
+
const worker = getOrCreateShamirWorker();
|
|
546
|
+
return new Promise((resolve, reject) => {
|
|
547
|
+
const timeoutId = setTimeout(() => {
|
|
548
|
+
pendingByRequestId.delete(requestId);
|
|
549
|
+
reject(new Error(`[shamir3pass-worker] Request timed out after ${WORKER_REQUEST_TIMEOUT_MS}ms`));
|
|
550
|
+
}, WORKER_REQUEST_TIMEOUT_MS);
|
|
551
|
+
pendingByRequestId.set(requestId, {
|
|
552
|
+
resolve,
|
|
553
|
+
reject,
|
|
554
|
+
timeoutId
|
|
555
|
+
});
|
|
556
|
+
const request = {
|
|
557
|
+
id: requestId,
|
|
558
|
+
type,
|
|
559
|
+
payload
|
|
560
|
+
};
|
|
561
|
+
try {
|
|
562
|
+
worker.postMessage(request, transfer || []);
|
|
563
|
+
} catch (error) {
|
|
564
|
+
const pending = pendingByRequestId.get(requestId);
|
|
565
|
+
if (pending) {
|
|
566
|
+
pendingByRequestId.delete(requestId);
|
|
567
|
+
clearTimeout(pending.timeoutId);
|
|
568
|
+
}
|
|
569
|
+
reject(error instanceof Error ? error : new Error(String(error || "Worker postMessage failed")));
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
function createShamir3PassRuntime() {
|
|
574
|
+
return {
|
|
575
|
+
createClientKeyHandle: async ({ groupId }) => normalizeClientKeyHandle(await sendWorkerRequest("createClientKeyHandle", {
|
|
576
|
+
groupId
|
|
577
|
+
})),
|
|
578
|
+
destroyClientKeyHandle: async ({ keyHandle }) => {
|
|
579
|
+
await sendWorkerRequest("destroyClientKeyHandle", {
|
|
580
|
+
keyHandle
|
|
581
|
+
});
|
|
582
|
+
},
|
|
583
|
+
addClientSealWithKeyHandle: async ({ ciphertextB64u, keyHandle }) => normalizeNonEmptyString(await sendWorkerRequest("addClientSealWithKeyHandle", {
|
|
584
|
+
ciphertextB64u,
|
|
585
|
+
keyHandle
|
|
586
|
+
}), "ciphertextB64u"),
|
|
587
|
+
addClientSealBytesWithKeyHandle: async ({ ciphertext, keyHandle }) => {
|
|
588
|
+
const ciphertextCopy = ciphertext.slice();
|
|
589
|
+
return normalizeNonEmptyString(await sendWorkerRequest("addClientSealBytesWithKeyHandle", {
|
|
590
|
+
ciphertext: ciphertextCopy.buffer,
|
|
591
|
+
keyHandle
|
|
592
|
+
}, [ciphertextCopy.buffer]), "ciphertextB64u");
|
|
593
|
+
},
|
|
594
|
+
removeClientSealWithKeyHandle: async ({ ciphertextB64u, keyHandle }) => normalizeNonEmptyString(await sendWorkerRequest("removeClientSealWithKeyHandle", {
|
|
595
|
+
ciphertextB64u,
|
|
596
|
+
keyHandle
|
|
597
|
+
}), "ciphertextB64u"),
|
|
598
|
+
removeClientSealWithKeyHandleToBytes: async ({ ciphertextB64u, keyHandle }) => {
|
|
599
|
+
const result = await sendWorkerRequest("removeClientSealWithKeyHandleToBytes", {
|
|
600
|
+
ciphertextB64u,
|
|
601
|
+
keyHandle
|
|
602
|
+
});
|
|
603
|
+
if (!(result instanceof ArrayBuffer)) {
|
|
604
|
+
throw new Error("ciphertext bytes response must be an ArrayBuffer");
|
|
605
|
+
}
|
|
606
|
+
return new Uint8Array(result);
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
async function warmupShamir3PassRuntime() {
|
|
611
|
+
const startedAt = performance.now();
|
|
612
|
+
try {
|
|
613
|
+
await sendWorkerRequest("warmup", {});
|
|
614
|
+
return { kind: "succeeded", elapsedMs: Math.max(0, Math.round(performance.now() - startedAt)) };
|
|
615
|
+
} catch {
|
|
616
|
+
return { kind: "failed", elapsedMs: Math.max(0, Math.round(performance.now() - startedAt)) };
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
async function getShamir3PassRuntime() {
|
|
620
|
+
if (!runtimeSingletonPromise) {
|
|
621
|
+
runtimeSingletonPromise = Promise.resolve(createShamir3PassRuntime()).catch((error) => {
|
|
622
|
+
runtimeSingletonPromise = null;
|
|
623
|
+
throw error;
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
return runtimeSingletonPromise;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// src/core/signingEngine/workerManager/workers/passkey-mpc-session.worker.ts
|
|
630
|
+
var PASSKEY_SERVER_SEALED_SECRET_CACHE_MAX_ENTRIES = 32;
|
|
631
|
+
var warmSessionPrfHandleCache = new Map;
|
|
632
|
+
var passkeyPrfFirstHandleStore = new Map;
|
|
633
|
+
var passkeyServerSealedSecretCache = new Map;
|
|
634
|
+
var signingSessionSealApplyInFlight = new Map;
|
|
635
|
+
var signingSessionSealRemoveInFlight = new Map;
|
|
636
|
+
var SIGNING_SESSION_SEAL_BASE_PATH = WALLET_SESSION_SEAL_BASE_PATH;
|
|
637
|
+
var SIGNING_SESSION_SEAL_ROUTE_TIMEOUT_MS = 15000;
|
|
638
|
+
function abortSigningSessionSealRoute(controller) {
|
|
639
|
+
controller.abort("timeout");
|
|
640
|
+
}
|
|
641
|
+
function parseSessionMessageId(value) {
|
|
642
|
+
return typeof value === "string" ? normalizeOptionalTrimmedString(value) || undefined : undefined;
|
|
643
|
+
}
|
|
644
|
+
function parseSessionString(value) {
|
|
645
|
+
if (typeof value !== "string")
|
|
646
|
+
return null;
|
|
647
|
+
return normalizeOptionalTrimmedString(value) || null;
|
|
648
|
+
}
|
|
649
|
+
function parseSessionInteger(value) {
|
|
650
|
+
return typeof value === "number" && Number.isSafeInteger(value) ? value : null;
|
|
651
|
+
}
|
|
652
|
+
function parseSessionStringArray(value) {
|
|
653
|
+
if (!Array.isArray(value))
|
|
654
|
+
return null;
|
|
655
|
+
const keys = Object.keys(value);
|
|
656
|
+
if (keys.length !== value.length || keys.some((key) => !/^\d+$/.test(key)))
|
|
657
|
+
return null;
|
|
658
|
+
const output = [];
|
|
659
|
+
for (let index = 0;index < value.length; index += 1) {
|
|
660
|
+
const parsed = parseSessionString(value[index]);
|
|
661
|
+
if (!parsed)
|
|
662
|
+
return null;
|
|
663
|
+
output.push(parsed);
|
|
664
|
+
}
|
|
665
|
+
return output;
|
|
666
|
+
}
|
|
667
|
+
function parseWarmSessionMaterialPutPayload(value) {
|
|
668
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
669
|
+
return null;
|
|
670
|
+
const fields = Object.keys(value);
|
|
671
|
+
if (fields.some((field) => ![
|
|
672
|
+
"thresholdSessionId",
|
|
673
|
+
"prfFirstB64u",
|
|
674
|
+
"expiresAtMs",
|
|
675
|
+
"remainingUses",
|
|
676
|
+
"transport"
|
|
677
|
+
].includes(field)) || !["thresholdSessionId", "prfFirstB64u", "expiresAtMs", "remainingUses"].every((field) => fields.includes(field))) {
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
680
|
+
const thresholdSessionId = parseSessionString(Reflect.get(value, "thresholdSessionId"));
|
|
681
|
+
const prfFirstB64u = parseSessionString(Reflect.get(value, "prfFirstB64u"));
|
|
682
|
+
const expiresAtMs = parseSessionInteger(Reflect.get(value, "expiresAtMs"));
|
|
683
|
+
const remainingUses = parseSessionInteger(Reflect.get(value, "remainingUses"));
|
|
684
|
+
const hasTransport = fields.includes("transport");
|
|
685
|
+
const transport = hasTransport ? parseSigningSessionSealTransport(Reflect.get(value, "transport")) : undefined;
|
|
686
|
+
if (!thresholdSessionId || !prfFirstB64u || expiresAtMs === null || remainingUses === null || hasTransport && !transport) {
|
|
687
|
+
return null;
|
|
688
|
+
}
|
|
689
|
+
return {
|
|
690
|
+
thresholdSessionId,
|
|
691
|
+
prfFirstB64u,
|
|
692
|
+
expiresAtMs,
|
|
693
|
+
remainingUses,
|
|
694
|
+
...transport ? { transport } : {}
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
function parseWarmSessionStatusReadPayload(value) {
|
|
698
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
699
|
+
return null;
|
|
700
|
+
const fields = Object.keys(value);
|
|
701
|
+
if (fields.length !== 1 || fields[0] !== "thresholdSessionId")
|
|
702
|
+
return null;
|
|
703
|
+
const thresholdSessionId = parseSessionString(Reflect.get(value, "thresholdSessionId"));
|
|
704
|
+
return thresholdSessionId ? { thresholdSessionId } : null;
|
|
705
|
+
}
|
|
706
|
+
function parseWarmSessionStatusBatchReadPayload(value) {
|
|
707
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
708
|
+
return null;
|
|
709
|
+
const fields = Object.keys(value);
|
|
710
|
+
if (fields.length !== 1 || fields[0] !== "thresholdSessionIds")
|
|
711
|
+
return null;
|
|
712
|
+
const thresholdSessionIds = parseSessionStringArray(Reflect.get(value, "thresholdSessionIds"));
|
|
713
|
+
return thresholdSessionIds ? { thresholdSessionIds } : null;
|
|
714
|
+
}
|
|
715
|
+
function parseWarmSessionMaterialClaimPayload(value) {
|
|
716
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
717
|
+
return null;
|
|
718
|
+
const fields = Object.keys(value);
|
|
719
|
+
if (fields.some((field) => !["thresholdSessionId", "uses", "consume", "curve"].includes(field)) || !fields.includes("thresholdSessionId")) {
|
|
720
|
+
return null;
|
|
721
|
+
}
|
|
722
|
+
const thresholdSessionId = parseSessionString(Reflect.get(value, "thresholdSessionId"));
|
|
723
|
+
const hasUses = fields.includes("uses");
|
|
724
|
+
const uses = hasUses ? parseSessionInteger(Reflect.get(value, "uses")) : 1;
|
|
725
|
+
const hasConsume = fields.includes("consume");
|
|
726
|
+
const consume = hasConsume ? Reflect.get(value, "consume") : true;
|
|
727
|
+
const hasCurve = fields.includes("curve");
|
|
728
|
+
const curve = hasCurve ? Reflect.get(value, "curve") : undefined;
|
|
729
|
+
if (!thresholdSessionId || uses === null || uses < 1 || typeof consume !== "boolean" || curve !== undefined && curve !== "ed25519" && curve !== "ecdsa") {
|
|
730
|
+
return null;
|
|
731
|
+
}
|
|
732
|
+
return {
|
|
733
|
+
thresholdSessionId,
|
|
734
|
+
uses,
|
|
735
|
+
consume,
|
|
736
|
+
...curve !== undefined ? { curve } : {}
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
function parseWarmSessionMaterialConsumePayload(value) {
|
|
740
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
741
|
+
return null;
|
|
742
|
+
const fields = Object.keys(value);
|
|
743
|
+
if (fields.some((field) => !["thresholdSessionId", "uses", "curve"].includes(field)) || !fields.includes("thresholdSessionId")) {
|
|
744
|
+
return null;
|
|
745
|
+
}
|
|
746
|
+
const thresholdSessionId = parseSessionString(Reflect.get(value, "thresholdSessionId"));
|
|
747
|
+
const hasUses = fields.includes("uses");
|
|
748
|
+
const uses = hasUses ? parseSessionInteger(Reflect.get(value, "uses")) : 1;
|
|
749
|
+
const hasCurve = fields.includes("curve");
|
|
750
|
+
const curve = hasCurve ? Reflect.get(value, "curve") : undefined;
|
|
751
|
+
if (!thresholdSessionId || uses === null || uses < 1 || curve !== undefined && curve !== "ed25519" && curve !== "ecdsa") {
|
|
752
|
+
return null;
|
|
753
|
+
}
|
|
754
|
+
return {
|
|
755
|
+
thresholdSessionId,
|
|
756
|
+
uses,
|
|
757
|
+
...curve !== undefined ? { curve } : {}
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
function parseWarmSessionSealAndPersistPayload(value) {
|
|
761
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
762
|
+
return null;
|
|
763
|
+
const fields = Object.keys(value);
|
|
764
|
+
if (fields.length !== 2 || !fields.includes("thresholdSessionId") || !fields.includes("transport")) {
|
|
765
|
+
return null;
|
|
766
|
+
}
|
|
767
|
+
const thresholdSessionId = parseSessionString(Reflect.get(value, "thresholdSessionId"));
|
|
768
|
+
const transport = parseSigningSessionSealTransport(Reflect.get(value, "transport"));
|
|
769
|
+
return thresholdSessionId && transport ? { thresholdSessionId, transport } : null;
|
|
770
|
+
}
|
|
771
|
+
function parseWarmSessionRehydratePayload(value) {
|
|
772
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
773
|
+
return null;
|
|
774
|
+
const fields = Object.keys(value);
|
|
775
|
+
const requiredFields = [
|
|
776
|
+
"thresholdSessionId",
|
|
777
|
+
"sealedSecretB64u",
|
|
778
|
+
"expiresAtMs",
|
|
779
|
+
"remainingUses",
|
|
780
|
+
"transport"
|
|
781
|
+
];
|
|
782
|
+
if (fields.some((field) => ![...requiredFields, "signingSessionSealKeyVersion"].includes(field)) || requiredFields.some((field) => !fields.includes(field))) {
|
|
783
|
+
return null;
|
|
784
|
+
}
|
|
785
|
+
const thresholdSessionId = parseSessionString(Reflect.get(value, "thresholdSessionId"));
|
|
786
|
+
const sealedSecretB64u = parseSessionString(Reflect.get(value, "sealedSecretB64u"));
|
|
787
|
+
const expiresAtMs = parseSessionInteger(Reflect.get(value, "expiresAtMs"));
|
|
788
|
+
const remainingUses = parseSessionInteger(Reflect.get(value, "remainingUses"));
|
|
789
|
+
const transport = parseSigningSessionSealTransport(Reflect.get(value, "transport"));
|
|
790
|
+
const hasKeyVersion = fields.includes("signingSessionSealKeyVersion");
|
|
791
|
+
const keyVersion = hasKeyVersion ? parseSessionString(Reflect.get(value, "signingSessionSealKeyVersion")) : undefined;
|
|
792
|
+
if (!thresholdSessionId || !sealedSecretB64u || expiresAtMs === null || remainingUses === null || !transport || hasKeyVersion && !keyVersion) {
|
|
793
|
+
return null;
|
|
794
|
+
}
|
|
795
|
+
return {
|
|
796
|
+
thresholdSessionId,
|
|
797
|
+
sealedSecretB64u,
|
|
798
|
+
expiresAtMs,
|
|
799
|
+
remainingUses,
|
|
800
|
+
...keyVersion ? { keyVersion } : {},
|
|
801
|
+
transport
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
function parsePasskeyMpcSessionWorkerMessage(value) {
|
|
805
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
806
|
+
return { kind: "unknown", type: undefined };
|
|
807
|
+
}
|
|
808
|
+
const fields = Object.keys(value);
|
|
809
|
+
if (fields.some((field) => !["id", "type", "payload"].includes(field)) || !fields.includes("type")) {
|
|
810
|
+
return { kind: "unknown", type: Reflect.get(value, "type") };
|
|
811
|
+
}
|
|
812
|
+
const id = fields.includes("id") ? parseSessionMessageId(Reflect.get(value, "id")) : undefined;
|
|
813
|
+
if (fields.includes("id") && id === undefined) {
|
|
814
|
+
return { kind: "unknown", type: Reflect.get(value, "type") };
|
|
815
|
+
}
|
|
816
|
+
const type = Reflect.get(value, "type");
|
|
817
|
+
const hasPayload = fields.includes("payload");
|
|
818
|
+
const payload = hasPayload ? Reflect.get(value, "payload") : undefined;
|
|
819
|
+
switch (type) {
|
|
820
|
+
case "PING":
|
|
821
|
+
return fields.length === (fields.includes("id") ? 2 : 1) ? { kind: "ping", ...id ? { id } : {} } : { kind: "unknown", id, type };
|
|
822
|
+
case "PREWARM_SHAMIR3PASS":
|
|
823
|
+
if (!hasPayload || payload === null || typeof payload !== "object" || Array.isArray(payload)) {
|
|
824
|
+
return { kind: "unknown", id, type };
|
|
825
|
+
}
|
|
826
|
+
if (Object.keys(payload).length !== 0)
|
|
827
|
+
return { kind: "unknown", id, type };
|
|
828
|
+
return { kind: "prewarm", ...id ? { id } : {} };
|
|
829
|
+
case "WARM_SESSION_MATERIAL_PUT":
|
|
830
|
+
return {
|
|
831
|
+
kind: "material_put",
|
|
832
|
+
...id ? { id } : {},
|
|
833
|
+
payload: hasPayload ? parseWarmSessionMaterialPutPayload(payload) : null
|
|
834
|
+
};
|
|
835
|
+
case "WARM_SESSION_STATUS_READ":
|
|
836
|
+
return {
|
|
837
|
+
kind: "status_read",
|
|
838
|
+
...id ? { id } : {},
|
|
839
|
+
payload: hasPayload ? parseWarmSessionStatusReadPayload(payload) : null
|
|
840
|
+
};
|
|
841
|
+
case "WARM_SESSION_STATUS_BATCH_READ":
|
|
842
|
+
return {
|
|
843
|
+
kind: "status_batch_read",
|
|
844
|
+
...id ? { id } : {},
|
|
845
|
+
payload: hasPayload ? parseWarmSessionStatusBatchReadPayload(payload) : null
|
|
846
|
+
};
|
|
847
|
+
case "WARM_SESSION_MATERIAL_CLAIM":
|
|
848
|
+
return {
|
|
849
|
+
kind: "material_claim",
|
|
850
|
+
...id ? { id } : {},
|
|
851
|
+
payload: hasPayload ? parseWarmSessionMaterialClaimPayload(payload) : null
|
|
852
|
+
};
|
|
853
|
+
case "WARM_SESSION_MATERIAL_CONSUME":
|
|
854
|
+
return {
|
|
855
|
+
kind: "material_consume",
|
|
856
|
+
...id ? { id } : {},
|
|
857
|
+
payload: hasPayload ? parseWarmSessionMaterialConsumePayload(payload) : null
|
|
858
|
+
};
|
|
859
|
+
case "WARM_SESSION_VOLATILE_MATERIAL_CLEAR":
|
|
860
|
+
return hasPayload ? { kind: "volatile_clear", ...id ? { id } : {}, payload } : { kind: "unknown", id, type };
|
|
861
|
+
case "WARM_SESSION_VOLATILE_MATERIAL_CLEAR_ALL":
|
|
862
|
+
return hasPayload ? { kind: "volatile_clear_all", ...id ? { id } : {}, payload } : { kind: "unknown", id, type };
|
|
863
|
+
case "WARM_SESSION_SEAL_AND_PERSIST":
|
|
864
|
+
return {
|
|
865
|
+
kind: "seal_and_persist",
|
|
866
|
+
...id ? { id } : {},
|
|
867
|
+
payload: hasPayload ? parseWarmSessionSealAndPersistPayload(payload) : null
|
|
868
|
+
};
|
|
869
|
+
case "WARM_SESSION_REHYDRATE":
|
|
870
|
+
return {
|
|
871
|
+
kind: "rehydrate",
|
|
872
|
+
...id ? { id } : {},
|
|
873
|
+
payload: hasPayload ? parseWarmSessionRehydratePayload(payload) : null
|
|
874
|
+
};
|
|
875
|
+
default:
|
|
876
|
+
return { kind: "unknown", id, type };
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
function nowMs() {
|
|
880
|
+
return Date.now();
|
|
881
|
+
}
|
|
882
|
+
function roundWorkerDurationMs(startedAt) {
|
|
883
|
+
return Math.max(0, Math.round(performance.now() - startedAt));
|
|
884
|
+
}
|
|
885
|
+
function createWarmSessionSealAndPersistDiagnostics() {
|
|
886
|
+
return {
|
|
887
|
+
runtimeSetupMs: 0,
|
|
888
|
+
clientSealMs: 0,
|
|
889
|
+
serverSealRouteMs: 0,
|
|
890
|
+
clientUnsealMs: 0,
|
|
891
|
+
policyUpdateMs: 0
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
function recordWarmSessionSealAndPersistDiagnosticDuration(args) {
|
|
895
|
+
args.diagnostics[args.bucket] += roundWorkerDurationMs(args.startedAt);
|
|
896
|
+
}
|
|
897
|
+
function toSessionId(prefix) {
|
|
898
|
+
const value = String(prefix || "").trim() || "session";
|
|
899
|
+
return `${value}:${secureRandomBase64Url(32, "passkey confirm worker session IDs")}`;
|
|
900
|
+
}
|
|
901
|
+
function createPasskeyPrfFirstHandle(args) {
|
|
902
|
+
const prfFirstB64u = normalizeOptionalTrimmedString(args.prfFirstB64u);
|
|
903
|
+
const expiresAtMs = Math.floor(Number(args.expiresAtMs) || 0);
|
|
904
|
+
if (!prfFirstB64u || expiresAtMs <= nowMs()) {
|
|
905
|
+
throw new Error("Invalid passkey PRF material handle input");
|
|
906
|
+
}
|
|
907
|
+
const prfFirstHandle = toSessionId("passkey-prf-first");
|
|
908
|
+
passkeyPrfFirstHandleStore.set(prfFirstHandle, {
|
|
909
|
+
prfFirstB64u,
|
|
910
|
+
expiresAtMs
|
|
911
|
+
});
|
|
912
|
+
return prfFirstHandle;
|
|
913
|
+
}
|
|
914
|
+
async function sha256HexUtf8(value) {
|
|
915
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
|
|
916
|
+
return bytesToHex(new Uint8Array(digest));
|
|
917
|
+
}
|
|
918
|
+
async function passkeyServerSealedSecretCacheKey(args) {
|
|
919
|
+
const prfFirstB64u = normalizeOptionalTrimmedString(args.prfFirstB64u);
|
|
920
|
+
const relayerUrl = normalizeOptionalTrimmedString(args.relayerUrl);
|
|
921
|
+
const keyVersion = normalizeOptionalNonEmptyString(args.keyVersion);
|
|
922
|
+
const cacheScope = args.cacheScope;
|
|
923
|
+
if (!prfFirstB64u || !relayerUrl || !keyVersion || !cacheScope)
|
|
924
|
+
return null;
|
|
925
|
+
const prfDigestHex = await sha256HexUtf8(prfFirstB64u);
|
|
926
|
+
return [
|
|
927
|
+
"passkey-server-sealed-secret-v1",
|
|
928
|
+
relayerUrl,
|
|
929
|
+
keyVersion,
|
|
930
|
+
SIGNING_SESSION_SEAL_GROUP_ID,
|
|
931
|
+
cacheScope.walletId,
|
|
932
|
+
cacheScope.credentialIdB64u,
|
|
933
|
+
cacheScope.walletSessionId,
|
|
934
|
+
cacheScope.quotaId,
|
|
935
|
+
prfDigestHex
|
|
936
|
+
].join("|");
|
|
937
|
+
}
|
|
938
|
+
function prunePasskeyServerSealedSecretCache() {
|
|
939
|
+
const now = nowMs();
|
|
940
|
+
for (const [key, entry] of passkeyServerSealedSecretCache) {
|
|
941
|
+
if (entry.expiresAtMs <= now)
|
|
942
|
+
passkeyServerSealedSecretCache.delete(key);
|
|
943
|
+
}
|
|
944
|
+
while (passkeyServerSealedSecretCache.size > PASSKEY_SERVER_SEALED_SECRET_CACHE_MAX_ENTRIES) {
|
|
945
|
+
const firstKey = passkeyServerSealedSecretCache.keys().next().value;
|
|
946
|
+
if (typeof firstKey !== "string")
|
|
947
|
+
return;
|
|
948
|
+
passkeyServerSealedSecretCache.delete(firstKey);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
function readPasskeyServerSealedSecretCache(cacheKey) {
|
|
952
|
+
if (!cacheKey)
|
|
953
|
+
return null;
|
|
954
|
+
prunePasskeyServerSealedSecretCache();
|
|
955
|
+
const entry = passkeyServerSealedSecretCache.get(cacheKey);
|
|
956
|
+
if (!entry || entry.expiresAtMs <= nowMs()) {
|
|
957
|
+
if (entry)
|
|
958
|
+
passkeyServerSealedSecretCache.delete(cacheKey);
|
|
959
|
+
return null;
|
|
960
|
+
}
|
|
961
|
+
return entry;
|
|
962
|
+
}
|
|
963
|
+
function writePasskeyServerSealedSecretCache(args) {
|
|
964
|
+
if (!args.cacheKey)
|
|
965
|
+
return;
|
|
966
|
+
const sealedSecretB64u = normalizeOptionalTrimmedString(args.sealedSecretB64u);
|
|
967
|
+
const expiresAtMs = Math.floor(Number(args.expiresAtMs) || 0);
|
|
968
|
+
if (!sealedSecretB64u || expiresAtMs <= nowMs())
|
|
969
|
+
return;
|
|
970
|
+
passkeyServerSealedSecretCache.set(args.cacheKey, { sealedSecretB64u, expiresAtMs });
|
|
971
|
+
prunePasskeyServerSealedSecretCache();
|
|
972
|
+
}
|
|
973
|
+
function deleteWarmSessionPrfHandle(thresholdSessionId) {
|
|
974
|
+
const entry = warmSessionPrfHandleCache.get(thresholdSessionId);
|
|
975
|
+
if (entry)
|
|
976
|
+
passkeyPrfFirstHandleStore.delete(entry.prfFirstHandle);
|
|
977
|
+
warmSessionPrfHandleCache.delete(thresholdSessionId);
|
|
978
|
+
}
|
|
979
|
+
function clearWarmSessionPrfHandles() {
|
|
980
|
+
warmSessionPrfHandleCache.clear();
|
|
981
|
+
passkeyPrfFirstHandleStore.clear();
|
|
982
|
+
passkeyServerSealedSecretCache.clear();
|
|
983
|
+
}
|
|
984
|
+
function storeWarmSessionPrfHandle(args) {
|
|
985
|
+
const thresholdSessionId = normalizeOptionalTrimmedString(args.thresholdSessionId);
|
|
986
|
+
const remainingUses = Math.floor(Number(args.remainingUses) || 0);
|
|
987
|
+
const expiresAtMs = Math.floor(Number(args.expiresAtMs) || 0);
|
|
988
|
+
if (!thresholdSessionId || remainingUses <= 0 || expiresAtMs <= nowMs()) {
|
|
989
|
+
throw new Error("Invalid warm-session PRF handle input");
|
|
990
|
+
}
|
|
991
|
+
deleteWarmSessionPrfHandle(thresholdSessionId);
|
|
992
|
+
const prfFirstHandle = createPasskeyPrfFirstHandle({
|
|
993
|
+
prfFirstB64u: args.prfFirstB64u,
|
|
994
|
+
expiresAtMs
|
|
995
|
+
});
|
|
996
|
+
const entry = { prfFirstHandle, expiresAtMs, remainingUses };
|
|
997
|
+
warmSessionPrfHandleCache.set(thresholdSessionId, entry);
|
|
998
|
+
return entry;
|
|
999
|
+
}
|
|
1000
|
+
function updateWarmSessionPrfHandlePolicy(thresholdSessionId, entry, policy) {
|
|
1001
|
+
const nextEntry = {
|
|
1002
|
+
prfFirstHandle: entry.prfFirstHandle,
|
|
1003
|
+
remainingUses: policy.remainingUses,
|
|
1004
|
+
expiresAtMs: policy.expiresAtMs
|
|
1005
|
+
};
|
|
1006
|
+
const secret = passkeyPrfFirstHandleStore.get(entry.prfFirstHandle);
|
|
1007
|
+
if (secret) {
|
|
1008
|
+
passkeyPrfFirstHandleStore.set(entry.prfFirstHandle, {
|
|
1009
|
+
prfFirstB64u: secret.prfFirstB64u,
|
|
1010
|
+
expiresAtMs: policy.expiresAtMs
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
warmSessionPrfHandleCache.set(thresholdSessionId, nextEntry);
|
|
1014
|
+
return nextEntry;
|
|
1015
|
+
}
|
|
1016
|
+
function parseSigningSessionSealTransport(value) {
|
|
1017
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
1018
|
+
return null;
|
|
1019
|
+
const curve = Reflect.get(value, "curve");
|
|
1020
|
+
const authMethod = Reflect.get(value, "authMethod");
|
|
1021
|
+
const requiredFields = curve === "ed25519" ? ["curve", "authMethod", "walletId", "relayerUrl", "walletSessionToken", "ed25519Restore"] : curve === "ecdsa" ? [
|
|
1022
|
+
"curve",
|
|
1023
|
+
"authMethod",
|
|
1024
|
+
"walletId",
|
|
1025
|
+
"chainTarget",
|
|
1026
|
+
"relayerUrl",
|
|
1027
|
+
"walletSessionToken",
|
|
1028
|
+
"ecdsaRestore"
|
|
1029
|
+
] : [];
|
|
1030
|
+
const optionalFields = [
|
|
1031
|
+
"signingSessionSealKeyVersion",
|
|
1032
|
+
"groupId",
|
|
1033
|
+
"serverSealedSecretCacheScope"
|
|
1034
|
+
];
|
|
1035
|
+
const fields = Object.keys(value);
|
|
1036
|
+
if (curve !== "ed25519" && curve !== "ecdsa" || authMethod !== "passkey" || fields.some((field) => ![...requiredFields, ...optionalFields].includes(field)) || requiredFields.some((field) => !fields.includes(field))) {
|
|
1037
|
+
return null;
|
|
1038
|
+
}
|
|
1039
|
+
const walletId = parseSessionString(Reflect.get(value, "walletId"));
|
|
1040
|
+
const relayerUrl = normalizeOptionalNonEmptyString(Reflect.get(value, "relayerUrl"));
|
|
1041
|
+
const walletSessionToken = normalizeOptionalNonEmptyString(Reflect.get(value, "walletSessionToken"));
|
|
1042
|
+
const restore = Reflect.get(value, curve === "ed25519" ? "ed25519Restore" : "ecdsaRestore");
|
|
1043
|
+
const chainTarget = curve === "ecdsa" ? Reflect.get(value, "chainTarget") : undefined;
|
|
1044
|
+
const rawKeyVersion = Reflect.get(value, "signingSessionSealKeyVersion");
|
|
1045
|
+
const hasKeyVersion = fields.includes("signingSessionSealKeyVersion");
|
|
1046
|
+
const keyVersion = normalizeOptionalNonEmptyString(rawKeyVersion);
|
|
1047
|
+
const hasCacheScope = fields.includes("serverSealedSecretCacheScope");
|
|
1048
|
+
const serverSealedSecretCacheScope = parsePasskeyServerSealedSecretCacheScope(Reflect.get(value, "serverSealedSecretCacheScope"));
|
|
1049
|
+
if (!walletId || !relayerUrl || !walletSessionToken || restore === null || typeof restore !== "object" || Array.isArray(restore) || curve === "ecdsa" && (chainTarget === null || typeof chainTarget !== "object" || Array.isArray(chainTarget)) || hasKeyVersion && !keyVersion || hasCacheScope && !serverSealedSecretCacheScope) {
|
|
1050
|
+
return null;
|
|
1051
|
+
}
|
|
1052
|
+
return {
|
|
1053
|
+
relayerUrl,
|
|
1054
|
+
walletSessionToken,
|
|
1055
|
+
...hasKeyVersion && keyVersion ? { keyVersion } : {},
|
|
1056
|
+
...serverSealedSecretCacheScope ? { serverSealedSecretCacheScope } : {}
|
|
1057
|
+
};
|
|
1058
|
+
}
|
|
1059
|
+
function parsePasskeyServerSealedSecretCacheScope(value) {
|
|
1060
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
1061
|
+
return;
|
|
1062
|
+
const fields = Object.keys(value);
|
|
1063
|
+
if (fields.length !== 5 || !["kind", "walletId", "credentialIdB64u", "walletSessionId", "quotaId"].every((field) => fields.includes(field)) || Reflect.get(value, "kind") !== "passkey_registration") {
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
const walletId = normalizeOptionalNonEmptyString(Reflect.get(value, "walletId"));
|
|
1067
|
+
const credentialIdB64u = normalizeOptionalNonEmptyString(Reflect.get(value, "credentialIdB64u"));
|
|
1068
|
+
const walletSessionId = normalizeOptionalNonEmptyString(Reflect.get(value, "walletSessionId"));
|
|
1069
|
+
const quotaId = normalizeOptionalNonEmptyString(Reflect.get(value, "quotaId"));
|
|
1070
|
+
if (!walletId || !credentialIdB64u || !walletSessionId || !quotaId)
|
|
1071
|
+
return;
|
|
1072
|
+
return {
|
|
1073
|
+
kind: "passkey_registration",
|
|
1074
|
+
walletId,
|
|
1075
|
+
credentialIdB64u,
|
|
1076
|
+
walletSessionId,
|
|
1077
|
+
quotaId
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
function parseSigningSessionSealRouteResult(value) {
|
|
1081
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
1082
|
+
return {
|
|
1083
|
+
ok: false,
|
|
1084
|
+
code: "invalid_response",
|
|
1085
|
+
message: "Invalid signing-session seal response"
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
const ok = Reflect.get(value, "ok");
|
|
1089
|
+
if (typeof ok !== "boolean") {
|
|
1090
|
+
return {
|
|
1091
|
+
ok: false,
|
|
1092
|
+
code: "invalid_response",
|
|
1093
|
+
message: "Invalid signing-session seal response"
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
const fields = Object.keys(value);
|
|
1097
|
+
const allowedFields = ok ? ["ok", "ciphertext", "keyVersion", "expiresAtMs", "remainingUses"] : ["ok", "code", "message"];
|
|
1098
|
+
if (fields.some((field) => !allowedFields.includes(field))) {
|
|
1099
|
+
return {
|
|
1100
|
+
ok: false,
|
|
1101
|
+
code: "invalid_response",
|
|
1102
|
+
message: "Invalid signing-session seal response"
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1105
|
+
if (!ok) {
|
|
1106
|
+
const code = Reflect.get(value, "code");
|
|
1107
|
+
const message = Reflect.get(value, "message");
|
|
1108
|
+
return {
|
|
1109
|
+
ok: false,
|
|
1110
|
+
code: typeof code === "string" ? code : "request_failed",
|
|
1111
|
+
message: typeof message === "string" ? message : "Signing-session seal request failed"
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
const ciphertext = normalizeOptionalTrimmedString(Reflect.get(value, "ciphertext"));
|
|
1115
|
+
const keyVersion = normalizeOptionalNonEmptyString(Reflect.get(value, "keyVersion"));
|
|
1116
|
+
const expiresAtMs = normalizePositiveInteger(Reflect.get(value, "expiresAtMs"));
|
|
1117
|
+
const remainingUses = normalizeNonNegativeInteger(Reflect.get(value, "remainingUses"));
|
|
1118
|
+
if (!ciphertext) {
|
|
1119
|
+
return {
|
|
1120
|
+
ok: false,
|
|
1121
|
+
code: "invalid_response",
|
|
1122
|
+
message: "Missing ciphertext in signing-session seal response"
|
|
1123
|
+
};
|
|
1124
|
+
}
|
|
1125
|
+
return {
|
|
1126
|
+
ok: true,
|
|
1127
|
+
ciphertext,
|
|
1128
|
+
...keyVersion ? { keyVersion } : {},
|
|
1129
|
+
...expiresAtMs != null ? { expiresAtMs } : {},
|
|
1130
|
+
...remainingUses != null ? { remainingUses } : {}
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
function makeSigningSessionSealSingleFlightKey(args) {
|
|
1134
|
+
const operation = args.operation === "apply-server-seal" ? "apply-server-seal" : "remove-server-seal";
|
|
1135
|
+
const thresholdSessionId = normalizeOptionalTrimmedString(args.thresholdSessionId) || "";
|
|
1136
|
+
const relayerUrl = normalizeOptionalTrimmedString(args.relayerUrl) || "";
|
|
1137
|
+
const keyVersion = normalizeOptionalNonEmptyString(args.keyVersion) || "";
|
|
1138
|
+
const payloadKey = normalizeOptionalNonEmptyString(args.payloadKey) || "";
|
|
1139
|
+
return `${operation}|${thresholdSessionId}|${relayerUrl}|${keyVersion}|${SIGNING_SESSION_SEAL_GROUP_ID}|${payloadKey}`;
|
|
1140
|
+
}
|
|
1141
|
+
async function callSigningSessionSealRoute(args) {
|
|
1142
|
+
const routePath = args.operation === "apply-server-seal" ? "apply-server-seal" : "remove-server-seal";
|
|
1143
|
+
const url = joinNormalizedUrl(args.transport.relayerUrl, `${SIGNING_SESSION_SEAL_BASE_PATH}/${routePath}`);
|
|
1144
|
+
const controller = new AbortController;
|
|
1145
|
+
const timeoutId = setTimeout(abortSigningSessionSealRoute, SIGNING_SESSION_SEAL_ROUTE_TIMEOUT_MS, controller);
|
|
1146
|
+
try {
|
|
1147
|
+
const headers = {
|
|
1148
|
+
"Content-Type": "application/json"
|
|
1149
|
+
};
|
|
1150
|
+
const keyVersion = normalizeOptionalNonEmptyString(args.keyVersion);
|
|
1151
|
+
headers.Authorization = `Bearer ${args.transport.walletSessionToken}`;
|
|
1152
|
+
const response = await fetch(url, {
|
|
1153
|
+
method: "POST",
|
|
1154
|
+
credentials: "omit",
|
|
1155
|
+
headers,
|
|
1156
|
+
signal: controller.signal,
|
|
1157
|
+
body: JSON.stringify({
|
|
1158
|
+
thresholdSessionId: args.thresholdSessionId,
|
|
1159
|
+
ciphertext: args.ciphertext,
|
|
1160
|
+
...keyVersion ? { keyVersion } : {}
|
|
1161
|
+
})
|
|
1162
|
+
});
|
|
1163
|
+
const data = await response.json().catch(() => null);
|
|
1164
|
+
const parsed = parseSigningSessionSealRouteResult(data);
|
|
1165
|
+
if (!response.ok && parsed.ok) {
|
|
1166
|
+
return {
|
|
1167
|
+
ok: false,
|
|
1168
|
+
code: "http_error",
|
|
1169
|
+
message: `Signing-session seal route returned HTTP ${response.status}`
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
if (!parsed.ok)
|
|
1173
|
+
return parsed;
|
|
1174
|
+
return parsed;
|
|
1175
|
+
} catch (error) {
|
|
1176
|
+
return {
|
|
1177
|
+
ok: false,
|
|
1178
|
+
code: controller.signal.aborted ? "timeout" : "network_error",
|
|
1179
|
+
message: controller.signal.aborted ? `Signing-session seal request timed out after ${SIGNING_SESSION_SEAL_ROUTE_TIMEOUT_MS}ms` : error instanceof Error ? error.message : String(error || "Signing-session seal request failed")
|
|
1180
|
+
};
|
|
1181
|
+
} finally {
|
|
1182
|
+
clearTimeout(timeoutId);
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
function resolvePolicyFromServerAndLocal(args) {
|
|
1186
|
+
const localRemainingUses = Math.max(0, Math.floor(Number(args.localRemainingUses) || 0));
|
|
1187
|
+
const localExpiresAtMs = Math.max(0, Math.floor(Number(args.localExpiresAtMs) || 0));
|
|
1188
|
+
const serverRemainingUses = normalizeNonNegativeInteger(args.serverRemainingUses) ?? localRemainingUses;
|
|
1189
|
+
const serverExpiresAtMs = normalizePositiveInteger(args.serverExpiresAtMs) || localExpiresAtMs;
|
|
1190
|
+
const remainingUses = Math.min(localRemainingUses, serverRemainingUses);
|
|
1191
|
+
const expiresAtMs = Math.min(localExpiresAtMs, serverExpiresAtMs);
|
|
1192
|
+
if (remainingUses <= 0) {
|
|
1193
|
+
return {
|
|
1194
|
+
ok: false,
|
|
1195
|
+
code: "exhausted",
|
|
1196
|
+
message: "Warm-session material exhausted for threshold session"
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
if (expiresAtMs <= nowMs()) {
|
|
1200
|
+
return {
|
|
1201
|
+
ok: false,
|
|
1202
|
+
code: "expired",
|
|
1203
|
+
message: "Warm-session material expired for threshold session"
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
return { ok: true, remainingUses, expiresAtMs };
|
|
1207
|
+
}
|
|
1208
|
+
function readWarmSessionMaterialEntry(thresholdSessionId) {
|
|
1209
|
+
if (!thresholdSessionId)
|
|
1210
|
+
return { ok: false, code: "invalid_args", message: "Missing threshold sessionId" };
|
|
1211
|
+
const entry = warmSessionPrfHandleCache.get(thresholdSessionId);
|
|
1212
|
+
if (!entry)
|
|
1213
|
+
return {
|
|
1214
|
+
ok: false,
|
|
1215
|
+
code: "not_found",
|
|
1216
|
+
message: "Warm-session material is not available for threshold session"
|
|
1217
|
+
};
|
|
1218
|
+
if (nowMs() >= entry.expiresAtMs) {
|
|
1219
|
+
deleteWarmSessionPrfHandle(thresholdSessionId);
|
|
1220
|
+
return {
|
|
1221
|
+
ok: false,
|
|
1222
|
+
code: "expired",
|
|
1223
|
+
message: "Warm-session material expired for threshold session"
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1226
|
+
if (entry.remainingUses <= 0) {
|
|
1227
|
+
deleteWarmSessionPrfHandle(thresholdSessionId);
|
|
1228
|
+
return {
|
|
1229
|
+
ok: false,
|
|
1230
|
+
code: "exhausted",
|
|
1231
|
+
message: "Warm-session material exhausted for threshold session"
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
const secret = passkeyPrfFirstHandleStore.get(entry.prfFirstHandle);
|
|
1235
|
+
if (!secret || nowMs() >= secret.expiresAtMs) {
|
|
1236
|
+
deleteWarmSessionPrfHandle(thresholdSessionId);
|
|
1237
|
+
return {
|
|
1238
|
+
ok: false,
|
|
1239
|
+
code: "not_found",
|
|
1240
|
+
message: "Warm-session material handle is not available for threshold session"
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
return {
|
|
1244
|
+
ok: true,
|
|
1245
|
+
entry,
|
|
1246
|
+
secret,
|
|
1247
|
+
remainingUses: entry.remainingUses,
|
|
1248
|
+
expiresAtMs: entry.expiresAtMs
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
function readWarmSessionClaimEntry(thresholdSessionId) {
|
|
1252
|
+
const activeEntry = readWarmSessionMaterialEntry(thresholdSessionId);
|
|
1253
|
+
if (!activeEntry.ok)
|
|
1254
|
+
return activeEntry;
|
|
1255
|
+
return {
|
|
1256
|
+
ok: true,
|
|
1257
|
+
remainingUses: activeEntry.remainingUses,
|
|
1258
|
+
expiresAtMs: activeEntry.expiresAtMs
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
function claimWarmSessionMaterialEntry(thresholdSessionId, uses, consume) {
|
|
1262
|
+
const activeEntry = readWarmSessionMaterialEntry(thresholdSessionId);
|
|
1263
|
+
if (!activeEntry.ok)
|
|
1264
|
+
return activeEntry;
|
|
1265
|
+
const entry = activeEntry.entry;
|
|
1266
|
+
const usesNeeded = Math.max(1, Math.floor(Number(uses) || 1));
|
|
1267
|
+
if (entry.remainingUses < usesNeeded) {
|
|
1268
|
+
return {
|
|
1269
|
+
ok: false,
|
|
1270
|
+
code: "exhausted",
|
|
1271
|
+
message: "Warm-session material exhausted for threshold session"
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
if (consume) {
|
|
1275
|
+
entry.remainingUses -= usesNeeded;
|
|
1276
|
+
if (entry.remainingUses <= 0) {
|
|
1277
|
+
deleteWarmSessionPrfHandle(thresholdSessionId);
|
|
1278
|
+
} else {
|
|
1279
|
+
warmSessionPrfHandleCache.set(thresholdSessionId, entry);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
return {
|
|
1283
|
+
ok: true,
|
|
1284
|
+
prfFirstB64u: activeEntry.secret.prfFirstB64u,
|
|
1285
|
+
remainingUses: entry.remainingUses,
|
|
1286
|
+
expiresAtMs: entry.expiresAtMs
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
function consumeWarmSessionMaterialEntry(thresholdSessionId, uses) {
|
|
1290
|
+
const activeEntry = readWarmSessionMaterialEntry(thresholdSessionId);
|
|
1291
|
+
if (!activeEntry.ok)
|
|
1292
|
+
return activeEntry;
|
|
1293
|
+
const entry = activeEntry.entry;
|
|
1294
|
+
const usesNeeded = Math.max(1, Math.floor(Number(uses) || 1));
|
|
1295
|
+
if (entry.remainingUses < usesNeeded) {
|
|
1296
|
+
return {
|
|
1297
|
+
ok: false,
|
|
1298
|
+
code: "exhausted",
|
|
1299
|
+
message: "Warm-session material exhausted for threshold session"
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
entry.remainingUses -= usesNeeded;
|
|
1303
|
+
if (entry.remainingUses <= 0) {
|
|
1304
|
+
deleteWarmSessionPrfHandle(thresholdSessionId);
|
|
1305
|
+
} else {
|
|
1306
|
+
warmSessionPrfHandleCache.set(thresholdSessionId, entry);
|
|
1307
|
+
}
|
|
1308
|
+
return {
|
|
1309
|
+
ok: true,
|
|
1310
|
+
remainingUses: entry.remainingUses,
|
|
1311
|
+
expiresAtMs: entry.expiresAtMs
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
async function runSigningSessionSealAndPersist(args) {
|
|
1315
|
+
const thresholdSessionId = normalizeOptionalTrimmedString(args.thresholdSessionId);
|
|
1316
|
+
if (!thresholdSessionId) {
|
|
1317
|
+
return { ok: false, code: "invalid_args", message: "Missing threshold sessionId" };
|
|
1318
|
+
}
|
|
1319
|
+
const activeEntry = readWarmSessionMaterialEntry(thresholdSessionId);
|
|
1320
|
+
if (!activeEntry.ok)
|
|
1321
|
+
return activeEntry;
|
|
1322
|
+
const entry = activeEntry.entry;
|
|
1323
|
+
const singleFlightKey = makeSigningSessionSealSingleFlightKey({
|
|
1324
|
+
operation: "apply-server-seal",
|
|
1325
|
+
thresholdSessionId,
|
|
1326
|
+
relayerUrl: args.transport.relayerUrl,
|
|
1327
|
+
keyVersion: args.transport.keyVersion,
|
|
1328
|
+
payloadKey: entry.prfFirstHandle
|
|
1329
|
+
});
|
|
1330
|
+
const inFlight = signingSessionSealApplyInFlight.get(singleFlightKey);
|
|
1331
|
+
if (inFlight)
|
|
1332
|
+
return await inFlight;
|
|
1333
|
+
const task = (async () => {
|
|
1334
|
+
const diagnostics = createWarmSessionSealAndPersistDiagnostics();
|
|
1335
|
+
try {
|
|
1336
|
+
const runtimeSetupStartedAt = performance.now();
|
|
1337
|
+
const runtime = await getShamir3PassRuntime();
|
|
1338
|
+
const clientKeyHandle = await runtime.createClientKeyHandle({
|
|
1339
|
+
groupId: SIGNING_SESSION_SEAL_GROUP_ID
|
|
1340
|
+
});
|
|
1341
|
+
recordWarmSessionSealAndPersistDiagnosticDuration({
|
|
1342
|
+
diagnostics,
|
|
1343
|
+
bucket: "runtimeSetupMs",
|
|
1344
|
+
startedAt: runtimeSetupStartedAt
|
|
1345
|
+
});
|
|
1346
|
+
try {
|
|
1347
|
+
const clientSealStartedAt = performance.now();
|
|
1348
|
+
const clientEncryptedCiphertext = await runtime.addClientSealWithKeyHandle({
|
|
1349
|
+
ciphertextB64u: activeEntry.secret.prfFirstB64u,
|
|
1350
|
+
keyHandle: clientKeyHandle.keyHandle
|
|
1351
|
+
});
|
|
1352
|
+
recordWarmSessionSealAndPersistDiagnosticDuration({
|
|
1353
|
+
diagnostics,
|
|
1354
|
+
bucket: "clientSealMs",
|
|
1355
|
+
startedAt: clientSealStartedAt
|
|
1356
|
+
});
|
|
1357
|
+
const serverSealRouteStartedAt = performance.now();
|
|
1358
|
+
const applied = await callSigningSessionSealRoute({
|
|
1359
|
+
operation: "apply-server-seal",
|
|
1360
|
+
transport: args.transport,
|
|
1361
|
+
thresholdSessionId,
|
|
1362
|
+
ciphertext: clientEncryptedCiphertext,
|
|
1363
|
+
keyVersion: args.transport.keyVersion
|
|
1364
|
+
});
|
|
1365
|
+
recordWarmSessionSealAndPersistDiagnosticDuration({
|
|
1366
|
+
diagnostics,
|
|
1367
|
+
bucket: "serverSealRouteMs",
|
|
1368
|
+
startedAt: serverSealRouteStartedAt
|
|
1369
|
+
});
|
|
1370
|
+
if (!applied.ok)
|
|
1371
|
+
return applied;
|
|
1372
|
+
const policyUpdateStartedAt = performance.now();
|
|
1373
|
+
const policy = resolvePolicyFromServerAndLocal({
|
|
1374
|
+
localRemainingUses: entry.remainingUses,
|
|
1375
|
+
localExpiresAtMs: entry.expiresAtMs,
|
|
1376
|
+
serverRemainingUses: applied.remainingUses,
|
|
1377
|
+
serverExpiresAtMs: applied.expiresAtMs
|
|
1378
|
+
});
|
|
1379
|
+
if (!policy.ok) {
|
|
1380
|
+
deleteWarmSessionPrfHandle(thresholdSessionId);
|
|
1381
|
+
return policy;
|
|
1382
|
+
}
|
|
1383
|
+
updateWarmSessionPrfHandlePolicy(thresholdSessionId, entry, policy);
|
|
1384
|
+
recordWarmSessionSealAndPersistDiagnosticDuration({
|
|
1385
|
+
diagnostics,
|
|
1386
|
+
bucket: "policyUpdateMs",
|
|
1387
|
+
startedAt: policyUpdateStartedAt
|
|
1388
|
+
});
|
|
1389
|
+
const keyVersion = normalizeOptionalNonEmptyString(applied.keyVersion) || normalizeOptionalNonEmptyString(args.transport.keyVersion);
|
|
1390
|
+
const sealedSecretCacheKey = keyVersion ? await passkeyServerSealedSecretCacheKey({
|
|
1391
|
+
prfFirstB64u: activeEntry.secret.prfFirstB64u,
|
|
1392
|
+
relayerUrl: args.transport.relayerUrl,
|
|
1393
|
+
keyVersion,
|
|
1394
|
+
cacheScope: args.transport.serverSealedSecretCacheScope
|
|
1395
|
+
}) : null;
|
|
1396
|
+
const cachedSealedSecret = readPasskeyServerSealedSecretCache(sealedSecretCacheKey);
|
|
1397
|
+
let sealedSecretB64u = cachedSealedSecret?.sealedSecretB64u || "";
|
|
1398
|
+
if (!sealedSecretB64u) {
|
|
1399
|
+
const clientUnsealStartedAt = performance.now();
|
|
1400
|
+
sealedSecretB64u = await runtime.removeClientSealWithKeyHandle({
|
|
1401
|
+
ciphertextB64u: applied.ciphertext,
|
|
1402
|
+
keyHandle: clientKeyHandle.keyHandle
|
|
1403
|
+
});
|
|
1404
|
+
recordWarmSessionSealAndPersistDiagnosticDuration({
|
|
1405
|
+
diagnostics,
|
|
1406
|
+
bucket: "clientUnsealMs",
|
|
1407
|
+
startedAt: clientUnsealStartedAt
|
|
1408
|
+
});
|
|
1409
|
+
writePasskeyServerSealedSecretCache({
|
|
1410
|
+
cacheKey: sealedSecretCacheKey,
|
|
1411
|
+
sealedSecretB64u,
|
|
1412
|
+
expiresAtMs: policy.expiresAtMs
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
return {
|
|
1416
|
+
ok: true,
|
|
1417
|
+
sealedSecretB64u,
|
|
1418
|
+
...keyVersion ? { keyVersion } : {},
|
|
1419
|
+
remainingUses: policy.remainingUses,
|
|
1420
|
+
expiresAtMs: policy.expiresAtMs,
|
|
1421
|
+
diagnostics
|
|
1422
|
+
};
|
|
1423
|
+
} finally {
|
|
1424
|
+
await runtime.destroyClientKeyHandle({ keyHandle: clientKeyHandle.keyHandle }).catch(() => {
|
|
1425
|
+
return;
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1428
|
+
} catch (error) {
|
|
1429
|
+
return {
|
|
1430
|
+
ok: false,
|
|
1431
|
+
code: "internal",
|
|
1432
|
+
message: error instanceof Error ? error.message : String(error || "Failed to apply server seal")
|
|
1433
|
+
};
|
|
1434
|
+
}
|
|
1435
|
+
})().finally(() => {
|
|
1436
|
+
signingSessionSealApplyInFlight.delete(singleFlightKey);
|
|
1437
|
+
});
|
|
1438
|
+
signingSessionSealApplyInFlight.set(singleFlightKey, task);
|
|
1439
|
+
return await task;
|
|
1440
|
+
}
|
|
1441
|
+
async function runSigningSessionRehydrate(args) {
|
|
1442
|
+
const thresholdSessionId = normalizeOptionalTrimmedString(args.thresholdSessionId);
|
|
1443
|
+
if (!thresholdSessionId) {
|
|
1444
|
+
return { ok: false, code: "invalid_args", message: "Missing threshold sessionId" };
|
|
1445
|
+
}
|
|
1446
|
+
const sealedSecretB64u = normalizeOptionalTrimmedString(args.sealedSecretB64u);
|
|
1447
|
+
if (!sealedSecretB64u) {
|
|
1448
|
+
return { ok: false, code: "invalid_args", message: "Missing sealedSecretB64u" };
|
|
1449
|
+
}
|
|
1450
|
+
const localRemainingUses = Math.max(0, Math.floor(Number(args.remainingUses) || 0));
|
|
1451
|
+
const localExpiresAtMs = Math.max(0, Math.floor(Number(args.expiresAtMs) || 0));
|
|
1452
|
+
if (localRemainingUses <= 0) {
|
|
1453
|
+
return {
|
|
1454
|
+
ok: false,
|
|
1455
|
+
code: "exhausted",
|
|
1456
|
+
message: "Warm-session material exhausted for threshold session"
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
if (localExpiresAtMs <= nowMs()) {
|
|
1460
|
+
return {
|
|
1461
|
+
ok: false,
|
|
1462
|
+
code: "expired",
|
|
1463
|
+
message: "Warm-session material expired for threshold session"
|
|
1464
|
+
};
|
|
1465
|
+
}
|
|
1466
|
+
const singleFlightKey = makeSigningSessionSealSingleFlightKey({
|
|
1467
|
+
operation: "remove-server-seal",
|
|
1468
|
+
thresholdSessionId,
|
|
1469
|
+
relayerUrl: args.transport.relayerUrl,
|
|
1470
|
+
keyVersion: args.keyVersion || args.transport.keyVersion,
|
|
1471
|
+
payloadKey: sealedSecretB64u
|
|
1472
|
+
});
|
|
1473
|
+
const inFlight = signingSessionSealRemoveInFlight.get(singleFlightKey);
|
|
1474
|
+
if (inFlight)
|
|
1475
|
+
return await inFlight;
|
|
1476
|
+
const task = (async () => {
|
|
1477
|
+
try {
|
|
1478
|
+
const runtime = await getShamir3PassRuntime();
|
|
1479
|
+
const clientKeyHandle = await runtime.createClientKeyHandle({
|
|
1480
|
+
groupId: SIGNING_SESSION_SEAL_GROUP_ID
|
|
1481
|
+
});
|
|
1482
|
+
try {
|
|
1483
|
+
const clientEncryptedCiphertext = await runtime.addClientSealWithKeyHandle({
|
|
1484
|
+
ciphertextB64u: sealedSecretB64u,
|
|
1485
|
+
keyHandle: clientKeyHandle.keyHandle
|
|
1486
|
+
});
|
|
1487
|
+
const removed = await callSigningSessionSealRoute({
|
|
1488
|
+
operation: "remove-server-seal",
|
|
1489
|
+
transport: args.transport,
|
|
1490
|
+
thresholdSessionId,
|
|
1491
|
+
ciphertext: clientEncryptedCiphertext,
|
|
1492
|
+
keyVersion: normalizeOptionalNonEmptyString(args.keyVersion) || args.transport.keyVersion
|
|
1493
|
+
});
|
|
1494
|
+
if (!removed.ok)
|
|
1495
|
+
return removed;
|
|
1496
|
+
const prfFirstB64u = await runtime.removeClientSealWithKeyHandle({
|
|
1497
|
+
ciphertextB64u: removed.ciphertext,
|
|
1498
|
+
keyHandle: clientKeyHandle.keyHandle
|
|
1499
|
+
});
|
|
1500
|
+
const policy = resolvePolicyFromServerAndLocal({
|
|
1501
|
+
localRemainingUses,
|
|
1502
|
+
localExpiresAtMs,
|
|
1503
|
+
serverRemainingUses: removed.remainingUses,
|
|
1504
|
+
serverExpiresAtMs: removed.expiresAtMs
|
|
1505
|
+
});
|
|
1506
|
+
if (!policy.ok)
|
|
1507
|
+
return policy;
|
|
1508
|
+
storeWarmSessionPrfHandle({
|
|
1509
|
+
thresholdSessionId,
|
|
1510
|
+
prfFirstB64u,
|
|
1511
|
+
remainingUses: policy.remainingUses,
|
|
1512
|
+
expiresAtMs: policy.expiresAtMs
|
|
1513
|
+
});
|
|
1514
|
+
return policy;
|
|
1515
|
+
} finally {
|
|
1516
|
+
await runtime.destroyClientKeyHandle({ keyHandle: clientKeyHandle.keyHandle }).catch(() => {
|
|
1517
|
+
return;
|
|
1518
|
+
});
|
|
1519
|
+
}
|
|
1520
|
+
} catch (error) {
|
|
1521
|
+
return {
|
|
1522
|
+
ok: false,
|
|
1523
|
+
code: "internal",
|
|
1524
|
+
message: error instanceof Error ? error.message : String(error || "Failed to remove server seal")
|
|
1525
|
+
};
|
|
1526
|
+
}
|
|
1527
|
+
})().finally(() => {
|
|
1528
|
+
signingSessionSealRemoveInFlight.delete(singleFlightKey);
|
|
1529
|
+
});
|
|
1530
|
+
signingSessionSealRemoveInFlight.set(singleFlightKey, task);
|
|
1531
|
+
return await task;
|
|
1532
|
+
}
|
|
1533
|
+
function postPasskeyMpcSessionWorkerResponse(id, payload) {
|
|
1534
|
+
const response = payload.success ? {
|
|
1535
|
+
...typeof id === "string" && id.trim() ? { id: id.trim() } : {},
|
|
1536
|
+
success: true,
|
|
1537
|
+
data: payload.data
|
|
1538
|
+
} : {
|
|
1539
|
+
...typeof id === "string" && id.trim() ? { id: id.trim() } : {},
|
|
1540
|
+
success: false,
|
|
1541
|
+
error: payload.error
|
|
1542
|
+
};
|
|
1543
|
+
try {
|
|
1544
|
+
self.postMessage(response);
|
|
1545
|
+
} catch {}
|
|
1546
|
+
}
|
|
1547
|
+
self.onmessage = (event) => {
|
|
1548
|
+
const incoming = parsePasskeyMpcSessionWorkerMessage(event.data);
|
|
1549
|
+
switch (incoming.kind) {
|
|
1550
|
+
case "ping":
|
|
1551
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, { success: true, data: { ok: true } });
|
|
1552
|
+
return;
|
|
1553
|
+
case "prewarm":
|
|
1554
|
+
(async () => {
|
|
1555
|
+
const outcome = await warmupShamir3PassRuntime();
|
|
1556
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, { success: true, data: outcome });
|
|
1557
|
+
})();
|
|
1558
|
+
return;
|
|
1559
|
+
case "material_put": {
|
|
1560
|
+
try {
|
|
1561
|
+
const payload = incoming.payload;
|
|
1562
|
+
if (!payload) {
|
|
1563
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, {
|
|
1564
|
+
success: true,
|
|
1565
|
+
data: {
|
|
1566
|
+
ok: false,
|
|
1567
|
+
code: "invalid_args",
|
|
1568
|
+
message: "Invalid WARM_SESSION_MATERIAL_PUT payload"
|
|
1569
|
+
}
|
|
1570
|
+
});
|
|
1571
|
+
return;
|
|
1572
|
+
}
|
|
1573
|
+
const { thresholdSessionId, prfFirstB64u, expiresAtMs, remainingUses } = payload;
|
|
1574
|
+
if (expiresAtMs <= nowMs() || remainingUses <= 0) {
|
|
1575
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, {
|
|
1576
|
+
success: true,
|
|
1577
|
+
data: {
|
|
1578
|
+
ok: false,
|
|
1579
|
+
code: "invalid_args",
|
|
1580
|
+
message: "Invalid expiresAtMs or remainingUses"
|
|
1581
|
+
}
|
|
1582
|
+
});
|
|
1583
|
+
return;
|
|
1584
|
+
}
|
|
1585
|
+
storeWarmSessionPrfHandle({ thresholdSessionId, prfFirstB64u, expiresAtMs, remainingUses });
|
|
1586
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, {
|
|
1587
|
+
success: true,
|
|
1588
|
+
data: { ok: true, remainingUses, expiresAtMs }
|
|
1589
|
+
});
|
|
1590
|
+
} catch (error) {
|
|
1591
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1592
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, { success: false, error: message });
|
|
1593
|
+
}
|
|
1594
|
+
return;
|
|
1595
|
+
}
|
|
1596
|
+
case "status_read":
|
|
1597
|
+
if (!incoming.payload) {
|
|
1598
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, {
|
|
1599
|
+
success: false,
|
|
1600
|
+
error: "Invalid WARM_SESSION_STATUS_READ payload"
|
|
1601
|
+
});
|
|
1602
|
+
return;
|
|
1603
|
+
}
|
|
1604
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, {
|
|
1605
|
+
success: true,
|
|
1606
|
+
data: readWarmSessionClaimEntry(incoming.payload.thresholdSessionId)
|
|
1607
|
+
});
|
|
1608
|
+
return;
|
|
1609
|
+
case "status_batch_read":
|
|
1610
|
+
if (!incoming.payload) {
|
|
1611
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, {
|
|
1612
|
+
success: false,
|
|
1613
|
+
error: "Invalid WARM_SESSION_STATUS_BATCH_READ payload"
|
|
1614
|
+
});
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1617
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, {
|
|
1618
|
+
success: true,
|
|
1619
|
+
data: {
|
|
1620
|
+
results: Array.from(new Set(incoming.payload.thresholdSessionIds)).map((thresholdSessionId) => ({
|
|
1621
|
+
thresholdSessionId,
|
|
1622
|
+
result: readWarmSessionClaimEntry(thresholdSessionId)
|
|
1623
|
+
}))
|
|
1624
|
+
}
|
|
1625
|
+
});
|
|
1626
|
+
return;
|
|
1627
|
+
case "material_claim":
|
|
1628
|
+
if (!incoming.payload) {
|
|
1629
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, {
|
|
1630
|
+
success: false,
|
|
1631
|
+
error: "Invalid WARM_SESSION_MATERIAL_CLAIM payload"
|
|
1632
|
+
});
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, {
|
|
1636
|
+
success: true,
|
|
1637
|
+
data: claimWarmSessionMaterialEntry(incoming.payload.thresholdSessionId, incoming.payload.uses, incoming.payload.consume)
|
|
1638
|
+
});
|
|
1639
|
+
return;
|
|
1640
|
+
case "material_consume":
|
|
1641
|
+
if (!incoming.payload) {
|
|
1642
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, {
|
|
1643
|
+
success: false,
|
|
1644
|
+
error: "Invalid WARM_SESSION_MATERIAL_CONSUME payload"
|
|
1645
|
+
});
|
|
1646
|
+
return;
|
|
1647
|
+
}
|
|
1648
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, {
|
|
1649
|
+
success: true,
|
|
1650
|
+
data: consumeWarmSessionMaterialEntry(incoming.payload.thresholdSessionId, incoming.payload.uses)
|
|
1651
|
+
});
|
|
1652
|
+
return;
|
|
1653
|
+
case "volatile_clear": {
|
|
1654
|
+
const command = parseClearVolatileWarmMaterialCommand(incoming.payload);
|
|
1655
|
+
if (command?.scope.kind === "session") {
|
|
1656
|
+
deleteWarmSessionPrfHandle(String(command.scope.thresholdSessionId));
|
|
1657
|
+
}
|
|
1658
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, { success: true, data: { ok: true } });
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
case "volatile_clear_all":
|
|
1662
|
+
clearWarmSessionPrfHandles();
|
|
1663
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, { success: true, data: { ok: true } });
|
|
1664
|
+
return;
|
|
1665
|
+
case "seal_and_persist":
|
|
1666
|
+
(async () => {
|
|
1667
|
+
const payload = incoming.payload;
|
|
1668
|
+
if (!payload) {
|
|
1669
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, {
|
|
1670
|
+
success: true,
|
|
1671
|
+
data: {
|
|
1672
|
+
ok: false,
|
|
1673
|
+
code: "invalid_args",
|
|
1674
|
+
message: "Invalid WARM_SESSION_SEAL_AND_PERSIST payload"
|
|
1675
|
+
}
|
|
1676
|
+
});
|
|
1677
|
+
return;
|
|
1678
|
+
}
|
|
1679
|
+
const result = await runSigningSessionSealAndPersist(payload);
|
|
1680
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, { success: true, data: result });
|
|
1681
|
+
})();
|
|
1682
|
+
return;
|
|
1683
|
+
case "rehydrate":
|
|
1684
|
+
(async () => {
|
|
1685
|
+
const payload = incoming.payload;
|
|
1686
|
+
if (!payload) {
|
|
1687
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, {
|
|
1688
|
+
success: true,
|
|
1689
|
+
data: {
|
|
1690
|
+
ok: false,
|
|
1691
|
+
code: "invalid_args",
|
|
1692
|
+
message: "Invalid WARM_SESSION_REHYDRATE payload"
|
|
1693
|
+
}
|
|
1694
|
+
});
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
const result = await runSigningSessionRehydrate(payload);
|
|
1698
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, { success: true, data: result });
|
|
1699
|
+
})();
|
|
1700
|
+
return;
|
|
1701
|
+
case "unknown":
|
|
1702
|
+
if (incoming.id) {
|
|
1703
|
+
postPasskeyMpcSessionWorkerResponse(incoming.id, {
|
|
1704
|
+
success: false,
|
|
1705
|
+
error: `Unsupported Passkey MPC session worker message type: ${String(incoming.type)}`
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1708
|
+
return;
|
|
1709
|
+
}
|
|
1710
|
+
};
|
|
1711
|
+
self.onerror = (error) => {
|
|
1712
|
+
console.error("[passkey-mpc-session-worker] error:", error);
|
|
1713
|
+
};
|
|
1714
|
+
self.onunhandledrejection = (event) => {
|
|
1715
|
+
console.error("[passkey-mpc-session-worker] Unhandled promise rejection:", event.reason);
|
|
1716
|
+
event.preventDefault();
|
|
1717
|
+
};
|