@functionland/react-native-fula 1.2.1 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,47 +1,60 @@
1
- package land.fx.fula;
2
-
3
- import android.util.Base64;
4
-
5
- import java.io.UnsupportedEncodingException;
6
- import java.security.InvalidAlgorithmParameterException;
7
- import java.security.InvalidKeyException;
8
- import java.security.NoSuchAlgorithmException;
9
- import java.security.spec.InvalidKeySpecException;
10
- import java.security.spec.InvalidParameterSpecException;
11
-
12
- import javax.crypto.BadPaddingException;
13
- import javax.crypto.Cipher;
14
- import javax.crypto.IllegalBlockSizeException;
15
- import javax.crypto.NoSuchPaddingException;
16
- import javax.crypto.SecretKey;
17
- import javax.crypto.SecretKeyFactory;
18
- import javax.crypto.spec.PBEKeySpec;
19
- import javax.crypto.spec.SecretKeySpec;
20
-
21
- public class Cryptography {
22
- public static String encryptMsg(String message, SecretKey secret)
23
- throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
24
- Cipher cipher = null;
25
- cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
26
- cipher.init(Cipher.ENCRYPT_MODE, secret);
27
- byte[] cipherText = cipher.doFinal(message.getBytes("UTF-8"));
28
- return Base64.encodeToString(cipherText, Base64.NO_WRAP);
29
- }
30
-
31
- public static String decryptMsg(String cipherText, SecretKey secret)
32
- throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidParameterSpecException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
33
- Cipher cipher = null;
34
- cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
35
- cipher.init(Cipher.DECRYPT_MODE, secret);
36
- byte[] decode = Base64.decode(cipherText, Base64.NO_WRAP);
37
- String decryptString = new String(cipher.doFinal(decode), "UTF-8");
38
- return decryptString;
39
- }
40
-
41
- public static SecretKey generateKey(byte[] key)
42
- throws NoSuchAlgorithmException, InvalidKeySpecException {
43
- PBEKeySpec pbeKeySpec = new PBEKeySpec(StaticHelper.bytesToBase64(key).toCharArray(), key, 1000, 128);
44
- SecretKey pbeKey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(pbeKeySpec);
45
- return new SecretKeySpec(pbeKey.getEncoded(), "AES");
46
- }
47
- }
1
+ package land.fx.fula;
2
+
3
+ import android.util.Base64;
4
+
5
+ import java.io.UnsupportedEncodingException;
6
+ import java.nio.charset.StandardCharsets;
7
+ import java.security.InvalidAlgorithmParameterException;
8
+ import java.security.InvalidKeyException;
9
+ import java.security.NoSuchAlgorithmException;
10
+ import java.security.spec.InvalidKeySpecException;
11
+ import java.security.SecureRandom;
12
+ import java.nio.ByteBuffer;
13
+ import java.security.spec.InvalidParameterSpecException;
14
+
15
+ import javax.crypto.BadPaddingException;
16
+ import javax.crypto.Cipher;
17
+ import javax.crypto.IllegalBlockSizeException;
18
+ import javax.crypto.NoSuchPaddingException;
19
+ import javax.crypto.SecretKey;
20
+ import javax.crypto.SecretKeyFactory;
21
+ import javax.crypto.spec.PBEKeySpec;
22
+ import javax.crypto.spec.SecretKeySpec;
23
+ import javax.crypto.spec.GCMParameterSpec;
24
+
25
+ public class Cryptography {
26
+ public static String encryptMsg(String message, SecretKey secret)
27
+ throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
28
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
29
+ byte[] iv = new byte[12]; // Ensure this is randomly generated for each encryption.
30
+ new SecureRandom().nextBytes(iv);
31
+ GCMParameterSpec spec = new GCMParameterSpec(128, iv);
32
+ cipher.init(Cipher.ENCRYPT_MODE, secret, spec);
33
+ byte[] cipherText = cipher.doFinal(message.getBytes(StandardCharsets.UTF_8));
34
+ ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + cipherText.length);
35
+ byteBuffer.put(iv);
36
+ byteBuffer.put(cipherText);
37
+ return Base64.encodeToString(byteBuffer.array(), Base64.NO_WRAP);
38
+ }
39
+
40
+ public static String decryptMsg(String cipherText, SecretKey secret)
41
+ throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
42
+ ByteBuffer byteBuffer = ByteBuffer.wrap(Base64.decode(cipherText, Base64.NO_WRAP));
43
+ byte[] iv = new byte[12];
44
+ byteBuffer.get(iv);
45
+ byte[] cipherBytes = new byte[byteBuffer.remaining()];
46
+ byteBuffer.get(cipherBytes);
47
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
48
+ GCMParameterSpec spec = new GCMParameterSpec(128, iv);
49
+ cipher.init(Cipher.DECRYPT_MODE, secret, spec);
50
+ String decryptString = new String(cipher.doFinal(cipherBytes), StandardCharsets.UTF_8);
51
+ return decryptString;
52
+ }
53
+
54
+ public static SecretKey generateKey(byte[] key)
55
+ throws NoSuchAlgorithmException, InvalidKeySpecException {
56
+ PBEKeySpec pbeKeySpec = new PBEKeySpec(StaticHelper.bytesToBase64(key).toCharArray(), key, 1000, 128);
57
+ SecretKey pbeKey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(pbeKeySpec);
58
+ return new SecretKeySpec(pbeKey.getEncoded(), "AES");
59
+ }
60
+ }
@@ -16,15 +16,25 @@ import org.apache.commons.io.FileUtils;
16
16
  import org.jetbrains.annotations.Contract;
