@tatchi-xyz/sdk 0.31.0 → 0.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/dist/cjs/core/IndexedDBManager/passkeyClientDB.js +2 -2
  2. package/dist/cjs/core/IndexedDBManager/passkeyClientDB.js.map +1 -1
  3. package/dist/cjs/core/TatchiPasskey/faucets/createAccountRelayServer.js +9 -8
  4. package/dist/cjs/core/TatchiPasskey/faucets/createAccountRelayServer.js.map +1 -1
  5. package/dist/cjs/core/TatchiPasskey/login.js +1 -1
  6. package/dist/cjs/core/TatchiPasskey/login.js.map +1 -1
  7. package/dist/cjs/core/TatchiPasskey/registration.js +67 -56
  8. package/dist/cjs/core/TatchiPasskey/registration.js.map +1 -1
  9. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.js +1 -10
  10. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.js.map +1 -1
  11. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js +58 -67
  12. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js.map +1 -1
  13. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js +74 -75
  14. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js.map +1 -1
  15. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.js +17 -7
  16. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.js.map +1 -1
  17. package/dist/cjs/core/WebAuthnManager/index.js +3 -3
  18. package/dist/cjs/core/WebAuthnManager/index.js.map +1 -1
  19. package/dist/cjs/core/defaultConfigs.js +3 -1
  20. package/dist/cjs/core/defaultConfigs.js.map +1 -1
  21. package/dist/cjs/react/components/AccountMenuButton/TransactionSettingsSection.js +3 -3
  22. package/dist/cjs/react/components/AccountMenuButton/TransactionSettingsSection.js.map +1 -1
  23. package/dist/cjs/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-CRlobBrN.css → PasskeyAuthMenu-D2eRb2-S.css} +3 -1
  24. package/dist/cjs/react/components/PasskeyAuthMenu/PasskeyAuthMenu-D2eRb2-S.css.map +1 -0
  25. package/dist/cjs/react/components/PasskeyAuthMenu/preload.js +1 -1
  26. package/dist/cjs/react/components/PasskeyAuthMenu/preload.js.map +1 -1
  27. package/dist/cjs/react/components/PasskeyAuthMenu/shell.js +52 -13
  28. package/dist/cjs/react/components/PasskeyAuthMenu/shell.js.map +1 -1
  29. package/dist/cjs/react/components/PasskeyAuthMenu/skeleton.js +4 -2
  30. package/dist/cjs/react/components/PasskeyAuthMenu/skeleton.js.map +1 -1
  31. package/dist/cjs/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js +5 -1
  32. package/dist/cjs/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js.map +1 -1
  33. package/dist/cjs/react/index.js +1 -1
  34. package/dist/cjs/react/src/core/IndexedDBManager/passkeyClientDB.js +2 -2
  35. package/dist/cjs/react/src/core/IndexedDBManager/passkeyClientDB.js.map +1 -1
  36. package/dist/cjs/react/src/core/TatchiPasskey/faucets/createAccountRelayServer.js +9 -8
  37. package/dist/cjs/react/src/core/TatchiPasskey/faucets/createAccountRelayServer.js.map +1 -1
  38. package/dist/cjs/react/src/core/TatchiPasskey/login.js +1 -1
  39. package/dist/cjs/react/src/core/TatchiPasskey/login.js.map +1 -1
  40. package/dist/cjs/react/src/core/TatchiPasskey/registration.js +67 -56
  41. package/dist/cjs/react/src/core/TatchiPasskey/registration.js.map +1 -1
  42. package/dist/cjs/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.js +1 -10
  43. package/dist/cjs/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.js.map +1 -1
  44. package/dist/cjs/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js +58 -67
  45. package/dist/cjs/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js.map +1 -1
  46. package/dist/cjs/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js +74 -75
  47. package/dist/cjs/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js.map +1 -1
  48. package/dist/cjs/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.js +17 -7
  49. package/dist/cjs/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.js.map +1 -1
  50. package/dist/cjs/react/src/core/WebAuthnManager/index.js +3 -3
  51. package/dist/cjs/react/src/core/WebAuthnManager/index.js.map +1 -1
  52. package/dist/cjs/react/src/core/defaultConfigs.js +3 -1
  53. package/dist/cjs/react/src/core/defaultConfigs.js.map +1 -1
  54. package/dist/cjs/server/core/AuthService.js +49 -6
  55. package/dist/cjs/server/core/AuthService.js.map +1 -1
  56. package/dist/cjs/server/sdk/src/core/defaultConfigs.js.map +1 -1
  57. package/dist/esm/core/IndexedDBManager/passkeyClientDB.js +2 -2
  58. package/dist/esm/core/IndexedDBManager/passkeyClientDB.js.map +1 -1
  59. package/dist/esm/core/TatchiPasskey/faucets/createAccountRelayServer.js +9 -8
  60. package/dist/esm/core/TatchiPasskey/faucets/createAccountRelayServer.js.map +1 -1
  61. package/dist/esm/core/TatchiPasskey/login.js +1 -1
  62. package/dist/esm/core/TatchiPasskey/login.js.map +1 -1
  63. package/dist/esm/core/TatchiPasskey/registration.js +67 -56
  64. package/dist/esm/core/TatchiPasskey/registration.js.map +1 -1
  65. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.js +1 -10
  66. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.js.map +1 -1
  67. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js +58 -67
  68. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js.map +1 -1
  69. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js +74 -75
  70. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js.map +1 -1
  71. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.js +17 -7
  72. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.js.map +1 -1
  73. package/dist/esm/core/WebAuthnManager/index.js +3 -3
  74. package/dist/esm/core/WebAuthnManager/index.js.map +1 -1
  75. package/dist/esm/core/defaultConfigs.js +3 -1
  76. package/dist/esm/core/defaultConfigs.js.map +1 -1
  77. package/dist/esm/react/components/AccountMenuButton/TransactionSettingsSection.js +3 -3
  78. package/dist/esm/react/components/AccountMenuButton/TransactionSettingsSection.js.map +1 -1
  79. package/dist/esm/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-D2VHZ04W.css → PasskeyAuthMenu-qTHAv58Z.css} +3 -1
  80. package/dist/esm/react/components/PasskeyAuthMenu/PasskeyAuthMenu-qTHAv58Z.css.map +1 -0
  81. package/dist/esm/react/components/PasskeyAuthMenu/preload.js +1 -1
  82. package/dist/esm/react/components/PasskeyAuthMenu/preload.js.map +1 -1
  83. package/dist/esm/react/components/PasskeyAuthMenu/shell.js +52 -13
  84. package/dist/esm/react/components/PasskeyAuthMenu/shell.js.map +1 -1
  85. package/dist/esm/react/components/PasskeyAuthMenu/skeleton.js +4 -2
  86. package/dist/esm/react/components/PasskeyAuthMenu/skeleton.js.map +1 -1
  87. package/dist/esm/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js +5 -1
  88. package/dist/esm/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js.map +1 -1
  89. package/dist/esm/react/index.js +1 -1
  90. package/dist/esm/react/src/core/IndexedDBManager/passkeyClientDB.js +2 -2
  91. package/dist/esm/react/src/core/IndexedDBManager/passkeyClientDB.js.map +1 -1
  92. package/dist/esm/react/src/core/TatchiPasskey/faucets/createAccountRelayServer.js +9 -8
  93. package/dist/esm/react/src/core/TatchiPasskey/faucets/createAccountRelayServer.js.map +1 -1
  94. package/dist/esm/react/src/core/TatchiPasskey/login.js +1 -1
  95. package/dist/esm/react/src/core/TatchiPasskey/login.js.map +1 -1
  96. package/dist/esm/react/src/core/TatchiPasskey/registration.js +67 -56
  97. package/dist/esm/react/src/core/TatchiPasskey/registration.js.map +1 -1
  98. package/dist/esm/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.js +1 -10
  99. package/dist/esm/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.js.map +1 -1
  100. package/dist/esm/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js +58 -67
  101. package/dist/esm/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js.map +1 -1
  102. package/dist/esm/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js +74 -75
  103. package/dist/esm/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js.map +1 -1
  104. package/dist/esm/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.js +17 -7
  105. package/dist/esm/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.js.map +1 -1
  106. package/dist/esm/react/src/core/WebAuthnManager/index.js +3 -3
  107. package/dist/esm/react/src/core/WebAuthnManager/index.js.map +1 -1
  108. package/dist/esm/react/src/core/defaultConfigs.js +3 -1
  109. package/dist/esm/react/src/core/defaultConfigs.js.map +1 -1
  110. package/dist/esm/react/styles/styles.css +2 -0
  111. package/dist/esm/sdk/{EmailRecovery-Dl8b4ONg.js → EmailRecovery-Y7rurd4B.js} +3 -3
  112. package/dist/esm/sdk/{EmailRecovery-v9oNO2Tc.js → EmailRecovery-lsjLWApQ.js} +1 -1
  113. package/dist/esm/sdk/{IndexedDBManager-B1cUvdyY.js → IndexedDBManager-CmdN7smS.js} +3 -3
  114. package/dist/esm/sdk/{createAdapters-Dv7ZJPf1.js → createAdapters-4c8mBiD5.js} +2 -11
  115. package/dist/esm/sdk/{createAdapters-Dv7ZJPf1.js.map → createAdapters-4c8mBiD5.js.map} +1 -1
  116. package/dist/esm/sdk/{createAdapters-1Hmc1vVC.js → createAdapters-DF32SIZa.js} +1 -10
  117. package/dist/esm/sdk/{defaultConfigs-BmCU1_qI.js → defaultConfigs-BQqiXif-.js} +3 -1
  118. package/dist/esm/sdk/{emailRecovery-4J-g9tlY.js → emailRecovery-C0LSDleV.js} +5 -5
  119. package/dist/esm/sdk/{getDeviceNumber-f8bfPB9U.js → getDeviceNumber-WiNzKx1x.js} +4 -2
  120. package/dist/esm/sdk/{getDeviceNumber-f8bfPB9U.js.map → getDeviceNumber-WiNzKx1x.js.map} +1 -1
  121. package/dist/esm/sdk/{linkDevice-C98klpcE.js → linkDevice-Ds1GNIDk.js} +4 -4
  122. package/dist/esm/sdk/{localOnly-40zxrBMm.js → localOnly-COpDBMkm.js} +2 -2
  123. package/dist/esm/sdk/{localOnly-40zxrBMm.js.map → localOnly-COpDBMkm.js.map} +1 -1
  124. package/dist/esm/sdk/{localOnly-BZPBj14l.js → localOnly-DQQuqgjJ.js} +1 -1
  125. package/dist/esm/sdk/{login-DnROv3eA.js → login-BKhTuGcy.js} +3 -3
  126. package/dist/esm/sdk/offline-export-app.js +29 -19
  127. package/dist/esm/sdk/offline-export-app.js.map +1 -1
  128. package/dist/esm/sdk/{registration-BP9M3tE1.js → registration-BR2G9tz_.js} +59 -68
  129. package/dist/esm/sdk/{registration-MrAOC8Ub.js → registration-R70lvG_o.js} +60 -69
  130. package/dist/esm/sdk/registration-R70lvG_o.js.map +1 -0
  131. package/dist/esm/sdk/{router-BEGGuWaB.js → router-2aGn-CTp.js} +1 -1
  132. package/dist/esm/sdk/{rpcCalls-CMzj_Va_.js → rpcCalls-BPI0icZG.js} +2 -2
  133. package/dist/esm/sdk/{rpcCalls-B44MZora.js → rpcCalls-BW3M_q3-.js} +1 -1
  134. package/dist/esm/sdk/{scanDevice-Cp-r-Z2T.js → scanDevice-BBSehlMx.js} +4 -4
  135. package/dist/esm/sdk/{syncAccount-CqWCmBVb.js → syncAccount-DEZHBiRa.js} +4 -4
  136. package/dist/esm/sdk/{syncAccount-Dt5jJbEB.js → syncAccount-DHKtl-xh.js} +2 -2
  137. package/dist/esm/sdk/{transactions-DAZrPW-6.js → transactions-Cg1TIUyK.js} +76 -77
  138. package/dist/esm/sdk/{transactions-CrjP8yPD.js → transactions-CxsklyCK.js} +77 -78
  139. package/dist/esm/sdk/transactions-CxsklyCK.js.map +1 -0
  140. package/dist/esm/sdk/wallet-iframe-host.js +116 -94
  141. package/dist/esm/server/core/AuthService.js +49 -6
  142. package/dist/esm/server/core/AuthService.js.map +1 -1
  143. package/dist/esm/server/sdk/src/core/defaultConfigs.js.map +1 -1
  144. package/dist/esm/wasm_vrf_worker/pkg/wasm_vrf_worker_bg.wasm +0 -0
  145. package/dist/types/src/__tests__/setup/bootstrap.d.ts.map +1 -1
  146. package/dist/types/src/core/IndexedDBManager/passkeyClientDB.d.ts +1 -1
  147. package/dist/types/src/core/IndexedDBManager/passkeyClientDB.d.ts.map +1 -1
  148. package/dist/types/src/core/TatchiPasskey/faucets/createAccountRelayServer.d.ts +6 -6
  149. package/dist/types/src/core/TatchiPasskey/faucets/createAccountRelayServer.d.ts.map +1 -1
  150. package/dist/types/src/core/TatchiPasskey/registration.d.ts.map +1 -1
  151. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.d.ts +0 -5
  152. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.d.ts.map +1 -1
  153. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.d.ts.map +1 -1
  154. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.d.ts.map +1 -1
  155. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.d.ts.map +1 -1
  156. package/dist/types/src/core/WebAuthnManager/index.d.ts +1 -1
  157. package/dist/types/src/core/WebAuthnManager/index.d.ts.map +1 -1
  158. package/dist/types/src/core/defaultConfigs.d.ts.map +1 -1
  159. package/dist/types/src/react/components/PasskeyAuthMenu/preload.d.ts.map +1 -1
  160. package/dist/types/src/react/components/PasskeyAuthMenu/shell.d.ts.map +1 -1
  161. package/dist/types/src/react/components/PasskeyAuthMenu/skeleton.d.ts +1 -1
  162. package/dist/types/src/react/components/PasskeyAuthMenu/skeleton.d.ts.map +1 -1
  163. package/dist/types/src/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.d.ts.map +1 -1
  164. package/dist/types/src/server/core/AuthService.d.ts.map +1 -1
  165. package/dist/workers/offline-export-sw.js +156 -1
  166. package/dist/workers/wasm_vrf_worker_bg.wasm +0 -0
  167. package/dist/workers/web3authn-signer.worker.js +1360 -2
  168. package/dist/workers/web3authn-vrf.worker.js +2857 -2
  169. package/package.json +1 -1
  170. package/dist/cjs/react/components/PasskeyAuthMenu/PasskeyAuthMenu-CRlobBrN.css.map +0 -1
  171. package/dist/esm/react/components/PasskeyAuthMenu/PasskeyAuthMenu-D2VHZ04W.css.map +0 -1
  172. package/dist/esm/sdk/registration-MrAOC8Ub.js.map +0 -1
  173. package/dist/esm/sdk/transactions-CrjP8yPD.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"registration.js","names":["uiVrfChallenge: VRFChallenge","credential: PublicKeyCredential | undefined","e: unknown","serialized: WebAuthnRegistrationCredential","err: unknown"],"sources":["../../../../../../../src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.ts"],"sourcesContent":["import type { VrfWorkerManagerContext } from '../../';\nimport type { ConfirmationConfig } from '../../../../types/signer-worker';\nimport {\n TransactionSummary,\n RegistrationSecureConfirmRequest,\n} from '../types';\nimport { VRFChallenge, TransactionContext } from '../../../../types';\nimport type { WebAuthnRegistrationCredential } from '../../../../types/webauthn';\nimport { sha256Base64UrlUtf8 } from '../../../../digests/intentDigest';\nimport {\n getNearAccountId,\n getIntentDigest,\n isUserCancelledSecureConfirm,\n ERROR_MESSAGES,\n getRegisterAccountPayload,\n} from './index';\nimport { isSerializedRegistrationCredential, serializeRegistrationCredentialWithPRF } from '../../../credentialsHelpers';\nimport { toError } from '../../../../../utils/errors';\nimport { createConfirmSession } from '../adapters/session';\nimport { createConfirmTxFlowAdapters } from '../adapters/createAdapters';\n\nexport async function handleRegistrationFlow(\n ctx: VrfWorkerManagerContext,\n request: RegistrationSecureConfirmRequest,\n worker: Worker,\n opts: { confirmationConfig: ConfirmationConfig; transactionSummary: TransactionSummary },\n): Promise<void> {\n\n const { confirmationConfig, transactionSummary } = opts;\n const adapters = createConfirmTxFlowAdapters(ctx);\n const session = createConfirmSession({\n adapters,\n worker,\n request,\n confirmationConfig,\n transactionSummary,\n });\n const nearAccountId = getNearAccountId(request);\n\n console.debug('[RegistrationFlow] start', {\n nearAccountId,\n uiMode: confirmationConfig?.uiMode,\n behavior: confirmationConfig?.behavior,\n theme: confirmationConfig?.theme,\n intentDigest: transactionSummary?.intentDigest,\n });\n\n // 1) NEAR context\n const nearRpc = await adapters.near.fetchNearContext({ nearAccountId, txCount: 1, reserveNonces: true });\n if (nearRpc.error && !nearRpc.transactionContext) {\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: `${ERROR_MESSAGES.nearRpcFailed}: ${nearRpc.details}`,\n });\n }\n const transactionContext = nearRpc.transactionContext as TransactionContext;\n session.setReservedNonces(nearRpc.reservedNonces);\n\n const computeBoundIntentDigestB64u = async (): Promise<string> => {\n const uiIntentDigest = getIntentDigest(request);\n if (!uiIntentDigest) {\n throw new Error('Missing intentDigest for registration flow');\n }\n return sha256Base64UrlUtf8(uiIntentDigest);\n };\n\n // 2) Initial VRF challenge via bootstrap\n const rpId = adapters.vrf.getRpId();\n const boundIntentDigestB64u = await computeBoundIntentDigestB64u();\n const bootstrap = await adapters.vrf.generateVrfKeypairBootstrap({\n vrfInputData: {\n userId: nearAccountId,\n rpId,\n blockHeight: transactionContext.txBlockHeight,\n blockHash: transactionContext.txBlockHash,\n intentDigest: boundIntentDigestB64u,\n },\n saveInMemory: true,\n sessionId: request.requestId,\n });\n let uiVrfChallenge: VRFChallenge = bootstrap.vrfChallenge;\n console.debug('[RegistrationFlow] VRF bootstrap ok', { blockHeight: uiVrfChallenge.blockHeight });\n\n // 3) UI confirm\n const { confirmed, error: uiError } = await session.promptUser({ vrfChallenge: uiVrfChallenge });\n if (!confirmed) {\n console.debug('[RegistrationFlow] user cancelled');\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: uiError,\n });\n }\n\n // 4) JIT refresh VRF (best-effort)\n try {\n const refreshed = await adapters.vrf.maybeRefreshVrfChallenge(request, nearAccountId);\n uiVrfChallenge = refreshed.vrfChallenge;\n session.updateUI({ vrfChallenge: uiVrfChallenge });\n console.debug('[RegistrationFlow] VRF JIT refresh ok', { blockHeight: uiVrfChallenge.blockHeight });\n } catch (e) {\n console.debug('[RegistrationFlow] VRF JIT refresh skipped', e);\n }\n\n // 5) Collect registration credentials (with duplicate retry)\n let credential: PublicKeyCredential | undefined;\n let deviceNumber = request.payload?.deviceNumber ?? 1;\n\n const tryCreate = async (dn?: number): Promise<PublicKeyCredential> => {\n console.debug('[RegistrationFlow] navigator.credentials.create start', { deviceNumber: dn });\n return await adapters.webauthn.createRegistrationCredential({\n nearAccountId,\n challenge: uiVrfChallenge,\n deviceNumber: dn,\n });\n };\n\n try {\n try {\n credential = await tryCreate(deviceNumber);\n console.debug('[RegistrationFlow] credentials.create ok');\n } catch (e: unknown) {\n const err = toError(e);\n const name = String(err?.name || '');\n const msg = String(err?.message || '');\n const isDuplicate = name === 'InvalidStateError' || /excluded|already\\s*registered/i.test(msg);\n if (isDuplicate) {\n const nextDeviceNumber = (deviceNumber !== undefined && Number.isFinite(deviceNumber)) ? (deviceNumber + 1) : 2;\n console.debug('[RegistrationFlow] duplicate credential, retry with next deviceNumber', { nextDeviceNumber });\n // Keep request payload and intentDigest in sync with the deviceNumber retry.\n deviceNumber = nextDeviceNumber;\n getRegisterAccountPayload(request).deviceNumber = nextDeviceNumber;\n request.intentDigest = request.type === 'registerAccount'\n ? `register:${nearAccountId}:${nextDeviceNumber}`\n : `device2-register:${nearAccountId}:${nextDeviceNumber}`;\n\n // Regenerate a VRF challenge bound to the updated intentDigest so the contract-side\n // VRF input derivation remains consistent end-to-end.\n const retryBoundIntentDigestB64u = await computeBoundIntentDigestB64u();\n const retryBootstrap = await adapters.vrf.generateVrfKeypairBootstrap({\n vrfInputData: {\n userId: nearAccountId,\n rpId,\n blockHeight: transactionContext.txBlockHeight,\n blockHash: transactionContext.txBlockHash,\n intentDigest: retryBoundIntentDigestB64u,\n },\n saveInMemory: true,\n sessionId: request.requestId,\n });\n uiVrfChallenge = retryBootstrap.vrfChallenge;\n session.updateUI({ vrfChallenge: uiVrfChallenge });\n\n credential = await tryCreate(nextDeviceNumber);\n } else {\n console.error('[RegistrationFlow] credentials.create failed (non-duplicate)', { name, msg });\n throw err;\n }\n }\n\n // We require registration credentials to include dual PRF outputs (first + second)\n // so VRF/NEAR key derivation can happen inside the workers without passing PRF outputs\n // as separate main-thread values.\n const serialized: WebAuthnRegistrationCredential = isSerializedRegistrationCredential(credential as unknown)\n ? (credential as unknown as WebAuthnRegistrationCredential)\n : serializeRegistrationCredentialWithPRF({\n credential: credential! as PublicKeyCredential,\n firstPrfOutput: true,\n secondPrfOutput: true,\n });\n\n // 6) Respond + close\n session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: true,\n credential: serialized,\n // PRF outputs are embedded in serialized credential; VRF worker extracts and sends via MessagePort\n vrfChallenge: uiVrfChallenge,\n transactionContext,\n });\n\n } catch (err: unknown) {\n const cancelled = isUserCancelledSecureConfirm(err);\n const msg = String((toError(err))?.message || err || '');\n // For missing PRF outputs, surface the error to caller (defensive path tests expect a throw)\n if (/Missing PRF result/i.test(msg) || /Missing PRF results/i.test(msg)) {\n return session.cleanupAndRethrow(err);\n }\n if (cancelled) {\n window.parent?.postMessage({ type: 'WALLET_UI_CLOSED' }, '*');\n }\n\n const isPrfBrowserUnsupported =\n /WebAuthn PRF output is missing from navigator\\.credentials\\.create\\(\\)/i.test(msg)\n || /does not fully support the WebAuthn PRF extension during registration/i.test(msg)\n || /roaming hardware authenticators .* not supported in this flow/i.test(msg);\n\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: cancelled\n ? ERROR_MESSAGES.cancelled\n : (isPrfBrowserUnsupported ? msg : ERROR_MESSAGES.collectCredentialsFailed),\n });\n }\n}\n"],"mappings":";;;;;;;;;AAqBA,eAAsB,uBACpB,KACA,SACA,QACA,MACe;CAEf,MAAM,EAAE,oBAAoB,uBAAuB;CACnD,MAAM,WAAW,4BAA4B;CAC7C,MAAM,UAAU,qBAAqB;EACnC;EACA;EACA;EACA;EACA;;CAEF,MAAM,gBAAgB,iBAAiB;AAEvC,SAAQ,MAAM,4BAA4B;EACxC;EACA,QAAQ,oBAAoB;EAC5B,UAAU,oBAAoB;EAC9B,OAAO,oBAAoB;EAC3B,cAAc,oBAAoB;;CAIpC,MAAM,UAAU,MAAM,SAAS,KAAK,iBAAiB;EAAE;EAAe,SAAS;EAAG,eAAe;;AACjG,KAAI,QAAQ,SAAS,CAAC,QAAQ,mBAC5B,QAAO,QAAQ,qBAAqB;EAClC,WAAW,QAAQ;EACnB,cAAc,gBAAgB;EAC9B,WAAW;EACX,OAAO,GAAG,eAAe,cAAc,IAAI,QAAQ;;CAGvD,MAAM,qBAAqB,QAAQ;AACnC,SAAQ,kBAAkB,QAAQ;CAElC,MAAM,+BAA+B,YAA6B;EAChE,MAAM,iBAAiB,gBAAgB;AACvC,MAAI,CAAC,eACH,OAAM,IAAI,MAAM;AAElB,SAAO,oBAAoB;;CAI7B,MAAM,OAAO,SAAS,IAAI;CAC1B,MAAM,wBAAwB,MAAM;CACpC,MAAM,YAAY,MAAM,SAAS,IAAI,4BAA4B;EAC/D,cAAc;GACZ,QAAQ;GACR;GACA,aAAa,mBAAmB;GAChC,WAAW,mBAAmB;GAC9B,cAAc;;EAEhB,cAAc;EACd,WAAW,QAAQ;;CAErB,IAAIA,iBAA+B,UAAU;AAC7C,SAAQ,MAAM,uCAAuC,EAAE,aAAa,eAAe;CAGnF,MAAM,EAAE,WAAW,OAAO,YAAY,MAAM,QAAQ,WAAW,EAAE,cAAc;AAC/E,KAAI,CAAC,WAAW;AACd,UAAQ,MAAM;AACd,SAAO,QAAQ,qBAAqB;GAClC,WAAW,QAAQ;GACnB,cAAc,gBAAgB;GAC9B,WAAW;GACX,OAAO;;;AAKX,KAAI;EACF,MAAM,YAAY,MAAM,SAAS,IAAI,yBAAyB,SAAS;AACvE,mBAAiB,UAAU;AAC3B,UAAQ,SAAS,EAAE,cAAc;AACjC,UAAQ,MAAM,yCAAyC,EAAE,aAAa,eAAe;UAC9E,GAAG;AACV,UAAQ,MAAM,8CAA8C;;CAI9D,IAAIC;CACJ,IAAI,eAAe,QAAQ,SAAS,gBAAgB;CAEpD,MAAM,YAAY,OAAO,OAA8C;AACrE,UAAQ,MAAM,yDAAyD,EAAE,cAAc;AACvF,SAAO,MAAM,SAAS,SAAS,6BAA6B;GAC1D;GACA,WAAW;GACX,cAAc;;;AAIlB,KAAI;AACF,MAAI;AACF,gBAAa,MAAM,UAAU;AAC7B,WAAQ,MAAM;WACPC,GAAY;GACnB,MAAM,MAAM,QAAQ;GACpB,MAAM,OAAO,OAAO,KAAK,QAAQ;GACjC,MAAM,MAAM,OAAO,KAAK,WAAW;GACnC,MAAM,cAAc,SAAS,uBAAuB,iCAAiC,KAAK;AAC1F,OAAI,aAAa;IACf,MAAM,mBAAoB,iBAAiB,UAAa,OAAO,SAAS,gBAAkB,eAAe,IAAK;AAC9G,YAAQ,MAAM,yEAAyE,EAAE;AAEzF,mBAAe;AACf,8BAA0B,SAAS,eAAe;AAClD,YAAQ,eAAe,QAAQ,SAAS,oBACpC,YAAY,cAAc,GAAG,qBAC7B,oBAAoB,cAAc,GAAG;IAIzC,MAAM,6BAA6B,MAAM;IACzC,MAAM,iBAAiB,MAAM,SAAS,IAAI,4BAA4B;KACpE,cAAc;MACZ,QAAQ;MACR;MACA,aAAa,mBAAmB;MAChC,WAAW,mBAAmB;MAC9B,cAAc;;KAEhB,cAAc;KACd,WAAW,QAAQ;;AAErB,qBAAiB,eAAe;AAChC,YAAQ,SAAS,EAAE,cAAc;AAEjC,iBAAa,MAAM,UAAU;UACxB;AACL,YAAQ,MAAM,gEAAgE;KAAE;KAAM;;AACtF,UAAM;;;EAOV,MAAMC,aAA6C,mCAAmC,cACjF,aACD,uCAAuC;GACzB;GACZ,gBAAgB;GAChB,iBAAiB;;AAIvB,UAAQ,qBAAqB;GAC3B,WAAW,QAAQ;GACnB,cAAc,gBAAgB;GAC9B,WAAW;GACX,YAAY;GAEZ,cAAc;GACd;;UAGKC,KAAc;EACrB,MAAM,YAAY,6BAA6B;EAC/C,MAAM,MAAM,OAAQ,QAAQ,MAAO,WAAW,OAAO;AAErD,MAAI,sBAAsB,KAAK,QAAQ,uBAAuB,KAAK,KACjE,QAAO,QAAQ,kBAAkB;AAEnC,MAAI,UACF,QAAO,QAAQ,YAAY,EAAE,MAAM,sBAAsB;EAG3D,MAAM,0BACJ,0EAA0E,KAAK,QAC5E,yEAAyE,KAAK,QAC9E,iEAAiE,KAAK;AAE3E,SAAO,QAAQ,qBAAqB;GAClC,WAAW,QAAQ;GACnB,cAAc,gBAAgB;GAC9B,WAAW;GACX,OAAO,YACH,eAAe,YACd,0BAA0B,MAAM,eAAe"}
