@thru/passkey 0.2.13 → 0.2.14
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/README.md +73 -90
- package/dist/auth.cjs +672 -0
- package/dist/auth.cjs.map +1 -0
- package/dist/auth.d.cts +60 -0
- package/dist/auth.d.ts +60 -0
- package/dist/auth.js +422 -0
- package/dist/auth.js.map +1 -0
- package/dist/chunk-2JHC7OOH.js +250 -0
- package/dist/chunk-2JHC7OOH.js.map +1 -0
- package/dist/chunk-75G2FPYW.js +54 -0
- package/dist/chunk-75G2FPYW.js.map +1 -0
- package/dist/chunk-B5SN7AS7.js +586 -0
- package/dist/chunk-B5SN7AS7.js.map +1 -0
- package/dist/chunk-LNDWK3FA.js +163 -0
- package/dist/chunk-LNDWK3FA.js.map +1 -0
- package/dist/index.cjs +27 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -187
- package/dist/index.d.ts +4 -187
- package/dist/index.js +47 -810
- package/dist/index.js.map +1 -1
- package/dist/mobile.cjs +301 -0
- package/dist/mobile.cjs.map +1 -0
- package/dist/mobile.d.cts +49 -0
- package/dist/mobile.d.ts +49 -0
- package/dist/mobile.js +41 -0
- package/dist/mobile.js.map +1 -0
- package/dist/popup.cjs +247 -0
- package/dist/popup.cjs.map +1 -0
- package/dist/popup.d.cts +22 -0
- package/dist/popup.d.ts +22 -0
- package/dist/popup.js +31 -0
- package/dist/popup.js.map +1 -0
- package/dist/server.cjs +351 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +119 -0
- package/dist/server.d.ts +119 -0
- package/dist/server.js +340 -0
- package/dist/server.js.map +1 -0
- package/dist/types-_HRzmn-j.d.cts +125 -0
- package/dist/types-_HRzmn-j.d.ts +125 -0
- package/dist/web.cjs +758 -0
- package/dist/web.cjs.map +1 -0
- package/dist/web.d.cts +32 -0
- package/dist/web.d.ts +32 -0
- package/dist/web.js +60 -0
- package/dist/web.js.map +1 -0
- package/package.json +47 -2
- package/src/auth/execute-tx.ts +87 -0
- package/src/auth/index.ts +18 -0
- package/src/auth/types.ts +56 -0
- package/src/auth/use-passkey-auth.ts +428 -0
- package/src/index.ts +37 -39
- package/src/mobile/errors.ts +31 -0
- package/src/mobile/index.ts +33 -0
- package/src/mobile/passkey.ts +154 -0
- package/src/mobile/storage.ts +115 -0
- package/src/mobile/types.ts +24 -0
- package/src/popup-entry.ts +33 -0
- package/src/popup-service.ts +0 -103
- package/src/server/challenge.ts +26 -0
- package/src/server/create-wallet.ts +149 -0
- package/src/server/handlers.ts +93 -0
- package/src/server/index.ts +13 -0
- package/src/server/submit.ts +47 -0
- package/src/server/types.ts +70 -0
- package/src/server/utils.ts +69 -0
- package/src/types.ts +1 -0
- package/src/web.ts +51 -0
- package/tsconfig.json +6 -1
- package/tsup.config.ts +9 -1
package/dist/server.js
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
// src/server/create-wallet.ts
|
|
2
|
+
import {
|
|
3
|
+
PASSKEY_MANAGER_PROGRAM_ADDRESS,
|
|
4
|
+
base64UrlToBytes,
|
|
5
|
+
buildAccountContext,
|
|
6
|
+
createCredentialLookupSeed,
|
|
7
|
+
createWalletSeed,
|
|
8
|
+
deriveCredentialLookupAddress,
|
|
9
|
+
deriveWalletAddress,
|
|
10
|
+
encodeCreateInstruction,
|
|
11
|
+
encodeRegisterCredentialInstruction
|
|
12
|
+
} from "@thru/passkey-manager";
|
|
13
|
+
|
|
14
|
+
// ../helpers/src/constants.ts
|
|
15
|
+
var BASE64_URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
16
|
+
var tempMap = new Int16Array(256).fill(-1);
|
|
17
|
+
for (let i = 0; i < BASE64_URL_ALPHABET.length; i++) {
|
|
18
|
+
tempMap[BASE64_URL_ALPHABET.charCodeAt(i)] = i;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// ../helpers/src/address.ts
|
|
22
|
+
function encodeAddress(bytes) {
|
|
23
|
+
if (bytes.length !== 32) {
|
|
24
|
+
throw new Error("Expected 32-byte address");
|
|
25
|
+
}
|
|
26
|
+
let checksum = 0;
|
|
27
|
+
let accumulator = 0;
|
|
28
|
+
let bitsCollected = 0;
|
|
29
|
+
const output = ["t", "a"];
|
|
30
|
+
for (let i = 0; i < 30; i++) {
|
|
31
|
+
const byte = bytes[i];
|
|
32
|
+
checksum += byte;
|
|
33
|
+
accumulator = (accumulator << 8 | byte) >>> 0;
|
|
34
|
+
bitsCollected += 8;
|
|
35
|
+
while (bitsCollected >= 6) {
|
|
36
|
+
const index = accumulator >> bitsCollected - 6 & 63;
|
|
37
|
+
output.push(BASE64_URL_ALPHABET[index]);
|
|
38
|
+
bitsCollected -= 6;
|
|
39
|
+
accumulator &= maskForBits(bitsCollected);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const secondLast = bytes[30];
|
|
43
|
+
checksum += secondLast;
|
|
44
|
+
accumulator = (accumulator << 8 | secondLast) >>> 0;
|
|
45
|
+
bitsCollected += 8;
|
|
46
|
+
const last = bytes[31];
|
|
47
|
+
checksum += last;
|
|
48
|
+
accumulator = (accumulator << 8 | last) >>> 0;
|
|
49
|
+
bitsCollected += 8;
|
|
50
|
+
accumulator = (accumulator << 8 | checksum & 255) >>> 0;
|
|
51
|
+
bitsCollected += 8;
|
|
52
|
+
while (bitsCollected >= 6) {
|
|
53
|
+
const index = accumulator >> bitsCollected - 6 & 63;
|
|
54
|
+
output.push(BASE64_URL_ALPHABET[index]);
|
|
55
|
+
bitsCollected -= 6;
|
|
56
|
+
accumulator &= maskForBits(bitsCollected);
|
|
57
|
+
}
|
|
58
|
+
return output.join("");
|
|
59
|
+
}
|
|
60
|
+
function maskForBits(bits) {
|
|
61
|
+
return bits === 0 ? 0 : (1 << bits) - 1;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/server/utils.ts
|
|
65
|
+
async function getStateProof(client, address, proofType = 1, targetSlot) {
|
|
66
|
+
const proofRequest = {
|
|
67
|
+
address,
|
|
68
|
+
proofType
|
|
69
|
+
};
|
|
70
|
+
if (targetSlot !== void 0) {
|
|
71
|
+
proofRequest.targetSlot = targetSlot;
|
|
72
|
+
}
|
|
73
|
+
const proof = await client.proofs.generate(proofRequest);
|
|
74
|
+
if (!proof.proof || proof.proof.length === 0) {
|
|
75
|
+
throw new Error(`No state proof returned for ${address}`);
|
|
76
|
+
}
|
|
77
|
+
return proof.proof;
|
|
78
|
+
}
|
|
79
|
+
async function trackTransaction(client, signature, timeoutMs = 5e3) {
|
|
80
|
+
try {
|
|
81
|
+
for await (const update of client.transactions.track(signature, { timeoutMs })) {
|
|
82
|
+
if (update.executionResult) {
|
|
83
|
+
return {
|
|
84
|
+
signature,
|
|
85
|
+
status: update.executionResult.userErrorCode === 0n ? "finalized" : "failed",
|
|
86
|
+
errorCode: update.executionResult.userErrorCode
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (update.statusCode === 3) {
|
|
90
|
+
return {
|
|
91
|
+
signature,
|
|
92
|
+
status: "finalized"
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
} catch {
|
|
97
|
+
return {
|
|
98
|
+
signature,
|
|
99
|
+
status: "timeout"
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
signature,
|
|
104
|
+
status: "timeout"
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function toThruAddress(bytes) {
|
|
108
|
+
return encodeAddress(bytes);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/server/create-wallet.ts
|
|
112
|
+
async function createPasskeyWallet(opts) {
|
|
113
|
+
const walletName = opts.walletName ?? "default";
|
|
114
|
+
const seed = await createWalletSeed(walletName, opts.pubkeyX, opts.pubkeyY);
|
|
115
|
+
const walletBytes = await deriveWalletAddress(seed, PASSKEY_MANAGER_PROGRAM_ADDRESS);
|
|
116
|
+
const walletAddress = toThruAddress(walletBytes);
|
|
117
|
+
let walletExists = false;
|
|
118
|
+
try {
|
|
119
|
+
await opts.client.accounts.get(walletAddress);
|
|
120
|
+
walletExists = true;
|
|
121
|
+
} catch {
|
|
122
|
+
walletExists = false;
|
|
123
|
+
}
|
|
124
|
+
if (!walletExists) {
|
|
125
|
+
const stateProof = await getStateProof(opts.client, walletAddress);
|
|
126
|
+
const accountCtx = buildAccountContext({
|
|
127
|
+
walletAddress,
|
|
128
|
+
readWriteAccounts: [],
|
|
129
|
+
readOnlyAccounts: [],
|
|
130
|
+
feePayerAddress: opts.adminAddress,
|
|
131
|
+
programAddress: PASSKEY_MANAGER_PROGRAM_ADDRESS
|
|
132
|
+
});
|
|
133
|
+
const createIx = encodeCreateInstruction({
|
|
134
|
+
walletAccountIdx: accountCtx.walletAccountIdx,
|
|
135
|
+
authority: {
|
|
136
|
+
tag: 1,
|
|
137
|
+
pubkeyX: opts.pubkeyX,
|
|
138
|
+
pubkeyY: opts.pubkeyY
|
|
139
|
+
},
|
|
140
|
+
seed,
|
|
141
|
+
stateProof
|
|
142
|
+
});
|
|
143
|
+
const transaction = await opts.client.transactions.build({
|
|
144
|
+
feePayer: { publicKey: opts.adminPublicKey },
|
|
145
|
+
program: PASSKEY_MANAGER_PROGRAM_ADDRESS,
|
|
146
|
+
instructionData: createIx,
|
|
147
|
+
accounts: {
|
|
148
|
+
readWrite: [walletAddress],
|
|
149
|
+
readOnly: []
|
|
150
|
+
},
|
|
151
|
+
header: { fee: 0n }
|
|
152
|
+
});
|
|
153
|
+
await transaction.sign(opts.adminPrivateKey);
|
|
154
|
+
const signature = await opts.client.transactions.send(transaction.toWire());
|
|
155
|
+
const result = await trackTransaction(opts.client, signature, 6e4);
|
|
156
|
+
if (result.status !== "finalized") {
|
|
157
|
+
throw new Error(
|
|
158
|
+
`Wallet creation failed with error code: ${result.errorCode ?? "unknown"}`
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
let credentialLookupAddress;
|
|
163
|
+
if (opts.credentialId) {
|
|
164
|
+
const credentialIdBytes = base64UrlToBytes(opts.credentialId);
|
|
165
|
+
const lookupAddressBytes = await deriveCredentialLookupAddress(
|
|
166
|
+
credentialIdBytes,
|
|
167
|
+
walletName,
|
|
168
|
+
PASSKEY_MANAGER_PROGRAM_ADDRESS
|
|
169
|
+
);
|
|
170
|
+
credentialLookupAddress = toThruAddress(lookupAddressBytes);
|
|
171
|
+
let lookupExists = false;
|
|
172
|
+
try {
|
|
173
|
+
await opts.client.accounts.get(credentialLookupAddress);
|
|
174
|
+
lookupExists = true;
|
|
175
|
+
} catch {
|
|
176
|
+
lookupExists = false;
|
|
177
|
+
}
|
|
178
|
+
if (!lookupExists) {
|
|
179
|
+
try {
|
|
180
|
+
const credSeed = await createCredentialLookupSeed(credentialIdBytes, walletName);
|
|
181
|
+
const stateProof = await getStateProof(opts.client, credentialLookupAddress);
|
|
182
|
+
const accountCtx = buildAccountContext({
|
|
183
|
+
walletAddress,
|
|
184
|
+
readWriteAccounts: [lookupAddressBytes],
|
|
185
|
+
readOnlyAccounts: [],
|
|
186
|
+
feePayerAddress: opts.adminAddress,
|
|
187
|
+
programAddress: PASSKEY_MANAGER_PROGRAM_ADDRESS
|
|
188
|
+
});
|
|
189
|
+
const registerIx = encodeRegisterCredentialInstruction({
|
|
190
|
+
walletAccountIdx: accountCtx.walletAccountIdx,
|
|
191
|
+
lookupAccountIdx: accountCtx.getAccountIndex(lookupAddressBytes),
|
|
192
|
+
seed: credSeed,
|
|
193
|
+
stateProof
|
|
194
|
+
});
|
|
195
|
+
const transaction = await opts.client.transactions.build({
|
|
196
|
+
feePayer: { publicKey: opts.adminPublicKey },
|
|
197
|
+
program: PASSKEY_MANAGER_PROGRAM_ADDRESS,
|
|
198
|
+
instructionData: registerIx,
|
|
199
|
+
accounts: {
|
|
200
|
+
readWrite: [walletAddress, credentialLookupAddress],
|
|
201
|
+
readOnly: []
|
|
202
|
+
},
|
|
203
|
+
header: { fee: 0n }
|
|
204
|
+
});
|
|
205
|
+
await transaction.sign(opts.adminPrivateKey);
|
|
206
|
+
const signature = await opts.client.transactions.send(transaction.toWire());
|
|
207
|
+
const result = await trackTransaction(opts.client, signature, 6e4);
|
|
208
|
+
if (result.status !== "finalized") {
|
|
209
|
+
throw new Error(
|
|
210
|
+
`Credential registration failed with status: ${result.status}${result.errorCode !== void 0 ? ` (error code: ${result.errorCode})` : ""}`
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
} catch (error) {
|
|
214
|
+
console.warn("Credential registration failed (non-fatal):", error);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
walletAddress,
|
|
220
|
+
credentialLookupAddress
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// src/server/challenge.ts
|
|
225
|
+
import {
|
|
226
|
+
bytesToBase64Url,
|
|
227
|
+
createValidateChallenge,
|
|
228
|
+
fetchWalletNonce
|
|
229
|
+
} from "@thru/passkey-manager";
|
|
230
|
+
async function createPasskeyChallenge(opts) {
|
|
231
|
+
const nonce = await fetchWalletNonce(opts.client, opts.walletAddress);
|
|
232
|
+
const challenge = await createValidateChallenge(
|
|
233
|
+
nonce,
|
|
234
|
+
opts.accountCtx.accountAddresses,
|
|
235
|
+
opts.invokeIx
|
|
236
|
+
);
|
|
237
|
+
return {
|
|
238
|
+
challenge: bytesToBase64Url(challenge),
|
|
239
|
+
nonce: nonce.toString()
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// src/server/submit.ts
|
|
244
|
+
import {
|
|
245
|
+
PASSKEY_MANAGER_PROGRAM_ADDRESS as PASSKEY_MANAGER_PROGRAM_ADDRESS2,
|
|
246
|
+
concatenateInstructions,
|
|
247
|
+
encodeValidateInstruction,
|
|
248
|
+
hexToBytes as hexToBytes2
|
|
249
|
+
} from "@thru/passkey-manager";
|
|
250
|
+
async function submitPasskeyTransaction(opts) {
|
|
251
|
+
const validateIx = encodeValidateInstruction({
|
|
252
|
+
walletAccountIdx: opts.accountCtx.walletAccountIdx,
|
|
253
|
+
authIdx: 0,
|
|
254
|
+
signatureR: hexToBytes2(opts.signatureR),
|
|
255
|
+
signatureS: hexToBytes2(opts.signatureS),
|
|
256
|
+
authenticatorData: Buffer.from(opts.authenticatorData, "base64"),
|
|
257
|
+
clientDataJSON: Buffer.from(opts.clientDataJSON, "base64")
|
|
258
|
+
});
|
|
259
|
+
const instructionData = concatenateInstructions([validateIx, opts.invokeIx]);
|
|
260
|
+
const transaction = await opts.client.transactions.build({
|
|
261
|
+
feePayer: { publicKey: opts.adminPublicKey },
|
|
262
|
+
program: PASSKEY_MANAGER_PROGRAM_ADDRESS2,
|
|
263
|
+
instructionData,
|
|
264
|
+
accounts: {
|
|
265
|
+
readWrite: opts.accountCtx.readWriteAddresses,
|
|
266
|
+
readOnly: opts.accountCtx.readOnlyAddresses
|
|
267
|
+
},
|
|
268
|
+
header: { fee: 0n }
|
|
269
|
+
});
|
|
270
|
+
await transaction.sign(opts.adminPrivateKey);
|
|
271
|
+
const signature = await opts.client.transactions.send(transaction.toWire());
|
|
272
|
+
return trackTransaction(opts.client, signature);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// src/server/handlers.ts
|
|
276
|
+
function createPasskeyHandlers(opts) {
|
|
277
|
+
const pendingContexts = /* @__PURE__ */ new Map();
|
|
278
|
+
const challengeTtlMs = opts.challengeTtlMs ?? 5 * 6e4;
|
|
279
|
+
function createPendingContextKey(walletAddress, nonce, challenge) {
|
|
280
|
+
return `${walletAddress}:${nonce}:${challenge}`;
|
|
281
|
+
}
|
|
282
|
+
function prunePendingContexts(now = Date.now()) {
|
|
283
|
+
for (const [nonce, entry] of pendingContexts.entries()) {
|
|
284
|
+
if (now - entry.createdAt > challengeTtlMs) {
|
|
285
|
+
pendingContexts.delete(nonce);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return {
|
|
290
|
+
challenge: async (walletAddress, params) => {
|
|
291
|
+
prunePendingContexts();
|
|
292
|
+
const context = await opts.buildContext(params);
|
|
293
|
+
const challenge = await createPasskeyChallenge({
|
|
294
|
+
client: opts.client,
|
|
295
|
+
walletAddress,
|
|
296
|
+
accountCtx: context.accountCtx,
|
|
297
|
+
invokeIx: context.invokeIx
|
|
298
|
+
});
|
|
299
|
+
pendingContexts.set(
|
|
300
|
+
createPendingContextKey(walletAddress, challenge.nonce, challenge.challenge),
|
|
301
|
+
{
|
|
302
|
+
context,
|
|
303
|
+
createdAt: Date.now()
|
|
304
|
+
}
|
|
305
|
+
);
|
|
306
|
+
return challenge;
|
|
307
|
+
},
|
|
308
|
+
submit: async (walletAddress, params, payload) => {
|
|
309
|
+
void params;
|
|
310
|
+
prunePendingContexts();
|
|
311
|
+
const pendingKey = createPendingContextKey(
|
|
312
|
+
walletAddress,
|
|
313
|
+
payload.nonce,
|
|
314
|
+
payload.challenge
|
|
315
|
+
);
|
|
316
|
+
const pending = pendingContexts.get(pendingKey);
|
|
317
|
+
if (!pending) {
|
|
318
|
+
throw new Error("Missing or expired challenge nonce");
|
|
319
|
+
}
|
|
320
|
+
pendingContexts.delete(pendingKey);
|
|
321
|
+
const { nonce: _nonce, challenge: _challenge, ...signaturePayload } = payload;
|
|
322
|
+
return submitPasskeyTransaction({
|
|
323
|
+
client: opts.client,
|
|
324
|
+
adminPublicKey: opts.adminPublicKey,
|
|
325
|
+
adminPrivateKey: opts.adminPrivateKey,
|
|
326
|
+
walletAddress,
|
|
327
|
+
accountCtx: pending.context.accountCtx,
|
|
328
|
+
invokeIx: pending.context.invokeIx,
|
|
329
|
+
...signaturePayload
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
export {
|
|
335
|
+
createPasskeyChallenge,
|
|
336
|
+
createPasskeyHandlers,
|
|
337
|
+
createPasskeyWallet,
|
|
338
|
+
submitPasskeyTransaction
|
|
339
|
+
};
|
|
340
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server/create-wallet.ts","../../helpers/src/constants.ts","../../helpers/src/address.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/passkey-manager';\nimport { toThruAddress, getStateProof, trackTransaction } from './utils';\nimport type { ThruClient } from './types';\n\nexport async function createPasskeyWallet(opts: {\n client: ThruClient;\n adminPublicKey: Uint8Array;\n adminPrivateKey: string;\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(seed, PASSKEY_MANAGER_PROGRAM_ADDRESS);\n const walletAddress = toThruAddress(walletBytes);\n\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) {\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: [walletAddress],\n readOnly: [],\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 error code: ${result.errorCode ?? 'unknown'}`\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 walletName,\n PASSKEY_MANAGER_PROGRAM_ADDRESS\n );\n\n credentialLookupAddress = toThruAddress(lookupAddressBytes);\n\n let lookupExists = false;\n try {\n await opts.client.accounts.get(credentialLookupAddress);\n lookupExists = true;\n } catch {\n lookupExists = false;\n }\n\n if (!lookupExists) {\n try {\n const credSeed = await createCredentialLookupSeed(credentialIdBytes, walletName);\n const stateProof = await getStateProof(opts.client, credentialLookupAddress);\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: [walletAddress, credentialLookupAddress],\n readOnly: [],\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 `Credential registration failed with status: ${result.status}${\n result.errorCode !== undefined ? ` (error code: ${result.errorCode})` : ''\n }`\n );\n }\n } catch (error) {\n console.warn('Credential registration failed (non-fatal):', error);\n }\n }\n }\n\n return {\n walletAddress,\n credentialLookupAddress,\n };\n}\n","export const BASE64_URL_ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_\";\n\nconst tempMap = new Int16Array(256).fill(-1);\nfor (let i = 0; i < BASE64_URL_ALPHABET.length; i++) {\n tempMap[BASE64_URL_ALPHABET.charCodeAt(i)] = i;\n}\nexport const BASE64_URL_MAP = tempMap\n\n","import { BASE64_URL_ALPHABET, BASE64_URL_MAP } from \"./constants\";\n\nexport function encodeAddress(bytes: Uint8Array): string {\n if (bytes.length !== 32) {\n throw new Error('Expected 32-byte address');\n }\n\n let checksum = 0;\n let accumulator = 0;\n let bitsCollected = 0;\n const output: string[] = ['t', 'a'];\n\n for (let i = 0; i < 30; i++) {\n const byte = bytes[i];\n checksum += byte;\n accumulator = ((accumulator << 8) | byte) >>> 0;\n bitsCollected += 8;\n while (bitsCollected >= 6) {\n const index = (accumulator >> (bitsCollected - 6)) & 0x3f;\n output.push(BASE64_URL_ALPHABET[index]);\n bitsCollected -= 6;\n accumulator &= maskForBits(bitsCollected);\n }\n }\n\n const secondLast = bytes[30];\n checksum += secondLast;\n accumulator = ((accumulator << 8) | secondLast) >>> 0;\n bitsCollected += 8;\n\n const last = bytes[31];\n checksum += last;\n accumulator = ((accumulator << 8) | last) >>> 0;\n bitsCollected += 8;\n\n accumulator = ((accumulator << 8) | (checksum & 0xff)) >>> 0;\n bitsCollected += 8;\n\n while (bitsCollected >= 6) {\n const index = (accumulator >> (bitsCollected - 6)) & 0x3f;\n output.push(BASE64_URL_ALPHABET[index]);\n bitsCollected -= 6;\n accumulator &= maskForBits(bitsCollected);\n }\n\n return output.join('');\n}\n\nexport function decodeAddress(value: string): Uint8Array {\n if (value.length !== 46) {\n throw new Error('Invalid address length');\n }\n if (!value.startsWith('ta')) {\n throw new Error('Address must start with \"ta\"');\n }\n\n const output = new Uint8Array(32);\n let checksum = 0;\n let inIdx = 2;\n let remaining = 40;\n let outIdx = 0;\n\n while (remaining >= 4) {\n const a = BASE64_URL_MAP[value.charCodeAt(inIdx)];\n const b = BASE64_URL_MAP[value.charCodeAt(inIdx + 1)];\n const c = BASE64_URL_MAP[value.charCodeAt(inIdx + 2)];\n const d = BASE64_URL_MAP[value.charCodeAt(inIdx + 3)];\n if (a < 0 || b < 0 || c < 0 || d < 0) {\n throw new Error('Invalid address encoding');\n }\n const triple = (a << 18) | (b << 12) | (c << 6) | d;\n const byte1 = (triple >> 16) & 0xff;\n const byte2 = (triple >> 8) & 0xff;\n const byte3 = triple & 0xff;\n checksum += byte1;\n checksum += byte2;\n checksum += byte3;\n output[outIdx++] = byte1;\n output[outIdx++] = byte2;\n output[outIdx++] = byte3;\n inIdx += 4;\n remaining -= 4;\n }\n\n const a = BASE64_URL_MAP[value.charCodeAt(inIdx)];\n const b = BASE64_URL_MAP[value.charCodeAt(inIdx + 1)];\n const c = BASE64_URL_MAP[value.charCodeAt(inIdx + 2)];\n const d = BASE64_URL_MAP[value.charCodeAt(inIdx + 3)];\n if (a < 0 || b < 0 || c < 0 || d < 0) {\n throw new Error('Invalid address encoding');\n }\n const triple = (a << 18) | (b << 12) | (c << 6) | d;\n const byte1 = (triple >> 16) & 0xff;\n const byte2 = (triple >> 8) & 0xff;\n const incomingChecksum = triple & 0xff;\n\n checksum += byte1;\n checksum += byte2;\n output[outIdx++] = byte1;\n output[outIdx++] = byte2;\n\n checksum &= 0xff;\n if (checksum !== incomingChecksum) {\n throw new Error('Address checksum mismatch');\n }\n\n return output;\n}\n\nfunction maskForBits(bits: number): number {\n return bits === 0 ? 0 : (1 << bits) - 1;\n}\n","import { encodeAddress } from '@thru/helpers';\nimport type { ThruClient, TransactionResult } from './types';\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 try {\n for await (const update of client.transactions.track(signature, { timeoutMs })) {\n if (update.executionResult) {\n return {\n signature,\n status: update.executionResult.userErrorCode === 0n ? 'finalized' : 'failed',\n errorCode: update.executionResult.userErrorCode,\n };\n }\n\n if (update.statusCode === 3) {\n return {\n signature,\n status: 'finalized',\n };\n }\n }\n } catch {\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","import {\n bytesToBase64Url,\n createValidateChallenge,\n fetchWalletNonce,\n} from '@thru/passkey-manager';\nimport type { AccountContext } from '@thru/passkey-manager';\nimport type { PasskeyChallengeResult, ThruClient } from './types';\n\nexport async function createPasskeyChallenge(opts: {\n client: ThruClient;\n walletAddress: string;\n accountCtx: AccountContext;\n invokeIx: Uint8Array;\n}): Promise<PasskeyChallengeResult> {\n const nonce = await fetchWalletNonce(opts.client, opts.walletAddress);\n const challenge = await createValidateChallenge(\n nonce,\n opts.accountCtx.accountAddresses,\n opts.invokeIx\n );\n\n return {\n challenge: bytesToBase64Url(challenge),\n nonce: nonce.toString(),\n };\n}\n","import {\n PASSKEY_MANAGER_PROGRAM_ADDRESS,\n concatenateInstructions,\n encodeValidateInstruction,\n hexToBytes,\n} from '@thru/passkey-manager';\nimport type { AccountContext } from '@thru/passkey-manager';\nimport { trackTransaction } from './utils';\nimport type {\n PasskeySignaturePayload,\n ThruClient,\n TransactionResult,\n} from './types';\n\nexport async function submitPasskeyTransaction(opts: {\n client: ThruClient;\n adminPublicKey: Uint8Array;\n adminPrivateKey: string;\n walletAddress: string;\n accountCtx: AccountContext;\n invokeIx: Uint8Array;\n} & PasskeySignaturePayload): Promise<TransactionResult> {\n const validateIx = encodeValidateInstruction({\n walletAccountIdx: opts.accountCtx.walletAccountIdx,\n authIdx: 0,\n signatureR: hexToBytes(opts.signatureR),\n signatureS: hexToBytes(opts.signatureS),\n authenticatorData: Buffer.from(opts.authenticatorData, 'base64'),\n clientDataJSON: Buffer.from(opts.clientDataJSON, 'base64'),\n });\n\n const instructionData = concatenateInstructions([validateIx, opts.invokeIx]);\n const transaction = await opts.client.transactions.build({\n feePayer: { publicKey: opts.adminPublicKey },\n program: PASSKEY_MANAGER_PROGRAM_ADDRESS,\n instructionData,\n accounts: {\n readWrite: opts.accountCtx.readWriteAddresses,\n readOnly: opts.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 return trackTransaction(opts.client, signature);\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: string;\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 invokeIx: context.invokeIx,\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 invokeIx: pending.context.invokeIx,\n ...signaturePayload,\n });\n },\n };\n}\n"],"mappings":"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","names":["PASSKEY_MANAGER_PROGRAM_ADDRESS","hexToBytes","hexToBytes","PASSKEY_MANAGER_PROGRAM_ADDRESS"]}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { PasskeySigningResult, PasskeyMetadata } from '@thru/passkey-manager';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Signing result with stored passkey metadata attached.
|
|
5
|
+
*/
|
|
6
|
+
interface PasskeyStoredSigningResult extends PasskeySigningResult {
|
|
7
|
+
passkey: PasskeyMetadata;
|
|
8
|
+
accounts?: PasskeyPopupAccount[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* WebAuthn client capabilities map.
|
|
12
|
+
*/
|
|
13
|
+
interface PasskeyClientCapabilities {
|
|
14
|
+
conditionalCreate?: boolean;
|
|
15
|
+
conditionalGet?: boolean;
|
|
16
|
+
credentialProtectionPolicy?: boolean;
|
|
17
|
+
credProps?: boolean;
|
|
18
|
+
minPinLength?: boolean;
|
|
19
|
+
multiFactor?: boolean;
|
|
20
|
+
passkeyPlatformAuthenticator?: boolean;
|
|
21
|
+
largeBlob?: boolean;
|
|
22
|
+
rpId?: boolean;
|
|
23
|
+
userVerifyingPlatformAuthenticator?: boolean;
|
|
24
|
+
relatedOrigins?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Context sent to popup for display purposes.
|
|
28
|
+
*/
|
|
29
|
+
interface PasskeyPopupContext {
|
|
30
|
+
appId?: string;
|
|
31
|
+
appName?: string;
|
|
32
|
+
appUrl?: string;
|
|
33
|
+
origin?: string;
|
|
34
|
+
imageUrl?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Account info passed through popup bridge.
|
|
38
|
+
*/
|
|
39
|
+
interface PasskeyPopupAccount {
|
|
40
|
+
index: number;
|
|
41
|
+
label?: string;
|
|
42
|
+
publicKey: string;
|
|
43
|
+
path?: string;
|
|
44
|
+
createdAt?: string;
|
|
45
|
+
addressType?: string;
|
|
46
|
+
publicKeyRawBase64?: string;
|
|
47
|
+
}
|
|
48
|
+
type PasskeyPopupAction = 'get' | 'create' | 'getStored';
|
|
49
|
+
interface PasskeyPopupGetRequestPayload {
|
|
50
|
+
credentialId: string;
|
|
51
|
+
challengeBase64Url: string;
|
|
52
|
+
rpId: string;
|
|
53
|
+
}
|
|
54
|
+
interface PasskeyPopupCreateRequestPayload {
|
|
55
|
+
alias: string;
|
|
56
|
+
userId: string;
|
|
57
|
+
rpId: string;
|
|
58
|
+
}
|
|
59
|
+
interface PasskeyPopupGetStoredRequestPayload {
|
|
60
|
+
challengeBase64Url: string;
|
|
61
|
+
context?: PasskeyPopupContext;
|
|
62
|
+
}
|
|
63
|
+
type PasskeyPopupRequestPayload = PasskeyPopupGetRequestPayload | PasskeyPopupCreateRequestPayload | PasskeyPopupGetStoredRequestPayload;
|
|
64
|
+
interface PasskeyPopupRequest {
|
|
65
|
+
type: string;
|
|
66
|
+
requestId: string;
|
|
67
|
+
action: PasskeyPopupAction;
|
|
68
|
+
payload: PasskeyPopupRequestPayload;
|
|
69
|
+
}
|
|
70
|
+
interface PasskeyPopupSigningResult {
|
|
71
|
+
signatureBase64Url: string;
|
|
72
|
+
authenticatorDataBase64Url: string;
|
|
73
|
+
clientDataJSONBase64Url: string;
|
|
74
|
+
signatureRBase64Url: string;
|
|
75
|
+
signatureSBase64Url: string;
|
|
76
|
+
}
|
|
77
|
+
interface PasskeyPopupStoredPasskey {
|
|
78
|
+
credentialId: string;
|
|
79
|
+
publicKeyX: string;
|
|
80
|
+
publicKeyY: string;
|
|
81
|
+
rpId: string;
|
|
82
|
+
label?: string;
|
|
83
|
+
createdAt: string;
|
|
84
|
+
lastUsedAt: string;
|
|
85
|
+
}
|
|
86
|
+
interface PasskeyPopupStoredSigningResult extends PasskeyPopupSigningResult {
|
|
87
|
+
passkey: PasskeyPopupStoredPasskey;
|
|
88
|
+
accounts?: PasskeyPopupAccount[];
|
|
89
|
+
}
|
|
90
|
+
interface PasskeyPopupRegistrationResult {
|
|
91
|
+
credentialId: string;
|
|
92
|
+
publicKeyX: string;
|
|
93
|
+
publicKeyY: string;
|
|
94
|
+
rpId: string;
|
|
95
|
+
}
|
|
96
|
+
type PasskeyPopupResponse = {
|
|
97
|
+
type: string;
|
|
98
|
+
requestId: string;
|
|
99
|
+
action: 'get';
|
|
100
|
+
success: true;
|
|
101
|
+
result: PasskeyPopupSigningResult;
|
|
102
|
+
} | {
|
|
103
|
+
type: string;
|
|
104
|
+
requestId: string;
|
|
105
|
+
action: 'create';
|
|
106
|
+
success: true;
|
|
107
|
+
result: PasskeyPopupRegistrationResult;
|
|
108
|
+
} | {
|
|
109
|
+
type: string;
|
|
110
|
+
requestId: string;
|
|
111
|
+
action: 'getStored';
|
|
112
|
+
success: true;
|
|
113
|
+
result: PasskeyPopupStoredSigningResult;
|
|
114
|
+
} | {
|
|
115
|
+
type: string;
|
|
116
|
+
requestId: string;
|
|
117
|
+
action: PasskeyPopupAction;
|
|
118
|
+
success: false;
|
|
119
|
+
error: {
|
|
120
|
+
name?: string;
|
|
121
|
+
message: string;
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export type { PasskeyStoredSigningResult as P, PasskeyClientCapabilities as a, PasskeyPopupContext as b, PasskeyPopupAccount as c, PasskeyPopupAction as d, PasskeyPopupGetRequestPayload as e, PasskeyPopupCreateRequestPayload as f, PasskeyPopupGetStoredRequestPayload as g, PasskeyPopupRequestPayload as h, PasskeyPopupRequest as i, PasskeyPopupSigningResult as j, PasskeyPopupStoredPasskey as k, PasskeyPopupStoredSigningResult as l, PasskeyPopupRegistrationResult as m, PasskeyPopupResponse as n };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { PasskeySigningResult, PasskeyMetadata } from '@thru/passkey-manager';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Signing result with stored passkey metadata attached.
|
|
5
|
+
*/
|
|
6
|
+
interface PasskeyStoredSigningResult extends PasskeySigningResult {
|
|
7
|
+
passkey: PasskeyMetadata;
|
|
8
|
+
accounts?: PasskeyPopupAccount[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* WebAuthn client capabilities map.
|
|
12
|
+
*/
|
|
13
|
+
interface PasskeyClientCapabilities {
|
|
14
|
+
conditionalCreate?: boolean;
|
|
15
|
+
conditionalGet?: boolean;
|
|
16
|
+
credentialProtectionPolicy?: boolean;
|
|
17
|
+
credProps?: boolean;
|
|
18
|
+
minPinLength?: boolean;
|
|
19
|
+
multiFactor?: boolean;
|
|
20
|
+
passkeyPlatformAuthenticator?: boolean;
|
|
21
|
+
largeBlob?: boolean;
|
|
22
|
+
rpId?: boolean;
|
|
23
|
+
userVerifyingPlatformAuthenticator?: boolean;
|
|
24
|
+
relatedOrigins?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Context sent to popup for display purposes.
|
|
28
|
+
*/
|
|
29
|
+
interface PasskeyPopupContext {
|
|
30
|
+
appId?: string;
|
|
31
|
+
appName?: string;
|
|
32
|
+
appUrl?: string;
|
|
33
|
+
origin?: string;
|
|
34
|
+
imageUrl?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Account info passed through popup bridge.
|
|
38
|
+
*/
|
|
39
|
+
interface PasskeyPopupAccount {
|
|
40
|
+
index: number;
|
|
41
|
+
label?: string;
|
|
42
|
+
publicKey: string;
|
|
43
|
+
path?: string;
|
|
44
|
+
createdAt?: string;
|
|
45
|
+
addressType?: string;
|
|
46
|
+
publicKeyRawBase64?: string;
|
|
47
|
+
}
|
|
48
|
+
type PasskeyPopupAction = 'get' | 'create' | 'getStored';
|
|
49
|
+
interface PasskeyPopupGetRequestPayload {
|
|
50
|
+
credentialId: string;
|
|
51
|
+
challengeBase64Url: string;
|
|
52
|
+
rpId: string;
|
|
53
|
+
}
|
|
54
|
+
interface PasskeyPopupCreateRequestPayload {
|
|
55
|
+
alias: string;
|
|
56
|
+
userId: string;
|
|
57
|
+
rpId: string;
|
|
58
|
+
}
|
|
59
|
+
interface PasskeyPopupGetStoredRequestPayload {
|
|
60
|
+
challengeBase64Url: string;
|
|
61
|
+
context?: PasskeyPopupContext;
|
|
62
|
+
}
|
|
63
|
+
type PasskeyPopupRequestPayload = PasskeyPopupGetRequestPayload | PasskeyPopupCreateRequestPayload | PasskeyPopupGetStoredRequestPayload;
|
|
64
|
+
interface PasskeyPopupRequest {
|
|
65
|
+
type: string;
|
|
66
|
+
requestId: string;
|
|
67
|
+
action: PasskeyPopupAction;
|
|
68
|
+
payload: PasskeyPopupRequestPayload;
|
|
69
|
+
}
|
|
70
|
+
interface PasskeyPopupSigningResult {
|
|
71
|
+
signatureBase64Url: string;
|
|
72
|
+
authenticatorDataBase64Url: string;
|
|
73
|
+
clientDataJSONBase64Url: string;
|
|
74
|
+
signatureRBase64Url: string;
|
|
75
|
+
signatureSBase64Url: string;
|
|
76
|
+
}
|
|
77
|
+
interface PasskeyPopupStoredPasskey {
|
|
78
|
+
credentialId: string;
|
|
79
|
+
publicKeyX: string;
|
|
80
|
+
publicKeyY: string;
|
|
81
|
+
rpId: string;
|
|
82
|
+
label?: string;
|
|
83
|
+
createdAt: string;
|
|
84
|
+
lastUsedAt: string;
|
|
85
|
+
}
|
|
86
|
+
interface PasskeyPopupStoredSigningResult extends PasskeyPopupSigningResult {
|
|
87
|
+
passkey: PasskeyPopupStoredPasskey;
|
|
88
|
+
accounts?: PasskeyPopupAccount[];
|
|
89
|
+
}
|
|
90
|
+
interface PasskeyPopupRegistrationResult {
|
|
91
|
+
credentialId: string;
|
|
92
|
+
publicKeyX: string;
|
|
93
|
+
publicKeyY: string;
|
|
94
|
+
rpId: string;
|
|
95
|
+
}
|
|
96
|
+
type PasskeyPopupResponse = {
|
|
97
|
+
type: string;
|
|
98
|
+
requestId: string;
|
|
99
|
+
action: 'get';
|
|
100
|
+
success: true;
|
|
101
|
+
result: PasskeyPopupSigningResult;
|
|
102
|
+
} | {
|
|
103
|
+
type: string;
|
|
104
|
+
requestId: string;
|
|
105
|
+
action: 'create';
|
|
106
|
+
success: true;
|
|
107
|
+
result: PasskeyPopupRegistrationResult;
|
|
108
|
+
} | {
|
|
109
|
+
type: string;
|
|
110
|
+
requestId: string;
|
|
111
|
+
action: 'getStored';
|
|
112
|
+
success: true;
|
|
113
|
+
result: PasskeyPopupStoredSigningResult;
|
|
114
|
+
} | {
|
|
115
|
+
type: string;
|
|
116
|
+
requestId: string;
|
|
117
|
+
action: PasskeyPopupAction;
|
|
118
|
+
success: false;
|
|
119
|
+
error: {
|
|
120
|
+
name?: string;
|
|
121
|
+
message: string;
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export type { PasskeyStoredSigningResult as P, PasskeyClientCapabilities as a, PasskeyPopupContext as b, PasskeyPopupAccount as c, PasskeyPopupAction as d, PasskeyPopupGetRequestPayload as e, PasskeyPopupCreateRequestPayload as f, PasskeyPopupGetStoredRequestPayload as g, PasskeyPopupRequestPayload as h, PasskeyPopupRequest as i, PasskeyPopupSigningResult as j, PasskeyPopupStoredPasskey as k, PasskeyPopupStoredSigningResult as l, PasskeyPopupRegistrationResult as m, PasskeyPopupResponse as n };
|