@getpara/react-native-wallet 2.0.0-alpha.3 → 2.0.0-dev.1
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.
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ConstructorOpts, ParaCore, Environment, PlatformUtils } from '@getpara/web-sdk';
|
|
2
|
+
import { Auth } from '@getpara/user-management-client';
|
|
2
3
|
/**
|
|
3
4
|
* Represents a mobile implementation of the Para SDK.
|
|
4
5
|
* @extends ParaCore
|
|
@@ -7,7 +8,6 @@ import { AuthStateSignup, ConstructorOpts, ParaCore, Environment, PlatformUtils
|
|
|
7
8
|
* const para = new ParaMobile(Environment.BETA, "api_key");
|
|
8
9
|
*/
|
|
9
10
|
export declare class ParaMobile extends ParaCore {
|
|
10
|
-
isNativePasskey: boolean;
|
|
11
11
|
private relyingPartyId;
|
|
12
12
|
/**
|
|
13
13
|
* Creates an instance of ParaMobile.
|
|
@@ -18,17 +18,35 @@ export declare class ParaMobile extends ParaCore {
|
|
|
18
18
|
*/
|
|
19
19
|
constructor(env: Environment, apiKey: string, relyingPartyId?: string, opts?: ConstructorOpts);
|
|
20
20
|
protected getPlatformUtils(): PlatformUtils;
|
|
21
|
+
/**
|
|
22
|
+
* Verifies an email and returns the biometrics ID.
|
|
23
|
+
* @param {string} verificationCode - The verification code sent to the email.
|
|
24
|
+
* @returns {Promise<string>} The biometrics ID.
|
|
25
|
+
*/
|
|
26
|
+
verifyEmailBiometricsId({ verificationCode }: {
|
|
27
|
+
verificationCode: string;
|
|
28
|
+
}): Promise<string>;
|
|
29
|
+
/**
|
|
30
|
+
* Verifies a phone number and returns the biometrics ID.
|
|
31
|
+
* @param {string} verificationCode - The verification code sent to the phone.
|
|
32
|
+
* @returns {Promise<string>} The biometrics ID.
|
|
33
|
+
*/
|
|
34
|
+
verifyPhoneBiometricsId({ verificationCode }: {
|
|
35
|
+
verificationCode: string;
|
|
36
|
+
}): Promise<string>;
|
|
21
37
|
/**
|
|
22
38
|
* Registers a passkey for the user.
|
|
23
39
|
* @param {Auth<'email'> | Auth<'phone'>} auth - The user's authentication details
|
|
24
40
|
* @param {string} biometricsId - The biometrics ID obtained from verification.
|
|
25
41
|
* @returns {Promise<void>}
|
|
26
42
|
*/
|
|
27
|
-
registerPasskey(
|
|
43
|
+
registerPasskey({ biometricsId, ...auth }: {
|
|
44
|
+
biometricsId: string;
|
|
45
|
+
} & (Auth<'email'> | Auth<'phone'>)): Promise<void>;
|
|
28
46
|
/**
|
|
29
47
|
* Logs in the user using their authentication credentials.
|
|
30
48
|
* @param {AuthParams} params - The authentication parameters.
|
|
31
49
|
* @returns {Promise<void>}
|
|
32
50
|
*/
|
|
33
|
-
login(): Promise<void>;
|
|
51
|
+
login({ ...auth }: Auth<'email'> | Auth<'phone'>): Promise<void>;
|
|
34
52
|
}
|
|
@@ -7,11 +7,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
11
|
+
var t = {};
|
|
12
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
13
|
+
t[p] = s[p];
|
|
14
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
15
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
16
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
17
|
+
t[p[i]] = s[p[i]];
|
|
18
|
+
}
|
|
19
|
+
return t;
|
|
20
|
+
};
|
|
10
21
|
import { ParaCore, Environment, decryptPrivateKeyAndDecryptShare, encryptPrivateKey, getAsymmetricKeyPair, getDerivedPrivateKeyAndDecrypt, getPublicKeyHex, getSHA256HashHex, parseCredentialCreationRes, } from '@getpara/web-sdk';
|
|
11
22
|
import * as Sentry from '@sentry/react-native';
|
|
12
23
|
import { ReactNativeUtils } from './ReactNativeUtils.js';
|
|
13
24
|
import { Passkey, } from 'react-native-passkey';
|
|
14
|
-
import { PublicKeyStatus } from '@getpara/user-management-client';
|
|
25
|
+
import { extractAuthInfo, PublicKeyStatus } from '@getpara/user-management-client';
|
|
15
26
|
import { setEnv } from '../config.js';
|
|
16
27
|
import base64url from 'base64url';
|
|
17
28
|
import { webcrypto } from 'crypto';
|
|
@@ -34,7 +45,6 @@ export class ParaMobile extends ParaCore {
|
|
|
34
45
|
*/
|
|
35
46
|
constructor(env, apiKey, relyingPartyId, opts) {
|
|
36
47
|
super(env, apiKey, opts);
|
|
37
|
-
this.isNativePasskey = true;
|
|
38
48
|
// starting with non-prod to see what kind of errors we get and if sensitive data is tracked
|
|
39
49
|
// will turn on in prod after monitoring
|
|
40
50
|
if (env !== Environment.PROD && env !== Environment.DEV) {
|
|
@@ -66,25 +76,56 @@ export class ParaMobile extends ParaCore {
|
|
|
66
76
|
getPlatformUtils() {
|
|
67
77
|
return new ReactNativeUtils();
|
|
68
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Verifies an email and returns the biometrics ID.
|
|
81
|
+
* @param {string} verificationCode - The verification code sent to the email.
|
|
82
|
+
* @returns {Promise<string>} The biometrics ID.
|
|
83
|
+
*/
|
|
84
|
+
verifyEmailBiometricsId(_a) {
|
|
85
|
+
const _super = Object.create(null, {
|
|
86
|
+
verifyEmail: { get: () => super.verifyEmail }
|
|
87
|
+
});
|
|
88
|
+
return __awaiter(this, arguments, void 0, function* ({ verificationCode }) {
|
|
89
|
+
const webAuthCreateUrl = yield _super.verifyEmail.call(this, { verificationCode });
|
|
90
|
+
const segments = webAuthCreateUrl.split('/');
|
|
91
|
+
const segments2 = segments[segments.length - 1].split('?');
|
|
92
|
+
const biometricsId = segments2[0];
|
|
93
|
+
return biometricsId;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Verifies a phone number and returns the biometrics ID.
|
|
98
|
+
* @param {string} verificationCode - The verification code sent to the phone.
|
|
99
|
+
* @returns {Promise<string>} The biometrics ID.
|
|
100
|
+
*/
|
|
101
|
+
verifyPhoneBiometricsId(_a) {
|
|
102
|
+
const _super = Object.create(null, {
|
|
103
|
+
verifyPhone: { get: () => super.verifyPhone }
|
|
104
|
+
});
|
|
105
|
+
return __awaiter(this, arguments, void 0, function* ({ verificationCode }) {
|
|
106
|
+
const webAuthCreateUrl = yield _super.verifyPhone.call(this, { verificationCode });
|
|
107
|
+
const segments = webAuthCreateUrl.split('/');
|
|
108
|
+
const segments2 = segments[segments.length - 1].split('?');
|
|
109
|
+
const biometricsId = segments2[0];
|
|
110
|
+
return biometricsId;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
69
113
|
/**
|
|
70
114
|
* Registers a passkey for the user.
|
|
71
115
|
* @param {Auth<'email'> | Auth<'phone'>} auth - The user's authentication details
|
|
72
116
|
* @param {string} biometricsId - The biometrics ID obtained from verification.
|
|
73
117
|
* @returns {Promise<void>}
|
|
74
118
|
*/
|
|
75
|
-
registerPasskey(
|
|
119
|
+
registerPasskey(_a) {
|
|
76
120
|
return __awaiter(this, void 0, void 0, function* () {
|
|
77
|
-
|
|
78
|
-
throw new Error('Passkey ID not found. Make sure you have enabled passkey logins in the Para Developer Portal.');
|
|
79
|
-
}
|
|
80
|
-
const userId = this.assertUserId();
|
|
81
|
-
const authInfo = this.assertIsAuthSet();
|
|
121
|
+
var { biometricsId } = _a, auth = __rest(_a, ["biometricsId"]);
|
|
82
122
|
if (!webcrypto || !webcrypto.getRandomValues) {
|
|
83
123
|
throw new Error('Web crypto is not available. Ensure you have imported the shim from @getpara/react-native-wallet.');
|
|
84
124
|
}
|
|
85
125
|
const userHandle = new Uint8Array(32);
|
|
86
126
|
webcrypto.getRandomValues(userHandle);
|
|
87
127
|
const userHandleEncoded = base64url.encode(userHandle);
|
|
128
|
+
const { identifier: displayIdentifier } = extractAuthInfo(auth, { isRequired: true });
|
|
88
129
|
const requestJson = {
|
|
89
130
|
authenticatorSelection: {
|
|
90
131
|
authenticatorAttachment: 'platform',
|
|
@@ -98,8 +139,8 @@ export class ParaMobile extends ParaCore {
|
|
|
98
139
|
},
|
|
99
140
|
user: {
|
|
100
141
|
id: userHandleEncoded,
|
|
101
|
-
name:
|
|
102
|
-
displayName:
|
|
142
|
+
name: displayIdentifier,
|
|
143
|
+
displayName: displayIdentifier,
|
|
103
144
|
},
|
|
104
145
|
pubKeyCredParams: [
|
|
105
146
|
{
|
|
@@ -129,14 +170,14 @@ export class ParaMobile extends ParaCore {
|
|
|
129
170
|
const encryptionKeyHash = getSHA256HashHex(userHandleEncoded);
|
|
130
171
|
const encryptedPrivateKeyHex = yield encryptPrivateKey(keyPair, userHandleEncoded);
|
|
131
172
|
const { partnerId } = yield this.ctx.client.touchSession();
|
|
132
|
-
yield this.ctx.client.patchSessionPublicKey(partnerId,
|
|
173
|
+
yield this.ctx.client.patchSessionPublicKey(partnerId, this.getUserId(), biometricsId, {
|
|
133
174
|
publicKey: resultJson.id,
|
|
134
175
|
sigDerivedPublicKey: publicKeyHex,
|
|
135
176
|
cosePublicKey,
|
|
136
177
|
clientDataJSON,
|
|
137
178
|
status: PublicKeyStatus.COMPLETE,
|
|
138
179
|
});
|
|
139
|
-
yield this.ctx.client.uploadEncryptedWalletPrivateKey(
|
|
180
|
+
yield this.ctx.client.uploadEncryptedWalletPrivateKey(this.getUserId(), encryptedPrivateKeyHex, encryptionKeyHash, resultJson.id);
|
|
140
181
|
});
|
|
141
182
|
}
|
|
142
183
|
/**
|
|
@@ -144,11 +185,12 @@ export class ParaMobile extends ParaCore {
|
|
|
144
185
|
* @param {AuthParams} params - The authentication parameters.
|
|
145
186
|
* @returns {Promise<void>}
|
|
146
187
|
*/
|
|
147
|
-
login() {
|
|
188
|
+
login(_a) {
|
|
148
189
|
return __awaiter(this, void 0, void 0, function* () {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const
|
|
190
|
+
var auth = __rest(_a, []);
|
|
191
|
+
yield this.logout();
|
|
192
|
+
const authInfo = extractAuthInfo(auth, { isRequired: true });
|
|
193
|
+
const { challenge, allowedPublicKeys } = yield this.ctx.client.getWebChallenge(authInfo.auth);
|
|
152
194
|
const requestJson = {
|
|
153
195
|
challenge,
|
|
154
196
|
timeout: 60000,
|
|
@@ -173,8 +215,17 @@ export class ParaMobile extends ParaCore {
|
|
|
173
215
|
signature: resultJson.response.signature,
|
|
174
216
|
},
|
|
175
217
|
});
|
|
176
|
-
|
|
177
|
-
|
|
218
|
+
const userId = verifyWebChallengeResult.data.userId;
|
|
219
|
+
yield this.setUserId(userId);
|
|
220
|
+
const { user } = yield this.ctx.client.getUser(userId);
|
|
221
|
+
if (user.phone) {
|
|
222
|
+
yield this.setPhoneNumber(user.phone.number, user.phone.countryCode);
|
|
223
|
+
}
|
|
224
|
+
if (user.email) {
|
|
225
|
+
yield this.setEmail(user.email);
|
|
226
|
+
}
|
|
227
|
+
if (user.farcasterUsername) {
|
|
228
|
+
yield this.setFarcasterUsername(user.farcasterUsername);
|
|
178
229
|
}
|
|
179
230
|
const encryptedSharesResult = yield this.ctx.client.getBiometricKeyshares(userId, resultJson.id);
|
|
180
231
|
const encryptionKeyHash = getSHA256HashHex(resultJson.response.userHandle);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getpara/react-native-wallet",
|
|
3
|
-
"version": "2.0.0-
|
|
3
|
+
"version": "2.0.0-dev.1",
|
|
4
4
|
"description": "Para Wallet for React Native",
|
|
5
5
|
"homepage": "https://getpara.com",
|
|
6
6
|
"author": "Para Team <hello@getpara.com> (https://getpara.com)",
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
"compile-signer": "bash ./scripts/compileSigner.sh"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@getpara/core-sdk": "2.0.0-
|
|
26
|
-
"@getpara/user-management-client": "2.0.0-
|
|
27
|
-
"@getpara/web-sdk": "2.0.0-
|
|
25
|
+
"@getpara/core-sdk": "2.0.0-dev.1",
|
|
26
|
+
"@getpara/user-management-client": "2.0.0-dev.1",
|
|
27
|
+
"@getpara/web-sdk": "2.0.0-dev.1",
|
|
28
28
|
"@peculiar/webcrypto": "^1.5.0",
|
|
29
29
|
"@sentry/react-native": "^6.7.0",
|
|
30
30
|
"node-forge": "1.3.1",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"publishConfig": {
|
|
61
61
|
"access": "public"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "426e843bd6084fb2e5f30ab87b02c79fc2f52832"
|
|
64
64
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
AuthStateSignup,
|
|
3
2
|
ConstructorOpts,
|
|
4
3
|
ParaCore,
|
|
5
4
|
Environment,
|
|
@@ -23,7 +22,7 @@ import {
|
|
|
23
22
|
PasskeyGetRequest,
|
|
24
23
|
PasskeyGetResult,
|
|
25
24
|
} from 'react-native-passkey';
|
|
26
|
-
import { PublicKeyStatus, WalletScheme } from '@getpara/user-management-client';
|
|
25
|
+
import { Auth, extractAuthInfo, PublicKeyStatus, WalletScheme } from '@getpara/user-management-client';
|
|
27
26
|
import { setEnv } from '../config.js';
|
|
28
27
|
import base64url from 'base64url';
|
|
29
28
|
import { webcrypto } from 'crypto';
|
|
@@ -39,8 +38,6 @@ const RS256_ALGORITHM = -257;
|
|
|
39
38
|
* const para = new ParaMobile(Environment.BETA, "api_key");
|
|
40
39
|
*/
|
|
41
40
|
export class ParaMobile extends ParaCore {
|
|
42
|
-
isNativePasskey = true;
|
|
43
|
-
|
|
44
41
|
private relyingPartyId: string;
|
|
45
42
|
/**
|
|
46
43
|
* Creates an instance of ParaMobile.
|
|
@@ -86,20 +83,40 @@ export class ParaMobile extends ParaCore {
|
|
|
86
83
|
return new ReactNativeUtils();
|
|
87
84
|
}
|
|
88
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Verifies an email and returns the biometrics ID.
|
|
88
|
+
* @param {string} verificationCode - The verification code sent to the email.
|
|
89
|
+
* @returns {Promise<string>} The biometrics ID.
|
|
90
|
+
*/
|
|
91
|
+
async verifyEmailBiometricsId({ verificationCode }: { verificationCode: string }): Promise<string> {
|
|
92
|
+
const webAuthCreateUrl = await super.verifyEmail({ verificationCode });
|
|
93
|
+
const segments = webAuthCreateUrl.split('/');
|
|
94
|
+
const segments2 = segments[segments.length - 1]!.split('?');
|
|
95
|
+
const biometricsId = segments2[0]!;
|
|
96
|
+
|
|
97
|
+
return biometricsId;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Verifies a phone number and returns the biometrics ID.
|
|
102
|
+
* @param {string} verificationCode - The verification code sent to the phone.
|
|
103
|
+
* @returns {Promise<string>} The biometrics ID.
|
|
104
|
+
*/
|
|
105
|
+
async verifyPhoneBiometricsId({ verificationCode }: { verificationCode: string }): Promise<string> {
|
|
106
|
+
const webAuthCreateUrl = await super.verifyPhone({ verificationCode });
|
|
107
|
+
const segments = webAuthCreateUrl.split('/');
|
|
108
|
+
const segments2 = segments[segments.length - 1]!.split('?');
|
|
109
|
+
const biometricsId = segments2[0]!;
|
|
110
|
+
|
|
111
|
+
return biometricsId;
|
|
112
|
+
}
|
|
89
113
|
/**
|
|
90
114
|
* Registers a passkey for the user.
|
|
91
115
|
* @param {Auth<'email'> | Auth<'phone'>} auth - The user's authentication details
|
|
92
116
|
* @param {string} biometricsId - The biometrics ID obtained from verification.
|
|
93
117
|
* @returns {Promise<void>}
|
|
94
118
|
*/
|
|
95
|
-
async registerPasskey(
|
|
96
|
-
if (!authState.passkeyId) {
|
|
97
|
-
throw new Error('Passkey ID not found. Make sure you have enabled passkey logins in the Para Developer Portal.');
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const userId = this.assertUserId();
|
|
101
|
-
const authInfo = this.assertIsAuthSet();
|
|
102
|
-
|
|
119
|
+
async registerPasskey({ biometricsId, ...auth }: { biometricsId: string } & (Auth<'email'> | Auth<'phone'>)) {
|
|
103
120
|
if (!webcrypto || !webcrypto.getRandomValues) {
|
|
104
121
|
throw new Error('Web crypto is not available. Ensure you have imported the shim from @getpara/react-native-wallet.');
|
|
105
122
|
}
|
|
@@ -107,6 +124,8 @@ export class ParaMobile extends ParaCore {
|
|
|
107
124
|
webcrypto.getRandomValues(userHandle);
|
|
108
125
|
const userHandleEncoded = base64url.encode(userHandle as any);
|
|
109
126
|
|
|
127
|
+
const { identifier: displayIdentifier } = extractAuthInfo(auth, { isRequired: true });
|
|
128
|
+
|
|
110
129
|
const requestJson: PasskeyCreateRequest = {
|
|
111
130
|
authenticatorSelection: {
|
|
112
131
|
authenticatorAttachment: 'platform' as any,
|
|
@@ -120,8 +139,8 @@ export class ParaMobile extends ParaCore {
|
|
|
120
139
|
},
|
|
121
140
|
user: {
|
|
122
141
|
id: userHandleEncoded,
|
|
123
|
-
name:
|
|
124
|
-
displayName:
|
|
142
|
+
name: displayIdentifier,
|
|
143
|
+
displayName: displayIdentifier,
|
|
125
144
|
},
|
|
126
145
|
pubKeyCredParams: [
|
|
127
146
|
{
|
|
@@ -156,7 +175,7 @@ export class ParaMobile extends ParaCore {
|
|
|
156
175
|
const encryptedPrivateKeyHex = await encryptPrivateKey(keyPair, userHandleEncoded);
|
|
157
176
|
|
|
158
177
|
const { partnerId } = await this.ctx.client.touchSession();
|
|
159
|
-
await this.ctx.client.patchSessionPublicKey(partnerId,
|
|
178
|
+
await this.ctx.client.patchSessionPublicKey(partnerId, this.getUserId()!, biometricsId, {
|
|
160
179
|
publicKey: resultJson.id,
|
|
161
180
|
sigDerivedPublicKey: publicKeyHex,
|
|
162
181
|
cosePublicKey,
|
|
@@ -164,7 +183,12 @@ export class ParaMobile extends ParaCore {
|
|
|
164
183
|
status: PublicKeyStatus.COMPLETE,
|
|
165
184
|
});
|
|
166
185
|
|
|
167
|
-
await this.ctx.client.uploadEncryptedWalletPrivateKey(
|
|
186
|
+
await this.ctx.client.uploadEncryptedWalletPrivateKey(
|
|
187
|
+
this.getUserId()!,
|
|
188
|
+
encryptedPrivateKeyHex,
|
|
189
|
+
encryptionKeyHash,
|
|
190
|
+
resultJson.id,
|
|
191
|
+
);
|
|
168
192
|
}
|
|
169
193
|
|
|
170
194
|
/**
|
|
@@ -172,11 +196,12 @@ export class ParaMobile extends ParaCore {
|
|
|
172
196
|
* @param {AuthParams} params - The authentication parameters.
|
|
173
197
|
* @returns {Promise<void>}
|
|
174
198
|
*/
|
|
175
|
-
async login(): Promise<void> {
|
|
176
|
-
this.
|
|
177
|
-
const userId = this.assertUserId();
|
|
199
|
+
async login({ ...auth }: Auth<'email'> | Auth<'phone'>): Promise<void> {
|
|
200
|
+
await this.logout();
|
|
178
201
|
|
|
179
|
-
const
|
|
202
|
+
const authInfo = extractAuthInfo(auth, { isRequired: true });
|
|
203
|
+
|
|
204
|
+
const { challenge, allowedPublicKeys } = await this.ctx.client.getWebChallenge(authInfo.auth);
|
|
180
205
|
|
|
181
206
|
const requestJson: PasskeyGetRequest = {
|
|
182
207
|
challenge,
|
|
@@ -206,8 +231,22 @@ export class ParaMobile extends ParaCore {
|
|
|
206
231
|
},
|
|
207
232
|
});
|
|
208
233
|
|
|
209
|
-
|
|
210
|
-
|
|
234
|
+
const userId = verifyWebChallengeResult.data.userId;
|
|
235
|
+
|
|
236
|
+
await this.setUserId(userId);
|
|
237
|
+
|
|
238
|
+
const { user } = await this.ctx.client.getUser(userId);
|
|
239
|
+
|
|
240
|
+
if (user.phone) {
|
|
241
|
+
await this.setPhoneNumber(user.phone.number, user.phone.countryCode);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (user.email) {
|
|
245
|
+
await this.setEmail(user.email);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (user.farcasterUsername) {
|
|
249
|
+
await this.setFarcasterUsername(user.farcasterUsername);
|
|
211
250
|
}
|
|
212
251
|
|
|
213
252
|
const encryptedSharesResult = await this.ctx.client.getBiometricKeyshares(userId, resultJson.id);
|