diff --git a/android/build.gradle b/android/build.gradle index 30fa071..722c3d7 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -62,7 +62,7 @@ repositories { dependencies { //noinspection GradleDynamicVersion implementation "com.facebook.react:react-native:+" // From node_modules - implementation 'com.github.functionland:fula-build-aar:1.2.1' // From jitpack.io + implementation 'com.github.functionland:fula-build-aar:1.9.0' // From jitpack.io implementation 'com.github.functionland:wnfs-build-aar:v1.4.1' // From jitpack.io implementation 'commons-io:commons-io:20030203.000550' // implementation files('mobile.aar') diff --git a/android/src/main/java/land/fx/fula/FulaModule.java b/android/src/main/java/land/fx/fula/FulaModule.java index e26d8e5..ecf11a7 100755 --- a/android/src/main/java/land/fx/fula/FulaModule.java +++ b/android/src/main/java/land/fx/fula/FulaModule.java @@ -67,7 +67,7 @@ public void initialize() { SharedPreferenceHelper sharedPref; SecretKey secretKeyGlobal; String identityEncryptedGlobal; - static String PRIVATE_KEY_STORE_ID = "PRIVATE_KEY"; + static String PRIVATE_KEY_STORE_PEERID = "PRIVATE_KEY"; public static class Client implements land.fx.wnfslib.Datastore { @@ -133,6 +133,15 @@ private byte[] toByte(@NonNull String input) { return input.getBytes(StandardCharsets.UTF_8); } + private byte[] decToByte(@NonNull String input) { + String[] parts = input.split(","); + byte[] output = new byte[parts.length]; + for (int i = 0; i < parts.length; i++) { + output[i] = Byte.parseByte(parts[i]); + } + return output; + } + @NonNull @Contract("_ -> new") public String toString(byte[] input) { @@ -422,30 +431,48 @@ private boolean retryFailedActionsInternal(int timeout) throws Exception { } @NonNull - private byte[] createPeerIdentity(byte[] privateKey) throws GeneralSecurityException, IOException { + private byte[] createPeerIdentity(byte[] identity) throws GeneralSecurityException, IOException { try { // 1: First: create public key from provided private key // 2: Should read the local keychain store (if it is key-value, key is public key above, // 3: if found, decrypt using the private key // 4: If not found or decryption not successful, generate an identity // 5: then encrypt and store in keychain - String encryptedKey = sharedPref.getValue(PRIVATE_KEY_STORE_ID); - SecretKey secretKey = Cryptography.generateKey(privateKey); + byte[] libp2pId; + String encryptedLibp2pId = sharedPref.getValue(PRIVATE_KEY_STORE_PEERID); + byte[] encryptionPair; + SecretKey encryptionSecretKey; + try { + encryptionSecretKey = Cryptography.generateKey(identity); + Log.d("ReactNative", "encryptionSecretKey generated from privateKey"); + } catch (Exception e) { + Log.d("ReactNative", "Failed to generate key for encryption: " + e.getMessage()); + throw new GeneralSecurityException("Failed to generate key encryption", e); + } + + if (encryptedLibp2pId == null || !encryptedLibp2pId.startsWith("FULA_ENC_V3:")) { + Log.d("ReactNative", "encryptedLibp2pId is not correct. creating new one " + encryptedLibp2pId); - if (encryptedKey == null || !encryptedKey.startsWith("FULA_ENC_V2:")) { - byte[] autoGeneratedIdentity; try { - autoGeneratedIdentity = Fulamobile.generateEd25519Key(); + libp2pId = Fulamobile.generateEd25519KeyFromString(toString(identity)); } catch (Exception e) { - Log.d("ReactNative", "Failed to generate key: " + e.getMessage()); - throw new GeneralSecurityException("Failed to generate key", e); + Log.d("ReactNative", "Failed to generate libp2pId: " + e.getMessage()); + throw new GeneralSecurityException("Failed to generate libp2pId", e); } - encryptedKey = "FULA_ENC_V2:" + Cryptography.encryptMsg(StaticHelper.bytesToBase64(autoGeneratedIdentity), secretKey); - sharedPref.add(PRIVATE_KEY_STORE_ID, encryptedKey); + encryptedLibp2pId = "FULA_ENC_V3:" + Cryptography.encryptMsg(StaticHelper.bytesToBase64(libp2pId), encryptionSecretKey); + sharedPref.add(PRIVATE_KEY_STORE_PEERID, encryptedLibp2pId); + } else { + Log.d("ReactNative", "encryptedLibp2pId is correct. decrypting " + encryptedLibp2pId); } - String decryptedKey = Cryptography.decryptMsg(encryptedKey.replace("FULA_ENC_V2:", ""), secretKey); - return StaticHelper.base64ToBytes(decryptedKey); + try { + String decryptedLibp2pId = Cryptography.decryptMsg(encryptedLibp2pId.replace("FULA_ENC_V3:", ""), encryptionSecretKey); + + return StaticHelper.base64ToBytes(decryptedLibp2pId); + } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) { + Log.d("ReactNative", "createPeerIdentity decryptMsg failed with Error: " + e.getMessage()); + throw (e); + } } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) { Log.d("ReactNative", "createPeerIdentity failed with Error: " + e.getMessage()); @@ -478,8 +505,8 @@ private boolean encrypt_and_store_config() throws Exception { String cid_encrypted = Cryptography.encryptMsg(this.rootConfig.getCid(), this.secretKeyGlobal); String private_ref_encrypted = Cryptography.encryptMsg(this.rootConfig.getPrivate_ref(), this.secretKeyGlobal); - sharedPref.add("FULA_ENC_V2:cid_encrypted_" + this.identityEncryptedGlobal, cid_encrypted); - sharedPref.add("FULA_ENC_V2:private_ref_encrypted_" + this.identityEncryptedGlobal, private_ref_encrypted); + sharedPref.add("FULA_ENC_V3:cid_encrypted_" + this.identityEncryptedGlobal, cid_encrypted); + sharedPref.add("FULA_ENC_V3:private_ref_encrypted_" + this.identityEncryptedGlobal, private_ref_encrypted); return true; } else { return false; @@ -496,14 +523,15 @@ private boolean logoutInternal(byte[] identity, String storePath) throws Excepti this.fula.flush(); } SecretKey secretKey = Cryptography.generateKey(identity); + String identity_encrypted = Cryptography.encryptMsg(Arrays.toString(identity), secretKey); - sharedPref.remove("FULA_ENC_V2:cid_encrypted_"+ identity_encrypted); - sharedPref.remove("FULA_ENC_V2:private_ref_encrypted_"+identity_encrypted); + sharedPref.remove("FULA_ENC_V3:cid_encrypted_"+ identity_encrypted); + sharedPref.remove("FULA_ENC_V3:private_ref_encrypted_"+identity_encrypted); //TODO: Should also remove peerid @Mahdi - sharedPref.remove("FULA_ENC_V2:cid_encrypted_"+ identity_encrypted); - sharedPref.remove("FULA_ENC_V2:private_ref_encrypted_"+ identity_encrypted); + sharedPref.remove("FULA_ENC_V3:cid_encrypted_"+ identity_encrypted); + sharedPref.remove("FULA_ENC_V3:private_ref_encrypted_"+ identity_encrypted); this.rootConfig = null; this.secretKeyGlobal = null; @@ -591,8 +619,8 @@ private String[] initInternal(byte[] identity, String storePath, String bloxAddr Log.d("ReactNative", "this.rootCid is empty."); //Load from keystore - String cid_encrypted_fetched = sharedPref.getValue("FULA_ENC_V2:cid_encrypted_"+ identity_encrypted); - String private_ref_encrypted_fetched = sharedPref.getValue("FULA_ENC_V2:private_ref_encrypted_"+identity_encrypted); + String cid_encrypted_fetched = sharedPref.getValue("FULA_ENC_V3:cid_encrypted_"+ identity_encrypted); + String private_ref_encrypted_fetched = sharedPref.getValue("FULA_ENC_V3:private_ref_encrypted_"+identity_encrypted); Log.d("ReactNative", "Here1"); String cid = ""; String private_ref = ""; @@ -1301,6 +1329,10 @@ public void removeStoredReplication(String seedString, String uploader, long poo }); } + //////////////////////////////////////////////////////////////// + ///////////////// Blox Hardware Methods //////////////////////// + //////////////////////////////////////////////////////////////// + @ReactMethod public void bloxFreeSpace(Promise promise) { ThreadUtils.runOnExecutor(() -> { @@ -1317,4 +1349,36 @@ public void bloxFreeSpace(Promise promise) { }); } + @ReactMethod + public void wifiRemoveall(Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "wifiRemoveall"); + try { + byte[] result = this.fula.wifiRemoveall(); + String resultString = toString(result); + Log.d("ReactNative", "result string="+resultString); + promise.resolve(resultString); + } catch (Exception e) { + Log.d("ReactNative", e.getMessage()); + promise.reject(e); + } + }); + } + + @ReactMethod + public void reboot(Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "reboot"); + try { + byte[] result = this.fula.reboot(); + String resultString = toString(result); + Log.d("ReactNative", "result string="+resultString); + promise.resolve(resultString); + } catch (Exception e) { + Log.d("ReactNative", e.getMessage()); + promise.reject(e); + } + }); + } + } diff --git a/example/src/App.tsx b/example/src/App.tsx index 6913976..6111457 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { StyleSheet, Text, View, Button, TextInput } from 'react-native'; -import { fula, blockchain, chainApi } from '@functionland/react-native-fula'; +import { fula, blockchain, chainApi, fxblox } from '@functionland/react-native-fula'; const App = () => { const [key, setKey] = React.useState(''); @@ -31,7 +31,7 @@ const App = () => { console.log(err.message, err.code); }); }; - //Key for peerId: 12D3KooWQGQo81K99HfbwuwhvbP4MYfo13fo7U6SAdkAnxoNBdPE + //Key for peerId: 12D3KooWDPZGpr4Jeq144R2KhezH7UHgHqyMXySh8tA5jzUyu2P8 const privateKey = [ 183, 7, 117, 9, 159, 132, 170, 235, 215, 34, 145, 181, 60, 207, 4, 27, 27, 17, 17, 167, 100, 89, 157, 218, 73, 200, 183, 145, 104, 151, 204, 142, 241, @@ -39,7 +39,7 @@ const App = () => { 203, 243, 211, 78, 120, 114, 199, 1, 197, 134, 6, 91, 87, 152, ]; const privateKeyString = "\\test"; - const bloxAddr = '/dns/relay.dev.fx.land/tcp/4001/p2p/12D3KooWDRrBaAfPwsGJivBoUw5fE7ZpDiyfUjqgiURq2DEcL835/p2p-circuit/p2p/12D3KooWD69C5yX91nPe3tz6HRiuw7Pia4xsxE9xv2CghoyK6MPK'; + const bloxAddr = '/dns/relay.dev.fx.land/tcp/4001/p2p/12D3KooWDRrBaAfPwsGJivBoUw5fE7ZpDiyfUjqgiURq2DEcL835/p2p-circuit/p2p/12D3KooWQR2XygKM7jhBduhvz2GDJdGEbZL8SZhkeBuXYPn2kRt6'; const newClient = async () => { try { return fula.newClient( @@ -419,6 +419,70 @@ const App = () => { }} color={inprogress ? 'green' : 'blue'} /> + +