@thru/passkey 0.2.21 → 0.2.23
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 +139 -0
- package/dist/auth/add-device.cjs.map +1 -0
- package/dist/auth/add-device.d.cts +69 -0
- package/dist/auth/add-device.d.ts +69 -0
- package/dist/auth/add-device.js +7 -0
- package/dist/auth/add-device.js.map +1 -0
- package/dist/auth.cjs +121 -6
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +2 -0
- package/dist/auth.d.ts +2 -0
- package/dist/auth.js +10 -4
- package/dist/auth.js.map +1 -1
- package/dist/chunk-KASTJBBY.js +128 -0
- package/dist/chunk-KASTJBBY.js.map +1 -0
- package/dist/{chunk-75G2FPYW.js → chunk-OULTQZT7.js} +4 -3
- package/dist/chunk-OULTQZT7.js.map +1 -0
- package/dist/{chunk-B5SN7AS7.js → chunk-TW7HANJM.js} +99 -49
- package/dist/chunk-TW7HANJM.js.map +1 -0
- package/dist/{chunk-2JHC7OOH.js → chunk-ZNBMADOM.js} +2 -2
- package/dist/chunk-ZNBMADOM.js.map +1 -0
- package/dist/index.cjs +102 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -2
- package/dist/mobile.cjs +2 -2
- package/dist/mobile.cjs.map +1 -1
- package/dist/mobile.d.cts +2 -2
- package/dist/mobile.d.ts +2 -2
- package/dist/mobile.js +2 -2
- package/dist/mobile.js.map +1 -1
- package/dist/popup.cjs +3 -2
- package/dist/popup.cjs.map +1 -1
- package/dist/popup.d.cts +3 -3
- package/dist/popup.d.ts +3 -3
- package/dist/popup.js +1 -1
- package/dist/server.cjs +54 -66
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +14 -6
- package/dist/server.d.ts +14 -6
- package/dist/server.js +58 -69
- package/dist/server.js.map +1 -1
- package/dist/{types-_HRzmn-j.d.cts → types-BTTlCVrw.d.cts} +25 -2
- package/dist/{types-_HRzmn-j.d.ts → types-BTTlCVrw.d.ts} +25 -2
- package/dist/web.cjs +99 -48
- package/dist/web.cjs.map +1 -1
- package/dist/web.d.cts +14 -7
- package/dist/web.d.ts +14 -7
- package/dist/web.js +3 -1
- package/package.json +11 -6
- package/src/auth/add-device.ts +236 -0
- package/src/auth/execute-tx.ts +1 -1
- package/src/auth/index.ts +11 -0
- package/src/auth/use-passkey-auth.ts +4 -2
- package/src/capabilities.ts +2 -1
- package/src/index.ts +4 -0
- package/src/label.test.ts +21 -0
- package/src/label.ts +14 -0
- package/src/mobile/index.ts +1 -1
- package/src/mobile/passkey.ts +1 -1
- package/src/mobile/storage.ts +1 -1
- package/src/mobile/types.ts +2 -2
- package/src/popup-service.ts +2 -1
- package/src/register.ts +23 -8
- package/src/server/challenge.ts +15 -4
- package/src/server/create-wallet.test.ts +2 -2
- package/src/server/create-wallet.ts +24 -16
- package/src/server/handlers.ts +6 -2
- package/src/server/submit.test.ts +24 -6
- package/src/server/submit.ts +41 -10
- package/src/server/types.ts +5 -3
- package/src/server/utils.ts +1 -1
- package/src/sign.ts +127 -37
- package/src/types.ts +27 -2
- package/src/web.ts +6 -2
- package/tsconfig.json +3 -2
- package/tsup.config.ts +1 -0
- package/dist/chunk-2JHC7OOH.js.map +0 -1
- package/dist/chunk-75G2FPYW.js.map +0 -1
- package/dist/chunk-B5SN7AS7.js.map +0 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/auth/add-device.ts
|
|
21
|
+
var add_device_exports = {};
|
|
22
|
+
__export(add_device_exports, {
|
|
23
|
+
addDeviceToAccount: () => addDeviceToAccount
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(add_device_exports);
|
|
26
|
+
var import_passkey_manager = require("@thru/programs/passkey-manager");
|
|
27
|
+
var import_multicall = require("@thru/programs/multicall");
|
|
28
|
+
async function addDeviceToAccount(params) {
|
|
29
|
+
const status = params.onStatus ?? (() => {
|
|
30
|
+
});
|
|
31
|
+
const walletAccount = await params.thru.accounts.get(params.walletAddress);
|
|
32
|
+
const walletData = walletAccount?.data?.data;
|
|
33
|
+
if (!walletData) {
|
|
34
|
+
throw new Error("Wallet account data missing");
|
|
35
|
+
}
|
|
36
|
+
const parsed = (0, import_passkey_manager.parseWalletAuthorities)(walletData);
|
|
37
|
+
const authorizing = parsed.authorities[params.authIdx];
|
|
38
|
+
if (!authorizing) {
|
|
39
|
+
throw new Error("Authorization index out of bounds");
|
|
40
|
+
}
|
|
41
|
+
if (authorizing.kind !== "passkey") {
|
|
42
|
+
throw new Error(
|
|
43
|
+
"addDeviceToAccount currently requires a passkey authority for VALIDATE"
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
const newAuthorityIdx = parsed.authorities.length;
|
|
47
|
+
let readWriteAccounts = [];
|
|
48
|
+
let lookupSeed;
|
|
49
|
+
let lookupAddressBytes;
|
|
50
|
+
let lookupProof;
|
|
51
|
+
if (params.credentialId) {
|
|
52
|
+
lookupSeed = await (0, import_passkey_manager.createCredentialLookupSeed)(params.credentialId);
|
|
53
|
+
lookupAddressBytes = await (0, import_passkey_manager.deriveWalletAddress)(
|
|
54
|
+
lookupSeed,
|
|
55
|
+
params.programAddress
|
|
56
|
+
);
|
|
57
|
+
status("Fetching state proof for credential lookup...");
|
|
58
|
+
const proofResult = await params.thru.proofs.generate({
|
|
59
|
+
proofType: 1,
|
|
60
|
+
address: lookupAddressBytes
|
|
61
|
+
});
|
|
62
|
+
lookupProof = proofResult.proof;
|
|
63
|
+
readWriteAccounts = [lookupAddressBytes];
|
|
64
|
+
}
|
|
65
|
+
const ctx = (0, import_passkey_manager.buildAccountContext)({
|
|
66
|
+
walletAddress: params.walletAddress,
|
|
67
|
+
readWriteAccounts,
|
|
68
|
+
readOnlyAccounts: params.credentialId ? [import_multicall.MULTICALL_PROGRAM_PUBKEY] : [],
|
|
69
|
+
programAddress: params.programAddress
|
|
70
|
+
});
|
|
71
|
+
const passkeyProgramPubkey = (0, import_passkey_manager.decodeAddress)(params.programAddress);
|
|
72
|
+
const addAuthorityInstruction = (0, import_passkey_manager.encodeAddAuthorityInstruction)({
|
|
73
|
+
walletAccountIdx: ctx.walletAccountIdx,
|
|
74
|
+
authority: params.newAuthority
|
|
75
|
+
});
|
|
76
|
+
let targetProgramIdx = ctx.getAccountIndex(passkeyProgramPubkey);
|
|
77
|
+
let targetInstructionData = addAuthorityInstruction;
|
|
78
|
+
if (params.credentialId) {
|
|
79
|
+
if (!lookupSeed || !lookupAddressBytes || !lookupProof) {
|
|
80
|
+
throw new Error("Credential lookup proof data missing");
|
|
81
|
+
}
|
|
82
|
+
const registerCredentialInstruction = (0, import_passkey_manager.encodeRegisterCredentialInstruction)({
|
|
83
|
+
walletAccountIdx: ctx.walletAccountIdx,
|
|
84
|
+
lookupAccountIdx: ctx.getAccountIndex(lookupAddressBytes),
|
|
85
|
+
seed: lookupSeed,
|
|
86
|
+
stateProof: lookupProof
|
|
87
|
+
});
|
|
88
|
+
targetProgramIdx = ctx.getAccountIndex(import_multicall.MULTICALL_PROGRAM_PUBKEY);
|
|
89
|
+
targetInstructionData = (0, import_multicall.buildMulticallInstruction)([
|
|
90
|
+
{
|
|
91
|
+
programIdx: ctx.getAccountIndex(passkeyProgramPubkey),
|
|
92
|
+
instructionData: addAuthorityInstruction
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
programIdx: ctx.getAccountIndex(passkeyProgramPubkey),
|
|
96
|
+
instructionData: registerCredentialInstruction
|
|
97
|
+
}
|
|
98
|
+
]);
|
|
99
|
+
}
|
|
100
|
+
const challenge = await (0, import_passkey_manager.createValidateChallenge)(
|
|
101
|
+
parsed.nonce,
|
|
102
|
+
ctx.accountAddresses,
|
|
103
|
+
ctx.walletAccountIdx,
|
|
104
|
+
params.authIdx,
|
|
105
|
+
{
|
|
106
|
+
programIdx: targetProgramIdx,
|
|
107
|
+
instructionData: targetInstructionData
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
status("Waiting for passkey approval...");
|
|
111
|
+
const signature = await params.passkey.signChallenge(challenge);
|
|
112
|
+
const validateInstruction = (0, import_passkey_manager.encodeValidateInstruction)({
|
|
113
|
+
walletAccountIdx: ctx.walletAccountIdx,
|
|
114
|
+
authIdx: params.authIdx,
|
|
115
|
+
targetInstruction: {
|
|
116
|
+
programIdx: targetProgramIdx,
|
|
117
|
+
instructionData: targetInstructionData
|
|
118
|
+
},
|
|
119
|
+
signatureR: signature.signatureR,
|
|
120
|
+
signatureS: signature.signatureS,
|
|
121
|
+
authenticatorData: signature.authenticatorData,
|
|
122
|
+
clientDataJSON: signature.clientDataJSON
|
|
123
|
+
});
|
|
124
|
+
status("Sending transaction...");
|
|
125
|
+
const result = await params.executor({
|
|
126
|
+
thru: params.thru,
|
|
127
|
+
walletSigner: params.walletSigner,
|
|
128
|
+
instructionData: validateInstruction,
|
|
129
|
+
readWriteAddresses: ctx.readWriteAddresses,
|
|
130
|
+
readOnlyAddresses: ctx.readOnlyAddresses,
|
|
131
|
+
label: params.credentialId ? "VALIDATE -> MULTICALL(ADD_AUTHORITY, REGISTER_CREDENTIAL)" : "VALIDATE -> ADD_AUTHORITY"
|
|
132
|
+
});
|
|
133
|
+
return { ...result, newAuthorityIdx };
|
|
134
|
+
}
|
|
135
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
136
|
+
0 && (module.exports = {
|
|
137
|
+
addDeviceToAccount
|
|
138
|
+
});
|
|
139
|
+
//# sourceMappingURL=add-device.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/auth/add-device.ts"],"sourcesContent":["/* Add-passkey-to-account transaction builder, lifted from\n `web/wallet-auth-manager/app/page.tsx` (`runValidateThen`,\n `handleSubmitAddPasskey`) so the wallet's `/embedded` post-connect\n step can reuse the exact same flow.\n\n Builds the on-chain transaction:\n VALIDATE(existingAuthority -> ADD_AUTHORITY(newPasskey))\n or VALIDATE(existingAuthority -> multicall[ADD_AUTHORITY, REGISTER_CREDENTIAL])\n asks the caller's existing passkey to sign the challenge, then asks\n the caller's wallet signer to sign the assembled transaction, sends\n it, and returns the result. */\n\nimport {\n type Authority,\n buildAccountContext,\n createValidateChallenge,\n createCredentialLookupSeed,\n decodeAddress,\n deriveWalletAddress,\n encodeAddAuthorityInstruction,\n encodeRegisterCredentialInstruction,\n encodeValidateInstruction,\n parseWalletAuthorities,\n type ParsedAuthority,\n type WalletSigner,\n} from \"@thru/programs/passkey-manager\";\nimport {\n MULTICALL_PROGRAM_PUBKEY,\n buildMulticallInstruction,\n} from \"@thru/programs/multicall\";\n\n/** Minimal shape required from a passkey signer. Both web's\n `signWithDiscoverablePasskey`/`signWithPasskey` and mobile's\n counterparts conform. */\nexport interface PasskeyChallengeSigner {\n signChallenge: (challenge: Uint8Array) => Promise<{\n signatureR: Uint8Array;\n signatureS: Uint8Array;\n authenticatorData: Uint8Array;\n clientDataJSON: Uint8Array;\n }>;\n}\n\n/** Minimal shape required from a Thru chain client. Loosely-typed\n because @thru/sdk's DTS emit is currently broken in this\n repo. The caller passes the real Thru and we narrow operationally. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyThruClient = any;\n\nexport interface AddDeviceParams {\n /** Loosely-typed Thru chain client (`@thru/sdk/client`). */\n thru: AnyThruClient;\n /** Wallet (the on-chain WalletAccount) to attach the passkey to. */\n walletAddress: string;\n /** Index of the existing authority that approves this change. Must\n currently be a passkey authority. */\n authIdx: number;\n /** New passkey to attach. tag = 1 (passkey). */\n newAuthority: Authority;\n /** Optional credential-lookup registration so the new passkey is\n discoverable on subsequent sign-ins. */\n credentialId?: Uint8Array;\n walletName?: string;\n /** Existing-passkey challenge signer (web or mobile). */\n passkey: PasskeyChallengeSigner;\n /** Wallet transaction signer that returns base64(signed bytes). */\n walletSigner: WalletSigner;\n /** Passkey program address (base58). */\n programAddress: string;\n /** Sign-and-send executor (lifted from passkey-transaction.ts in the\n wallet-auth-manager - wallet apps own this because it depends on\n the `Thru` client's transaction builder). */\n executor: TxExecutor;\n /** Optional status callback so UIs can show progress. */\n onStatus?: (message: string) => void;\n}\n\nexport interface TxExecutorParams {\n thru: AnyThruClient;\n walletSigner: WalletSigner;\n instructionData: Uint8Array;\n readWriteAddresses: string[];\n readOnlyAddresses: string[];\n label: string;\n}\n\nexport interface TxExecutorResult {\n signature: string;\n /** Loosely-typed because @thru/sdk types aren't available. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n execution: any;\n}\n\nexport type TxExecutor = (\n params: TxExecutorParams,\n) => Promise<TxExecutorResult>;\n\nexport interface AddDeviceResult extends TxExecutorResult {\n /** The new passkey's authority index after the transaction lands. */\n newAuthorityIdx: number;\n}\n\n/**\n * Run VALIDATE + ADD_AUTHORITY [+ REGISTER_CREDENTIAL] to attach a new\n * passkey to an on-chain WalletAccount.\n */\nexport async function addDeviceToAccount(\n params: AddDeviceParams,\n): Promise<AddDeviceResult> {\n const status = params.onStatus ?? (() => {});\n\n const walletAccount = await params.thru.accounts.get(params.walletAddress);\n const walletData: Uint8Array | undefined = walletAccount?.data?.data;\n if (!walletData) {\n throw new Error(\"Wallet account data missing\");\n }\n\n const parsed = parseWalletAuthorities(walletData);\n const authorizing: ParsedAuthority | undefined =\n parsed.authorities[params.authIdx];\n if (!authorizing) {\n throw new Error(\"Authorization index out of bounds\");\n }\n if (authorizing.kind !== \"passkey\") {\n throw new Error(\n \"addDeviceToAccount currently requires a passkey authority for VALIDATE\",\n );\n }\n\n /* The new authority will land at the next free slot. */\n const newAuthorityIdx = parsed.authorities.length;\n\n let readWriteAccounts: Uint8Array[] = [];\n let lookupSeed: Uint8Array | undefined;\n let lookupAddressBytes: Uint8Array | undefined;\n let lookupProof: Uint8Array | undefined;\n\n if (params.credentialId) {\n lookupSeed = await createCredentialLookupSeed(params.credentialId);\n lookupAddressBytes = await deriveWalletAddress(\n lookupSeed,\n params.programAddress,\n );\n\n status(\"Fetching state proof for credential lookup...\");\n const proofResult = await params.thru.proofs.generate({\n proofType: 1 /* StateProofType.CREATING */,\n address: lookupAddressBytes,\n });\n lookupProof = proofResult.proof;\n readWriteAccounts = [lookupAddressBytes];\n }\n\n const ctx = buildAccountContext({\n walletAddress: params.walletAddress,\n readWriteAccounts,\n readOnlyAccounts: params.credentialId ? [MULTICALL_PROGRAM_PUBKEY] : [],\n programAddress: params.programAddress,\n });\n\n const passkeyProgramPubkey = decodeAddress(params.programAddress);\n const addAuthorityInstruction = encodeAddAuthorityInstruction({\n walletAccountIdx: ctx.walletAccountIdx,\n authority: params.newAuthority,\n });\n\n let targetProgramIdx = ctx.getAccountIndex(passkeyProgramPubkey);\n let targetInstructionData = addAuthorityInstruction;\n\n if (params.credentialId) {\n if (!lookupSeed || !lookupAddressBytes || !lookupProof) {\n throw new Error(\"Credential lookup proof data missing\");\n }\n\n const registerCredentialInstruction = encodeRegisterCredentialInstruction({\n walletAccountIdx: ctx.walletAccountIdx,\n lookupAccountIdx: ctx.getAccountIndex(lookupAddressBytes),\n seed: lookupSeed,\n stateProof: lookupProof,\n });\n\n targetProgramIdx = ctx.getAccountIndex(MULTICALL_PROGRAM_PUBKEY);\n targetInstructionData = buildMulticallInstruction([\n {\n programIdx: ctx.getAccountIndex(passkeyProgramPubkey),\n instructionData: addAuthorityInstruction,\n },\n {\n programIdx: ctx.getAccountIndex(passkeyProgramPubkey),\n instructionData: registerCredentialInstruction,\n },\n ]);\n }\n\n /* Build the VALIDATE challenge over the target CPI and ask the caller's passkey to sign. */\n const challenge = await createValidateChallenge(\n parsed.nonce,\n ctx.accountAddresses,\n ctx.walletAccountIdx,\n params.authIdx,\n {\n programIdx: targetProgramIdx,\n instructionData: targetInstructionData,\n },\n );\n\n status(\"Waiting for passkey approval...\");\n const signature = await params.passkey.signChallenge(challenge);\n\n const validateInstruction = encodeValidateInstruction({\n walletAccountIdx: ctx.walletAccountIdx,\n authIdx: params.authIdx,\n targetInstruction: {\n programIdx: targetProgramIdx,\n instructionData: targetInstructionData,\n },\n signatureR: signature.signatureR,\n signatureS: signature.signatureS,\n authenticatorData: signature.authenticatorData,\n clientDataJSON: signature.clientDataJSON,\n });\n\n status(\"Sending transaction...\");\n const result = await params.executor({\n thru: params.thru,\n walletSigner: params.walletSigner,\n instructionData: validateInstruction,\n readWriteAddresses: ctx.readWriteAddresses,\n readOnlyAddresses: ctx.readOnlyAddresses,\n label: params.credentialId\n ? \"VALIDATE -> MULTICALL(ADD_AUTHORITY, REGISTER_CREDENTIAL)\"\n : \"VALIDATE -> ADD_AUTHORITY\",\n });\n\n return { ...result, newAuthorityIdx };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Authority, WalletSigner } from '@thru/programs/passkey-manager';
|
|
2
|
+
|
|
3
|
+
/** Minimal shape required from a passkey signer. Both web's
|
|
4
|
+
`signWithDiscoverablePasskey`/`signWithPasskey` and mobile's
|
|
5
|
+
counterparts conform. */
|
|
6
|
+
interface PasskeyChallengeSigner {
|
|
7
|
+
signChallenge: (challenge: Uint8Array) => Promise<{
|
|
8
|
+
signatureR: Uint8Array;
|
|
9
|
+
signatureS: Uint8Array;
|
|
10
|
+
authenticatorData: Uint8Array;
|
|
11
|
+
clientDataJSON: Uint8Array;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
/** Minimal shape required from a Thru chain client. Loosely-typed
|
|
15
|
+
because @thru/sdk's DTS emit is currently broken in this
|
|
16
|
+
repo. The caller passes the real Thru and we narrow operationally. */
|
|
17
|
+
type AnyThruClient = any;
|
|
18
|
+
interface AddDeviceParams {
|
|
19
|
+
/** Loosely-typed Thru chain client (`@thru/sdk/client`). */
|
|
20
|
+
thru: AnyThruClient;
|
|
21
|
+
/** Wallet (the on-chain WalletAccount) to attach the passkey to. */
|
|
22
|
+
walletAddress: string;
|
|
23
|
+
/** Index of the existing authority that approves this change. Must
|
|
24
|
+
currently be a passkey authority. */
|
|
25
|
+
authIdx: number;
|
|
26
|
+
/** New passkey to attach. tag = 1 (passkey). */
|
|
27
|
+
newAuthority: Authority;
|
|
28
|
+
/** Optional credential-lookup registration so the new passkey is
|
|
29
|
+
discoverable on subsequent sign-ins. */
|
|
30
|
+
credentialId?: Uint8Array;
|
|
31
|
+
walletName?: string;
|
|
32
|
+
/** Existing-passkey challenge signer (web or mobile). */
|
|
33
|
+
passkey: PasskeyChallengeSigner;
|
|
34
|
+
/** Wallet transaction signer that returns base64(signed bytes). */
|
|
35
|
+
walletSigner: WalletSigner;
|
|
36
|
+
/** Passkey program address (base58). */
|
|
37
|
+
programAddress: string;
|
|
38
|
+
/** Sign-and-send executor (lifted from passkey-transaction.ts in the
|
|
39
|
+
wallet-auth-manager - wallet apps own this because it depends on
|
|
40
|
+
the `Thru` client's transaction builder). */
|
|
41
|
+
executor: TxExecutor;
|
|
42
|
+
/** Optional status callback so UIs can show progress. */
|
|
43
|
+
onStatus?: (message: string) => void;
|
|
44
|
+
}
|
|
45
|
+
interface TxExecutorParams {
|
|
46
|
+
thru: AnyThruClient;
|
|
47
|
+
walletSigner: WalletSigner;
|
|
48
|
+
instructionData: Uint8Array;
|
|
49
|
+
readWriteAddresses: string[];
|
|
50
|
+
readOnlyAddresses: string[];
|
|
51
|
+
label: string;
|
|
52
|
+
}
|
|
53
|
+
interface TxExecutorResult {
|
|
54
|
+
signature: string;
|
|
55
|
+
/** Loosely-typed because @thru/sdk types aren't available. */
|
|
56
|
+
execution: any;
|
|
57
|
+
}
|
|
58
|
+
type TxExecutor = (params: TxExecutorParams) => Promise<TxExecutorResult>;
|
|
59
|
+
interface AddDeviceResult extends TxExecutorResult {
|
|
60
|
+
/** The new passkey's authority index after the transaction lands. */
|
|
61
|
+
newAuthorityIdx: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Run VALIDATE + ADD_AUTHORITY [+ REGISTER_CREDENTIAL] to attach a new
|
|
65
|
+
* passkey to an on-chain WalletAccount.
|
|
66
|
+
*/
|
|
67
|
+
declare function addDeviceToAccount(params: AddDeviceParams): Promise<AddDeviceResult>;
|
|
68
|
+
|
|
69
|
+
export { type AddDeviceParams, type AddDeviceResult, type AnyThruClient, type PasskeyChallengeSigner, type TxExecutor, type TxExecutorParams, type TxExecutorResult, addDeviceToAccount };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Authority, WalletSigner } from '@thru/programs/passkey-manager';
|
|
2
|
+
|
|
3
|
+
/** Minimal shape required from a passkey signer. Both web's
|
|
4
|
+
`signWithDiscoverablePasskey`/`signWithPasskey` and mobile's
|
|
5
|
+
counterparts conform. */
|
|
6
|
+
interface PasskeyChallengeSigner {
|
|
7
|
+
signChallenge: (challenge: Uint8Array) => Promise<{
|
|
8
|
+
signatureR: Uint8Array;
|
|
9
|
+
signatureS: Uint8Array;
|
|
10
|
+
authenticatorData: Uint8Array;
|
|
11
|
+
clientDataJSON: Uint8Array;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
/** Minimal shape required from a Thru chain client. Loosely-typed
|
|
15
|
+
because @thru/sdk's DTS emit is currently broken in this
|
|
16
|
+
repo. The caller passes the real Thru and we narrow operationally. */
|
|
17
|
+
type AnyThruClient = any;
|
|
18
|
+
interface AddDeviceParams {
|
|
19
|
+
/** Loosely-typed Thru chain client (`@thru/sdk/client`). */
|
|
20
|
+
thru: AnyThruClient;
|
|
21
|
+
/** Wallet (the on-chain WalletAccount) to attach the passkey to. */
|
|
22
|
+
walletAddress: string;
|
|
23
|
+
/** Index of the existing authority that approves this change. Must
|
|
24
|
+
currently be a passkey authority. */
|
|
25
|
+
authIdx: number;
|
|
26
|
+
/** New passkey to attach. tag = 1 (passkey). */
|
|
27
|
+
newAuthority: Authority;
|
|
28
|
+
/** Optional credential-lookup registration so the new passkey is
|
|
29
|
+
discoverable on subsequent sign-ins. */
|
|
30
|
+
credentialId?: Uint8Array;
|
|
31
|
+
walletName?: string;
|
|
32
|
+
/** Existing-passkey challenge signer (web or mobile). */
|
|
33
|
+
passkey: PasskeyChallengeSigner;
|
|
34
|
+
/** Wallet transaction signer that returns base64(signed bytes). */
|
|
35
|
+
walletSigner: WalletSigner;
|
|
36
|
+
/** Passkey program address (base58). */
|
|
37
|
+
programAddress: string;
|
|
38
|
+
/** Sign-and-send executor (lifted from passkey-transaction.ts in the
|
|
39
|
+
wallet-auth-manager - wallet apps own this because it depends on
|
|
40
|
+
the `Thru` client's transaction builder). */
|
|
41
|
+
executor: TxExecutor;
|
|
42
|
+
/** Optional status callback so UIs can show progress. */
|
|
43
|
+
onStatus?: (message: string) => void;
|
|
44
|
+
}
|
|
45
|
+
interface TxExecutorParams {
|
|
46
|
+
thru: AnyThruClient;
|
|
47
|
+
walletSigner: WalletSigner;
|
|
48
|
+
instructionData: Uint8Array;
|
|
49
|
+
readWriteAddresses: string[];
|
|
50
|
+
readOnlyAddresses: string[];
|
|
51
|
+
label: string;
|
|
52
|
+
}
|
|
53
|
+
interface TxExecutorResult {
|
|
54
|
+
signature: string;
|
|
55
|
+
/** Loosely-typed because @thru/sdk types aren't available. */
|
|
56
|
+
execution: any;
|
|
57
|
+
}
|
|
58
|
+
type TxExecutor = (params: TxExecutorParams) => Promise<TxExecutorResult>;
|
|
59
|
+
interface AddDeviceResult extends TxExecutorResult {
|
|
60
|
+
/** The new passkey's authority index after the transaction lands. */
|
|
61
|
+
newAuthorityIdx: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Run VALIDATE + ADD_AUTHORITY [+ REGISTER_CREDENTIAL] to attach a new
|
|
65
|
+
* passkey to an on-chain WalletAccount.
|
|
66
|
+
*/
|
|
67
|
+
declare function addDeviceToAccount(params: AddDeviceParams): Promise<AddDeviceResult>;
|
|
68
|
+
|
|
69
|
+
export { type AddDeviceParams, type AddDeviceResult, type AnyThruClient, type PasskeyChallengeSigner, type TxExecutor, type TxExecutorParams, type TxExecutorResult, addDeviceToAccount };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/auth.cjs
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/auth/index.ts
|
|
31
31
|
var auth_exports = {};
|
|
32
32
|
__export(auth_exports, {
|
|
33
|
+
addDeviceToAccount: () => addDeviceToAccount,
|
|
33
34
|
createPasskeyAuthStore: () => createPasskeyAuthStore,
|
|
34
35
|
executePasskeyTransaction: () => executePasskeyTransaction,
|
|
35
36
|
getPasskeyAuthStore: () => getPasskeyAuthStore,
|
|
@@ -38,11 +39,11 @@ __export(auth_exports, {
|
|
|
38
39
|
module.exports = __toCommonJS(auth_exports);
|
|
39
40
|
|
|
40
41
|
// src/auth/execute-tx.ts
|
|
41
|
-
var import_passkey_manager2 = require("@thru/passkey-manager");
|
|
42
|
+
var import_passkey_manager2 = require("@thru/programs/passkey-manager");
|
|
42
43
|
|
|
43
44
|
// src/mobile/passkey.ts
|
|
44
45
|
var import_react_native_passkeys = require("react-native-passkeys");
|
|
45
|
-
var import_passkey_manager = require("@thru/passkey-manager");
|
|
46
|
+
var import_passkey_manager = require("@thru/programs/passkey-manager");
|
|
46
47
|
function getDefaultConfig(config) {
|
|
47
48
|
const env = globalThis.process?.env ?? {};
|
|
48
49
|
return {
|
|
@@ -301,8 +302,119 @@ async function executePasskeyTransaction(opts) {
|
|
|
301
302
|
return submitData;
|
|
302
303
|
}
|
|
303
304
|
|
|
305
|
+
// src/auth/add-device.ts
|
|
306
|
+
var import_passkey_manager3 = require("@thru/programs/passkey-manager");
|
|
307
|
+
var import_multicall = require("@thru/programs/multicall");
|
|
308
|
+
async function addDeviceToAccount(params) {
|
|
309
|
+
const status = params.onStatus ?? (() => {
|
|
310
|
+
});
|
|
311
|
+
const walletAccount = await params.thru.accounts.get(params.walletAddress);
|
|
312
|
+
const walletData = walletAccount?.data?.data;
|
|
313
|
+
if (!walletData) {
|
|
314
|
+
throw new Error("Wallet account data missing");
|
|
315
|
+
}
|
|
316
|
+
const parsed = (0, import_passkey_manager3.parseWalletAuthorities)(walletData);
|
|
317
|
+
const authorizing = parsed.authorities[params.authIdx];
|
|
318
|
+
if (!authorizing) {
|
|
319
|
+
throw new Error("Authorization index out of bounds");
|
|
320
|
+
}
|
|
321
|
+
if (authorizing.kind !== "passkey") {
|
|
322
|
+
throw new Error(
|
|
323
|
+
"addDeviceToAccount currently requires a passkey authority for VALIDATE"
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
const newAuthorityIdx = parsed.authorities.length;
|
|
327
|
+
let readWriteAccounts = [];
|
|
328
|
+
let lookupSeed;
|
|
329
|
+
let lookupAddressBytes;
|
|
330
|
+
let lookupProof;
|
|
331
|
+
if (params.credentialId) {
|
|
332
|
+
lookupSeed = await (0, import_passkey_manager3.createCredentialLookupSeed)(params.credentialId);
|
|
333
|
+
lookupAddressBytes = await (0, import_passkey_manager3.deriveWalletAddress)(
|
|
334
|
+
lookupSeed,
|
|
335
|
+
params.programAddress
|
|
336
|
+
);
|
|
337
|
+
status("Fetching state proof for credential lookup...");
|
|
338
|
+
const proofResult = await params.thru.proofs.generate({
|
|
339
|
+
proofType: 1,
|
|
340
|
+
address: lookupAddressBytes
|
|
341
|
+
});
|
|
342
|
+
lookupProof = proofResult.proof;
|
|
343
|
+
readWriteAccounts = [lookupAddressBytes];
|
|
344
|
+
}
|
|
345
|
+
const ctx = (0, import_passkey_manager3.buildAccountContext)({
|
|
346
|
+
walletAddress: params.walletAddress,
|
|
347
|
+
readWriteAccounts,
|
|
348
|
+
readOnlyAccounts: params.credentialId ? [import_multicall.MULTICALL_PROGRAM_PUBKEY] : [],
|
|
349
|
+
programAddress: params.programAddress
|
|
350
|
+
});
|
|
351
|
+
const passkeyProgramPubkey = (0, import_passkey_manager3.decodeAddress)(params.programAddress);
|
|
352
|
+
const addAuthorityInstruction = (0, import_passkey_manager3.encodeAddAuthorityInstruction)({
|
|
353
|
+
walletAccountIdx: ctx.walletAccountIdx,
|
|
354
|
+
authority: params.newAuthority
|
|
355
|
+
});
|
|
356
|
+
let targetProgramIdx = ctx.getAccountIndex(passkeyProgramPubkey);
|
|
357
|
+
let targetInstructionData = addAuthorityInstruction;
|
|
358
|
+
if (params.credentialId) {
|
|
359
|
+
if (!lookupSeed || !lookupAddressBytes || !lookupProof) {
|
|
360
|
+
throw new Error("Credential lookup proof data missing");
|
|
361
|
+
}
|
|
362
|
+
const registerCredentialInstruction = (0, import_passkey_manager3.encodeRegisterCredentialInstruction)({
|
|
363
|
+
walletAccountIdx: ctx.walletAccountIdx,
|
|
364
|
+
lookupAccountIdx: ctx.getAccountIndex(lookupAddressBytes),
|
|
365
|
+
seed: lookupSeed,
|
|
366
|
+
stateProof: lookupProof
|
|
367
|
+
});
|
|
368
|
+
targetProgramIdx = ctx.getAccountIndex(import_multicall.MULTICALL_PROGRAM_PUBKEY);
|
|
369
|
+
targetInstructionData = (0, import_multicall.buildMulticallInstruction)([
|
|
370
|
+
{
|
|
371
|
+
programIdx: ctx.getAccountIndex(passkeyProgramPubkey),
|
|
372
|
+
instructionData: addAuthorityInstruction
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
programIdx: ctx.getAccountIndex(passkeyProgramPubkey),
|
|
376
|
+
instructionData: registerCredentialInstruction
|
|
377
|
+
}
|
|
378
|
+
]);
|
|
379
|
+
}
|
|
380
|
+
const challenge = await (0, import_passkey_manager3.createValidateChallenge)(
|
|
381
|
+
parsed.nonce,
|
|
382
|
+
ctx.accountAddresses,
|
|
383
|
+
ctx.walletAccountIdx,
|
|
384
|
+
params.authIdx,
|
|
385
|
+
{
|
|
386
|
+
programIdx: targetProgramIdx,
|
|
387
|
+
instructionData: targetInstructionData
|
|
388
|
+
}
|
|
389
|
+
);
|
|
390
|
+
status("Waiting for passkey approval...");
|
|
391
|
+
const signature = await params.passkey.signChallenge(challenge);
|
|
392
|
+
const validateInstruction = (0, import_passkey_manager3.encodeValidateInstruction)({
|
|
393
|
+
walletAccountIdx: ctx.walletAccountIdx,
|
|
394
|
+
authIdx: params.authIdx,
|
|
395
|
+
targetInstruction: {
|
|
396
|
+
programIdx: targetProgramIdx,
|
|
397
|
+
instructionData: targetInstructionData
|
|
398
|
+
},
|
|
399
|
+
signatureR: signature.signatureR,
|
|
400
|
+
signatureS: signature.signatureS,
|
|
401
|
+
authenticatorData: signature.authenticatorData,
|
|
402
|
+
clientDataJSON: signature.clientDataJSON
|
|
403
|
+
});
|
|
404
|
+
status("Sending transaction...");
|
|
405
|
+
const result = await params.executor({
|
|
406
|
+
thru: params.thru,
|
|
407
|
+
walletSigner: params.walletSigner,
|
|
408
|
+
instructionData: validateInstruction,
|
|
409
|
+
readWriteAddresses: ctx.readWriteAddresses,
|
|
410
|
+
readOnlyAddresses: ctx.readOnlyAddresses,
|
|
411
|
+
label: params.credentialId ? "VALIDATE -> MULTICALL(ADD_AUTHORITY, REGISTER_CREDENTIAL)" : "VALIDATE -> ADD_AUTHORITY"
|
|
412
|
+
});
|
|
413
|
+
return { ...result, newAuthorityIdx };
|
|
414
|
+
}
|
|
415
|
+
|
|
304
416
|
// src/auth/use-passkey-auth.ts
|
|
305
|
-
var
|
|
417
|
+
var import_passkey_manager4 = require("@thru/programs/passkey-manager");
|
|
306
418
|
var import_zustand = require("zustand");
|
|
307
419
|
|
|
308
420
|
// src/mobile/errors.ts
|
|
@@ -429,18 +541,20 @@ function createPasskeyAuthStore(config) {
|
|
|
429
541
|
set({ isLoading: true, error: null, needsNewPasskey: false });
|
|
430
542
|
try {
|
|
431
543
|
const tempId = `user-${Date.now()}`;
|
|
432
|
-
const
|
|
544
|
+
const passkeyLabel = resolvedAlias.trim() || "Thru Wallet";
|
|
545
|
+
const { credentialId, publicKeyX, publicKeyY, rpId } = await registerPasskey(passkeyLabel, tempId, {
|
|
433
546
|
rpId: config.rpId,
|
|
434
547
|
rpName: config.rpName
|
|
435
548
|
});
|
|
436
549
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
437
|
-
const pubkeyXHex = (0,
|
|
438
|
-
const pubkeyYHex = (0,
|
|
550
|
+
const pubkeyXHex = (0, import_passkey_manager4.bytesToHex)(publicKeyX);
|
|
551
|
+
const pubkeyYHex = (0, import_passkey_manager4.bytesToHex)(publicKeyY);
|
|
439
552
|
await storePasskeyMetadata({
|
|
440
553
|
credentialId,
|
|
441
554
|
publicKeyX: pubkeyXHex,
|
|
442
555
|
publicKeyY: pubkeyYHex,
|
|
443
556
|
rpId,
|
|
557
|
+
label: passkeyLabel,
|
|
444
558
|
createdAt: now,
|
|
445
559
|
lastUsedAt: now
|
|
446
560
|
});
|
|
@@ -664,6 +778,7 @@ function usePasskeyAuth(config) {
|
|
|
664
778
|
}
|
|
665
779
|
// Annotate the CommonJS export names for ESM import in node:
|
|
666
780
|
0 && (module.exports = {
|
|
781
|
+
addDeviceToAccount,
|
|
667
782
|
createPasskeyAuthStore,
|
|
668
783
|
executePasskeyTransaction,
|
|
669
784
|
getPasskeyAuthStore,
|