passkey-kit 0.4.3 → 0.4.5
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/package.json +1 -2
- package/src/base.ts +8 -8
- package/src/kit.ts +43 -17
- package/types/base.d.ts +3 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "passkey-kit",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
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",
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
"@stellar/stellar-sdk": "12.1.0",
|
|
13
13
|
"base64url": "^3.0.1",
|
|
14
14
|
"buffer": "^6.0.3",
|
|
15
|
-
"cbor-x": "^1.5.9",
|
|
16
15
|
"passkey-factory-sdk": "0.2.1",
|
|
17
16
|
"passkey-kit-sdk": "0.2.1"
|
|
18
17
|
},
|
package/src/base.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { SorobanRpc, xdr } from "@stellar/stellar-sdk"
|
|
|
2
2
|
import base64url from "base64url"
|
|
3
3
|
|
|
4
4
|
export class PasskeyBase {
|
|
5
|
-
public rpc: SorobanRpc.Server
|
|
6
|
-
public rpcUrl: string
|
|
5
|
+
public rpc: SorobanRpc.Server | undefined
|
|
6
|
+
public rpcUrl: string | undefined
|
|
7
7
|
public launchtubeUrl: string | undefined
|
|
8
8
|
public launchtubeJwt: string | undefined
|
|
9
9
|
public mercuryUrl: string | undefined
|
|
@@ -12,9 +12,7 @@ export class PasskeyBase {
|
|
|
12
12
|
public mercuryPassword: string | undefined
|
|
13
13
|
|
|
14
14
|
constructor(options: {
|
|
15
|
-
rpcUrl
|
|
16
|
-
networkPassphrase: string,
|
|
17
|
-
factoryContractId: string,
|
|
15
|
+
rpcUrl?: string,
|
|
18
16
|
launchtubeUrl?: string,
|
|
19
17
|
launchtubeJwt?: string,
|
|
20
18
|
mercuryUrl?: string,
|
|
@@ -53,8 +51,10 @@ export class PasskeyBase {
|
|
|
53
51
|
if (!mercuryJwt && mercuryUrl && mercuryEmail && mercuryPassword)
|
|
54
52
|
this.setMercuryJwt()
|
|
55
53
|
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
if (rpcUrl) {
|
|
55
|
+
this.rpcUrl = rpcUrl
|
|
56
|
+
this.rpc = new SorobanRpc.Server(rpcUrl)
|
|
57
|
+
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
public async setMercuryJwt() {
|
|
@@ -89,7 +89,7 @@ export class PasskeyBase {
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
public async getSigners(contractId: string) {
|
|
92
|
-
if (!this.mercuryUrl || !this.mercuryJwt)
|
|
92
|
+
if (!this.rpc || !this.mercuryUrl || !this.mercuryJwt)
|
|
93
93
|
throw new Error('Mercury service not configured')
|
|
94
94
|
|
|
95
95
|
const signers = await fetch(`${this.mercuryUrl}/zephyr/execute`, {
|
package/src/kit.ts
CHANGED
|
@@ -4,7 +4,6 @@ import { Address, StrKey, hash, xdr, Transaction, SorobanRpc, Operation, Transac
|
|
|
4
4
|
import base64url from 'base64url'
|
|
5
5
|
import { startRegistration, startAuthentication } from "@simplewebauthn/browser"
|
|
6
6
|
import type { AuthenticatorAttestationResponseJSON } from "@simplewebauthn/types"
|
|
7
|
-
import { decode } from 'cbor-x/decode'
|
|
8
7
|
import { Buffer } from 'buffer'
|
|
9
8
|
import { PasskeyBase } from './base'
|
|
10
9
|
|
|
@@ -29,6 +28,12 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
29
28
|
|
|
30
29
|
super(options)
|
|
31
30
|
|
|
31
|
+
if (!this.rpcUrl)
|
|
32
|
+
this.rpcUrl = rpcUrl
|
|
33
|
+
|
|
34
|
+
if (!this.rpc)
|
|
35
|
+
this.rpc = new SorobanRpc.Server(rpcUrl)
|
|
36
|
+
|
|
32
37
|
this.networkPassphrase = networkPassphrase
|
|
33
38
|
this.factory = new FactoryClient({
|
|
34
39
|
contractId: factoryContractId,
|
|
@@ -82,7 +87,7 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
82
87
|
},
|
|
83
88
|
pubKeyCredParams: [{ alg: -7, type: "public-key" }],
|
|
84
89
|
attestation: "none",
|
|
85
|
-
timeout: 120_000
|
|
90
|
+
timeout: 120_000,
|
|
86
91
|
});
|
|
87
92
|
|
|
88
93
|
if (!this.keyId)
|
|
@@ -90,7 +95,7 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
90
95
|
|
|
91
96
|
return {
|
|
92
97
|
keyId: base64url.toBuffer(id),
|
|
93
|
-
publicKey: this.getPublicKey(response)
|
|
98
|
+
publicKey: await this.getPublicKey(response)
|
|
94
99
|
}
|
|
95
100
|
}
|
|
96
101
|
|
|
@@ -109,7 +114,7 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
109
114
|
timeout: 120_000
|
|
110
115
|
});
|
|
111
116
|
|
|
112
|
-
console.log(response);
|
|
117
|
+
// console.log(response);
|
|
113
118
|
|
|
114
119
|
keyId = response.id
|
|
115
120
|
}
|
|
@@ -140,7 +145,7 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
140
145
|
// attempt passkey id derivation
|
|
141
146
|
try {
|
|
142
147
|
// TODO what is the error if the entry exists but is archived?
|
|
143
|
-
await this.rpc
|
|
148
|
+
await this.rpc!.getContractData(contractId, xdr.ScVal.scvLedgerKeyContractInstance())
|
|
144
149
|
}
|
|
145
150
|
// if that fails look up from the `getContractId` function
|
|
146
151
|
catch {
|
|
@@ -172,7 +177,7 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
172
177
|
// Default mirrors DEFAULT_TIMEOUT (currently 5 minutes) https://github.com/stellar/js-stellar-sdk/blob/master/src/contract/utils.ts#L7
|
|
173
178
|
let { keyId, ledgersToLive = 60 } = options || {}
|
|
174
179
|
|
|
175
|
-
const lastLedger = await this.rpc
|
|
180
|
+
const lastLedger = await this.rpc!.getLatestLedger().then(({ sequence }) => sequence)
|
|
176
181
|
const credentials = entry.credentials().address();
|
|
177
182
|
const preimage = xdr.HashIdPreimage.envelopeTypeSorobanAuthorization(
|
|
178
183
|
new xdr.HashIdPreimageSorobanAuthorization({
|
|
@@ -295,7 +300,7 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
295
300
|
await this.signAuthEntries(entries, options)
|
|
296
301
|
}
|
|
297
302
|
|
|
298
|
-
const sim = await this.rpc
|
|
303
|
+
const sim = await this.rpc!.simulateTransaction(txn)
|
|
299
304
|
|
|
300
305
|
if (
|
|
301
306
|
SorobanRpc.Api.isSimulationError(sim)
|
|
@@ -311,30 +316,51 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
311
316
|
@Later
|
|
312
317
|
*/
|
|
313
318
|
|
|
314
|
-
private getPublicKey(response: AuthenticatorAttestationResponseJSON) {
|
|
319
|
+
private async getPublicKey(response: AuthenticatorAttestationResponseJSON) {
|
|
315
320
|
let publicKey: Buffer | undefined
|
|
316
321
|
|
|
317
|
-
if (response.publicKey)
|
|
318
|
-
publicKey = base64url.toBuffer(response.publicKey)
|
|
322
|
+
if (response.publicKey) {
|
|
323
|
+
publicKey = base64url.toBuffer(response.publicKey)
|
|
324
|
+
publicKey = publicKey!.slice(publicKey!.length - 65)
|
|
325
|
+
}
|
|
319
326
|
|
|
320
327
|
if (
|
|
321
328
|
!publicKey
|
|
322
329
|
|| publicKey[0] !== 0x04
|
|
323
330
|
|| publicKey.length !== 65
|
|
324
331
|
) {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
332
|
+
let x: Buffer
|
|
333
|
+
let y: Buffer
|
|
334
|
+
|
|
335
|
+
if (response.authenticatorData) {
|
|
336
|
+
const authenticatorData = base64url.toBuffer(response.authenticatorData)
|
|
337
|
+
const credentialIdLength = (authenticatorData[53] << 8) | authenticatorData[54]
|
|
338
|
+
|
|
339
|
+
x = authenticatorData.slice(65 + credentialIdLength, 97 + credentialIdLength)
|
|
340
|
+
y = authenticatorData.slice(100 + credentialIdLength, 132 + credentialIdLength)
|
|
341
|
+
} else {
|
|
342
|
+
const attestationData = base64url.toBuffer(response.attestationObject)
|
|
343
|
+
|
|
344
|
+
let startIndex = attestationData.indexOf(0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20)
|
|
345
|
+
startIndex = startIndex + startIndex.length
|
|
346
|
+
|
|
347
|
+
x = attestationData.slice(startIndex, 32 + startIndex)
|
|
348
|
+
y = attestationData.slice(35 + startIndex, 67 + startIndex)
|
|
349
|
+
}
|
|
330
350
|
|
|
331
351
|
publicKey = Buffer.from([
|
|
332
352
|
0x04, // (0x04 prefix) https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm
|
|
333
|
-
...
|
|
334
|
-
...
|
|
353
|
+
...x,
|
|
354
|
+
...y
|
|
335
355
|
])
|
|
336
356
|
}
|
|
337
357
|
|
|
358
|
+
/* TODO
|
|
359
|
+
- 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
|
|
360
|
+
Given that `startRegistration` doesn't produce a signature, verifying we've got the correct public key isn't really possible
|
|
361
|
+
@Later
|
|
362
|
+
*/
|
|
363
|
+
|
|
338
364
|
return publicKey
|
|
339
365
|
}
|
|
340
366
|
|
package/types/base.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SorobanRpc } from "@stellar/stellar-sdk";
|
|
2
2
|
export declare class PasskeyBase {
|
|
3
|
-
rpc: SorobanRpc.Server;
|
|
4
|
-
rpcUrl: string;
|
|
3
|
+
rpc: SorobanRpc.Server | undefined;
|
|
4
|
+
rpcUrl: string | undefined;
|
|
5
5
|
launchtubeUrl: string | undefined;
|
|
6
6
|
launchtubeJwt: string | undefined;
|
|
7
7
|
mercuryUrl: string | undefined;
|
|
@@ -9,9 +9,7 @@ export declare class PasskeyBase {
|
|
|
9
9
|
mercuryEmail: string | undefined;
|
|
10
10
|
mercuryPassword: string | undefined;
|
|
11
11
|
constructor(options: {
|
|
12
|
-
rpcUrl
|
|
13
|
-
networkPassphrase: string;
|
|
14
|
-
factoryContractId: string;
|
|
12
|
+
rpcUrl?: string;
|
|
15
13
|
launchtubeUrl?: string;
|
|
16
14
|
launchtubeJwt?: string;
|
|
17
15
|
mercuryUrl?: string;
|