@thru/passkey 0.2.27 → 0.2.29
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/dist/auth/add-device.cjs +11 -2
- package/dist/auth/add-device.cjs.map +1 -1
- package/dist/auth/add-device.d.cts +12 -2
- package/dist/auth/add-device.d.ts +12 -2
- package/dist/auth/add-device.js +3 -1
- package/dist/auth.cjs +12 -3
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +1 -1
- package/dist/auth.d.ts +1 -1
- package/dist/auth.js +4 -2
- package/dist/auth.js.map +1 -1
- package/dist/{chunk-ZNBMADOM.js → chunk-L53S4RKQ.js} +2 -2
- package/dist/chunk-L53S4RKQ.js.map +1 -0
- package/dist/{chunk-KASTJBBY.js → chunk-NFK5D7EI.js} +15 -5
- package/dist/chunk-NFK5D7EI.js.map +1 -0
- package/dist/{chunk-TW7HANJM.js → chunk-YV4LITL4.js} +40 -5
- package/dist/chunk-YV4LITL4.js.map +1 -0
- package/dist/index.cjs +39 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mobile.cjs +1 -1
- package/dist/mobile.cjs.map +1 -1
- package/dist/mobile.js +1 -1
- package/dist/popup.d.cts +2 -2
- package/dist/popup.d.ts +2 -2
- package/dist/server.cjs +2 -2
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +3 -2
- package/dist/server.js.map +1 -1
- package/dist/{types-BTTlCVrw.d.cts → types-CIzH-qtR.d.cts} +2 -0
- package/dist/{types-BTTlCVrw.d.ts → types-CIzH-qtR.d.ts} +2 -0
- package/dist/web.cjs +39 -4
- package/dist/web.cjs.map +1 -1
- package/dist/web.d.cts +2 -2
- package/dist/web.d.ts +2 -2
- package/dist/web.js +1 -1
- package/package.json +3 -3
- package/src/auth/add-device.ts +31 -3
- package/src/auth/index.ts +2 -1
- package/src/mobile/passkey.ts +1 -1
- package/src/server/create-wallet.test.ts +4 -0
- package/src/server/create-wallet.ts +3 -2
- package/src/sign.test.ts +48 -0
- package/src/sign.ts +52 -4
- package/src/types.ts +2 -0
- package/dist/chunk-KASTJBBY.js.map +0 -1
- package/dist/chunk-TW7HANJM.js.map +0 -1
- package/dist/chunk-ZNBMADOM.js.map +0 -1
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/create-wallet.ts","../src/server/utils.ts","../src/server/challenge.ts","../src/server/submit.ts","../src/server/handlers.ts"],"sourcesContent":["import {\n PASSKEY_MANAGER_PROGRAM_ADDRESS,\n base64UrlToBytes,\n buildAccountContext,\n createCredentialLookupSeed,\n createWalletSeed,\n deriveCredentialLookupAddress,\n deriveWalletAddress,\n encodeCreateInstruction,\n encodeRegisterCredentialInstruction,\n} from '@thru/programs/passkey-manager';\nimport {\n toThruAddress,\n getStateProof,\n trackTransaction,\n withSerializedFeePayer,\n} from \"./utils\";\nimport type { ThruClient } from \"./types\";\n\nexport async function createPasskeyWallet(opts: {\n client: ThruClient;\n adminPublicKey: Uint8Array;\n adminPrivateKey: Uint8Array;\n adminAddress: string;\n pubkeyX: Uint8Array;\n pubkeyY: Uint8Array;\n credentialId?: string;\n walletName?: string;\n}): Promise<{ walletAddress: string; credentialLookupAddress?: string }> {\n const walletName = opts.walletName ?? \"default\";\n const seed = await createWalletSeed(walletName, opts.pubkeyX, opts.pubkeyY);\n const walletBytes = await deriveWalletAddress(\n seed,\n PASSKEY_MANAGER_PROGRAM_ADDRESS,\n );\n const walletAddress = toThruAddress(walletBytes);\n\n await withSerializedFeePayer(opts.adminPublicKey, async () => {\n let walletExists = false;\n try {\n await opts.client.accounts.get(walletAddress);\n walletExists = true;\n } catch {\n walletExists = false;\n }\n\n if (walletExists) return;\n\n const stateProof = await getStateProof(opts.client, walletAddress);\n const accountCtx = buildAccountContext({\n walletAddress,\n readWriteAccounts: [],\n readOnlyAccounts: [],\n feePayerAddress: opts.adminAddress,\n programAddress: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n });\n\n const createIx = encodeCreateInstruction({\n walletAccountIdx: accountCtx.walletAccountIdx,\n authority: {\n tag: 1,\n pubkeyX: opts.pubkeyX,\n pubkeyY: opts.pubkeyY,\n },\n seed,\n stateProof,\n });\n\n const transaction = await opts.client.transactions.build({\n feePayer: { publicKey: opts.adminPublicKey },\n program: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n instructionData: createIx,\n accounts: {\n readWrite: accountCtx.readWriteAddresses,\n readOnly: accountCtx.readOnlyAddresses,\n },\n header: { fee: 0n },\n });\n\n await transaction.sign(opts.adminPrivateKey);\n const signature = await opts.client.transactions.send(transaction.toWire());\n const result = await trackTransaction(opts.client, signature, 60000);\n if (result.status !== \"finalized\") {\n throw new Error(\n `Wallet creation failed with status: ${result.status}${\n result.errorCode !== undefined\n ? ` (error code: ${result.errorCode})`\n : \"\"\n }`,\n );\n }\n });\n\n let credentialLookupAddress: string | undefined;\n if (opts.credentialId) {\n const credentialIdBytes = base64UrlToBytes(opts.credentialId);\n const lookupAddressBytes = await deriveCredentialLookupAddress(\n credentialIdBytes,\n PASSKEY_MANAGER_PROGRAM_ADDRESS,\n );\n const lookupAddress = toThruAddress(lookupAddressBytes);\n\n credentialLookupAddress = lookupAddress;\n\n try {\n await withSerializedFeePayer(opts.adminPublicKey, async () => {\n let lookupExists = false;\n try {\n await opts.client.accounts.get(lookupAddress);\n lookupExists = true;\n } catch {\n lookupExists = false;\n }\n\n if (lookupExists) return;\n\n const credSeed = await createCredentialLookupSeed(credentialIdBytes);\n const stateProof = await getStateProof(opts.client, lookupAddress);\n const accountCtx = buildAccountContext({\n walletAddress,\n readWriteAccounts: [lookupAddressBytes],\n readOnlyAccounts: [],\n feePayerAddress: opts.adminAddress,\n programAddress: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n });\n\n const registerIx = encodeRegisterCredentialInstruction({\n walletAccountIdx: accountCtx.walletAccountIdx,\n lookupAccountIdx: accountCtx.getAccountIndex(lookupAddressBytes),\n seed: credSeed,\n stateProof,\n });\n\n const transaction = await opts.client.transactions.build({\n feePayer: { publicKey: opts.adminPublicKey },\n program: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n instructionData: registerIx,\n accounts: {\n readWrite: accountCtx.readWriteAddresses,\n readOnly: accountCtx.readOnlyAddresses,\n },\n header: { fee: 0n },\n });\n\n await transaction.sign(opts.adminPrivateKey);\n const signature = await opts.client.transactions.send(\n transaction.toWire(),\n );\n const result = await trackTransaction(opts.client, signature, 60000);\n if (result.status !== \"finalized\") {\n throw new Error(\n `Credential registration failed with status: ${result.status}${\n result.errorCode !== undefined\n ? ` (error code: ${result.errorCode})`\n : \"\"\n }`,\n );\n }\n });\n } catch (error) {\n console.warn(\"Credential registration failed (non-fatal):\", error);\n }\n }\n\n return {\n walletAddress,\n credentialLookupAddress,\n };\n}\n","import { encodeAddress } from '@thru/sdk/helpers';\nimport type { ThruClient, TransactionResult } from './types';\n\nconst feePayerQueueSymbol = Symbol.for('thru.sharedFeePayerQueues');\n\nfunction getFeePayerQueues(): Map<string, Promise<void>> {\n const globalQueues = globalThis as typeof globalThis & {\n [feePayerQueueSymbol]?: Map<string, Promise<void>>;\n };\n\n if (!globalQueues[feePayerQueueSymbol]) {\n globalQueues[feePayerQueueSymbol] = new Map<string, Promise<void>>();\n }\n\n return globalQueues[feePayerQueueSymbol];\n}\n\nexport async function getStateProof(\n client: ThruClient,\n address: string,\n proofType: number = 1,\n targetSlot?: bigint\n): Promise<Uint8Array> {\n const proofRequest: {\n address: string;\n proofType: number;\n targetSlot?: bigint;\n } = {\n address,\n proofType,\n };\n\n if (targetSlot !== undefined) {\n proofRequest.targetSlot = targetSlot;\n }\n\n const proof = await client.proofs.generate(proofRequest);\n\n if (!proof.proof || proof.proof.length === 0) {\n throw new Error(`No state proof returned for ${address}`);\n }\n\n return proof.proof;\n}\n\nexport async function trackTransaction(\n client: ThruClient,\n signature: string,\n timeoutMs: number = 5000\n): Promise<TransactionResult> {\n let finalizedSeen = false;\n\n try {\n for await (const update of client.transactions.track(signature, { timeoutMs })) {\n if (update.executionResult) {\n const vmError =\n update.executionResult.vmError !== undefined && update.executionResult.vmError !== null\n ? BigInt(update.executionResult.vmError)\n : 0n;\n const userErrorCode = update.executionResult.userErrorCode;\n const executionError =\n update.executionResult.executionResult !== undefined &&\n update.executionResult.executionResult !== null\n ? BigInt(update.executionResult.executionResult)\n : 0n;\n const success = vmError === 0n && executionError === 0n && userErrorCode === 0n;\n\n return {\n signature,\n status: success ? 'finalized' : 'failed',\n errorCode: vmError !== 0n ? vmError : executionError !== 0n ? executionError : userErrorCode,\n };\n }\n\n if (update.statusCode === 3) {\n finalizedSeen = true;\n }\n }\n\n if (finalizedSeen) {\n return {\n signature,\n status: 'finalized_without_execution',\n };\n }\n } catch {\n if (finalizedSeen) {\n return {\n signature,\n status: 'finalized_without_execution',\n };\n }\n\n return {\n signature,\n status: 'timeout',\n };\n }\n\n return {\n signature,\n status: 'timeout',\n };\n}\n\nexport function toThruAddress(bytes: Uint8Array): string {\n return encodeAddress(bytes);\n}\n\nexport async function withSerializedFeePayer<T>(\n feePayerPublicKey: Uint8Array,\n work: () => Promise<T>\n): Promise<T> {\n const queueKey = toThruAddress(feePayerPublicKey);\n const feePayerQueues = getFeePayerQueues();\n const previous = feePayerQueues.get(queueKey) ?? Promise.resolve();\n let release!: () => void;\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n const tail = previous.then(() => current);\n feePayerQueues.set(queueKey, tail);\n\n await previous;\n\n try {\n return await work();\n } finally {\n release();\n if (feePayerQueues.get(queueKey) === tail) {\n feePayerQueues.delete(queueKey);\n }\n }\n}\n","import {\n bytesToBase64Url,\n createValidateChallenge,\n decodeAddress,\n fetchWalletNonce,\n} from '@thru/programs/passkey-manager';\nimport type { AccountContext } from '@thru/programs/passkey-manager';\nimport type { PasskeyChallengeResult, ThruClient } from './types';\n\nexport async function createPasskeyChallenge(opts: {\n client: ThruClient;\n walletAddress: string;\n accountCtx: AccountContext;\n targetProgramAddress: string;\n instructionData: Uint8Array;\n authIdx?: number;\n}): Promise<PasskeyChallengeResult> {\n const nonce = await fetchWalletNonce(opts.client, opts.walletAddress);\n const targetProgramIdx = opts.accountCtx.getAccountIndex(\n decodeAddress(opts.targetProgramAddress)\n );\n const challenge = await createValidateChallenge(\n nonce,\n opts.accountCtx.accountAddresses,\n opts.accountCtx.walletAccountIdx,\n opts.authIdx ?? 0,\n {\n programIdx: targetProgramIdx,\n instructionData: opts.instructionData,\n }\n );\n\n return {\n challenge: bytesToBase64Url(challenge),\n nonce: nonce.toString(),\n };\n}\n","import {\n PASSKEY_MANAGER_PROGRAM_ADDRESS,\n decodeAddress,\n encodeValidateInstruction,\n hexToBytes,\n} from '@thru/programs/passkey-manager';\nimport type { AccountContext } from '@thru/programs/passkey-manager';\nimport { trackTransaction, withSerializedFeePayer } from './utils';\nimport type {\n BuiltPasskeyTransaction,\n PasskeySignaturePayload,\n PasskeyTransactionHeaderOverrides,\n ThruClient,\n TransactionResult,\n} from './types';\n\nfunction base64ToBytes(base64: string): Uint8Array {\n type BufferLike = {\n from(value: string, encoding: 'base64'): Uint8Array;\n };\n const globalBuffer = (globalThis as { Buffer?: BufferLike }).Buffer;\n if (globalBuffer) {\n return globalBuffer.from(base64, 'base64');\n }\n\n if (typeof atob === 'function') {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n }\n\n throw new Error('Base64 decoding is not supported in this environment');\n}\n\n/**\n * Builds and signs a passkey-manager transaction without submitting it.\n *\n * Callers that override the transaction nonce are responsible for coordinating\n * fee-payer nonce allocation before calling this helper. Use\n * `submitPasskeyTransaction` for the serialized one-off submit path.\n */\nexport async function buildPasskeyTransaction(opts: {\n client: ThruClient;\n adminPublicKey: Uint8Array;\n adminPrivateKey: Uint8Array;\n walletAddress: string;\n accountCtx: AccountContext;\n targetProgramAddress: string;\n instructionData: Uint8Array;\n authIdx?: number;\n header?: PasskeyTransactionHeaderOverrides;\n} & PasskeySignaturePayload): Promise<BuiltPasskeyTransaction> {\n const targetProgramIdx = opts.accountCtx.getAccountIndex(\n decodeAddress(opts.targetProgramAddress)\n );\n const validateIx = encodeValidateInstruction({\n walletAccountIdx: opts.accountCtx.walletAccountIdx,\n authIdx: opts.authIdx ?? 0,\n targetInstruction: {\n programIdx: targetProgramIdx,\n instructionData: opts.instructionData,\n },\n signatureR: hexToBytes(opts.signatureR),\n signatureS: hexToBytes(opts.signatureS),\n authenticatorData: base64ToBytes(opts.authenticatorData),\n clientDataJSON: base64ToBytes(opts.clientDataJSON),\n });\n\n const transaction = await opts.client.transactions.build({\n feePayer: { publicKey: opts.adminPublicKey },\n program: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n instructionData: validateIx,\n accounts: {\n readWrite: opts.accountCtx.readWriteAddresses,\n readOnly: opts.accountCtx.readOnlyAddresses,\n },\n header: {\n fee: 0n,\n ...opts.header,\n },\n });\n\n await transaction.sign(opts.adminPrivateKey);\n return {\n transaction,\n rawTransaction: transaction.toWire(),\n };\n}\n\nexport async function submitPasskeyTransaction(opts: {\n client: ThruClient;\n adminPublicKey: Uint8Array;\n adminPrivateKey: Uint8Array;\n walletAddress: string;\n accountCtx: AccountContext;\n targetProgramAddress: string;\n instructionData: Uint8Array;\n authIdx?: number;\n header?: PasskeyTransactionHeaderOverrides;\n} & PasskeySignaturePayload): Promise<TransactionResult> {\n return withSerializedFeePayer(opts.adminPublicKey, async () => {\n const { rawTransaction } = await buildPasskeyTransaction(opts);\n const signature = await opts.client.transactions.send(rawTransaction);\n return trackTransaction(opts.client, signature);\n });\n}\n","import type { PasskeyContextResult } from './types';\nimport { createPasskeyChallenge } from './challenge';\nimport { submitPasskeyTransaction } from './submit';\nimport type {\n PasskeyChallengeSubmitPayload,\n ThruClient,\n TransactionResult,\n} from './types';\n\nexport function createPasskeyHandlers<P>(opts: {\n buildContext: (params: P) => Promise<PasskeyContextResult>;\n adminPublicKey: Uint8Array;\n adminPrivateKey: Uint8Array;\n client: ThruClient;\n challengeTtlMs?: number;\n}) {\n const pendingContexts = new Map<\n string,\n { context: PasskeyContextResult; createdAt: number }\n >();\n const challengeTtlMs = opts.challengeTtlMs ?? 5 * 60_000;\n\n function createPendingContextKey(\n walletAddress: string,\n nonce: string,\n challenge: string\n ): string {\n return `${walletAddress}:${nonce}:${challenge}`;\n }\n\n function prunePendingContexts(now = Date.now()): void {\n for (const [nonce, entry] of pendingContexts.entries()) {\n if (now - entry.createdAt > challengeTtlMs) {\n pendingContexts.delete(nonce);\n }\n }\n }\n\n return {\n challenge: async (walletAddress: string, params: P) => {\n prunePendingContexts();\n\n const context = await opts.buildContext(params);\n const challenge = await createPasskeyChallenge({\n client: opts.client,\n walletAddress,\n accountCtx: context.accountCtx,\n targetProgramAddress: context.targetProgramAddress,\n instructionData: context.instructionData,\n authIdx: context.authIdx,\n });\n\n pendingContexts.set(\n createPendingContextKey(walletAddress, challenge.nonce, challenge.challenge),\n {\n context,\n createdAt: Date.now(),\n }\n );\n\n return challenge;\n },\n submit: async (\n walletAddress: string,\n params: P,\n payload: PasskeyChallengeSubmitPayload\n ): Promise<TransactionResult> => {\n void params;\n prunePendingContexts();\n\n const pendingKey = createPendingContextKey(\n walletAddress,\n payload.nonce,\n payload.challenge\n );\n const pending = pendingContexts.get(pendingKey);\n if (!pending) {\n throw new Error('Missing or expired challenge nonce');\n }\n\n pendingContexts.delete(pendingKey);\n const { nonce: _nonce, challenge: _challenge, ...signaturePayload } = payload;\n\n return submitPasskeyTransaction({\n client: opts.client,\n adminPublicKey: opts.adminPublicKey,\n adminPrivateKey: opts.adminPrivateKey,\n walletAddress,\n accountCtx: pending.context.accountCtx,\n targetProgramAddress: pending.context.targetProgramAddress,\n instructionData: pending.context.instructionData,\n authIdx: pending.context.authIdx,\n ...signaturePayload,\n });\n },\n };\n}\n"],"mappings":"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","names":["PASSKEY_MANAGER_PROGRAM_ADDRESS","decodeAddress","decodeAddress","PASSKEY_MANAGER_PROGRAM_ADDRESS"]}
|
|
1
|
+
{"version":3,"sources":["../src/server/create-wallet.ts","../src/server/utils.ts","../src/server/challenge.ts","../src/server/submit.ts","../src/server/handlers.ts"],"sourcesContent":["import {\n PASSKEY_MANAGER_PROGRAM_ADDRESS,\n base64UrlToBytes,\n buildAccountContext,\n createAuthorityRecord,\n createCredentialLookupSeed,\n createWalletSeed,\n deriveCredentialLookupAddress,\n deriveWalletAddress,\n encodeCreateInstruction,\n encodeRegisterCredentialInstruction,\n} from '@thru/programs/passkey-manager';\nimport {\n toThruAddress,\n getStateProof,\n trackTransaction,\n withSerializedFeePayer,\n} from \"./utils\";\nimport type { ThruClient } from \"./types\";\n\nexport async function createPasskeyWallet(opts: {\n client: ThruClient;\n adminPublicKey: Uint8Array;\n adminPrivateKey: Uint8Array;\n adminAddress: string;\n pubkeyX: Uint8Array;\n pubkeyY: Uint8Array;\n credentialId?: string;\n walletName?: string;\n}): Promise<{ walletAddress: string; credentialLookupAddress?: string }> {\n const walletName = opts.walletName ?? \"default\";\n const seed = await createWalletSeed(walletName, opts.pubkeyX, opts.pubkeyY);\n const walletBytes = await deriveWalletAddress(\n seed,\n PASSKEY_MANAGER_PROGRAM_ADDRESS,\n );\n const walletAddress = toThruAddress(walletBytes);\n\n await withSerializedFeePayer(opts.adminPublicKey, async () => {\n let walletExists = false;\n try {\n await opts.client.accounts.get(walletAddress);\n walletExists = true;\n } catch {\n walletExists = false;\n }\n\n if (walletExists) return;\n\n const stateProof = await getStateProof(opts.client, walletAddress);\n const accountCtx = buildAccountContext({\n walletAddress,\n readWriteAccounts: [],\n readOnlyAccounts: [],\n feePayerAddress: opts.adminAddress,\n programAddress: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n });\n\n const createIx = encodeCreateInstruction({\n walletAccountIdx: accountCtx.walletAccountIdx,\n authorityRecord: createAuthorityRecord({\n tag: 1,\n pubkeyX: opts.pubkeyX,\n pubkeyY: opts.pubkeyY,\n }),\n seed,\n stateProof,\n });\n\n const transaction = await opts.client.transactions.build({\n feePayer: { publicKey: opts.adminPublicKey },\n program: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n instructionData: createIx,\n accounts: {\n readWrite: accountCtx.readWriteAddresses,\n readOnly: accountCtx.readOnlyAddresses,\n },\n header: { fee: 0n },\n });\n\n await transaction.sign(opts.adminPrivateKey);\n const signature = await opts.client.transactions.send(transaction.toWire());\n const result = await trackTransaction(opts.client, signature, 60000);\n if (result.status !== \"finalized\") {\n throw new Error(\n `Wallet creation failed with status: ${result.status}${\n result.errorCode !== undefined\n ? ` (error code: ${result.errorCode})`\n : \"\"\n }`,\n );\n }\n });\n\n let credentialLookupAddress: string | undefined;\n if (opts.credentialId) {\n const credentialIdBytes = base64UrlToBytes(opts.credentialId);\n const lookupAddressBytes = await deriveCredentialLookupAddress(\n credentialIdBytes,\n PASSKEY_MANAGER_PROGRAM_ADDRESS,\n );\n const lookupAddress = toThruAddress(lookupAddressBytes);\n\n credentialLookupAddress = lookupAddress;\n\n try {\n await withSerializedFeePayer(opts.adminPublicKey, async () => {\n let lookupExists = false;\n try {\n await opts.client.accounts.get(lookupAddress);\n lookupExists = true;\n } catch {\n lookupExists = false;\n }\n\n if (lookupExists) return;\n\n const credSeed = await createCredentialLookupSeed(credentialIdBytes);\n const stateProof = await getStateProof(opts.client, lookupAddress);\n const accountCtx = buildAccountContext({\n walletAddress,\n readWriteAccounts: [lookupAddressBytes],\n readOnlyAccounts: [],\n feePayerAddress: opts.adminAddress,\n programAddress: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n });\n\n const registerIx = encodeRegisterCredentialInstruction({\n walletAccountIdx: accountCtx.walletAccountIdx,\n lookupAccountIdx: accountCtx.getAccountIndex(lookupAddressBytes),\n seed: credSeed,\n stateProof,\n });\n\n const transaction = await opts.client.transactions.build({\n feePayer: { publicKey: opts.adminPublicKey },\n program: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n instructionData: registerIx,\n accounts: {\n readWrite: accountCtx.readWriteAddresses,\n readOnly: accountCtx.readOnlyAddresses,\n },\n header: { fee: 0n },\n });\n\n await transaction.sign(opts.adminPrivateKey);\n const signature = await opts.client.transactions.send(\n transaction.toWire(),\n );\n const result = await trackTransaction(opts.client, signature, 60000);\n if (result.status !== \"finalized\") {\n throw new Error(\n `Credential registration failed with status: ${result.status}${\n result.errorCode !== undefined\n ? ` (error code: ${result.errorCode})`\n : \"\"\n }`,\n );\n }\n });\n } catch (error) {\n console.warn(\"Credential registration failed (non-fatal):\", error);\n }\n }\n\n return {\n walletAddress,\n credentialLookupAddress,\n };\n}\n","import { encodeAddress } from '@thru/sdk/helpers';\nimport type { ThruClient, TransactionResult } from './types';\n\nconst feePayerQueueSymbol = Symbol.for('thru.sharedFeePayerQueues');\n\nfunction getFeePayerQueues(): Map<string, Promise<void>> {\n const globalQueues = globalThis as typeof globalThis & {\n [feePayerQueueSymbol]?: Map<string, Promise<void>>;\n };\n\n if (!globalQueues[feePayerQueueSymbol]) {\n globalQueues[feePayerQueueSymbol] = new Map<string, Promise<void>>();\n }\n\n return globalQueues[feePayerQueueSymbol];\n}\n\nexport async function getStateProof(\n client: ThruClient,\n address: string,\n proofType: number = 1,\n targetSlot?: bigint\n): Promise<Uint8Array> {\n const proofRequest: {\n address: string;\n proofType: number;\n targetSlot?: bigint;\n } = {\n address,\n proofType,\n };\n\n if (targetSlot !== undefined) {\n proofRequest.targetSlot = targetSlot;\n }\n\n const proof = await client.proofs.generate(proofRequest);\n\n if (!proof.proof || proof.proof.length === 0) {\n throw new Error(`No state proof returned for ${address}`);\n }\n\n return proof.proof;\n}\n\nexport async function trackTransaction(\n client: ThruClient,\n signature: string,\n timeoutMs: number = 5000\n): Promise<TransactionResult> {\n let finalizedSeen = false;\n\n try {\n for await (const update of client.transactions.track(signature, { timeoutMs })) {\n if (update.executionResult) {\n const vmError =\n update.executionResult.vmError !== undefined && update.executionResult.vmError !== null\n ? BigInt(update.executionResult.vmError)\n : 0n;\n const userErrorCode = update.executionResult.userErrorCode;\n const executionError =\n update.executionResult.executionResult !== undefined &&\n update.executionResult.executionResult !== null\n ? BigInt(update.executionResult.executionResult)\n : 0n;\n const success = vmError === 0n && executionError === 0n && userErrorCode === 0n;\n\n return {\n signature,\n status: success ? 'finalized' : 'failed',\n errorCode: vmError !== 0n ? vmError : executionError !== 0n ? executionError : userErrorCode,\n };\n }\n\n if (update.statusCode === 3) {\n finalizedSeen = true;\n }\n }\n\n if (finalizedSeen) {\n return {\n signature,\n status: 'finalized_without_execution',\n };\n }\n } catch {\n if (finalizedSeen) {\n return {\n signature,\n status: 'finalized_without_execution',\n };\n }\n\n return {\n signature,\n status: 'timeout',\n };\n }\n\n return {\n signature,\n status: 'timeout',\n };\n}\n\nexport function toThruAddress(bytes: Uint8Array): string {\n return encodeAddress(bytes);\n}\n\nexport async function withSerializedFeePayer<T>(\n feePayerPublicKey: Uint8Array,\n work: () => Promise<T>\n): Promise<T> {\n const queueKey = toThruAddress(feePayerPublicKey);\n const feePayerQueues = getFeePayerQueues();\n const previous = feePayerQueues.get(queueKey) ?? Promise.resolve();\n let release!: () => void;\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n const tail = previous.then(() => current);\n feePayerQueues.set(queueKey, tail);\n\n await previous;\n\n try {\n return await work();\n } finally {\n release();\n if (feePayerQueues.get(queueKey) === tail) {\n feePayerQueues.delete(queueKey);\n }\n }\n}\n","import {\n bytesToBase64Url,\n createValidateChallenge,\n decodeAddress,\n fetchWalletNonce,\n} from '@thru/programs/passkey-manager';\nimport type { AccountContext } from '@thru/programs/passkey-manager';\nimport type { PasskeyChallengeResult, ThruClient } from './types';\n\nexport async function createPasskeyChallenge(opts: {\n client: ThruClient;\n walletAddress: string;\n accountCtx: AccountContext;\n targetProgramAddress: string;\n instructionData: Uint8Array;\n authIdx?: number;\n}): Promise<PasskeyChallengeResult> {\n const nonce = await fetchWalletNonce(opts.client, opts.walletAddress);\n const targetProgramIdx = opts.accountCtx.getAccountIndex(\n decodeAddress(opts.targetProgramAddress)\n );\n const challenge = await createValidateChallenge(\n nonce,\n opts.accountCtx.accountAddresses,\n opts.accountCtx.walletAccountIdx,\n opts.authIdx ?? 0,\n {\n programIdx: targetProgramIdx,\n instructionData: opts.instructionData,\n }\n );\n\n return {\n challenge: bytesToBase64Url(challenge),\n nonce: nonce.toString(),\n };\n}\n","import {\n PASSKEY_MANAGER_PROGRAM_ADDRESS,\n decodeAddress,\n encodeValidateInstruction,\n hexToBytes,\n} from '@thru/programs/passkey-manager';\nimport type { AccountContext } from '@thru/programs/passkey-manager';\nimport { trackTransaction, withSerializedFeePayer } from './utils';\nimport type {\n BuiltPasskeyTransaction,\n PasskeySignaturePayload,\n PasskeyTransactionHeaderOverrides,\n ThruClient,\n TransactionResult,\n} from './types';\n\nfunction base64ToBytes(base64: string): Uint8Array {\n type BufferLike = {\n from(value: string, encoding: 'base64'): Uint8Array;\n };\n const globalBuffer = (globalThis as { Buffer?: BufferLike }).Buffer;\n if (globalBuffer) {\n return globalBuffer.from(base64, 'base64');\n }\n\n if (typeof atob === 'function') {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n }\n\n throw new Error('Base64 decoding is not supported in this environment');\n}\n\n/**\n * Builds and signs a passkey-manager transaction without submitting it.\n *\n * Callers that override the transaction nonce are responsible for coordinating\n * fee-payer nonce allocation before calling this helper. Use\n * `submitPasskeyTransaction` for the serialized one-off submit path.\n */\nexport async function buildPasskeyTransaction(opts: {\n client: ThruClient;\n adminPublicKey: Uint8Array;\n adminPrivateKey: Uint8Array;\n walletAddress: string;\n accountCtx: AccountContext;\n targetProgramAddress: string;\n instructionData: Uint8Array;\n authIdx?: number;\n header?: PasskeyTransactionHeaderOverrides;\n} & PasskeySignaturePayload): Promise<BuiltPasskeyTransaction> {\n const targetProgramIdx = opts.accountCtx.getAccountIndex(\n decodeAddress(opts.targetProgramAddress)\n );\n const validateIx = encodeValidateInstruction({\n walletAccountIdx: opts.accountCtx.walletAccountIdx,\n authIdx: opts.authIdx ?? 0,\n targetInstruction: {\n programIdx: targetProgramIdx,\n instructionData: opts.instructionData,\n },\n signatureR: hexToBytes(opts.signatureR),\n signatureS: hexToBytes(opts.signatureS),\n authenticatorData: base64ToBytes(opts.authenticatorData),\n clientDataJSON: base64ToBytes(opts.clientDataJSON),\n });\n\n const transaction = await opts.client.transactions.build({\n feePayer: { publicKey: opts.adminPublicKey },\n program: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n instructionData: validateIx,\n accounts: {\n readWrite: opts.accountCtx.readWriteAddresses,\n readOnly: opts.accountCtx.readOnlyAddresses,\n },\n header: {\n fee: 0n,\n ...opts.header,\n },\n });\n\n await transaction.sign(opts.adminPrivateKey);\n return {\n transaction,\n rawTransaction: transaction.toWire(),\n };\n}\n\nexport async function submitPasskeyTransaction(opts: {\n client: ThruClient;\n adminPublicKey: Uint8Array;\n adminPrivateKey: Uint8Array;\n walletAddress: string;\n accountCtx: AccountContext;\n targetProgramAddress: string;\n instructionData: Uint8Array;\n authIdx?: number;\n header?: PasskeyTransactionHeaderOverrides;\n} & PasskeySignaturePayload): Promise<TransactionResult> {\n return withSerializedFeePayer(opts.adminPublicKey, async () => {\n const { rawTransaction } = await buildPasskeyTransaction(opts);\n const signature = await opts.client.transactions.send(rawTransaction);\n return trackTransaction(opts.client, signature);\n });\n}\n","import type { PasskeyContextResult } from './types';\nimport { createPasskeyChallenge } from './challenge';\nimport { submitPasskeyTransaction } from './submit';\nimport type {\n PasskeyChallengeSubmitPayload,\n ThruClient,\n TransactionResult,\n} from './types';\n\nexport function createPasskeyHandlers<P>(opts: {\n buildContext: (params: P) => Promise<PasskeyContextResult>;\n adminPublicKey: Uint8Array;\n adminPrivateKey: Uint8Array;\n client: ThruClient;\n challengeTtlMs?: number;\n}) {\n const pendingContexts = new Map<\n string,\n { context: PasskeyContextResult; createdAt: number }\n >();\n const challengeTtlMs = opts.challengeTtlMs ?? 5 * 60_000;\n\n function createPendingContextKey(\n walletAddress: string,\n nonce: string,\n challenge: string\n ): string {\n return `${walletAddress}:${nonce}:${challenge}`;\n }\n\n function prunePendingContexts(now = Date.now()): void {\n for (const [nonce, entry] of pendingContexts.entries()) {\n if (now - entry.createdAt > challengeTtlMs) {\n pendingContexts.delete(nonce);\n }\n }\n }\n\n return {\n challenge: async (walletAddress: string, params: P) => {\n prunePendingContexts();\n\n const context = await opts.buildContext(params);\n const challenge = await createPasskeyChallenge({\n client: opts.client,\n walletAddress,\n accountCtx: context.accountCtx,\n targetProgramAddress: context.targetProgramAddress,\n instructionData: context.instructionData,\n authIdx: context.authIdx,\n });\n\n pendingContexts.set(\n createPendingContextKey(walletAddress, challenge.nonce, challenge.challenge),\n {\n context,\n createdAt: Date.now(),\n }\n );\n\n return challenge;\n },\n submit: async (\n walletAddress: string,\n params: P,\n payload: PasskeyChallengeSubmitPayload\n ): Promise<TransactionResult> => {\n void params;\n prunePendingContexts();\n\n const pendingKey = createPendingContextKey(\n walletAddress,\n payload.nonce,\n payload.challenge\n );\n const pending = pendingContexts.get(pendingKey);\n if (!pending) {\n throw new Error('Missing or expired challenge nonce');\n }\n\n pendingContexts.delete(pendingKey);\n const { nonce: _nonce, challenge: _challenge, ...signaturePayload } = payload;\n\n return submitPasskeyTransaction({\n client: opts.client,\n adminPublicKey: opts.adminPublicKey,\n adminPrivateKey: opts.adminPrivateKey,\n walletAddress,\n accountCtx: pending.context.accountCtx,\n targetProgramAddress: pending.context.targetProgramAddress,\n instructionData: pending.context.instructionData,\n authIdx: pending.context.authIdx,\n ...signaturePayload,\n });\n },\n };\n}\n"],"mappings":"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","names":["PASSKEY_MANAGER_PROGRAM_ADDRESS","decodeAddress","decodeAddress","PASSKEY_MANAGER_PROGRAM_ADDRESS"]}
|
|
@@ -32,12 +32,14 @@ interface PasskeyPopupContext {
|
|
|
32
32
|
appUrl?: string;
|
|
33
33
|
origin?: string;
|
|
34
34
|
imageUrl?: string;
|
|
35
|
+
preferStoredPasskey?: boolean;
|
|
35
36
|
}
|
|
36
37
|
/**
|
|
37
38
|
* Options for stored passkey signing in embedded contexts.
|
|
38
39
|
*/
|
|
39
40
|
interface PasskeyStoredSigningOptions {
|
|
40
41
|
allowPopupFallback?: boolean;
|
|
42
|
+
allowDiscoverableFallback?: boolean;
|
|
41
43
|
/** Prefer an RP-scoped discoverable credential prompt over a stored
|
|
42
44
|
* credential-id lookup. Native WebViews can show misleading
|
|
43
45
|
* app-level "no passkey" UI when allowCredentials is stale, while a
|
|
@@ -32,12 +32,14 @@ interface PasskeyPopupContext {
|
|
|
32
32
|
appUrl?: string;
|
|
33
33
|
origin?: string;
|
|
34
34
|
imageUrl?: string;
|
|
35
|
+
preferStoredPasskey?: boolean;
|
|
35
36
|
}
|
|
36
37
|
/**
|
|
37
38
|
* Options for stored passkey signing in embedded contexts.
|
|
38
39
|
*/
|
|
39
40
|
interface PasskeyStoredSigningOptions {
|
|
40
41
|
allowPopupFallback?: boolean;
|
|
42
|
+
allowDiscoverableFallback?: boolean;
|
|
41
43
|
/** Prefer an RP-scoped discoverable credential prompt over a stored
|
|
42
44
|
* credential-id lookup. Native WebViews can show misleading
|
|
43
45
|
* app-level "no passkey" UI when allowCredentials is stale, while a
|
package/dist/web.cjs
CHANGED
|
@@ -555,6 +555,7 @@ function createDistinctPasskeyLabel(baseLabel, _options = {}) {
|
|
|
555
555
|
|
|
556
556
|
// src/sign.ts
|
|
557
557
|
var import_passkey_manager2 = require("@thru/programs/passkey-manager");
|
|
558
|
+
var WEB_AUTHN_FOCUS_RETRY_DELAYS_MS = [150, 300];
|
|
558
559
|
async function signWithPasskey(credentialId, challenge, rpId) {
|
|
559
560
|
if (!isWebAuthnSupported()) {
|
|
560
561
|
throw new Error("WebAuthn is not supported in this browser");
|
|
@@ -570,10 +571,15 @@ async function signWithStoredPasskey(challenge, rpId, preferredPasskey, allPassk
|
|
|
570
571
|
throw new Error("WebAuthn is not supported in this browser");
|
|
571
572
|
}
|
|
572
573
|
const allowPopupFallback = options.allowPopupFallback ?? true;
|
|
574
|
+
const allowDiscoverableFallback = options.allowDiscoverableFallback ?? true;
|
|
573
575
|
const preopenedPopup = allowPopupFallback ? maybePreopenPopup("get", openPasskeyPopupWindow) : null;
|
|
574
576
|
const promptMode = allowPopupFallback ? await getPasskeyPromptMode("get") : "inline";
|
|
575
577
|
const storedPasskey = preferredPasskey;
|
|
576
578
|
const canUsePopup = allowPopupFallback && isInIframe();
|
|
579
|
+
if (!allowDiscoverableFallback && !storedPasskey) {
|
|
580
|
+
closePopup(preopenedPopup);
|
|
581
|
+
throw new Error("No stored passkey available for this wallet");
|
|
582
|
+
}
|
|
577
583
|
if (options.preferDiscoverable) {
|
|
578
584
|
closePopup(preopenedPopup);
|
|
579
585
|
return signWithDiscoverableStoredPasskey(
|
|
@@ -599,7 +605,7 @@ async function signWithStoredPasskey(challenge, rpId, preferredPasskey, allPassk
|
|
|
599
605
|
passkey: storedPasskey
|
|
600
606
|
};
|
|
601
607
|
} catch (error) {
|
|
602
|
-
if (!shouldFallbackToDiscoverable(error)) {
|
|
608
|
+
if (!allowDiscoverableFallback || !shouldFallbackToDiscoverable(error)) {
|
|
603
609
|
throw error;
|
|
604
610
|
}
|
|
605
611
|
return signWithDiscoverableStoredPasskey(
|
|
@@ -710,9 +716,7 @@ async function signWithPasskeyAssertion(challenge, rpId, credentialId) {
|
|
|
710
716
|
}
|
|
711
717
|
];
|
|
712
718
|
}
|
|
713
|
-
const assertion = await
|
|
714
|
-
publicKey: getOptions
|
|
715
|
-
});
|
|
719
|
+
const assertion = await getPasskeyAssertionWithFocusRetry(getOptions);
|
|
716
720
|
if (!assertion) {
|
|
717
721
|
throw new Error("Passkey authentication was cancelled");
|
|
718
722
|
}
|
|
@@ -731,6 +735,37 @@ async function signWithPasskeyAssertion(challenge, rpId, credentialId) {
|
|
|
731
735
|
authenticatorAttachment: rawAttachment
|
|
732
736
|
};
|
|
733
737
|
}
|
|
738
|
+
async function getPasskeyAssertionWithFocusRetry(publicKey) {
|
|
739
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
740
|
+
try {
|
|
741
|
+
return await navigator.credentials.get({
|
|
742
|
+
publicKey
|
|
743
|
+
});
|
|
744
|
+
} catch (error) {
|
|
745
|
+
const retryDelayMs = WEB_AUTHN_FOCUS_RETRY_DELAYS_MS[attempt];
|
|
746
|
+
if (retryDelayMs === void 0 || !isDocumentNotFocusedError(error)) {
|
|
747
|
+
throw error;
|
|
748
|
+
}
|
|
749
|
+
await waitForFocusRetry(retryDelayMs);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
function isDocumentNotFocusedError(error) {
|
|
754
|
+
const name = error && typeof error === "object" && "name" in error ? String(error.name) : "";
|
|
755
|
+
const message = error && typeof error === "object" && "message" in error ? String(error.message) : "";
|
|
756
|
+
const normalized = `${name} ${message}`.toLowerCase();
|
|
757
|
+
return normalized.includes("document is not focused");
|
|
758
|
+
}
|
|
759
|
+
function waitForFocusRetry(delayMs) {
|
|
760
|
+
return new Promise((resolve) => {
|
|
761
|
+
const finish = () => setTimeout(resolve, delayMs);
|
|
762
|
+
if (typeof requestAnimationFrame !== "function") {
|
|
763
|
+
finish();
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
requestAnimationFrame(() => requestAnimationFrame(finish));
|
|
767
|
+
});
|
|
768
|
+
}
|
|
734
769
|
async function signWithPasskeyViaPopup(credentialId, challenge, rpId, preopenedPopup) {
|
|
735
770
|
const result = await requestPasskeyPopup(
|
|
736
771
|
"get",
|
package/dist/web.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/web.ts","../src/register.ts","../src/capabilities.ts","../src/popup.ts","../src/label.ts","../src/sign.ts"],"sourcesContent":["export type {\n PasskeyRegistrationResult,\n PasskeySigningResult,\n PasskeyDiscoverableSigningResult,\n PasskeyStoredSigningResult,\n PasskeyMetadata,\n PasskeyClientCapabilities,\n PasskeyPopupContext,\n PasskeyPopupAccount,\n PasskeyStoredSigningOptions,\n PasskeyRegistrationOptions,\n} from './types';\n\nexport { registerPasskey } from './register';\nexport { createDistinctPasskeyLabel } from './label';\nexport type { DistinctPasskeyLabelOptions } from './label';\n\nexport {\n signWithPasskey,\n signWithStoredPasskey,\n signWithDiscoverablePasskey,\n} from './sign';\n\nexport {\n parseDerSignature,\n normalizeLowS,\n normalizeSignatureComponent,\n P256_N,\n P256_HALF_N,\n bytesToBigIntBE,\n bigIntToBytesBE,\n} from '@thru/programs/passkey-manager';\n\nexport {\n isWebAuthnSupported,\n preloadPasskeyClientCapabilities,\n getPasskeyClientCapabilities,\n getCachedPasskeyClientCapabilities,\n shouldUsePasskeyPopup,\n isInIframe,\n type PasskeyPromptAction,\n} from './capabilities';\n\nexport {\n arrayBufferToBase64Url,\n base64UrlToArrayBuffer,\n bytesToBase64,\n bytesToBase64Url,\n base64UrlToBytes,\n bytesToHex,\n hexToBytes,\n bytesEqual,\n compareBytes,\n uniqueAccounts,\n} from '@thru/programs/passkey-manager';\n","import type {\n PasskeyRegistrationOptions,\n PasskeyRegistrationResult,\n PasskeyPopupRegistrationResult,\n} from './types';\nimport { arrayBufferToBase64Url, bytesToHex } from '@thru/programs/passkey-manager';\nimport {\n isWebAuthnSupported,\n getPasskeyPromptMode,\n maybePreopenPopup,\n shouldFallbackToPopup,\n type PasskeyPromptAction,\n} from './capabilities';\nimport { requestPasskeyPopup, openPasskeyPopupWindow, closePopup } from './popup';\n\n/**\n * Register a new passkey for a profile.\n */\nexport async function registerPasskey(\n alias: string,\n userId: string,\n rpId: string,\n options: PasskeyRegistrationOptions = {}\n): Promise<PasskeyRegistrationResult> {\n if (!isWebAuthnSupported()) {\n throw new Error('WebAuthn is not supported in this browser');\n }\n\n return runWithPromptMode(\n 'create',\n () => registerPasskeyInline(alias, userId, rpId),\n (preopenedPopup) => registerPasskeyViaPopup(alias, userId, rpId, preopenedPopup),\n options\n );\n}\n\nasync function runWithPromptMode<T>(\n action: PasskeyPromptAction,\n inlineFn: () => Promise<T>,\n popupFn: (preopenedPopup?: Window | null) => Promise<T>,\n options: PasskeyRegistrationOptions = {}\n): Promise<T> {\n const allowPopupFallback = options.allowPopupFallback ?? true;\n const preopenedPopup = allowPopupFallback ? maybePreopenPopup(action, openPasskeyPopupWindow) : null;\n const promptMode = allowPopupFallback ? await getPasskeyPromptMode(action) : 'inline';\n if (promptMode === 'popup') {\n return popupFn(preopenedPopup);\n }\n\n closePopup(preopenedPopup);\n\n try {\n return await inlineFn();\n } catch (error) {\n if (allowPopupFallback && shouldFallbackToPopup(error)) {\n return popupFn();\n }\n throw error;\n }\n}\n\nasync function registerPasskeyInline(\n alias: string,\n userId: string,\n rpId: string\n): Promise<PasskeyRegistrationResult> {\n const rpName = 'Thru Wallet';\n\n const userIdBytes = new TextEncoder().encode(userId);\n const userIdBuffer = userIdBytes.slice(0, 64);\n\n const challenge = crypto.getRandomValues(new Uint8Array(32));\n\n const createOptions: PublicKeyCredentialCreationOptions = {\n challenge,\n rp: {\n id: rpId,\n name: rpName,\n },\n user: {\n id: userIdBuffer,\n name: alias,\n displayName: alias,\n },\n pubKeyCredParams: [\n { type: 'public-key', alg: -7 },\n ],\n authenticatorSelection: {\n authenticatorAttachment: 'platform',\n userVerification: 'required',\n residentKey: 'required',\n requireResidentKey: true,\n },\n attestation: 'none',\n timeout: 60000,\n };\n\n const credential = (await navigator.credentials.create({\n publicKey: createOptions,\n })) as PublicKeyCredential | null;\n\n if (!credential) {\n throw new Error('Passkey registration was cancelled');\n }\n\n const response = credential.response as AuthenticatorAttestationResponse;\n const { x, y } = extractP256PublicKey(response);\n const authenticatorAttachment =\n (\n credential as PublicKeyCredential & {\n authenticatorAttachment?: AuthenticatorAttachment | null;\n }\n ).authenticatorAttachment ?? null;\n\n return {\n credentialId: arrayBufferToBase64Url(credential.rawId),\n publicKeyX: bytesToHex(x),\n publicKeyY: bytesToHex(y),\n rpId,\n authenticatorAttachment,\n };\n}\n\nasync function registerPasskeyViaPopup(\n alias: string,\n userId: string,\n rpId: string,\n preopenedPopup?: Window | null\n): Promise<PasskeyRegistrationResult> {\n const result = await requestPasskeyPopup<PasskeyPopupRegistrationResult>(\n 'create',\n { alias, userId, rpId },\n preopenedPopup\n );\n return result;\n}\n\n// Key extraction helpers\n\nfunction extractP256PublicKey(\n response: AuthenticatorAttestationResponse\n): { x: Uint8Array; y: Uint8Array } {\n if (typeof response.getPublicKey === 'function') {\n const spkiKey = response.getPublicKey();\n if (spkiKey) {\n return extractFromSpki(new Uint8Array(spkiKey));\n }\n }\n\n if (typeof response.getAuthenticatorData === 'function') {\n const authData = new Uint8Array(response.getAuthenticatorData());\n return extractFromAuthenticatorData(authData);\n }\n\n throw new Error('Unable to extract public key: browser does not support required WebAuthn methods');\n}\n\nfunction extractFromSpki(spki: Uint8Array): { x: Uint8Array; y: Uint8Array } {\n const pointStart = spki.length - 65;\n\n if (spki[pointStart] !== 0x04) {\n throw new Error('Invalid SPKI format: expected uncompressed point');\n }\n\n const x = spki.slice(pointStart + 1, pointStart + 33);\n const y = spki.slice(pointStart + 33, pointStart + 65);\n\n if (x.length !== 32 || y.length !== 32) {\n throw new Error('Invalid SPKI format: incorrect coordinate length');\n }\n\n return { x, y };\n}\n\nfunction extractFromAuthenticatorData(authData: Uint8Array): { x: Uint8Array; y: Uint8Array } {\n const rpIdHashLength = 32;\n const flagsLength = 1;\n const counterLength = 4;\n const offset = rpIdHashLength + flagsLength + counterLength;\n const aaguidLength = 16;\n const credIdLenOffset = offset + aaguidLength;\n const credIdLength = (authData[credIdLenOffset] << 8) | authData[credIdLenOffset + 1];\n const coseKeyOffset = credIdLenOffset + 2 + credIdLength;\n const coseKey = authData.slice(coseKeyOffset);\n\n return extractFromCoseKey(coseKey);\n}\n\nfunction extractFromCoseKey(coseKey: Uint8Array): { x: Uint8Array; y: Uint8Array } {\n const mapStart = coseKey[0];\n if (mapStart !== 0xa5 && mapStart !== 0xa4) {\n throw new Error('Invalid COSE key format');\n }\n\n let offset = 1;\n let x: Uint8Array | null = null;\n let y: Uint8Array | null = null;\n\n while (offset < coseKey.length) {\n const key = coseKey[offset++];\n const valueType = coseKey[offset++];\n\n if (key === 0x21) {\n const length = valueType & 0x1f;\n x = coseKey.slice(offset, offset + length);\n offset += length;\n continue;\n }\n\n if (key === 0x22) {\n const length = valueType & 0x1f;\n y = coseKey.slice(offset, offset + length);\n offset += length;\n continue;\n }\n\n if (valueType >= 0x40 && valueType <= 0x5f) {\n const length = valueType & 0x1f;\n offset += length;\n continue;\n }\n\n if (valueType === 0x01 || valueType === 0x02 || valueType === 0x03) {\n continue;\n }\n\n if (valueType >= 0x18 && valueType <= 0x1b) {\n const size = 1 << (valueType - 0x18);\n offset += size;\n continue;\n }\n }\n\n if (!x || !y) {\n throw new Error('Failed to extract P-256 public key from COSE data');\n }\n\n if (x.length !== 32 || y.length !== 32) {\n throw new Error('Invalid COSE key: incorrect coordinate length');\n }\n\n return { x, y };\n}\n","import type { PasskeyClientCapabilities } from './types';\n\nconst globalProcess = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process;\nconst DEBUG = globalProcess?.env?.NEXT_PUBLIC_PASSKEY_DEBUG === '1';\n\nlet cachedClientCapabilities: PasskeyClientCapabilities | null | undefined;\nlet clientCapabilitiesPromise: Promise<PasskeyClientCapabilities | null> | null = null;\n\nexport function isWebAuthnSupported(): boolean {\n const supported =\n typeof window !== 'undefined' &&\n typeof window.PublicKeyCredential !== 'undefined' &&\n typeof navigator.credentials !== 'undefined';\n\n if (DEBUG) {\n console.log('[Passkey] WebAuthn support check:', {\n window: typeof window !== 'undefined',\n PublicKeyCredential:\n typeof window !== 'undefined' && typeof window.PublicKeyCredential !== 'undefined',\n credentials:\n typeof window !== 'undefined' &&\n typeof navigator !== 'undefined' &&\n typeof navigator.credentials !== 'undefined',\n supported,\n });\n }\n\n return supported;\n}\n\nasync function fetchPasskeyClientCapabilities(): Promise<PasskeyClientCapabilities | null> {\n if (typeof window === 'undefined' || typeof window.PublicKeyCredential === 'undefined') {\n return null;\n }\n\n const getClientCapabilities = (window.PublicKeyCredential as {\n getClientCapabilities?: () => Promise<PasskeyClientCapabilities>;\n }).getClientCapabilities;\n\n if (typeof getClientCapabilities !== 'function') {\n return null;\n }\n\n try {\n const capabilities = await getClientCapabilities.call(window.PublicKeyCredential);\n if (DEBUG) {\n console.log('[Passkey] WebAuthn client capabilities:', capabilities);\n }\n return capabilities ?? null;\n } catch (error) {\n if (DEBUG) {\n console.warn('[Passkey] Failed to read client capabilities:', error);\n }\n return null;\n }\n}\n\nexport function preloadPasskeyClientCapabilities(): void {\n if (cachedClientCapabilities !== undefined || clientCapabilitiesPromise) {\n return;\n }\n\n clientCapabilitiesPromise = fetchPasskeyClientCapabilities().then((capabilities) => {\n cachedClientCapabilities = capabilities;\n return capabilities;\n });\n}\n\nexport async function getPasskeyClientCapabilities(): Promise<PasskeyClientCapabilities | null> {\n if (cachedClientCapabilities !== undefined) {\n return cachedClientCapabilities;\n }\n\n if (!clientCapabilitiesPromise) {\n preloadPasskeyClientCapabilities();\n }\n\n if (!clientCapabilitiesPromise) {\n cachedClientCapabilities = null;\n return null;\n }\n\n const capabilities = await clientCapabilitiesPromise;\n cachedClientCapabilities = capabilities;\n return capabilities;\n}\n\nexport function getCachedPasskeyClientCapabilities(): PasskeyClientCapabilities | null | undefined {\n return cachedClientCapabilities;\n}\n\nexport function isInIframe(): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n try {\n return window.self !== window.top;\n } catch {\n return true;\n }\n}\n\nexport type PasskeyPromptAction = 'get' | 'create';\n\nexport async function shouldUsePasskeyPopup(action: PasskeyPromptAction): Promise<boolean> {\n if (!isInIframe()) {\n return false;\n }\n const mode = await getPasskeyPromptMode(action);\n return mode === 'popup';\n}\n\ntype PasskeyPromptMode = 'inline' | 'popup';\n\nfunction getPermissionsPolicyAllowsFeature(feature: string): boolean | null {\n if (typeof document === 'undefined') {\n return null;\n }\n\n const policy = (document as { permissionsPolicy?: { allowsFeature?: (name: string) => boolean } })\n .permissionsPolicy;\n const featurePolicy = (document as { featurePolicy?: { allowsFeature?: (name: string) => boolean } })\n .featurePolicy;\n const allowsFeature = policy?.allowsFeature || featurePolicy?.allowsFeature;\n\n if (typeof allowsFeature !== 'function') {\n return null;\n }\n\n try {\n return allowsFeature(feature);\n } catch {\n return null;\n }\n}\n\nfunction getCachedPromptMode(action: PasskeyPromptAction): PasskeyPromptMode | 'unknown' {\n if (!isInIframe()) {\n return 'inline';\n }\n\n if (cachedClientCapabilities === undefined && !clientCapabilitiesPromise) {\n preloadPasskeyClientCapabilities();\n }\n\n const feature =\n action === 'create' ? 'publickey-credentials-create' : 'publickey-credentials-get';\n const policyAllows = getPermissionsPolicyAllowsFeature(feature);\n const capabilities = getCachedPasskeyClientCapabilities();\n const supportsInline =\n capabilities?.passkeyPlatformAuthenticator === true ||\n capabilities?.userVerifyingPlatformAuthenticator === true;\n\n if (policyAllows === false) {\n return 'popup';\n }\n\n if (capabilities === undefined) {\n return 'unknown';\n }\n\n if (!supportsInline) {\n return 'popup';\n }\n\n return 'inline';\n}\n\nexport async function getPasskeyPromptMode(action: PasskeyPromptAction): Promise<PasskeyPromptMode> {\n if (!isInIframe()) {\n return 'inline';\n }\n\n const feature =\n action === 'create' ? 'publickey-credentials-create' : 'publickey-credentials-get';\n const policyAllows = getPermissionsPolicyAllowsFeature(feature);\n const capabilities = await getPasskeyClientCapabilities();\n const supportsInline =\n capabilities?.passkeyPlatformAuthenticator === true ||\n capabilities?.userVerifyingPlatformAuthenticator === true;\n\n if (DEBUG) {\n console.log('[Passkey] Prompt mode check:', {\n action,\n policyAllows,\n supportsInline,\n capabilities,\n });\n }\n\n if (!supportsInline) {\n return 'popup';\n }\n\n if (policyAllows === false) {\n return 'popup';\n }\n\n return 'inline';\n}\n\nexport function maybePreopenPopup(action: PasskeyPromptAction, openPopupFn: () => Window): Window | null {\n const cachedMode = getCachedPromptMode(action);\n if (cachedMode !== 'popup') {\n return null;\n }\n\n try {\n return openPopupFn();\n } catch {\n return null;\n }\n}\n\nexport function shouldFallbackToPopup(error: unknown): boolean {\n if (!isInIframe()) {\n return false;\n }\n\n const name =\n error && typeof error === 'object' && 'name' in error ? String((error as { name?: unknown }).name) : '';\n const message =\n error && typeof error === 'object' && 'message' in error\n ? String((error as { message?: unknown }).message)\n : '';\n const normalized = `${name} ${message}`.toLowerCase();\n\n if (\n normalized.includes('cancel') ||\n normalized.includes('canceled') ||\n normalized.includes('cancelled') ||\n normalized.includes('user canceled') ||\n normalized.includes('user cancelled') ||\n normalized.includes('aborted')\n ) {\n return false;\n }\n\n if (normalized.includes('securityerror')) {\n return true;\n }\n\n if (normalized.includes('notallowederror')) {\n if (\n normalized.includes('permission') ||\n normalized.includes('policy') ||\n normalized.includes('iframe') ||\n normalized.includes('frame')\n ) {\n return true;\n }\n }\n\n return false;\n}\n","import type {\n PasskeyPopupAction,\n PasskeyPopupRequestPayload,\n PasskeyPopupRequest,\n PasskeyPopupResponse,\n} from './types';\n\nexport const PASSKEY_POPUP_PATH = '/passkey/popup';\nexport const PASSKEY_POPUP_READY_EVENT = 'thru:passkey-popup-ready';\nexport const PASSKEY_POPUP_REQUEST_EVENT = 'thru:passkey-popup-request';\nexport const PASSKEY_POPUP_RESPONSE_EVENT = 'thru:passkey-popup-response';\nexport const PASSKEY_POPUP_CHANNEL = 'thru:passkey-popup-channel';\n\nconst PASSKEY_POPUP_TIMEOUT_MS = 60000;\n\nexport function closePopup(popup: Window | null | undefined): void {\n if (popup && !popup.closed) {\n popup.close();\n }\n}\n\nexport function openPasskeyPopupWindow(): Window {\n const popupUrl = new URL(PASSKEY_POPUP_PATH, window.location.origin).toString();\n const popup = window.open(\n popupUrl,\n 'thru_passkey_popup',\n 'popup=yes,width=440,height=640'\n );\n\n if (!popup) {\n throw new Error('Passkey popup was blocked');\n }\n\n return popup;\n}\n\nfunction createPopupRequestId(): string {\n const rand = Math.random().toString(36).slice(2, 10);\n return `passkey_${Date.now()}_${rand}`;\n}\n\nexport async function requestPasskeyPopup<T>(\n action: PasskeyPopupAction,\n payload: PasskeyPopupRequestPayload,\n preopenedPopup?: Window | null\n): Promise<T> {\n if (typeof window === 'undefined') {\n throw new Error('Passkey popup is only available in the browser');\n }\n\n const requestId = createPopupRequestId();\n const targetOrigin = window.location.origin;\n let popup: Window | null = preopenedPopup ?? null;\n const channel =\n typeof BroadcastChannel !== 'undefined' ? new BroadcastChannel(PASSKEY_POPUP_CHANNEL) : null;\n\n return new Promise<T>((resolve, reject) => {\n let timeout: ReturnType<typeof setTimeout> | null = null;\n let closePoll: ReturnType<typeof setInterval> | null = null;\n let requestSent = false;\n\n const cleanup = () => {\n if (timeout) {\n clearTimeout(timeout);\n timeout = null;\n }\n if (closePoll) {\n clearInterval(closePoll);\n closePoll = null;\n }\n window.removeEventListener('message', handleMessage);\n if (channel) {\n channel.removeEventListener('message', handleChannelMessage);\n channel.close();\n }\n };\n\n const sendRequest = (viaChannel: boolean) => {\n if (requestSent) {\n return;\n }\n requestSent = true;\n\n const request: PasskeyPopupRequest = {\n type: PASSKEY_POPUP_REQUEST_EVENT,\n requestId,\n action,\n payload,\n };\n\n if (viaChannel) {\n channel?.postMessage(request);\n return;\n }\n\n popup?.postMessage(request, targetOrigin);\n };\n\n const handleResponse = (data: PasskeyPopupResponse) => {\n if (data.requestId !== requestId) {\n return;\n }\n\n cleanup();\n if (popup && !popup.closed) {\n popup.close();\n }\n\n if (data.success) {\n resolve((data as Extract<PasskeyPopupResponse, { success: true }>).result as T);\n } else {\n const err = new Error(data.error?.message || 'Passkey popup failed');\n if (data.error?.name) {\n (err as { name?: string }).name = data.error.name;\n }\n reject(err);\n }\n };\n\n const handleMessage = (event: MessageEvent) => {\n if (event.origin !== targetOrigin) {\n return;\n }\n\n const data = event.data as PasskeyPopupResponse | { type?: string };\n if (!data || typeof data !== 'object') {\n return;\n }\n\n if (data.type === PASSKEY_POPUP_READY_EVENT) {\n if (popup && event.source !== popup) {\n return;\n }\n sendRequest(false);\n return;\n }\n\n if (data.type === PASSKEY_POPUP_RESPONSE_EVENT && 'requestId' in data) {\n handleResponse(data as PasskeyPopupResponse);\n }\n };\n\n window.addEventListener('message', handleMessage);\n\n const handleChannelMessage = (event: MessageEvent) => {\n const data = event.data as PasskeyPopupResponse | { type?: string };\n if (!data || typeof data !== 'object') {\n return;\n }\n\n if (data.type === PASSKEY_POPUP_READY_EVENT) {\n sendRequest(true);\n return;\n }\n\n if (data.type === PASSKEY_POPUP_RESPONSE_EVENT && 'requestId' in data) {\n handleResponse(data as PasskeyPopupResponse);\n }\n };\n\n if (channel) {\n channel.addEventListener('message', handleChannelMessage);\n }\n\n if (!popup) {\n try {\n popup = openPasskeyPopupWindow();\n } catch (error) {\n cleanup();\n reject(error);\n return;\n }\n }\n\n timeout = setTimeout(() => {\n cleanup();\n try {\n popup?.close();\n } catch {\n /* ignore */\n }\n reject(new Error('Passkey popup timed out'));\n }, PASSKEY_POPUP_TIMEOUT_MS);\n\n closePoll = setInterval(() => {\n if (popup && popup.closed) {\n cleanup();\n reject(new Error('Passkey popup was closed'));\n }\n }, 250);\n });\n}\n","const DEFAULT_LABEL = 'Thru Wallet passkey';\n\nexport interface DistinctPasskeyLabelOptions {\n existingLabels?: Iterable<string | null | undefined>;\n maxAttempts?: number;\n suffixFactory?: () => string;\n}\n\nexport function createDistinctPasskeyLabel(\n baseLabel: string,\n _options: DistinctPasskeyLabelOptions = {}\n): string {\n return baseLabel.trim() || DEFAULT_LABEL;\n}\n","import type {\n PasskeySigningResult,\n PasskeyStoredSigningResult,\n PasskeyDiscoverableSigningResult,\n PasskeyMetadata,\n PasskeyPopupContext,\n PasskeyPopupSigningResult,\n PasskeyPopupStoredSigningResult,\n PasskeyStoredSigningOptions,\n} from './types';\nimport {\n arrayBufferToBase64Url,\n base64UrlToArrayBuffer,\n bytesToBase64Url,\n base64UrlToBytes,\n parseDerSignature,\n normalizeLowS,\n} from '@thru/programs/passkey-manager';\nimport {\n isWebAuthnSupported,\n getPasskeyPromptMode,\n isInIframe,\n maybePreopenPopup,\n shouldFallbackToPopup,\n type PasskeyPromptAction,\n} from './capabilities';\nimport {\n requestPasskeyPopup,\n openPasskeyPopupWindow,\n closePopup,\n} from './popup';\n\n/**\n * Sign a challenge with an existing passkey (by credential ID).\n */\nexport async function signWithPasskey(\n credentialId: string,\n challenge: Uint8Array,\n rpId: string\n): Promise<PasskeySigningResult> {\n if (!isWebAuthnSupported()) {\n throw new Error('WebAuthn is not supported in this browser');\n }\n\n return runWithPromptMode(\n 'get',\n () => signWithPasskeyInline(credentialId, challenge, rpId),\n (preopenedPopup) =>\n signWithPasskeyViaPopup(credentialId, challenge, rpId, preopenedPopup)\n );\n}\n\n/**\n * Sign with stored passkey (for embedded/popup contexts).\n */\nexport async function signWithStoredPasskey(\n challenge: Uint8Array,\n rpId: string,\n preferredPasskey: PasskeyMetadata | null,\n allPasskeys: PasskeyMetadata[],\n context?: PasskeyPopupContext,\n options: PasskeyStoredSigningOptions = {}\n): Promise<PasskeyStoredSigningResult> {\n if (!isWebAuthnSupported()) {\n throw new Error('WebAuthn is not supported in this browser');\n }\n\n const allowPopupFallback = options.allowPopupFallback ?? true;\n const preopenedPopup = allowPopupFallback\n ? maybePreopenPopup('get', openPasskeyPopupWindow)\n : null;\n const promptMode = allowPopupFallback\n ? await getPasskeyPromptMode('get')\n : 'inline';\n const storedPasskey = preferredPasskey;\n const canUsePopup = allowPopupFallback && isInIframe();\n\n if (options.preferDiscoverable) {\n closePopup(preopenedPopup);\n return signWithDiscoverableStoredPasskey(\n challenge,\n storedPasskey?.rpId ?? rpId,\n allPasskeys\n );\n }\n\n if (promptMode === 'popup' || (canUsePopup && !storedPasskey)) {\n return requestStoredPasskeyPopup(challenge, preopenedPopup, context);\n }\n\n closePopup(preopenedPopup);\n\n try {\n if (storedPasskey) {\n try {\n const result = await signWithPasskeyInline(\n storedPasskey.credentialId,\n challenge,\n storedPasskey.rpId\n );\n return {\n ...result,\n passkey: storedPasskey,\n };\n } catch (error) {\n if (!shouldFallbackToDiscoverable(error)) {\n throw error;\n }\n return signWithDiscoverableStoredPasskey(\n challenge,\n storedPasskey.rpId,\n allPasskeys\n );\n }\n }\n\n return signWithDiscoverableStoredPasskey(challenge, rpId, allPasskeys);\n } catch (error) {\n if (canUsePopup && shouldFallbackToPopup(error)) {\n return requestStoredPasskeyPopup(challenge, undefined, context);\n }\n\n throw error;\n }\n}\n\nasync function signWithDiscoverableStoredPasskey(\n challenge: Uint8Array,\n rpId: string,\n allPasskeys: PasskeyMetadata[]\n): Promise<PasskeyStoredSigningResult> {\n const discoverable = await signWithDiscoverablePasskey(challenge, rpId);\n const matchingPasskey =\n allPasskeys.find((p) => p.credentialId === discoverable.credentialId) ??\n null;\n const now = new Date().toISOString();\n const passkey = matchingPasskey ?? {\n credentialId: discoverable.credentialId,\n publicKeyX: '',\n publicKeyY: '',\n rpId: discoverable.rpId,\n createdAt: now,\n lastUsedAt: now,\n };\n\n return {\n signature: discoverable.signature,\n authenticatorData: discoverable.authenticatorData,\n clientDataJSON: discoverable.clientDataJSON,\n signatureR: discoverable.signatureR,\n signatureS: discoverable.signatureS,\n authenticatorAttachment: discoverable.authenticatorAttachment,\n passkey,\n };\n}\n\nfunction shouldFallbackToDiscoverable(error: unknown): boolean {\n const name =\n error && typeof error === 'object' && 'name' in error\n ? String((error as { name?: unknown }).name)\n : '';\n const message =\n error && typeof error === 'object' && 'message' in error\n ? String((error as { message?: unknown }).message)\n : '';\n const normalized = `${name} ${message}`.toLowerCase();\n\n if (\n normalized.includes('user rejected') ||\n normalized.includes('user canceled') ||\n normalized.includes('user cancelled')\n ) {\n return false;\n }\n\n return (\n normalized.includes('notallowederror') ||\n normalized.includes('invalidstateerror') ||\n normalized.includes('notfounderror') ||\n normalized.includes('not found') ||\n normalized.includes('no passkey') ||\n normalized.includes('no credential') ||\n normalized.includes('saved for this app')\n );\n}\n\n/**\n * Sign with a discoverable passkey (no credential ID - browser prompts user to select).\n */\nexport async function signWithDiscoverablePasskey(\n challenge: Uint8Array,\n rpId: string\n): Promise<PasskeyDiscoverableSigningResult> {\n if (!isWebAuthnSupported()) {\n throw new Error('WebAuthn is not supported in this browser');\n }\n\n const resolvedRpId = rpId;\n const result = await signWithPasskeyAssertion(challenge, resolvedRpId);\n\n return {\n signature: result.signature,\n authenticatorData: result.authenticatorData,\n clientDataJSON: result.clientDataJSON,\n signatureR: result.signatureR,\n signatureS: result.signatureS,\n credentialId: result.credentialId,\n rpId: resolvedRpId,\n authenticatorAttachment: result.authenticatorAttachment,\n };\n}\n\n// Internal helpers\n\nasync function runWithPromptMode<T>(\n action: PasskeyPromptAction,\n inlineFn: () => Promise<T>,\n popupFn: (preopenedPopup?: Window | null) => Promise<T>\n): Promise<T> {\n const preopenedPopup = maybePreopenPopup(action, openPasskeyPopupWindow);\n const promptMode = await getPasskeyPromptMode(action);\n if (promptMode === 'popup') {\n return popupFn(preopenedPopup);\n }\n\n closePopup(preopenedPopup);\n\n try {\n return await inlineFn();\n } catch (error) {\n if (shouldFallbackToPopup(error)) {\n return popupFn();\n }\n throw error;\n }\n}\n\nasync function signWithPasskeyInline(\n credentialId: string,\n challenge: Uint8Array,\n rpId: string\n): Promise<PasskeySigningResult> {\n const result = await signWithPasskeyAssertion(challenge, rpId, credentialId);\n return {\n signature: result.signature,\n authenticatorData: result.authenticatorData,\n clientDataJSON: result.clientDataJSON,\n signatureR: result.signatureR,\n signatureS: result.signatureS,\n authenticatorAttachment: result.authenticatorAttachment,\n };\n}\n\nasync function signWithPasskeyAssertion(\n challenge: Uint8Array,\n rpId: string,\n credentialId?: string\n): Promise<PasskeySigningResult & { credentialId: string }> {\n const challengeBytes = new Uint8Array(challenge);\n const getOptions: PublicKeyCredentialRequestOptions = {\n challenge: challengeBytes,\n rpId,\n userVerification: 'required',\n timeout: 60000,\n };\n\n if (credentialId) {\n const credentialIdBuffer = base64UrlToArrayBuffer(credentialId);\n getOptions.allowCredentials = [\n {\n type: 'public-key',\n id: credentialIdBuffer,\n transports: ['internal', 'hybrid', 'usb', 'ble', 'nfc'],\n },\n ];\n }\n\n const assertion = (await navigator.credentials.get({\n publicKey: getOptions,\n })) as PublicKeyCredential | null;\n\n if (!assertion) {\n throw new Error('Passkey authentication was cancelled');\n }\n\n const response = assertion.response as AuthenticatorAssertionResponse;\n\n const signature = new Uint8Array(response.signature);\n let { r, s } = parseDerSignature(signature);\n s = normalizeLowS(s);\n\n /* `authenticatorAttachment` distinguishes a same-device passkey\n ('platform') from a cross-device one signed via QR / hybrid\n transport ('cross-platform'). Drives the wallet's add-device\n prompt. Browsers may report null. */\n const rawAttachment =\n (\n assertion as PublicKeyCredential & {\n authenticatorAttachment?: AuthenticatorAttachment | null;\n }\n ).authenticatorAttachment ?? null;\n\n return {\n signature: new Uint8Array([...r, ...s]),\n authenticatorData: new Uint8Array(response.authenticatorData),\n clientDataJSON: new Uint8Array(response.clientDataJSON),\n signatureR: r,\n signatureS: s,\n credentialId: arrayBufferToBase64Url(assertion.rawId),\n authenticatorAttachment: rawAttachment,\n };\n}\n\nasync function signWithPasskeyViaPopup(\n credentialId: string,\n challenge: Uint8Array,\n rpId: string,\n preopenedPopup?: Window | null\n): Promise<PasskeySigningResult> {\n const result = await requestPasskeyPopup<PasskeyPopupSigningResult>(\n 'get',\n {\n credentialId,\n challengeBase64Url: bytesToBase64Url(challenge),\n rpId,\n },\n preopenedPopup\n );\n\n return decodePopupSigningResult(result);\n}\n\nasync function requestStoredPasskeyPopup(\n challenge: Uint8Array,\n preopenedPopup?: Window | null,\n context?: PasskeyPopupContext\n): Promise<PasskeyStoredSigningResult> {\n const result = await requestPasskeyPopup<PasskeyPopupStoredSigningResult>(\n 'getStored',\n {\n challengeBase64Url: bytesToBase64Url(challenge),\n context,\n },\n preopenedPopup\n );\n return decodePopupStoredSigningResult(result);\n}\n\nfunction decodePopupSigningResult(\n result: PasskeyPopupSigningResult\n): PasskeySigningResult {\n return {\n signature: base64UrlToBytes(result.signatureBase64Url),\n authenticatorData: base64UrlToBytes(result.authenticatorDataBase64Url),\n clientDataJSON: base64UrlToBytes(result.clientDataJSONBase64Url),\n signatureR: base64UrlToBytes(result.signatureRBase64Url),\n signatureS: base64UrlToBytes(result.signatureSBase64Url),\n authenticatorAttachment: result.authenticatorAttachment ?? null,\n };\n}\n\nfunction decodePopupStoredSigningResult(\n result: PasskeyPopupStoredSigningResult\n): PasskeyStoredSigningResult {\n return {\n ...decodePopupSigningResult(result),\n passkey: result.passkey,\n accounts: result.accounts,\n };\n}\n"],"mappings":"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","names":["import_passkey_manager","runWithPromptMode","import_passkey_manager"]}
|
|
1
|
+
{"version":3,"sources":["../src/web.ts","../src/register.ts","../src/capabilities.ts","../src/popup.ts","../src/label.ts","../src/sign.ts"],"sourcesContent":["export type {\n PasskeyRegistrationResult,\n PasskeySigningResult,\n PasskeyDiscoverableSigningResult,\n PasskeyStoredSigningResult,\n PasskeyMetadata,\n PasskeyClientCapabilities,\n PasskeyPopupContext,\n PasskeyPopupAccount,\n PasskeyStoredSigningOptions,\n PasskeyRegistrationOptions,\n} from './types';\n\nexport { registerPasskey } from './register';\nexport { createDistinctPasskeyLabel } from './label';\nexport type { DistinctPasskeyLabelOptions } from './label';\n\nexport {\n signWithPasskey,\n signWithStoredPasskey,\n signWithDiscoverablePasskey,\n} from './sign';\n\nexport {\n parseDerSignature,\n normalizeLowS,\n normalizeSignatureComponent,\n P256_N,\n P256_HALF_N,\n bytesToBigIntBE,\n bigIntToBytesBE,\n} from '@thru/programs/passkey-manager';\n\nexport {\n isWebAuthnSupported,\n preloadPasskeyClientCapabilities,\n getPasskeyClientCapabilities,\n getCachedPasskeyClientCapabilities,\n shouldUsePasskeyPopup,\n isInIframe,\n type PasskeyPromptAction,\n} from './capabilities';\n\nexport {\n arrayBufferToBase64Url,\n base64UrlToArrayBuffer,\n bytesToBase64,\n bytesToBase64Url,\n base64UrlToBytes,\n bytesToHex,\n hexToBytes,\n bytesEqual,\n compareBytes,\n uniqueAccounts,\n} from '@thru/programs/passkey-manager';\n","import type {\n PasskeyRegistrationOptions,\n PasskeyRegistrationResult,\n PasskeyPopupRegistrationResult,\n} from './types';\nimport { arrayBufferToBase64Url, bytesToHex } from '@thru/programs/passkey-manager';\nimport {\n isWebAuthnSupported,\n getPasskeyPromptMode,\n maybePreopenPopup,\n shouldFallbackToPopup,\n type PasskeyPromptAction,\n} from './capabilities';\nimport { requestPasskeyPopup, openPasskeyPopupWindow, closePopup } from './popup';\n\n/**\n * Register a new passkey for a profile.\n */\nexport async function registerPasskey(\n alias: string,\n userId: string,\n rpId: string,\n options: PasskeyRegistrationOptions = {}\n): Promise<PasskeyRegistrationResult> {\n if (!isWebAuthnSupported()) {\n throw new Error('WebAuthn is not supported in this browser');\n }\n\n return runWithPromptMode(\n 'create',\n () => registerPasskeyInline(alias, userId, rpId),\n (preopenedPopup) => registerPasskeyViaPopup(alias, userId, rpId, preopenedPopup),\n options\n );\n}\n\nasync function runWithPromptMode<T>(\n action: PasskeyPromptAction,\n inlineFn: () => Promise<T>,\n popupFn: (preopenedPopup?: Window | null) => Promise<T>,\n options: PasskeyRegistrationOptions = {}\n): Promise<T> {\n const allowPopupFallback = options.allowPopupFallback ?? true;\n const preopenedPopup = allowPopupFallback ? maybePreopenPopup(action, openPasskeyPopupWindow) : null;\n const promptMode = allowPopupFallback ? await getPasskeyPromptMode(action) : 'inline';\n if (promptMode === 'popup') {\n return popupFn(preopenedPopup);\n }\n\n closePopup(preopenedPopup);\n\n try {\n return await inlineFn();\n } catch (error) {\n if (allowPopupFallback && shouldFallbackToPopup(error)) {\n return popupFn();\n }\n throw error;\n }\n}\n\nasync function registerPasskeyInline(\n alias: string,\n userId: string,\n rpId: string\n): Promise<PasskeyRegistrationResult> {\n const rpName = 'Thru Wallet';\n\n const userIdBytes = new TextEncoder().encode(userId);\n const userIdBuffer = userIdBytes.slice(0, 64);\n\n const challenge = crypto.getRandomValues(new Uint8Array(32));\n\n const createOptions: PublicKeyCredentialCreationOptions = {\n challenge,\n rp: {\n id: rpId,\n name: rpName,\n },\n user: {\n id: userIdBuffer,\n name: alias,\n displayName: alias,\n },\n pubKeyCredParams: [\n { type: 'public-key', alg: -7 },\n ],\n authenticatorSelection: {\n authenticatorAttachment: 'platform',\n userVerification: 'required',\n residentKey: 'required',\n requireResidentKey: true,\n },\n attestation: 'none',\n timeout: 60000,\n };\n\n const credential = (await navigator.credentials.create({\n publicKey: createOptions,\n })) as PublicKeyCredential | null;\n\n if (!credential) {\n throw new Error('Passkey registration was cancelled');\n }\n\n const response = credential.response as AuthenticatorAttestationResponse;\n const { x, y } = extractP256PublicKey(response);\n const authenticatorAttachment =\n (\n credential as PublicKeyCredential & {\n authenticatorAttachment?: AuthenticatorAttachment | null;\n }\n ).authenticatorAttachment ?? null;\n\n return {\n credentialId: arrayBufferToBase64Url(credential.rawId),\n publicKeyX: bytesToHex(x),\n publicKeyY: bytesToHex(y),\n rpId,\n authenticatorAttachment,\n };\n}\n\nasync function registerPasskeyViaPopup(\n alias: string,\n userId: string,\n rpId: string,\n preopenedPopup?: Window | null\n): Promise<PasskeyRegistrationResult> {\n const result = await requestPasskeyPopup<PasskeyPopupRegistrationResult>(\n 'create',\n { alias, userId, rpId },\n preopenedPopup\n );\n return result;\n}\n\n// Key extraction helpers\n\nfunction extractP256PublicKey(\n response: AuthenticatorAttestationResponse\n): { x: Uint8Array; y: Uint8Array } {\n if (typeof response.getPublicKey === 'function') {\n const spkiKey = response.getPublicKey();\n if (spkiKey) {\n return extractFromSpki(new Uint8Array(spkiKey));\n }\n }\n\n if (typeof response.getAuthenticatorData === 'function') {\n const authData = new Uint8Array(response.getAuthenticatorData());\n return extractFromAuthenticatorData(authData);\n }\n\n throw new Error('Unable to extract public key: browser does not support required WebAuthn methods');\n}\n\nfunction extractFromSpki(spki: Uint8Array): { x: Uint8Array; y: Uint8Array } {\n const pointStart = spki.length - 65;\n\n if (spki[pointStart] !== 0x04) {\n throw new Error('Invalid SPKI format: expected uncompressed point');\n }\n\n const x = spki.slice(pointStart + 1, pointStart + 33);\n const y = spki.slice(pointStart + 33, pointStart + 65);\n\n if (x.length !== 32 || y.length !== 32) {\n throw new Error('Invalid SPKI format: incorrect coordinate length');\n }\n\n return { x, y };\n}\n\nfunction extractFromAuthenticatorData(authData: Uint8Array): { x: Uint8Array; y: Uint8Array } {\n const rpIdHashLength = 32;\n const flagsLength = 1;\n const counterLength = 4;\n const offset = rpIdHashLength + flagsLength + counterLength;\n const aaguidLength = 16;\n const credIdLenOffset = offset + aaguidLength;\n const credIdLength = (authData[credIdLenOffset] << 8) | authData[credIdLenOffset + 1];\n const coseKeyOffset = credIdLenOffset + 2 + credIdLength;\n const coseKey = authData.slice(coseKeyOffset);\n\n return extractFromCoseKey(coseKey);\n}\n\nfunction extractFromCoseKey(coseKey: Uint8Array): { x: Uint8Array; y: Uint8Array } {\n const mapStart = coseKey[0];\n if (mapStart !== 0xa5 && mapStart !== 0xa4) {\n throw new Error('Invalid COSE key format');\n }\n\n let offset = 1;\n let x: Uint8Array | null = null;\n let y: Uint8Array | null = null;\n\n while (offset < coseKey.length) {\n const key = coseKey[offset++];\n const valueType = coseKey[offset++];\n\n if (key === 0x21) {\n const length = valueType & 0x1f;\n x = coseKey.slice(offset, offset + length);\n offset += length;\n continue;\n }\n\n if (key === 0x22) {\n const length = valueType & 0x1f;\n y = coseKey.slice(offset, offset + length);\n offset += length;\n continue;\n }\n\n if (valueType >= 0x40 && valueType <= 0x5f) {\n const length = valueType & 0x1f;\n offset += length;\n continue;\n }\n\n if (valueType === 0x01 || valueType === 0x02 || valueType === 0x03) {\n continue;\n }\n\n if (valueType >= 0x18 && valueType <= 0x1b) {\n const size = 1 << (valueType - 0x18);\n offset += size;\n continue;\n }\n }\n\n if (!x || !y) {\n throw new Error('Failed to extract P-256 public key from COSE data');\n }\n\n if (x.length !== 32 || y.length !== 32) {\n throw new Error('Invalid COSE key: incorrect coordinate length');\n }\n\n return { x, y };\n}\n","import type { PasskeyClientCapabilities } from './types';\n\nconst globalProcess = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process;\nconst DEBUG = globalProcess?.env?.NEXT_PUBLIC_PASSKEY_DEBUG === '1';\n\nlet cachedClientCapabilities: PasskeyClientCapabilities | null | undefined;\nlet clientCapabilitiesPromise: Promise<PasskeyClientCapabilities | null> | null = null;\n\nexport function isWebAuthnSupported(): boolean {\n const supported =\n typeof window !== 'undefined' &&\n typeof window.PublicKeyCredential !== 'undefined' &&\n typeof navigator.credentials !== 'undefined';\n\n if (DEBUG) {\n console.log('[Passkey] WebAuthn support check:', {\n window: typeof window !== 'undefined',\n PublicKeyCredential:\n typeof window !== 'undefined' && typeof window.PublicKeyCredential !== 'undefined',\n credentials:\n typeof window !== 'undefined' &&\n typeof navigator !== 'undefined' &&\n typeof navigator.credentials !== 'undefined',\n supported,\n });\n }\n\n return supported;\n}\n\nasync function fetchPasskeyClientCapabilities(): Promise<PasskeyClientCapabilities | null> {\n if (typeof window === 'undefined' || typeof window.PublicKeyCredential === 'undefined') {\n return null;\n }\n\n const getClientCapabilities = (window.PublicKeyCredential as {\n getClientCapabilities?: () => Promise<PasskeyClientCapabilities>;\n }).getClientCapabilities;\n\n if (typeof getClientCapabilities !== 'function') {\n return null;\n }\n\n try {\n const capabilities = await getClientCapabilities.call(window.PublicKeyCredential);\n if (DEBUG) {\n console.log('[Passkey] WebAuthn client capabilities:', capabilities);\n }\n return capabilities ?? null;\n } catch (error) {\n if (DEBUG) {\n console.warn('[Passkey] Failed to read client capabilities:', error);\n }\n return null;\n }\n}\n\nexport function preloadPasskeyClientCapabilities(): void {\n if (cachedClientCapabilities !== undefined || clientCapabilitiesPromise) {\n return;\n }\n\n clientCapabilitiesPromise = fetchPasskeyClientCapabilities().then((capabilities) => {\n cachedClientCapabilities = capabilities;\n return capabilities;\n });\n}\n\nexport async function getPasskeyClientCapabilities(): Promise<PasskeyClientCapabilities | null> {\n if (cachedClientCapabilities !== undefined) {\n return cachedClientCapabilities;\n }\n\n if (!clientCapabilitiesPromise) {\n preloadPasskeyClientCapabilities();\n }\n\n if (!clientCapabilitiesPromise) {\n cachedClientCapabilities = null;\n return null;\n }\n\n const capabilities = await clientCapabilitiesPromise;\n cachedClientCapabilities = capabilities;\n return capabilities;\n}\n\nexport function getCachedPasskeyClientCapabilities(): PasskeyClientCapabilities | null | undefined {\n return cachedClientCapabilities;\n}\n\nexport function isInIframe(): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n try {\n return window.self !== window.top;\n } catch {\n return true;\n }\n}\n\nexport type PasskeyPromptAction = 'get' | 'create';\n\nexport async function shouldUsePasskeyPopup(action: PasskeyPromptAction): Promise<boolean> {\n if (!isInIframe()) {\n return false;\n }\n const mode = await getPasskeyPromptMode(action);\n return mode === 'popup';\n}\n\ntype PasskeyPromptMode = 'inline' | 'popup';\n\nfunction getPermissionsPolicyAllowsFeature(feature: string): boolean | null {\n if (typeof document === 'undefined') {\n return null;\n }\n\n const policy = (document as { permissionsPolicy?: { allowsFeature?: (name: string) => boolean } })\n .permissionsPolicy;\n const featurePolicy = (document as { featurePolicy?: { allowsFeature?: (name: string) => boolean } })\n .featurePolicy;\n const allowsFeature = policy?.allowsFeature || featurePolicy?.allowsFeature;\n\n if (typeof allowsFeature !== 'function') {\n return null;\n }\n\n try {\n return allowsFeature(feature);\n } catch {\n return null;\n }\n}\n\nfunction getCachedPromptMode(action: PasskeyPromptAction): PasskeyPromptMode | 'unknown' {\n if (!isInIframe()) {\n return 'inline';\n }\n\n if (cachedClientCapabilities === undefined && !clientCapabilitiesPromise) {\n preloadPasskeyClientCapabilities();\n }\n\n const feature =\n action === 'create' ? 'publickey-credentials-create' : 'publickey-credentials-get';\n const policyAllows = getPermissionsPolicyAllowsFeature(feature);\n const capabilities = getCachedPasskeyClientCapabilities();\n const supportsInline =\n capabilities?.passkeyPlatformAuthenticator === true ||\n capabilities?.userVerifyingPlatformAuthenticator === true;\n\n if (policyAllows === false) {\n return 'popup';\n }\n\n if (capabilities === undefined) {\n return 'unknown';\n }\n\n if (!supportsInline) {\n return 'popup';\n }\n\n return 'inline';\n}\n\nexport async function getPasskeyPromptMode(action: PasskeyPromptAction): Promise<PasskeyPromptMode> {\n if (!isInIframe()) {\n return 'inline';\n }\n\n const feature =\n action === 'create' ? 'publickey-credentials-create' : 'publickey-credentials-get';\n const policyAllows = getPermissionsPolicyAllowsFeature(feature);\n const capabilities = await getPasskeyClientCapabilities();\n const supportsInline =\n capabilities?.passkeyPlatformAuthenticator === true ||\n capabilities?.userVerifyingPlatformAuthenticator === true;\n\n if (DEBUG) {\n console.log('[Passkey] Prompt mode check:', {\n action,\n policyAllows,\n supportsInline,\n capabilities,\n });\n }\n\n if (!supportsInline) {\n return 'popup';\n }\n\n if (policyAllows === false) {\n return 'popup';\n }\n\n return 'inline';\n}\n\nexport function maybePreopenPopup(action: PasskeyPromptAction, openPopupFn: () => Window): Window | null {\n const cachedMode = getCachedPromptMode(action);\n if (cachedMode !== 'popup') {\n return null;\n }\n\n try {\n return openPopupFn();\n } catch {\n return null;\n }\n}\n\nexport function shouldFallbackToPopup(error: unknown): boolean {\n if (!isInIframe()) {\n return false;\n }\n\n const name =\n error && typeof error === 'object' && 'name' in error ? String((error as { name?: unknown }).name) : '';\n const message =\n error && typeof error === 'object' && 'message' in error\n ? String((error as { message?: unknown }).message)\n : '';\n const normalized = `${name} ${message}`.toLowerCase();\n\n if (\n normalized.includes('cancel') ||\n normalized.includes('canceled') ||\n normalized.includes('cancelled') ||\n normalized.includes('user canceled') ||\n normalized.includes('user cancelled') ||\n normalized.includes('aborted')\n ) {\n return false;\n }\n\n if (normalized.includes('securityerror')) {\n return true;\n }\n\n if (normalized.includes('notallowederror')) {\n if (\n normalized.includes('permission') ||\n normalized.includes('policy') ||\n normalized.includes('iframe') ||\n normalized.includes('frame')\n ) {\n return true;\n }\n }\n\n return false;\n}\n","import type {\n PasskeyPopupAction,\n PasskeyPopupRequestPayload,\n PasskeyPopupRequest,\n PasskeyPopupResponse,\n} from './types';\n\nexport const PASSKEY_POPUP_PATH = '/passkey/popup';\nexport const PASSKEY_POPUP_READY_EVENT = 'thru:passkey-popup-ready';\nexport const PASSKEY_POPUP_REQUEST_EVENT = 'thru:passkey-popup-request';\nexport const PASSKEY_POPUP_RESPONSE_EVENT = 'thru:passkey-popup-response';\nexport const PASSKEY_POPUP_CHANNEL = 'thru:passkey-popup-channel';\n\nconst PASSKEY_POPUP_TIMEOUT_MS = 60000;\n\nexport function closePopup(popup: Window | null | undefined): void {\n if (popup && !popup.closed) {\n popup.close();\n }\n}\n\nexport function openPasskeyPopupWindow(): Window {\n const popupUrl = new URL(PASSKEY_POPUP_PATH, window.location.origin).toString();\n const popup = window.open(\n popupUrl,\n 'thru_passkey_popup',\n 'popup=yes,width=440,height=640'\n );\n\n if (!popup) {\n throw new Error('Passkey popup was blocked');\n }\n\n return popup;\n}\n\nfunction createPopupRequestId(): string {\n const rand = Math.random().toString(36).slice(2, 10);\n return `passkey_${Date.now()}_${rand}`;\n}\n\nexport async function requestPasskeyPopup<T>(\n action: PasskeyPopupAction,\n payload: PasskeyPopupRequestPayload,\n preopenedPopup?: Window | null\n): Promise<T> {\n if (typeof window === 'undefined') {\n throw new Error('Passkey popup is only available in the browser');\n }\n\n const requestId = createPopupRequestId();\n const targetOrigin = window.location.origin;\n let popup: Window | null = preopenedPopup ?? null;\n const channel =\n typeof BroadcastChannel !== 'undefined' ? new BroadcastChannel(PASSKEY_POPUP_CHANNEL) : null;\n\n return new Promise<T>((resolve, reject) => {\n let timeout: ReturnType<typeof setTimeout> | null = null;\n let closePoll: ReturnType<typeof setInterval> | null = null;\n let requestSent = false;\n\n const cleanup = () => {\n if (timeout) {\n clearTimeout(timeout);\n timeout = null;\n }\n if (closePoll) {\n clearInterval(closePoll);\n closePoll = null;\n }\n window.removeEventListener('message', handleMessage);\n if (channel) {\n channel.removeEventListener('message', handleChannelMessage);\n channel.close();\n }\n };\n\n const sendRequest = (viaChannel: boolean) => {\n if (requestSent) {\n return;\n }\n requestSent = true;\n\n const request: PasskeyPopupRequest = {\n type: PASSKEY_POPUP_REQUEST_EVENT,\n requestId,\n action,\n payload,\n };\n\n if (viaChannel) {\n channel?.postMessage(request);\n return;\n }\n\n popup?.postMessage(request, targetOrigin);\n };\n\n const handleResponse = (data: PasskeyPopupResponse) => {\n if (data.requestId !== requestId) {\n return;\n }\n\n cleanup();\n if (popup && !popup.closed) {\n popup.close();\n }\n\n if (data.success) {\n resolve((data as Extract<PasskeyPopupResponse, { success: true }>).result as T);\n } else {\n const err = new Error(data.error?.message || 'Passkey popup failed');\n if (data.error?.name) {\n (err as { name?: string }).name = data.error.name;\n }\n reject(err);\n }\n };\n\n const handleMessage = (event: MessageEvent) => {\n if (event.origin !== targetOrigin) {\n return;\n }\n\n const data = event.data as PasskeyPopupResponse | { type?: string };\n if (!data || typeof data !== 'object') {\n return;\n }\n\n if (data.type === PASSKEY_POPUP_READY_EVENT) {\n if (popup && event.source !== popup) {\n return;\n }\n sendRequest(false);\n return;\n }\n\n if (data.type === PASSKEY_POPUP_RESPONSE_EVENT && 'requestId' in data) {\n handleResponse(data as PasskeyPopupResponse);\n }\n };\n\n window.addEventListener('message', handleMessage);\n\n const handleChannelMessage = (event: MessageEvent) => {\n const data = event.data as PasskeyPopupResponse | { type?: string };\n if (!data || typeof data !== 'object') {\n return;\n }\n\n if (data.type === PASSKEY_POPUP_READY_EVENT) {\n sendRequest(true);\n return;\n }\n\n if (data.type === PASSKEY_POPUP_RESPONSE_EVENT && 'requestId' in data) {\n handleResponse(data as PasskeyPopupResponse);\n }\n };\n\n if (channel) {\n channel.addEventListener('message', handleChannelMessage);\n }\n\n if (!popup) {\n try {\n popup = openPasskeyPopupWindow();\n } catch (error) {\n cleanup();\n reject(error);\n return;\n }\n }\n\n timeout = setTimeout(() => {\n cleanup();\n try {\n popup?.close();\n } catch {\n /* ignore */\n }\n reject(new Error('Passkey popup timed out'));\n }, PASSKEY_POPUP_TIMEOUT_MS);\n\n closePoll = setInterval(() => {\n if (popup && popup.closed) {\n cleanup();\n reject(new Error('Passkey popup was closed'));\n }\n }, 250);\n });\n}\n","const DEFAULT_LABEL = 'Thru Wallet passkey';\n\nexport interface DistinctPasskeyLabelOptions {\n existingLabels?: Iterable<string | null | undefined>;\n maxAttempts?: number;\n suffixFactory?: () => string;\n}\n\nexport function createDistinctPasskeyLabel(\n baseLabel: string,\n _options: DistinctPasskeyLabelOptions = {}\n): string {\n return baseLabel.trim() || DEFAULT_LABEL;\n}\n","import type {\n PasskeySigningResult,\n PasskeyStoredSigningResult,\n PasskeyDiscoverableSigningResult,\n PasskeyMetadata,\n PasskeyPopupContext,\n PasskeyPopupSigningResult,\n PasskeyPopupStoredSigningResult,\n PasskeyStoredSigningOptions,\n} from './types';\nimport {\n arrayBufferToBase64Url,\n base64UrlToArrayBuffer,\n bytesToBase64Url,\n base64UrlToBytes,\n parseDerSignature,\n normalizeLowS,\n} from '@thru/programs/passkey-manager';\nimport {\n isWebAuthnSupported,\n getPasskeyPromptMode,\n isInIframe,\n maybePreopenPopup,\n shouldFallbackToPopup,\n type PasskeyPromptAction,\n} from './capabilities';\nimport {\n requestPasskeyPopup,\n openPasskeyPopupWindow,\n closePopup,\n} from './popup';\n\nconst WEB_AUTHN_FOCUS_RETRY_DELAYS_MS = [150, 300];\n\n/**\n * Sign a challenge with an existing passkey (by credential ID).\n */\nexport async function signWithPasskey(\n credentialId: string,\n challenge: Uint8Array,\n rpId: string\n): Promise<PasskeySigningResult> {\n if (!isWebAuthnSupported()) {\n throw new Error('WebAuthn is not supported in this browser');\n }\n\n return runWithPromptMode(\n 'get',\n () => signWithPasskeyInline(credentialId, challenge, rpId),\n (preopenedPopup) =>\n signWithPasskeyViaPopup(credentialId, challenge, rpId, preopenedPopup)\n );\n}\n\n/**\n * Sign with stored passkey (for embedded/popup contexts).\n */\nexport async function signWithStoredPasskey(\n challenge: Uint8Array,\n rpId: string,\n preferredPasskey: PasskeyMetadata | null,\n allPasskeys: PasskeyMetadata[],\n context?: PasskeyPopupContext,\n options: PasskeyStoredSigningOptions = {}\n): Promise<PasskeyStoredSigningResult> {\n if (!isWebAuthnSupported()) {\n throw new Error('WebAuthn is not supported in this browser');\n }\n\n const allowPopupFallback = options.allowPopupFallback ?? true;\n const allowDiscoverableFallback = options.allowDiscoverableFallback ?? true;\n const preopenedPopup = allowPopupFallback\n ? maybePreopenPopup('get', openPasskeyPopupWindow)\n : null;\n const promptMode = allowPopupFallback\n ? await getPasskeyPromptMode('get')\n : 'inline';\n const storedPasskey = preferredPasskey;\n const canUsePopup = allowPopupFallback && isInIframe();\n\n if (!allowDiscoverableFallback && !storedPasskey) {\n closePopup(preopenedPopup);\n throw new Error('No stored passkey available for this wallet');\n }\n\n if (options.preferDiscoverable) {\n closePopup(preopenedPopup);\n return signWithDiscoverableStoredPasskey(\n challenge,\n storedPasskey?.rpId ?? rpId,\n allPasskeys\n );\n }\n\n if (promptMode === 'popup' || (canUsePopup && !storedPasskey)) {\n return requestStoredPasskeyPopup(challenge, preopenedPopup, context);\n }\n\n closePopup(preopenedPopup);\n\n try {\n if (storedPasskey) {\n try {\n const result = await signWithPasskeyInline(\n storedPasskey.credentialId,\n challenge,\n storedPasskey.rpId\n );\n return {\n ...result,\n passkey: storedPasskey,\n };\n } catch (error) {\n if (!allowDiscoverableFallback || !shouldFallbackToDiscoverable(error)) {\n throw error;\n }\n return signWithDiscoverableStoredPasskey(\n challenge,\n storedPasskey.rpId,\n allPasskeys\n );\n }\n }\n\n return signWithDiscoverableStoredPasskey(challenge, rpId, allPasskeys);\n } catch (error) {\n if (canUsePopup && shouldFallbackToPopup(error)) {\n return requestStoredPasskeyPopup(challenge, undefined, context);\n }\n\n throw error;\n }\n}\n\nasync function signWithDiscoverableStoredPasskey(\n challenge: Uint8Array,\n rpId: string,\n allPasskeys: PasskeyMetadata[]\n): Promise<PasskeyStoredSigningResult> {\n const discoverable = await signWithDiscoverablePasskey(challenge, rpId);\n const matchingPasskey =\n allPasskeys.find((p) => p.credentialId === discoverable.credentialId) ??\n null;\n const now = new Date().toISOString();\n const passkey = matchingPasskey ?? {\n credentialId: discoverable.credentialId,\n publicKeyX: '',\n publicKeyY: '',\n rpId: discoverable.rpId,\n createdAt: now,\n lastUsedAt: now,\n };\n\n return {\n signature: discoverable.signature,\n authenticatorData: discoverable.authenticatorData,\n clientDataJSON: discoverable.clientDataJSON,\n signatureR: discoverable.signatureR,\n signatureS: discoverable.signatureS,\n authenticatorAttachment: discoverable.authenticatorAttachment,\n passkey,\n };\n}\n\nfunction shouldFallbackToDiscoverable(error: unknown): boolean {\n const name =\n error && typeof error === 'object' && 'name' in error\n ? String((error as { name?: unknown }).name)\n : '';\n const message =\n error && typeof error === 'object' && 'message' in error\n ? String((error as { message?: unknown }).message)\n : '';\n const normalized = `${name} ${message}`.toLowerCase();\n\n if (\n normalized.includes('user rejected') ||\n normalized.includes('user canceled') ||\n normalized.includes('user cancelled')\n ) {\n return false;\n }\n\n return (\n normalized.includes('notallowederror') ||\n normalized.includes('invalidstateerror') ||\n normalized.includes('notfounderror') ||\n normalized.includes('not found') ||\n normalized.includes('no passkey') ||\n normalized.includes('no credential') ||\n normalized.includes('saved for this app')\n );\n}\n\n/**\n * Sign with a discoverable passkey (no credential ID - browser prompts user to select).\n */\nexport async function signWithDiscoverablePasskey(\n challenge: Uint8Array,\n rpId: string\n): Promise<PasskeyDiscoverableSigningResult> {\n if (!isWebAuthnSupported()) {\n throw new Error('WebAuthn is not supported in this browser');\n }\n\n const resolvedRpId = rpId;\n const result = await signWithPasskeyAssertion(challenge, resolvedRpId);\n\n return {\n signature: result.signature,\n authenticatorData: result.authenticatorData,\n clientDataJSON: result.clientDataJSON,\n signatureR: result.signatureR,\n signatureS: result.signatureS,\n credentialId: result.credentialId,\n rpId: resolvedRpId,\n authenticatorAttachment: result.authenticatorAttachment,\n };\n}\n\n// Internal helpers\n\nasync function runWithPromptMode<T>(\n action: PasskeyPromptAction,\n inlineFn: () => Promise<T>,\n popupFn: (preopenedPopup?: Window | null) => Promise<T>\n): Promise<T> {\n const preopenedPopup = maybePreopenPopup(action, openPasskeyPopupWindow);\n const promptMode = await getPasskeyPromptMode(action);\n if (promptMode === 'popup') {\n return popupFn(preopenedPopup);\n }\n\n closePopup(preopenedPopup);\n\n try {\n return await inlineFn();\n } catch (error) {\n if (shouldFallbackToPopup(error)) {\n return popupFn();\n }\n throw error;\n }\n}\n\nasync function signWithPasskeyInline(\n credentialId: string,\n challenge: Uint8Array,\n rpId: string\n): Promise<PasskeySigningResult> {\n const result = await signWithPasskeyAssertion(challenge, rpId, credentialId);\n return {\n signature: result.signature,\n authenticatorData: result.authenticatorData,\n clientDataJSON: result.clientDataJSON,\n signatureR: result.signatureR,\n signatureS: result.signatureS,\n authenticatorAttachment: result.authenticatorAttachment,\n };\n}\n\nasync function signWithPasskeyAssertion(\n challenge: Uint8Array,\n rpId: string,\n credentialId?: string\n): Promise<PasskeySigningResult & { credentialId: string }> {\n const challengeBytes = new Uint8Array(challenge);\n const getOptions: PublicKeyCredentialRequestOptions = {\n challenge: challengeBytes,\n rpId,\n userVerification: 'required',\n timeout: 60000,\n };\n\n if (credentialId) {\n const credentialIdBuffer = base64UrlToArrayBuffer(credentialId);\n getOptions.allowCredentials = [\n {\n type: 'public-key',\n id: credentialIdBuffer,\n transports: ['internal', 'hybrid', 'usb', 'ble', 'nfc'],\n },\n ];\n }\n\n const assertion = await getPasskeyAssertionWithFocusRetry(getOptions);\n\n if (!assertion) {\n throw new Error('Passkey authentication was cancelled');\n }\n\n const response = assertion.response as AuthenticatorAssertionResponse;\n\n const signature = new Uint8Array(response.signature);\n let { r, s } = parseDerSignature(signature);\n s = normalizeLowS(s);\n\n /* `authenticatorAttachment` distinguishes a same-device passkey\n ('platform') from a cross-device one signed via QR / hybrid\n transport ('cross-platform'). Drives the wallet's add-device\n prompt. Browsers may report null. */\n const rawAttachment =\n (\n assertion as PublicKeyCredential & {\n authenticatorAttachment?: AuthenticatorAttachment | null;\n }\n ).authenticatorAttachment ?? null;\n\n return {\n signature: new Uint8Array([...r, ...s]),\n authenticatorData: new Uint8Array(response.authenticatorData),\n clientDataJSON: new Uint8Array(response.clientDataJSON),\n signatureR: r,\n signatureS: s,\n credentialId: arrayBufferToBase64Url(assertion.rawId),\n authenticatorAttachment: rawAttachment,\n };\n}\n\nasync function getPasskeyAssertionWithFocusRetry(\n publicKey: PublicKeyCredentialRequestOptions\n): Promise<PublicKeyCredential | null> {\n for (let attempt = 0; ; attempt += 1) {\n try {\n return (await navigator.credentials.get({\n publicKey,\n })) as PublicKeyCredential | null;\n } catch (error) {\n const retryDelayMs = WEB_AUTHN_FOCUS_RETRY_DELAYS_MS[attempt];\n if (retryDelayMs === undefined || !isDocumentNotFocusedError(error)) {\n throw error;\n }\n await waitForFocusRetry(retryDelayMs);\n }\n }\n}\n\nfunction isDocumentNotFocusedError(error: unknown): boolean {\n const name =\n error && typeof error === 'object' && 'name' in error\n ? String((error as { name?: unknown }).name)\n : '';\n const message =\n error && typeof error === 'object' && 'message' in error\n ? String((error as { message?: unknown }).message)\n : '';\n const normalized = `${name} ${message}`.toLowerCase();\n return normalized.includes('document is not focused');\n}\n\nfunction waitForFocusRetry(delayMs: number): Promise<void> {\n return new Promise((resolve) => {\n const finish = () => setTimeout(resolve, delayMs);\n if (typeof requestAnimationFrame !== 'function') {\n finish();\n return;\n }\n requestAnimationFrame(() => requestAnimationFrame(finish));\n });\n}\n\nasync function signWithPasskeyViaPopup(\n credentialId: string,\n challenge: Uint8Array,\n rpId: string,\n preopenedPopup?: Window | null\n): Promise<PasskeySigningResult> {\n const result = await requestPasskeyPopup<PasskeyPopupSigningResult>(\n 'get',\n {\n credentialId,\n challengeBase64Url: bytesToBase64Url(challenge),\n rpId,\n },\n preopenedPopup\n );\n\n return decodePopupSigningResult(result);\n}\n\nasync function requestStoredPasskeyPopup(\n challenge: Uint8Array,\n preopenedPopup?: Window | null,\n context?: PasskeyPopupContext\n): Promise<PasskeyStoredSigningResult> {\n const result = await requestPasskeyPopup<PasskeyPopupStoredSigningResult>(\n 'getStored',\n {\n challengeBase64Url: bytesToBase64Url(challenge),\n context,\n },\n preopenedPopup\n );\n return decodePopupStoredSigningResult(result);\n}\n\nfunction decodePopupSigningResult(\n result: PasskeyPopupSigningResult\n): PasskeySigningResult {\n return {\n signature: base64UrlToBytes(result.signatureBase64Url),\n authenticatorData: base64UrlToBytes(result.authenticatorDataBase64Url),\n clientDataJSON: base64UrlToBytes(result.clientDataJSONBase64Url),\n signatureR: base64UrlToBytes(result.signatureRBase64Url),\n signatureS: base64UrlToBytes(result.signatureSBase64Url),\n authenticatorAttachment: result.authenticatorAttachment ?? null,\n };\n}\n\nfunction decodePopupStoredSigningResult(\n result: PasskeyPopupStoredSigningResult\n): PasskeyStoredSigningResult {\n return {\n ...decodePopupSigningResult(result),\n passkey: result.passkey,\n accounts: result.accounts,\n };\n}\n"],"mappings":"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","names":["import_passkey_manager","runWithPromptMode","import_passkey_manager"]}
|
package/dist/web.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as PasskeyRegistrationOptions, c as PasskeyPopupContext, o as PasskeyStoredSigningOptions, p as PasskeyStoredSigningResult, P as PasskeyClientCapabilities } from './types-
|
|
2
|
-
export { a as PasskeyPopupAccount } from './types-
|
|
1
|
+
import { n as PasskeyRegistrationOptions, c as PasskeyPopupContext, o as PasskeyStoredSigningOptions, p as PasskeyStoredSigningResult, P as PasskeyClientCapabilities } from './types-CIzH-qtR.cjs';
|
|
2
|
+
export { a as PasskeyPopupAccount } from './types-CIzH-qtR.cjs';
|
|
3
3
|
import { PasskeyRegistrationResult, PasskeyDiscoverableSigningResult, PasskeySigningResult, PasskeyMetadata } from '@thru/programs/passkey-manager';
|
|
4
4
|
export { P256_HALF_N, P256_N, PasskeyDiscoverableSigningResult, PasskeyMetadata, PasskeyRegistrationResult, PasskeySigningResult, arrayBufferToBase64Url, base64UrlToArrayBuffer, base64UrlToBytes, bigIntToBytesBE, bytesEqual, bytesToBase64, bytesToBase64Url, bytesToBigIntBE, bytesToHex, compareBytes, hexToBytes, normalizeLowS, normalizeSignatureComponent, parseDerSignature, uniqueAccounts } from '@thru/programs/passkey-manager';
|
|
5
5
|
|
package/dist/web.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as PasskeyRegistrationOptions, c as PasskeyPopupContext, o as PasskeyStoredSigningOptions, p as PasskeyStoredSigningResult, P as PasskeyClientCapabilities } from './types-
|
|
2
|
-
export { a as PasskeyPopupAccount } from './types-
|
|
1
|
+
import { n as PasskeyRegistrationOptions, c as PasskeyPopupContext, o as PasskeyStoredSigningOptions, p as PasskeyStoredSigningResult, P as PasskeyClientCapabilities } from './types-CIzH-qtR.js';
|
|
2
|
+
export { a as PasskeyPopupAccount } from './types-CIzH-qtR.js';
|
|
3
3
|
import { PasskeyRegistrationResult, PasskeyDiscoverableSigningResult, PasskeySigningResult, PasskeyMetadata } from '@thru/programs/passkey-manager';
|
|
4
4
|
export { P256_HALF_N, P256_N, PasskeyDiscoverableSigningResult, PasskeyMetadata, PasskeyRegistrationResult, PasskeySigningResult, arrayBufferToBase64Url, base64UrlToArrayBuffer, base64UrlToBytes, bigIntToBytesBE, bytesEqual, bytesToBase64, bytesToBase64Url, bytesToBigIntBE, bytesToHex, compareBytes, hexToBytes, normalizeLowS, normalizeSignatureComponent, parseDerSignature, uniqueAccounts } from '@thru/programs/passkey-manager';
|
|
5
5
|
|
package/dist/web.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thru/passkey",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.29",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@thru/sdk": "0.2.
|
|
47
|
-
"@thru/programs": "0.2.
|
|
46
|
+
"@thru/sdk": "0.2.29",
|
|
47
|
+
"@thru/programs": "0.2.29"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"expo-secure-store": "*",
|
package/src/auth/add-device.ts
CHANGED
|
@@ -12,12 +12,15 @@
|
|
|
12
12
|
|
|
13
13
|
import {
|
|
14
14
|
type Authority,
|
|
15
|
+
type AuthorityRecord,
|
|
15
16
|
buildAccountContext,
|
|
16
|
-
|
|
17
|
+
createAuthorityRecord,
|
|
17
18
|
createCredentialLookupSeed,
|
|
19
|
+
createValidateChallenge,
|
|
18
20
|
decodeAddress,
|
|
19
21
|
deriveWalletAddress,
|
|
20
22
|
encodeAddAuthorityInstruction,
|
|
23
|
+
encodeLegacyAddAuthorityInstruction,
|
|
21
24
|
encodeRegisterCredentialInstruction,
|
|
22
25
|
encodeValidateInstruction,
|
|
23
26
|
parseWalletAuthorities,
|
|
@@ -57,6 +60,7 @@ export interface AddDeviceParams {
|
|
|
57
60
|
authIdx: number;
|
|
58
61
|
/** New passkey to attach. tag = 1 (passkey). */
|
|
59
62
|
newAuthority: Authority;
|
|
63
|
+
newAuthorityRecord?: AuthorityRecord;
|
|
60
64
|
/** Optional credential-lookup registration so the new passkey is
|
|
61
65
|
discoverable on subsequent sign-ins. */
|
|
62
66
|
credentialId?: Uint8Array;
|
|
@@ -100,12 +104,32 @@ export interface AddDeviceResult extends TxExecutorResult {
|
|
|
100
104
|
newAuthorityIdx: number;
|
|
101
105
|
}
|
|
102
106
|
|
|
107
|
+
export interface AddAuthorityParams
|
|
108
|
+
extends Omit<AddDeviceParams, "newAuthority" | "newAuthorityRecord" | "credentialId" | "walletName"> {
|
|
109
|
+
/** Complete authority record to append. */
|
|
110
|
+
authorityRecord: AuthorityRecord;
|
|
111
|
+
}
|
|
112
|
+
|
|
103
113
|
/**
|
|
104
114
|
* Run VALIDATE + ADD_AUTHORITY [+ REGISTER_CREDENTIAL] to attach a new
|
|
105
115
|
* passkey to an on-chain WalletAccount.
|
|
106
116
|
*/
|
|
107
117
|
export async function addDeviceToAccount(
|
|
108
118
|
params: AddDeviceParams,
|
|
119
|
+
): Promise<AddDeviceResult> {
|
|
120
|
+
return addAuthorityToAccount({
|
|
121
|
+
...params,
|
|
122
|
+
authorityRecord:
|
|
123
|
+
params.newAuthorityRecord ?? createAuthorityRecord(params.newAuthority),
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Run VALIDATE + ADD_AUTHORITY to attach a complete authority record to an
|
|
129
|
+
* on-chain WalletAccount.
|
|
130
|
+
*/
|
|
131
|
+
export async function addAuthorityToAccount(
|
|
132
|
+
params: AddAuthorityParams & Pick<AddDeviceParams, "credentialId" | "walletName">,
|
|
109
133
|
): Promise<AddDeviceResult> {
|
|
110
134
|
const status = params.onStatus ?? (() => {});
|
|
111
135
|
|
|
@@ -159,9 +183,13 @@ export async function addDeviceToAccount(
|
|
|
159
183
|
});
|
|
160
184
|
|
|
161
185
|
const passkeyProgramPubkey = decodeAddress(params.programAddress);
|
|
162
|
-
const
|
|
186
|
+
const encodeAuthorityInstruction =
|
|
187
|
+
parsed.layout === "legacyAuthority"
|
|
188
|
+
? encodeLegacyAddAuthorityInstruction
|
|
189
|
+
: encodeAddAuthorityInstruction;
|
|
190
|
+
const addAuthorityInstruction = encodeAuthorityInstruction({
|
|
163
191
|
walletAccountIdx: ctx.walletAccountIdx,
|
|
164
|
-
|
|
192
|
+
authorityRecord: params.authorityRecord,
|
|
165
193
|
});
|
|
166
194
|
|
|
167
195
|
let targetProgramIdx = ctx.getAccountIndex(passkeyProgramPubkey);
|
package/src/auth/index.ts
CHANGED
|
@@ -11,8 +11,9 @@ export type {
|
|
|
11
11
|
|
|
12
12
|
export { executePasskeyTransaction } from './execute-tx';
|
|
13
13
|
|
|
14
|
-
export { addDeviceToAccount } from './add-device';
|
|
14
|
+
export { addAuthorityToAccount, addDeviceToAccount } from './add-device';
|
|
15
15
|
export type {
|
|
16
|
+
AddAuthorityParams,
|
|
16
17
|
AddDeviceParams,
|
|
17
18
|
AddDeviceResult,
|
|
18
19
|
AnyThruClient,
|
package/src/mobile/passkey.ts
CHANGED
|
@@ -22,7 +22,7 @@ function getDefaultConfig(config?: PasskeyMobileConfig): Required<PasskeyMobileC
|
|
|
22
22
|
const env = (globalThis as ProcessLike).process?.env ?? {};
|
|
23
23
|
|
|
24
24
|
return {
|
|
25
|
-
rpId: config?.rpId ?? env.EXPO_PUBLIC_PASSKEY_RP_ID ?? '
|
|
25
|
+
rpId: config?.rpId ?? env.EXPO_PUBLIC_PASSKEY_RP_ID ?? 'app.tid.sh',
|
|
26
26
|
rpName: config?.rpName ?? env.EXPO_PUBLIC_PASSKEY_RP_NAME ?? 'Thru Wallet',
|
|
27
27
|
};
|
|
28
28
|
}
|
|
@@ -22,6 +22,10 @@ vi.mock('@thru/programs/passkey-manager', () => ({
|
|
|
22
22
|
readOnlyAddresses: [],
|
|
23
23
|
getAccountIndex: () => 2,
|
|
24
24
|
}),
|
|
25
|
+
createAuthorityRecord: (authority: unknown) => ({
|
|
26
|
+
authority,
|
|
27
|
+
expiresAtBlockTimeSeconds: 0xffffffffffffffffn,
|
|
28
|
+
}),
|
|
25
29
|
createCredentialLookupSeed: async () => new Uint8Array([8]),
|
|
26
30
|
createWalletSeed: async () => new Uint8Array([1]),
|
|
27
31
|
deriveCredentialLookupAddress: async () => new Uint8Array([22]),
|