1
+ {"version":3,"file":"registration.js","names":["uiVrfChallenge: VRFChallenge","credential: PublicKeyCredential | undefined","e: unknown","serialized: WebAuthnRegistrationCredential","err: unknown"],"sources":["../../../../../../../src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.ts"],"sourcesContent":["import type { VrfWorkerManagerContext } from '../../';\nimport type { ConfirmationConfig } from '../../../../types/signer-worker';\nimport {\n TransactionSummary,\n RegistrationSecureConfirmRequest,\n} from '../types';\nimport { VRFChallenge, TransactionContext } from '../../../../types';\nimport type { WebAuthnRegistrationCredential } from '../../../../types/webauthn';\nimport { sha256Base64UrlUtf8 } from '../../../../digests/intentDigest';\nimport {\n getNearAccountId,\n getIntentDigest,\n isUserCancelledSecureConfirm,\n ERROR_MESSAGES,\n getRegisterAccountPayload,\n} from './index';\nimport { isSerializedRegistrationCredential, serializeRegistrationCredentialWithPRF } from '../../../credentialsHelpers';\nimport { toError } from '../../../../../utils/errors';\nimport { createConfirmSession } from '../adapters/session';\nimport { createConfirmTxFlowAdapters } from '../adapters/createAdapters';\n\nexport async function handleRegistrationFlow(\n ctx: VrfWorkerManagerContext,\n request: RegistrationSecureConfirmRequest,\n worker: Worker,\n opts: { confirmationConfig: ConfirmationConfig; transactionSummary: TransactionSummary },\n): Promise<void> {\n\n const { confirmationConfig, transactionSummary } = opts;\n const adapters = createConfirmTxFlowAdapters(ctx);\n const session = createConfirmSession({\n adapters,\n worker,\n request,\n confirmationConfig,\n transactionSummary,\n });\n const nearAccountId = getNearAccountId(request);\n\n try {\n // 1) NEAR context\n const nearRpc = await adapters.near.fetchNearContext({ nearAccountId, txCount: 1, reserveNonces: true });\n if (nearRpc.error && !nearRpc.transactionContext) {\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: `${ERROR_MESSAGES.nearRpcFailed}: ${nearRpc.details}`,\n });\n }\n const transactionContext = nearRpc.transactionContext as TransactionContext;\n session.setReservedNonces(nearRpc.reservedNonces);\n\n const computeBoundIntentDigestB64u = async (): Promise<string> => {\n const uiIntentDigest = getIntentDigest(request);\n if (!uiIntentDigest) {\n throw new Error('Missing intentDigest for registration flow');\n }\n return sha256Base64UrlUtf8(uiIntentDigest);\n };\n\n // 2) Initial VRF challenge via bootstrap\n const rpId = adapters.vrf.getRpId();\n const boundIntentDigestB64u = await computeBoundIntentDigestB64u();\n const bootstrap = await adapters.vrf.generateVrfKeypairBootstrap({\n vrfInputData: {\n userId: nearAccountId,\n rpId,\n blockHeight: transactionContext.txBlockHeight,\n blockHash: transactionContext.txBlockHash,\n intentDigest: boundIntentDigestB64u,\n },\n saveInMemory: true,\n sessionId: request.requestId,\n });\n let uiVrfChallenge: VRFChallenge = bootstrap.vrfChallenge;\n console.debug('[RegistrationFlow] VRF bootstrap ok', { blockHeight: uiVrfChallenge.blockHeight });\n\n // 3) UI confirm\n const { confirmed, error: uiError } = await session.promptUser({ vrfChallenge: uiVrfChallenge });\n if (!confirmed) {\n console.debug('[RegistrationFlow] user cancelled');\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: uiError,\n });\n }\n\n // 4) JIT refresh VRF (best-effort)\n try {\n const refreshed = await adapters.vrf.maybeRefreshVrfChallenge(request, nearAccountId);\n uiVrfChallenge = refreshed.vrfChallenge;\n session.updateUI({ vrfChallenge: uiVrfChallenge });\n console.debug('[RegistrationFlow] VRF JIT refresh ok', { blockHeight: uiVrfChallenge.blockHeight });\n } catch (e) {\n console.debug('[RegistrationFlow] VRF JIT refresh skipped', e);\n }\n\n // 5) Collect registration credentials (with duplicate retry)\n let credential: PublicKeyCredential | undefined;\n let deviceNumber = request.payload?.deviceNumber ?? 1;\n\n const tryCreate = async (dn?: number): Promise<PublicKeyCredential> => {\n console.debug('[RegistrationFlow] navigator.credentials.create start', { deviceNumber: dn });\n return await adapters.webauthn.createRegistrationCredential({\n nearAccountId,\n challenge: uiVrfChallenge,\n deviceNumber: dn,\n });\n };\n\n try {\n credential = await tryCreate(deviceNumber);\n } catch (e: unknown) {\n\n const err = toError(e);\n const name = String(err?.name || '');\n const msg = String(err?.message || '');\n const isDuplicate = name === 'InvalidStateError' || /excluded|already\\s*registered/i.test(msg);\n\n if (isDuplicate) {\n const nextDeviceNumber = (deviceNumber !== undefined && Number.isFinite(deviceNumber)) ? (deviceNumber + 1) : 2;\n console.debug('[RegistrationFlow] duplicate credential, retry with next deviceNumber', { nextDeviceNumber });\n // Keep request payload and intentDigest in sync with the deviceNumber retry.\n deviceNumber = nextDeviceNumber;\n getRegisterAccountPayload(request).deviceNumber = nextDeviceNumber;\n request.intentDigest = request.type === 'registerAccount'\n ? `register:${nearAccountId}:${nextDeviceNumber}`\n : `device2-register:${nearAccountId}:${nextDeviceNumber}`;\n\n // Regenerate a VRF challenge bound to the updated intentDigest so the contract-side\n // VRF input derivation remains consistent end-to-end.\n const retryBoundIntentDigestB64u = await computeBoundIntentDigestB64u();\n const retryBootstrap = await adapters.vrf.generateVrfKeypairBootstrap({\n vrfInputData: {\n userId: nearAccountId,\n rpId,\n blockHeight: transactionContext.txBlockHeight,\n blockHash: transactionContext.txBlockHash,\n intentDigest: retryBoundIntentDigestB64u,\n },\n saveInMemory: true,\n sessionId: request.requestId,\n });\n uiVrfChallenge = retryBootstrap.vrfChallenge;\n session.updateUI({ vrfChallenge: uiVrfChallenge });\n\n credential = await tryCreate(nextDeviceNumber);\n } else {\n console.error('[RegistrationFlow] credentials.create failed (non-duplicate)', { name, msg });\n throw err;\n }\n }\n\n // We require registration credentials to include dual PRF outputs (first + second)\n // so VRF/NEAR key derivation can happen inside the workers without passing PRF outputs\n // as separate main-thread values.\n const serialized: WebAuthnRegistrationCredential = isSerializedRegistrationCredential(credential)\n ? (credential as unknown as WebAuthnRegistrationCredential)\n : serializeRegistrationCredentialWithPRF({\n credential: credential! as PublicKeyCredential,\n firstPrfOutput: true,\n secondPrfOutput: true,\n });\n\n // 6) Respond + close\n session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: true,\n credential: serialized,\n // PRF outputs are embedded in serialized credential; VRF worker extracts and sends via MessagePort\n vrfChallenge: uiVrfChallenge,\n transactionContext,\n });\n } catch (err: unknown) {\n\n const cancelled = isUserCancelledSecureConfirm(err);\n const msg = String((toError(err))?.message || err || '');\n if (cancelled) {\n window.parent?.postMessage({ type: 'WALLET_UI_CLOSED' }, '*');\n }\n\n const isPrfBrowserUnsupported =\n /WebAuthn PRF output is missing from navigator\\.credentials\\.create\\(\\)/i.test(msg)\n || /does not fully support the WebAuthn PRF extension during registration/i.test(msg)\n || /roaming hardware authenticators .* not supported in this flow/i.test(msg);\n\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: cancelled\n ? ERROR_MESSAGES.cancelled\n : (isPrfBrowserUnsupported ? msg : (msg || ERROR_MESSAGES.collectCredentialsFailed)),\n });\n }\n}\n"],"mappings":"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"}
@@ -26,91 +26,91 @@ async function handleTransactionSigningFlow(ctx, request, worker, opts) {
26
26
  transactionSummary
27
27
  });
