passkey-kit 0.7.1 → 0.7.3
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/cheatsheet +1 -1
- package/package.json +3 -3
- package/src/index.ts +2 -2
- package/src/kit.ts +251 -115
- package/src/server.ts +5 -5
- package/types/index.d.ts +2 -2
- package/types/kit.d.ts +12 -6
package/cheatsheet
CHANGED
|
@@ -13,7 +13,7 @@ stellar contract deploy --wasm target/wasm32-unknown-unknown/release/sample_poli
|
|
|
13
13
|
|
|
14
14
|
export JWT=???
|
|
15
15
|
mercury-cli --jwt $JWT --local false --mainnet false deploy
|
|
16
|
-
mercury-cli --jwt $JWT --local false --mainnet false catchup --project-name "smart-wallets-data-multi-signer-multi-sig" --contracts "
|
|
16
|
+
mercury-cli --jwt $JWT --local false --mainnet false catchup --project-name "smart-wallets-data-multi-signer-multi-sig" --contracts "CBMMJ55OQSFSYASVENVHW55QNA4Q52GE42P23E4V7O37GKMETKOFFENA"
|
|
17
17
|
curl -X GET https://api.mercurydata.app/catchups/4
|
|
18
18
|
curl -X POST https://api.mercurydata.app/zephyr/execute -H "Authorization: Bearer $MERCURY_JWT" -H 'Content-Type: application/json' -d '{"mode":{"Function": {"fname": "get_signers_by_address", "arguments": "{\"address\": \"CA4G3X75IGGNXNLXFIVFNYIGC6YAVLA7KSIFFDBSR7RQ7KEZMZWLXQBH\"}"}}}'
|
|
19
19
|
curl -X POST https://api.mercurydata.app/zephyr/execute -H "Authorization: Bearer $MERCURY_JWT" -H 'Content-Type: application/json' -d '{"mode":{"Function": {"fname": "get_address_by_signer", "arguments": "{\"id\": [78,127,30,69,248,174,95,168,47,59,161,168,51,120,117,135,112,133,232,92]}"}}}'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "passkey-kit",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "A helper library for creating and using passkey accounts on the Stellar blockchain.",
|
|
5
5
|
"author": "Tyler van der Hoeven",
|
|
6
6
|
"license": "MIT",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"base64url": "^3.0.1",
|
|
15
15
|
"buffer": "^6.0.3",
|
|
16
16
|
"passkey-factory-sdk": "0.3.1",
|
|
17
|
-
"
|
|
18
|
-
"
|
|
17
|
+
"sac-sdk": "0.1.0",
|
|
18
|
+
"passkey-kit-sdk": "0.3.1"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@simplewebauthn/types": "^10.0.0",
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PasskeyServer } from "./server"
|
|
2
|
-
import { PasskeyKit
|
|
2
|
+
import { PasskeyKit } from "./kit"
|
|
3
3
|
import { SACClient } from "./sac"
|
|
4
4
|
|
|
5
|
-
export { PasskeyServer, PasskeyKit, SACClient
|
|
5
|
+
export { PasskeyServer, PasskeyKit, SACClient }
|
package/src/kit.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { Client as PasskeyClient, type
|
|
1
|
+
import { Client as PasskeyClient, type Signature, type SignerKey } from 'passkey-kit-sdk'
|
|
2
2
|
import { Client as FactoryClient } from 'passkey-factory-sdk'
|
|
3
|
-
import { Address, StrKey, hash, xdr, Transaction, SorobanRpc,
|
|
3
|
+
import { Address, StrKey, hash, xdr, Transaction, SorobanRpc, TransactionBuilder, Keypair } from '@stellar/stellar-sdk'
|
|
4
4
|
import base64url from 'base64url'
|
|
5
5
|
import { startRegistration, startAuthentication } from "@simplewebauthn/browser"
|
|
6
6
|
import type { AuthenticatorAttestationResponseJSON, AuthenticatorSelectionCriteria } from "@simplewebauthn/types"
|
|
7
7
|
import { Buffer } from 'buffer'
|
|
8
8
|
import { PasskeyBase } from './base'
|
|
9
|
-
|
|
10
|
-
export const DEFAULT_LTL = 12
|
|
9
|
+
import { DEFAULT_TIMEOUT } from '@stellar/stellar-sdk/contract'
|
|
11
10
|
|
|
12
11
|
export class PasskeyKit extends PasskeyBase {
|
|
13
12
|
declare public rpc: SorobanRpc.Server
|
|
@@ -51,17 +50,17 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
51
50
|
signer: {
|
|
52
51
|
tag: 'Secp256r1',
|
|
53
52
|
values: [
|
|
54
|
-
keyId,
|
|
55
|
-
publicKey,
|
|
53
|
+
keyId,
|
|
54
|
+
publicKey,
|
|
56
55
|
[new Map()],
|
|
57
|
-
{tag: 'Persistent', values: undefined},
|
|
56
|
+
{ tag: 'Persistent', values: undefined },
|
|
58
57
|
]
|
|
59
58
|
},
|
|
60
59
|
})
|
|
61
60
|
|
|
62
61
|
if (result.isErr())
|
|
63
62
|
throw new Error(result.unwrapErr().message)
|
|
64
|
-
|
|
63
|
+
|
|
65
64
|
if (!built)
|
|
66
65
|
throw new Error('Failed to create wallet')
|
|
67
66
|
|
|
@@ -99,11 +98,6 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
99
98
|
displayName
|
|
100
99
|
},
|
|
101
100
|
authenticatorSelection,
|
|
102
|
-
// authenticatorSelection: {
|
|
103
|
-
// requireResidentKey: false,
|
|
104
|
-
// residentKey: "preferred",
|
|
105
|
-
// userVerification: "discouraged",
|
|
106
|
-
// },
|
|
107
101
|
pubKeyCredParams: [{ alg: -7, type: "public-key" }],
|
|
108
102
|
// attestation: "none",
|
|
109
103
|
// timeout: 120_000,
|
|
@@ -188,98 +182,134 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
188
182
|
public async signAuthEntry(
|
|
189
183
|
entry: xdr.SorobanAuthorizationEntry,
|
|
190
184
|
options?: {
|
|
191
|
-
keyId?: 'any' | string | Uint8Array
|
|
192
185
|
rpId?: string,
|
|
193
|
-
|
|
186
|
+
keyId?: 'any' | string | Uint8Array
|
|
187
|
+
keypair?: Keypair,
|
|
188
|
+
validUntilLedgerSeq?: number
|
|
194
189
|
}
|
|
195
190
|
) {
|
|
196
|
-
let { keyId,
|
|
191
|
+
let { rpId, keyId, keypair, validUntilLedgerSeq } = options || {}
|
|
192
|
+
|
|
193
|
+
if (keyId && keypair)
|
|
194
|
+
throw new Error('Provide either `options.keyId` or `options.keypair` but not both')
|
|
197
195
|
|
|
198
|
-
const lastLedger = await this.rpc.getLatestLedger().then(({ sequence }) => sequence)
|
|
199
196
|
const credentials = entry.credentials().address();
|
|
197
|
+
|
|
198
|
+
if (!validUntilLedgerSeq) {
|
|
199
|
+
validUntilLedgerSeq = credentials.signatureExpirationLedger()
|
|
200
|
+
|
|
201
|
+
if (!validUntilLedgerSeq) {
|
|
202
|
+
const lastLedger = await this.rpc.getLatestLedger().then(({ sequence }) => sequence)
|
|
203
|
+
validUntilLedgerSeq = lastLedger + DEFAULT_TIMEOUT / 5;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
credentials.signatureExpirationLedger(validUntilLedgerSeq)
|
|
208
|
+
|
|
200
209
|
const preimage = xdr.HashIdPreimage.envelopeTypeSorobanAuthorization(
|
|
201
210
|
new xdr.HashIdPreimageSorobanAuthorization({
|
|
202
211
|
networkId: hash(Buffer.from(this.networkPassphrase)),
|
|
203
212
|
nonce: credentials.nonce(),
|
|
204
|
-
|
|
205
|
-
// Call it `validUntilLedgerSeq` like the JS SDK
|
|
206
|
-
signatureExpirationLedger: lastLedger + ledgersToLive,
|
|
213
|
+
signatureExpirationLedger: credentials.signatureExpirationLedger(),
|
|
207
214
|
invocation: entry.rootInvocation()
|
|
208
215
|
})
|
|
209
216
|
)
|
|
210
217
|
const payload = hash(preimage.toXDR())
|
|
211
218
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|| (!keyId && !this.keyId)
|
|
215
|
-
? {
|
|
216
|
-
challenge: base64url(payload),
|
|
217
|
-
rpId,
|
|
218
|
-
// userVerification: "discouraged",
|
|
219
|
-
// timeout: 120_000
|
|
220
|
-
}
|
|
221
|
-
: {
|
|
222
|
-
challenge: base64url(payload),
|
|
223
|
-
rpId,
|
|
224
|
-
allowCredentials: [
|
|
225
|
-
{
|
|
226
|
-
id: keyId instanceof Uint8Array
|
|
227
|
-
? base64url(Buffer.from(keyId))
|
|
228
|
-
: keyId || this.keyId!,
|
|
229
|
-
type: "public-key",
|
|
230
|
-
},
|
|
231
|
-
],
|
|
232
|
-
// userVerification: "discouraged",
|
|
233
|
-
// timeout: 120_000
|
|
234
|
-
}
|
|
235
|
-
);
|
|
219
|
+
let key: SignerKey
|
|
220
|
+
let val: Signature
|
|
236
221
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
222
|
+
// Sign with the keypair as an ed25519 signer
|
|
223
|
+
if (keypair) {
|
|
224
|
+
const signature = keypair.sign(payload);
|
|
240
225
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
//
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
226
|
+
key = {
|
|
227
|
+
tag: "Ed25519",
|
|
228
|
+
values: [keypair.rawPublicKey()]
|
|
229
|
+
}
|
|
230
|
+
val = {
|
|
231
|
+
tag: "Ed25519",
|
|
232
|
+
values: [signature],
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Default, use passkey
|
|
237
|
+
else {
|
|
238
|
+
const authenticationResponse = await this.WebAuthn.startAuthentication(
|
|
239
|
+
keyId === 'any'
|
|
240
|
+
|| (!keyId && !this.keyId)
|
|
241
|
+
? {
|
|
242
|
+
challenge: base64url(payload),
|
|
243
|
+
rpId,
|
|
244
|
+
// userVerification: "discouraged",
|
|
245
|
+
// timeout: 120_000
|
|
246
|
+
}
|
|
247
|
+
: {
|
|
248
|
+
challenge: base64url(payload),
|
|
249
|
+
rpId,
|
|
250
|
+
allowCredentials: [
|
|
251
|
+
{
|
|
252
|
+
id: keyId instanceof Uint8Array
|
|
253
|
+
? base64url(Buffer.from(keyId))
|
|
254
|
+
: keyId || this.keyId!,
|
|
255
|
+
type: "public-key",
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
// userVerification: "discouraged",
|
|
259
|
+
// timeout: 120_000
|
|
260
|
+
}
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
key = {
|
|
264
|
+
tag: "Secp256r1",
|
|
265
|
+
values: [base64url.toBuffer(authenticationResponse.id)]
|
|
266
|
+
}
|
|
267
|
+
val = {
|
|
268
|
+
tag: "Secp256r1",
|
|
269
|
+
values: [
|
|
270
|
+
{
|
|
271
|
+
authenticator_data: base64url.toBuffer(
|
|
272
|
+
authenticationResponse.response.authenticatorData,
|
|
273
|
+
),
|
|
274
|
+
client_data_json: base64url.toBuffer(
|
|
275
|
+
authenticationResponse.response.clientDataJSON,
|
|
276
|
+
),
|
|
277
|
+
signature: this.compactSignature(
|
|
278
|
+
base64url.toBuffer(authenticationResponse.response.signature)
|
|
279
|
+
),
|
|
280
|
+
},
|
|
281
|
+
],
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const scKeyType = xdr.ScSpecTypeDef.scSpecTypeUdt(
|
|
286
|
+
new xdr.ScSpecTypeUdt({ name: "SignerKey" }),
|
|
287
|
+
);
|
|
288
|
+
const scValType = xdr.ScSpecTypeDef.scSpecTypeUdt(
|
|
289
|
+
new xdr.ScSpecTypeUdt({ name: "Signature" }),
|
|
290
|
+
);
|
|
291
|
+
const scVal = this.wallet!.spec.nativeToScVal(val, scValType);
|
|
292
|
+
const scKey = this.wallet!.spec.nativeToScVal(key, scKeyType);
|
|
293
|
+
const scEntry = new xdr.ScMapEntry({
|
|
294
|
+
key: scKey,
|
|
295
|
+
val: scVal,
|
|
296
|
+
})
|
|
280
297
|
|
|
281
|
-
credentials.
|
|
282
|
-
|
|
298
|
+
switch (credentials.signature().switch().name) {
|
|
299
|
+
case 'scvVoid':
|
|
300
|
+
credentials.signature(xdr.ScVal.scvMap([scEntry]))
|
|
301
|
+
break;
|
|
302
|
+
case 'scvMap':
|
|
303
|
+
// Add the new signature to the existing map
|
|
304
|
+
credentials.signature().map()?.push(scEntry)
|
|
305
|
+
// Order the map by key
|
|
306
|
+
credentials.signature().map()?.sort((a, b) =>
|
|
307
|
+
a.key().toXDR().compare(b.key().toXDR())
|
|
308
|
+
)
|
|
309
|
+
break;
|
|
310
|
+
default:
|
|
311
|
+
throw new Error('Unsupported signature')
|
|
312
|
+
}
|
|
283
313
|
|
|
284
314
|
return entry
|
|
285
315
|
}
|
|
@@ -287,10 +317,14 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
287
317
|
public async signAuthEntries(
|
|
288
318
|
entries: xdr.SorobanAuthorizationEntry[],
|
|
289
319
|
options?: {
|
|
320
|
+
rpId?: string,
|
|
290
321
|
keyId?: 'any' | string | Uint8Array
|
|
291
|
-
|
|
322
|
+
keypair?: Keypair,
|
|
323
|
+
validUntilLedgerSeq?: number
|
|
292
324
|
}
|
|
293
325
|
) {
|
|
326
|
+
// TODO should there be more control over which auth entries are signed? Especially given we support multiple signers now?
|
|
327
|
+
// As-is .sign() will always sign every smart wallet auth entry. This may be okay but likely we should have more control over which auth entry the signer is signing
|
|
294
328
|
for (const auth of entries) {
|
|
295
329
|
if (
|
|
296
330
|
auth.credentials().switch().name === 'sorobanCredentialsAddress'
|
|
@@ -308,15 +342,133 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
308
342
|
public async sign(
|
|
309
343
|
txn: Transaction | string,
|
|
310
344
|
options?: {
|
|
345
|
+
rpId?: string,
|
|
311
346
|
keyId?: 'any' | string | Uint8Array
|
|
312
|
-
|
|
347
|
+
keypair?: Keypair,
|
|
348
|
+
validUntilLedgerSeq?: number
|
|
313
349
|
}
|
|
314
350
|
) {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
351
|
+
txn = this.getTxn(txn)
|
|
352
|
+
|
|
353
|
+
// Only need to sign auth for `invokeHostFunction` operations
|
|
354
|
+
if (txn.operations[0].type === 'invokeHostFunction') {
|
|
355
|
+
const entries = txn.operations[0].auth
|
|
356
|
+
|
|
357
|
+
if (entries)
|
|
358
|
+
await this.signAuthEntries(entries, options)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return txn.toXDR()
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
public async attachPolicy(
|
|
365
|
+
txn: Transaction | string,
|
|
366
|
+
index: number,
|
|
367
|
+
policy: string
|
|
368
|
+
) {
|
|
369
|
+
txn = this.getTxn(txn)
|
|
370
|
+
|
|
371
|
+
// Only need to sign auth for `invokeHostFunction` operations
|
|
372
|
+
if (txn.operations[0].type !== 'invokeHostFunction')
|
|
373
|
+
return txn.toXDR()
|
|
374
|
+
|
|
375
|
+
if (!this.wallet)
|
|
376
|
+
throw new Error('Wallet not connected')
|
|
377
|
+
|
|
378
|
+
let context_arg: xdr.ScVal
|
|
379
|
+
|
|
380
|
+
const auth = txn.operations[0].auth?.[index]
|
|
381
|
+
const context = auth?.rootInvocation().function()
|
|
382
|
+
|
|
383
|
+
if (!auth || !context)
|
|
384
|
+
throw new Error('No context found')
|
|
385
|
+
|
|
386
|
+
switch (context.switch().name) {
|
|
387
|
+
case 'sorobanAuthorizedFunctionTypeContractFn':
|
|
388
|
+
switch (context.contractFn().contractAddress().switch().name) {
|
|
389
|
+
case 'scAddressTypeContract':
|
|
390
|
+
context_arg = xdr.ScVal.scvVec([
|
|
391
|
+
xdr.ScVal.scvSymbol("Contract"),
|
|
392
|
+
xdr.ScVal.scvMap([
|
|
393
|
+
new xdr.ScMapEntry({
|
|
394
|
+
key: xdr.ScVal.scvSymbol("args"),
|
|
395
|
+
val: xdr.ScVal.scvVec(context.contractFn().args()),
|
|
396
|
+
}),
|
|
397
|
+
new xdr.ScMapEntry({
|
|
398
|
+
key: xdr.ScVal.scvSymbol("contract"),
|
|
399
|
+
val: Address.contract(context.contractFn().contractAddress().contractId()).toScVal(),
|
|
400
|
+
}),
|
|
401
|
+
new xdr.ScMapEntry({
|
|
402
|
+
key: xdr.ScVal.scvSymbol("fn_name"),
|
|
403
|
+
val: xdr.ScVal.scvSymbol(context.contractFn().functionName()),
|
|
404
|
+
}),
|
|
405
|
+
]),
|
|
406
|
+
])
|
|
407
|
+
break;
|
|
408
|
+
default:
|
|
409
|
+
throw new Error('Unsupported contractAddress')
|
|
410
|
+
}
|
|
411
|
+
break;
|
|
412
|
+
case 'sorobanAuthorizedFunctionTypeCreateContractHostFn':
|
|
413
|
+
switch (context.createContractHostFn().contractIdPreimage().switch().name) {
|
|
414
|
+
case 'contractIdPreimageFromAddress':
|
|
415
|
+
context_arg = xdr.ScVal.scvVec([
|
|
416
|
+
xdr.ScVal.scvSymbol("CreateContractHostFn"),
|
|
417
|
+
xdr.ScVal.scvMap([
|
|
418
|
+
new xdr.ScMapEntry({
|
|
419
|
+
key: xdr.ScVal.scvSymbol("executable"),
|
|
420
|
+
val: xdr.ScVal.scvVec([
|
|
421
|
+
xdr.ScVal.scvSymbol("Wasm"),
|
|
422
|
+
xdr.ScVal.scvBytes(context.createContractHostFn().executable().wasmHash())
|
|
423
|
+
]),
|
|
424
|
+
}),
|
|
425
|
+
new xdr.ScMapEntry({
|
|
426
|
+
key: xdr.ScVal.scvSymbol("salt"),
|
|
427
|
+
val: xdr.ScVal.scvBytes(context.createContractHostFn().contractIdPreimage().fromAddress().salt()),
|
|
428
|
+
}),
|
|
429
|
+
]),
|
|
430
|
+
])
|
|
431
|
+
break;
|
|
432
|
+
default:
|
|
433
|
+
throw new Error('Unsupported contractIdPreimage')
|
|
434
|
+
}
|
|
435
|
+
break;
|
|
436
|
+
default:
|
|
437
|
+
throw new Error('Unsupported context')
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const __check_auth_args = new xdr.InvokeContractArgs({
|
|
441
|
+
contractAddress: Address.fromString(this.wallet.options.contractId).toScAddress(),
|
|
442
|
+
functionName: "__check_auth",
|
|
443
|
+
args: [context_arg],
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
const __check_auth_invocation = new xdr.SorobanAuthorizedInvocation({
|
|
447
|
+
function:
|
|
448
|
+
xdr.SorobanAuthorizedFunction.sorobanAuthorizedFunctionTypeContractFn(
|
|
449
|
+
__check_auth_args,
|
|
450
|
+
),
|
|
451
|
+
subInvocations: [],
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
const __check_auth = new xdr.SorobanAuthorizationEntry({
|
|
455
|
+
credentials: xdr.SorobanCredentials.sorobanCredentialsAddress(
|
|
456
|
+
new xdr.SorobanAddressCredentials({
|
|
457
|
+
address: Address.fromString(policy).toScAddress(),
|
|
458
|
+
nonce: auth.credentials().address().nonce(),
|
|
459
|
+
signatureExpirationLedger: auth.credentials().address().signatureExpirationLedger(),
|
|
460
|
+
signature: xdr.ScVal.scvVec([]),
|
|
461
|
+
}),
|
|
462
|
+
),
|
|
463
|
+
rootInvocation: __check_auth_invocation,
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
txn.operations[0].auth?.push(__check_auth)
|
|
467
|
+
|
|
468
|
+
return txn.toXDR()
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
private getTxn(txn: Transaction | string): Transaction {
|
|
320
472
|
txn = TransactionBuilder.cloneFrom(new Transaction(
|
|
321
473
|
typeof txn === 'string'
|
|
322
474
|
? txn
|
|
@@ -335,28 +487,12 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
335
487
|
) throw new Error('Must include only one operation of type `invokeHostFunction` or `extendFootprintTtl` or `restoreFootprint`')
|
|
336
488
|
}
|
|
337
489
|
|
|
338
|
-
|
|
339
|
-
if (txn.operations[0].type === 'invokeHostFunction') {
|
|
340
|
-
const entries = (txn.operations[0] as Operation.InvokeHostFunction).auth
|
|
341
|
-
|
|
342
|
-
if (entries)
|
|
343
|
-
await this.signAuthEntries(entries, options)
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
const sim = await this.rpc.simulateTransaction(txn)
|
|
347
|
-
|
|
348
|
-
if (
|
|
349
|
-
SorobanRpc.Api.isSimulationError(sim)
|
|
350
|
-
|| SorobanRpc.Api.isSimulationRestore(sim) // TODO handle state archival
|
|
351
|
-
) throw sim
|
|
352
|
-
|
|
353
|
-
return SorobanRpc.assembleTransaction(txn, sim).build().toXDR()
|
|
490
|
+
return txn
|
|
354
491
|
}
|
|
355
492
|
|
|
356
|
-
/*
|
|
493
|
+
/* LATER
|
|
357
494
|
- Add a getKeyInfo action to get info about a specific passkey
|
|
358
495
|
Specifically looking for name, type, etc. data so a user could grok what signer mapped to what passkey
|
|
359
|
-
@Later
|
|
360
496
|
*/
|
|
361
497
|
|
|
362
498
|
private async getPublicKey(response: AuthenticatorAttestationResponseJSON) {
|
|
@@ -399,10 +535,10 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
399
535
|
])
|
|
400
536
|
}
|
|
401
537
|
|
|
402
|
-
/* TODO
|
|
538
|
+
/* TODO
|
|
403
539
|
- We're doing some pretty "smart" public key decoding stuff so we should verify the signature against this final public key before assuming it's safe to use and save on-chain
|
|
404
540
|
Hmm...Given that `startRegistration` doesn't produce a signature, verifying we've got the correct public key isn't really possible
|
|
405
|
-
|
|
541
|
+
- This probably needs to be an onchain check, even if just a simulation, just to ensure everything looks good before we get too far adding value etc.
|
|
406
542
|
*/
|
|
407
543
|
|
|
408
544
|
return publicKey
|
package/src/server.ts
CHANGED
|
@@ -119,20 +119,20 @@ export class PasskeyServer extends PasskeyBase {
|
|
|
119
119
|
return res || undefined as string | undefined
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
/*
|
|
122
|
+
/* LATER
|
|
123
123
|
- Add a method for getting a paginated or filtered list of all a wallet's events
|
|
124
|
-
@Later
|
|
125
124
|
*/
|
|
126
125
|
|
|
127
|
-
|
|
128
|
-
public async send(xdr: string, fee: number = 10_000) {
|
|
126
|
+
public async send(xdr: string, fee?: number) {
|
|
129
127
|
if (!this.launchtubeUrl || !this.launchtubeJwt)
|
|
130
128
|
throw new Error('Launchtube service not configured')
|
|
131
129
|
|
|
132
130
|
const data = new FormData();
|
|
133
131
|
|
|
134
132
|
data.set('xdr', xdr);
|
|
135
|
-
|
|
133
|
+
|
|
134
|
+
if (fee)
|
|
135
|
+
data.set('fee', fee.toString());
|
|
136
136
|
|
|
137
137
|
return fetch(this.launchtubeUrl, {
|
|
138
138
|
method: 'POST',
|
package/types/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { PasskeyServer } from "./server";
|
|
2
|
-
import { PasskeyKit
|
|
2
|
+
import { PasskeyKit } from "./kit";
|
|
3
3
|
import { SACClient } from "./sac";
|
|
4
|
-
export { PasskeyServer, PasskeyKit, SACClient
|
|
4
|
+
export { PasskeyServer, PasskeyKit, SACClient };
|
package/types/kit.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { Client as PasskeyClient } from 'passkey-kit-sdk';
|
|
2
2
|
import { Client as FactoryClient } from 'passkey-factory-sdk';
|
|
3
|
-
import { xdr, Transaction, SorobanRpc } from '@stellar/stellar-sdk';
|
|
3
|
+
import { xdr, Transaction, SorobanRpc, Keypair } from '@stellar/stellar-sdk';
|
|
4
4
|
import { startRegistration, startAuthentication } from "@simplewebauthn/browser";
|
|
5
5
|
import type { AuthenticatorSelectionCriteria } from "@simplewebauthn/types";
|
|
6
6
|
import { Buffer } from 'buffer';
|
|
7
7
|
import { PasskeyBase } from './base';
|
|
8
|
-
export declare const DEFAULT_LTL = 12;
|
|
9
8
|
export declare class PasskeyKit extends PasskeyBase {
|
|
10
9
|
rpc: SorobanRpc.Server;
|
|
11
10
|
rpcUrl: string;
|
|
@@ -47,18 +46,25 @@ export declare class PasskeyKit extends PasskeyBase {
|
|
|
47
46
|
contractId: string;
|
|
48
47
|
}>;
|
|
49
48
|
signAuthEntry(entry: xdr.SorobanAuthorizationEntry, options?: {
|
|
50
|
-
keyId?: 'any' | string | Uint8Array;
|
|
51
49
|
rpId?: string;
|
|
52
|
-
|
|
50
|
+
keyId?: 'any' | string | Uint8Array;
|
|
51
|
+
keypair?: Keypair;
|
|
52
|
+
validUntilLedgerSeq?: number;
|
|
53
53
|
}): Promise<xdr.SorobanAuthorizationEntry>;
|
|
54
54
|
signAuthEntries(entries: xdr.SorobanAuthorizationEntry[], options?: {
|
|
55
|
+
rpId?: string;
|
|
55
56
|
keyId?: 'any' | string | Uint8Array;
|
|
56
|
-
|
|
57
|
+
keypair?: Keypair;
|
|
58
|
+
validUntilLedgerSeq?: number;
|
|
57
59
|
}): Promise<xdr.SorobanAuthorizationEntry[]>;
|
|
58
60
|
sign(txn: Transaction | string, options?: {
|
|
61
|
+
rpId?: string;
|
|
59
62
|
keyId?: 'any' | string | Uint8Array;
|
|
60
|
-
|
|
63
|
+
keypair?: Keypair;
|
|
64
|
+
validUntilLedgerSeq?: number;
|
|
61
65
|
}): Promise<string>;
|
|
66
|
+
attachPolicy(txn: Transaction | string, index: number, policy: string): Promise<string>;
|
|
67
|
+
private getTxn;
|
|
62
68
|
private getPublicKey;
|
|
63
69
|
private compactSignature;
|
|
64
70
|
}
|