17
17
 
18
18
  import java.io.File;
19
+ import java.io.IOException;
19
20
  import java.nio.charset.StandardCharsets;
21
+ import java.security.GeneralSecurityException;
22
+ import java.security.InvalidAlgorithmParameterException;
23
+ import java.security.InvalidKeyException;
24
+ import java.security.NoSuchAlgorithmException;
20
25
  import java.util.Arrays;
21
26
 
27
+ import javax.crypto.BadPaddingException;
28
+ import javax.crypto.IllegalBlockSizeException;
29
+ import javax.crypto.NoSuchPaddingException;
22
30
  import javax.crypto.SecretKey;
23
31
 
24
32
  import java.util.concurrent.Executors;
25
33
  import java.util.concurrent.ScheduledExecutorService;
26
34
  import java.util.concurrent.TimeUnit;
27
35
  import java.util.concurrent.atomic.AtomicBoolean;
36
+ import java.util.concurrent.Future;
37
+ import java.util.concurrent.TimeoutException;
28
38
 
29
39
  import org.json.JSONObject;
30
40
  import org.json.JSONArray;
@@ -263,42 +273,50 @@ public class FulaModule extends ReactContextBaseJavaModule {
263
273
 
264
274
  private boolean checkConnectionInternal(int timeout) throws Exception {
265
275
  try {
266
- Log.d("ReactNative", "checkConnectionInternal started");
267
- if (this.fula != null) {
276
+ Log.d("ReactNative", "checkConnectionInternal started");
277
+ if (this.fula != null) {
278
+ try {
279
+ Log.d("ReactNative", "connectToBlox started");
280
+
281
+ AtomicBoolean connectionStatus = new AtomicBoolean(false);
282
+ ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
283
+ Future<?> future = executor.submit(() -> {
268
284
  try {
269
- Log.d("ReactNative", "connectToBlox started");
270
-
271
- AtomicBoolean connectionStatus = new AtomicBoolean(false);
272
- ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
273
- executor.schedule(() -> {
274
- try {
275
- this.fula.connectToBlox();
276
- connectionStatus.set(true);
277
- Log.d("ReactNative", "checkConnectionInternal succeeded ");
278
- } catch (Exception e) {
279
- Log.d("ReactNative", "checkConnectionInternal failed with Error: " + e.getMessage());
280
- }
281
- }, 0, TimeUnit.SECONDS);
282
-
283
- executor.schedule(() -> {
284
- executor.shutdown();
285
- }, timeout, TimeUnit.SECONDS);
286
-
287
- executor.awaitTermination(timeout, TimeUnit.SECONDS);
288
- return connectionStatus.get();
285
+ this.fula.connectToBlox();
286
+ connectionStatus.set(true);
287
+ Log.d("ReactNative", "checkConnectionInternal succeeded ");
289
288
  } catch (Exception e) {
290
- Log.d("ReactNative", "checkConnectionInternal failed with Error: " + e.getMessage());
291
- return false;
289
+ Log.d("ReactNative", "checkConnectionInternal failed with Error: " + e.getMessage());
292
290
  }
293
- } else {
294
- Log.d("ReactNative", "checkConnectionInternal failed because fula is not initialized ");
291
+ });
292
+
293
+ try {
294
+ future.get(timeout, TimeUnit.SECONDS);
295
+ } catch (TimeoutException te) {
296
+ // If the timeout occurs, shut down the executor and return false
297
+ executor.shutdownNow();
295
298
  return false;
299
+ } finally {
300
+ // If the future task is done, we can shut down the executor
301
+ if (future.isDone()) {
302
+ executor.shutdown();
303
+ }
304
+ }
305
+
306
+ return connectionStatus.get();
307
+ } catch (Exception e) {
308
+ Log.d("ReactNative", "checkConnectionInternal failed with Error: " + e.getMessage());
309
+ return false;
296
310
  }
311
+ } else {
312
+ Log.d("ReactNative", "checkConnectionInternal failed because fula is not initialized ");
313
+ return false;
314
+ }
297
315
  } catch (Exception e) {
298
- Log.d("ReactNative", "checkConnectionInternal failed with Error: " + e.getMessage());
299
- throw (e);
316
+ Log.d("ReactNative", "checkConnectionInternal failed with Error: " + e.getMessage());
317
+ throw (e);
300
318
  }
301
- }
319
+ }
302
320
 
303
321
  @ReactMethod
304
322
  private void checkFailedActions(boolean retry, int timeout, Promise promise) throws Exception {
@@ -404,24 +422,32 @@ public class FulaModule extends ReactContextBaseJavaModule {
404
422
  }
405
423
 
406
424
  @NonNull
407
- private byte[] createPeerIdentity(byte[] privateKey) throws Exception {
425
+ private byte[] createPeerIdentity(byte[] privateKey) throws GeneralSecurityException, IOException {
408
426
  try {
409
427
  // 1: First: create public key from provided private key
410
428
  // 2: Should read the local keychain store (if it is key-value, key is public key above,
411
429
  // 3: if found, decrypt using the private key
412
430
  // 4: If not found or decryption not successful, generate an identity
413
431
  // 5: then encrypt and store in keychain
414
-
415
432
  String encryptedKey = sharedPref.getValue(PRIVATE_KEY_STORE_ID);
416
433
  SecretKey secretKey = Cryptography.generateKey(privateKey);
417
- if (encryptedKey == null) {
418
- byte[] autoGeneratedIdentity = Fulamobile.generateEd25519Key();
419
- encryptedKey = Cryptography.encryptMsg(StaticHelper.bytesToBase64(autoGeneratedIdentity), secretKey);
434
+
435
+ if (encryptedKey == null || !encryptedKey.startsWith("FULA_ENC_V2:")) {
436
+ byte[] autoGeneratedIdentity;
437
+ try {
438
+ autoGeneratedIdentity = Fulamobile.generateEd25519Key();
439
+ } catch (Exception e) {
440
+ Log.d("ReactNative", "Failed to generate key: " + e.getMessage());
441
+ throw new GeneralSecurityException("Failed to generate key", e);
442
+ }
443
+ encryptedKey = "FULA_ENC_V2:" + Cryptography.encryptMsg(StaticHelper.bytesToBase64(autoGeneratedIdentity), secretKey);
420
444
  sharedPref.add(PRIVATE_KEY_STORE_ID, encryptedKey);
421
445
  }
422
- return StaticHelper.base64ToBytes(Cryptography.decryptMsg(encryptedKey, secretKey));
423
446
 
424
- } catch (Exception e) {
447
+ String decryptedKey = Cryptography.decryptMsg(encryptedKey.replace("FULA_ENC_V2:", ""), secretKey);
448
+ return StaticHelper.base64ToBytes(decryptedKey);
449
+
450
+ } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
425
451
  Log.d("ReactNative", "createPeerIdentity failed with Error: " + e.getMessage());
426
452
  throw (e);
427
453
  }
@@ -502,7 +528,8 @@ public class FulaModule extends ReactContextBaseJavaModule {
502
528
  }
503
529
 
504
530
  @NonNull
505
- private byte[] newClientInternal(byte[] identity, String storePath, String bloxAddr, String exchange, boolean autoFlush, boolean useRelay, boolean refresh) throws Exception {
531
+ private byte[] newClientInternal(byte[] identity, String storePath, String bloxAddr, String exchange, boolean autoFlush, boolean useRelay, boolean refresh) throws GeneralSecurityException, IOException {
532
+ byte[] peerIdentity = null;
506
533
  try {
507
534
  fulaConfig = new Config();
508
535
  if (storePath == null || storePath.trim().isEmpty()) {
@@ -512,7 +539,7 @@ public class FulaModule extends ReactContextBaseJavaModule {
512
539
  }
513
540
  Log.d("ReactNative", "newClientInternal storePath is set: " + fulaConfig.getStorePath());
514
541
 
515
- byte[] peerIdentity = this.createPeerIdentity(identity);
542
+ peerIdentity = this.createPeerIdentity(identity);
516
543
  fulaConfig.setIdentity(peerIdentity);
517
544
  Log.d("ReactNative", "peerIdentity is set: " + toString(fulaConfig.getIdentity()));
518
545
  fulaConfig.setBloxAddr(bloxAddr);
@@ -525,19 +552,25 @@ public class FulaModule extends ReactContextBaseJavaModule {
525
552
  }
526
553
  if (this.fula == null || refresh) {
527
554
  Log.d("ReactNative", "Creating a new Fula instance");
528
- shutdownInternal();
529
- this.fula = Fulamobile.newClient(fulaConfig);
530
- }
531
- if (this.fula != null) {
532
- this.fula.flush();
555
+ try {
556
+ shutdownInternal();
557
+ this.fula = Fulamobile.newClient(fulaConfig);
558
+ if (this.fula != null) {
559
+ this.fula.flush();
560
+ }
561
+ } catch (Exception e) {
562
+ Log.d("ReactNative", "Failed to create new Fula instance: " + e.getMessage());
563
+ throw new IOException("Failed to create new Fula instance", e);
564
+ }
533
565
  }
534
- return peerIdentity;
535
- } catch (Exception e) {
566
+ } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
536
567
  Log.d("ReactNative", "newclientInternal failed with Error: " + e.getMessage());
537
568
  throw (e);
538
569
  }
570
+ return peerIdentity;
539
571
  }
540
572
 
573
+
541
574
  @NonNull
542
575
  private String[] initInternal(byte[] identity, String storePath, String bloxAddr, String exchange, boolean autoFlush, String rootCid, boolean useRelay, boolean refresh) throws Exception {
543
576
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@functionland/react-native-fula",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "This package is a bridge to use the Fula libp2p protocols in the react-native which is using wnfs",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -28,7 +28,7 @@
28
28
  "lint": "eslint \"**/*.{js,ts,tsx}\"",
29
29
  "prepare": "bob build",
30
30
  "release": "release-it",
31
- "example": "set NODE_OPTIONS=--openssl-legacy-provider && yarn --cwd example",
31
+ "example": "set NODE_OPTIONS='' && yarn --cwd example",
32
32
  "pods": "cd example && pod-install --quiet",
33
33
  "bootstrap": "yarn example && yarn && yarn pods"
34
34
  },