28
28
  const nearAccountId = getNearAccountId(request);
29
- const signingAuthMode = getSigningAuthMode(request);
30
- const usesNeeded = getTxCount(request);
31
- const vrfIntentDigestB64u = request.type === SecureConfirmationType.SIGN_TRANSACTION ? getIntentDigest(request) : request.type === SecureConfirmationType.SIGN_NEP413_MESSAGE ? await computeUiIntentDigestFromNep413({
32
- nearAccountId,
33
- recipient: request.payload.recipient,
34
- message: request.payload.message
35
- }) : void 0;
36
- const sessionPolicyDigest32 = request.payload.sessionPolicyDigest32;
37
- const nearRpc = await adapters.near.fetchNearContext({
38
- nearAccountId,
39
- txCount: usesNeeded,
40
- reserveNonces: true
41
- });
42
- if (!nearRpc.transactionContext) {
43
- console.error("[SigningFlow] fetchNearContext failed", {
44
- error: nearRpc.error,
45
- details: nearRpc.details
46
- });
47
- return session.confirmAndCloseModal({
48
- requestId: request.requestId,
49
- intentDigest: getIntentDigest(request),
50
- confirmed: false,
51
- error: nearRpc.details ? `${ERROR_MESSAGES.nearRpcFailed}: ${nearRpc.details}` : ERROR_MESSAGES.nearRpcFailed
29
+ try {
30
+ const signingAuthMode = getSigningAuthMode(request);
31
+ const usesNeeded = getTxCount(request);
32
+ const vrfIntentDigestB64u = request.type === SecureConfirmationType.SIGN_TRANSACTION ? getIntentDigest(request) : request.type === SecureConfirmationType.SIGN_NEP413_MESSAGE ? await computeUiIntentDigestFromNep413({
33
+ nearAccountId,
34
+ recipient: request.payload.recipient,
35
+ message: request.payload.message
36
+ }) : void 0;
37
+ const sessionPolicyDigest32 = request.payload.sessionPolicyDigest32;
38
+ const nearRpc = await adapters.near.fetchNearContext({
39
+ nearAccountId,
40
+ txCount: usesNeeded,
41
+ reserveNonces: true
52
42
  });
53
- }
54
- session.setReservedNonces(nearRpc.reservedNonces);
55
- let transactionContext = nearRpc.transactionContext;
56
- const rpId = adapters.vrf.getRpId();
57
- let uiVrfChallenge;
58
- let uiVrfChallengeForUi = rpId ? {
59
- userId: nearAccountId,
60
- rpId,
61
- blockHeight: transactionContext.txBlockHeight,
62
- blockHash: transactionContext.txBlockHash
63
- } : void 0;
64
- if (signingAuthMode === "webauthn") {
65
- uiVrfChallenge = await adapters.vrf.generateVrfChallengeForSession({
66
- userId: nearAccountId,
67
- rpId,
68
- blockHeight: transactionContext.txBlockHeight,
69
- blockHash: transactionContext.txBlockHash,
70
- ...vrfIntentDigestB64u ? { intentDigest: vrfIntentDigestB64u } : {},
71
- ...sessionPolicyDigest32 ? { sessionPolicyDigest32 } : {}
72
- }, request.requestId);
73
- uiVrfChallengeForUi = uiVrfChallenge;
74
- }
75
- const { confirmed, error: uiError } = await session.promptUser({ vrfChallenge: uiVrfChallengeForUi });
76
- if (!confirmed) return session.confirmAndCloseModal({
77
- requestId: request.requestId,
78
- intentDigest: getIntentDigest(request),
79
- confirmed: false,
80
- error: uiError
81
- });
82
- if (signingAuthMode === "warmSession") {
83
- try {
84
- await adapters.vrf.dispenseSessionKey({
85
- sessionId: request.requestId,
86
- uses: usesNeeded
43
+ if (!nearRpc.transactionContext) {
44
+ console.error("[SigningFlow] fetchNearContext failed", {
45
+ error: nearRpc.error,
46
+ details: nearRpc.details
87
47
  });
88
- } catch (err) {
89
- const msg = String(toError(err)?.message || err || "");
90
48
  return session.confirmAndCloseModal({
91
49
  requestId: request.requestId,
92
50
  intentDigest: getIntentDigest(request),
93
51
  confirmed: false,
94
- error: msg || "Failed to dispense warm session key"
52
+ error: nearRpc.details ? `${ERROR_MESSAGES.nearRpcFailed}: ${nearRpc.details}` : ERROR_MESSAGES.nearRpcFailed
95
53
  });
96
54
  }
97
- session.confirmAndCloseModal({
55
+ session.setReservedNonces(nearRpc.reservedNonces);
56
+ let transactionContext = nearRpc.transactionContext;
57
+ const rpId = adapters.vrf.getRpId();
58
+ let uiVrfChallenge;
59
+ let uiVrfChallengeForUi = rpId ? {
60
+ userId: nearAccountId,
61
+ rpId,
62
+ blockHeight: transactionContext.txBlockHeight,
63
+ blockHash: transactionContext.txBlockHash
64
+ } : void 0;
65
+ if (signingAuthMode === "webauthn") {
66
+ uiVrfChallenge = await adapters.vrf.generateVrfChallengeForSession({
67
+ userId: nearAccountId,
68
+ rpId,
69
+ blockHeight: transactionContext.txBlockHeight,
70
+ blockHash: transactionContext.txBlockHash,
71
+ ...vrfIntentDigestB64u ? { intentDigest: vrfIntentDigestB64u } : {},
72
+ ...sessionPolicyDigest32 ? { sessionPolicyDigest32 } : {}
73
+ }, request.requestId);
74
+ uiVrfChallengeForUi = uiVrfChallenge;
75
+ }
76
+ const { confirmed, error: uiError } = await session.promptUser({ vrfChallenge: uiVrfChallengeForUi });
77
+ if (!confirmed) return session.confirmAndCloseModal({
98
78
  requestId: request.requestId,
99
79
  intentDigest: getIntentDigest(request),
100
- confirmed: true,
101
- transactionContext
80
+ confirmed: false,
81
+ error: uiError
102
82
  });
103
- return;
104
- }
105
- try {
106
- const refreshed = await adapters.vrf.maybeRefreshVrfChallenge(request, nearAccountId);
107
- uiVrfChallenge = refreshed.vrfChallenge;
108
- transactionContext = refreshed.transactionContext;
109
- session.updateUI({ vrfChallenge: uiVrfChallenge });
110
- } catch (e) {
111
- console.debug("[SigningFlow] VRF JIT refresh skipped", e);
112
- }
113
- try {
83
+ if (signingAuthMode === "warmSession") {
84
+ try {
85
+ await adapters.vrf.dispenseSessionKey({
86
+ sessionId: request.requestId,
87
+ uses: usesNeeded
88
+ });
89
+ } catch (err) {
90
+ const msg = String(toError(err)?.message || err || "");
91
+ return session.confirmAndCloseModal({
92
+ requestId: request.requestId,
93
+ intentDigest: getIntentDigest(request),
94
+ confirmed: false,
95
+ error: msg || "Failed to dispense warm session key"
96
+ });
97
+ }
98
+ session.confirmAndCloseModal({
99
+ requestId: request.requestId,
100
+ intentDigest: getIntentDigest(request),
101
+ confirmed: true,
102
+ transactionContext
103
+ });
104
+ return;
105
+ }
106
+ try {
107
+ const refreshed = await adapters.vrf.maybeRefreshVrfChallenge(request, nearAccountId);
108
+ uiVrfChallenge = refreshed.vrfChallenge;
109
+ transactionContext = refreshed.transactionContext;
110
+ session.updateUI({ vrfChallenge: uiVrfChallenge });
111
+ } catch (e) {
112
+ console.debug("[SigningFlow] VRF JIT refresh skipped", e);
113
+ }
114
114
  if (!uiVrfChallenge) throw new Error("Missing vrfChallenge for WebAuthn signing flow");
115
115
  const serializedCredential = await adapters.webauthn.collectAuthenticationCredentialWithPRF({
116
116
  nearAccountId,
@@ -158,7 +158,6 @@ async function handleTransactionSigningFlow(ctx, request, worker, opts) {
158
158
  } catch (err) {
159
159
  const cancelled = isUserCancelledSecureConfirm(err);
160
160
  const msg = String(toError(err)?.message || err || "");
161
- if (/Missing PRF result/i.test(msg) || /Missing PRF results/i.test(msg)) return session.cleanupAndRethrow(err);
162
161
  if (cancelled) window.parent?.postMessage({ type: "WALLET_UI_CLOSED" }, "*");
163
162
  const isWrongPasskeyError = /multiple passkeys \(devicenumbers\) for account/i.test(msg);
164
163
  return session.confirmAndCloseModal({
@@ -1 +1 @@
1
- {"version":3,"file":"transactions.js","names":["transactionContext: TransactionContext","uiVrfChallenge: VRFChallenge | undefined","uiVrfChallengeForUi: Partial<VRFChallenge> | undefined","err: unknown","contractId: string | undefined","nearRpcUrl: string | undefined"],"sources":["../../../../../../../src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.ts"],"sourcesContent":["import type { VrfWorkerManagerContext } from '../../';\nimport type { ConfirmationConfig } from '../../../../types/signer-worker';\nimport {\n SecureConfirmationType,\n TransactionSummary,\n SigningSecureConfirmRequest,\n SigningAuthMode,\n} from '../types';\nimport { VRFChallenge, TransactionContext } from '../../../../types';\nimport {\n getNearAccountId,\n getIntentDigest,\n getTxCount,\n isUserCancelledSecureConfirm,\n ERROR_MESSAGES,\n getSignTransactionPayload,\n} from './index';\nimport { toAccountId } from '../../../../types/accountIds';\nimport { getLastLoggedInDeviceNumber } from '../../../SignerWorkerManager/getDeviceNumber';\nimport { toError } from '../../../../../utils/errors';\nimport { PASSKEY_MANAGER_DEFAULT_CONFIGS } from '../../../../defaultConfigs';\nimport { createConfirmSession } from '../adapters/session';\nimport { createConfirmTxFlowAdapters } from '../adapters/createAdapters';\nimport { computeUiIntentDigestFromNep413 } from '../../../../digests/intentDigest';\n\nfunction getSigningAuthMode(request: SigningSecureConfirmRequest): SigningAuthMode {\n if (request.type === SecureConfirmationType.SIGN_TRANSACTION) {\n return getSignTransactionPayload(request).signingAuthMode ?? 'webauthn';\n }\n if (request.type === SecureConfirmationType.SIGN_NEP413_MESSAGE) {\n return request.payload.signingAuthMode ?? 'webauthn';\n }\n return 'webauthn';\n}\n\nexport async function handleTransactionSigningFlow(\n ctx: VrfWorkerManagerContext,\n request: SigningSecureConfirmRequest,\n worker: Worker,\n opts: { confirmationConfig: ConfirmationConfig; transactionSummary: TransactionSummary },\n): Promise<void> {\n const { confirmationConfig, transactionSummary } = opts;\n const adapters = createConfirmTxFlowAdapters(ctx);\n const session = createConfirmSession({\n adapters,\n worker,\n request,\n confirmationConfig,\n transactionSummary,\n });\n const nearAccountId = getNearAccountId(request);\n const signingAuthMode = getSigningAuthMode(request);\n const usesNeeded = getTxCount(request);\n const vrfIntentDigestB64u = request.type === SecureConfirmationType.SIGN_TRANSACTION\n ? getIntentDigest(request)\n : request.type === SecureConfirmationType.SIGN_NEP413_MESSAGE\n ? await computeUiIntentDigestFromNep413({\n nearAccountId,\n recipient: request.payload.recipient,\n message: request.payload.message,\n })\n : undefined;\n const sessionPolicyDigest32 = request.payload.sessionPolicyDigest32;\n\n // 1) NEAR context + nonce reservation\n const nearRpc = await adapters.near.fetchNearContext({ nearAccountId, txCount: usesNeeded, reserveNonces: true });\n if (!nearRpc.transactionContext) {\n // eslint-disable-next-line no-console\n console.error('[SigningFlow] fetchNearContext failed', { error: nearRpc.error, details: nearRpc.details });\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: nearRpc.details ? `${ERROR_MESSAGES.nearRpcFailed}: ${nearRpc.details}` : ERROR_MESSAGES.nearRpcFailed,\n });\n }\n session.setReservedNonces(nearRpc.reservedNonces);\n let transactionContext: TransactionContext = nearRpc.transactionContext;\n\n // 2) Security context shown in the confirmer (rpId + block height).\n // For warmSession signing we still want to show this context even though\n // we won't collect a WebAuthn credential.\n const rpId = adapters.vrf.getRpId();\n let uiVrfChallenge: VRFChallenge | undefined;\n let uiVrfChallengeForUi: Partial<VRFChallenge> | undefined = rpId\n ? {\n userId: nearAccountId,\n rpId,\n blockHeight: transactionContext.txBlockHeight,\n blockHash: transactionContext.txBlockHash,\n }\n : undefined;\n\n // Initial VRF challenge (only needed for WebAuthn credential collection)\n if (signingAuthMode === 'webauthn') {\n uiVrfChallenge = await adapters.vrf.generateVrfChallengeForSession(\n {\n userId: nearAccountId,\n rpId,\n blockHeight: transactionContext.txBlockHeight,\n blockHash: transactionContext.txBlockHash,\n ...(vrfIntentDigestB64u ? { intentDigest: vrfIntentDigestB64u } : {}),\n ...(sessionPolicyDigest32 ? { sessionPolicyDigest32 } : {}),\n },\n request.requestId,\n );\n uiVrfChallengeForUi = uiVrfChallenge;\n }\n\n // 3) UI confirm\n const { confirmed, error: uiError } = await session.promptUser({ vrfChallenge: uiVrfChallengeForUi });\n if (!confirmed) {\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: uiError,\n });\n }\n\n // 4) Warm session: dispense WrapKeySeed and skip WebAuthn\n if (signingAuthMode === 'warmSession') {\n try {\n await adapters.vrf.dispenseSessionKey({ sessionId: request.requestId, uses: usesNeeded });\n } catch (err: unknown) {\n const msg = String((toError(err))?.message || err || '');\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: msg || 'Failed to dispense warm session key',\n });\n }\n\n session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: true,\n transactionContext,\n });\n return;\n }\n\n // 5) JIT refresh VRF + ctx (best-effort)\n try {\n const refreshed = await adapters.vrf.maybeRefreshVrfChallenge(request, nearAccountId);\n uiVrfChallenge = refreshed.vrfChallenge;\n transactionContext = refreshed.transactionContext;\n session.updateUI({ vrfChallenge: uiVrfChallenge });\n } catch (e) {\n console.debug('[SigningFlow] VRF JIT refresh skipped', e);\n }\n\n // 6) Collect authentication credential\n try {\n if (!uiVrfChallenge) {\n throw new Error('Missing vrfChallenge for WebAuthn signing flow');\n }\n const serializedCredential = await adapters.webauthn.collectAuthenticationCredentialWithPRF({\n nearAccountId,\n vrfChallenge: uiVrfChallenge,\n });\n\n // 5c) Derive WrapKeySeed inside the VRF worker and deliver it to the signer worker via\n // the reserved WrapKeySeed MessagePort. Main thread only sees wrapKeySalt metadata.\n let contractId: string | undefined;\n let nearRpcUrl: string | undefined;\n try {\n // Ensure VRF session is active and bound to the same account we are signing for.\n const vrfStatus = await adapters.vrf.checkVrfStatus();\n if (!vrfStatus.active) {\n throw new Error('VRF keypair not active in memory. VRF session may have expired or was not properly initialized. Please refresh and try again.');\n }\n if (!vrfStatus.nearAccountId || String(vrfStatus.nearAccountId) !== String(toAccountId(nearAccountId))) {\n throw new Error('VRF session is active but bound to a different account than the one being signed. Please log in again on this device.');\n }\n\n const deviceNumber = await getLastLoggedInDeviceNumber(toAccountId(nearAccountId), ctx.indexedDB.clientDB);\n const keyMaterial = await ctx.indexedDB.nearKeysDB.getLocalKeyMaterial(nearAccountId, deviceNumber);\n if (!keyMaterial) {\n throw new Error(`No key material found for account ${nearAccountId} device ${deviceNumber}`);\n }\n const wrapKeySalt = keyMaterial.wrapKeySalt;\n if (!wrapKeySalt) {\n throw new Error('Missing wrapKeySalt in vault; re-register to upgrade vault format.');\n }\n\n // Extract contract verification context when available.\n // - SIGN_TRANSACTION: use per-request rpcCall (already normalized by caller).\n // - SIGN_NEP413_MESSAGE: allow per-request override; fall back to PASSKEY_MANAGER_DEFAULT_CONFIGS.\n if (request.type === SecureConfirmationType.SIGN_TRANSACTION) {\n const payload = getSignTransactionPayload(request);\n contractId = payload?.rpcCall?.contractId;\n nearRpcUrl = payload?.rpcCall?.nearRpcUrl;\n } else if (request.type === SecureConfirmationType.SIGN_NEP413_MESSAGE) {\n const payload = request.payload;\n contractId = payload.contractId || PASSKEY_MANAGER_DEFAULT_CONFIGS.contractId;\n nearRpcUrl = payload.nearRpcUrl || PASSKEY_MANAGER_DEFAULT_CONFIGS.nearRpcUrl;\n }\n\n await adapters.vrf.mintSessionKeysAndSendToSigner({\n sessionId: request.requestId,\n wrapKeySalt,\n contractId,\n nearRpcUrl,\n credential: serializedCredential,\n });\n\t } catch (err) {\n\t console.error('[SigningFlow] WrapKeySeed derivation failed:', err);\n\t throw err; // Don't silently ignore - propagate the error\n\t }\n\n // 6) Respond; keep nonces reserved for worker to use\n session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: true,\n credential: serializedCredential,\n // prfOutput intentionally omitted to keep signer PRF-free\n // WrapKeySeed travels only over the dedicated VRF→Signer MessagePort; do not echo in the main-thread envelope\n vrfChallenge: uiVrfChallenge,\n transactionContext,\n });\n } catch (err: unknown) {\n // Treat TouchID/FaceID cancellation and related errors as a negative decision\n const cancelled = isUserCancelledSecureConfirm(err);\n // For missing PRF outputs, surface the error to caller (defensive path tests expect a throw)\n const msg = String((toError(err))?.message || err || '');\n if (/Missing PRF result/i.test(msg) || /Missing PRF results/i.test(msg)) {\n // Ensure UI is closed and nonces released, then rethrow\n return session.cleanupAndRethrow(err);\n }\n if (cancelled) {\n window.parent?.postMessage({ type: 'WALLET_UI_CLOSED' }, '*');\n }\n const isWrongPasskeyError = /multiple passkeys \\(devicenumbers\\) for account/i.test(msg);\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: cancelled\n ? ERROR_MESSAGES.cancelled\n : (isWrongPasskeyError ? msg : (msg || ERROR_MESSAGES.collectCredentialsFailed)),\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"transactions.js","names":["transactionContext: TransactionContext","uiVrfChallenge: VRFChallenge | undefined","uiVrfChallengeForUi: Partial<VRFChallenge> | undefined","err: unknown","contractId: string | undefined","nearRpcUrl: string | undefined"],"sources":["../../../../../../../src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.ts"],"sourcesContent":["import type { VrfWorkerManagerContext } from '../../';\nimport type { ConfirmationConfig } from '../../../../types/signer-worker';\nimport {\n SecureConfirmationType,\n TransactionSummary,\n SigningSecureConfirmRequest,\n SigningAuthMode,\n} from '../types';\nimport { VRFChallenge, TransactionContext } from '../../../../types';\nimport {\n getNearAccountId,\n getIntentDigest,\n getTxCount,\n isUserCancelledSecureConfirm,\n ERROR_MESSAGES,\n getSignTransactionPayload,\n} from './index';\nimport { toAccountId } from '../../../../types/accountIds';\nimport { getLastLoggedInDeviceNumber } from '../../../SignerWorkerManager/getDeviceNumber';\nimport { toError } from '../../../../../utils/errors';\nimport { PASSKEY_MANAGER_DEFAULT_CONFIGS } from '../../../../defaultConfigs';\nimport { createConfirmSession } from '../adapters/session';\nimport { createConfirmTxFlowAdapters } from '../adapters/createAdapters';\nimport { computeUiIntentDigestFromNep413 } from '../../../../digests/intentDigest';\n\nfunction getSigningAuthMode(request: SigningSecureConfirmRequest): SigningAuthMode {\n if (request.type === SecureConfirmationType.SIGN_TRANSACTION) {\n return getSignTransactionPayload(request).signingAuthMode ?? 'webauthn';\n }\n if (request.type === SecureConfirmationType.SIGN_NEP413_MESSAGE) {\n return request.payload.signingAuthMode ?? 'webauthn';\n }\n return 'webauthn';\n}\n\nexport async function handleTransactionSigningFlow(\n ctx: VrfWorkerManagerContext,\n request: SigningSecureConfirmRequest,\n worker: Worker,\n opts: { confirmationConfig: ConfirmationConfig; transactionSummary: TransactionSummary },\n): Promise<void> {\n const { confirmationConfig, transactionSummary } = opts;\n const adapters = createConfirmTxFlowAdapters(ctx);\n const session = createConfirmSession({\n adapters,\n worker,\n request,\n confirmationConfig,\n transactionSummary,\n });\n const nearAccountId = getNearAccountId(request);\n try {\n const signingAuthMode = getSigningAuthMode(request);\n const usesNeeded = getTxCount(request);\n const vrfIntentDigestB64u = request.type === SecureConfirmationType.SIGN_TRANSACTION\n ? getIntentDigest(request)\n : request.type === SecureConfirmationType.SIGN_NEP413_MESSAGE\n ? await computeUiIntentDigestFromNep413({\n nearAccountId,\n recipient: request.payload.recipient,\n message: request.payload.message,\n })\n : undefined;\n const sessionPolicyDigest32 = request.payload.sessionPolicyDigest32;\n\n // 1) NEAR context + nonce reservation\n const nearRpc = await adapters.near.fetchNearContext({ nearAccountId, txCount: usesNeeded, reserveNonces: true });\n if (!nearRpc.transactionContext) {\n // eslint-disable-next-line no-console\n console.error('[SigningFlow] fetchNearContext failed', { error: nearRpc.error, details: nearRpc.details });\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: nearRpc.details ? `${ERROR_MESSAGES.nearRpcFailed}: ${nearRpc.details}` : ERROR_MESSAGES.nearRpcFailed,\n });\n }\n session.setReservedNonces(nearRpc.reservedNonces);\n let transactionContext: TransactionContext = nearRpc.transactionContext;\n\n // 2) Security context shown in the confirmer (rpId + block height).\n // For warmSession signing we still want to show this context even though\n // we won't collect a WebAuthn credential.\n const rpId = adapters.vrf.getRpId();\n let uiVrfChallenge: VRFChallenge | undefined;\n let uiVrfChallengeForUi: Partial<VRFChallenge> | undefined = rpId\n ? {\n userId: nearAccountId,\n rpId,\n blockHeight: transactionContext.txBlockHeight,\n blockHash: transactionContext.txBlockHash,\n }\n : undefined;\n\n // Initial VRF challenge (only needed for WebAuthn credential collection)\n if (signingAuthMode === 'webauthn') {\n uiVrfChallenge = await adapters.vrf.generateVrfChallengeForSession(\n {\n userId: nearAccountId,\n rpId,\n blockHeight: transactionContext.txBlockHeight,\n blockHash: transactionContext.txBlockHash,\n ...(vrfIntentDigestB64u ? { intentDigest: vrfIntentDigestB64u } : {}),\n ...(sessionPolicyDigest32 ? { sessionPolicyDigest32 } : {}),\n },\n request.requestId,\n );\n uiVrfChallengeForUi = uiVrfChallenge;\n }\n\n // 3) UI confirm\n const { confirmed, error: uiError } = await session.promptUser({ vrfChallenge: uiVrfChallengeForUi });\n if (!confirmed) {\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: uiError,\n });\n }\n\n // 4) Warm session: dispense WrapKeySeed and skip WebAuthn\n if (signingAuthMode === 'warmSession') {\n try {\n await adapters.vrf.dispenseSessionKey({ sessionId: request.requestId, uses: usesNeeded });\n } catch (err: unknown) {\n const msg = String((toError(err))?.message || err || '');\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: msg || 'Failed to dispense warm session key',\n });\n }\n\n session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: true,\n transactionContext,\n });\n return;\n }\n\n // 5) JIT refresh VRF + ctx (best-effort)\n try {\n const refreshed = await adapters.vrf.maybeRefreshVrfChallenge(request, nearAccountId);\n uiVrfChallenge = refreshed.vrfChallenge;\n transactionContext = refreshed.transactionContext;\n session.updateUI({ vrfChallenge: uiVrfChallenge });\n } catch (e) {\n console.debug('[SigningFlow] VRF JIT refresh skipped', e);\n }\n\n // 6) Collect authentication credential\n if (!uiVrfChallenge) {\n throw new Error('Missing vrfChallenge for WebAuthn signing flow');\n }\n const serializedCredential = await adapters.webauthn.collectAuthenticationCredentialWithPRF({\n nearAccountId,\n vrfChallenge: uiVrfChallenge,\n });\n\n // 5c) Derive WrapKeySeed inside the VRF worker and deliver it to the signer worker via\n // the reserved WrapKeySeed MessagePort. Main thread only sees wrapKeySalt metadata.\n let contractId: string | undefined;\n let nearRpcUrl: string | undefined;\n try {\n // Ensure VRF session is active and bound to the same account we are signing for.\n const vrfStatus = await adapters.vrf.checkVrfStatus();\n if (!vrfStatus.active) {\n throw new Error('VRF keypair not active in memory. VRF session may have expired or was not properly initialized. Please refresh and try again.');\n }\n if (!vrfStatus.nearAccountId || String(vrfStatus.nearAccountId) !== String(toAccountId(nearAccountId))) {\n throw new Error('VRF session is active but bound to a different account than the one being signed. Please log in again on this device.');\n }\n\n const deviceNumber = await getLastLoggedInDeviceNumber(toAccountId(nearAccountId), ctx.indexedDB.clientDB);\n const keyMaterial = await ctx.indexedDB.nearKeysDB.getLocalKeyMaterial(nearAccountId, deviceNumber);\n if (!keyMaterial) {\n throw new Error(`No key material found for account ${nearAccountId} device ${deviceNumber}`);\n }\n const wrapKeySalt = keyMaterial.wrapKeySalt;\n if (!wrapKeySalt) {\n throw new Error('Missing wrapKeySalt in vault; re-register to upgrade vault format.');\n }\n\n // Extract contract verification context when available.\n // - SIGN_TRANSACTION: use per-request rpcCall (already normalized by caller).\n // - SIGN_NEP413_MESSAGE: allow per-request override; fall back to PASSKEY_MANAGER_DEFAULT_CONFIGS.\n if (request.type === SecureConfirmationType.SIGN_TRANSACTION) {\n const payload = getSignTransactionPayload(request);\n contractId = payload?.rpcCall?.contractId;\n nearRpcUrl = payload?.rpcCall?.nearRpcUrl;\n } else if (request.type === SecureConfirmationType.SIGN_NEP413_MESSAGE) {\n const payload = request.payload;\n contractId = payload.contractId || PASSKEY_MANAGER_DEFAULT_CONFIGS.contractId;\n nearRpcUrl = payload.nearRpcUrl || PASSKEY_MANAGER_DEFAULT_CONFIGS.nearRpcUrl;\n }\n\n await adapters.vrf.mintSessionKeysAndSendToSigner({\n sessionId: request.requestId,\n wrapKeySalt,\n contractId,\n nearRpcUrl,\n credential: serializedCredential,\n });\n\t } catch (err) {\n\t console.error('[SigningFlow] WrapKeySeed derivation failed:', err);\n\t throw err; // Don't silently ignore - propagate the error\n\t }\n\n // 6) Respond; keep nonces reserved for worker to use\n session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: true,\n credential: serializedCredential,\n // prfOutput intentionally omitted to keep signer PRF-free\n // WrapKeySeed travels only over the dedicated VRF→Signer MessagePort; do not echo in the main-thread envelope\n vrfChallenge: uiVrfChallenge,\n transactionContext,\n });\n } catch (err: unknown) {\n // Treat TouchID/FaceID cancellation and related errors as a negative decision\n const cancelled = isUserCancelledSecureConfirm(err);\n const msg = String((toError(err))?.message || err || '');\n if (cancelled) {\n window.parent?.postMessage({ type: 'WALLET_UI_CLOSED' }, '*');\n }\n const isWrongPasskeyError = /multiple passkeys \\(devicenumbers\\) for account/i.test(msg);\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: cancelled\n ? ERROR_MESSAGES.cancelled\n : (isWrongPasskeyError ? msg : (msg || ERROR_MESSAGES.collectCredentialsFailed)),\n });\n }\n}\n"],"mappings":"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"}
@@ -51,13 +51,23 @@ async function handlePromptUserConfirmInJsMainThread(ctx, message, worker) {
51
51
  });
52
52
  return;
53
53
  }
54
- await handler({
55
- ctx,
56
- request,
57
- worker,
58
- confirmationConfig,
59
- transactionSummary
60
- });
54
+ try {
55
+ await handler({
56
+ ctx,
57
+ request,
58
+ worker,
59
+ confirmationConfig,
60
+ transactionSummary
61
+ });
62
+ } catch (e) {
63
+ console.error("[SecureConfirm][Host] handler failed", e);
64
+ sendConfirmResponse(worker, {
65
+ requestId: request.requestId,
66
+ intentDigest: getIntentDigest(request),
67
+ confirmed: false,
68
+ error: errorMessage(e) || "Secure confirmation failed"
69
+ });
70
+ }
61
71
  }
62
72
  async function importFlow(label, loader) {
63
73
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"handleSecureConfirmRequest.js","names":["request: SecureConfirmRequest","confirmationConfig: ConfirmationConfig","transactionSummary: TransactionSummary","e: unknown","_err: unknown","HANDLERS: Partial<Record<SecureConfirmationType, Handler>>"],"sources":["../../../../../../src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.ts"],"sourcesContent":["import type { VrfWorkerManagerContext } from '../';\nimport type { ConfirmationConfig } from '../../../types/signer-worker';\nimport { determineConfirmationConfig } from './determineConfirmationConfig';\nimport {\n TransactionSummary,\n SecureConfirmMessageType,\n SecureConfirmRequest,\n SecureConfirmationType,\n} from './types';\nimport { errorMessage, toError } from '../../../../utils/errors';\nimport {\n parseTransactionSummary,\n getIntentDigest,\n sendConfirmResponse,\n sanitizeForPostMessage,\n} from './flows';\nimport {\n assertNoForbiddenMainThreadSigningSecrets,\n validateSecureConfirmRequest,\n} from './adapters/requestAdapter';\nimport type {\n LocalOnlySecureConfirmRequest,\n RegistrationSecureConfirmRequest,\n SigningSecureConfirmRequest,\n} from './types';\n\n/**\n * Handles secure confirmation requests from the worker with robust error handling\n * => SecureConfirmMessageType.PROMPT_USER_CONFIRM_IN_JS_MAIN_THREAD\n * and proper data validation. Supports both transaction and registration confirmation flows.\n */\nexport async function handlePromptUserConfirmInJsMainThread(\n ctx: VrfWorkerManagerContext,\n message: {\n type: SecureConfirmMessageType.PROMPT_USER_CONFIRM_IN_JS_MAIN_THREAD,\n data: SecureConfirmRequest,\n },\n worker: Worker\n): Promise<void> {\n\n // 1. Validate and parse request\n let request: SecureConfirmRequest;\n let confirmationConfig: ConfirmationConfig;\n let transactionSummary: TransactionSummary;\n\n try {\n\n request = validateSecureConfirmRequest(message.data);\n assertNoForbiddenMainThreadSigningSecrets(request);\n confirmationConfig = determineConfirmationConfig(ctx, request);\n\n const parsedSummary = parseTransactionSummary(request.summary);\n const intentDigest = getIntentDigest(request);\n\n transactionSummary = sanitizeForPostMessage({\n ...parsedSummary,\n ...(intentDigest ? { intentDigest } : {}),\n }) as TransactionSummary;\n\n } catch (e: unknown) {\n\n console.error('[SecureConfirm][Host] validateAndParseRequest failed', e);\n // Attempt to send a structured error back to the worker to avoid hard failure\n try {\n const rid = (message?.data as any)?.requestId;\n if (typeof rid === 'string' && rid) {\n sendConfirmResponse(worker, {\n requestId: rid,\n confirmed: false,\n error: errorMessage(e) || 'Invalid secure confirm request',\n });\n return;\n }\n } catch (_err: unknown) {\n throw toError(e);\n }\n throw toError(e);\n }\n\n const handler = HANDLERS[request.type];\n if (!handler) {\n // Unsupported type fallback: return structured error to worker.\n sendConfirmResponse(worker, {\n requestId: request.requestId,\n confirmed: false,\n error: 'Unsupported secure confirmation type'\n });\n return;\n }\n\n await handler({ ctx, request, worker, confirmationConfig, transactionSummary });\n}\n\ntype HandlerArgs = {\n ctx: VrfWorkerManagerContext;\n request: SecureConfirmRequest;\n worker: Worker;\n confirmationConfig: ConfirmationConfig;\n transactionSummary: TransactionSummary;\n};\n\ntype Handler = (args: HandlerArgs) => Promise<void>;\n\nasync function importFlow<T>(label: string, loader: () => Promise<T>): Promise<T> {\n try {\n return await loader();\n } catch (e) {\n console.error(`[SecureConfirm][Host] failed to import ${label} flow module`, e);\n throw e;\n }\n}\n\nconst HANDLERS: Partial<Record<SecureConfirmationType, Handler>> = {\n [SecureConfirmationType.DECRYPT_PRIVATE_KEY_WITH_PRF]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleLocalOnlyFlow } = await importFlow('localOnly', () => import('./flows/localOnly'));\n await handleLocalOnlyFlow(ctx, request as LocalOnlySecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.SHOW_SECURE_PRIVATE_KEY_UI]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleLocalOnlyFlow } = await importFlow('localOnly', () => import('./flows/localOnly'));\n await handleLocalOnlyFlow(ctx, request as LocalOnlySecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.REGISTER_ACCOUNT]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleRegistrationFlow } = await importFlow('registration', () => import('./flows/registration'));\n await handleRegistrationFlow(ctx, request as RegistrationSecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.LINK_DEVICE]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleRegistrationFlow } = await importFlow('registration', () => import('./flows/registration'));\n await handleRegistrationFlow(ctx, request as RegistrationSecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.SIGN_TRANSACTION]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleTransactionSigningFlow } = await importFlow('transactions', () => import('./flows/transactions'));\n await handleTransactionSigningFlow(ctx, request as SigningSecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.SIGN_NEP413_MESSAGE]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleTransactionSigningFlow } = await importFlow('transactions', () => import('./flows/transactions'));\n await handleTransactionSigningFlow(ctx, request as SigningSecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n};\n"],"mappings":";;;;;;;;;;;;;AA+BA,eAAsB,sCACpB,KACA,SAIA,QACe;CAGf,IAAIA;CACJ,IAAIC;CACJ,IAAIC;AAEJ,KAAI;AAEF,YAAU,6BAA6B,QAAQ;AAC/C,4CAA0C;AAC1C,uBAAqB,4BAA4B,KAAK;EAEtD,MAAM,gBAAgB,wBAAwB,QAAQ;EACtD,MAAM,eAAe,gBAAgB;AAErC,uBAAqB,uBAAuB;GAC1C,GAAG;GACH,GAAI,eAAe,EAAE,iBAAiB;;UAGjCC,GAAY;AAEnB,UAAQ,MAAM,wDAAwD;AAEtE,MAAI;GACF,MAAM,OAAO,SAAS,OAAc;AACpC,OAAI,OAAO,QAAQ,YAAY,KAAK;AAClC,wBAAoB,QAAQ;KAC1B,WAAW;KACX,WAAW;KACX,OAAO,aAAa,MAAM;;AAE5B;;WAEKC,MAAe;AACtB,SAAM,QAAQ;;AAEhB,QAAM,QAAQ;;CAGhB,MAAM,UAAU,SAAS,QAAQ;AACjC,KAAI,CAAC,SAAS;AAEZ,sBAAoB,QAAQ;GAC1B,WAAW,QAAQ;GACnB,WAAW;GACX,OAAO;;AAET;;AAGF,OAAM,QAAQ;EAAE;EAAK;EAAS;EAAQ;EAAoB;;;AAa5D,eAAe,WAAc,OAAe,QAAsC;AAChF,KAAI;AACF,SAAO,MAAM;UACN,GAAG;AACV,UAAQ,MAAM,0CAA0C,MAAM,eAAe;AAC7E,QAAM;;;AAIV,MAAMC,WAA6D;EAChE,uBAAuB,+BAA+B,OAAO,EAAE,KAAK,SAAS,QAAQ,oBAAoB,yBAAyB;EACjI,MAAM,EAAE,wBAAwB,MAAM,WAAW,mBAAmB,OAAO;AAC3E,QAAM,oBAAoB,KAAK,SAA0C,QAAQ;GAAE;GAAoB;;;EAExG,uBAAuB,6BAA6B,OAAO,EAAE,KAAK,SAAS,QAAQ,oBAAoB,yBAAyB;EAC/H,MAAM,EAAE,wBAAwB,MAAM,WAAW,mBAAmB,OAAO;AAC3E,QAAM,oBAAoB,KAAK,SAA0C,QAAQ;GAAE;GAAoB;;;EAExG,uBAAuB,mBAAmB,OAAO,EAAE,KAAK,SAAS,QAAQ,oBAAoB,yBAAyB;EACrH,MAAM,EAAE,2BAA2B,MAAM,WAAW,sBAAsB,OAAO;AACjF,QAAM,uBAAuB,KAAK,SAA6C,QAAQ;GAAE;GAAoB;;;EAE9G,uBAAuB,cAAc,OAAO,EAAE,KAAK,SAAS,QAAQ,oBAAoB,yBAAyB;EAChH,MAAM,EAAE,2BAA2B,MAAM,WAAW,sBAAsB,OAAO;AACjF,QAAM,uBAAuB,KAAK,SAA6C,QAAQ;GAAE;GAAoB;;;EAE9G,uBAAuB,mBAAmB,OAAO,EAAE,KAAK,SAAS,QAAQ,oBAAoB,yBAAyB;EACrH,MAAM,EAAE,iCAAiC,MAAM,WAAW,sBAAsB,OAAO;AACvF,QAAM,6BAA6B,KAAK,SAAwC,QAAQ;GAAE;GAAoB;;;EAE/G,uBAAuB,sBAAsB,OAAO,EAAE,KAAK,SAAS,QAAQ,oBAAoB,yBAAyB;EACxH,MAAM,EAAE,iCAAiC,MAAM,WAAW,sBAAsB,OAAO;AACvF,QAAM,6BAA6B,KAAK,SAAwC,QAAQ;GAAE;GAAoB"}
1
+ {"version":3,"file":"handleSecureConfirmRequest.js","names":["request: SecureConfirmRequest","confirmationConfig: ConfirmationConfig","transactionSummary: TransactionSummary","e: unknown","_err: unknown","HANDLERS: Partial<Record<SecureConfirmationType, Handler>>"],"sources":["../../../../../../src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.ts"],"sourcesContent":["import type { VrfWorkerManagerContext } from '../';\nimport type { ConfirmationConfig } from '../../../types/signer-worker';\nimport { determineConfirmationConfig } from './determineConfirmationConfig';\nimport {\n TransactionSummary,\n SecureConfirmMessageType,\n SecureConfirmRequest,\n SecureConfirmationType,\n} from './types';\nimport { errorMessage, toError } from '../../../../utils/errors';\nimport {\n parseTransactionSummary,\n getIntentDigest,\n sendConfirmResponse,\n sanitizeForPostMessage,\n} from './flows';\nimport {\n assertNoForbiddenMainThreadSigningSecrets,\n validateSecureConfirmRequest,\n} from './adapters/requestAdapter';\nimport type {\n LocalOnlySecureConfirmRequest,\n RegistrationSecureConfirmRequest,\n SigningSecureConfirmRequest,\n} from './types';\n\n/**\n * Handles secure confirmation requests from the worker with robust error handling\n * => SecureConfirmMessageType.PROMPT_USER_CONFIRM_IN_JS_MAIN_THREAD\n * and proper data validation. Supports both transaction and registration confirmation flows.\n */\nexport async function handlePromptUserConfirmInJsMainThread(\n ctx: VrfWorkerManagerContext,\n message: {\n type: SecureConfirmMessageType.PROMPT_USER_CONFIRM_IN_JS_MAIN_THREAD,\n data: SecureConfirmRequest,\n },\n worker: Worker\n): Promise<void> {\n\n // 1. Validate and parse request\n let request: SecureConfirmRequest;\n let confirmationConfig: ConfirmationConfig;\n let transactionSummary: TransactionSummary;\n\n try {\n\n request = validateSecureConfirmRequest(message.data);\n assertNoForbiddenMainThreadSigningSecrets(request);\n confirmationConfig = determineConfirmationConfig(ctx, request);\n\n const parsedSummary = parseTransactionSummary(request.summary);\n const intentDigest = getIntentDigest(request);\n\n transactionSummary = sanitizeForPostMessage({\n ...parsedSummary,\n ...(intentDigest ? { intentDigest } : {}),\n }) as TransactionSummary;\n\n } catch (e: unknown) {\n\n console.error('[SecureConfirm][Host] validateAndParseRequest failed', e);\n // Attempt to send a structured error back to the worker to avoid hard failure\n try {\n const rid = (message?.data as any)?.requestId;\n if (typeof rid === 'string' && rid) {\n sendConfirmResponse(worker, {\n requestId: rid,\n confirmed: false,\n error: errorMessage(e) || 'Invalid secure confirm request',\n });\n return;\n }\n } catch (_err: unknown) {\n throw toError(e);\n }\n throw toError(e);\n }\n\n const handler = HANDLERS[request.type];\n if (!handler) {\n // Unsupported type fallback: return structured error to worker.\n sendConfirmResponse(worker, {\n requestId: request.requestId,\n confirmed: false,\n error: 'Unsupported secure confirmation type'\n });\n return;\n }\n\n try {\n await handler({ ctx, request, worker, confirmationConfig, transactionSummary });\n } catch (e: unknown) {\n console.error('[SecureConfirm][Host] handler failed', e);\n // Best-effort: always respond to the worker so VRF-side requests don't hang indefinitely.\n sendConfirmResponse(worker, {\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: errorMessage(e) || 'Secure confirmation failed',\n });\n }\n}\n\ntype HandlerArgs = {\n ctx: VrfWorkerManagerContext;\n request: SecureConfirmRequest;\n worker: Worker;\n confirmationConfig: ConfirmationConfig;\n transactionSummary: TransactionSummary;\n};\n\ntype Handler = (args: HandlerArgs) => Promise<void>;\n\nasync function importFlow<T>(label: string, loader: () => Promise<T>): Promise<T> {\n try {\n return await loader();\n } catch (e) {\n console.error(`[SecureConfirm][Host] failed to import ${label} flow module`, e);\n throw e;\n }\n}\n\nconst HANDLERS: Partial<Record<SecureConfirmationType, Handler>> = {\n [SecureConfirmationType.DECRYPT_PRIVATE_KEY_WITH_PRF]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleLocalOnlyFlow } = await importFlow('localOnly', () => import('./flows/localOnly'));\n await handleLocalOnlyFlow(ctx, request as LocalOnlySecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.SHOW_SECURE_PRIVATE_KEY_UI]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleLocalOnlyFlow } = await importFlow('localOnly', () => import('./flows/localOnly'));\n await handleLocalOnlyFlow(ctx, request as LocalOnlySecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.REGISTER_ACCOUNT]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleRegistrationFlow } = await importFlow('registration', () => import('./flows/registration'));\n await handleRegistrationFlow(ctx, request as RegistrationSecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.LINK_DEVICE]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleRegistrationFlow } = await importFlow('registration', () => import('./flows/registration'));\n await handleRegistrationFlow(ctx, request as RegistrationSecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.SIGN_TRANSACTION]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleTransactionSigningFlow } = await importFlow('transactions', () => import('./flows/transactions'));\n await handleTransactionSigningFlow(ctx, request as SigningSecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.SIGN_NEP413_MESSAGE]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleTransactionSigningFlow } = await importFlow('transactions', () => import('./flows/transactions'));\n await handleTransactionSigningFlow(ctx, request as SigningSecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n};\n"],"mappings":";;;;;;;;;;;;;AA+BA,eAAsB,sCACpB,KACA,SAIA,QACe;CAGf,IAAIA;CACJ,IAAIC;CACJ,IAAIC;AAEJ,KAAI;AAEF,YAAU,6BAA6B,QAAQ;AAC/C,4CAA0C;AAC1C,uBAAqB,4BAA4B,KAAK;EAEtD,MAAM,gBAAgB,wBAAwB,QAAQ;EACtD,MAAM,eAAe,gBAAgB;AAErC,uBAAqB,uBAAuB;GAC1C,GAAG;GACH,GAAI,eAAe,EAAE,iBAAiB;;UAGjCC,GAAY;AAEnB,UAAQ,MAAM,wDAAwD;AAEtE,MAAI;GACF,MAAM,OAAO,SAAS,OAAc;AACpC,OAAI,OAAO,QAAQ,YAAY,KAAK;AAClC,wBAAoB,QAAQ;KAC1B,WAAW;KACX,WAAW;KACX,OAAO,aAAa,MAAM;;AAE5B;;WAEKC,MAAe;AACtB,SAAM,QAAQ;;AAEhB,QAAM,QAAQ;;CAGhB,MAAM,UAAU,SAAS,QAAQ;AACjC,KAAI,CAAC,SAAS;AAEZ,sBAAoB,QAAQ;GAC1B,WAAW,QAAQ;GACnB,WAAW;GACX,OAAO;;AAET;;AAGF,KAAI;AACF,QAAM,QAAQ;GAAE;GAAK;GAAS;GAAQ;GAAoB;;UACnDD,GAAY;AACnB,UAAQ,MAAM,wCAAwC;AAEtD,sBAAoB,QAAQ;GAC1B,WAAW,QAAQ;GACnB,cAAc,gBAAgB;GAC9B,WAAW;GACX,OAAO,aAAa,MAAM;;;;AAehC,eAAe,WAAc,OAAe,QAAsC;AAChF,KAAI;AACF,SAAO,MAAM;UACN,GAAG;AACV,UAAQ,MAAM,0CAA0C,MAAM,eAAe;AAC7E,QAAM;;;AAIV,MAAME,WAA6D;EAChE,uBAAuB,+BAA+B,OAAO,EAAE,KAAK,SAAS,QAAQ,oBAAoB,yBAAyB;EACjI,MAAM,EAAE,wBAAwB,MAAM,WAAW,mBAAmB,OAAO;AAC3E,QAAM,oBAAoB,KAAK,SAA0C,QAAQ;GAAE;GAAoB;;;EAExG,uBAAuB,6BAA6B,OAAO,EAAE,KAAK,SAAS,QAAQ,oBAAoB,yBAAyB;EAC/H,MAAM,EAAE,wBAAwB,MAAM,WAAW,mBAAmB,OAAO;AAC3E,QAAM,oBAAoB,KAAK,SAA0C,QAAQ;GAAE;GAAoB;;;EAExG,uBAAuB,mBAAmB,OAAO,EAAE,KAAK,SAAS,QAAQ,oBAAoB,yBAAyB;EACrH,MAAM,EAAE,2BAA2B,MAAM,WAAW,sBAAsB,OAAO;AACjF,QAAM,uBAAuB,KAAK,SAA6C,QAAQ;GAAE;GAAoB;;;EAE9G,uBAAuB,cAAc,OAAO,EAAE,KAAK,SAAS,QAAQ,oBAAoB,yBAAyB;EAChH,MAAM,EAAE,2BAA2B,MAAM,WAAW,sBAAsB,OAAO;AACjF,QAAM,uBAAuB,KAAK,SAA6C,QAAQ;GAAE;GAAoB;;;EAE9G,uBAAuB,mBAAmB,OAAO,EAAE,KAAK,SAAS,QAAQ,oBAAoB,yBAAyB;EACrH,MAAM,EAAE,iCAAiC,MAAM,WAAW,sBAAsB,OAAO;AACvF,QAAM,6BAA6B,KAAK,SAAwC,QAAQ;GAAE;GAAoB;;;EAE/G,uBAAuB,sBAAsB,OAAO,EAAE,KAAK,SAAS,QAAQ,oBAAoB,yBAAyB;EACxH,MAAM,EAAE,iCAAiC,MAAM,WAAW,sBAAsB,OAAO;AACvF,QAAM,6BAA6B,KAAK,SAAwC,QAAQ;GAAE;GAAoB"}
@@ -447,13 +447,13 @@ var WebAuthnManager = class {
447
447
  /**
448
448
  * Persist refreshed server-encrypted VRF keypair in IndexedDB.
449
449
  */
450
- async updateServerEncryptedVrfKeypair(nearAccountId, serverEncrypted) {
450
+ async updateServerEncryptedVrfKeypair(nearAccountId, serverEncrypted, deviceNumber) {
451
451
  await IndexedDBManager.clientDB.updateUser(nearAccountId, { serverEncryptedVrfKeypair: {
452
452
  ciphertextVrfB64u: serverEncrypted.ciphertextVrfB64u,
453
453
  kek_s_b64u: serverEncrypted.kek_s_b64u,
454
454
  serverKeyId: serverEncrypted.serverKeyId,
455
455
  updatedAt: Date.now()
456
- } });
456
+ } }, deviceNumber);
457
457
  }
458
458
  async clearVrfSession() {
459
459
  if (typeof window !== "undefined" && this.workerBaseOrigin !== window.location.origin) return;
@@ -561,7 +561,7 @@ var WebAuthnManager = class {
561
561
  const active = status.active && status.nearAccountId === nearAccountId;
562
562
  if (!active) return false;
563
563
  const refreshed = await this.shamir3PassEncryptCurrentVrfKeypair();
564
- await this.updateServerEncryptedVrfKeypair(nearAccountId, refreshed);
564
+ await this.updateServerEncryptedVrfKeypair(nearAccountId, refreshed, userData?.deviceNumber);
565
565
  return true;
566
566
  } catch {
567
567
  return false;