diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/AccountManager.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/AccountManager.java new file mode 100644 index 0000000000..fd25e08604 --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/AccountManager.java @@ -0,0 +1,345 @@ +package im.status.ethereum.module; + +import com.facebook.react.bridge.Callback; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import statusgo.Statusgo; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; +import org.json.JSONObject; +import org.json.JSONException; +import android.util.Log; +import android.content.Context; +import android.app.Activity; + +public class AccountManager extends ReactContextBaseJavaModule { + private static final String TAG = "AccountManager"; + private static final String gethLogFileName = "geth.log"; + private ReactApplicationContext reactContext; + + private Utils utils; + private LogManager logManager; + + public AccountManager(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + this.utils = new Utils(reactContext); + this.logManager = new LogManager(reactContext); + } + + @Override + public String getName() { + return "AccountManager"; + } + + private String getTestnetDataDir(final String absRootDirPath) { + return this.utils.pathCombine(absRootDirPath, "ethereum/testnet"); + } + + @ReactMethod + public void createAccountAndLogin(final String createAccountRequest) { + Log.d(TAG, "createAccountAndLogin"); + String result = Statusgo.createAccountAndLogin(createAccountRequest); + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "createAccountAndLogin success: " + result); + Log.d(TAG, "Geth node started"); + } else { + Log.e(TAG, "createAccountAndLogin failed: " + result); + } + } + + @ReactMethod + public void restoreAccountAndLogin(final String restoreAccountRequest) { + Log.d(TAG, "restoreAccountAndLogin"); + String result = Statusgo.restoreAccountAndLogin(restoreAccountRequest); + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "restoreAccountAndLogin success: " + result); + Log.d(TAG, "Geth node started"); + } else { + Log.e(TAG, "restoreAccountAndLogin failed: " + result); + } + } + + private String updateConfig(final String jsonConfigString, final String absRootDirPath, final String keystoreDirPath) throws JSONException { + final JSONObject jsonConfig = new JSONObject(jsonConfigString); + // retrieve parameters from app config, that will be applied onto the Go-side config later on + final String dataDirPath = jsonConfig.getString("DataDir"); + final Boolean logEnabled = jsonConfig.getBoolean("LogEnabled"); + final Context context = this.getReactApplicationContext(); + final File gethLogFile = logEnabled ? this.logManager.prepareLogsFile(context) : null; + String gethLogDirPath = null; + if (gethLogFile != null) { + gethLogDirPath = gethLogFile.getParent(); + } + + Log.d(TAG, "log dir: " + gethLogDirPath + " log name: " + gethLogFileName); + + jsonConfig.put("DataDir", dataDirPath); + jsonConfig.put("KeyStoreDir", keystoreDirPath); + jsonConfig.put("LogDir", gethLogDirPath); + jsonConfig.put("LogFile", gethLogFileName); + + return jsonConfig.toString(); + } + + private static void prettyPrintConfig(final String config) { + Log.d(TAG, "startNode() with config (see below)"); + String configOutput = config; + final int maxOutputLen = 4000; + Log.d(TAG, "********************** NODE CONFIG ****************************"); + while (!configOutput.isEmpty()) { + Log.d(TAG, "Node config:" + configOutput.substring(0, Math.min(maxOutputLen, configOutput.length()))); + if (configOutput.length() > maxOutputLen) { + configOutput = configOutput.substring(maxOutputLen); + } else { + break; + } + } + Log.d(TAG, "******************* ENDOF NODE CONFIG *************************"); + } + + private void copyDirectory(File sourceLocation, File targetLocation) throws IOException { + if (sourceLocation.isDirectory()) { + if (!targetLocation.exists() && !targetLocation.mkdirs()) { + throw new IOException("Cannot create dir " + targetLocation.getAbsolutePath()); + } + + String[] children = sourceLocation.list(); + for (int i = 0; i < children.length; i++) { + copyDirectory(new File(sourceLocation, children[i]), new File(targetLocation, children[i])); + } + } else { + File directory = targetLocation.getParentFile(); + if (directory != null && !directory.exists() && !directory.mkdirs()) { + throw new IOException("Cannot create dir " + directory.getAbsolutePath()); + } + + InputStream in = new FileInputStream(sourceLocation); + OutputStream out = new FileOutputStream(targetLocation); + + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + in.close(); + out.close(); + } + } + + private String prepareDirAndUpdateConfig(final String jsonConfigString, final String keyUID) { + + final String absRootDirPath = this.utils.getNoBackupDirectory(); + final String dataFolder = this.getTestnetDataDir(absRootDirPath); + Log.d(TAG, "Starting Geth node in folder: " + dataFolder); + + try { + final File newFile = new File(dataFolder); + // todo handle error? + newFile.mkdir(); + } catch (Exception e) { + Log.e(TAG, "error making folder: " + dataFolder, e); + } + + final String ropstenFlagPath = this.utils.pathCombine(absRootDirPath, "ropsten_flag"); + final File ropstenFlag = new File(ropstenFlagPath); + if (!ropstenFlag.exists()) { + try { + final String chaindDataFolderPath = this.utils.pathCombine(dataFolder, "StatusIM/lightchaindata"); + final File lightChainFolder = new File(chaindDataFolderPath); + if (lightChainFolder.isDirectory()) { + String[] children = lightChainFolder.list(); + for (int i = 0; i < children.length; i++) { + new File(lightChainFolder, children[i]).delete(); + } + } + lightChainFolder.delete(); + ropstenFlag.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + String testnetDataDir = dataFolder; + String oldKeystoreDir = this.utils.pathCombine(testnetDataDir, "keystore"); + String newKeystoreDir = this.utils.pathCombine(absRootDirPath, "keystore"); + final File oldKeystore = new File(oldKeystoreDir); + if (oldKeystore.exists()) { + try { + final File newKeystore = new File(newKeystoreDir); + copyDirectory(oldKeystore, newKeystore); + + if (oldKeystore.isDirectory()) { + String[] children = oldKeystore.list(); + for (int i = 0; i < children.length; i++) { + new File(oldKeystoreDir, children[i]).delete(); + } + } + oldKeystore.delete(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + try { + final String multiaccountKeystoreDir = this.utils.pathCombine("/keystore", keyUID); + final String updatedJsonConfigString = this.updateConfig(jsonConfigString, absRootDirPath, multiaccountKeystoreDir); + + prettyPrintConfig(updatedJsonConfigString); + + return updatedJsonConfigString; + } catch (JSONException e) { + Log.e(TAG, "updateConfig failed: " + e.getMessage()); + System.exit(1); + + return ""; + } + } + + @ReactMethod + public void prepareDirAndUpdateConfig(final String keyUID, final String config, final Callback callback) { + Log.d(TAG, "prepareDirAndUpdateConfig"); + String finalConfig = prepareDirAndUpdateConfig(config, keyUID); + callback.invoke(finalConfig); + } + + @ReactMethod + public void saveAccountAndLoginWithKeycard(final String multiaccountData, final String password, final String settings, final String config, final String accountsData, final String chatKey) { + try { + Log.d(TAG, "saveAccountAndLoginWithKeycard"); + String finalConfig = prepareDirAndUpdateConfig(config, this.utils.getKeyUID(multiaccountData)); + String result = Statusgo.saveAccountAndLoginWithKeycard(multiaccountData, password, settings, finalConfig, accountsData, chatKey); + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "saveAccountAndLoginWithKeycard result: " + result); + Log.d(TAG, "Geth node started"); + } else { + Log.e(TAG, "saveAccountAndLoginWithKeycard failed: " + result); + } + } catch (JSONException e) { + Log.e(TAG, "JSON conversion failed: " + e.getMessage()); + } + } + + @ReactMethod + public void loginWithKeycard(final String accountData, final String password, final String chatKey, final String nodeConfigJSON) { + Log.d(TAG, "loginWithKeycard"); + this.utils.migrateKeyStoreDir(accountData, password); + String result = Statusgo.loginWithKeycard(accountData, password, chatKey, nodeConfigJSON); + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "LoginWithKeycard result: " + result); + } else { + Log.e(TAG, "LoginWithKeycard failed: " + result); + } + } + + @ReactMethod + public void loginWithConfig(final String accountData, final String password, final String configJSON) { + Log.d(TAG, "loginWithConfig"); + this.utils.migrateKeyStoreDir(accountData, password); + String result = Statusgo.loginWithConfig(accountData, password, configJSON); + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "LoginWithConfig result: " + result); + } else { + Log.e(TAG, "LoginWithConfig failed: " + result); + } + } + + @ReactMethod + public void loginAccount(final String request) { + Log.d(TAG, "loginAccount"); + String result = Statusgo.loginAccount(request); + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "loginAccount result: " + result); + } else { + Log.e(TAG, "loginAccount failed: " + result); + } + } + + @ReactMethod + public void verify(final String address, final String password, final Callback callback) throws JSONException { + Activity currentActivity = getCurrentActivity(); + + final String absRootDirPath = this.utils.getNoBackupDirectory(); + final String newKeystoreDir = this.utils.pathCombine(absRootDirPath, "keystore"); + + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.verifyAccountPassword(newKeystoreDir, address, password), callback); + } + + @ReactMethod + public void verifyDatabasePassword(final String keyUID, final String password, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.verifyDatabasePassword(keyUID, password), callback); + } + + @ReactMethod + private void openAccounts(final Callback callback) throws JSONException { + Log.d(TAG, "openAccounts"); + final String rootDir = this.utils.getNoBackupDirectory(); + Log.d(TAG, "[Opening accounts" + rootDir); + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.openAccounts(rootDir), callback); + } + + //TODO : refactor logout usage to accept callback so that we can do this.utils.executeRunnableStatusGoMethod + @ReactMethod + public void logout() { + Log.d(TAG, "logout"); + Runnable r = new Runnable() { + @Override + public void run() { + String result = Statusgo.logout(); + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "Logout result: " + result); + } else { + Log.e(TAG, "Logout failed: " + result); + } + } + }; + + StatusThreadPoolExecutor.getInstance().execute(r); + } + + @ReactMethod + public void multiAccountStoreAccount(final String json, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountStoreAccount(json), callback); + } + + @ReactMethod + public void multiAccountLoadAccount(final String json, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountLoadAccount(json), callback); + } + + @ReactMethod + public void multiAccountDeriveAddresses(final String json, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountDeriveAddresses(json), callback); + } + + @ReactMethod + public void multiAccountGenerateAndDeriveAddresses(final String json, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountGenerateAndDeriveAddresses(json), callback); + } + + @ReactMethod + public void multiAccountStoreDerived(final String json, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountStoreDerivedAccounts(json), callback); + } + + @ReactMethod + public void multiAccountImportMnemonic(final String json, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountImportMnemonic(json), callback); + } + + @ReactMethod + public void multiAccountImportPrivateKey(final String json, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountImportPrivateKey(json), callback); + } + + @ReactMethod + public void deleteMultiaccount(final String keyUID, final Callback callback) throws JSONException { + final String keyStoreDir = this.utils.getKeyStorePath(keyUID); + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.deleteMultiaccount(keyUID, keyStoreDir), callback); + } +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/DatabaseManager.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/DatabaseManager.java new file mode 100644 index 0000000000..e725af99df --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/DatabaseManager.java @@ -0,0 +1,66 @@ +package im.status.ethereum.module; + +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.Callback; +import statusgo.Statusgo; +import android.util.Log; +import java.io.File; +import android.os.Environment; +import android.content.Context; +public class DatabaseManager extends ReactContextBaseJavaModule { + private static final String TAG = "DatabaseManager"; + private ReactApplicationContext reactContext; + private static final String exportDBFileName = "export.db"; + private Utils utils; + public DatabaseManager(ReactApplicationContext reactContext) { + this.reactContext = reactContext; + this.utils = new Utils(reactContext); + } + @Override + public String getName() { + return "DatabaseManager"; + } + + private File getExportDBFile() { + final Context context = this.getReactApplicationContext(); + // Environment.getExternalStoragePublicDirectory doesn't work as expected on Android Q + // https://developer.android.com/reference/android/os/Environment#getExternalStoragePublicDirectory(java.lang.String) + final File pubDirectory = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS); + final File filename = new File(pubDirectory, exportDBFileName); + + return filename; + } + + @ReactMethod + public void exportUnencryptedDatabase(final String accountData, final String password, final Callback callback) { + Log.d(TAG, "login"); + + final File newFile = getExportDBFile(); + + this.utils.migrateKeyStoreDir(accountData, password); + String result = Statusgo.exportUnencryptedDatabase(accountData, password, newFile.getAbsolutePath()); + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "Login result: " + result); + } else { + Log.e(TAG, "Login failed: " + result); + } + } + + @ReactMethod + public void importUnencryptedDatabase(final String accountData, final String password) { + Log.d(TAG, "importUnencryptedDatabase"); + + final File newFile = getExportDBFile(); + + this.utils.migrateKeyStoreDir(accountData, password); + String result = Statusgo.importUnencryptedDatabase(accountData, password, newFile.getAbsolutePath()); + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "import result: " + result); + } else { + Log.e(TAG, "import failed: " + result); + } + } + +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/EncryptionUtils.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/EncryptionUtils.java new file mode 100644 index 0000000000..bed7b8ac08 --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/EncryptionUtils.java @@ -0,0 +1,173 @@ +package im.status.ethereum.module; + +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.Callback; +import android.util.Log; +import statusgo.Statusgo; +import org.json.JSONException; +import java.util.function.Function; +import android.app.Activity; +import android.view.WindowManager; +import android.os.Build; +import android.view.Window; +import android.preference.PreferenceManager; +import android.content.SharedPreferences; + +public class EncryptionUtils extends ReactContextBaseJavaModule { + private static final String TAG = "EncryptionUtils"; + + private ReactApplicationContext reactContext; + private Utils utils; + + public EncryptionUtils(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + this.utils = new Utils(reactContext); + } + + @Override + public String getName() { + return "EncryptionUtils"; + } + + @ReactMethod + private void initKeystore(final String keyUID, final Callback callback) throws JSONException { + Log.d(TAG, "initKeystore"); + + final String commonKeydir = this.utils.pathCombine(this.utils.getNoBackupDirectory(), "/keystore"); + final String keydir = this.utils.pathCombine(commonKeydir, keyUID); + + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.initKeystore(keydir), callback); + } + + @ReactMethod + public void reEncryptDbAndKeystore(final String keyUID, final String password, final String newPassword, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.changeDatabasePassword(keyUID, password, newPassword), callback); + } + + @ReactMethod + public void convertToKeycardAccount(final String keyUID, final String accountData, final String options, final String keycardUID, final String password, + final String newPassword, final Callback callback) throws JSONException { + final String keyStoreDir = this.utils.getKeyStorePath(keyUID); + this.utils.executeRunnableStatusGoMethod(() -> { + Statusgo.initKeystore(keyStoreDir); + return Statusgo.convertToKeycardAccount(accountData, options, keycardUID, password, newPassword); + }, callback); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public String encodeTransfer(final String to, final String value) { + return Statusgo.encodeTransfer(to, value); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public String decodeParameters(final String decodeParamJSON) { + return Statusgo.decodeParameters(decodeParamJSON); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public String hexToNumber(final String hex) { + return Statusgo.hexToNumber(hex); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public String numberToHex(final String numString) { + return Statusgo.numberToHex(numString); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public String sha3(final String str) { + return Statusgo.sha3(str); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public String utf8ToHex(final String str) { + return Statusgo.utf8ToHex(str); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public String hexToUtf8(final String str) { + return Statusgo.hexToUtf8(str); + } + + @ReactMethod + public void setBlankPreviewFlag(final Boolean blankPreview) { + final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this.reactContext); + sharedPrefs.edit().putBoolean("BLANK_PREVIEW", blankPreview).commit(); + setSecureFlag(); + } + + private void setSecureFlag() { + final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this.reactContext); + final boolean setSecure = sharedPrefs.getBoolean("BLANK_PREVIEW", true); + final Activity activity = this.reactContext.getCurrentActivity(); + if (activity != null) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + final Window window = activity.getWindow(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && setSecure) { + window.addFlags(WindowManager.LayoutParams.FLAG_SECURE); + } else { + window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE); + } + } + }); + } + } + + @ReactMethod + public void hashTransaction(final String txArgsJSON, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.hashTransaction(txArgsJSON), callback); + } + + @ReactMethod + public void hashMessage(final String message, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.hashMessage(message), callback); + } + + @ReactMethod + public void multiformatDeserializePublicKey(final String multiCodecKey, final String base58btc, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiformatDeserializePublicKey(multiCodecKey,base58btc), callback); + } + + @ReactMethod + public void deserializeAndCompressKey(final String desktopKey, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.deserializeAndCompressKey(desktopKey), callback); + } + + @ReactMethod + public void hashTypedData(final String data, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.hashTypedData(data), callback); + } + + @ReactMethod + public void hashTypedDataV4(final String data, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.hashTypedDataV4(data), callback); + } + + @ReactMethod + public void signMessage(final String rpcParams, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.signMessage(rpcParams), callback); + } + + @ReactMethod + public void signTypedData(final String data, final String account, final String password, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.signTypedData(data, account, password), callback); + } + + @ReactMethod + public void signTypedDataV4(final String data, final String account, final String password, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.signTypedDataV4(data, account, password), callback); + + } + + @ReactMethod + public void signGroupMembership(final String content, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.signGroupMembership(content), callback); + } + + +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/LogManager.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/LogManager.java new file mode 100644 index 0000000000..6a1873157e --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/LogManager.java @@ -0,0 +1,227 @@ +package im.status.ethereum.module; + +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.Callback; +import java.io.File; +import java.util.Stack; +import android.util.Log; +import android.net.Uri; +import java.io.OutputStreamWriter; +import java.io.IOException; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import androidx.core.content.FileProvider; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.FileOutputStream; +import java.util.zip.ZipOutputStream; +import java.io.FileInputStream; +import java.util.zip.ZipEntry; +import org.json.JSONObject; +import statusgo.Statusgo; +import android.content.Context; +import org.json.JSONException; +public class LogManager extends ReactContextBaseJavaModule { + private static final String TAG = "LogManager"; + private static final String gethLogFileName = "geth.log"; + private static final String statusLogFileName = "Status.log"; + private static final String logsZipFileName = "Status-debug-logs.zip"; + private ReactApplicationContext reactContext; + private Utils utils; + + public LogManager(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + this.utils = new Utils(reactContext); + } + + @Override + public String getName() { + return "LogManager"; + } + + private File getLogsFile() { + final File pubDirectory = this.utils.getPublicStorageDirectory(); + final File logFile = new File(pubDirectory, gethLogFileName); + + return logFile; + } + + public File prepareLogsFile(final Context context) { + final File logFile = this.utils.getLogsFile(); + + try { + logFile.setReadable(true); + File parent = logFile.getParentFile(); + if (!parent.canWrite()) { + return null; + } + if (!parent.exists()) { + parent.mkdirs(); + } + logFile.createNewFile(); + logFile.setWritable(true); + Log.d(TAG, "Can write " + logFile.canWrite()); + Uri gethLogUri = Uri.fromFile(logFile); + + String gethLogFilePath = logFile.getAbsolutePath(); + Log.d(TAG, gethLogFilePath); + + return logFile; + } catch (Exception e) { + Log.d(TAG, "Can't create geth.log file! " + e.getMessage()); + } + + return null; + } + + private void showErrorMessage(final String message) { + final Activity activity = getCurrentActivity(); + + new AlertDialog.Builder(activity) + .setTitle("Error") + .setMessage(message) + .setNegativeButton("Exit", new DialogInterface.OnClickListener() { + public void onClick(final DialogInterface dialog, final int id) { + dialog.dismiss(); + } + }).show(); + } + + private void dumpAdbLogsTo(final FileOutputStream statusLogStream) throws IOException { + final String filter = "logcat -d -b main ReactNativeJS:D StatusModule:D StatusService:D StatusNativeLogs:D *:S"; + final java.lang.Process p = Runtime.getRuntime().exec(filter); + final java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream())); + final java.io.BufferedWriter out = new java.io.BufferedWriter(new java.io.OutputStreamWriter(statusLogStream)); + String line; + while ((line = in.readLine()) != null) { + out.write(line); + out.newLine(); + } + out.close(); + in.close(); + } + + private Boolean zip(File[] _files, File zipFile, Stack errorList) { + final int BUFFER = 0x8000; + + try { + BufferedInputStream origin = null; + FileOutputStream dest = new FileOutputStream(zipFile); + ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest)); + byte data[] = new byte[BUFFER]; + + for (int i = 0; i < _files.length; i++) { + final File file = _files[i]; + if (file == null || !file.exists()) { + continue; + } + + Log.v("Compress", "Adding: " + file.getAbsolutePath()); + try { + FileInputStream fi = new FileInputStream(file); + origin = new BufferedInputStream(fi, BUFFER); + + ZipEntry entry = new ZipEntry(file.getName()); + out.putNextEntry(entry); + int count; + + while ((count = origin.read(data, 0, BUFFER)) != -1) { + out.write(data, 0, count); + } + origin.close(); + } catch (IOException e) { + Log.e(TAG, e.getMessage()); + errorList.push(e.getMessage()); + } + } + + out.close(); + + return true; + } catch (Exception e) { + Log.e(TAG, e.getMessage()); + e.printStackTrace(); + return false; + } + } + + @ReactMethod + public void sendLogs(final String dbJson, final String jsLogs, final Callback callback) { + Log.d(TAG, "sendLogs"); + if (!this.utils.checkAvailability()) { + return; + } + + final Context context = this.getReactApplicationContext(); + final File logsTempDir = new File(context.getCacheDir(), "logs"); // This path needs to be in sync with android/app/src/main/res/xml/file_provider_paths.xml + logsTempDir.mkdir(); + + final File dbFile = new File(logsTempDir, "db.json"); + try { + OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(dbFile)); + outputStreamWriter.write(dbJson); + outputStreamWriter.close(); + } catch (IOException e) { + Log.e(TAG, "File write failed: " + e.toString()); + showErrorMessage(e.getLocalizedMessage()); + } + + final File zipFile = new File(logsTempDir, logsZipFileName); + final File statusLogFile = new File(logsTempDir, statusLogFileName); + final File gethLogFile = getLogsFile(); + + try { + if (zipFile.exists() || zipFile.createNewFile()) { + final long usableSpace = zipFile.getUsableSpace(); + if (usableSpace < 20 * 1024 * 1024) { + final String message = String.format("Insufficient space available on device (%s) to write logs.\nPlease free up some space.", android.text.format.Formatter.formatShortFileSize(context, usableSpace)); + Log.e(TAG, message); + showErrorMessage(message); + return; + } + } + + dumpAdbLogsTo(new FileOutputStream(statusLogFile)); + + final Stack errorList = new Stack(); + final Boolean zipped = zip(new File[]{dbFile, gethLogFile, statusLogFile}, zipFile, errorList); + if (zipped && zipFile.exists()) { + zipFile.setReadable(true, false); + Uri extUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", zipFile); + callback.invoke(extUri.toString()); + } else { + Log.d(TAG, "File " + zipFile.getAbsolutePath() + " does not exist"); + } + } catch (Exception e) { + Log.e(TAG, e.getMessage()); + showErrorMessage(e.getLocalizedMessage()); + e.printStackTrace(); + return; + } finally { + dbFile.delete(); + statusLogFile.delete(); + zipFile.deleteOnExit(); + } + } + + @ReactMethod + public void initLogging(final boolean enabled, final boolean mobileSystem, final String logLevel, final Callback callback) throws JSONException { + final JSONObject jsonConfig = new JSONObject(); + jsonConfig.put("Enabled", enabled); + jsonConfig.put("MobileSystem", mobileSystem); + jsonConfig.put("Level", logLevel); + jsonConfig.put("File", getLogsFile().getAbsolutePath()); + final String config = jsonConfig.toString(); + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.initLogging(config), callback); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public String logFileDirectory() { + return this.utils.getPublicStorageDirectory().getAbsolutePath(); + } + +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/NetworkManager.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/NetworkManager.java new file mode 100644 index 0000000000..873aa59671 --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/NetworkManager.java @@ -0,0 +1,78 @@ +package im.status.ethereum.module; + +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.Callback; +import org.json.JSONException; +import statusgo.Statusgo; +import org.json.JSONObject; + +public class NetworkManager extends ReactContextBaseJavaModule { + private ReactApplicationContext reactContext; + private Utils utils; + + public NetworkManager(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + this.utils = new Utils(reactContext); + } + + @Override + public String getName() { + return "NetworkManager"; + } + + @ReactMethod + public void startSearchForLocalPairingPeers(final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.startSearchForLocalPairingPeers(), callback); + } + + @ReactMethod + public void getConnectionStringForBootstrappingAnotherDevice(final String configJSON, final Callback callback) throws JSONException { + final JSONObject jsonConfig = new JSONObject(configJSON); + final JSONObject senderConfig = jsonConfig.getJSONObject("senderConfig"); + final String keyUID = senderConfig.getString("keyUID"); + final String keyStorePath = this.utils.getKeyStorePath(keyUID); + senderConfig.put("keystorePath", keyStorePath); + + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.getConnectionStringForBootstrappingAnotherDevice(jsonConfig.toString()), callback); + } + + @ReactMethod + public void inputConnectionStringForBootstrapping(final String connectionString, final String configJSON, final Callback callback) throws JSONException { + final JSONObject jsonConfig = new JSONObject(configJSON); + final JSONObject receiverConfig = jsonConfig.getJSONObject("receiverConfig"); + final String keyStorePath = this.utils.pathCombine(this.utils.getNoBackupDirectory(), "/keystore"); + receiverConfig.put("keystorePath", keyStorePath); + receiverConfig.getJSONObject("nodeConfig").put("rootDataDir", this.utils.getNoBackupDirectory()); + + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.inputConnectionStringForBootstrapping(connectionString, jsonConfig.toString()), callback); + } + + @ReactMethod + public void sendTransactionWithSignature(final String txArgsJSON, final String signature, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.sendTransactionWithSignature(txArgsJSON, signature), callback); + } + + @ReactMethod + public void sendTransaction(final String txArgsJSON, final String password, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.sendTransaction(txArgsJSON, password), callback); + } + + @ReactMethod + public void callRPC(final String payload, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.callRPC(payload), callback); + } + + @ReactMethod + public void callPrivateRPC(final String payload, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.callPrivateRPC(payload), callback); + } + + @ReactMethod + public void recover(final String rpcParams, final Callback callback) throws JSONException { + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.recover(rpcParams), callback); + } + +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java index 7a9f913e67..be1216fb27 100644 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java @@ -1,32 +1,10 @@ package im.status.ethereum.module; import android.app.Activity; -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.Uri; -import android.os.Bundle; -import android.os.Build; -import android.os.Environment; - -import android.preference.PreferenceManager; - -import androidx.core.content.FileProvider; - import android.util.Log; import android.view.Window; import android.view.WindowManager; -import android.webkit.WebView; -import android.webkit.CookieManager; -import android.webkit.CookieSyncManager; -import android.webkit.WebStorage; -import android.content.Context; -import android.view.View; -import android.widget.TextView; -import android.widget.EditText; -import android.view.inputmethod.InputMethodManager; +import android.os.Build; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Callback; @@ -34,62 +12,34 @@ import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.WritableMap; import com.facebook.react.modules.core.DeviceEventManagerModule; -import com.facebook.react.uimanager.UIManagerModule; -import com.facebook.react.uimanager.UIBlock; -import com.facebook.react.uimanager.NativeViewHierarchyManager; import statusgo.SignalHandler; import statusgo.Statusgo; import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONArray; - - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; -import java.text.SimpleDateFormat; import java.util.HashMap; -import java.util.function.Function; -import java.util.function.Supplier; import java.util.Map; -import java.util.Stack; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - import javax.annotation.Nullable; -import android.app.Service; - class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventListener, SignalHandler { private static final String TAG = "StatusModule"; - private static final String logsZipFileName = "Status-debug-logs.zip"; - private static final String gethLogFileName = "geth.log"; - private static final String exportDBFileName = "export.db"; - private static final String statusLogFileName = "Status.log"; private static StatusModule module; private ReactApplicationContext reactContext; private boolean rootedDevice; private boolean background; + private Utils utils; + StatusModule(ReactApplicationContext reactContext, boolean rootedDevice) { super(reactContext); this.reactContext = reactContext; this.rootedDevice = rootedDevice; + this.utils = new Utils(reactContext); + reactContext.addLifecycleEventListener(this); } @@ -99,7 +49,7 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL } @Override - public void onHostResume() { // Activity `onResume` + public void onHostResume() { module = this; this.background = false; Statusgo.setMobileSignalHandler(this); @@ -115,33 +65,6 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL Log.d(TAG, "******************* ON HOST DESTROY *************************"); } - private boolean checkAvailability() { - // We wait at least 10s for getCurrentActivity to return a value, - // otherwise we give up - for (int attempts = 0; attempts < 100; attempts++) { - if (getCurrentActivity() != null) { - return true; - } - try { - Thread.sleep(100); - } catch (InterruptedException ex) { - if (getCurrentActivity() != null) { - return true; - } - Log.d(TAG, "Activity doesn't exist"); - return false; - } - } - - Log.d(TAG, "Activity doesn't exist"); - return false; - - } - - public String getNoBackupDirectory() { - return this.getReactApplicationContext().getNoBackupFilesDir().getAbsolutePath(); - } - public void handleSignal(final String jsonEventString) { Log.d(TAG, "Signal event"); WritableMap params = Arguments.createMap(); @@ -149,948 +72,6 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL this.getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("gethEvent", params); } - private File getPublicStorageDirectory() { - final Context context = this.getReactApplicationContext(); - // Environment.getExternalStoragePublicDirectory doesn't work as expected on Android Q - // https://developer.android.com/reference/android/os/Environment#getExternalStoragePublicDirectory(java.lang.String) - return context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS); - } - - private File getLogsFile() { - final File pubDirectory = this.getPublicStorageDirectory(); - final File logFile = new File(pubDirectory, gethLogFileName); - - return logFile; - } - - private File getExportDBFile() { - final Context context = this.getReactApplicationContext(); - // Environment.getExternalStoragePublicDirectory doesn't work as expected on Android Q - // https://developer.android.com/reference/android/os/Environment#getExternalStoragePublicDirectory(java.lang.String) - final File pubDirectory = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS); - final File filename = new File(pubDirectory, exportDBFileName); - - return filename; - } - - private File prepareLogsFile(final Context context) { - final File logFile = getLogsFile(); - - try { - logFile.setReadable(true); - File parent = logFile.getParentFile(); - if (!parent.canWrite()) { - return null; - } - if (!parent.exists()) { - parent.mkdirs(); - } - logFile.createNewFile(); - logFile.setWritable(true); - Log.d(TAG, "Can write " + logFile.canWrite()); - Uri gethLogUri = Uri.fromFile(logFile); - - String gethLogFilePath = logFile.getAbsolutePath(); - Log.d(TAG, gethLogFilePath); - - return logFile; - } catch (Exception e) { - Log.d(TAG, "Can't create geth.log file! " + e.getMessage()); - } - - return null; - } - - private String updateConfig(final String jsonConfigString, final String absRootDirPath, final String keystoreDirPath) throws JSONException { - final JSONObject jsonConfig = new JSONObject(jsonConfigString); - // retrieve parameters from app config, that will be applied onto the Go-side config later on - final String dataDirPath = jsonConfig.getString("DataDir"); - final Boolean logEnabled = jsonConfig.getBoolean("LogEnabled"); - final Context context = this.getReactApplicationContext(); - final File gethLogFile = logEnabled ? prepareLogsFile(context) : null; - String gethLogDirPath = null; - if (gethLogFile != null) { - gethLogDirPath = gethLogFile.getParent(); - } - - Log.d(TAG, "log dir: " + gethLogDirPath + " log name: " + gethLogFileName); - - jsonConfig.put("DataDir", dataDirPath); - jsonConfig.put("KeyStoreDir", keystoreDirPath); - jsonConfig.put("LogDir", gethLogDirPath); - jsonConfig.put("LogFile", gethLogFileName); - - return jsonConfig.toString(); - } - - private static void prettyPrintConfig(final String config) { - Log.d(TAG, "startNode() with config (see below)"); - String configOutput = config; - final int maxOutputLen = 4000; - Log.d(TAG, "********************** NODE CONFIG ****************************"); - while (!configOutput.isEmpty()) { - Log.d(TAG, "Node config:" + configOutput.substring(0, Math.min(maxOutputLen, configOutput.length()))); - if (configOutput.length() > maxOutputLen) { - configOutput = configOutput.substring(maxOutputLen); - } else { - break; - } - } - Log.d(TAG, "******************* ENDOF NODE CONFIG *************************"); - } - - private String getTestnetDataDir(final String absRootDirPath) { - return pathCombine(absRootDirPath, "ethereum/testnet"); - } - - private String pathCombine(final String path1, final String path2) { - // Replace this logic with Paths.get(path1, path2) once API level 26+ becomes the minimum supported API level - final File file = new File(path1, path2); - return file.getAbsolutePath(); - } - - private String prepareDirAndUpdateConfig(final String jsonConfigString, final String keyUID) { - - Activity currentActivity = getCurrentActivity(); - - final String absRootDirPath = this.getNoBackupDirectory(); - final String dataFolder = this.getTestnetDataDir(absRootDirPath); - Log.d(TAG, "Starting Geth node in folder: " + dataFolder); - - try { - final File newFile = new File(dataFolder); - // todo handle error? - newFile.mkdir(); - } catch (Exception e) { - Log.e(TAG, "error making folder: " + dataFolder, e); - } - - final String ropstenFlagPath = pathCombine(absRootDirPath, "ropsten_flag"); - final File ropstenFlag = new File(ropstenFlagPath); - if (!ropstenFlag.exists()) { - try { - final String chaindDataFolderPath = pathCombine(dataFolder, "StatusIM/lightchaindata"); - final File lightChainFolder = new File(chaindDataFolderPath); - if (lightChainFolder.isDirectory()) { - String[] children = lightChainFolder.list(); - for (int i = 0; i < children.length; i++) { - new File(lightChainFolder, children[i]).delete(); - } - } - lightChainFolder.delete(); - ropstenFlag.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - String testnetDataDir = dataFolder; - String oldKeystoreDir = pathCombine(testnetDataDir, "keystore"); - String newKeystoreDir = pathCombine(absRootDirPath, "keystore"); - final File oldKeystore = new File(oldKeystoreDir); - if (oldKeystore.exists()) { - try { - final File newKeystore = new File(newKeystoreDir); - copyDirectory(oldKeystore, newKeystore); - - if (oldKeystore.isDirectory()) { - String[] children = oldKeystore.list(); - for (int i = 0; i < children.length; i++) { - new File(oldKeystoreDir, children[i]).delete(); - } - } - oldKeystore.delete(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - try { - final String multiaccountKeystoreDir = pathCombine("/keystore", keyUID); - final String updatedJsonConfigString = this.updateConfig(jsonConfigString, absRootDirPath, multiaccountKeystoreDir); - - prettyPrintConfig(updatedJsonConfigString); - - return updatedJsonConfigString; - } catch (JSONException e) { - Log.e(TAG, "updateConfig failed: " + e.getMessage()); - System.exit(1); - - return ""; - } - } - - @ReactMethod - public void prepareDirAndUpdateConfig(final String keyUID, final String config, final Callback callback) { - Log.d(TAG, "prepareDirAndUpdateConfig"); - String finalConfig = prepareDirAndUpdateConfig(config, keyUID); - callback.invoke(finalConfig); - } - - @ReactMethod - public void createAccountAndLogin(final String createAccountRequest) { - Log.d(TAG, "createAccountAndLogin"); - String result = Statusgo.createAccountAndLogin(createAccountRequest); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "createAccountAndLogin success: " + result); - Log.d(TAG, "Geth node started"); - } else { - Log.e(TAG, "createAccountAndLogin failed: " + result); - } - } - - @ReactMethod - public void restoreAccountAndLogin(final String restoreAccountRequest) { - Log.d(TAG, "restoreAccountAndLogin"); - String result = Statusgo.restoreAccountAndLogin(restoreAccountRequest); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "restoreAccountAndLogin success: " + result); - Log.d(TAG, "Geth node started"); - } else { - Log.e(TAG, "restoreAccountAndLogin failed: " + result); - } - } - - @ReactMethod - public void saveAccountAndLogin(final String multiaccountData, final String password, final String settings, final String config, final String accountsData) { - try { - Log.d(TAG, "saveAccountAndLogin"); - String finalConfig = prepareDirAndUpdateConfig(config, this.getKeyUID(multiaccountData)); - String result = Statusgo.saveAccountAndLogin(multiaccountData, password, settings, finalConfig, accountsData); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "saveAccountAndLogin result: " + result); - Log.d(TAG, "Geth node started"); - } else { - Log.e(TAG, "saveAccountAndLogin failed: " + result); - } - } catch (JSONException e) { - Log.e(TAG, "JSON conversion failed: " + e.getMessage()); - } - } - - @ReactMethod - public void saveAccountAndLoginWithKeycard(final String multiaccountData, final String password, final String settings, final String config, final String accountsData, final String chatKey) { - try { - Log.d(TAG, "saveAccountAndLoginWithKeycard"); - String finalConfig = prepareDirAndUpdateConfig(config, this.getKeyUID(multiaccountData)); - String result = Statusgo.saveAccountAndLoginWithKeycard(multiaccountData, password, settings, finalConfig, accountsData, chatKey); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "saveAccountAndLoginWithKeycard result: " + result); - Log.d(TAG, "Geth node started"); - } else { - Log.e(TAG, "saveAccountAndLoginWithKeycard failed: " + result); - } - } catch (JSONException e) { - Log.e(TAG, "JSON conversion failed: " + e.getMessage()); - } - } - - private String getKeyUID(final String json) throws JSONException { - final JSONObject jsonObj = new JSONObject(json); - return jsonObj.getString("key-uid"); - } - - @ReactMethod - public void login(final String accountData, final String password) { - Log.d(TAG, "login"); - this.migrateKeyStoreDir(accountData, password); - String result = Statusgo.login(accountData, password); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "Login result: " + result); - } else { - Log.e(TAG, "Login failed: " + result); - } - } - - @ReactMethod - public void loginWithConfig(final String accountData, final String password, final String configJSON) { - Log.d(TAG, "loginWithConfig"); - this.migrateKeyStoreDir(accountData, password); - String result = Statusgo.loginWithConfig(accountData, password, configJSON); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "LoginWithConfig result: " + result); - } else { - Log.e(TAG, "LoginWithConfig failed: " + result); - } - } - - @ReactMethod - public void loginAccount(final String request) { - Log.d(TAG, "loginAccount"); - String result = Statusgo.loginAccount(request); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "loginAccount result: " + result); - } else { - Log.e(TAG, "loginAccount failed: " + result); - } - } - - @ReactMethod - public void exportUnencryptedDatabase(final String accountData, final String password, final Callback callback) { - Log.d(TAG, "login"); - - final File newFile = getExportDBFile(); - - this.migrateKeyStoreDir(accountData, password); - String result = Statusgo.exportUnencryptedDatabase(accountData, password, newFile.getAbsolutePath()); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "Login result: " + result); - } else { - Log.e(TAG, "Login failed: " + result); - } - } - - @ReactMethod - public void importUnencryptedDatabase(final String accountData, final String password) { - Log.d(TAG, "importUnencryptedDatabase"); - - final File newFile = getExportDBFile(); - - this.migrateKeyStoreDir(accountData, password); - String result = Statusgo.importUnencryptedDatabase(accountData, password, newFile.getAbsolutePath()); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "import result: " + result); - } else { - Log.e(TAG, "import failed: " + result); - } - } - - @ReactMethod - public void logout() { - Log.d(TAG, "logout"); - if (!checkAvailability()) { - System.exit(0); - return; - } - - Runnable r = new Runnable() { - @Override - public void run() { - String result = Statusgo.logout(); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "Logout result: " + result); - } else { - Log.e(TAG, "Logout failed: " + result); - } - } - }; - - StatusThreadPoolExecutor.getInstance().execute(r); - } - - private void deleteDirectory(File folder) { - File[] files = folder.listFiles(); - if (files != null) { - for (File f : files) { - if (f.isDirectory()) { - deleteDirectory(f); - } else { - f.delete(); - } - } - } - folder.delete(); - } - - private void copyDirectory(File sourceLocation, File targetLocation) throws IOException { - if (sourceLocation.isDirectory()) { - if (!targetLocation.exists() && !targetLocation.mkdirs()) { - throw new IOException("Cannot create dir " + targetLocation.getAbsolutePath()); - } - - String[] children = sourceLocation.list(); - for (int i = 0; i < children.length; i++) { - copyDirectory(new File(sourceLocation, children[i]), new File(targetLocation, children[i])); - } - } else { - File directory = targetLocation.getParentFile(); - if (directory != null && !directory.exists() && !directory.mkdirs()) { - throw new IOException("Cannot create dir " + directory.getAbsolutePath()); - } - - InputStream in = new FileInputStream(sourceLocation); - OutputStream out = new FileOutputStream(targetLocation); - - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) > 0) { - out.write(buf, 0, len); - } - in.close(); - out.close(); - } - } - - @ReactMethod - private void initKeystore(final String keyUID, final Callback callback) { - Log.d(TAG, "initKeystore"); - - Activity currentActivity = getCurrentActivity(); - - if (!checkAvailability()) { - Log.e(TAG, "[initKeystore] Activity doesn't exist, cannot init keystore"); - System.exit(0); - return; - } - - final String commonKeydir = pathCombine(this.getNoBackupDirectory(), "/keystore"); - final String keydir = pathCombine(commonKeydir, keyUID); - - Runnable r = new Runnable() { - @Override - public void run() { - Statusgo.initKeystore(keydir); - callback.invoke(true); - } - }; - - StatusThreadPoolExecutor.getInstance().execute(r); - } - - @ReactMethod - private void openAccounts(final Callback callback) { - Activity currentActivity = getCurrentActivity(); - - final String rootDir = this.getNoBackupDirectory(); - Log.d(TAG, "openAccounts"); - if (!checkAvailability()) { - Log.e(TAG, "[openAccounts] Activity doesn't exist, cannot call openAccounts"); - System.exit(0); - return; - } - - Log.d(TAG, "[Opening accounts" + rootDir); - - Runnable r = new Runnable() { - @Override - public void run() { - String result = Statusgo.openAccounts(rootDir); - callback.invoke(result); - } - }; - - StatusThreadPoolExecutor.getInstance().execute(r); - } - - private void executeRunnableStatusGoMethod(Supplier method, Callback callback) throws JSONException { - if (!checkAvailability()) { - callback.invoke(false); - return; - } - - Runnable runnableTask = () -> { - String res = method.get(); - callback.invoke(res); - }; - - StatusThreadPoolExecutor.getInstance().execute(runnableTask); - } - - @ReactMethod - public void verify(final String address, final String password, final Callback callback) throws JSONException { - Activity currentActivity = getCurrentActivity(); - - final String absRootDirPath = this.getNoBackupDirectory(); - final String newKeystoreDir = pathCombine(absRootDirPath, "keystore"); - - executeRunnableStatusGoMethod(() -> Statusgo.verifyAccountPassword(newKeystoreDir, address, password), callback); - } - - @ReactMethod - public void verifyDatabasePassword(final String keyUID, final String password, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.verifyDatabasePassword(keyUID, password), callback); - } - - public String getKeyStorePath(String keyUID) { - final String commonKeydir = pathCombine(this.getNoBackupDirectory(), "/keystore"); - final String keydir = pathCombine(commonKeydir, keyUID); - - return keydir; - } - - public void migrateKeyStoreDir(final String accountData, final String password) { - try { - final String commonKeydir = pathCombine(this.getNoBackupDirectory(), "/keystore"); - final String keydir = this.getKeyStorePath(this.getKeyUID(accountData)); - Log.d(TAG, "before migrateKeyStoreDir " + keydir); - - File keydirFile = new File(keydir); - if(!keydirFile.exists() || keydirFile.list().length == 0) { - Log.d(TAG, "migrateKeyStoreDir"); - Statusgo.migrateKeyStoreDir(accountData, password, commonKeydir, keydir); - Statusgo.initKeystore(keydir); - } - } catch (JSONException e) { - Log.e(TAG, "JSON conversion failed: " + e.getMessage()); - } - } - - @ReactMethod - public void loginWithKeycard(final String accountData, final String password, final String chatKey, final String nodeConfigJSON) { - Log.d(TAG, "loginWithKeycard"); - this.migrateKeyStoreDir(accountData, password); - String result = Statusgo.loginWithKeycard(accountData, password, chatKey, nodeConfigJSON); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "LoginWithKeycard result: " + result); - } else { - Log.e(TAG, "LoginWithKeycard failed: " + result); - } - } - - private Boolean zip(File[] _files, File zipFile, Stack errorList) { - final int BUFFER = 0x8000; - - try { - BufferedInputStream origin = null; - FileOutputStream dest = new FileOutputStream(zipFile); - ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest)); - byte data[] = new byte[BUFFER]; - - for (int i = 0; i < _files.length; i++) { - final File file = _files[i]; - if (file == null || !file.exists()) { - continue; - } - - Log.v("Compress", "Adding: " + file.getAbsolutePath()); - try { - FileInputStream fi = new FileInputStream(file); - origin = new BufferedInputStream(fi, BUFFER); - - ZipEntry entry = new ZipEntry(file.getName()); - out.putNextEntry(entry); - int count; - - while ((count = origin.read(data, 0, BUFFER)) != -1) { - out.write(data, 0, count); - } - origin.close(); - } catch (IOException e) { - Log.e(TAG, e.getMessage()); - errorList.push(e.getMessage()); - } - } - - out.close(); - - return true; - } catch (Exception e) { - Log.e(TAG, e.getMessage()); - e.printStackTrace(); - return false; - } - } - - private void dumpAdbLogsTo(final FileOutputStream statusLogStream) throws IOException { - final String filter = "logcat -d -b main ReactNativeJS:D StatusModule:D StatusService:D StatusNativeLogs:D *:S"; - final java.lang.Process p = Runtime.getRuntime().exec(filter); - final java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream())); - final java.io.BufferedWriter out = new java.io.BufferedWriter(new java.io.OutputStreamWriter(statusLogStream)); - String line; - while ((line = in.readLine()) != null) { - out.write(line); - out.newLine(); - } - out.close(); - in.close(); - } - - private void showErrorMessage(final String message) { - final Activity activity = getCurrentActivity(); - - new AlertDialog.Builder(activity) - .setTitle("Error") - .setMessage(message) - .setNegativeButton("Exit", new DialogInterface.OnClickListener() { - public void onClick(final DialogInterface dialog, final int id) { - dialog.dismiss(); - } - }).show(); - } - - @ReactMethod - public void sendLogs(final String dbJson, final String jsLogs, final Callback callback) { - Log.d(TAG, "sendLogs"); - if (!checkAvailability()) { - return; - } - - final Context context = this.getReactApplicationContext(); - final File logsTempDir = new File(context.getCacheDir(), "logs"); // This path needs to be in sync with android/app/src/main/res/xml/file_provider_paths.xml - logsTempDir.mkdir(); - - final File dbFile = new File(logsTempDir, "db.json"); - try { - OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(dbFile)); - outputStreamWriter.write(dbJson); - outputStreamWriter.close(); - } catch (IOException e) { - Log.e(TAG, "File write failed: " + e.toString()); - showErrorMessage(e.getLocalizedMessage()); - } - - final File zipFile = new File(logsTempDir, logsZipFileName); - final File statusLogFile = new File(logsTempDir, statusLogFileName); - final File gethLogFile = getLogsFile(); - - try { - if (zipFile.exists() || zipFile.createNewFile()) { - final long usableSpace = zipFile.getUsableSpace(); - if (usableSpace < 20 * 1024 * 1024) { - final String message = String.format("Insufficient space available on device (%s) to write logs.\nPlease free up some space.", android.text.format.Formatter.formatShortFileSize(context, usableSpace)); - Log.e(TAG, message); - showErrorMessage(message); - return; - } - } - - dumpAdbLogsTo(new FileOutputStream(statusLogFile)); - - final Stack errorList = new Stack(); - final Boolean zipped = zip(new File[]{dbFile, gethLogFile, statusLogFile}, zipFile, errorList); - if (zipped && zipFile.exists()) { - zipFile.setReadable(true, false); - Uri extUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", zipFile); - callback.invoke(extUri.toString()); - } else { - Log.d(TAG, "File " + zipFile.getAbsolutePath() + " does not exist"); - } - } catch (Exception e) { - Log.e(TAG, e.getMessage()); - showErrorMessage(e.getLocalizedMessage()); - e.printStackTrace(); - return; - } finally { - dbFile.delete(); - statusLogFile.delete(); - zipFile.deleteOnExit(); - } - } - - @ReactMethod - public void addPeer(final String enode, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.addPeer(enode), callback); - } - - @ReactMethod - public void multiAccountStoreAccount(final String json, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.multiAccountStoreAccount(json), callback); - } - - @ReactMethod - public void multiAccountLoadAccount(final String json, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.multiAccountLoadAccount(json), callback); - } - - @ReactMethod - public void multiAccountReset(final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.multiAccountReset(), callback); - - } - - @ReactMethod - public void multiAccountDeriveAddresses(final String json, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.multiAccountDeriveAddresses(json), callback); - } - - @ReactMethod - public void multiAccountGenerateAndDeriveAddresses(final String json, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.multiAccountGenerateAndDeriveAddresses(json), callback); - } - - @ReactMethod - public void multiAccountStoreDerived(final String json, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.multiAccountStoreDerivedAccounts(json), callback); - } - - @ReactMethod - public void multiAccountImportMnemonic(final String json, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.multiAccountImportMnemonic(json), callback); - } - - @ReactMethod - public void multiAccountImportPrivateKey(final String json, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.multiAccountImportPrivateKey(json), callback); - } - - @ReactMethod - public void hashTransaction(final String txArgsJSON, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.hashTransaction(txArgsJSON), callback); - } - - @ReactMethod - public void hashMessage(final String message, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.hashMessage(message), callback); - } - - @ReactMethod - public void startSearchForLocalPairingPeers(final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.startSearchForLocalPairingPeers(), callback); - } - - @ReactMethod - public void getConnectionStringForBootstrappingAnotherDevice(final String configJSON, final Callback callback) throws JSONException { - final JSONObject jsonConfig = new JSONObject(configJSON); - final JSONObject senderConfig = jsonConfig.getJSONObject("senderConfig"); - final String keyUID = senderConfig.getString("keyUID"); - final String keyStorePath = this.getKeyStorePath(keyUID); - senderConfig.put("keystorePath", keyStorePath); - - executeRunnableStatusGoMethod(() -> Statusgo.getConnectionStringForBootstrappingAnotherDevice(jsonConfig.toString()), callback); - } - - @ReactMethod - public void inputConnectionStringForBootstrapping(final String connectionString, final String configJSON, final Callback callback) throws JSONException { - final JSONObject jsonConfig = new JSONObject(configJSON); - final JSONObject receiverConfig = jsonConfig.getJSONObject("receiverConfig"); - final String keyStorePath = pathCombine(this.getNoBackupDirectory(), "/keystore"); - receiverConfig.put("keystorePath", keyStorePath); - receiverConfig.getJSONObject("nodeConfig").put("rootDataDir", this.getNoBackupDirectory()); - executeRunnableStatusGoMethod(() -> Statusgo.inputConnectionStringForBootstrapping(connectionString, jsonConfig.toString()), callback); - } - - @ReactMethod - public void multiformatSerializePublicKey(final String multiCodecKey, final String base58btc, final Callback callback) throws JSONException { - if (!checkAvailability()) { - callback.invoke(false); - return; - } - - Runnable runnableTask = new Runnable() { - @Override - public void run() { - String res = Statusgo.multiformatSerializePublicKey(multiCodecKey,base58btc); - callback.invoke(res); - } - }; - - StatusThreadPoolExecutor.getInstance().execute(runnableTask); - } - - @ReactMethod - public void multiformatDeserializePublicKey(final String multiCodecKey, final String base58btc, final Callback callback) throws JSONException { - if (!checkAvailability()) { - callback.invoke(false); - return; - } - - Runnable runnableTask = new Runnable() { - @Override - public void run() { - String res = Statusgo.multiformatDeserializePublicKey(multiCodecKey,base58btc); - callback.invoke(res); - } - }; - - StatusThreadPoolExecutor.getInstance().execute(runnableTask); - } - - @ReactMethod - public void compressPublicKey(final String multiCodecKey, final Callback callback) throws JSONException { - if (!checkAvailability()) { - callback.invoke(false); - return; - } - - Runnable runnableTask = new Runnable() { - @Override - public void run() { - String res = Statusgo.compressPublicKey(multiCodecKey); - callback.invoke(res); - } - }; - - StatusThreadPoolExecutor.getInstance().execute(runnableTask); - } - - @ReactMethod - public void decompressPublicKey(final String multiCodecKey, final Callback callback) throws JSONException { - if (!checkAvailability()) { - callback.invoke(false); - return; - } - - Runnable runnableTask = new Runnable() { - @Override - public void run() { - String res = Statusgo.decompressPublicKey(multiCodecKey); - callback.invoke(res); - } - }; - - StatusThreadPoolExecutor.getInstance().execute(runnableTask); - } - - @ReactMethod - public void deserializeAndCompressKey(final String desktopKey, final Callback callback) throws JSONException { - if (!checkAvailability()) { - callback.invoke(false); - return; - } - - Runnable runnableTask = new Runnable() { - @Override - public void run() { - String res = Statusgo.deserializeAndCompressKey(desktopKey); - callback.invoke(res); - } - }; - - StatusThreadPoolExecutor.getInstance().execute(runnableTask); - } - - @ReactMethod - public void hashTypedData(final String data, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.hashTypedData(data), callback); - } - - @ReactMethod - public void hashTypedDataV4(final String data, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.hashTypedDataV4(data), callback); - } - - @ReactMethod - public void sendTransactionWithSignature(final String txArgsJSON, final String signature, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.sendTransactionWithSignature(txArgsJSON, signature), callback); - } - - @ReactMethod - public void sendTransaction(final String txArgsJSON, final String password, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.sendTransaction(txArgsJSON, password), callback); - } - - @ReactMethod - public void signMessage(final String rpcParams, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.signMessage(rpcParams), callback); - } - - @ReactMethod - public void recover(final String rpcParams, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.recover(rpcParams), callback); - } - - @ReactMethod - public void signTypedData(final String data, final String account, final String password, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.signTypedData(data, account, password), callback); - } - - @ReactMethod - public void signTypedDataV4(final String data, final String account, final String password, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.signTypedDataV4(data, account, password), callback); - - } - - @ReactMethod - public void setAdjustResize() { - Log.d(TAG, "setAdjustResize"); - final Activity activity = getCurrentActivity(); - if (activity == null) { - return; - } - - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); - } - }); - } - - @ReactMethod - public void setAdjustPan() { - Log.d(TAG, "setAdjustPan"); - final Activity activity = getCurrentActivity(); - if (activity == null) { - return; - } - - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); - } - }); - } - - @ReactMethod - public void setSoftInputMode(final int mode) { - Log.d(TAG, "setSoftInputMode"); - final Activity activity = getCurrentActivity(); - if (activity == null) { - return; - } - - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - activity.getWindow().setSoftInputMode(mode); - } - }); - } - - @SuppressWarnings("deprecation") - @ReactMethod - public void clearCookies() { - Log.d(TAG, "clearCookies"); - final Activity activity = getCurrentActivity(); - if (activity == null) { - return; - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { - CookieManager.getInstance().removeAllCookies(null); - CookieManager.getInstance().flush(); - } else { - CookieSyncManager cookieSyncManager = CookieSyncManager.createInstance(activity); - cookieSyncManager.startSync(); - CookieManager cookieManager = CookieManager.getInstance(); - cookieManager.removeAllCookie(); - cookieManager.removeSessionCookie(); - cookieSyncManager.stopSync(); - cookieSyncManager.sync(); - } - } - - @ReactMethod - public void toggleWebviewDebug(final boolean val) { - Log.d(TAG, "toggleWebviewDebug"); - final Activity activity = getCurrentActivity(); - if (activity == null) { - return; - } - - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - WebView.setWebContentsDebuggingEnabled(val); - } - }); - } - - @ReactMethod - public void clearStorageAPIs() { - Log.d(TAG, "clearStorageAPIs"); - final Activity activity = getCurrentActivity(); - if (activity == null) { - return; - } - - WebStorage storage = WebStorage.getInstance(); - if (storage != null) { - storage.deleteAllData(); - } - } - - @ReactMethod - public void callRPC(final String payload, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.callRPC(payload), callback); - } - - @ReactMethod - public void callPrivateRPC(final String payload, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.callPrivateRPC(payload), callback); - } - @ReactMethod public void closeApplication() { System.exit(0); @@ -1108,79 +89,21 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL Statusgo.appStateChange(type); } - @ReactMethod - public void stopLocalNotifications() { - Log.d(TAG, "stopLocalNotifications"); - Statusgo.stopLocalNotifications(); - } - @ReactMethod public void startLocalNotifications() { Log.d(TAG, "startLocalNotifications"); Statusgo.startLocalNotifications(); } - @ReactMethod - public void setBlankPreviewFlag(final Boolean blankPreview) { - final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this.reactContext); - sharedPrefs.edit().putBoolean("BLANK_PREVIEW", blankPreview).commit(); - setSecureFlag(); - } - - private void setSecureFlag() { - final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this.reactContext); - final boolean setSecure = sharedPrefs.getBoolean("BLANK_PREVIEW", true); - final Activity activity = this.reactContext.getCurrentActivity(); - if (activity != null) { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - final Window window = activity.getWindow(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && setSecure) { - window.addFlags(WindowManager.LayoutParams.FLAG_SECURE); - } else { - window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE); - } - } - }); - } - } - - private Boolean is24Hour() { - return android.text.format.DateFormat.is24HourFormat(this.reactContext.getApplicationContext()); - } - - @ReactMethod - public void extractGroupMembershipSignatures(final String signaturePairs, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.extractGroupMembershipSignatures(signaturePairs), callback); - } - - @ReactMethod - public void signGroupMembership(final String content, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.signGroupMembership(content), callback); - } - @ReactMethod public void getNodeConfig(final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.getNodeConfig(), callback); - } - - @ReactMethod - public void deleteMultiaccount(final String keyUID, final Callback callback) throws JSONException { - final String keyStoreDir = this.getKeyStorePath(keyUID); - executeRunnableStatusGoMethod(() -> Statusgo.deleteMultiaccount(keyUID, keyStoreDir), callback); + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.getNodeConfig(), callback); } @ReactMethod public void deleteImportedKey(final String keyUID, final String address, final String password, final Callback callback) throws JSONException { - final String keyStoreDir = this.getKeyStorePath(keyUID); - executeRunnableStatusGoMethod(() -> Statusgo.deleteImportedKey(address, password, keyStoreDir), callback); - } - - @ReactMethod(isBlockingSynchronousMethod = true) - public String keystoreDir() { - final String absRootDirPath = this.getNoBackupDirectory(); - return pathCombine(absRootDirPath, "keystore"); + final String keyStoreDir = this.utils.getKeyStorePath(keyUID); + this.utils.executeRunnableStatusGoMethod(() -> Statusgo.deleteImportedKey(address, password, keyStoreDir), callback); } @ReactMethod(isBlockingSynchronousMethod = true) @@ -1188,83 +111,12 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL return Statusgo.fleets(); } - @ReactMethod(isBlockingSynchronousMethod = true) - public String backupDisabledDataDir() { - return this.getNoBackupDirectory(); - } - - - @ReactMethod(isBlockingSynchronousMethod = true) - public String logFileDirectory() { - return getPublicStorageDirectory().getAbsolutePath(); - } - - @ReactMethod(isBlockingSynchronousMethod = true) - public String encodeTransfer(final String to, final String value) { - return Statusgo.encodeTransfer(to, value); - } - - @ReactMethod(isBlockingSynchronousMethod = true) - public String encodeFunctionCall(final String method, final String paramsJSON) { - return Statusgo.encodeFunctionCall(method, paramsJSON); - } - - @ReactMethod(isBlockingSynchronousMethod = true) - public String decodeParameters(final String decodeParamJSON) { - return Statusgo.decodeParameters(decodeParamJSON); - } - - @ReactMethod(isBlockingSynchronousMethod = true) - public String hexToNumber(final String hex) { - return Statusgo.hexToNumber(hex); - } - - @ReactMethod(isBlockingSynchronousMethod = true) - public String numberToHex(final String numString) { - return Statusgo.numberToHex(numString); - } - - @ReactMethod(isBlockingSynchronousMethod = true) - public String sha3(final String str) { - return Statusgo.sha3(str); - } - - @ReactMethod(isBlockingSynchronousMethod = true) - public String utf8ToHex(final String str) { - return Statusgo.utf8ToHex(str); - } - - @ReactMethod(isBlockingSynchronousMethod = true) - public String hexToUtf8(final String str) { - return Statusgo.hexToUtf8(str); - } - - @ReactMethod(isBlockingSynchronousMethod = true) - public String checkAddressChecksum(final String address) { - return Statusgo.checkAddressChecksum(address); - } - - @ReactMethod(isBlockingSynchronousMethod = true) - public String isAddress(final String address) { - return Statusgo.isAddress(address); - } - - @ReactMethod(isBlockingSynchronousMethod = true) - public String toChecksumAddress(final String address) { - return Statusgo.toChecksumAddress(address); - } - - @ReactMethod - public void identiconAsync(final String seed, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.identicon(seed), callback); - } - @Override public @Nullable Map getConstants() { HashMap constants = new HashMap(); - constants.put("is24Hour", this.is24Hour()); + constants.put("is24Hour", this.utils.is24Hour()); constants.put("model", Build.MODEL); constants.put("brand", Build.BRAND); constants.put("buildId", Build.ID); @@ -1277,25 +129,6 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL callback.invoke(rootedDevice); } - @ReactMethod - public void validateMnemonic(final String seed, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.validateMnemonic(seed), callback); - } - - @ReactMethod - public void activateKeepAwake() { - final Activity activity = getCurrentActivity(); - - if (activity != null) { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - }); - } - } - @ReactMethod public void deactivateKeepAwake() { final Activity activity = getCurrentActivity(); @@ -1310,50 +143,5 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL } } - @ReactMethod - public void resetKeyboardInputCursor(final int reactTagToReset, final int selection) { - UIManagerModule uiManager = getReactApplicationContext().getNativeModule(UIManagerModule.class); - uiManager.addUIBlock(new UIBlock() { - @Override - public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) { - InputMethodManager imm = (InputMethodManager) getReactApplicationContext().getBaseContext().getSystemService(Context.INPUT_METHOD_SERVICE); - if (imm != null) { - View viewToReset = nativeViewHierarchyManager.resolveView(reactTagToReset); - imm.restartInput(viewToReset); - try { - EditText textView = (EditText) viewToReset; - textView.setSelection(selection); - } catch (Exception e) {} - } - } - }); - } - - @ReactMethod - public void reEncryptDbAndKeystore(final String keyUID, final String password, final String newPassword, final Callback callback) throws JSONException { - executeRunnableStatusGoMethod(() -> Statusgo.changeDatabasePassword(keyUID, password, newPassword), callback); - } - - @ReactMethod - public void convertToKeycardAccount(final String keyUID, final String accountData, final String options, final String keycardUID, final String password, - final String newPassword, final Callback callback) throws JSONException { - final String keyStoreDir = this.getKeyStorePath(keyUID); - executeRunnableStatusGoMethod(() -> { - Statusgo.initKeystore(keyStoreDir); - return Statusgo.convertToKeycardAccount(accountData, options, keycardUID, password, newPassword); - }, callback); - } - - @ReactMethod - public void initLogging(final boolean enabled, final boolean mobileSystem, final String logLevel, final Callback callback) throws JSONException { - final JSONObject jsonConfig = new JSONObject(); - jsonConfig.put("Enabled", enabled); - jsonConfig.put("MobileSystem", mobileSystem); - jsonConfig.put("Level", logLevel); - jsonConfig.put("File", getLogsFile().getAbsolutePath()); - final String config = jsonConfig.toString(); - executeRunnableStatusGoMethod(() -> Statusgo.initLogging(config), callback); - } - } diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusPackage.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusPackage.java index debb325796..76874cf176 100644 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusPackage.java +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusPackage.java @@ -30,6 +30,13 @@ public class StatusPackage implements ReactPackage { List modules = new ArrayList<>(); modules.add(new StatusModule(reactContext, this.rootedDevice)); + modules.add(new AccountManager(reactContext)); + modules.add(new EncryptionUtils(reactContext)); + modules.add(new DatabaseManager(reactContext)); + modules.add(new UIHelper(reactContext)); + modules.add(new LogManager(reactContext)); + modules.add(new Utils(reactContext)); + modules.add(new NetworkManager(reactContext)); modules.add(new RNSelectableTextInputModule(reactContext)); return modules; diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/UIHelper.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/UIHelper.java new file mode 100644 index 0000000000..a3a2691a98 --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/UIHelper.java @@ -0,0 +1,124 @@ +package im.status.ethereum.module; + +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import android.app.Activity; +import android.util.Log; +import android.os.Build; +import android.webkit.WebView; +import android.webkit.CookieManager; +import android.webkit.CookieSyncManager; +import android.webkit.WebStorage; +import android.view.WindowManager; +import com.facebook.react.uimanager.UIManagerModule; +import com.facebook.react.uimanager.UIBlock; +import com.facebook.react.uimanager.NativeViewHierarchyManager; +import android.view.inputmethod.InputMethodManager; +import android.view.View; +import android.widget.EditText; +import android.content.Context; + +public class UIHelper extends ReactContextBaseJavaModule { + private static final String TAG = "UIHelper"; + private ReactApplicationContext reactContext; + + public UIHelper(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + } + + @Override + public String getName() { + return "UIHelper"; + } + + @ReactMethod + public void setSoftInputMode(final int mode) { + Log.d(TAG, "setSoftInputMode"); + final Activity activity = getCurrentActivity(); + if (activity == null) { + return; + } + + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + activity.getWindow().setSoftInputMode(mode); + } + }); + } + + @SuppressWarnings("deprecation") + @ReactMethod + public void clearCookies() { + Log.d(TAG, "clearCookies"); + final Activity activity = getCurrentActivity(); + if (activity == null) { + return; + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { + CookieManager.getInstance().removeAllCookies(null); + CookieManager.getInstance().flush(); + } else { + CookieSyncManager cookieSyncManager = CookieSyncManager.createInstance(activity); + cookieSyncManager.startSync(); + CookieManager cookieManager = CookieManager.getInstance(); + cookieManager.removeAllCookie(); + cookieManager.removeSessionCookie(); + cookieSyncManager.stopSync(); + cookieSyncManager.sync(); + } + } + + @ReactMethod + public void toggleWebviewDebug(final boolean val) { + Log.d(TAG, "toggleWebviewDebug"); + final Activity activity = getCurrentActivity(); + if (activity == null) { + return; + } + + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + WebView.setWebContentsDebuggingEnabled(val); + } + }); + } + + @ReactMethod + public void clearStorageAPIs() { + Log.d(TAG, "clearStorageAPIs"); + final Activity activity = getCurrentActivity(); + if (activity == null) { + return; + } + + WebStorage storage = WebStorage.getInstance(); + if (storage != null) { + storage.deleteAllData(); + } + } + + @ReactMethod + public void resetKeyboardInputCursor(final int reactTagToReset, final int selection) { + UIManagerModule uiManager = getReactApplicationContext().getNativeModule(UIManagerModule.class); + uiManager.addUIBlock(new UIBlock() { + @Override + public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) { + InputMethodManager imm = (InputMethodManager) getReactApplicationContext().getBaseContext().getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + View viewToReset = nativeViewHierarchyManager.resolveView(reactTagToReset); + imm.restartInput(viewToReset); + try { + EditText textView = (EditText) viewToReset; + textView.setSelection(selection); + } catch (Exception e) {} + } + } + }); + } + +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/Utils.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/Utils.java new file mode 100644 index 0000000000..0cbb057e1d --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/Utils.java @@ -0,0 +1,155 @@ +package im.status.ethereum.module; + +import com.facebook.react.bridge.Callback; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import android.util.Log; +import java.util.function.Supplier; +import java.io.File; +import android.content.Context; +import android.os.Environment; +import org.json.JSONObject; +import org.json.JSONException; +import statusgo.Statusgo; + +public class Utils extends ReactContextBaseJavaModule { + private static final String gethLogFileName = "geth.log"; + + private static final String TAG = "Utils"; + private ReactApplicationContext reactContext; + + public Utils(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + } + + @Override + public String getName() { + return "Utils"; + } + public String getNoBackupDirectory() { + return this.getReactApplicationContext().getNoBackupFilesDir().getAbsolutePath(); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public String backupDisabledDataDir() { + return getNoBackupDirectory(); + } + + public File getPublicStorageDirectory() { + final Context context = this.getReactApplicationContext(); + // Environment.getExternalStoragePublicDirectory doesn't work as expected on Android Q + // https://developer.android.com/reference/android/os/Environment#getExternalStoragePublicDirectory(java.lang.String) + return context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS); + } + + public File getLogsFile() { + final File pubDirectory = getPublicStorageDirectory(); + final File logFile = new File(pubDirectory, gethLogFileName); + + return logFile; + } + + public String getKeyUID(final String json) throws JSONException { + final JSONObject jsonObj = new JSONObject(json); + return jsonObj.getString("key-uid"); + } + + public String pathCombine(final String path1, final String path2) { + // Replace this logic with Paths.get(path1, path2) once API level 26+ becomes the minimum supported API level + final File file = new File(path1, path2); + return file.getAbsolutePath(); + } + + public String getKeyStorePath(String keyUID) { + final String commonKeydir = pathCombine(getNoBackupDirectory(), "/keystore"); + final String keydir = pathCombine(commonKeydir, keyUID); + + return keydir; + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public String keystoreDir() { + final String absRootDirPath = getNoBackupDirectory(); + return pathCombine(absRootDirPath, "keystore"); + } + + public void migrateKeyStoreDir(final String accountData, final String password) { + try { + final String commonKeydir = pathCombine(getNoBackupDirectory(), "/keystore"); + final String keydir = getKeyStorePath(getKeyUID(accountData)); + Log.d(TAG, "before migrateKeyStoreDir " + keydir); + + File keydirFile = new File(keydir); + if(!keydirFile.exists() || keydirFile.list().length == 0) { + Log.d(TAG, "migrateKeyStoreDir"); + Statusgo.migrateKeyStoreDir(accountData, password, commonKeydir, keydir); + Statusgo.initKeystore(keydir); + } + } catch (JSONException e) { + Log.e(TAG, "JSON conversion failed: " + e.getMessage()); + } + } + + public boolean checkAvailability() { + // We wait at least 10s for getCurrentActivity to return a value, + // otherwise we give up + for (int attempts = 0; attempts < 100; attempts++) { + if (getCurrentActivity() != null) { + return true; + } + try { + Thread.sleep(100); + } catch (InterruptedException ex) { + if (getCurrentActivity() != null) { + return true; + } + Log.d(TAG, "Activity doesn't exist"); + return false; + } + } + + Log.d(TAG, "Activity doesn't exist"); + return false; + } + + public void executeRunnableStatusGoMethod(Supplier method, Callback callback) throws JSONException { + if (!checkAvailability()) { + callback.invoke(false); + return; + } + + Runnable runnableTask = () -> { + String res = method.get(); + callback.invoke(res); + }; + + StatusThreadPoolExecutor.getInstance().execute(runnableTask); + } + + @ReactMethod + public void validateMnemonic(final String seed, final Callback callback) throws JSONException { + executeRunnableStatusGoMethod(() -> Statusgo.validateMnemonic(seed), callback); + } + + public Boolean is24Hour() { + return android.text.format.DateFormat.is24HourFormat(this.reactContext.getApplicationContext()); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public String checkAddressChecksum(final String address) { + return Statusgo.checkAddressChecksum(address); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public String isAddress(final String address) { + return Statusgo.isAddress(address); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public String toChecksumAddress(final String address) { + return Statusgo.toChecksumAddress(address); + } + +} diff --git a/modules/react-native-status/ios/RCTStatus/AccountManager.h b/modules/react-native-status/ios/RCTStatus/AccountManager.h new file mode 100644 index 0000000000..7698eebe02 --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/AccountManager.h @@ -0,0 +1,9 @@ +#import +#import +#import +#import "Statusgo.h" +#import "RCTLog.h" + +@interface AccountManager : NSObject + +@end diff --git a/modules/react-native-status/ios/RCTStatus/AccountManager.m b/modules/react-native-status/ios/RCTStatus/AccountManager.m new file mode 100644 index 0000000000..01d5560187 --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/AccountManager.m @@ -0,0 +1,217 @@ +#import "AccountManager.h" +#import "React/RCTBridge.h" +#import "React/RCTEventDispatcher.h" +#import "Statusgo.h" +#import "Utils.h" + +@implementation AccountManager + +RCT_EXPORT_MODULE(); + +RCT_EXPORT_METHOD(createAccountAndLogin:(NSString *)request) { +#if DEBUG + NSLog(@"createAccountAndLogin() method called"); +#endif + StatusgoCreateAccountAndLogin(request); +} + +RCT_EXPORT_METHOD(restoreAccountAndLogin:(NSString *)request) { +#if DEBUG + NSLog(@"restoreAccountAndLogin() method called"); +#endif + StatusgoRestoreAccountAndLogin(request); +} + +-(NSString *) prepareDirAndUpdateConfig:(NSString *)config + withKeyUID:(NSString *)keyUID { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + NSURL *rootUrl =[[fileManager + URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] + lastObject]; + NSURL *absTestnetFolderName = [rootUrl URLByAppendingPathComponent:@"ethereum/testnet"]; + + if (![fileManager fileExistsAtPath:absTestnetFolderName.path]) + [fileManager createDirectoryAtPath:absTestnetFolderName.path withIntermediateDirectories:YES attributes:nil error:&error]; + + NSURL *flagFolderUrl = [rootUrl URLByAppendingPathComponent:@"ropsten_flag"]; + + if(![fileManager fileExistsAtPath:flagFolderUrl.path]){ + NSLog(@"remove lightchaindata"); + NSURL *absLightChainDataUrl = [absTestnetFolderName URLByAppendingPathComponent:@"StatusIM/lightchaindata"]; + if([fileManager fileExistsAtPath:absLightChainDataUrl.path]) { + [fileManager removeItemAtPath:absLightChainDataUrl.path + error:nil]; + } + [fileManager createDirectoryAtPath:flagFolderUrl.path + withIntermediateDirectories:NO + attributes:nil + error:&error]; + } + + NSLog(@"after remove lightchaindata"); + + NSString *keystore = @"keystore"; + NSURL *absTestnetKeystoreUrl = [absTestnetFolderName URLByAppendingPathComponent:keystore]; + NSURL *absKeystoreUrl = [rootUrl URLByAppendingPathComponent:keystore]; + if([fileManager fileExistsAtPath:absTestnetKeystoreUrl.path]){ + NSLog(@"copy keystore"); + [fileManager copyItemAtPath:absTestnetKeystoreUrl.path toPath:absKeystoreUrl.path error:nil]; + [fileManager removeItemAtPath:absTestnetKeystoreUrl.path error:nil]; + } + + NSLog(@"after lightChainData"); + + NSLog(@"preconfig: %@", config); + NSData *configData = [config dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary *configJSON = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:nil]; + NSString *relativeDataDir = [configJSON objectForKey:@"DataDir"]; + NSString *absDataDir = [rootUrl.path stringByAppendingString:relativeDataDir]; + NSURL *absDataDirUrl = [NSURL fileURLWithPath:absDataDir]; + NSString *keystoreDir = [@"/keystore/" stringByAppendingString:keyUID]; + [configJSON setValue:keystoreDir forKey:@"KeyStoreDir"]; + [configJSON setValue:@"" forKey:@"LogDir"]; + [configJSON setValue:@"geth.log" forKey:@"LogFile"]; + NSString *resultingConfig = [Utils jsonStringWithPrettyPrint:NO fromDictionary:configJSON]; + + NSLog(@"node config %@", resultingConfig); + + if(![fileManager fileExistsAtPath:absDataDir]) { + [fileManager createDirectoryAtPath:absDataDir + withIntermediateDirectories:YES attributes:nil error:nil]; + } + + NSLog(@"logUrlPath %@ rootDir %@", @"geth.log", rootUrl.path); + NSURL *absLogUrl = [absDataDirUrl URLByAppendingPathComponent:@"geth.log"]; + if(![fileManager fileExistsAtPath:absLogUrl.path]) { + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + [dict setObject:[NSNumber numberWithInt:511] forKey:NSFilePosixPermissions]; + [fileManager createFileAtPath:absLogUrl.path contents:nil attributes:dict]; + } + + return resultingConfig; + +} + +RCT_EXPORT_METHOD(deleteMultiaccount:(NSString *)keyUID + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"DeleteMultiaccount() method called"); +#endif + NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID]; + NSString *result = StatusgoDeleteMultiaccount(keyUID, multiaccountKeystoreDir.path); + callback(@[result]); +} + +RCT_EXPORT_METHOD(prepareDirAndUpdateConfig:(NSString *)keyUID + config:(NSString *)config + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"PrepareDirAndUpdateConfig() method called"); +#endif + NSString *updatedConfig = [self prepareDirAndUpdateConfig:config + withKeyUID:keyUID]; + callback(@[updatedConfig]); +} + +RCT_EXPORT_METHOD(saveAccountAndLoginWithKeycard:(NSString *)multiaccountData + password:(NSString *)password + settings:(NSString *)settings + config:(NSString *)config + accountsData:(NSString *)accountsData + chatKey:(NSString *)chatKey) { +#if DEBUG + NSLog(@"SaveAccountAndLoginWithKeycard() method called"); +#endif + [Utils getExportDbFilePath]; + NSString *keyUID = [Utils getKeyUID:multiaccountData]; + NSString *finalConfig = [self prepareDirAndUpdateConfig:config + withKeyUID:keyUID]; + NSString *result = StatusgoSaveAccountAndLoginWithKeycard(multiaccountData, password, settings, finalConfig, accountsData, chatKey); + NSLog(@"%@", result); +} + +RCT_EXPORT_METHOD(loginWithKeycard:(NSString *)accountData + password:(NSString *)password + chatKey:(NSString *)chatKey + nodeConfigJSON:(NSString *)nodeConfigJSON) { +#if DEBUG + NSLog(@"LoginWithKeycard() method called"); +#endif + [Utils getExportDbFilePath]; + [Utils migrateKeystore:accountData password:password]; + + NSString *result = StatusgoLoginWithKeycard(accountData, password, chatKey, nodeConfigJSON); + + NSLog(@"%@", result); +} + +RCT_EXPORT_METHOD(loginWithConfig:(NSString *)accountData + password:(NSString *)password + configJSON:(NSString *)configJSON) { +#if DEBUG + NSLog(@"LoginWithConfig() method called"); +#endif + [Utils getExportDbFilePath]; + [Utils migrateKeystore:accountData password:password]; + NSString *result = StatusgoLoginWithConfig(accountData, password, configJSON); + NSLog(@"%@", result); +} + +RCT_EXPORT_METHOD(loginAccount:(NSString *)request) { +#if DEBUG + NSLog(@"LoginAccount() method called"); +#endif + NSString *result = StatusgoLoginAccount(request); + NSLog(@"%@", result); +} + +RCT_EXPORT_METHOD(verify:(NSString *)address + password:(NSString *)password + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"VerifyAccountPassword() method called"); +#endif + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *rootUrl =[[fileManager + URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] + lastObject]; + NSURL *absKeystoreUrl = [rootUrl URLByAppendingPathComponent:@"keystore"]; + + NSString *result = StatusgoVerifyAccountPassword(absKeystoreUrl.path, address, password); + callback(@[result]); +} + +RCT_EXPORT_METHOD(verifyDatabasePassword:(NSString *)keyUID + password:(NSString *)password + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"VerifyDatabasePassword() method called"); +#endif + NSString *result = StatusgoVerifyDatabasePassword(keyUID, password); + callback(@[result]); +} + +RCT_EXPORT_METHOD(openAccounts:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"OpenAccounts() method called"); +#endif + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *rootUrl =[[fileManager + URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] + lastObject]; + + NSString *result = StatusgoOpenAccounts(rootUrl.path); + callback(@[result]); +} + +RCT_EXPORT_METHOD(logout) { +#if DEBUG + NSLog(@"Logout() method called"); +#endif + NSString *result = StatusgoLogout(); + + NSLog(@"%@", result); +} + +@end diff --git a/modules/react-native-status/ios/RCTStatus/DatabaseManager.h b/modules/react-native-status/ios/RCTStatus/DatabaseManager.h new file mode 100644 index 0000000000..7ff6e7dac5 --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/DatabaseManager.h @@ -0,0 +1,9 @@ +#import +#import +#import +#import "Statusgo.h" +#import "RCTLog.h" + +@interface DatabaseManager : NSObject + +@end diff --git a/modules/react-native-status/ios/RCTStatus/DatabaseManager.m b/modules/react-native-status/ios/RCTStatus/DatabaseManager.m new file mode 100644 index 0000000000..69581bee07 --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/DatabaseManager.m @@ -0,0 +1,33 @@ +#import "DatabaseManager.h" +#import "React/RCTBridge.h" +#import "React/RCTEventDispatcher.h" +#import "Statusgo.h" +#import "Utils.h" + +@implementation DatabaseManager + +RCT_EXPORT_MODULE(); + +RCT_EXPORT_METHOD(exportUnencryptedDatabase:(NSString *)accountData + password:(NSString *)password + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"exportUnencryptedDatabase() method called"); +#endif + + NSString *filePath = [Utils getExportDbFilePath]; + StatusgoExportUnencryptedDatabase(accountData, password, filePath); + + callback(@[filePath]); +} + +RCT_EXPORT_METHOD(importUnencryptedDatabase:(NSString *)accountData + password:(NSString *)password) { +#if DEBUG + NSLog(@"importUnencryptedDatabase() method called"); +#endif + ""; +} + + +@end diff --git a/modules/react-native-status/ios/RCTStatus/EncryptionUtils.h b/modules/react-native-status/ios/RCTStatus/EncryptionUtils.h new file mode 100644 index 0000000000..29fa9a1703 --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/EncryptionUtils.h @@ -0,0 +1,9 @@ +#import +#import +#import +#import "Statusgo.h" +#import "RCTLog.h" + +@interface EncryptionUtils : NSObject + +@end diff --git a/modules/react-native-status/ios/RCTStatus/EncryptionUtils.m b/modules/react-native-status/ios/RCTStatus/EncryptionUtils.m new file mode 100644 index 0000000000..99dbf91036 --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/EncryptionUtils.m @@ -0,0 +1,200 @@ +#import "EncryptionUtils.h" +#import "React/RCTBridge.h" +#import "React/RCTEventDispatcher.h" +#import "Statusgo.h" +#import "Utils.h" + +@implementation EncryptionUtils + +RCT_EXPORT_MODULE(); + +#pragma mark - InitKeystore method + +RCT_EXPORT_METHOD(initKeystore:(NSString *)keyUID + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"initKeystore() method called"); +#endif + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *rootUrl =[[fileManager + URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] + lastObject]; + + NSURL *commonKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"]; + NSURL *keystoreDir = [commonKeystoreDir URLByAppendingPathComponent:keyUID]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), + ^(void) + { + NSString *res = StatusgoInitKeystore(keystoreDir.path); + NSLog(@"InitKeyStore result %@", res); + callback(@[]); + }); +} + +RCT_EXPORT_METHOD(reEncryptDbAndKeystore:(NSString *)keyUID + currentPassword:(NSString *)currentPassword + newPassword:(NSString *)newPassword + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"reEncryptDbAndKeystore() method called"); +#endif + // changes password and re-encrypts keystore + NSString *result = StatusgoChangeDatabasePassword(keyUID, currentPassword, newPassword); + callback(@[result]); +} + +RCT_EXPORT_METHOD(convertToKeycardAccount:(NSString *)keyUID + accountData:(NSString *)accountData + settings:(NSString *)settings + keycardUID:(NSString *)keycardUID + currentPassword:(NSString *)currentPassword + newPassword:(NSString *)newPassword + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"convertToKeycardAccount() method called"); +#endif + NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID]; + StatusgoInitKeystore(multiaccountKeystoreDir.path); + NSString *result = StatusgoConvertToKeycardAccount(accountData, settings, keycardUID, currentPassword, newPassword); + callback(@[result]); +} + +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(encodeTransfer:(NSString *)to + value:(NSString *)value) { + return StatusgoEncodeTransfer(to,value); +} + +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(encodeFunctionCall:(NSString *)method + paramsJSON:(NSString *)paramsJSON) { + return StatusgoEncodeFunctionCall(method,paramsJSON); +} + +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(decodeParameters:(NSString *)decodeParamJSON) { + return StatusgoDecodeParameters(decodeParamJSON); +} + +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(hexToNumber:(NSString *)hex) { + return StatusgoHexToNumber(hex); +} + +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(numberToHex:(NSString *)numString) { + return StatusgoNumberToHex(numString); +} + +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(sha3:(NSString *)str) { + return StatusgoSha3(str); +} + +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(utf8ToHex:(NSString *)str) { + return StatusgoUtf8ToHex(str); +} + +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(hexToUtf8:(NSString *)str) { + return StatusgoHexToUtf8(str); +} + +RCT_EXPORT_METHOD(setBlankPreviewFlag:(BOOL *)newValue) +{ + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + + [userDefaults setBool:newValue forKey:@"BLANK_PREVIEW"]; + + [userDefaults synchronize]; +} + +RCT_EXPORT_METHOD(hashTransaction:(NSString *)txArgsJSON + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"HashTransaction() method called"); +#endif + NSString *result = StatusgoHashTransaction(txArgsJSON); + callback(@[result]); +} + +RCT_EXPORT_METHOD(hashMessage:(NSString *)message + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"hashMessage() method called"); +#endif + NSString *result = StatusgoHashMessage(message); + callback(@[result]); +} + +RCT_EXPORT_METHOD(localPairingPreflightOutboundCheck:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"LocalPairingPreflightOutboundCheck() method called"); +#endif + NSString *result = StatusgoLocalPairingPreflightOutboundCheck(); + callback(@[result]); +} + +RCT_EXPORT_METHOD(multiformatDeserializePublicKey:(NSString *)multiCodecKey + base58btc:(NSString *)base58btc + callback:(RCTResponseSenderBlock)callback) { + NSString *result = StatusgoMultiformatDeserializePublicKey(multiCodecKey,base58btc); + callback(@[result]); +} + +RCT_EXPORT_METHOD(deserializeAndCompressKey:(NSString *)desktopKey + callback:(RCTResponseSenderBlock)callback) { + NSString *result = StatusgoDeserializeAndCompressKey(desktopKey); + callback(@[result]); +} + +RCT_EXPORT_METHOD(hashTypedData:(NSString *)data + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"hashTypedData() method called"); +#endif + NSString *result = StatusgoHashTypedData(data); + callback(@[result]); +} + +RCT_EXPORT_METHOD(hashTypedDataV4:(NSString *)data + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"hashTypedDataV4() method called"); +#endif + NSString *result = StatusgoHashTypedDataV4(data); + callback(@[result]); +} + +#pragma mark - SignMessage + +RCT_EXPORT_METHOD(signMessage:(NSString *)message + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"SignMessage() method called"); +#endif + NSString *result = StatusgoSignMessage(message); + callback(@[result]); +} + +#pragma mark - SignTypedData + +RCT_EXPORT_METHOD(signTypedData:(NSString *)data + account:(NSString *)account + password:(NSString *)password + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"SignTypedData() method called"); +#endif + NSString *result = StatusgoSignTypedData(data, account, password); + callback(@[result]); +} + +#pragma mark - SignTypedDataV4 + +RCT_EXPORT_METHOD(signTypedDataV4:(NSString *)data + account:(NSString *)account + password:(NSString *)password + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"SignTypedDataV4() method called"); +#endif + NSString *result = StatusgoSignTypedDataV4(data, account, password); + callback(@[result]); +} + +@end diff --git a/modules/react-native-status/ios/RCTStatus/LogManager.h b/modules/react-native-status/ios/RCTStatus/LogManager.h new file mode 100644 index 0000000000..a7a264f988 --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/LogManager.h @@ -0,0 +1,9 @@ +#import +#import +#import +#import "Statusgo.h" +#import "RCTLog.h" + +@interface LogManager : NSObject + +@end diff --git a/modules/react-native-status/ios/RCTStatus/LogManager.m b/modules/react-native-status/ios/RCTStatus/LogManager.m new file mode 100644 index 0000000000..1a5740b571 --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/LogManager.m @@ -0,0 +1,115 @@ +#import "LogManager.h" +#import "React/RCTBridge.h" +#import "React/RCTEventDispatcher.h" +#import "Statusgo.h" +#import "Utils.h" +#import "SSZipArchive.h" + +@implementation LogManager + +RCT_EXPORT_MODULE(); + +#pragma mark - SendLogs method + +RCT_EXPORT_METHOD(sendLogs:(NSString *)dbJson + jsLogs:(NSString *)jsLogs + callback:(RCTResponseSenderBlock)callback) { + // TODO: Implement SendLogs for iOS +#if DEBUG + NSLog(@"SendLogs() method called, not implemented"); +#endif + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + NSURL *rootUrl =[[fileManager + URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] + lastObject]; + + NSURL *zipFile = [rootUrl URLByAppendingPathComponent:@"logs.zip"]; + [fileManager removeItemAtPath:zipFile.path error:nil]; + + NSURL *logsFolderName = [rootUrl URLByAppendingPathComponent:@"logs"]; + + if (![fileManager fileExistsAtPath:logsFolderName.path]) + [fileManager createDirectoryAtPath:logsFolderName.path withIntermediateDirectories:YES attributes:nil error:&error]; + + NSURL *dbFile = [logsFolderName URLByAppendingPathComponent:@"db.json"]; + NSURL *jsLogsFile = [logsFolderName URLByAppendingPathComponent:@"Status.log"]; +#if DEBUG + NSString *networkDirPath = @"ethereum/mainnet_rpc_dev"; +#else + NSString *networkDirPath = @"ethereum/mainnet_rpc"; +#endif + +#if DEBUG + NSString *goerliNetworkDirPath = @"ethereum/goerli_rpc_dev"; +#else + NSString *goerliNetworkDirPath = @"ethereum/goerli_rpc"; +#endif + + NSURL *networkDir = [rootUrl URLByAppendingPathComponent:networkDirPath]; + NSURL *originalGethLogsFile = [networkDir URLByAppendingPathComponent:@"geth.log"]; + NSURL *gethLogsFile = [logsFolderName URLByAppendingPathComponent:@"mainnet_geth.log"]; + + NSURL *goerliNetworkDir = [rootUrl URLByAppendingPathComponent:goerliNetworkDirPath]; + NSURL *goerliGethLogsFile = [goerliNetworkDir URLByAppendingPathComponent:@"geth.log"]; + NSURL *goerliLogsFile = [logsFolderName URLByAppendingPathComponent:@"goerli_geth.log"]; + + NSURL *mainGethLogsFile = [rootUrl URLByAppendingPathComponent:@"geth.log"]; + NSURL *mainLogsFile = [logsFolderName URLByAppendingPathComponent:@"geth.log"]; + + [dbJson writeToFile:dbFile.path atomically:YES encoding:NSUTF8StringEncoding error:nil]; + [jsLogs writeToFile:jsLogsFile.path atomically:YES encoding:NSUTF8StringEncoding error:nil]; + + //NSString* gethLogs = StatusgoExportNodeLogs(); + //[gethLogs writeToFile:gethLogsFile.path atomically:YES encoding:NSUTF8StringEncoding error:nil]; + [fileManager copyItemAtPath:originalGethLogsFile.path toPath:gethLogsFile.path error:nil]; + [fileManager copyItemAtPath:goerliGethLogsFile.path toPath:goerliLogsFile.path error:nil]; + [fileManager copyItemAtPath:mainGethLogsFile.path toPath:mainLogsFile.path error:nil]; + + [SSZipArchive createZipFileAtPath:zipFile.path withContentsOfDirectory:logsFolderName.path]; + [fileManager removeItemAtPath:logsFolderName.path error:nil]; + + callback(@[zipFile.absoluteString]); +} + +RCT_EXPORT_METHOD(initLogging:(BOOL)enabled + mobileSystem:(BOOL)mobileSystem + logLevel:(NSString *)logLevel + callback:(RCTResponseSenderBlock)callback) +{ + NSString *logDirectory = [self logFileDirectory]; + NSString *logFilePath = [logDirectory stringByAppendingPathComponent:@"geth.log"]; + + NSMutableDictionary *jsonConfig = [NSMutableDictionary dictionary]; + jsonConfig[@"Enabled"] = @(enabled); + jsonConfig[@"MobileSystem"] = @(mobileSystem); + jsonConfig[@"Level"] = logLevel; + jsonConfig[@"File"] = logFilePath; + + NSError *error = nil; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonConfig options:0 error:&error]; + + if (error) { + // Handle JSON serialization error + callback(@[error.localizedDescription]); + return; + } + + NSString *config = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + + // Call your native logging initialization method here + NSString *initResult = StatusgoInitLogging(config); + + callback(@[initResult]); +} + +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(logFileDirectory) { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *rootUrl =[[fileManager + URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] + lastObject]; + return rootUrl.path; +} + + +@end diff --git a/modules/react-native-status/ios/RCTStatus/NetworkManager.h b/modules/react-native-status/ios/RCTStatus/NetworkManager.h new file mode 100644 index 0000000000..cc8ce42f98 --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/NetworkManager.h @@ -0,0 +1,9 @@ +#import +#import +#import +#import "Statusgo.h" +#import "RCTLog.h" + +@interface NetworkManager : NSObject + +@end diff --git a/modules/react-native-status/ios/RCTStatus/NetworkManager.m b/modules/react-native-status/ios/RCTStatus/NetworkManager.m new file mode 100644 index 0000000000..c82448be72 --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/NetworkManager.m @@ -0,0 +1,109 @@ +#import "NetworkManager.h" +#import "React/RCTBridge.h" +#import "React/RCTEventDispatcher.h" +#import "Statusgo.h" +#import "Utils.h" + +@implementation NetworkManager + +RCT_EXPORT_MODULE(); + +RCT_EXPORT_METHOD(startSearchForLocalPairingPeers:(RCTResponseSenderBlock)callback) { + NSString *result = StatusgoStartSearchForLocalPairingPeers(); + callback(@[result]); +} + +RCT_EXPORT_METHOD(getConnectionStringForBootstrappingAnotherDevice:(NSString *)configJSON + callback:(RCTResponseSenderBlock)callback) { + + NSData *configData = [configJSON dataUsingEncoding:NSUTF8StringEncoding]; + NSError *error; + NSMutableDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:&error]; + NSMutableDictionary *senderConfig = configDict[@"senderConfig"]; + NSString *keyUID = senderConfig[@"keyUID"]; + NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID]; + NSString *keystoreDir = multiaccountKeystoreDir.path; + + [senderConfig setValue:keystoreDir forKey:@"keystorePath"]; + NSString *modifiedConfigJSON = [Utils jsonStringWithPrettyPrint:NO fromDictionary:configDict]; + + NSString *result = StatusgoGetConnectionStringForBootstrappingAnotherDevice(modifiedConfigJSON); + callback(@[result]); +} + +RCT_EXPORT_METHOD(inputConnectionStringForBootstrapping:(NSString *)cs + configJSON:(NSString *)configJSON + callback:(RCTResponseSenderBlock)callback) { + + NSData *configData = [configJSON dataUsingEncoding:NSUTF8StringEncoding]; + NSError *error; + NSMutableDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:&error]; + NSMutableDictionary *receiverConfig = configDict[@"receiverConfig"]; + NSMutableDictionary *nodeConfig = receiverConfig[@"nodeConfig"]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *rootUrl =[[fileManager URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject]; + NSURL *multiaccountKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"]; + NSString *keystoreDir = multiaccountKeystoreDir.path; + NSString *rootDataDir = rootUrl.path; + + [receiverConfig setValue:keystoreDir forKey:@"keystorePath"]; + [nodeConfig setValue:rootDataDir forKey:@"rootDataDir"]; + NSString *modifiedConfigJSON = [Utils jsonStringWithPrettyPrint:NO fromDictionary:configDict]; + NSString *result = StatusgoInputConnectionStringForBootstrapping(cs, modifiedConfigJSON); + callback(@[result]); +} + +RCT_EXPORT_METHOD(sendTransactionWithSignature:(NSString *)txArgsJSON + signature:(NSString *)signature + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"sendTransactionWithSignature() method called"); +#endif + NSString *result = StatusgoSendTransactionWithSignature(txArgsJSON, signature); + callback(@[result]); +} + +#pragma mark - SendTransaction + +RCT_EXPORT_METHOD(sendTransaction:(NSString *)txArgsJSON + password:(NSString *)password + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"SendTransaction() method called"); +#endif + NSString *result = StatusgoSendTransaction(txArgsJSON, password); + callback(@[result]); +} + +RCT_EXPORT_METHOD(callRPC:(NSString *)payload + callback:(RCTResponseSenderBlock)callback) { + dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSString *result = StatusgoCallRPC(payload); + dispatch_async(dispatch_get_main_queue(), ^{ + callback(@[result]); + }); + }); +} + +RCT_EXPORT_METHOD(callPrivateRPC:(NSString *)payload + callback:(RCTResponseSenderBlock)callback) { + dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSString *result = StatusgoCallPrivateRPC(payload); + dispatch_async(dispatch_get_main_queue(), ^{ + callback(@[result]); + }); + }); +} + +#pragma mark - Recover + +RCT_EXPORT_METHOD(recover:(NSString *)message + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"Recover() method called"); +#endif + NSString *result = StatusgoRecover(message); + callback(@[result]); +} + +@end diff --git a/modules/react-native-status/ios/RCTStatus/RCTStatus.m b/modules/react-native-status/ios/RCTStatus/RCTStatus.m index dd064ac784..d3a9360182 100644 --- a/modules/react-native-status/ios/RCTStatus/RCTStatus.m +++ b/modules/react-native-status/ios/RCTStatus/RCTStatus.m @@ -2,48 +2,8 @@ #import "React/RCTBridge.h" #import "React/RCTEventDispatcher.h" #import "Statusgo.h" -#import "SSZipArchive.h" -@interface NSDictionary (BVJSONString) --(NSString*) bv_jsonStringWithPrettyPrint:(BOOL) prettyPrint; -@end - -@implementation NSDictionary (BVJSONString) - --(NSString*) bv_jsonStringWithPrettyPrint:(BOOL) prettyPrint { - NSError *error; - NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self - options:(NSJSONWritingOptions) (prettyPrint ? NSJSONWritingPrettyPrinted : 0) - error:&error]; - - if (! jsonData) { - NSLog(@"bv_jsonStringWithPrettyPrint: error: %@", error.localizedDescription); - return @"{}"; - } else { - return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; - } -} -@end - -@interface NSArray (BVJSONString) -- (NSString *)bv_jsonStringWithPrettyPrint:(BOOL)prettyPrint; -@end - -@implementation NSArray (BVJSONString) --(NSString*) bv_jsonStringWithPrettyPrint:(BOOL) prettyPrint { - NSError *error; - NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self - options:(NSJSONWritingOptions) (prettyPrint ? NSJSONWritingPrettyPrinted : 0) - error:&error]; - - if (! jsonData) { - NSLog(@"bv_jsonStringWithPrettyPrint: error: %@", error.localizedDescription); - return @"[]"; - } else { - return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; - } -} -@end +#import "Utils.h" static RCTBridge *bridge; @@ -96,7 +56,6 @@ RCT_EXPORT_METHOD(shouldMoveToInternalStorage:(RCTResponseSenderBlock)onResultCa onResultCallback(@[[NSNull null]]); } - #pragma mark - moveToInternalStorage RCT_EXPORT_METHOD(moveToInternalStorage:(RCTResponseSenderBlock)onResultCallback) { @@ -104,96 +63,6 @@ RCT_EXPORT_METHOD(moveToInternalStorage:(RCTResponseSenderBlock)onResultCallback onResultCallback(@[[NSNull null]]); } - - -#pragma mark - InitKeystore method - -RCT_EXPORT_METHOD(initKeystore:(NSString *)keyUID - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"initKeystore() method called"); -#endif - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSURL *rootUrl =[[fileManager - URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] - lastObject]; - - NSURL *commonKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"]; - NSURL *keystoreDir = [commonKeystoreDir URLByAppendingPathComponent:keyUID]; - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), - ^(void) - { - NSString *res = StatusgoInitKeystore(keystoreDir.path); - NSLog(@"InitKeyStore result %@", res); - callback(@[]); - }); -} - - -#pragma mark - SendLogs method - -RCT_EXPORT_METHOD(sendLogs:(NSString *)dbJson - jsLogs:(NSString *)jsLogs - callback:(RCTResponseSenderBlock)callback) { - // TODO: Implement SendLogs for iOS -#if DEBUG - NSLog(@"SendLogs() method called, not implemented"); -#endif - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSError *error = nil; - NSURL *rootUrl =[[fileManager - URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] - lastObject]; - - NSURL *zipFile = [rootUrl URLByAppendingPathComponent:@"logs.zip"]; - [fileManager removeItemAtPath:zipFile.path error:nil]; - - NSURL *logsFolderName = [rootUrl URLByAppendingPathComponent:@"logs"]; - - if (![fileManager fileExistsAtPath:logsFolderName.path]) - [fileManager createDirectoryAtPath:logsFolderName.path withIntermediateDirectories:YES attributes:nil error:&error]; - - NSURL *dbFile = [logsFolderName URLByAppendingPathComponent:@"db.json"]; - NSURL *jsLogsFile = [logsFolderName URLByAppendingPathComponent:@"Status.log"]; -#if DEBUG - NSString *networkDirPath = @"ethereum/mainnet_rpc_dev"; -#else - NSString *networkDirPath = @"ethereum/mainnet_rpc"; -#endif - -#if DEBUG - NSString *goerliNetworkDirPath = @"ethereum/goerli_rpc_dev"; -#else - NSString *goerliNetworkDirPath = @"ethereum/goerli_rpc"; -#endif - - NSURL *networkDir = [rootUrl URLByAppendingPathComponent:networkDirPath]; - NSURL *originalGethLogsFile = [networkDir URLByAppendingPathComponent:@"geth.log"]; - NSURL *gethLogsFile = [logsFolderName URLByAppendingPathComponent:@"mainnet_geth.log"]; - - NSURL *goerliNetworkDir = [rootUrl URLByAppendingPathComponent:goerliNetworkDirPath]; - NSURL *goerliGethLogsFile = [goerliNetworkDir URLByAppendingPathComponent:@"geth.log"]; - NSURL *goerliLogsFile = [logsFolderName URLByAppendingPathComponent:@"goerli_geth.log"]; - - NSURL *mainGethLogsFile = [rootUrl URLByAppendingPathComponent:@"geth.log"]; - NSURL *mainLogsFile = [logsFolderName URLByAppendingPathComponent:@"geth.log"]; - - [dbJson writeToFile:dbFile.path atomically:YES encoding:NSUTF8StringEncoding error:nil]; - [jsLogs writeToFile:jsLogsFile.path atomically:YES encoding:NSUTF8StringEncoding error:nil]; - - //NSString* gethLogs = StatusgoExportNodeLogs(); - //[gethLogs writeToFile:gethLogsFile.path atomically:YES encoding:NSUTF8StringEncoding error:nil]; - [fileManager copyItemAtPath:originalGethLogsFile.path toPath:gethLogsFile.path error:nil]; - [fileManager copyItemAtPath:goerliGethLogsFile.path toPath:goerliLogsFile.path error:nil]; - [fileManager copyItemAtPath:mainGethLogsFile.path toPath:mainLogsFile.path error:nil]; - - [SSZipArchive createZipFileAtPath:zipFile.path withContentsOfDirectory:logsFolderName.path]; - [fileManager removeItemAtPath:logsFolderName.path error:nil]; - - callback(@[zipFile.absoluteString]); -} - RCT_EXPORT_METHOD(exportLogs:(RCTResponseSenderBlock)callback) { #if DEBUG NSLog(@"exportLogs() method called"); @@ -202,25 +71,6 @@ RCT_EXPORT_METHOD(exportLogs:(RCTResponseSenderBlock)callback) { callback(@[result]); } -RCT_EXPORT_METHOD(addPeer:(NSString *)enode - callback:(RCTResponseSenderBlock)callback) { - NSString *result = StatusgoAddPeer(enode); - callback(@[result]); -#if DEBUG - NSLog(@"AddPeer() method called"); -#endif -} - -RCT_EXPORT_METHOD(deleteMultiaccount:(NSString *)keyUID - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"DeleteMultiaccount() method called"); -#endif - NSURL *multiaccountKeystoreDir = [self getKeyStoreDir:keyUID]; - NSString *result = StatusgoDeleteMultiaccount(keyUID, multiaccountKeystoreDir.path); - callback(@[result]); -} - RCT_EXPORT_METHOD(deleteImportedKey:(NSString *)keyUID address:(NSString *)address password:(NSString *)password @@ -228,7 +78,7 @@ RCT_EXPORT_METHOD(deleteImportedKey:(NSString *)keyUID #if DEBUG NSLog(@"DeleteImportedKey() method called"); #endif - NSURL *multiaccountKeystoreDir = [self getKeyStoreDir:keyUID]; + NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID]; NSString *result = StatusgoDeleteImportedKey(address, password, multiaccountKeystoreDir.path); callback(@[result]); } @@ -260,14 +110,6 @@ RCT_EXPORT_METHOD(multiAccountLoadAccount:(NSString *)json callback(@[result]); } -RCT_EXPORT_METHOD(multiAccountReset:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"MultiAccountReset() method called"); -#endif - NSString *result = StatusgoMultiAccountReset(); - callback(@[result]); -} - RCT_EXPORT_METHOD(multiAccountStoreDerived:(NSString *)json callback:(RCTResponseSenderBlock)callback) { #if DEBUG @@ -286,137 +128,6 @@ RCT_EXPORT_METHOD(multiAccountImportPrivateKey:(NSString *)json callback(@[result]); } -RCT_EXPORT_METHOD(hashTransaction:(NSString *)txArgsJSON - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"HashTransaction() method called"); -#endif - NSString *result = StatusgoHashTransaction(txArgsJSON); - callback(@[result]); -} - -RCT_EXPORT_METHOD(hashMessage:(NSString *)message - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"hashMessage() method called"); -#endif - NSString *result = StatusgoHashMessage(message); - callback(@[result]); -} - -RCT_EXPORT_METHOD(localPairingPreflightOutboundCheck:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"LocalPairingPreflightOutboundCheck() method called"); -#endif - NSString *result = StatusgoLocalPairingPreflightOutboundCheck(); - callback(@[result]); -} - -RCT_EXPORT_METHOD(startSearchForLocalPairingPeers:(RCTResponseSenderBlock)callback) { - NSString *result = StatusgoStartSearchForLocalPairingPeers(); - callback(@[result]); -} - -RCT_EXPORT_METHOD(getConnectionStringForBootstrappingAnotherDevice:(NSString *)configJSON - callback:(RCTResponseSenderBlock)callback) { - - NSData *configData = [configJSON dataUsingEncoding:NSUTF8StringEncoding]; - NSError *error; - NSMutableDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:&error]; - NSMutableDictionary *senderConfig = configDict[@"senderConfig"]; - NSString *keyUID = senderConfig[@"keyUID"]; - NSURL *multiaccountKeystoreDir = [self getKeyStoreDir:keyUID]; - NSString *keystoreDir = multiaccountKeystoreDir.path; - - [senderConfig setValue:keystoreDir forKey:@"keystorePath"]; - NSString *modifiedConfigJSON = [configDict bv_jsonStringWithPrettyPrint:NO]; - - NSString *result = StatusgoGetConnectionStringForBootstrappingAnotherDevice(modifiedConfigJSON); - callback(@[result]); -} - -RCT_EXPORT_METHOD(inputConnectionStringForBootstrapping:(NSString *)cs - configJSON:(NSString *)configJSON - callback:(RCTResponseSenderBlock)callback) { - - NSData *configData = [configJSON dataUsingEncoding:NSUTF8StringEncoding]; - NSError *error; - NSMutableDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:&error]; - NSMutableDictionary *receiverConfig = configDict[@"receiverConfig"]; - NSMutableDictionary *nodeConfig = receiverConfig[@"nodeConfig"]; - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSURL *rootUrl =[[fileManager URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject]; - NSURL *multiaccountKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"]; - NSString *keystoreDir = multiaccountKeystoreDir.path; - NSString *rootDataDir = rootUrl.path; - - [receiverConfig setValue:keystoreDir forKey:@"keystorePath"]; - [nodeConfig setValue:rootDataDir forKey:@"rootDataDir"]; - NSString *modifiedConfigJSON = [configDict bv_jsonStringWithPrettyPrint:NO]; - NSString *result = StatusgoInputConnectionStringForBootstrapping(cs, modifiedConfigJSON); - callback(@[result]); -} - -RCT_EXPORT_METHOD(multiformatSerializePublicKey:(NSString *)multiCodecKey - base58btc:(NSString *)base58btc - callback:(RCTResponseSenderBlock)callback) { - NSString *result = StatusgoMultiformatSerializePublicKey(multiCodecKey,base58btc); - callback(@[result]); -} - -RCT_EXPORT_METHOD(multiformatDeserializePublicKey:(NSString *)multiCodecKey - base58btc:(NSString *)base58btc - callback:(RCTResponseSenderBlock)callback) { - NSString *result = StatusgoMultiformatDeserializePublicKey(multiCodecKey,base58btc); - callback(@[result]); -} - -RCT_EXPORT_METHOD(decompressPublicKey:(NSString *)multiCodecKey - callback:(RCTResponseSenderBlock)callback) { - NSString *result = StatusgoDecompressPublicKey(multiCodecKey); - callback(@[result]); -} - -RCT_EXPORT_METHOD(compressPublicKey:(NSString *)multiCodecKey - callback:(RCTResponseSenderBlock)callback) { - NSString *result = StatusgoCompressPublicKey(multiCodecKey); - callback(@[result]); -} - -RCT_EXPORT_METHOD(deserializeAndCompressKey:(NSString *)desktopKey - callback:(RCTResponseSenderBlock)callback) { - NSString *result = StatusgoDeserializeAndCompressKey(desktopKey); - callback(@[result]); -} - -RCT_EXPORT_METHOD(hashTypedData:(NSString *)data - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"hashTypedData() method called"); -#endif - NSString *result = StatusgoHashTypedData(data); - callback(@[result]); -} - -RCT_EXPORT_METHOD(hashTypedDataV4:(NSString *)data - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"hashTypedDataV4() method called"); -#endif - NSString *result = StatusgoHashTypedDataV4(data); - callback(@[result]); -} - -RCT_EXPORT_METHOD(sendTransactionWithSignature:(NSString *)txArgsJSON - signature:(NSString *)signature - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"sendTransactionWithSignature() method called"); -#endif - NSString *result = StatusgoSendTransactionWithSignature(txArgsJSON, signature); - callback(@[result]); -} - RCT_EXPORT_METHOD(multiAccountImportMnemonic:(NSString *)json callback:(RCTResponseSenderBlock)callback) { #if DEBUG @@ -435,388 +146,6 @@ RCT_EXPORT_METHOD(multiAccountDeriveAddresses:(NSString *)json callback(@[result]); } --(NSString *) getKeyUID:(NSString *)jsonString { - NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; - NSDictionary *json = [NSJSONSerialization - JSONObjectWithData:data - options:NSJSONReadingMutableContainers - error:nil]; - - return [json valueForKey:@"key-uid"]; -} - --(NSString *) prepareDirAndUpdateConfig:(NSString *)config - withKeyUID:(NSString *)keyUID { - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSError *error = nil; - NSURL *rootUrl =[[fileManager - URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] - lastObject]; - NSURL *absTestnetFolderName = [rootUrl URLByAppendingPathComponent:@"ethereum/testnet"]; - - if (![fileManager fileExistsAtPath:absTestnetFolderName.path]) - [fileManager createDirectoryAtPath:absTestnetFolderName.path withIntermediateDirectories:YES attributes:nil error:&error]; - - NSURL *flagFolderUrl = [rootUrl URLByAppendingPathComponent:@"ropsten_flag"]; - - if(![fileManager fileExistsAtPath:flagFolderUrl.path]){ - NSLog(@"remove lightchaindata"); - NSURL *absLightChainDataUrl = [absTestnetFolderName URLByAppendingPathComponent:@"StatusIM/lightchaindata"]; - if([fileManager fileExistsAtPath:absLightChainDataUrl.path]) { - [fileManager removeItemAtPath:absLightChainDataUrl.path - error:nil]; - } - [fileManager createDirectoryAtPath:flagFolderUrl.path - withIntermediateDirectories:NO - attributes:nil - error:&error]; - } - - NSLog(@"after remove lightchaindata"); - - NSString *keystore = @"keystore"; - NSURL *absTestnetKeystoreUrl = [absTestnetFolderName URLByAppendingPathComponent:keystore]; - NSURL *absKeystoreUrl = [rootUrl URLByAppendingPathComponent:keystore]; - if([fileManager fileExistsAtPath:absTestnetKeystoreUrl.path]){ - NSLog(@"copy keystore"); - [fileManager copyItemAtPath:absTestnetKeystoreUrl.path toPath:absKeystoreUrl.path error:nil]; - [fileManager removeItemAtPath:absTestnetKeystoreUrl.path error:nil]; - } - - NSLog(@"after lightChainData"); - - NSLog(@"preconfig: %@", config); - NSData *configData = [config dataUsingEncoding:NSUTF8StringEncoding]; - NSDictionary *configJSON = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:nil]; - NSString *relativeDataDir = [configJSON objectForKey:@"DataDir"]; - NSString *absDataDir = [rootUrl.path stringByAppendingString:relativeDataDir]; - NSURL *absDataDirUrl = [NSURL fileURLWithPath:absDataDir]; - NSString *keystoreDir = [@"/keystore/" stringByAppendingString:keyUID]; - [configJSON setValue:keystoreDir forKey:@"KeyStoreDir"]; - [configJSON setValue:@"" forKey:@"LogDir"]; - [configJSON setValue:@"geth.log" forKey:@"LogFile"]; - - NSString *resultingConfig = [configJSON bv_jsonStringWithPrettyPrint:NO]; - NSLog(@"node config %@", resultingConfig); - - if(![fileManager fileExistsAtPath:absDataDir]) { - [fileManager createDirectoryAtPath:absDataDir - withIntermediateDirectories:YES attributes:nil error:nil]; - } - - NSLog(@"logUrlPath %@ rootDir %@", @"geth.log", rootUrl.path); - NSURL *absLogUrl = [absDataDirUrl URLByAppendingPathComponent:@"geth.log"]; - if(![fileManager fileExistsAtPath:absLogUrl.path]) { - NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; - [dict setObject:[NSNumber numberWithInt:511] forKey:NSFilePosixPermissions]; - [fileManager createFileAtPath:absLogUrl.path contents:nil attributes:dict]; - } - - return resultingConfig; - -} - - -RCT_EXPORT_METHOD(prepareDirAndUpdateConfig:(NSString *)keyUID - config:(NSString *)config - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"PrepareDirAndUpdateConfig() method called"); -#endif - NSString *updatedConfig = [self prepareDirAndUpdateConfig:config - withKeyUID:keyUID]; - callback(@[updatedConfig]); -} - -RCT_EXPORT_METHOD(saveAccountAndLogin:(NSString *)multiaccountData - password:(NSString *)password - settings:(NSString *)settings - config:(NSString *)config - accountsData:(NSString *)accountsData) { -#if DEBUG - NSLog(@"SaveAccountAndLogin() method called"); -#endif - [self getExportDbFilePath]; - NSString *keyUID = [self getKeyUID:multiaccountData]; - NSString *finalConfig = [self prepareDirAndUpdateConfig:config - withKeyUID:keyUID]; - NSString *result = StatusgoSaveAccountAndLogin(multiaccountData, password, settings, finalConfig, accountsData); - NSLog(@"%@", result); -} - -RCT_EXPORT_METHOD(saveAccountAndLoginWithKeycard:(NSString *)multiaccountData - password:(NSString *)password - settings:(NSString *)settings - config:(NSString *)config - accountsData:(NSString *)accountsData - chatKey:(NSString *)chatKey) { -#if DEBUG - NSLog(@"SaveAccountAndLoginWithKeycard() method called"); -#endif - [self getExportDbFilePath]; - NSString *keyUID = [self getKeyUID:multiaccountData]; - NSString *finalConfig = [self prepareDirAndUpdateConfig:config - withKeyUID:keyUID]; - NSString *result = StatusgoSaveAccountAndLoginWithKeycard(multiaccountData, password, settings, finalConfig, accountsData, chatKey); - NSLog(@"%@", result); -} - -- (NSString *) getExportDbFilePath { - NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"export.db"]; - NSFileManager *fileManager = [NSFileManager defaultManager]; - - if ([fileManager fileExistsAtPath:filePath]) { - [fileManager removeItemAtPath:filePath error:nil]; - } - - return filePath; -} - -- (NSURL *) getKeyStoreDir:(NSString *)keyUID { - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSURL *rootUrl =[[fileManager - URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] - lastObject]; - - NSURL *oldKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"]; - NSURL *multiaccountKeystoreDir = [oldKeystoreDir URLByAppendingPathComponent:keyUID]; - - return multiaccountKeystoreDir; -} - -- (void) migrateKeystore:(NSString *)accountData - password:(NSString *)password { - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSURL *rootUrl =[[fileManager - URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] - lastObject]; - - NSString *keyUID = [self getKeyUID:accountData]; - NSURL *oldKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"]; - NSURL *multiaccountKeystoreDir = [self getKeyStoreDir:keyUID]; - - NSArray *keys = [fileManager contentsOfDirectoryAtPath:multiaccountKeystoreDir.path error:nil]; - if (keys.count == 0) { - NSString *migrationResult = StatusgoMigrateKeyStoreDir(accountData, password, oldKeystoreDir.path, multiaccountKeystoreDir.path); - NSLog(@"keystore migration result %@", migrationResult); - - NSString *initKeystoreResult = StatusgoInitKeystore(multiaccountKeystoreDir.path); - NSLog(@"InitKeyStore result %@", initKeystoreResult); - } -} - -RCT_EXPORT_METHOD(login:(NSString *)accountData - password:(NSString *)password) { -#if DEBUG - NSLog(@"Login() method called"); -#endif - [self getExportDbFilePath]; - [self migrateKeystore:accountData password:password]; - NSString *result = StatusgoLogin(accountData, password); - NSLog(@"%@", result); -} - -RCT_EXPORT_METHOD(loginWithConfig:(NSString *)accountData - password:(NSString *)password - configJSON:(NSString *)configJSON) { -#if DEBUG - NSLog(@"LoginWithConfig() method called"); -#endif - [self getExportDbFilePath]; - [self migrateKeystore:accountData password:password]; - NSString *result = StatusgoLoginWithConfig(accountData, password, configJSON); - NSLog(@"%@", result); -} - -RCT_EXPORT_METHOD(loginAccount:(NSString *)request) { -#if DEBUG - NSLog(@"LoginAccount() method called"); -#endif - NSString *result = StatusgoLoginAccount(request); - NSLog(@"%@", result); -} - -RCT_EXPORT_METHOD(loginWithKeycard:(NSString *)accountData - password:(NSString *)password - chatKey:(NSString *)chatKey - nodeConfigJSON:(NSString *)nodeConfigJSON) { -#if DEBUG - NSLog(@"LoginWithKeycard() method called"); -#endif - [self getExportDbFilePath]; - [self migrateKeystore:accountData password:password]; - - NSString *result = StatusgoLoginWithKeycard(accountData, password, chatKey, nodeConfigJSON); - - NSLog(@"%@", result); -} - -RCT_EXPORT_METHOD(logout) { -#if DEBUG - NSLog(@"Logout() method called"); -#endif - NSString *result = StatusgoLogout(); - - NSLog(@"%@", result); -} - -RCT_EXPORT_METHOD(openAccounts:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"OpenAccounts() method called"); -#endif - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSURL *rootUrl =[[fileManager - URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] - lastObject]; - - NSString *result = StatusgoOpenAccounts(rootUrl.path); - callback(@[result]); -} - -RCT_EXPORT_METHOD(verify:(NSString *)address - password:(NSString *)password - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"VerifyAccountPassword() method called"); -#endif - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSURL *rootUrl =[[fileManager - URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] - lastObject]; - NSURL *absKeystoreUrl = [rootUrl URLByAppendingPathComponent:@"keystore"]; - - NSString *result = StatusgoVerifyAccountPassword(absKeystoreUrl.path, address, password); - callback(@[result]); -} - -RCT_EXPORT_METHOD(verifyDatabasePassword:(NSString *)keyUID - password:(NSString *)password - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"VerifyDatabasePassword() method called"); -#endif - NSString *result = StatusgoVerifyDatabasePassword(keyUID, password); - callback(@[result]); -} - -RCT_EXPORT_METHOD(reEncryptDbAndKeystore:(NSString *)keyUID - currentPassword:(NSString *)currentPassword - newPassword:(NSString *)newPassword - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"reEncryptDbAndKeystore() method called"); -#endif - // changes password and re-encrypts keystore - NSString *result = StatusgoChangeDatabasePassword(keyUID, currentPassword, newPassword); - callback(@[result]); -} - -RCT_EXPORT_METHOD(convertToKeycardAccount:(NSString *)keyUID - accountData:(NSString *)accountData - settings:(NSString *)settings - keycardUID:(NSString *)keycardUID - currentPassword:(NSString *)currentPassword - newPassword:(NSString *)newPassword - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"convertToKeycardAccount() method called"); -#endif - NSURL *multiaccountKeystoreDir = [self getKeyStoreDir:keyUID]; - StatusgoInitKeystore(multiaccountKeystoreDir.path); - NSString *result = StatusgoConvertToKeycardAccount(accountData, settings, keycardUID, currentPassword, newPassword); - callback(@[result]); -} - - -#pragma mark - SendTransaction - -RCT_EXPORT_METHOD(sendTransaction:(NSString *)txArgsJSON - password:(NSString *)password - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"SendTransaction() method called"); -#endif - NSString *result = StatusgoSendTransaction(txArgsJSON, password); - callback(@[result]); -} - - -#pragma mark - SignMessage - -RCT_EXPORT_METHOD(signMessage:(NSString *)message - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"SignMessage() method called"); -#endif - NSString *result = StatusgoSignMessage(message); - callback(@[result]); -} - - -#pragma mark - Recover - -RCT_EXPORT_METHOD(recover:(NSString *)message - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"Recover() method called"); -#endif - NSString *result = StatusgoRecover(message); - callback(@[result]); -} - - -#pragma mark - SignTypedData - -RCT_EXPORT_METHOD(signTypedData:(NSString *)data - account:(NSString *)account - password:(NSString *)password - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"SignTypedData() method called"); -#endif - NSString *result = StatusgoSignTypedData(data, account, password); - callback(@[result]); -} - - -#pragma mark - SignTypedDataV4 - -RCT_EXPORT_METHOD(signTypedDataV4:(NSString *)data - account:(NSString *)account - password:(NSString *)password - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"SignTypedDataV4() method called"); -#endif - NSString *result = StatusgoSignTypedDataV4(data, account, password); - callback(@[result]); -} - - -#pragma mark - SignGroupMembership - -RCT_EXPORT_METHOD(signGroupMembership:(NSString *)content - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"SignGroupMembership() method called"); -#endif - NSString *result = StatusgoSignGroupMembership(content); - callback(@[result]); -} - - -#pragma mark - ExtractGroupMembershipSignatures - -RCT_EXPORT_METHOD(extractGroupMembershipSignatures:(NSString *)content - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"ExtractGroupMembershipSignatures() method called"); -#endif - NSString *result = StatusgoExtractGroupMembershipSignatures(content); - callback(@[result]); -} - - #pragma mark - GetNodeConfig RCT_EXPORT_METHOD(getNodeConfig:(RCTResponseSenderBlock)callback) { @@ -827,206 +156,14 @@ RCT_EXPORT_METHOD(getNodeConfig:(RCTResponseSenderBlock)callback) { callback(@[result]); } - - -#pragma mark - only android methods - -RCT_EXPORT_METHOD(setAdjustResize) { -#if DEBUG - NSLog(@"setAdjustResize() works only on Android"); -#endif -} - -RCT_EXPORT_METHOD(setAdjustPan) { -#if DEBUG - NSLog(@"setAdjustPan() works only on Android"); -#endif -} - -RCT_EXPORT_METHOD(setSoftInputMode: (NSInteger) i) { -#if DEBUG - NSLog(@"setSoftInputMode() works only on Android"); -#endif -} - -RCT_EXPORT_METHOD(clearCookies) { - NSHTTPCookie *cookie; - NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; - - for (cookie in [storage cookies]) { - [storage deleteCookie:cookie]; - } -} - -RCT_EXPORT_METHOD(clearStorageAPIs) { - [[NSURLCache sharedURLCache] removeAllCachedResponses]; - - NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; - NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil]; - for (NSString *string in array) { - NSLog(@"Removing %@", [path stringByAppendingPathComponent:string]); - if ([[string pathExtension] isEqualToString:@"localstorage"]) - [[NSFileManager defaultManager] removeItemAtPath:[path stringByAppendingPathComponent:string] error:nil]; - } -} - -RCT_EXPORT_METHOD(callRPC:(NSString *)payload - callback:(RCTResponseSenderBlock)callback) { - dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSString *result = StatusgoCallRPC(payload); - dispatch_async(dispatch_get_main_queue(), ^{ - callback(@[result]); - }); - }); -} - -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(keystoreDir) { - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSURL *rootUrl =[[fileManager - URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] - lastObject]; - - NSURL *commonKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"]; - - return commonKeystoreDir.path; -} - - -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(backupDisabledDataDir) { - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSURL *rootUrl =[[fileManager - URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] - lastObject]; - return rootUrl.path; -} - -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(logFileDirectory) { - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSURL *rootUrl =[[fileManager - URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] - lastObject]; - return rootUrl.path; -} - -RCT_EXPORT_METHOD(initLogging:(BOOL)enabled - mobileSystem:(BOOL)mobileSystem - logLevel:(NSString *)logLevel - callback:(RCTResponseSenderBlock)callback) -{ - NSString *logDirectory = [self logFileDirectory]; - NSString *logFilePath = [logDirectory stringByAppendingPathComponent:@"geth.log"]; - - NSMutableDictionary *jsonConfig = [NSMutableDictionary dictionary]; - jsonConfig[@"Enabled"] = @(enabled); - jsonConfig[@"MobileSystem"] = @(mobileSystem); - jsonConfig[@"Level"] = logLevel; - jsonConfig[@"File"] = logFilePath; - - NSError *error = nil; - NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonConfig options:0 error:&error]; - - if (error) { - // Handle JSON serialization error - callback(@[error.localizedDescription]); - return; - } - - NSString *config = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; - - // Call your native logging initialization method here - NSString *initResult = StatusgoInitLogging(config); - - callback(@[initResult]); -} - -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(encodeTransfer:(NSString *)to - value:(NSString *)value) { - return StatusgoEncodeTransfer(to,value); -} - -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(encodeFunctionCall:(NSString *)method - paramsJSON:(NSString *)paramsJSON) { - return StatusgoEncodeFunctionCall(method,paramsJSON); -} - -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(decodeParameters:(NSString *)decodeParamJSON) { - return StatusgoDecodeParameters(decodeParamJSON); -} - -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(hexToNumber:(NSString *)hex) { - return StatusgoHexToNumber(hex); -} - -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(numberToHex:(NSString *)numString) { - return StatusgoNumberToHex(numString); -} - -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(sha3:(NSString *)str) { - return StatusgoSha3(str); -} - -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(utf8ToHex:(NSString *)str) { - return StatusgoUtf8ToHex(str); -} - -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(hexToUtf8:(NSString *)str) { - return StatusgoHexToUtf8(str); -} - -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(checkAddressChecksum:(NSString *)address) { - return StatusgoCheckAddressChecksum(address); -} - -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isAddress:(NSString *)address) { - return StatusgoIsAddress(address); -} - RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(fleets) { return StatusgoFleets(); } -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(toChecksumAddress:(NSString *)address) { - return StatusgoToChecksumAddress(address); -} - -RCT_EXPORT_METHOD(validateMnemonic:(NSString *)seed - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"validateMnemonic() method called"); -#endif - NSString *result = StatusgoValidateMnemonic(seed); - callback(@[result]); -} - -RCT_EXPORT_METHOD(createAccountAndLogin:(NSString *)request) { -#if DEBUG - NSLog(@"createAccountAndLogin() method called"); -#endif - StatusgoCreateAccountAndLogin(request); -} - -RCT_EXPORT_METHOD(restoreAccountAndLogin:(NSString *)request) { -#if DEBUG - NSLog(@"restoreAccountAndLogin() method called"); -#endif - StatusgoRestoreAccountAndLogin(request); -} - -RCT_EXPORT_METHOD(callPrivateRPC:(NSString *)payload - callback:(RCTResponseSenderBlock)callback) { - dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSString *result = StatusgoCallPrivateRPC(payload); - dispatch_async(dispatch_get_main_queue(), ^{ - callback(@[result]); - }); - }); -} - RCT_EXPORT_METHOD(closeApplication) { exit(0); } - RCT_EXPORT_METHOD(connectionChange:(NSString *)type isExpensive:(BOOL)isExpensive) { #if DEBUG @@ -1042,13 +179,6 @@ RCT_EXPORT_METHOD(appStateChange:(NSString *)type) { StatusgoAppStateChange(type); } -RCT_EXPORT_METHOD(stopLocalNotifications) { -#if DEBUG - NSLog(@"StopLocalNotifications() method called"); -#endif -StatusgoStopLocalNotifications(); -} - RCT_EXPORT_METHOD(startLocalNotifications) { #if DEBUG NSLog(@"StartLocalNotifications() method called"); @@ -1056,50 +186,6 @@ RCT_EXPORT_METHOD(startLocalNotifications) { StatusgoStartLocalNotifications(); } -RCT_EXPORT_METHOD(exportUnencryptedDatabase:(NSString *)accountData - password:(NSString *)password - callback:(RCTResponseSenderBlock)callback) { -#if DEBUG - NSLog(@"exportUnencryptedDatabase() method called"); -#endif - - NSString *filePath = [self getExportDbFilePath]; - StatusgoExportUnencryptedDatabase(accountData, password, filePath); - - callback(@[filePath]); -} - -RCT_EXPORT_METHOD(importUnencryptedDatabase:(NSString *)accountData - password:(NSString *)password) { -#if DEBUG - NSLog(@"importUnencryptedDatabase() method called"); -#endif - ""; -} - -RCT_EXPORT_METHOD(setBlankPreviewFlag:(BOOL *)newValue) -{ - NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - - [userDefaults setBool:newValue forKey:@"BLANK_PREVIEW"]; - - [userDefaults synchronize]; -} - -RCT_EXPORT_METHOD(activateKeepAwake) -{ - dispatch_async(dispatch_get_main_queue(), ^{ - [[UIApplication sharedApplication] setIdleTimerDisabled:YES]; - }); -} - -RCT_EXPORT_METHOD(deactivateKeepAwake) -{ - dispatch_async(dispatch_get_main_queue(), ^{ - [[UIApplication sharedApplication] setIdleTimerDisabled:NO]; - }); -} - #pragma mark - deviceinfo - (bool) is24Hour @@ -1130,7 +216,7 @@ RCT_EXPORT_METHOD(deactivateKeepAwake) - (NSString*) deviceName { - return [[UIDevice currentDevice] name];; + return [[UIDevice currentDevice] name]; } - (NSDictionary *)constantsToExport diff --git a/modules/react-native-status/ios/RCTStatus/RCTStatus.xcodeproj/project.pbxproj b/modules/react-native-status/ios/RCTStatus/RCTStatus.xcodeproj/project.pbxproj index 26ab84803c..352f933e56 100644 --- a/modules/react-native-status/ios/RCTStatus/RCTStatus.xcodeproj/project.pbxproj +++ b/modules/react-native-status/ios/RCTStatus/RCTStatus.xcodeproj/project.pbxproj @@ -3,13 +3,20 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 206C9F3E1D474E910063E3E6 /* RCTStatus.h in Copy Files */ = {isa = PBXBuildFile; fileRef = 206C9F3D1D474E910063E3E6 /* RCTStatus.h */; }; 206C9F401D474E910063E3E6 /* RCTStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 206C9F3F1D474E910063E3E6 /* RCTStatus.m */; }; CE4E31B11D86951A0033ED64 /* Statusgo.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE4E31B01D86951A0033ED64 /* Statusgo.xcframework */; }; + E92244EB2B485F2400915F4C /* UIHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = E92244E92B485F2400915F4C /* UIHelper.m */; }; + E967A3AC2B47BD5A00FB19B2 /* Utils.m in Sources */ = {isa = PBXBuildFile; fileRef = E967A3AB2B47BD5A00FB19B2 /* Utils.m */; }; + E9BEF3602B470BF1001F6755 /* NetworkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E9BEF35E2B470BF1001F6755 /* NetworkManager.m */; }; + E9C33AA62B4828A60074B1C5 /* DatabaseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E9C33AA52B4828A60074B1C5 /* DatabaseManager.m */; }; + E9DB08932B4858B400F51053 /* LogManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E9DB08912B4858B400F51053 /* LogManager.m */; }; + E9F5C3322B483B6C001A7F40 /* EncryptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = E9F5C3312B483B6C001A7F40 /* EncryptionUtils.m */; }; + E9FC4ED12B47EEFF00E834DB /* AccountManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E9FC4ECF2B47EEFF00E834DB /* AccountManager.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -31,6 +38,20 @@ 206C9F3D1D474E910063E3E6 /* RCTStatus.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTStatus.h; sourceTree = ""; }; 206C9F3F1D474E910063E3E6 /* RCTStatus.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTStatus.m; sourceTree = ""; }; CE4E31B01D86951A0033ED64 /* Statusgo.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Statusgo.xcframework; sourceTree = ""; }; + E92244E92B485F2400915F4C /* UIHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIHelper.m; sourceTree = ""; }; + E92244EA2B485F2400915F4C /* UIHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIHelper.h; sourceTree = ""; }; + E967A3AA2B47BD5A00FB19B2 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Utils.h; sourceTree = ""; }; + E967A3AB2B47BD5A00FB19B2 /* Utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Utils.m; sourceTree = ""; }; + E9BEF35E2B470BF1001F6755 /* NetworkManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NetworkManager.m; sourceTree = ""; }; + E9BEF35F2B470BF1001F6755 /* NetworkManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkManager.h; sourceTree = ""; }; + E9C33AA42B4828A60074B1C5 /* DatabaseManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DatabaseManager.h; sourceTree = ""; }; + E9C33AA52B4828A60074B1C5 /* DatabaseManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DatabaseManager.m; sourceTree = ""; }; + E9DB08912B4858B400F51053 /* LogManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LogManager.m; sourceTree = ""; }; + E9DB08922B4858B400F51053 /* LogManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogManager.h; sourceTree = ""; }; + E9F5C3302B483B6C001A7F40 /* EncryptionUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EncryptionUtils.h; sourceTree = ""; }; + E9F5C3312B483B6C001A7F40 /* EncryptionUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EncryptionUtils.m; sourceTree = ""; }; + E9FC4ECF2B47EEFF00E834DB /* AccountManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AccountManager.m; sourceTree = ""; }; + E9FC4ED02B47EEFF00E834DB /* AccountManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccountManager.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -65,6 +86,20 @@ 206C9F3C1D474E910063E3E6 /* Status */ = { isa = PBXGroup; children = ( + E92244EA2B485F2400915F4C /* UIHelper.h */, + E92244E92B485F2400915F4C /* UIHelper.m */, + E9DB08922B4858B400F51053 /* LogManager.h */, + E9DB08912B4858B400F51053 /* LogManager.m */, + E9F5C3302B483B6C001A7F40 /* EncryptionUtils.h */, + E9F5C3312B483B6C001A7F40 /* EncryptionUtils.m */, + E9C33AA42B4828A60074B1C5 /* DatabaseManager.h */, + E9C33AA52B4828A60074B1C5 /* DatabaseManager.m */, + E9FC4ED02B47EEFF00E834DB /* AccountManager.h */, + E9FC4ECF2B47EEFF00E834DB /* AccountManager.m */, + E967A3AA2B47BD5A00FB19B2 /* Utils.h */, + E967A3AB2B47BD5A00FB19B2 /* Utils.m */, + E9BEF35F2B470BF1001F6755 /* NetworkManager.h */, + E9BEF35E2B470BF1001F6755 /* NetworkManager.m */, 206C9F3D1D474E910063E3E6 /* RCTStatus.h */, 206C9F3F1D474E910063E3E6 /* RCTStatus.m */, ); @@ -127,7 +162,14 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + E9DB08932B4858B400F51053 /* LogManager.m in Sources */, + E9F5C3322B483B6C001A7F40 /* EncryptionUtils.m in Sources */, + E967A3AC2B47BD5A00FB19B2 /* Utils.m in Sources */, + E92244EB2B485F2400915F4C /* UIHelper.m in Sources */, + E9BEF3602B470BF1001F6755 /* NetworkManager.m in Sources */, 206C9F401D474E910063E3E6 /* RCTStatus.m in Sources */, + E9C33AA62B4828A60074B1C5 /* DatabaseManager.m in Sources */, + E9FC4ED12B47EEFF00E834DB /* AccountManager.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/modules/react-native-status/ios/RCTStatus/UIHelper.h b/modules/react-native-status/ios/RCTStatus/UIHelper.h new file mode 100644 index 0000000000..2f5b16284d --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/UIHelper.h @@ -0,0 +1,8 @@ +#import +#import +#import +#import "RCTLog.h" + +@interface UIHelper : NSObject + +@end diff --git a/modules/react-native-status/ios/RCTStatus/UIHelper.m b/modules/react-native-status/ios/RCTStatus/UIHelper.m new file mode 100644 index 0000000000..00e8ee0862 --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/UIHelper.m @@ -0,0 +1,39 @@ +#import "UIHelper.h" +#import "React/RCTBridge.h" +#import "React/RCTEventDispatcher.h" + +@implementation UIHelper + +RCT_EXPORT_MODULE(); + +#pragma mark - only android methods + +RCT_EXPORT_METHOD(setSoftInputMode: (NSInteger) i) { +#if DEBUG + NSLog(@"setSoftInputMode() works only on Android"); +#endif +} + +RCT_EXPORT_METHOD(clearCookies) { + NSHTTPCookie *cookie; + NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + + for (cookie in [storage cookies]) { + [storage deleteCookie:cookie]; + } +} + +RCT_EXPORT_METHOD(clearStorageAPIs) { + [[NSURLCache sharedURLCache] removeAllCachedResponses]; + + NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; + NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil]; + for (NSString *string in array) { + NSLog(@"Removing %@", [path stringByAppendingPathComponent:string]); + if ([[string pathExtension] isEqualToString:@"localstorage"]) + [[NSFileManager defaultManager] removeItemAtPath:[path stringByAppendingPathComponent:string] error:nil]; + } +} + + +@end diff --git a/modules/react-native-status/ios/RCTStatus/Utils.h b/modules/react-native-status/ios/RCTStatus/Utils.h new file mode 100644 index 0000000000..c7cf5f9d9b --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/Utils.h @@ -0,0 +1,16 @@ +#import +#import +#import +#import "Statusgo.h" +#import "RCTLog.h" + +@interface Utils : NSObject + ++ (NSString *)jsonStringWithPrettyPrint:(BOOL)prettyPrint fromDictionary:(NSDictionary *)dictionary; ++ (NSString *)jsonStringWithPrettyPrint:(BOOL)prettyPrint fromArray:(NSArray *)array; ++ (NSURL *)getKeyStoreDirForKeyUID:(NSString *)keyUID; ++ (NSString *)getExportDbFilePath; ++ (NSString *)getKeyUID:(NSString *)jsonString; ++ (void)migrateKeystore:(NSString *)accountData password:(NSString *)password; + +@end diff --git a/modules/react-native-status/ios/RCTStatus/Utils.m b/modules/react-native-status/ios/RCTStatus/Utils.m new file mode 100644 index 0000000000..2d2be69a51 --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/Utils.m @@ -0,0 +1,128 @@ +#import "Utils.h" +#import "React/RCTBridge.h" +#import "React/RCTEventDispatcher.h" +#import "Statusgo.h" +#import "Utils.h" + +@implementation Utils + +RCT_EXPORT_MODULE(); + ++ (NSString *)jsonStringWithPrettyPrint:(BOOL)prettyPrint fromDictionary:(NSDictionary *)dictionary { + NSError *error; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary + options:(NSJSONWritingOptions)(prettyPrint ? NSJSONWritingPrettyPrinted : 0) + error:&error]; + + if (!jsonData) { + NSLog(@"jsonStringWithPrettyPrint: error: %@", error.localizedDescription); + return @"{}"; + } else { + return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + } +} + ++ (NSString *)jsonStringWithPrettyPrint:(BOOL)prettyPrint fromArray:(NSArray *)array { + NSError *error; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:array + options:(NSJSONWritingOptions)(prettyPrint ? NSJSONWritingPrettyPrinted : 0) + error:&error]; + + if (!jsonData) { + NSLog(@"jsonStringWithPrettyPrint: error: %@", error.localizedDescription); + return @"[]"; + } else { + return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + } +} + ++ (NSURL *)getKeyStoreDirForKeyUID:(NSString *)keyUID { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *rootUrl = [[fileManager URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject]; + + NSURL *oldKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"]; + NSURL *multiaccountKeystoreDir = [oldKeystoreDir URLByAppendingPathComponent:keyUID]; + + return multiaccountKeystoreDir; +} + ++ (NSString *) getKeyUID:(NSString *)jsonString { + NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary *json = [NSJSONSerialization + JSONObjectWithData:data + options:NSJSONReadingMutableContainers + error:nil]; + + return [json valueForKey:@"key-uid"]; +} + ++ (NSString *) getExportDbFilePath { + NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"export.db"]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + + if ([fileManager fileExistsAtPath:filePath]) { + [fileManager removeItemAtPath:filePath error:nil]; + } + + return filePath; +} + ++ (void) migrateKeystore:(NSString *)accountData + password:(NSString *)password { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *rootUrl =[[fileManager + URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] + lastObject]; + + NSURL *keyUID = [self getKeyStoreDirForKeyUID:accountData]; + NSURL *oldKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"]; + NSURL *multiaccountKeystoreDir = [self getKeyStoreDirForKeyUID:keyUID.path]; + + NSArray *keys = [fileManager contentsOfDirectoryAtPath:multiaccountKeystoreDir.path error:nil]; + if (keys.count == 0) { + NSString *migrationResult = StatusgoMigrateKeyStoreDir(accountData, password, oldKeystoreDir.path, multiaccountKeystoreDir.path); + NSLog(@"keystore migration result %@", migrationResult); + + NSString *initKeystoreResult = StatusgoInitKeystore(multiaccountKeystoreDir.path); + NSLog(@"InitKeyStore result %@", initKeystoreResult); + } +} + +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(backupDisabledDataDir) { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *rootUrl =[[fileManager + URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] + lastObject]; + return rootUrl.path; +} + +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(keystoreDir) { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *rootUrl =[[fileManager + URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] + lastObject]; + + NSURL *commonKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"]; + + return commonKeystoreDir.path; +} + +RCT_EXPORT_METHOD(validateMnemonic:(NSString *)seed + callback:(RCTResponseSenderBlock)callback) { + #if DEBUG + NSLog(@"validateMnemonic() method called"); + #endif + NSString *result = StatusgoValidateMnemonic(seed); + callback(@[result]); +} + +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(checkAddressChecksum:(NSString *)address) { + return StatusgoCheckAddressChecksum(address); +} + +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(toChecksumAddress:(NSString *)address) { + return StatusgoToChecksumAddress(address); +} + + +@end diff --git a/scripts/lint/trailing-newline.sh b/scripts/lint/trailing-newline.sh index f35c1ed2b9..97872a643a 100755 --- a/scripts/lint/trailing-newline.sh +++ b/scripts/lint/trailing-newline.sh @@ -2,7 +2,7 @@ set -eof pipefail -FILES=$(comm -23 <(sort <(git ls-files --cached --others --exclude-standard)) <(sort <(git ls-files --deleted)) | grep --ignore-case -E '\.(java|cpp|nix|json|sh|md|js|clj|cljs|cljc|edn)$') +FILES=$(comm -23 <(sort <(git ls-files --cached --others --exclude-standard)) <(sort <(git ls-files --deleted)) | grep --ignore-case -E '\.(java|cpp|nix|json|sh|md|js|clj|cljs|cljc|edn|kt|m)$') N_FILES=$(echo "$FILES" | wc -l) LINT_SHOULD_FIX=0 diff --git a/src/legacy/status_im/utils/test.cljs b/src/legacy/status_im/utils/test.cljs index 2aac2a6bfc..4bfb83d7b1 100644 --- a/src/legacy/status_im/utils/test.cljs +++ b/src/legacy/status_im/utils/test.cljs @@ -31,104 +31,81 @@ (.pollSignal native-status signal-received-callback) 100)))) -(def status +(def ui-helper (clj->js - {:openAccounts - (fn [callback] - (callback (.openAccounts native-status test-dir))) - - :multiAccountStoreDerived - (fn [json callback] - (callback (.multiAccountStoreDerivedAccounts native-status json))) - - :getNodeConfig (fn [] (types/clj->json {:WakuV2Config ""})) - - :backupDisabledDataDir (fn [] (str test-dir "/backup")) - :keystoreDir (fn [] "") - :logFileDirectory (fn [] (str test-dir "/log")) - :clearCookies identity - :clearStorageAPIs identity - :setBlankPreviewFlag identity - - :callPrivateRPC - (fn [payload callback] - (callback (.callPrivateRPC native-status payload))) - - :createAccountAndLogin (fn [request] (.createAccountAndLogin native-status request)) - - :saveAccountAndLogin - (fn [multiaccount-data password settings config accounts-data] - (.saveAccountAndLogin native-status multiaccount-data password settings config accounts-data)) - - :logout - (fn [] (.logout native-status)) - - :multiAccountGenerateAndDeriveAddresses - (fn [json callback] - (callback (.multiAccountGenerateAndDeriveAddresses native-status json))) - - :multiAccountImportMnemonic - (fn [json callback] - (callback (.multiAccountImportMnemonic native-status json))) - - :multiAccountLoadAccount - (fn [json callback] - (callback (.multiAccountLoadAccount native-status json))) - - :multiAccountDeriveAddresses - (fn [json callback] - (callback (.multiAccountDeriveAddresses native-status json))) + {:clearCookies identity + :clearStorageAPIs identity})) +(def encryption-utils + (clj->js + {:sha3 + (fn [s] (.sha3 native-status s)) + :setBlankPreviewFlag + identity + :encodeTransfer + (fn [to-norm amount-hex] + (.encodeTransfer native-status to-norm amount-hex)) + :hexToNumber + (fn [hex] (.hexToNumber native-status hex)) + :decodeParameters + (fn [decode-param-json] + (.decodeParameters native-status decode-param-json)) + :numberToHex + (fn [num-str] (.numberToHex native-status num-str)) + :initKeystore + (fn [key-uid callback] + (callback (.initKeystore native-status + (str test-dir "/keystore/" key-uid)))) :multiformatDeserializePublicKey (fn [public-key deserialization-key callback] (callback (.multiformatDeserializePublicKey native-status public-key - deserialization-key))) + deserialization-key)))})) - :initKeystore - (fn [key-uid callback] - (callback (.initKeystore native-status - (str test-dir "/keystore/" key-uid)))) - - :encodeTransfer - (fn [to-norm amount-hex] - (.encodeTransfer native-status to-norm amount-hex)) - - :encodeFunctionCall - (fn [method params-json] - (.encodeFunctionCall native-status method params-json)) - - :decodeParameters - (fn [decode-param-json] - (.decodeParameters native-status decode-param-json)) - - :hexToNumber - (fn [hex] (.hexToNumber native-status hex)) - - :numberToHex - (fn [num-str] (.numberToHex native-status num-str)) - - :checkAddressChecksum - (fn [address] (.checkAddressChecksum native-status address)) - - :sha3 - (fn [s] (.sha3 native-status s)) +(def account-manager + (clj->js + {:openAccounts + (fn [callback] + (callback (.openAccounts native-status test-dir))) + :createAccountAndLogin + (fn [request] (.createAccountAndLogin native-status request)) + :logout + (fn [] (.logout native-status)) + :multiAccountImportMnemonic + (fn [json callback] + (callback (.multiAccountImportMnemonic native-status json))) + :multiAccountLoadAccount + (fn [json callback] + (callback (.multiAccountLoadAccount native-status json))) + :multiAccountDeriveAddresses + (fn [json callback] + (callback (.multiAccountDeriveAddresses native-status json))) + :multiAccountGenerateAndDeriveAddresses + (fn [json callback] + (callback (.multiAccountGenerateAndDeriveAddresses native-status json))) + :multiAccountStoreDerived + (fn [json callback] + (callback (.multiAccountStoreDerivedAccounts native-status json)))})) +(def utils + (clj->js + {:backupDisabledDataDir + (fn [] (str test-dir "/backup")) + :keystoreDir (fn [] "") :toChecksumAddress (fn [address] (.toChecksumAddress native-status address)) - - :isAddress - (fn [address] (.isAddress native-status address)) - - :fleets - (fn [] (.fleets native-status)) - + :checkAddressChecksum + (fn [address] (.checkAddressChecksum native-status address)) :validateMnemonic (fn [json callback] (callback (.validateMnemonic native-status json))) + :isAddress + (fn [address] (.isAddress native-status address))})) - :startLocalNotifications identity - +(def log-manager + (clj->js + {:logFileDirectory + (fn [] (str test-dir "/log")) :initLogging (fn [enabled mobile-system log-level callback] (callback (.initLogging native-status @@ -136,3 +113,18 @@ :MobileSystem mobile-system :Level log-level :File (str test-dir "/geth.log")}))))})) + +(def network + (clj->js + {:callPrivateRPC + (fn [payload callback] + (callback (.callPrivateRPC native-status payload)))})) + +(def status + (clj->js + {:getNodeConfig + (fn [] (types/clj->json {:WakuV2Config ""})) + :fleets + (fn [] (.fleets native-status)) + :startLocalNotifications + identity})) diff --git a/src/mocks/js_dependencies.cljs b/src/mocks/js_dependencies.cljs index 66973e6317..27d3b41f6d 100644 --- a/src/mocks/js_dependencies.cljs +++ b/src/mocks/js_dependencies.cljs @@ -38,6 +38,12 @@ {:NativeModules {:RNGestureHandlerModule {:Direction (fn [])} :PushNotifications {} :Status utils.test/status + :EncryptionUtils utils.test/encryption-utils + :AccountManager utils.test/account-manager + :Utils utils.test/utils + :LogManager utils.test/log-manager + :NetworkManager utils.test/network + :UIHelper utils.test/ui-helper :ReanimatedModule {:configureProps (fn [])}} :View {} diff --git a/src/native_module/core.cljs b/src/native_module/core.cljs index 1a4c70191f..dc4cda0f44 100644 --- a/src/native_module/core.cljs +++ b/src/native_module/core.cljs @@ -11,6 +11,41 @@ (when (exists? (.-NativeModules react-native)) (.-Status ^js (.-NativeModules react-native)))) +(defn account-manager + [] + (when (exists? (.-NativeModules react-native)) + (.-AccountManager ^js (.-NativeModules react-native)))) + +(defn encryption + [] + (when (exists? (.-NativeModules react-native)) + (.-EncryptionUtils ^js (.-NativeModules react-native)))) + +(defn database + [] + (when (exists? (.-NativeModules react-native)) + (.-DatabaseManager ^js (.-NativeModules react-native)))) + +(defn ui-helper + [] + (when (exists? (.-NativeModules react-native)) + (.-UIHelper ^js (.-NativeModules react-native)))) + +(defn log-manager + [] + (when (exists? (.-NativeModules react-native)) + (.-LogManager ^js (.-NativeModules react-native)))) + +(defn utils + [] + (when (exists? (.-NativeModules react-native)) + (.-Utils ^js (.-NativeModules react-native)))) + +(defn network + [] + (when (exists? (.-NativeModules react-native)) + (.-NetworkManager ^js (.-NativeModules react-native)))) + (defn init [handler] (.addListener ^js (.-DeviceEventEmitter ^js react-native) "gethEvent" #(handler (.-jsonEvent ^js %)))) @@ -18,24 +53,24 @@ (defn clear-web-data [] (log/debug "[native-module] clear-web-data") - (when (status) - (.clearCookies ^js (status)) - (.clearStorageAPIs ^js (status)))) + (when (ui-helper) + (.clearCookies ^js (ui-helper)) + (.clearStorageAPIs ^js (ui-helper)))) (defn init-keystore [key-uid callback] (log/debug "[native-module] init-keystore" key-uid) - (.initKeystore ^js (status) key-uid callback)) + (.initKeystore ^js (encryption) key-uid callback)) (defn open-accounts [callback] (log/debug "[native-module] open-accounts") - (.openAccounts ^js (status) #(callback (types/json->clj %)))) + (.openAccounts ^js (account-manager) #(callback (types/json->clj %)))) (defn prepare-dir-and-update-config [key-uid config callback] (log/debug "[native-module] prepare-dir-and-update-config") - (.prepareDirAndUpdateConfig ^js (status) + (.prepareDirAndUpdateConfig ^js (account-manager) key-uid config #(callback (types/json->clj %)))) @@ -47,7 +82,7 @@ (init-keystore key-uid #(.saveAccountAndLoginWithKeycard - ^js (status) + ^js (account-manager) multiaccount-data password settings @@ -63,24 +98,24 @@ (let [config (if config (types/clj->json config) "")] (init-keystore key-uid - #(.loginWithConfig ^js (status) account-data hashed-password config)))) + #(.loginWithConfig ^js (account-manager) account-data hashed-password config)))) (defn login-account "NOTE: beware, the password has to be sha3 hashed" [{:keys [keyUid] :as request}] - (log/debug "[native-module] loginWithConfig") + (log/debug "[native-module] loginAccount") (clear-web-data) (init-keystore keyUid - #(.loginAccount ^js (status) (types/clj->json request)))) + #(.loginAccount ^js (account-manager) (types/clj->json request)))) (defn create-account-and-login [request] - (.createAccountAndLogin ^js (status) (types/clj->json request))) + (.createAccountAndLogin ^js (account-manager) (types/clj->json request))) (defn restore-account-and-login [request] - (.restoreAccountAndLogin ^js (status) (types/clj->json request))) + (.restoreAccountAndLogin ^js (account-manager) (types/clj->json request))) (defn export-db "NOTE: beware, the password has to be sha3 hashed" @@ -89,7 +124,7 @@ (clear-web-data) (init-keystore key-uid - #(.exportUnencryptedDatabase ^js (status) account-data hashed-password callback))) + #(.exportUnencryptedDatabase ^js (database) account-data hashed-password callback))) (defn import-db "NOTE: beware, the password has to be sha3 hashed" @@ -98,13 +133,13 @@ (clear-web-data) (init-keystore key-uid - #(.importUnencryptedDatabase ^js (status) account-data hashed-password))) + #(.importUnencryptedDatabase ^js (database) account-data hashed-password))) (defn logout [] (log/debug "[native-module] logout") (clear-web-data) - (.logout ^js (status))) + (.logout ^js (account-manager))) (defn multiaccount-load-account "NOTE: beware, the password has to be sha3 hashed @@ -114,7 +149,7 @@ from memory" [address hashed-password callback] (log/debug "[native-module] multiaccount-load-account") - (.multiAccountLoadAccount ^js (status) + (.multiAccountLoadAccount ^js (account-manager) (types/clj->json {:address address :password hashed-password}) callback)) @@ -127,7 +162,7 @@ [account-id paths callback] (log/debug "[native-module] multiaccount-derive-addresses") (when (status) - (.multiAccountDeriveAddresses ^js (status) + (.multiAccountDeriveAddresses ^js (account-manager) (types/clj->json {:accountID account-id :paths paths}) callback))) @@ -145,7 +180,7 @@ (when (status) (init-keystore key-uid - #(.multiAccountStoreAccount ^js (status) + #(.multiAccountStoreAccount ^js (account-manager) (types/clj->json {:accountID account-id :password hashed-password}) callback)))) @@ -158,7 +193,7 @@ account-id) (init-keystore key-uid - #(.multiAccountStoreDerived ^js (status) + #(.multiAccountStoreDerived ^js (account-manager) (types/clj->json {:accountID account-id :paths paths :password hashed-password}) @@ -171,7 +206,7 @@ to store the key" [n mnemonic-length paths callback] (log/debug "[native-module] multiaccount-generate-and-derive-addresses") - (.multiAccountGenerateAndDeriveAddresses ^js (status) + (.multiAccountGenerateAndDeriveAddresses ^js (account-manager) (types/clj->json {:n n :mnemonicPhraseLength mnemonic-length :bip39Passphrase "" @@ -181,7 +216,7 @@ (defn multiaccount-import-mnemonic [mnemonic password callback] (log/debug "[native-module] multiaccount-import-mnemonic") - (.multiAccountImportMnemonic ^js (status) + (.multiAccountImportMnemonic ^js (account-manager) (types/clj->json {:mnemonicPhrase mnemonic ;;NOTE this is not the multiaccount password :Bip39Passphrase password}) @@ -190,7 +225,7 @@ (defn multiaccount-import-private-key [private-key callback] (log/debug "[native-module] multiaccount-import-private-key") - (.multiAccountImportPrivateKey ^js (status) + (.multiAccountImportPrivateKey ^js (account-manager) (types/clj->json {:privateKey private-key}) callback)) @@ -198,13 +233,13 @@ "NOTE: beware, the password has to be sha3 hashed" [address hashed-password callback] (log/debug "[native-module] verify") - (.verify ^js (status) address hashed-password callback)) + (.verify ^js (account-manager) address hashed-password callback)) (defn verify-database-password "NOTE: beware, the password has to be sha3 hashed" [key-uid hashed-password callback] (log/debug "[native-module] verify-database-password") - (.verifyDatabasePassword ^js (status) key-uid hashed-password callback)) + (.verifyDatabasePassword ^js (account-manager) key-uid hashed-password callback)) (defn login-with-keycard [{:keys [key-uid multiaccount-data password chat-key node-config]}] @@ -212,47 +247,51 @@ (clear-web-data) (init-keystore key-uid - #(.loginWithKeycard ^js (status) multiaccount-data password chat-key (types/clj->json node-config)))) + #(.loginWithKeycard ^js (account-manager) + multiaccount-data + password + chat-key + (types/clj->json node-config)))) (defn set-soft-input-mode [mode] (log/debug "[native-module] set-soft-input-mode") - (.setSoftInputMode ^js (status) mode)) + (.setSoftInputMode ^js (ui-helper) mode)) (defn call-rpc [payload callback] (log/debug "[native-module] call-rpc") - (.callRPC ^js (status) payload callback)) + (.callRPC ^js (network) payload callback)) (defn call-private-rpc [payload callback] - (.callPrivateRPC ^js (status) payload callback)) + (.callPrivateRPC ^js (network) payload callback)) (defn hash-transaction "used for keycard" [rpcParams callback] (log/debug "[native-module] hash-transaction") - (.hashTransaction ^js (status) rpcParams callback)) + (.hashTransaction ^js (encryption) rpcParams callback)) (defn hash-message "used for keycard" [message callback] (log/debug "[native-module] hash-message") - (.hashMessage ^js (status) message callback)) + (.hashMessage ^js (encryption) message callback)) (defn start-searching-for-local-pairing-peers "starts a UDP multicast beacon that both listens for and broadcasts to LAN peers" [callback] (log/info "[native-module] Start Searching for Local Pairing Peers" {:fn :start-searching-for-local-pairing-peers}) - (.startSearchForLocalPairingPeers ^js (status) callback)) + (.startSearchForLocalPairingPeers ^js (network) callback)) (defn local-pairing-preflight-outbound-check "Checks whether the device has allows connecting to the local server" [callback] (log/info "[native-module] Performing local pairing preflight check") (when platform/ios? - (.localPairingPreflightOutboundCheck ^js (status) callback))) + (.localPairingPreflightOutboundCheck ^js (encryption) callback))) (defn get-connection-string-for-bootstrapping-another-device "Generates connection string form status-go for the purpose of local pairing on the sender end" @@ -260,7 +299,7 @@ (log/info "[native-module] Fetching Connection String" {:fn :get-connection-string-for-bootstrapping-another-device :config-json config-json}) - (.getConnectionStringForBootstrappingAnotherDevice ^js (status) config-json callback)) + (.getConnectionStringForBootstrappingAnotherDevice ^js (network) config-json callback)) (defn input-connection-string-for-bootstrapping "Provides connection string to status-go for the purpose of local pairing on the receiver end" @@ -269,7 +308,7 @@ {:fn :input-connection-string-for-bootstrapping :config-json config-json :connection-string connection-string}) - (.inputConnectionStringForBootstrapping ^js (status) connection-string config-json callback)) + (.inputConnectionStringForBootstrapping ^js (network) connection-string config-json callback)) (defn deserialize-and-compress-key "Provides a community id (public key) to status-go which is first deserialized @@ -280,7 +319,7 @@ (log/info "[native-module] Deserializing and then compressing public key" {:fn :deserialize-and-compress-key :key input-key}) - (.deserializeAndCompressKey ^js (status) input-key callback)) + (.deserializeAndCompressKey ^js (encryption) input-key callback)) (defn compressed-key->public-key "Provides compressed key to status-go and gets back the uncompressed public key via deserialization" @@ -288,59 +327,59 @@ (log/info "[native-module] Deserializing compressed key" {:fn :compressed-key->public-key :public-key public-key}) - (.multiformatDeserializePublicKey ^js (status) public-key deserialization-key callback)) + (.multiformatDeserializePublicKey ^js (encryption) public-key deserialization-key callback)) (defn hash-typed-data "used for keycard" [data callback] (log/debug "[native-module] hash-typed-data") - (.hashTypedData ^js (status) data callback)) + (.hashTypedData ^js (encryption) data callback)) (defn hash-typed-data-v4 "used for keycard" [data callback] (log/debug "[native-module] hash-typed-data-v4") - (.hashTypedDataV4 ^js (status) data callback)) + (.hashTypedDataV4 ^js (encryption) data callback)) (defn send-transaction-with-signature "used for keycard" [rpcParams sig callback] (log/debug "[native-module] send-transaction-with-signature") - (.sendTransactionWithSignature ^js (status) rpcParams sig callback)) + (.sendTransactionWithSignature ^js (network) rpcParams sig callback)) (defn sign-message "NOTE: beware, the password in rpcParams has to be sha3 hashed" [rpcParams callback] (log/debug "[native-module] sign-message") - (.signMessage ^js (status) rpcParams callback)) + (.signMessage ^js (encryption) rpcParams callback)) (defn recover-message [rpcParams callback] (log/debug "[native-module] recover") - (.recover ^js (status) rpcParams callback)) + (.recover ^js (network) rpcParams callback)) (defn send-transaction "NOTE: beware, the password has to be sha3 hashed" [rpcParams hashed-password callback] (log/debug "[native-module] send-transaction") - (.sendTransaction ^js (status) rpcParams hashed-password callback)) + (.sendTransaction ^js (network) rpcParams hashed-password callback)) (defn sign-typed-data "NOTE: beware, the password has to be sha3 hashed" [data account hashed-password callback] (log/debug "[native-module] sign-typed-data") - (.signTypedData ^js (status) data account hashed-password callback)) + (.signTypedData ^js (encryption) data account hashed-password callback)) (defn sign-typed-data-v4 "NOTE: beware, the password has to be sha3 hashed" [data account hashed-password callback] (log/debug "[native-module] sign-typed-data-v4") - (.signTypedDataV4 ^js (status) data account hashed-password callback)) + (.signTypedDataV4 ^js (encryption) data account hashed-password callback)) (defn send-logs [dbJson js-logs callback] (log/debug "[native-module] send-logs") - (.sendLogs ^js (status) dbJson js-logs callback)) + (.sendLogs ^js (log-manager) dbJson js-logs callback)) (defn close-application [] @@ -365,7 +404,7 @@ (defn set-blank-preview-flag [flag] (log/debug "[native-module] set-blank-preview-flag") - (.setBlankPreviewFlag ^js (status) flag)) + (.setBlankPreviewFlag ^js (encryption) flag)) (defn get-device-model-info [] @@ -393,7 +432,7 @@ (defn toggle-webview-debug [on] (log/debug "[native-module] toggle-webview-debug" on) - (.toggleWebviewDebug ^js (status) on)) + (.toggleWebviewDebug ^js (ui-helper) on)) (defn rooted-device? [callback] @@ -416,72 +455,72 @@ (defn encode-transfer [to-norm amount-hex] (log/debug "[native-module] encode-transfer") - (.encodeTransfer ^js (status) to-norm amount-hex)) + (.encodeTransfer ^js (encryption) to-norm amount-hex)) (defn decode-parameters [bytes-string types] (log/debug "[native-module] decode-parameters") - (let [json-str (.decodeParameters ^js (status) + (let [json-str (.decodeParameters ^js (encryption) (types/clj->json {:bytesString bytes-string :types types}))] (types/json->clj json-str))) (defn hex-to-number [hex] (log/debug "[native-module] hex-to-number") - (let [json-str (.hexToNumber ^js (status) hex)] + (let [json-str (.hexToNumber ^js (encryption) hex)] (types/json->clj json-str))) (defn number-to-hex [num] (log/debug "[native-module] number-to-hex") - (.numberToHex ^js (status) (str num))) + (.numberToHex ^js (encryption) (str num))) (defn sha3 [s] (log/debug "[native-module] sha3") (when s - (.sha3 ^js (status) (str s)))) + (.sha3 ^js (encryption) (str s)))) (defn utf8-to-hex [s] (log/debug "[native-module] utf8-to-hex") - (.utf8ToHex ^js (status) s)) + (.utf8ToHex ^js (encryption) s)) (defn hex-to-utf8 [s] (log/debug "[native-module] hex-to-utf8") - (.hexToUtf8 ^js (status) s)) + (.hexToUtf8 ^js (encryption) s)) (defn check-address-checksum [address] (log/debug "[native-module] check-address-checksum") - (let [result (.checkAddressChecksum ^js (status) address)] + (let [result (.checkAddressChecksum ^js (utils) address)] (types/json->clj result))) (defn address? [address] (log/debug "[native-module] address?") (when address - (let [result (.isAddress ^js (status) address)] + (let [result (.isAddress ^js (utils) address)] (types/json->clj result)))) (defn to-checksum-address [address] (log/debug "[native-module] to-checksum-address") - (.toChecksumAddress ^js (status) address)) + (.toChecksumAddress ^js (utils) address)) (defn validate-mnemonic "Validate that a mnemonic conforms to BIP39 dictionary/checksum standards" [mnemonic callback] (log/debug "[native-module] validate-mnemonic") - (.validateMnemonic ^js (status) mnemonic callback)) + (.validateMnemonic ^js (utils) mnemonic callback)) (defn delete-multiaccount "Delete multiaccount from database, deletes multiaccount's database and key files." [key-uid callback] (log/debug "[native-module] delete-multiaccount") - (.deleteMultiaccount ^js (status) key-uid callback)) + (.deleteMultiaccount ^js (account-manager) key-uid callback)) (defn delete-imported-key "Delete imported key file." @@ -493,7 +532,7 @@ [input selection] (log/debug "[native-module] resetKeyboardInput") (when platform/android? - (.resetKeyboardInputCursor ^js (status) input selection))) + (.resetKeyboardInputCursor ^js (ui-helper) input selection))) ;; passwords are hashed (defn reset-password @@ -501,12 +540,12 @@ (log/debug "[native-module] change-database-password") (init-keystore key-uid - #(.reEncryptDbAndKeystore ^js (status) key-uid current-password# new-password# callback))) + #(.reEncryptDbAndKeystore ^js (encryption) key-uid current-password# new-password# callback))) (defn convert-to-keycard-account [{:keys [key-uid] :as multiaccount-data} settings current-password# new-password callback] (log/debug "[native-module] convert-to-keycard-account") - (.convertToKeycardAccount ^js (status) + (.convertToKeycardAccount ^js (encryption) key-uid (types/clj->json multiaccount-data) (types/clj->json settings) @@ -517,7 +556,7 @@ (defn backup-disabled-data-dir [] - (.backupDisabledDataDir ^js (status))) + (.backupDisabledDataDir ^js (utils))) (defn fleets [] @@ -525,12 +564,12 @@ (defn keystore-dir [] - (.keystoreDir ^js (status))) + (.keystoreDir ^js (utils))) (defn log-file-directory [] - (.logFileDirectory ^js (status))) + (.logFileDirectory ^js (log-manager))) (defn init-status-go-logging [{:keys [enable? mobile-system? log-level callback]}] - (.initLogging ^js (status) enable? mobile-system? log-level callback)) + (.initLogging ^js (log-manager) enable? mobile-system? log-level callback)) diff --git a/src/status_im/constants.cljs b/src/status_im/constants.cljs index 881c554d8b..b899d11083 100644 --- a/src/status_im/constants.cljs +++ b/src/status_im/constants.cljs @@ -335,13 +335,6 @@ (def ^:const local-pairing-action-sync-device 3) (def ^:const local-pairing-action-pairing-installation 4) -(def ^:const serialization-key - "We pass this serialization key as a parameter to MultiformatSerializePublicKey - function at status-go, This key determines the output base of the serialization. - according to https://specs.status.im/spec/2#public-key-serialization we serialize - keys with base58btc encoding" - "z") - (def ^:const deserialization-key "We pass this deserialization key as a parameter to MultiformatDeserializePublicKey function at status-go, This key determines the output base of the deserialization.