passkey-kit 0.3.0 → 0.4.0
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 +4 -2
- package/cheatsheet +4 -3
- package/package.json +4 -4
- package/packages/passkey-factory-sdk/package.json +3 -3
- package/packages/passkey-factory-sdk/src/index.ts +3 -3
- package/packages/passkey-factory-sdk/types/index.d.ts +1 -1
- package/packages/passkey-kit-sdk/package.json +3 -3
- package/packages/passkey-kit-sdk/src/index.ts +21 -45
- package/packages/passkey-kit-sdk/types/index.d.ts +11 -36
- package/src/kit.ts +75 -164
- package/tsconfig.json +1 -2
- package/types/kit.d.ts +5 -6
- package/types/src/base.d.ts +9 -0
- package/types/src/index.d.ts +3 -0
- package/types/src/kit.d.ts +53 -0
- package/types/tests/index.d.ts +1 -0
package/README.md
CHANGED
|
@@ -13,13 +13,14 @@ On the client:
|
|
|
13
13
|
```ts
|
|
14
14
|
const account = new PasskeyKit({
|
|
15
15
|
rpcUrl: env.RPC_URL,
|
|
16
|
-
networkPassphrase: env.NETWORK_PASSPHRASE
|
|
16
|
+
networkPassphrase: env.NETWORK_PASSPHRASE,
|
|
17
|
+
factoryContractId: env.FACTORY_CONTRACT_ID,
|
|
17
18
|
});
|
|
18
19
|
```
|
|
19
20
|
|
|
20
21
|
On the server:
|
|
21
22
|
```ts
|
|
22
|
-
const account = new
|
|
23
|
+
const account = new PasskeyBase({
|
|
23
24
|
launchtubeUrl: env.LAUNCHTUBE_URL,
|
|
24
25
|
launchtubeJwt: env.LAUNCHTUBE_JWT,
|
|
25
26
|
});
|
|
@@ -37,6 +38,7 @@ For any questions or to showcase your progress please join the `#passkeys` chann
|
|
|
37
38
|
|
|
38
39
|
Passkey kit consists of three primary directories:
|
|
39
40
|
- `./contracts` - Contains the Rust Soroban smart contracts of the smart wallet implementation.
|
|
41
|
+
- `./zephyr` - Contains the [Zephyr](https://www.mercurydata.app/products/zephyr-vm) program for processing smart wallet events.
|
|
40
42
|
- `./src` - Contains the TypeScript files for the actual TS SDK library.
|
|
41
43
|
- `./demo` - Contains a basic demo of the SDK in action.
|
|
42
44
|
|
package/cheatsheet
CHANGED
|
@@ -9,7 +9,8 @@ pnpm publish --no-git-checks
|
|
|
9
9
|
|
|
10
10
|
export MERCURY_JWT=???
|
|
11
11
|
mercury-cli --jwt $MERCURY_JWT --local false --mainnet false deploy
|
|
12
|
-
mercury-cli --jwt $MERCURY_JWT --local false --mainnet false catchup --contracts "
|
|
13
|
-
curl -X
|
|
12
|
+
mercury-cli --jwt $MERCURY_JWT --local false --mainnet false catchup --contracts "CCXIUFR243N7QWKXY44LZO3DVUXHAVBEEJWFGNGNVVB44VJXIYWVGNTR" # don't forget to subscribe to the contract first
|
|
13
|
+
curl -X GET https://api.mercurydata.app/catchups/4
|
|
14
|
+
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\": \"CCXIUFR243N7QWKXY44LZO3DVUXHAVBEEJWFGNGNVVB44VJXIYWVGNTR\"}"}}}'
|
|
14
15
|
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]}"}}}'
|
|
15
|
-
curl -X POST https://api.mercurydata.app/zephyr/execute -H "Authorization: Bearer $MERCURY_JWT" -H 'Content-Type: application/json' -d '{"mode":{"Function": {"fname": "get_events_by_address", "arguments": "{\"address\": \"
|
|
16
|
+
curl -X POST https://api.mercurydata.app/zephyr/execute -H "Authorization: Bearer $MERCURY_JWT" -H 'Content-Type: application/json' -d '{"mode":{"Function": {"fname": "get_events_by_address", "arguments": "{\"address\": \"CCXIUFR243N7QWKXY44LZO3DVUXHAVBEEJWFGNGNVVB44VJXIYWVGNTR\"}"}}}'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "passkey-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
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",
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
"@simplewebauthn/browser": "^10.0.0",
|
|
12
12
|
"@stellar/stellar-sdk": "12.1.0",
|
|
13
13
|
"base64url": "^3.0.1",
|
|
14
|
-
"bigint-conversion": "^2.4.3",
|
|
15
14
|
"buffer": "^6.0.3",
|
|
16
15
|
"cbor-x": "^1.5.9",
|
|
17
|
-
"passkey-factory-sdk": "0.
|
|
18
|
-
"passkey-kit-sdk": "0.
|
|
16
|
+
"passkey-factory-sdk": "0.2.0",
|
|
17
|
+
"passkey-kit-sdk": "0.2.0"
|
|
19
18
|
},
|
|
20
19
|
"devDependencies": {
|
|
20
|
+
"@simplewebauthn/types": "^10.0.0",
|
|
21
21
|
"typescript": "^5.5.3"
|
|
22
22
|
},
|
|
23
23
|
"workspaces": [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.2.0",
|
|
3
3
|
"name": "passkey-factory-sdk",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "src/index.ts",
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"buffer": "6.0.3",
|
|
13
|
-
"@stellar/stellar-sdk": "12.0
|
|
13
|
+
"@stellar/stellar-sdk": "12.1.0"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"typescript": "5.
|
|
16
|
+
"typescript": "5.5.3"
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -15,13 +15,13 @@ if (typeof window !== 'undefined') {
|
|
|
15
15
|
export const networks = {
|
|
16
16
|
testnet: {
|
|
17
17
|
networkPassphrase: "Test SDF Network ; September 2015",
|
|
18
|
-
contractId: "
|
|
18
|
+
contractId: "CBCPNJNIR7I6ZI5AIXTMYI3MCDCSTNUZ57XL75HQWI6Y4ESWUP24HRBG",
|
|
19
19
|
}
|
|
20
20
|
} as const
|
|
21
21
|
|
|
22
22
|
export const Errors = {
|
|
23
|
-
1: { message: "" },
|
|
24
|
-
2: { message: "" }
|
|
23
|
+
1: { message: "NotInitialized" },
|
|
24
|
+
2: { message: "AlreadyInitialized" }
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export interface Client {
|
|
@@ -3,7 +3,7 @@ import { AssembledTransaction, Client as ContractClient, ClientOptions as Contra
|
|
|
3
3
|
export declare const networks: {
|
|
4
4
|
readonly testnet: {
|
|
5
5
|
readonly networkPassphrase: "Test SDF Network ; September 2015";
|
|
6
|
-
readonly contractId: "
|
|
6
|
+
readonly contractId: "CBCPNJNIR7I6ZI5AIXTMYI3MCDCSTNUZ57XL75HQWI6Y4ESWUP24HRBG";
|
|
7
7
|
};
|
|
8
8
|
};
|
|
9
9
|
export declare const Errors: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.2.0",
|
|
3
3
|
"name": "passkey-kit-sdk",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "src/index.ts",
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"buffer": "6.0.3",
|
|
13
|
-
"@stellar/stellar-sdk": "12.0
|
|
13
|
+
"@stellar/stellar-sdk": "12.1.0"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"typescript": "5.
|
|
16
|
+
"typescript": "5.5.3"
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -15,21 +15,19 @@ if (typeof window !== 'undefined') {
|
|
|
15
15
|
export const networks = {
|
|
16
16
|
testnet: {
|
|
17
17
|
networkPassphrase: "Test SDF Network ; September 2015",
|
|
18
|
-
contractId: "
|
|
18
|
+
contractId: "CBCPNJNIR7I6ZI5AIXTMYI3MCDCSTNUZ57XL75HQWI6Y4ESWUP24HRBG",
|
|
19
19
|
}
|
|
20
20
|
} as const
|
|
21
21
|
|
|
22
22
|
export const Errors = {
|
|
23
|
-
1: { message: "" },
|
|
24
|
-
2: { message: "" },
|
|
25
|
-
3: { message: "" },
|
|
26
|
-
4: { message: "" },
|
|
27
|
-
5: { message: "" },
|
|
28
|
-
6: { message: "" },
|
|
29
|
-
7: { message: "" },
|
|
30
|
-
8: { message: "" }
|
|
31
|
-
9: { message: "" },
|
|
32
|
-
10: { message: "" }
|
|
23
|
+
1: { message: "NotFound" },
|
|
24
|
+
2: { message: "NotPermitted" },
|
|
25
|
+
3: { message: "AlreadyInitialized" },
|
|
26
|
+
4: { message: "ClientDataJsonChallengeIncorrect" },
|
|
27
|
+
5: { message: "Secp256r1PublicKeyParse" },
|
|
28
|
+
6: { message: "Secp256r1SignatureParse" },
|
|
29
|
+
7: { message: "Secp256r1VerifyFailed" },
|
|
30
|
+
8: { message: "JsonParseError" }
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
export interface Signature {
|
|
@@ -61,29 +59,9 @@ export interface Client {
|
|
|
61
59
|
}) => Promise<AssembledTransaction<Result<void>>>
|
|
62
60
|
|
|
63
61
|
/**
|
|
64
|
-
* Construct and simulate a
|
|
65
|
-
*/
|
|
66
|
-
upgrade: ({ hash }: { hash: Buffer }, options?: {
|
|
67
|
-
/**
|
|
68
|
-
* The fee to pay for the transaction. Default: BASE_FEE
|
|
69
|
-
*/
|
|
70
|
-
fee?: number;
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT
|
|
74
|
-
*/
|
|
75
|
-
timeoutInSeconds?: number;
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true
|
|
79
|
-
*/
|
|
80
|
-
simulate?: boolean;
|
|
81
|
-
}) => Promise<AssembledTransaction<Result<void>>>
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Construct and simulate a add_sig transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
|
|
62
|
+
* Construct and simulate a add transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
|
|
85
63
|
*/
|
|
86
|
-
|
|
64
|
+
add: ({ id, pk, admin }: { id: Buffer, pk: Buffer, admin: boolean }, options?: {
|
|
87
65
|
/**
|
|
88
66
|
* The fee to pay for the transaction. Default: BASE_FEE
|
|
89
67
|
*/
|
|
@@ -101,9 +79,9 @@ export interface Client {
|
|
|
101
79
|
}) => Promise<AssembledTransaction<Result<void>>>
|
|
102
80
|
|
|
103
81
|
/**
|
|
104
|
-
* Construct and simulate a
|
|
82
|
+
* Construct and simulate a remove transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
|
|
105
83
|
*/
|
|
106
|
-
|
|
84
|
+
remove: ({ id }: { id: Buffer }, options?: {
|
|
107
85
|
/**
|
|
108
86
|
* The fee to pay for the transaction. Default: BASE_FEE
|
|
109
87
|
*/
|
|
@@ -121,9 +99,9 @@ export interface Client {
|
|
|
121
99
|
}) => Promise<AssembledTransaction<Result<void>>>
|
|
122
100
|
|
|
123
101
|
/**
|
|
124
|
-
* Construct and simulate a
|
|
102
|
+
* Construct and simulate a upgrade transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
|
|
125
103
|
*/
|
|
126
|
-
|
|
104
|
+
upgrade: ({ hash }: { hash: Buffer }, options?: {
|
|
127
105
|
/**
|
|
128
106
|
* The fee to pay for the transaction. Default: BASE_FEE
|
|
129
107
|
*/
|
|
@@ -143,12 +121,11 @@ export interface Client {
|
|
|
143
121
|
export class Client extends ContractClient {
|
|
144
122
|
constructor(public readonly options: ContractClientOptions) {
|
|
145
123
|
super(
|
|
146
|
-
new ContractSpec(["
|
|
124
|
+
new ContractSpec(["AAAABAAAAAAAAAAAAAAABUVycm9yAAAAAAAACAAAAAAAAAAITm90Rm91bmQAAAABAAAAAAAAAAxOb3RQZXJtaXR0ZWQAAAACAAAAAAAAABJBbHJlYWR5SW5pdGlhbGl6ZWQAAAAAAAMAAAAAAAAAIENsaWVudERhdGFKc29uQ2hhbGxlbmdlSW5jb3JyZWN0AAAABAAAAAAAAAAXU2VjcDI1NnIxUHVibGljS2V5UGFyc2UAAAAABQAAAAAAAAAXU2VjcDI1NnIxU2lnbmF0dXJlUGFyc2UAAAAABgAAAAAAAAAVU2VjcDI1NnIxVmVyaWZ5RmFpbGVkAAAAAAAABwAAAAAAAAAOSnNvblBhcnNlRXJyb3IAAAAAAAg=",
|
|
147
125
|
"AAAAAAAAAAAAAAAEaW5pdAAAAAIAAAAAAAAAAmlkAAAAAAAOAAAAAAAAAAJwawAAAAAD7gAAAEEAAAABAAAD6QAAA+0AAAAAAAAAAw==",
|
|
126
|
+
"AAAAAAAAAAAAAAADYWRkAAAAAAMAAAAAAAAAAmlkAAAAAAAOAAAAAAAAAAJwawAAAAAD7gAAAEEAAAAAAAAABWFkbWluAAAAAAAAAQAAAAEAAAPpAAAD7QAAAAAAAAAD",
|
|
127
|
+
"AAAAAAAAAAAAAAAGcmVtb3ZlAAAAAAABAAAAAAAAAAJpZAAAAAAADgAAAAEAAAPpAAAD7QAAAAAAAAAD",
|
|
148
128
|
"AAAAAAAAAAAAAAAHdXBncmFkZQAAAAABAAAAAAAAAARoYXNoAAAD7gAAACAAAAABAAAD6QAAA+0AAAAAAAAAAw==",
|
|
149
|
-
"AAAAAAAAAAAAAAAHYWRkX3NpZwAAAAACAAAAAAAAAAJpZAAAAAAADgAAAAAAAAACcGsAAAAAA+4AAABBAAAAAQAAA+kAAAPtAAAAAAAAAAM=",
|
|
150
|
-
"AAAAAAAAAAAAAAAGcm1fc2lnAAAAAAABAAAAAAAAAAJpZAAAAAAADgAAAAEAAAPpAAAD7QAAAAAAAAAD",
|
|
151
|
-
"AAAAAAAAAAAAAAAIcmVfc3VwZXIAAAABAAAAAAAAAAJpZAAAAAAADgAAAAEAAAPpAAAD7QAAAAAAAAAD",
|
|
152
129
|
"AAAAAQAAAAAAAAAAAAAACVNpZ25hdHVyZQAAAAAAAAQAAAAAAAAAEmF1dGhlbnRpY2F0b3JfZGF0YQAAAAAADgAAAAAAAAAQY2xpZW50X2RhdGFfanNvbgAAAA4AAAAAAAAAAmlkAAAAAAAOAAAAAAAAAAlzaWduYXR1cmUAAAAAAAPuAAAAQA==",
|
|
153
130
|
"AAAAAAAAAAAAAAAMX19jaGVja19hdXRoAAAAAwAAAAAAAAARc2lnbmF0dXJlX3BheWxvYWQAAAAAAAPuAAAAIAAAAAAAAAAJc2lnbmF0dXJlAAAAAAAH0AAAAAlTaWduYXR1cmUAAAAAAAAAAAAADWF1dGhfY29udGV4dHMAAAAAAAPqAAAH0AAAAAdDb250ZXh0AAAAAAEAAAPpAAAD7QAAAAAAAAAD"]),
|
|
154
131
|
options
|
|
@@ -156,9 +133,8 @@ export class Client extends ContractClient {
|
|
|
156
133
|
}
|
|
157
134
|
public readonly fromJSON = {
|
|
158
135
|
init: this.txFromJSON<Result<void>>,
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
re_super: this.txFromJSON<Result<void>>
|
|
136
|
+
add: this.txFromJSON<Result<void>>,
|
|
137
|
+
remove: this.txFromJSON<Result<void>>,
|
|
138
|
+
upgrade: this.txFromJSON<Result<void>>
|
|
163
139
|
}
|
|
164
140
|
}
|
|
@@ -3,7 +3,7 @@ import { AssembledTransaction, Client as ContractClient, ClientOptions as Contra
|
|
|
3
3
|
export declare const networks: {
|
|
4
4
|
readonly testnet: {
|
|
5
5
|
readonly networkPassphrase: "Test SDF Network ; September 2015";
|
|
6
|
-
readonly contractId: "
|
|
6
|
+
readonly contractId: "CBCPNJNIR7I6ZI5AIXTMYI3MCDCSTNUZ57XL75HQWI6Y4ESWUP24HRBG";
|
|
7
7
|
};
|
|
8
8
|
};
|
|
9
9
|
export declare const Errors: {
|
|
@@ -31,12 +31,6 @@ export declare const Errors: {
|
|
|
31
31
|
8: {
|
|
32
32
|
message: string;
|
|
33
33
|
};
|
|
34
|
-
9: {
|
|
35
|
-
message: string;
|
|
36
|
-
};
|
|
37
|
-
10: {
|
|
38
|
-
message: string;
|
|
39
|
-
};
|
|
40
34
|
};
|
|
41
35
|
export interface Signature {
|
|
42
36
|
authenticator_data: Buffer;
|
|
@@ -66,30 +60,12 @@ export interface Client {
|
|
|
66
60
|
simulate?: boolean;
|
|
67
61
|
}) => Promise<AssembledTransaction<Result<void>>>;
|
|
68
62
|
/**
|
|
69
|
-
* Construct and simulate a
|
|
63
|
+
* Construct and simulate a add transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
|
|
70
64
|
*/
|
|
71
|
-
|
|
72
|
-
hash: Buffer;
|
|
73
|
-
}, options?: {
|
|
74
|
-
/**
|
|
75
|
-
* The fee to pay for the transaction. Default: BASE_FEE
|
|
76
|
-
*/
|
|
77
|
-
fee?: number;
|
|
78
|
-
/**
|
|
79
|
-
* The maximum amount of time to wait for the transaction to complete. Default: DEFAULT_TIMEOUT
|
|
80
|
-
*/
|
|
81
|
-
timeoutInSeconds?: number;
|
|
82
|
-
/**
|
|
83
|
-
* Whether to automatically simulate the transaction when constructing the AssembledTransaction. Default: true
|
|
84
|
-
*/
|
|
85
|
-
simulate?: boolean;
|
|
86
|
-
}) => Promise<AssembledTransaction<Result<void>>>;
|
|
87
|
-
/**
|
|
88
|
-
* Construct and simulate a add_sig transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
|
|
89
|
-
*/
|
|
90
|
-
add_sig: ({ id, pk }: {
|
|
65
|
+
add: ({ id, pk, admin }: {
|
|
91
66
|
id: Buffer;
|
|
92
67
|
pk: Buffer;
|
|
68
|
+
admin: boolean;
|
|
93
69
|
}, options?: {
|
|
94
70
|
/**
|
|
95
71
|
* The fee to pay for the transaction. Default: BASE_FEE
|
|
@@ -105,9 +81,9 @@ export interface Client {
|
|
|
105
81
|
simulate?: boolean;
|
|
106
82
|
}) => Promise<AssembledTransaction<Result<void>>>;
|
|
107
83
|
/**
|
|
108
|
-
* Construct and simulate a
|
|
84
|
+
* Construct and simulate a remove transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
|
|
109
85
|
*/
|
|
110
|
-
|
|
86
|
+
remove: ({ id }: {
|
|
111
87
|
id: Buffer;
|
|
112
88
|
}, options?: {
|
|
113
89
|
/**
|
|
@@ -124,10 +100,10 @@ export interface Client {
|
|
|
124
100
|
simulate?: boolean;
|
|
125
101
|
}) => Promise<AssembledTransaction<Result<void>>>;
|
|
126
102
|
/**
|
|
127
|
-
* Construct and simulate a
|
|
103
|
+
* Construct and simulate a upgrade transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
|
|
128
104
|
*/
|
|
129
|
-
|
|
130
|
-
|
|
105
|
+
upgrade: ({ hash }: {
|
|
106
|
+
hash: Buffer;
|
|
131
107
|
}, options?: {
|
|
132
108
|
/**
|
|
133
109
|
* The fee to pay for the transaction. Default: BASE_FEE
|
|
@@ -148,9 +124,8 @@ export declare class Client extends ContractClient {
|
|
|
148
124
|
constructor(options: ContractClientOptions);
|
|
149
125
|
readonly fromJSON: {
|
|
150
126
|
init: (json: string) => AssembledTransaction<Result<void, import("@stellar/stellar-sdk/contract").ErrorMessage>>;
|
|
127
|
+
add: (json: string) => AssembledTransaction<Result<void, import("@stellar/stellar-sdk/contract").ErrorMessage>>;
|
|
128
|
+
remove: (json: string) => AssembledTransaction<Result<void, import("@stellar/stellar-sdk/contract").ErrorMessage>>;
|
|
151
129
|
upgrade: (json: string) => AssembledTransaction<Result<void, import("@stellar/stellar-sdk/contract").ErrorMessage>>;
|
|
152
|
-
add_sig: (json: string) => AssembledTransaction<Result<void, import("@stellar/stellar-sdk/contract").ErrorMessage>>;
|
|
153
|
-
rm_sig: (json: string) => AssembledTransaction<Result<void, import("@stellar/stellar-sdk/contract").ErrorMessage>>;
|
|
154
|
-
re_super: (json: string) => AssembledTransaction<Result<void, import("@stellar/stellar-sdk/contract").ErrorMessage>>;
|
|
155
130
|
};
|
|
156
131
|
}
|
package/src/kit.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Client as PasskeyClient } from 'passkey-kit-sdk'
|
|
2
2
|
import { Client as FactoryClient } from 'passkey-factory-sdk'
|
|
3
|
-
import { Address, Networks, StrKey, hash, xdr, Transaction, SorobanRpc, Operation,
|
|
4
|
-
import { bufToBigint, bigintToBuf } from 'bigint-conversion'
|
|
3
|
+
import { Address, Networks, StrKey, hash, xdr, Transaction, SorobanRpc, Operation, TransactionBuilder } from '@stellar/stellar-sdk'
|
|
5
4
|
import base64url from 'base64url'
|
|
6
5
|
import { startRegistration, startAuthentication } from "@simplewebauthn/browser"
|
|
6
|
+
import type { AuthenticatorAttestationResponseJSON } from "@simplewebauthn/types"
|
|
7
7
|
import { decode } from 'cbor-x/decode'
|
|
8
8
|
import { Buffer } from 'buffer'
|
|
9
9
|
import { PasskeyBase } from './base'
|
|
@@ -49,8 +49,8 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
49
49
|
})
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
public async createWallet(
|
|
53
|
-
const { keyId, publicKey } = await this.createKey(
|
|
52
|
+
public async createWallet(app: string, user: string) {
|
|
53
|
+
const { keyId, publicKey } = await this.createKey(app, user)
|
|
54
54
|
|
|
55
55
|
const { result, built } = await this.factory.deploy({
|
|
56
56
|
id: keyId,
|
|
@@ -72,17 +72,19 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
public async createKey(
|
|
76
|
-
const
|
|
75
|
+
public async createKey(app: string, user: string) {
|
|
76
|
+
const now = new Date()
|
|
77
|
+
const displayName = `${user} — ${now.toLocaleString()}`
|
|
78
|
+
const { id, response} = await startRegistration({
|
|
77
79
|
challenge: base64url("stellaristhebetterblockchain"),
|
|
78
80
|
rp: {
|
|
79
81
|
// id: undefined,
|
|
80
|
-
name,
|
|
82
|
+
name: app,
|
|
81
83
|
},
|
|
82
|
-
user: {
|
|
83
|
-
id: base64url(user),
|
|
84
|
-
name:
|
|
85
|
-
displayName
|
|
84
|
+
user: { // TODO there's a real danger here of overwriting a user's key if they use the same `user` name
|
|
85
|
+
id: base64url(`${user}:${now.getTime()}:${Math.random()}`),
|
|
86
|
+
name: displayName,
|
|
87
|
+
displayName
|
|
86
88
|
},
|
|
87
89
|
authenticatorSelection: {
|
|
88
90
|
requireResidentKey: false,
|
|
@@ -94,18 +96,12 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
94
96
|
});
|
|
95
97
|
|
|
96
98
|
if (!this.keyId)
|
|
97
|
-
this.keyId =
|
|
99
|
+
this.keyId = id;
|
|
98
100
|
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
const publicKey = Buffer.from([
|
|
102
|
-
4, // (0x04 prefix) https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm
|
|
103
|
-
...publicKeyObject.get('-2')!,
|
|
104
|
-
...publicKeyObject.get('-3')!
|
|
105
|
-
])
|
|
101
|
+
const publicKey = this.getPublicKey(response);
|
|
106
102
|
|
|
107
103
|
return {
|
|
108
|
-
keyId: base64url.toBuffer(
|
|
104
|
+
keyId: base64url.toBuffer(id),
|
|
109
105
|
publicKey
|
|
110
106
|
}
|
|
111
107
|
}
|
|
@@ -115,21 +111,23 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
115
111
|
getContractId?: GetContractIdFunction
|
|
116
112
|
}) {
|
|
117
113
|
let { keyId, getContractId } = opts
|
|
118
|
-
let keyIdBuffer:
|
|
114
|
+
let keyIdBuffer: Buffer
|
|
119
115
|
|
|
120
116
|
if (!keyId) {
|
|
121
|
-
const
|
|
117
|
+
const response = await startAuthentication({
|
|
122
118
|
challenge: base64url("stellaristhebetterblockchain"),
|
|
123
119
|
// rpId: undefined,
|
|
124
120
|
userVerification: "discouraged",
|
|
125
121
|
});
|
|
126
122
|
|
|
127
|
-
|
|
123
|
+
console.log(response);
|
|
124
|
+
|
|
125
|
+
keyId = response.id
|
|
128
126
|
}
|
|
129
127
|
|
|
130
128
|
if (keyId instanceof Uint8Array) {
|
|
131
|
-
keyIdBuffer = keyId
|
|
132
|
-
keyId = base64url(
|
|
129
|
+
keyIdBuffer = Buffer.from(keyId)
|
|
130
|
+
keyId = base64url(keyIdBuffer)
|
|
133
131
|
} else {
|
|
134
132
|
keyIdBuffer = base64url.toBuffer(keyId)
|
|
135
133
|
}
|
|
@@ -222,7 +220,7 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
222
220
|
allowCredentials: [
|
|
223
221
|
{
|
|
224
222
|
id: keyId instanceof Uint8Array
|
|
225
|
-
? base64url(keyId)
|
|
223
|
+
? base64url(Buffer.from(keyId))
|
|
226
224
|
: keyId || this.keyId!,
|
|
227
225
|
type: "public-key",
|
|
228
226
|
},
|
|
@@ -231,8 +229,9 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
231
229
|
}
|
|
232
230
|
);
|
|
233
231
|
|
|
234
|
-
const
|
|
235
|
-
|
|
232
|
+
const signature = this.compactSignature(
|
|
233
|
+
base64url.toBuffer(authenticationResponse.response.signature)
|
|
234
|
+
);
|
|
236
235
|
|
|
237
236
|
credentials.signatureExpirationLedger(lastLedger + ledgersToLive)
|
|
238
237
|
credentials.signature(xdr.ScVal.scvMap([
|
|
@@ -323,27 +322,6 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
323
322
|
|
|
324
323
|
return SorobanRpc.assembleTransaction(txn, sim).build().toXDR()
|
|
325
324
|
}
|
|
326
|
-
public async getSuperKeyId() {
|
|
327
|
-
const data: Map<string, any> = new Map()
|
|
328
|
-
|
|
329
|
-
const { val } = await this.rpc.getContractData(
|
|
330
|
-
this.wallet!.options.contractId,
|
|
331
|
-
xdr.ScVal.scvLedgerKeyContractInstance(),
|
|
332
|
-
);
|
|
333
|
-
|
|
334
|
-
val.contractData()
|
|
335
|
-
.val()
|
|
336
|
-
.instance()
|
|
337
|
-
.storage()
|
|
338
|
-
?.forEach((entry) => {
|
|
339
|
-
data.set(
|
|
340
|
-
scValToNative(entry.key()),
|
|
341
|
-
scValToNative(entry.val()),
|
|
342
|
-
);
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
return base64url(data.get('super'))
|
|
346
|
-
}
|
|
347
325
|
|
|
348
326
|
/* TODO
|
|
349
327
|
- Add a getKeyInfo action to get info about a specific passkey
|
|
@@ -351,133 +329,66 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
351
329
|
@Later
|
|
352
330
|
*/
|
|
353
331
|
|
|
354
|
-
private
|
|
355
|
-
|
|
356
|
-
const authDataUint8Array = new Uint8Array(authData);
|
|
357
|
-
const authDataView = new DataView(authDataUint8Array.buffer, 0, authDataUint8Array.length);
|
|
358
|
-
|
|
359
|
-
let offset = 0;
|
|
360
|
-
|
|
361
|
-
// RP ID Hash (32 bytes)
|
|
362
|
-
const rpIdHash = authData.slice(offset, offset + 32);
|
|
363
|
-
offset += 32;
|
|
364
|
-
|
|
365
|
-
// Flags (1 byte)
|
|
366
|
-
const flags = authDataView.getUint8(offset);
|
|
367
|
-
offset += 1;
|
|
368
|
-
|
|
369
|
-
// Sign Count (4 bytes, big endian)
|
|
370
|
-
const signCount = authDataView.getUint32(offset, false);
|
|
371
|
-
offset += 4;
|
|
372
|
-
|
|
373
|
-
// Attested Credential Data, if present
|
|
374
|
-
if (flags & 0x40) { // Checking the AT flag
|
|
375
|
-
// AAGUID (16 bytes)
|
|
376
|
-
const aaguid = authData.slice(offset, offset + 16);
|
|
377
|
-
offset += 16;
|
|
378
|
-
|
|
379
|
-
// Credential ID Length (2 bytes, big endian)
|
|
380
|
-
const credIdLength = authDataView.getUint16(offset, false);
|
|
381
|
-
offset += 2;
|
|
382
|
-
|
|
383
|
-
// Credential ID (variable length)
|
|
384
|
-
const credentialId = authData.slice(offset, offset + credIdLength);
|
|
385
|
-
offset += credIdLength;
|
|
386
|
-
|
|
387
|
-
// Credential Public Key - (77 bytes...I hope)
|
|
388
|
-
const credentialPublicKey = authData.slice(offset, offset + 77);
|
|
389
|
-
offset += 77;
|
|
390
|
-
|
|
391
|
-
// Any leftover bytes. I found some when using a YubiKey
|
|
392
|
-
const theRest = authData.slice(offset);
|
|
393
|
-
|
|
394
|
-
// Decode the credential public key to COSE
|
|
395
|
-
const publicKeyObject = new Map<string, any>(Object.entries(decode(credentialPublicKey)));
|
|
396
|
-
|
|
397
|
-
return {
|
|
398
|
-
rpIdHash,
|
|
399
|
-
flags,
|
|
400
|
-
signCount,
|
|
401
|
-
aaguid,
|
|
402
|
-
credIdLength,
|
|
403
|
-
credentialId,
|
|
404
|
-
credentialPublicKey,
|
|
405
|
-
theRest,
|
|
406
|
-
publicKeyObject
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
throw new Error("Attested credential data not present in the flags.");
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
private convertEcdsaSignatureAsnToCompact(sig: Buffer) {
|
|
414
|
-
// Define the order of the curve secp256k1
|
|
415
|
-
// https://github.com/RustCrypto/elliptic-curves/blob/master/p256/src/lib.rs#L72
|
|
416
|
-
const q = Buffer.from('ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551', 'hex')
|
|
417
|
-
|
|
418
|
-
// ASN Sequence
|
|
419
|
-
let offset = 0;
|
|
420
|
-
if (sig[offset] != 0x30) {
|
|
421
|
-
throw "signature is not a sequence";
|
|
422
|
-
}
|
|
423
|
-
offset += 1;
|
|
332
|
+
private getPublicKey(response: AuthenticatorAttestationResponseJSON) {
|
|
333
|
+
let publicKey: Buffer | undefined
|
|
424
334
|
|
|
425
|
-
|
|
426
|
-
|
|
335
|
+
if (response.publicKey)
|
|
336
|
+
publicKey = base64url.toBuffer(response.publicKey).slice(response.publicKey.length - 65)
|
|
427
337
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
338
|
+
if (
|
|
339
|
+
!publicKey
|
|
340
|
+
|| publicKey[0] !== 0x04
|
|
341
|
+
|| publicKey.length !== 65
|
|
342
|
+
) {
|
|
343
|
+
// Extract and decode attestation object (CBOR), slice authenticator data to get COSE-encoded public key, and decode COSE to obtain key components
|
|
344
|
+
const { authData } = response.authenticatorData ? { authData: base64url.toBuffer(response.authenticatorData) } : decode(base64url.toBuffer(response.attestationObject));
|
|
345
|
+
const credentialIdLength = (authData[53] << 8) + authData[54];
|
|
346
|
+
const publicKeyBytes = authData.slice(55 + credentialIdLength);
|
|
347
|
+
const publicKeyCose = decode(publicKeyBytes);
|
|
348
|
+
|
|
349
|
+
publicKey = Buffer.from([
|
|
350
|
+
0x04, // (0x04 prefix) https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm
|
|
351
|
+
...publicKeyCose['-2'],
|
|
352
|
+
...publicKeyCose['-3']
|
|
353
|
+
])
|
|
431
354
|
}
|
|
432
|
-
offset += 1;
|
|
433
355
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
356
|
+
return publicKey
|
|
357
|
+
}
|
|
358
|
+
private compactSignature(signature: Buffer) {
|
|
359
|
+
// Decode the DER signature
|
|
360
|
+
let offset = 2;
|
|
437
361
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
if (rLen != 33 || sig[offset] != 0x00) {
|
|
441
|
-
throw "can only handle larger than 32 byte R's that are len 33 and lead with zero";
|
|
442
|
-
}
|
|
443
|
-
offset += 1;
|
|
444
|
-
}
|
|
445
|
-
const r = sig.slice(offset, offset + 32);
|
|
446
|
-
offset += 32;
|
|
362
|
+
const rLength = signature[offset + 1];
|
|
363
|
+
const r = signature.slice(offset + 2, offset + 2 + rLength);
|
|
447
364
|
|
|
448
|
-
|
|
449
|
-
if (sig[offset] != 0x02) {
|
|
450
|
-
throw "second element in sequence is not an integer";
|
|
451
|
-
}
|
|
452
|
-
offset += 1;
|
|
365
|
+
offset += 2 + rLength;
|
|
453
366
|
|
|
454
|
-
|
|
455
|
-
const
|
|
456
|
-
offset += 1;
|
|
367
|
+
const sLength = signature[offset + 1];
|
|
368
|
+
const s = signature.slice(offset + 2, offset + 2 + sLength);
|
|
457
369
|
|
|
458
|
-
//
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
throw "can only handle larger than 32 byte R's that are len 33 and lead with zero";
|
|
462
|
-
}
|
|
463
|
-
offset += 1;
|
|
464
|
-
}
|
|
370
|
+
// Convert r and s to BigInt
|
|
371
|
+
const rBigInt = BigInt('0x' + r.toString('hex'));
|
|
372
|
+
let sBigInt = BigInt('0x' + s.toString('hex'));
|
|
465
373
|
|
|
466
|
-
|
|
374
|
+
// Ensure s is in the low-S form
|
|
375
|
+
// https://github.com/stellar/stellar-protocol/discussions/1435#discussioncomment-8809175
|
|
376
|
+
// https://discord.com/channels/897514728459468821/1233048618571927693
|
|
377
|
+
// Define the order of the curve secp256r1
|
|
378
|
+
// https://github.com/RustCrypto/elliptic-curves/blob/master/p256/src/lib.rs#L72
|
|
379
|
+
const n = BigInt('0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551');
|
|
380
|
+
const halfN = n / 2n;
|
|
467
381
|
|
|
468
|
-
|
|
382
|
+
if (sBigInt > halfN)
|
|
383
|
+
sBigInt = n - sBigInt;
|
|
469
384
|
|
|
470
|
-
|
|
385
|
+
// Convert back to buffers and ensure they are 32 bytes
|
|
386
|
+
const rPadded = Buffer.from(rBigInt.toString(16).padStart(64, '0'), 'hex');
|
|
387
|
+
const sLowS = Buffer.from(sBigInt.toString(16).padStart(64, '0'), 'hex');
|
|
471
388
|
|
|
472
|
-
//
|
|
473
|
-
|
|
474
|
-
// https://discord.com/channels/897514728459468821/1233048618571927693
|
|
475
|
-
if (bufToBigint(s) > ((bufToBigint(q) - BigInt(1)) / BigInt(2))) {
|
|
476
|
-
signature64 = Buffer.from([...r, ...Buffer.from(bigintToBuf(bufToBigint(q) - bufToBigint(s), true) as ArrayBuffer)]);
|
|
477
|
-
} else {
|
|
478
|
-
signature64 = Buffer.from([...r, ...s]);
|
|
479
|
-
}
|
|
389
|
+
// Concatenate r and low-s
|
|
390
|
+
const concatSignature = Buffer.concat([rPadded, sLowS]);
|
|
480
391
|
|
|
481
|
-
return
|
|
392
|
+
return concatSignature;
|
|
482
393
|
}
|
|
483
394
|
}
|
package/tsconfig.json
CHANGED
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
"target": "ESNext",
|
|
7
7
|
"module": "ESNext",
|
|
8
8
|
"moduleDetection": "force",
|
|
9
|
-
// "allowJs": true,
|
|
10
9
|
|
|
11
10
|
// Bundler mode
|
|
12
11
|
"moduleResolution": "node",
|
|
@@ -26,5 +25,5 @@
|
|
|
26
25
|
"noPropertyAccessFromIndexSignature": false,
|
|
27
26
|
"strictNullChecks": true,
|
|
28
27
|
},
|
|
29
|
-
"exclude": ["./demo", "./packages", "./types", "./contracts", "./zephyr"]
|
|
28
|
+
"exclude": ["./demo", "./packages", "./types", "./contracts", "./zephyr", "./bun_tests"]
|
|
30
29
|
}
|
package/types/kit.d.ts
CHANGED
|
@@ -19,12 +19,12 @@ export declare class PasskeyKit extends PasskeyBase {
|
|
|
19
19
|
networkPassphrase: string;
|
|
20
20
|
factoryContractId: string;
|
|
21
21
|
});
|
|
22
|
-
createWallet(
|
|
22
|
+
createWallet(app: string, user: string): Promise<{
|
|
23
23
|
keyId: Buffer;
|
|
24
24
|
contractId: string;
|
|
25
25
|
xdr: string;
|
|
26
26
|
}>;
|
|
27
|
-
createKey(
|
|
27
|
+
createKey(app: string, user: string): Promise<{
|
|
28
28
|
keyId: Buffer;
|
|
29
29
|
publicKey: Buffer;
|
|
30
30
|
}>;
|
|
@@ -32,7 +32,7 @@ export declare class PasskeyKit extends PasskeyBase {
|
|
|
32
32
|
keyId?: string | Uint8Array;
|
|
33
33
|
getContractId?: GetContractIdFunction;
|
|
34
34
|
}): Promise<{
|
|
35
|
-
keyId:
|
|
35
|
+
keyId: Buffer;
|
|
36
36
|
contractId: string;
|
|
37
37
|
}>;
|
|
38
38
|
signAuthEntry(entry: xdr.SorobanAuthorizationEntry, options?: {
|
|
@@ -47,8 +47,7 @@ export declare class PasskeyKit extends PasskeyBase {
|
|
|
47
47
|
keyId?: 'any' | string | Uint8Array;
|
|
48
48
|
ledgersToLive?: number;
|
|
49
49
|
}): Promise<string>;
|
|
50
|
-
|
|
51
|
-
private
|
|
52
|
-
private convertEcdsaSignatureAsnToCompact;
|
|
50
|
+
private getPublicKey;
|
|
51
|
+
private compactSignature;
|
|
53
52
|
}
|
|
54
53
|
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Client as PasskeyClient } from 'passkey-kit-sdk';
|
|
2
|
+
import { Client as FactoryClient } from 'passkey-factory-sdk';
|
|
3
|
+
import { Networks, xdr, Transaction, SorobanRpc } from '@stellar/stellar-sdk';
|
|
4
|
+
import { Buffer } from 'buffer';
|
|
5
|
+
import { PasskeyBase } from './base';
|
|
6
|
+
type GetContractIdFunction = (keyId: string) => Promise<string>;
|
|
7
|
+
export declare class PasskeyKit extends PasskeyBase {
|
|
8
|
+
keyId: string | undefined;
|
|
9
|
+
keyExpired: boolean | undefined;
|
|
10
|
+
wallet: PasskeyClient | undefined;
|
|
11
|
+
factory: FactoryClient;
|
|
12
|
+
networkPassphrase: Networks;
|
|
13
|
+
rpcUrl: string;
|
|
14
|
+
rpc: SorobanRpc.Server;
|
|
15
|
+
constructor(options: {
|
|
16
|
+
rpcUrl: string;
|
|
17
|
+
launchtubeUrl?: string;
|
|
18
|
+
launchtubeJwt?: string;
|
|
19
|
+
networkPassphrase: string;
|
|
20
|
+
factoryContractId: string;
|
|
21
|
+
});
|
|
22
|
+
createWallet(name: string, user: string): Promise<{
|
|
23
|
+
keyId: Buffer;
|
|
24
|
+
contractId: string;
|
|
25
|
+
xdr: string;
|
|
26
|
+
}>;
|
|
27
|
+
createKey(name: string, user: string): Promise<{
|
|
28
|
+
keyId: Buffer;
|
|
29
|
+
publicKey: Buffer;
|
|
30
|
+
}>;
|
|
31
|
+
connectWallet(opts: {
|
|
32
|
+
keyId?: string | Uint8Array;
|
|
33
|
+
getContractId?: GetContractIdFunction;
|
|
34
|
+
}): Promise<{
|
|
35
|
+
keyId: Buffer;
|
|
36
|
+
contractId: string;
|
|
37
|
+
}>;
|
|
38
|
+
signAuthEntry(entry: xdr.SorobanAuthorizationEntry, options?: {
|
|
39
|
+
keyId?: 'any' | string | Uint8Array;
|
|
40
|
+
ledgersToLive?: number;
|
|
41
|
+
}): Promise<xdr.SorobanAuthorizationEntry>;
|
|
42
|
+
signAuthEntries(entries: xdr.SorobanAuthorizationEntry[], options?: {
|
|
43
|
+
keyId?: 'any' | string | Uint8Array;
|
|
44
|
+
ledgersToLive?: number;
|
|
45
|
+
}): Promise<xdr.SorobanAuthorizationEntry[]>;
|
|
46
|
+
sign(txn: Transaction | string, options?: {
|
|
47
|
+
keyId?: 'any' | string | Uint8Array;
|
|
48
|
+
ledgersToLive?: number;
|
|
49
|
+
}): Promise<string>;
|
|
50
|
+
private getPublicKeyObject;
|
|
51
|
+
private convertEcdsaSignatureAsnToCompact;
|
|
52
|
+
}
|
|
53
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|