@getpara/react-native-wallet 2.0.0-alpha.6 → 2.0.0-alpha.60
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/dist/config.d.ts +3 -0
- package/dist/config.js +1 -0
- package/dist/react-native/ParaMobile.d.ts +5 -2
- package/dist/react-native/ParaMobile.js +65 -19
- package/dist/react-native/ReactNativeUtils.d.ts +1 -0
- package/dist/react-native/ReactNativeUtils.js +5 -0
- package/dist/shim.d.ts +130 -1
- package/dist/shim.js +187 -10
- package/package.json +58 -25
- package/src/config.ts +2 -0
- package/src/react-native/ParaMobile.ts +70 -14
- package/src/react-native/ReactNativeUtils.ts +4 -0
- package/src/shim.js +215 -10
- /package/src/{index.tsx → index.ts} +0 -0
package/dist/config.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { Environment } from '@getpara/web-sdk';
|
|
2
|
+
declare function getPortalBaseURL(env: Environment): "http://localhost:3003" | "https://app.sandbox.usecapsule.com" | "https://app.beta.usecapsule.com" | "https://app.usecapsule.com";
|
|
3
|
+
declare function getBaseUrl(env: Environment): string;
|
|
2
4
|
export declare function getBaseMPCNetworkWSUrl(env: Environment): string;
|
|
3
5
|
export declare let userManagementServer: string;
|
|
4
6
|
export declare let portalBase: string;
|
|
5
7
|
export declare let mpcNetworkWSServer: string;
|
|
6
8
|
export declare function setEnv(env: Environment): void;
|
|
7
9
|
export declare const DEBUG_MODE_ENABLED = false;
|
|
10
|
+
export { getBaseUrl, getPortalBaseURL };
|
package/dist/config.js
CHANGED
|
@@ -11,13 +11,16 @@ export declare class ParaMobile extends ParaCore {
|
|
|
11
11
|
private relyingPartyId;
|
|
12
12
|
/**
|
|
13
13
|
* Creates an instance of ParaMobile.
|
|
14
|
-
* @param {Environment} env - The environment to use (DEV, SANDBOX, BETA, or PROD).
|
|
14
|
+
* @param {Environment} env - The environment to use (DEV, SANDBOX, BETA, or PROD). Optional if the apiKey contains an environment prefix (e.g., "prod_your_api_key"). Updated API keys can be found at https://developer.getpara.com.
|
|
15
15
|
* @param {string} [apiKey] - The API key for authentication.
|
|
16
16
|
* @param {string} [relyingPartyId] - The relying party ID for WebAuthn.
|
|
17
17
|
* @param {ConstructorOpts} [opts] - Additional constructor options.
|
|
18
18
|
*/
|
|
19
|
-
constructor(env: Environment, apiKey: string, relyingPartyId?: string, opts?: ConstructorOpts);
|
|
19
|
+
constructor(env: Environment | undefined, apiKey: string, relyingPartyId?: string, opts?: ConstructorOpts);
|
|
20
|
+
constructor(apiKey: string, relyingPartyId?: string, opts?: ConstructorOpts);
|
|
21
|
+
ready(): Promise<void>;
|
|
20
22
|
protected getPlatformUtils(): PlatformUtils;
|
|
23
|
+
isPasskeySupported(): Promise<boolean>;
|
|
21
24
|
/**
|
|
22
25
|
* Registers a passkey for the user.
|
|
23
26
|
* @param {Auth<'email'> | Auth<'phone'>} auth - The user's authentication details
|
|
@@ -8,10 +8,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { ParaCore, Environment, decryptPrivateKeyAndDecryptShare, encryptPrivateKey, getAsymmetricKeyPair, getDerivedPrivateKeyAndDecrypt, getPublicKeyHex, getSHA256HashHex, parseCredentialCreationRes, } from '@getpara/web-sdk';
|
|
11
|
-
import * as Sentry from '@sentry/react-native';
|
|
12
11
|
import { ReactNativeUtils } from './ReactNativeUtils.js';
|
|
13
12
|
import { Passkey, } from 'react-native-passkey';
|
|
14
|
-
import {
|
|
13
|
+
import { AuthMethodStatus } from '@getpara/user-management-client';
|
|
15
14
|
import { setEnv } from '../config.js';
|
|
16
15
|
import base64url from 'base64url';
|
|
17
16
|
import { webcrypto } from 'crypto';
|
|
@@ -25,24 +24,61 @@ const RS256_ALGORITHM = -257;
|
|
|
25
24
|
* const para = new ParaMobile(Environment.BETA, "api_key");
|
|
26
25
|
*/
|
|
27
26
|
export class ParaMobile extends ParaCore {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
constructor(envOrApiKey, apiKeyOrRelyingPartyId, relyingPartyIdOrOpts, optsArg) {
|
|
28
|
+
let env, apiKey, relyingPartyId, opts;
|
|
29
|
+
// Helper function to check if value is a valid Environment
|
|
30
|
+
const isEnvironment = (value) => {
|
|
31
|
+
return Object.values(Environment).includes(value);
|
|
32
|
+
};
|
|
33
|
+
if (arguments.length === 1) {
|
|
34
|
+
// 1-parameter case: (apiKey)
|
|
35
|
+
env = undefined;
|
|
36
|
+
apiKey = envOrApiKey;
|
|
37
|
+
relyingPartyId = undefined;
|
|
38
|
+
opts = undefined;
|
|
39
|
+
}
|
|
40
|
+
else if (arguments.length === 2) {
|
|
41
|
+
if (isEnvironment(envOrApiKey)) {
|
|
42
|
+
// 2-parameter case: (env, apiKey)
|
|
43
|
+
env = envOrApiKey;
|
|
44
|
+
apiKey = apiKeyOrRelyingPartyId;
|
|
45
|
+
relyingPartyId = undefined;
|
|
46
|
+
opts = undefined;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// 2-parameter case: (apiKey, relyingPartyId)
|
|
50
|
+
env = undefined;
|
|
51
|
+
apiKey = envOrApiKey;
|
|
52
|
+
relyingPartyId = apiKeyOrRelyingPartyId;
|
|
53
|
+
opts = undefined;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else if (arguments.length === 3) {
|
|
57
|
+
if (isEnvironment(envOrApiKey)) {
|
|
58
|
+
// 3-parameter case: (env, apiKey, relyingPartyId)
|
|
59
|
+
env = envOrApiKey;
|
|
60
|
+
apiKey = apiKeyOrRelyingPartyId;
|
|
61
|
+
relyingPartyId = relyingPartyIdOrOpts;
|
|
62
|
+
opts = undefined;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
// 3-parameter case: (apiKey, relyingPartyId, opts)
|
|
66
|
+
env = undefined;
|
|
67
|
+
apiKey = envOrApiKey;
|
|
68
|
+
relyingPartyId = apiKeyOrRelyingPartyId;
|
|
69
|
+
opts = relyingPartyIdOrOpts;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// 4-parameter case: (env, apiKey, relyingPartyId, opts)
|
|
74
|
+
env = envOrApiKey;
|
|
75
|
+
apiKey = apiKeyOrRelyingPartyId;
|
|
76
|
+
relyingPartyId = relyingPartyIdOrOpts;
|
|
77
|
+
opts = optsArg;
|
|
78
|
+
}
|
|
79
|
+
env = ParaCore.resolveEnvironment(env, apiKey); // Ensure the environment is resolved before calling super
|
|
36
80
|
super(env, apiKey, opts);
|
|
37
81
|
this.isNativePasskey = true;
|
|
38
|
-
// starting with non-prod to see what kind of errors we get and if sensitive data is tracked
|
|
39
|
-
// will turn on in prod after monitoring
|
|
40
|
-
if (env !== Environment.PROD && env !== Environment.DEV) {
|
|
41
|
-
Sentry.init({
|
|
42
|
-
environment: env.toLowerCase(),
|
|
43
|
-
dsn: 'https://59cea0cfbbb30a646c4e9f2feea06da4@o4504568036720640.ingest.us.sentry.io/4508850922323968',
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
82
|
setEnv(env);
|
|
47
83
|
if (relyingPartyId) {
|
|
48
84
|
this.relyingPartyId = relyingPartyId;
|
|
@@ -63,9 +99,19 @@ export class ParaMobile extends ParaCore {
|
|
|
63
99
|
}
|
|
64
100
|
}
|
|
65
101
|
}
|
|
102
|
+
ready() {
|
|
103
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
104
|
+
this.isReady = true;
|
|
105
|
+
});
|
|
106
|
+
}
|
|
66
107
|
getPlatformUtils() {
|
|
67
108
|
return new ReactNativeUtils();
|
|
68
109
|
}
|
|
110
|
+
isPasskeySupported() {
|
|
111
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
112
|
+
return Passkey.isSupported();
|
|
113
|
+
});
|
|
114
|
+
}
|
|
69
115
|
/**
|
|
70
116
|
* Registers a passkey for the user.
|
|
71
117
|
* @param {Auth<'email'> | Auth<'phone'>} auth - The user's authentication details
|
|
@@ -134,7 +180,7 @@ export class ParaMobile extends ParaCore {
|
|
|
134
180
|
sigDerivedPublicKey: publicKeyHex,
|
|
135
181
|
cosePublicKey,
|
|
136
182
|
clientDataJSON,
|
|
137
|
-
status:
|
|
183
|
+
status: AuthMethodStatus.COMPLETE,
|
|
138
184
|
});
|
|
139
185
|
yield this.ctx.client.uploadEncryptedWalletPrivateKey(userId, encryptedPrivateKeyHex, encryptionKeyHash, resultJson.id);
|
|
140
186
|
});
|
|
@@ -48,4 +48,5 @@ export declare class ReactNativeUtils implements PlatformUtils {
|
|
|
48
48
|
walletId: string;
|
|
49
49
|
}>;
|
|
50
50
|
ed25519Sign(ctx: Ctx, userId: string, walletId: string, share: string, base64Bytes: string, _sessionCookie: string): Promise<SignatureRes>;
|
|
51
|
+
initializeWorker(_ctx: Ctx): Promise<void>;
|
|
51
52
|
}
|
package/dist/shim.d.ts
CHANGED
|
@@ -1 +1,130 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export function ensureParaCrypto(): {
|
|
2
|
+
baseCrypto: webcrypto.Crypto | {
|
|
3
|
+
getCiphers: () => string[];
|
|
4
|
+
getHashes: () => string[];
|
|
5
|
+
webcrypto: {
|
|
6
|
+
subtle: import("react-native-quick-crypto/lib/typescript/src/subtle").Subtle;
|
|
7
|
+
SubtleCrypto: typeof import("react-native-quick-crypto/lib/typescript/src/subtle").Subtle;
|
|
8
|
+
CryptoKey: typeof import("react-native-quick-crypto/lib/typescript/src/keys").CryptoKey;
|
|
9
|
+
};
|
|
10
|
+
randomFill<T extends import("react-native-quick-crypto/lib/typescript/src/Utils").ABV>(buffer: T, callback: (err: Error | null, buf: T) => void): void;
|
|
11
|
+
randomFill<T extends import("react-native-quick-crypto/lib/typescript/src/Utils").ABV>(buffer: T, offset: number, callback: (err: Error | null, buf: T) => void): void;
|
|
12
|
+
randomFill<T extends import("react-native-quick-crypto/lib/typescript/src/Utils").ABV>(buffer: T, offset: number, size: number, callback: (err: Error | null, buf: T) => void): void;
|
|
13
|
+
randomFillSync<T extends import("react-native-quick-crypto/lib/typescript/src/Utils").ABV>(buffer: T, offset?: number, size?: number): T;
|
|
14
|
+
randomBytes(size: number): Buffer;
|
|
15
|
+
randomBytes(size: number, callback: (err: Error | null, buf?: Buffer) => void): void;
|
|
16
|
+
randomInt(max: number, callback: (err: Error | null, value: number) => void): void;
|
|
17
|
+
randomInt(max: number): number;
|
|
18
|
+
randomInt(min: number, max: number, callback: (err: Error | null, value: number) => void): void;
|
|
19
|
+
randomInt(min: number, max: number): number;
|
|
20
|
+
getRandomValues(data: import("react-native-quick-crypto/lib/typescript/src/random").RandomTypedArrays): import("react-native-quick-crypto/lib/typescript/src/random").RandomTypedArrays;
|
|
21
|
+
randomUUID(): string;
|
|
22
|
+
rng: typeof import("react-native-quick-crypto/lib/typescript/src/random").randomBytes;
|
|
23
|
+
pseudoRandomBytes: typeof import("react-native-quick-crypto/lib/typescript/src/random").randomBytes;
|
|
24
|
+
prng: typeof import("react-native-quick-crypto/lib/typescript/src/random").randomBytes;
|
|
25
|
+
pbkdf2(password: import("react-native-quick-crypto/lib/typescript/src/Utils").BinaryLike, salt: import("react-native-quick-crypto/lib/typescript/src/Utils").BinaryLike, iterations: number, keylen: number, digest: string, callback: (err: Error | null, derivedKey?: Buffer) => void): void;
|
|
26
|
+
pbkdf2Sync(password: import("react-native-quick-crypto/lib/typescript/src/Utils").BinaryLike, salt: import("react-native-quick-crypto/lib/typescript/src/Utils").BinaryLike, iterations: number, keylen: number, digest?: string): ArrayBuffer;
|
|
27
|
+
pbkdf2DeriveBits(algorithm: import("react-native-quick-crypto/lib/typescript/src/keys").SubtleAlgorithm, baseKey: import("react-native-quick-crypto/lib/typescript/src/keys").CryptoKey, length: number): Promise<ArrayBuffer>;
|
|
28
|
+
createHmac: typeof import("react-native-quick-crypto/lib/typescript/src/Hmac").createHmac;
|
|
29
|
+
Hmac: typeof import("react-native-quick-crypto/lib/typescript/src/Hmac").createHmac;
|
|
30
|
+
Hash: typeof import("react-native-quick-crypto/lib/typescript/src/Hash").createHash;
|
|
31
|
+
createHash: typeof import("react-native-quick-crypto/lib/typescript/src/Hash").createHash;
|
|
32
|
+
createCipher: typeof import("react-native-quick-crypto/lib/typescript/src/Cipher").createCipher;
|
|
33
|
+
createCipheriv: typeof import("react-native-quick-crypto/lib/typescript/src/Cipher").createCipheriv;
|
|
34
|
+
createDecipher: typeof import("react-native-quick-crypto/lib/typescript/src/Cipher").createDecipher;
|
|
35
|
+
createDecipheriv: typeof import("react-native-quick-crypto/lib/typescript/src/Cipher").createDecipheriv;
|
|
36
|
+
createPublicKey: typeof import("react-native-quick-crypto/lib/typescript/src/keys").createPublicKey;
|
|
37
|
+
createPrivateKey: (key: import("react-native-quick-crypto/lib/typescript/src/Utils").BinaryLike | import("react-native-quick-crypto/lib/typescript/src/keys").EncodingOptions) => import("react-native-quick-crypto/lib/typescript/src/keys").PrivateKeyObject;
|
|
38
|
+
createSecretKey: typeof import("react-native-quick-crypto/lib/typescript/src/keys").createSecretKey;
|
|
39
|
+
publicEncrypt: (options: import("react-native-quick-crypto/lib/typescript/src/keys").EncodingOptions | import("react-native-quick-crypto/lib/typescript/src/Utils").BinaryLike, buffer: import("react-native-quick-crypto/lib/typescript/src/Utils").BinaryLike) => Buffer;
|
|
40
|
+
publicDecrypt: (options: import("react-native-quick-crypto/lib/typescript/src/keys").EncodingOptions | import("react-native-quick-crypto/lib/typescript/src/Utils").BinaryLike, buffer: import("react-native-quick-crypto/lib/typescript/src/Utils").BinaryLike) => Buffer;
|
|
41
|
+
privateDecrypt: (options: import("react-native-quick-crypto/lib/typescript/src/keys").EncodingOptions | import("react-native-quick-crypto/lib/typescript/src/Utils").BinaryLike, buffer: import("react-native-quick-crypto/lib/typescript/src/Utils").BinaryLike) => Buffer;
|
|
42
|
+
generateKey: (type: import("react-native-quick-crypto/lib/typescript/src/keys").SecretKeyType, options: import("react-native-quick-crypto/lib/typescript/src/keys").AesKeyGenParams, callback: import("react-native-quick-crypto/lib/typescript/src/keygen").KeyGenCallback) => void;
|
|
43
|
+
generateKeyPair: (type: import("react-native-quick-crypto/lib/typescript/src/keys").KeyPairType, options: import("react-native-quick-crypto/lib/typescript/src/Cipher").GenerateKeyPairOptions, callback: import("react-native-quick-crypto/lib/typescript/src/Cipher").GenerateKeyPairCallback) => void;
|
|
44
|
+
generateKeyPairSync: typeof import("react-native-quick-crypto/lib/typescript/src/Cipher").generateKeyPairSync;
|
|
45
|
+
generateKeySync: (type: import("react-native-quick-crypto/lib/typescript/src/keys").SecretKeyType, options: import("react-native-quick-crypto/lib/typescript/src/keys").AesKeyGenParams) => import("react-native-quick-crypto/lib/typescript/src/keys").SecretKeyObject;
|
|
46
|
+
createSign: typeof import("react-native-quick-crypto/lib/typescript/src/sig").createSign;
|
|
47
|
+
createVerify: typeof import("react-native-quick-crypto/lib/typescript/src/sig").createVerify;
|
|
48
|
+
subtle: import("react-native-quick-crypto/lib/typescript/src/subtle").Subtle;
|
|
49
|
+
constants: {
|
|
50
|
+
OPENSSL_VERSION_NUMBER: number;
|
|
51
|
+
SSL_OP_ALL: number;
|
|
52
|
+
SSL_OP_ALLOW_NO_DHE_KEX: number;
|
|
53
|
+
SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: number;
|
|
54
|
+
SSL_OP_CIPHER_SERVER_PREFERENCE: number;
|
|
55
|
+
SSL_OP_CISCO_ANYCONNECT: number;
|
|
56
|
+
SSL_OP_COOKIE_EXCHANGE: number;
|
|
57
|
+
SSL_OP_CRYPTOPRO_TLSEXT_BUG: number;
|
|
58
|
+
SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: number;
|
|
59
|
+
SSL_OP_EPHEMERAL_RSA: number;
|
|
60
|
+
SSL_OP_LEGACY_SERVER_CONNECT: number;
|
|
61
|
+
SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: number;
|
|
62
|
+
SSL_OP_MICROSOFT_SESS_ID_BUG: number;
|
|
63
|
+
SSL_OP_MSIE_SSLV2_RSA_PADDING: number;
|
|
64
|
+
SSL_OP_NETSCAPE_CA_DN_BUG: number;
|
|
65
|
+
SSL_OP_NETSCAPE_CHALLENGE_BUG: number;
|
|
66
|
+
SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG: number;
|
|
67
|
+
SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: number;
|
|
68
|
+
SSL_OP_NO_COMPRESSION: number;
|
|
69
|
+
SSL_OP_NO_ENCRYPT_THEN_MAC: number;
|
|
70
|
+
SSL_OP_NO_QUERY_MTU: number;
|
|
71
|
+
SSL_OP_NO_RENEGOTIATION: number;
|
|
72
|
+
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION: number;
|
|
73
|
+
SSL_OP_NO_SSLv2: number;
|
|
74
|
+
SSL_OP_NO_SSLv3: number;
|
|
75
|
+
SSL_OP_NO_TICKET: number;
|
|
76
|
+
SSL_OP_NO_TLSv1: number;
|
|
77
|
+
SSL_OP_NO_TLSv1_1: number;
|
|
78
|
+
SSL_OP_NO_TLSv1_2: number;
|
|
79
|
+
SSL_OP_NO_TLSv1_3: number;
|
|
80
|
+
SSL_OP_PKCS1_CHECK_1: number;
|
|
81
|
+
SSL_OP_PKCS1_CHECK_2: number;
|
|
82
|
+
SSL_OP_PRIORITIZE_CHACHA: number;
|
|
83
|
+
SSL_OP_SINGLE_DH_USE: number;
|
|
84
|
+
SSL_OP_SINGLE_ECDH_USE: number;
|
|
85
|
+
SSL_OP_SSLEAY_080_CLIENT_DH_BUG: number;
|
|
86
|
+
SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG: number;
|
|
87
|
+
SSL_OP_TLS_BLOCK_PADDING_BUG: number;
|
|
88
|
+
SSL_OP_TLS_D5_BUG: number;
|
|
89
|
+
SSL_OP_TLS_ROLLBACK_BUG: number;
|
|
90
|
+
ENGINE_METHOD_RSA: number;
|
|
91
|
+
ENGINE_METHOD_DSA: number;
|
|
92
|
+
ENGINE_METHOD_DH: number;
|
|
93
|
+
ENGINE_METHOD_RAND: number;
|
|
94
|
+
ENGINE_METHOD_EC: number;
|
|
95
|
+
ENGINE_METHOD_CIPHERS: number;
|
|
96
|
+
ENGINE_METHOD_DIGESTS: number;
|
|
97
|
+
ENGINE_METHOD_PKEY_METHS: number;
|
|
98
|
+
ENGINE_METHOD_PKEY_ASN1_METHS: number;
|
|
99
|
+
ENGINE_METHOD_ALL: number;
|
|
100
|
+
ENGINE_METHOD_NONE: number;
|
|
101
|
+
DH_CHECK_P_NOT_SAFE_PRIME: number;
|
|
102
|
+
DH_CHECK_P_NOT_PRIME: number;
|
|
103
|
+
DH_UNABLE_TO_CHECK_GENERATOR: number;
|
|
104
|
+
DH_NOT_SUITABLE_GENERATOR: number;
|
|
105
|
+
ALPN_ENABLED: number;
|
|
106
|
+
RSA_PKCS1_PADDING: number;
|
|
107
|
+
RSA_SSLV23_PADDING: number;
|
|
108
|
+
RSA_NO_PADDING: number;
|
|
109
|
+
RSA_PKCS1_OAEP_PADDING: number;
|
|
110
|
+
RSA_X931_PADDING: number;
|
|
111
|
+
RSA_PKCS1_PSS_PADDING: number;
|
|
112
|
+
RSA_PSS_SALTLEN_DIGEST: number;
|
|
113
|
+
RSA_PSS_SALTLEN_MAX_SIGN: number;
|
|
114
|
+
RSA_PSS_SALTLEN_AUTO: number;
|
|
115
|
+
defaultCoreCipherList: string;
|
|
116
|
+
TLS1_VERSION: number;
|
|
117
|
+
TLS1_1_VERSION: number;
|
|
118
|
+
TLS1_2_VERSION: number;
|
|
119
|
+
TLS1_3_VERSION: number;
|
|
120
|
+
POINT_CONVERSION_COMPRESSED: number;
|
|
121
|
+
POINT_CONVERSION_UNCOMPRESSED: number;
|
|
122
|
+
POINT_CONVERSION_HYBRID: number;
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
peculiarCrypto: PeculiarCrypto;
|
|
126
|
+
};
|
|
127
|
+
export function ensureCreateECDH(): any;
|
|
128
|
+
import { webcrypto } from 'crypto';
|
|
129
|
+
import { Buffer } from '@craftzdog/react-native-buffer';
|
|
130
|
+
import { Crypto as PeculiarCrypto } from '@peculiar/webcrypto';
|
package/dist/shim.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import quickCrypto from 'react-native-quick-crypto';
|
|
2
2
|
import { webcrypto } from 'crypto';
|
|
3
|
-
import { Crypto } from '@peculiar/webcrypto';
|
|
3
|
+
import { Crypto as PeculiarCrypto } from '@peculiar/webcrypto';
|
|
4
|
+
import { ec as EllipticEC } from 'elliptic';
|
|
4
5
|
import Forge from 'node-forge';
|
|
5
6
|
import modPow from 'react-native-modpow';
|
|
6
7
|
import { atob, btoa } from 'react-native-quick-base64';
|
|
@@ -33,16 +34,191 @@ const setupBase64Polyfills = () => {
|
|
|
33
34
|
throw new Error('Base64 polyfills failed to initialize');
|
|
34
35
|
}
|
|
35
36
|
};
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
const curveAliases = {
|
|
38
|
+
'P-256': 'p256',
|
|
39
|
+
'p-256': 'p256',
|
|
40
|
+
'prime256v1': 'p256',
|
|
41
|
+
'secp256r1': 'p256',
|
|
42
|
+
'secp256k1': 'secp256k1',
|
|
43
|
+
};
|
|
44
|
+
const getBufferImpl = () => {
|
|
45
|
+
const BufferImpl = globalThis.Buffer;
|
|
46
|
+
if (!BufferImpl) {
|
|
47
|
+
// prettier-ignore
|
|
48
|
+
throw new Error("[Para React Native shim] Buffer global missing. Please import '@getpara/react-native-wallet/shim' before using cryptography helpers.");
|
|
49
|
+
}
|
|
50
|
+
return BufferImpl;
|
|
51
|
+
};
|
|
52
|
+
const bufferFrom = (data, encoding = 'binary') => {
|
|
53
|
+
const BufferImpl = getBufferImpl();
|
|
54
|
+
if (BufferImpl.isBuffer && BufferImpl.isBuffer(data)) {
|
|
55
|
+
return data;
|
|
56
|
+
}
|
|
57
|
+
if (typeof data === 'string') {
|
|
58
|
+
switch (encoding) {
|
|
59
|
+
case 'hex':
|
|
60
|
+
return BufferImpl.from(data, 'hex');
|
|
61
|
+
case 'base64':
|
|
62
|
+
return BufferImpl.from(data, 'base64');
|
|
63
|
+
default:
|
|
64
|
+
return BufferImpl.from(data, 'binary');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return BufferImpl.from(data);
|
|
68
|
+
};
|
|
69
|
+
const bufferTo = (buf, encoding = 'binary') => {
|
|
70
|
+
const BufferImpl = getBufferImpl();
|
|
71
|
+
switch (encoding) {
|
|
72
|
+
case 'hex':
|
|
73
|
+
return BufferImpl.from(buf).toString('hex');
|
|
74
|
+
case 'base64':
|
|
75
|
+
return BufferImpl.from(buf).toString('base64');
|
|
76
|
+
case 'binary':
|
|
77
|
+
default:
|
|
78
|
+
return BufferImpl.from(buf);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
let cachedCreateECDH = null;
|
|
82
|
+
const ensureCreateECDH = () => {
|
|
83
|
+
if (!cachedCreateECDH) {
|
|
84
|
+
cachedCreateECDH = curveName => {
|
|
85
|
+
const BufferImpl = getBufferImpl();
|
|
86
|
+
const normalizedCurve = curveAliases[curveName] || curveName;
|
|
87
|
+
if (!normalizedCurve && typeof __DEV__ !== 'undefined' && __DEV__) {
|
|
88
|
+
console.warn('[Para React Native shim] Unknown curve alias', curveName);
|
|
89
|
+
}
|
|
90
|
+
const ec = new EllipticEC(normalizedCurve);
|
|
91
|
+
const secretByteLength = (() => {
|
|
92
|
+
const order = (ec && ec.curve && ec.curve.n) || (ec && ec.n);
|
|
93
|
+
if (!order) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
if (typeof order.byteLength === 'function') {
|
|
97
|
+
return order.byteLength();
|
|
98
|
+
}
|
|
99
|
+
if (typeof order.bitLength === 'function') {
|
|
100
|
+
return Math.ceil(order.bitLength() / 8);
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
})();
|
|
104
|
+
let keyPair = ec.genKeyPair();
|
|
105
|
+
return {
|
|
106
|
+
generateKeys: (encoding = 'binary', format = 'uncompressed') => {
|
|
107
|
+
keyPair = ec.genKeyPair();
|
|
108
|
+
const compressed = format === 'compressed' || format === 'comp';
|
|
109
|
+
const publicKey = keyPair.getPublic(compressed, 'array');
|
|
110
|
+
return bufferTo(BufferImpl.from(publicKey), encoding || 'binary');
|
|
111
|
+
},
|
|
112
|
+
computeSecret: (publicKey, inputEncoding = 'binary', outputEncoding = 'binary') => {
|
|
113
|
+
const publicKeyBuf = bufferFrom(publicKey, inputEncoding || 'binary');
|
|
114
|
+
const derived = keyPair.derive(ec.keyFromPublic(publicKeyBuf).getPublic());
|
|
115
|
+
const padded = secretByteLength ? derived.toArray('be', secretByteLength) : derived.toArray('be');
|
|
116
|
+
// Match Node's ECDH API: shared secret is always curve-size bytes.
|
|
117
|
+
const secret = BufferImpl.from(padded);
|
|
118
|
+
return bufferTo(secret, outputEncoding || 'binary');
|
|
119
|
+
},
|
|
120
|
+
getPrivateKey: (encoding = 'binary') => {
|
|
121
|
+
return bufferTo(keyPair.getPrivate().toArrayLike(BufferImpl, 'be', 32), encoding || 'binary');
|
|
122
|
+
},
|
|
123
|
+
getPublicKey: (encoding = 'binary', format = 'uncompressed') => {
|
|
124
|
+
const compressed = format === 'compressed' || format === 'comp';
|
|
125
|
+
const publicKey = keyPair.getPublic(compressed, 'array');
|
|
126
|
+
return bufferTo(BufferImpl.from(publicKey), encoding || 'binary');
|
|
127
|
+
},
|
|
128
|
+
setPrivateKey: (privateKey, encoding = 'binary') => {
|
|
129
|
+
keyPair = ec.keyFromPrivate(bufferFrom(privateKey, encoding));
|
|
130
|
+
},
|
|
131
|
+
setPublicKey: (publicKey, encoding = 'binary') => {
|
|
132
|
+
keyPair = ec.keyFromPublic(bufferFrom(publicKey, encoding));
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
const possibleTargets = [];
|
|
138
|
+
const globalCrypto = globalThis.crypto;
|
|
139
|
+
if (globalCrypto) {
|
|
140
|
+
possibleTargets.push(globalCrypto, globalCrypto.default);
|
|
141
|
+
}
|
|
142
|
+
possibleTargets.push(quickCrypto, quickCrypto && quickCrypto.default);
|
|
143
|
+
try {
|
|
144
|
+
const nodeCrypto = require('crypto');
|
|
145
|
+
possibleTargets.push(nodeCrypto, nodeCrypto && nodeCrypto.default);
|
|
146
|
+
// eslint-disable-next-line no-unused-vars
|
|
147
|
+
}
|
|
148
|
+
catch (_err) {
|
|
149
|
+
// The Node crypto module is not available in React Native; ignore failures.
|
|
40
150
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
151
|
+
const patchedTargets = new Set(possibleTargets.filter(Boolean));
|
|
152
|
+
let patched = false;
|
|
153
|
+
patchedTargets.forEach(target => {
|
|
154
|
+
if (target && typeof target === 'object' && target.createECDH !== cachedCreateECDH) {
|
|
155
|
+
try {
|
|
156
|
+
target.createECDH = cachedCreateECDH;
|
|
157
|
+
patched = true;
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
if (typeof __DEV__ !== 'undefined' && __DEV__) {
|
|
161
|
+
console.warn('[Para React Native shim] Failed to patch createECDH', err);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
if (patched && typeof __DEV__ !== 'undefined' && __DEV__) {
|
|
167
|
+
console.info('[Para React Native shim] createECDH patched function');
|
|
168
|
+
}
|
|
169
|
+
return cachedCreateECDH;
|
|
170
|
+
};
|
|
171
|
+
const syncWindowLikeGlobals = cryptoObj => {
|
|
172
|
+
const maybeWindow = globalThis.window;
|
|
173
|
+
if (maybeWindow && typeof maybeWindow === 'object' && maybeWindow.crypto !== cryptoObj) {
|
|
174
|
+
maybeWindow.crypto = cryptoObj;
|
|
175
|
+
}
|
|
176
|
+
const maybeSelf = globalThis.self;
|
|
177
|
+
if (maybeSelf && typeof maybeSelf === 'object' && maybeSelf.crypto !== cryptoObj) {
|
|
178
|
+
maybeSelf.crypto = cryptoObj;
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
const ensureParaCrypto = () => {
|
|
182
|
+
getBufferImpl();
|
|
183
|
+
const baseCrypto = (typeof globalThis.crypto === 'object' && globalThis.crypto) || quickCrypto;
|
|
184
|
+
if (!baseCrypto || typeof baseCrypto !== 'object') {
|
|
185
|
+
throw new Error('[Para React Native shim] No crypto object found to polyfill');
|
|
186
|
+
}
|
|
187
|
+
if (typeof baseCrypto.default === 'undefined') {
|
|
188
|
+
baseCrypto.default = baseCrypto;
|
|
189
|
+
}
|
|
190
|
+
const peculiarCrypto = new PeculiarCrypto();
|
|
191
|
+
baseCrypto.subtle = peculiarCrypto.subtle;
|
|
192
|
+
baseCrypto.getRandomValues = peculiarCrypto.getRandomValues.bind(peculiarCrypto);
|
|
193
|
+
if (baseCrypto.default && baseCrypto.default !== baseCrypto) {
|
|
194
|
+
baseCrypto.default.subtle = baseCrypto.subtle;
|
|
195
|
+
baseCrypto.default.getRandomValues = baseCrypto.getRandomValues;
|
|
196
|
+
}
|
|
197
|
+
globalThis.crypto = baseCrypto;
|
|
198
|
+
syncWindowLikeGlobals(baseCrypto);
|
|
199
|
+
try {
|
|
200
|
+
const brorand = require('brorand');
|
|
201
|
+
if (brorand && brorand.Rand) {
|
|
202
|
+
brorand.Rand.prototype._rand = function _rand(n) {
|
|
203
|
+
const arr = new Uint8Array(n);
|
|
204
|
+
baseCrypto.getRandomValues(arr);
|
|
205
|
+
return arr;
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
if (typeof __DEV__ !== 'undefined' && __DEV__) {
|
|
211
|
+
console.warn('[Para React Native shim] Failed to patch brorand RNG', err);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
ensureCreateECDH();
|
|
215
|
+
return { baseCrypto, peculiarCrypto };
|
|
216
|
+
};
|
|
217
|
+
const setupCryptoPolyfills = () => {
|
|
218
|
+
const { peculiarCrypto } = ensureParaCrypto();
|
|
219
|
+
if (webcrypto && typeof webcrypto === 'object') {
|
|
220
|
+
webcrypto.getRandomValues = peculiarCrypto.getRandomValues.bind(peculiarCrypto);
|
|
44
221
|
}
|
|
45
|
-
webcrypto.getRandomValues = peculiarCrypto.getRandomValues.bind(peculiarCrypto);
|
|
46
222
|
if (typeof Forge === 'undefined') {
|
|
47
223
|
throw new Error('node-forge not loaded');
|
|
48
224
|
}
|
|
@@ -73,3 +249,4 @@ setupBase64Polyfills();
|
|
|
73
249
|
setupCryptoPolyfills();
|
|
74
250
|
setupTextEncodingPolyfills();
|
|
75
251
|
setupStructuredClonePolyfill();
|
|
252
|
+
export { ensureParaCrypto, ensureCreateECDH };
|
package/package.json
CHANGED
|
@@ -1,32 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getpara/react-native-wallet",
|
|
3
|
-
"version": "2.0.0-alpha.6",
|
|
4
3
|
"description": "Para Wallet for React Native",
|
|
5
|
-
"
|
|
4
|
+
"version": "2.0.0-alpha.60",
|
|
6
5
|
"author": "Para Team <hello@getpara.com> (https://getpara.com)",
|
|
7
|
-
"main": "dist/index.js",
|
|
8
|
-
"module": "dist/index.js",
|
|
9
|
-
"types": "dist/index.d.ts",
|
|
10
|
-
"files": [
|
|
11
|
-
"dist",
|
|
12
|
-
"src",
|
|
13
|
-
"ios",
|
|
14
|
-
"android",
|
|
15
|
-
"cpp",
|
|
16
|
-
"*.podspec",
|
|
17
|
-
"signer.xcframework",
|
|
18
|
-
"signer.aar"
|
|
19
|
-
],
|
|
20
|
-
"scripts": {
|
|
21
|
-
"build": "rm -rf dist && tsc",
|
|
22
|
-
"compile-signer": "bash ./scripts/compileSigner.sh"
|
|
23
|
-
},
|
|
24
6
|
"dependencies": {
|
|
25
|
-
"@getpara/core-sdk": "2.0.0-alpha.
|
|
26
|
-
"@getpara/user-management-client": "2.0.0-alpha.
|
|
27
|
-
"@getpara/web-sdk": "2.0.0-alpha.
|
|
7
|
+
"@getpara/core-sdk": "2.0.0-alpha.60",
|
|
8
|
+
"@getpara/user-management-client": "2.0.0-alpha.60",
|
|
9
|
+
"@getpara/web-sdk": "2.0.0-alpha.60",
|
|
28
10
|
"@peculiar/webcrypto": "^1.5.0",
|
|
29
|
-
"@
|
|
11
|
+
"@ungap/structured-clone": "1.3.0",
|
|
30
12
|
"node-forge": "1.3.1",
|
|
31
13
|
"react-native-url-polyfill": "2.0.0",
|
|
32
14
|
"text-encoding": "0.7.0"
|
|
@@ -43,8 +25,32 @@
|
|
|
43
25
|
"react-native-passkey": "3.1.0",
|
|
44
26
|
"react-native-quick-base64": "2.1.2",
|
|
45
27
|
"react-native-quick-crypto": "0.7.12",
|
|
46
|
-
"typescript": "^5.
|
|
28
|
+
"typescript": "^5.8.3"
|
|
47
29
|
},
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"default": "./dist/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./shim": {
|
|
35
|
+
"default": "./dist/shim.js"
|
|
36
|
+
},
|
|
37
|
+
"./dist/shim.js": {
|
|
38
|
+
"default": "./dist/shim.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"dist",
|
|
43
|
+
"src",
|
|
44
|
+
"ios",
|
|
45
|
+
"android",
|
|
46
|
+
"cpp",
|
|
47
|
+
"*.podspec",
|
|
48
|
+
"signer.xcframework",
|
|
49
|
+
"signer.aar"
|
|
50
|
+
],
|
|
51
|
+
"homepage": "https://getpara.com",
|
|
52
|
+
"main": "./dist/index.js",
|
|
53
|
+
"module": "./dist/index.js",
|
|
48
54
|
"peerDependencies": {
|
|
49
55
|
"@craftzdog/react-native-buffer": "*",
|
|
50
56
|
"@react-native-async-storage/async-storage": "*",
|
|
@@ -60,5 +66,32 @@
|
|
|
60
66
|
"publishConfig": {
|
|
61
67
|
"access": "public"
|
|
62
68
|
},
|
|
63
|
-
"
|
|
69
|
+
"react-native": {
|
|
70
|
+
".": "./dist/index.js",
|
|
71
|
+
"./shim": "./dist/shim.js",
|
|
72
|
+
"./dist/shim.js": "./dist/shim.js"
|
|
73
|
+
},
|
|
74
|
+
"scripts": {
|
|
75
|
+
"build": "rm -rf dist && tsc",
|
|
76
|
+
"compile-signer": "bash ./scripts/compileSigner.sh",
|
|
77
|
+
"test": "vitest run --coverage"
|
|
78
|
+
},
|
|
79
|
+
"sideEffects": [
|
|
80
|
+
"./dist/shim.js"
|
|
81
|
+
],
|
|
82
|
+
"types": "./dist/index.d.ts",
|
|
83
|
+
"typesVersions": {
|
|
84
|
+
"*": {
|
|
85
|
+
"shim": [
|
|
86
|
+
"./dist/shim.d.ts"
|
|
87
|
+
],
|
|
88
|
+
"dist/shim.js": [
|
|
89
|
+
"./dist/shim.d.ts"
|
|
90
|
+
],
|
|
91
|
+
"*": [
|
|
92
|
+
"./dist/index.d.ts"
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"gitHead": "b445d9dcf909a9bfa72d4f21b825fcf7c643be0c"
|
|
64
97
|
}
|
package/src/config.ts
CHANGED
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
getSHA256HashHex,
|
|
14
14
|
parseCredentialCreationRes,
|
|
15
15
|
} from '@getpara/web-sdk';
|
|
16
|
-
import * as Sentry from '@sentry/react-native';
|
|
17
16
|
|
|
18
17
|
import { ReactNativeUtils } from './ReactNativeUtils.js';
|
|
19
18
|
import {
|
|
@@ -23,7 +22,7 @@ import {
|
|
|
23
22
|
PasskeyGetRequest,
|
|
24
23
|
PasskeyGetResult,
|
|
25
24
|
} from 'react-native-passkey';
|
|
26
|
-
import { CurrentWalletIds,
|
|
25
|
+
import { CurrentWalletIds, AuthMethodStatus, TWalletScheme } from '@getpara/user-management-client';
|
|
27
26
|
import { setEnv } from '../config.js';
|
|
28
27
|
import base64url from 'base64url';
|
|
29
28
|
import { webcrypto } from 'crypto';
|
|
@@ -44,23 +43,72 @@ export class ParaMobile extends ParaCore {
|
|
|
44
43
|
private relyingPartyId: string;
|
|
45
44
|
/**
|
|
46
45
|
* Creates an instance of ParaMobile.
|
|
47
|
-
* @param {Environment} env - The environment to use (DEV, SANDBOX, BETA, or PROD).
|
|
46
|
+
* @param {Environment} env - The environment to use (DEV, SANDBOX, BETA, or PROD). Optional if the apiKey contains an environment prefix (e.g., "prod_your_api_key"). Updated API keys can be found at https://developer.getpara.com.
|
|
48
47
|
* @param {string} [apiKey] - The API key for authentication.
|
|
49
48
|
* @param {string} [relyingPartyId] - The relying party ID for WebAuthn.
|
|
50
49
|
* @param {ConstructorOpts} [opts] - Additional constructor options.
|
|
51
50
|
*/
|
|
52
|
-
constructor(env: Environment, apiKey: string, relyingPartyId?: string, opts?: ConstructorOpts)
|
|
53
|
-
|
|
51
|
+
constructor(env: Environment | undefined, apiKey: string, relyingPartyId?: string, opts?: ConstructorOpts);
|
|
52
|
+
constructor(apiKey: string, relyingPartyId?: string, opts?: ConstructorOpts);
|
|
53
|
+
constructor(
|
|
54
|
+
envOrApiKey: Environment | undefined | string,
|
|
55
|
+
apiKeyOrRelyingPartyId?: string,
|
|
56
|
+
relyingPartyIdOrOpts?: string | ConstructorOpts,
|
|
57
|
+
optsArg?: ConstructorOpts,
|
|
58
|
+
) {
|
|
59
|
+
let env: Environment | undefined, apiKey: string, relyingPartyId: string | undefined, opts: ConstructorOpts | undefined;
|
|
60
|
+
|
|
61
|
+
// Helper function to check if value is a valid Environment
|
|
62
|
+
const isEnvironment = (value: any): value is Environment => {
|
|
63
|
+
return Object.values(Environment).includes(value);
|
|
64
|
+
};
|
|
54
65
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
66
|
+
if (arguments.length === 1) {
|
|
67
|
+
// 1-parameter case: (apiKey)
|
|
68
|
+
env = undefined;
|
|
69
|
+
apiKey = envOrApiKey as string;
|
|
70
|
+
relyingPartyId = undefined;
|
|
71
|
+
opts = undefined;
|
|
72
|
+
} else if (arguments.length === 2) {
|
|
73
|
+
if (isEnvironment(envOrApiKey)) {
|
|
74
|
+
// 2-parameter case: (env, apiKey)
|
|
75
|
+
env = envOrApiKey;
|
|
76
|
+
apiKey = apiKeyOrRelyingPartyId as string;
|
|
77
|
+
relyingPartyId = undefined;
|
|
78
|
+
opts = undefined;
|
|
79
|
+
} else {
|
|
80
|
+
// 2-parameter case: (apiKey, relyingPartyId)
|
|
81
|
+
env = undefined;
|
|
82
|
+
apiKey = envOrApiKey as string;
|
|
83
|
+
relyingPartyId = apiKeyOrRelyingPartyId;
|
|
84
|
+
opts = undefined;
|
|
85
|
+
}
|
|
86
|
+
} else if (arguments.length === 3) {
|
|
87
|
+
if (isEnvironment(envOrApiKey)) {
|
|
88
|
+
// 3-parameter case: (env, apiKey, relyingPartyId)
|
|
89
|
+
env = envOrApiKey;
|
|
90
|
+
apiKey = apiKeyOrRelyingPartyId as string;
|
|
91
|
+
relyingPartyId = relyingPartyIdOrOpts as string;
|
|
92
|
+
opts = undefined;
|
|
93
|
+
} else {
|
|
94
|
+
// 3-parameter case: (apiKey, relyingPartyId, opts)
|
|
95
|
+
env = undefined;
|
|
96
|
+
apiKey = envOrApiKey as string;
|
|
97
|
+
relyingPartyId = apiKeyOrRelyingPartyId;
|
|
98
|
+
opts = relyingPartyIdOrOpts as ConstructorOpts;
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
// 4-parameter case: (env, apiKey, relyingPartyId, opts)
|
|
102
|
+
env = envOrApiKey as Environment | undefined;
|
|
103
|
+
apiKey = apiKeyOrRelyingPartyId as string;
|
|
104
|
+
relyingPartyId = relyingPartyIdOrOpts as string | undefined;
|
|
105
|
+
opts = optsArg;
|
|
62
106
|
}
|
|
63
107
|
|
|
108
|
+
env = ParaCore.resolveEnvironment(env, apiKey); // Ensure the environment is resolved before calling super
|
|
109
|
+
|
|
110
|
+
super(env, apiKey, opts);
|
|
111
|
+
|
|
64
112
|
setEnv(env);
|
|
65
113
|
|
|
66
114
|
if (relyingPartyId) {
|
|
@@ -82,10 +130,18 @@ export class ParaMobile extends ParaCore {
|
|
|
82
130
|
}
|
|
83
131
|
}
|
|
84
132
|
|
|
133
|
+
async ready() {
|
|
134
|
+
this.isReady = true;
|
|
135
|
+
}
|
|
136
|
+
|
|
85
137
|
protected getPlatformUtils(): PlatformUtils {
|
|
86
138
|
return new ReactNativeUtils();
|
|
87
139
|
}
|
|
88
140
|
|
|
141
|
+
async isPasskeySupported(): Promise<boolean> {
|
|
142
|
+
return Passkey.isSupported();
|
|
143
|
+
}
|
|
144
|
+
|
|
89
145
|
/**
|
|
90
146
|
* Registers a passkey for the user.
|
|
91
147
|
* @param {Auth<'email'> | Auth<'phone'>} auth - The user's authentication details
|
|
@@ -161,7 +217,7 @@ export class ParaMobile extends ParaCore {
|
|
|
161
217
|
sigDerivedPublicKey: publicKeyHex,
|
|
162
218
|
cosePublicKey,
|
|
163
219
|
clientDataJSON,
|
|
164
|
-
status:
|
|
220
|
+
status: AuthMethodStatus.COMPLETE,
|
|
165
221
|
});
|
|
166
222
|
|
|
167
223
|
await this.ctx.client.uploadEncryptedWalletPrivateKey(userId, encryptedPrivateKeyHex, encryptionKeyHash, resultJson.id);
|
|
@@ -234,7 +290,7 @@ export class ParaMobile extends ParaCore {
|
|
|
234
290
|
decryptedShares = await decryptPrivateKeyAndDecryptShare(
|
|
235
291
|
resultJson.response.userHandle,
|
|
236
292
|
encryptedSharesResult.data.keyShares,
|
|
237
|
-
encryptedPrivateKeys[0]
|
|
293
|
+
encryptedPrivateKeys[0]!.encryptedPrivateKey,
|
|
238
294
|
);
|
|
239
295
|
}
|
|
240
296
|
|
|
@@ -262,4 +262,8 @@ export class ReactNativeUtils implements PlatformUtils {
|
|
|
262
262
|
const base64Sig = await ParaSignerModule.ed25519Sign(protocolId, share, base64Bytes);
|
|
263
263
|
return { signature: base64Sig };
|
|
264
264
|
}
|
|
265
|
+
|
|
266
|
+
async initializeWorker(_ctx: Ctx): Promise<void> {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
265
269
|
}
|
package/src/shim.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import quickCrypto from 'react-native-quick-crypto';
|
|
2
2
|
import { webcrypto } from 'crypto';
|
|
3
|
-
import { Crypto } from '@peculiar/webcrypto';
|
|
3
|
+
import { Crypto as PeculiarCrypto } from '@peculiar/webcrypto';
|
|
4
|
+
import { ec as EllipticEC } from 'elliptic';
|
|
4
5
|
import Forge from 'node-forge';
|
|
5
6
|
import modPow from 'react-native-modpow';
|
|
6
7
|
import { atob, btoa } from 'react-native-quick-base64';
|
|
@@ -37,16 +38,218 @@ const setupBase64Polyfills = () => {
|
|
|
37
38
|
}
|
|
38
39
|
};
|
|
39
40
|
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
const curveAliases = {
|
|
42
|
+
'P-256': 'p256',
|
|
43
|
+
'p-256': 'p256',
|
|
44
|
+
'prime256v1': 'p256',
|
|
45
|
+
'secp256r1': 'p256',
|
|
46
|
+
'secp256k1': 'secp256k1',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const getBufferImpl = () => {
|
|
50
|
+
const BufferImpl = globalThis.Buffer;
|
|
51
|
+
if (!BufferImpl) {
|
|
52
|
+
// prettier-ignore
|
|
53
|
+
throw new Error(
|
|
54
|
+
"[Para React Native shim] Buffer global missing. Please import '@getpara/react-native-wallet/shim' before using cryptography helpers."
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return BufferImpl;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const bufferFrom = (data, encoding = 'binary') => {
|
|
61
|
+
const BufferImpl = getBufferImpl();
|
|
62
|
+
if (BufferImpl.isBuffer && BufferImpl.isBuffer(data)) {
|
|
63
|
+
return data;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (typeof data === 'string') {
|
|
67
|
+
switch (encoding) {
|
|
68
|
+
case 'hex':
|
|
69
|
+
return BufferImpl.from(data, 'hex');
|
|
70
|
+
case 'base64':
|
|
71
|
+
return BufferImpl.from(data, 'base64');
|
|
72
|
+
default:
|
|
73
|
+
return BufferImpl.from(data, 'binary');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return BufferImpl.from(data);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const bufferTo = (buf, encoding = 'binary') => {
|
|
81
|
+
const BufferImpl = getBufferImpl();
|
|
82
|
+
switch (encoding) {
|
|
83
|
+
case 'hex':
|
|
84
|
+
return BufferImpl.from(buf).toString('hex');
|
|
85
|
+
case 'base64':
|
|
86
|
+
return BufferImpl.from(buf).toString('base64');
|
|
87
|
+
case 'binary':
|
|
88
|
+
default:
|
|
89
|
+
return BufferImpl.from(buf);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
let cachedCreateECDH = null;
|
|
94
|
+
|
|
95
|
+
const ensureCreateECDH = () => {
|
|
96
|
+
if (!cachedCreateECDH) {
|
|
97
|
+
cachedCreateECDH = curveName => {
|
|
98
|
+
const BufferImpl = getBufferImpl();
|
|
99
|
+
const normalizedCurve = curveAliases[curveName] || curveName;
|
|
100
|
+
if (!normalizedCurve && typeof __DEV__ !== 'undefined' && __DEV__) {
|
|
101
|
+
console.warn('[Para React Native shim] Unknown curve alias', curveName);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const ec = new EllipticEC(normalizedCurve);
|
|
105
|
+
const secretByteLength = (() => {
|
|
106
|
+
const order = (ec && ec.curve && ec.curve.n) || (ec && ec.n);
|
|
107
|
+
if (!order) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
if (typeof order.byteLength === 'function') {
|
|
111
|
+
return order.byteLength();
|
|
112
|
+
}
|
|
113
|
+
if (typeof order.bitLength === 'function') {
|
|
114
|
+
return Math.ceil(order.bitLength() / 8);
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
})();
|
|
118
|
+
let keyPair = ec.genKeyPair();
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
generateKeys: (encoding = 'binary', format = 'uncompressed') => {
|
|
122
|
+
keyPair = ec.genKeyPair();
|
|
123
|
+
const compressed = format === 'compressed' || format === 'comp';
|
|
124
|
+
const publicKey = keyPair.getPublic(compressed, 'array');
|
|
125
|
+
return bufferTo(BufferImpl.from(publicKey), encoding || 'binary');
|
|
126
|
+
},
|
|
127
|
+
computeSecret: (publicKey, inputEncoding = 'binary', outputEncoding = 'binary') => {
|
|
128
|
+
const publicKeyBuf = bufferFrom(publicKey, inputEncoding || 'binary');
|
|
129
|
+
const derived = keyPair.derive(ec.keyFromPublic(publicKeyBuf).getPublic());
|
|
130
|
+
const padded = secretByteLength ? derived.toArray('be', secretByteLength) : derived.toArray('be');
|
|
131
|
+
// Match Node's ECDH API: shared secret is always curve-size bytes.
|
|
132
|
+
const secret = BufferImpl.from(padded);
|
|
133
|
+
return bufferTo(secret, outputEncoding || 'binary');
|
|
134
|
+
},
|
|
135
|
+
getPrivateKey: (encoding = 'binary') => {
|
|
136
|
+
return bufferTo(keyPair.getPrivate().toArrayLike(BufferImpl, 'be', 32), encoding || 'binary');
|
|
137
|
+
},
|
|
138
|
+
getPublicKey: (encoding = 'binary', format = 'uncompressed') => {
|
|
139
|
+
const compressed = format === 'compressed' || format === 'comp';
|
|
140
|
+
const publicKey = keyPair.getPublic(compressed, 'array');
|
|
141
|
+
return bufferTo(BufferImpl.from(publicKey), encoding || 'binary');
|
|
142
|
+
},
|
|
143
|
+
setPrivateKey: (privateKey, encoding = 'binary') => {
|
|
144
|
+
keyPair = ec.keyFromPrivate(bufferFrom(privateKey, encoding));
|
|
145
|
+
},
|
|
146
|
+
setPublicKey: (publicKey, encoding = 'binary') => {
|
|
147
|
+
keyPair = ec.keyFromPublic(bufferFrom(publicKey, encoding));
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
};
|
|
44
151
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
152
|
+
|
|
153
|
+
const possibleTargets = [];
|
|
154
|
+
const globalCrypto = globalThis.crypto;
|
|
155
|
+
if (globalCrypto) {
|
|
156
|
+
possibleTargets.push(globalCrypto, globalCrypto.default);
|
|
48
157
|
}
|
|
49
|
-
|
|
158
|
+
possibleTargets.push(quickCrypto, quickCrypto && quickCrypto.default);
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
const nodeCrypto = require('crypto');
|
|
162
|
+
possibleTargets.push(nodeCrypto, nodeCrypto && nodeCrypto.default);
|
|
163
|
+
// eslint-disable-next-line no-unused-vars
|
|
164
|
+
} catch (_err) {
|
|
165
|
+
// The Node crypto module is not available in React Native; ignore failures.
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const patchedTargets = new Set(possibleTargets.filter(Boolean));
|
|
169
|
+
let patched = false;
|
|
170
|
+
|
|
171
|
+
patchedTargets.forEach(target => {
|
|
172
|
+
if (target && typeof target === 'object' && target.createECDH !== cachedCreateECDH) {
|
|
173
|
+
try {
|
|
174
|
+
target.createECDH = cachedCreateECDH;
|
|
175
|
+
patched = true;
|
|
176
|
+
} catch (err) {
|
|
177
|
+
if (typeof __DEV__ !== 'undefined' && __DEV__) {
|
|
178
|
+
console.warn('[Para React Native shim] Failed to patch createECDH', err);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
if (patched && typeof __DEV__ !== 'undefined' && __DEV__) {
|
|
185
|
+
console.info('[Para React Native shim] createECDH patched function');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return cachedCreateECDH;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const syncWindowLikeGlobals = cryptoObj => {
|
|
192
|
+
const maybeWindow = globalThis.window;
|
|
193
|
+
if (maybeWindow && typeof maybeWindow === 'object' && maybeWindow.crypto !== cryptoObj) {
|
|
194
|
+
maybeWindow.crypto = cryptoObj;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const maybeSelf = globalThis.self;
|
|
198
|
+
if (maybeSelf && typeof maybeSelf === 'object' && maybeSelf.crypto !== cryptoObj) {
|
|
199
|
+
maybeSelf.crypto = cryptoObj;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const ensureParaCrypto = () => {
|
|
204
|
+
getBufferImpl();
|
|
205
|
+
const baseCrypto = (typeof globalThis.crypto === 'object' && globalThis.crypto) || quickCrypto;
|
|
206
|
+
|
|
207
|
+
if (!baseCrypto || typeof baseCrypto !== 'object') {
|
|
208
|
+
throw new Error('[Para React Native shim] No crypto object found to polyfill');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (typeof baseCrypto.default === 'undefined') {
|
|
212
|
+
baseCrypto.default = baseCrypto;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const peculiarCrypto = new PeculiarCrypto();
|
|
216
|
+
|
|
217
|
+
baseCrypto.subtle = peculiarCrypto.subtle;
|
|
218
|
+
baseCrypto.getRandomValues = peculiarCrypto.getRandomValues.bind(peculiarCrypto);
|
|
219
|
+
|
|
220
|
+
if (baseCrypto.default && baseCrypto.default !== baseCrypto) {
|
|
221
|
+
baseCrypto.default.subtle = baseCrypto.subtle;
|
|
222
|
+
baseCrypto.default.getRandomValues = baseCrypto.getRandomValues;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
globalThis.crypto = baseCrypto;
|
|
226
|
+
syncWindowLikeGlobals(baseCrypto);
|
|
227
|
+
try {
|
|
228
|
+
const brorand = require('brorand');
|
|
229
|
+
if (brorand && brorand.Rand) {
|
|
230
|
+
brorand.Rand.prototype._rand = function _rand(n) {
|
|
231
|
+
const arr = new Uint8Array(n);
|
|
232
|
+
baseCrypto.getRandomValues(arr);
|
|
233
|
+
return arr;
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
} catch (err) {
|
|
237
|
+
if (typeof __DEV__ !== 'undefined' && __DEV__) {
|
|
238
|
+
console.warn('[Para React Native shim] Failed to patch brorand RNG', err);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
ensureCreateECDH();
|
|
242
|
+
|
|
243
|
+
return { baseCrypto, peculiarCrypto };
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const setupCryptoPolyfills = () => {
|
|
247
|
+
const { peculiarCrypto } = ensureParaCrypto();
|
|
248
|
+
|
|
249
|
+
if (webcrypto && typeof webcrypto === 'object') {
|
|
250
|
+
webcrypto.getRandomValues = peculiarCrypto.getRandomValues.bind(peculiarCrypto);
|
|
251
|
+
}
|
|
252
|
+
|
|
50
253
|
if (typeof Forge === 'undefined') {
|
|
51
254
|
throw new Error('node-forge not loaded');
|
|
52
255
|
}
|
|
@@ -80,3 +283,5 @@ setupBase64Polyfills();
|
|
|
80
283
|
setupCryptoPolyfills();
|
|
81
284
|
setupTextEncodingPolyfills();
|
|
82
285
|
setupStructuredClonePolyfill();
|
|
286
|
+
|
|
287
|
+
export { ensureParaCrypto, ensureCreateECDH };
|
|
File without changes
|