feat_: support use status backend server (#21450)

* chore_: use status.go v2 endpoint

39511298...e255fb8b

* feat: use status backend server (#21550)

* chore: add env variable STATUS_BACKEND_SERVER_IMAGE_SERVER_URI_PREFIX

* update doc

* fix_: image_server lint issue

* chore_: update status-go version
This commit is contained in:
frank 2024-11-19 18:50:01 +08:00 committed by GitHub
parent 08c97b078a
commit 7acaff6167
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 1925 additions and 434 deletions

View File

@ -0,0 +1,53 @@
## Solution to use Status Backend Server
`StatusBackendClient` is the entry point to use Status Backend Server. We need always to call `status-im.setup.status-backend-client/init` whether `STATUS_BACKEND_SERVER_ENABLED` is `1` or not. If it's not enabled, the invocation to functions in `native-module.core` will be delegated to built-in status-go library, otherwise it will be delegated to status-go running in status-backend server. Currently, all functions has usages in `native-module.core` should be supported delegated to.
NOTE: not all the native functions used `StatusBackendClient`, only the corresponding functions in `native-module.core` has usages should be supported delegated to ATM.
related [PR](https://github.com/status-im/status-mobile/pull/21550)
## Usage
### Add environment variables to your local machine:
```shell
# enable using status backend server or not, otherwise it will use built-in status-go library
export STATUS_BACKEND_SERVER_ENABLED=1
#The host should contain an IP address and a port separated by a colon.
#The port comes from your running status backend server.
#If you run it by PORT=60000 make run-status-backend , then host will likely be 127.0.0.1:60000
export STATUS_BACKEND_SERVER_HOST="127.0.0.1:60000"
export STATUS_BACKEND_SERVER_ROOT_DATA_DIR="/path/to/your/root/data/dir"
```
You need to change `STATUS_BACKEND_SERVER_ROOT_DATA_DIR` to your preferred directory and ensure it exists, it should be in absolute path.
All the db files and log files(requests.log/geth.log) and keystore files etc will be stored in this directory.
### Start the status backend server:
```shell
PORT=60000 make run-status-backend
```
MAKE SURE the status-backend is checked out to a revision that's at least compatible with the revision in status-mobile/status-go-version.json before starting the server.
For the Android simulator, you need to reverse the port:
```shell
adb reverse tcp:60000 tcp:60000
```
However, there is restriction when use adb reverse, we use random port for media server. So I'd suggest use "10.0.2.2:60000" as `STATUS_BACKEND_SERVER_HOST`.
### Debug status-go using IDEA
Assume you've already set up the development environment for status-go, open status-go project use IDEA, run `make generate` with terminal in the status-go project root directory to ensure all the generated files are up to date, then open `cmd/status-backend/main.go` file, navigate to function `main()`, click the green play button on the left of `main()`, choose `Modify Run Configuration`, in `Program arguments` section, add `--address=localhost:60000 --media-https=false`, then click `OK`, finally click the green play button on the left of `main()` again and choose `Debug ...`.
Basically, you don't have to run `make generate` again and again, just run it once at the beginning. So you can re-run and debug it faster!
## Known Android simulator issues
- Issue#1: Android simulator may not display images due to TLS certificate validation issues with the image server
- solution: use http instead of https for media server with command: `MEDIA_HTTPS=false PORT=60000 make run-status-backend`, currently status-go does not support http for media server. You have to use this draft [PR](https://github.com/status-im/status-go/pull/6060), you also need to set env variable `STATUS_BACKEND_SERVER_IMAGE_SERVER_URI_PREFIX` to "http://10.0.2.2:" so that `image_server.cljs` can work, and to make `/accountInitials` work, you need to copy `Inter-Medium.ttf` to your host machine from the android simulator, let's say you store it in `/Users/mac/Downloads/Inter-Medium.ttf`, then you need to update `get-font-file-ready` manually in `image_server.cljs` to return the correct path so that status backend server can access it.
- Issue#2: exportUnencryptedDatabaseV2/import-multiaccount does not work for android, probably cause of tech debt, I found it during creating the draft PR.
- Issue#3: unable to invoke `multiaccounts_storeIdentityImage` to change avatar image.
- The reason is that we path the absolute path of the image to the backend server, but the image file is stored in the android simulator. the backend server cannot access it as it runs in the host machine.
If you're using ios simulator, you can skip above issues!
## Details for issue#1 if you're interested
- we use `react-native-fast-image` which use okhttpclient behind
- we were using custom cert for https
- we fetch the custom cert through endpoint `ImageServerTLSCert`
- we fetched it through built-in status-go before, now we need to fetch it through status backend server
- we expect `OkHttpClientProvider.setOkHttpClientFactory(StatusOkHttpClientFactory())` to be invoked early(will trigger fetching wrong custom cert via built-in status-go since StatusBackendClient is not initialised yet!) in `MainApplication.kt` before executing clojure code, otherwise we will get black screen after `make run-android` . After deep research, I found there's no way to update the cert okhttpclient used to the correct one return from status backend server

View File

@ -29,6 +29,8 @@
#import <Security/Security.h> #import <Security/Security.h>
#import <react/config/ReactNativeConfig.h> #import <react/config/ReactNativeConfig.h>
#import "StatusBackendClient.h"
//TODO: properly import the framework //TODO: properly import the framework
extern "C" NSString* StatusgoImageServerTLSCert(); extern "C" NSString* StatusgoImageServerTLSCert();
@ -188,7 +190,12 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
__block NSURLCredential *credential = nil; __block NSURLCredential *credential = nil;
NSString *pemCert = StatusgoImageServerTLSCert(); NSString *pemCert = [StatusBackendClient executeStatusGoRequestWithResult:@"ImageServerTLSCert"
body:@""
statusgoFunction:^NSString *{
return StatusgoImageServerTLSCert();
}];
pemCert = [pemCert stringByReplacingOccurrencesOfString:@"-----BEGIN CERTIFICATE-----\n" withString:@""]; pemCert = [pemCert stringByReplacingOccurrencesOfString:@"-----BEGIN CERTIFICATE-----\n" withString:@""];
pemCert = [pemCert stringByReplacingOccurrencesOfString:@"\n-----END CERTIFICATE-----" withString:@""]; pemCert = [pemCert stringByReplacingOccurrencesOfString:@"\n-----END CERTIFICATE-----" withString:@""];
NSData *derCert = [[NSData alloc] initWithBase64EncodedString:pemCert options:NSDataBase64DecodingIgnoreUnknownCharacters]; NSData *derCert = [[NSData alloc] initWithBase64EncodedString:pemCert options:NSDataBase64DecodingIgnoreUnknownCharacters];

View File

@ -24,25 +24,23 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
@ReactMethod @ReactMethod
fun createAccountAndLogin(createAccountRequest: String) { fun createAccountAndLogin(createAccountRequest: String) {
Log.d(TAG, "createAccountAndLogin") Log.d(TAG, "createAccountAndLogin")
val result = Statusgo.createAccountAndLogin(createAccountRequest)
if (result.startsWith("{\"error\":\"\"")) { StatusBackendClient.executeStatusGoRequest(
Log.d(TAG, "createAccountAndLogin success: $result") endpoint = "CreateAccountAndLogin",
Log.d(TAG, "Geth node started") requestBody = createAccountRequest,
} else { statusgoFunction = { Statusgo.createAccountAndLogin(createAccountRequest) }
Log.e(TAG, "createAccountAndLogin failed: $result") )
}
} }
@ReactMethod @ReactMethod
fun restoreAccountAndLogin(restoreAccountRequest: String) { fun restoreAccountAndLogin(restoreAccountRequest: String) {
Log.d(TAG, "restoreAccountAndLogin") Log.d(TAG, "restoreAccountAndLogin")
val result = Statusgo.restoreAccountAndLogin(restoreAccountRequest)
if (result.startsWith("{\"error\":\"\"")) { StatusBackendClient.executeStatusGoRequest(
Log.d(TAG, "restoreAccountAndLogin success: $result") endpoint = "RestoreAccountAndLogin",
Log.d(TAG, "Geth node started") requestBody = restoreAccountRequest,
} else { statusgoFunction = { Statusgo.restoreAccountAndLogin(restoreAccountRequest) }
Log.e(TAG, "restoreAccountAndLogin failed: $result") )
}
} }
private fun updateConfig(jsonConfigString: String, absRootDirPath: String, keystoreDirPath: String): String { private fun updateConfig(jsonConfigString: String, absRootDirPath: String, keystoreDirPath: String): String {
@ -173,12 +171,7 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
accountsData, accountsData,
chatKey chatKey
) )
if (result.startsWith("{\"error\":\"\"")) { utils.handleStatusGoResponse(result, "saveAccountAndLoginWithKeycard")
Log.d(TAG, "saveAccountAndLoginWithKeycard result: $result")
Log.d(TAG, "Geth node started")
} else {
Log.e(TAG, "saveAccountAndLoginWithKeycard failed: $result")
}
} catch (e: JSONException) { } catch (e: JSONException) {
Log.e(TAG, "JSON conversion failed: ${e.message}") Log.e(TAG, "JSON conversion failed: ${e.message}")
} }
@ -189,11 +182,7 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
Log.d(TAG, "loginWithKeycard") Log.d(TAG, "loginWithKeycard")
utils.migrateKeyStoreDir(accountData, password) utils.migrateKeyStoreDir(accountData, password)
val result = Statusgo.loginWithKeycard(accountData, password, chatKey, nodeConfigJSON) val result = Statusgo.loginWithKeycard(accountData, password, chatKey, nodeConfigJSON)
if (result.startsWith("{\"error\":\"\"")) { utils.handleStatusGoResponse(result, "loginWithKeycard")
Log.d(TAG, "LoginWithKeycard result: $result")
} else {
Log.e(TAG, "LoginWithKeycard failed: $result")
}
} }
@ReactMethod @ReactMethod
@ -201,22 +190,17 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
Log.d(TAG, "loginWithConfig") Log.d(TAG, "loginWithConfig")
utils.migrateKeyStoreDir(accountData, password) utils.migrateKeyStoreDir(accountData, password)
val result = Statusgo.loginWithConfig(accountData, password, configJSON) val result = Statusgo.loginWithConfig(accountData, password, configJSON)
if (result.startsWith("{\"error\":\"\"")) { utils.handleStatusGoResponse(result, "loginWithConfig")
Log.d(TAG, "LoginWithConfig result: $result")
} else {
Log.e(TAG, "LoginWithConfig failed: $result")
}
} }
@ReactMethod @ReactMethod
fun loginAccount(request: String) { fun loginAccount(request: String) {
Log.d(TAG, "loginAccount") Log.d(TAG, "loginAccount")
val result = Statusgo.loginAccount(request) StatusBackendClient.executeStatusGoRequest(
if (result.startsWith("{\"error\":\"\"")) { endpoint = "LoginAccount",
Log.d(TAG, "loginAccount result: $result") requestBody = request,
} else { statusgoFunction = { Statusgo.loginAccount(request) }
Log.e(TAG, "loginAccount failed: $result") )
}
} }
@ReactMethod @ReactMethod
@ -224,16 +208,31 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
val absRootDirPath = utils.getNoBackupDirectory() val absRootDirPath = utils.getNoBackupDirectory()
val newKeystoreDir = utils.pathCombine(absRootDirPath, "keystore") val newKeystoreDir = utils.pathCombine(absRootDirPath, "keystore")
utils.executeRunnableStatusGoMethod( val jsonParams = JSONObject()
{ Statusgo.verifyAccountPassword(newKeystoreDir, address, password) }, jsonParams.put("keyStoreDir", newKeystoreDir)
jsonParams.put("address", address)
jsonParams.put("password", password)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "VerifyAccountPasswordV2",
requestBody = jsonParams.toString(),
statusgoFunction = { Statusgo.verifyAccountPasswordV2(jsonParams.toString()) },
callback callback
) )
} }
@ReactMethod @ReactMethod
fun verifyDatabasePassword(keyUID: String, password: String, callback: Callback) { fun verifyDatabasePassword(keyUID: String, password: String, callback: Callback) {
utils.executeRunnableStatusGoMethod( val jsonParams = JSONObject()
{ Statusgo.verifyDatabasePassword(keyUID, password) }, jsonParams.put("keyUID", keyUID)
jsonParams.put("password", password)
val jsonString = jsonParams.toString()
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "VerifyDatabasePasswordV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.verifyDatabasePasswordV2(jsonString) },
callback callback
) )
} }
@ -249,79 +248,136 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
@ReactMethod @ReactMethod
private fun initializeApplication(request: String, callback: Callback) { private fun initializeApplication(request: String, callback: Callback) {
Log.d(TAG, "initializeApplication") Log.d(TAG, "initializeApplication")
Log.d(TAG, "[Initializing application $request") StatusBackendClient.executeStatusGoRequestWithCallback(
utils.executeRunnableStatusGoMethod({ Statusgo.initializeApplication(request) }, callback) "InitializeApplication",
request,
{ Statusgo.initializeApplication(request) },
callback
)
} }
@ReactMethod @ReactMethod
private fun acceptTerms(callback: Callback) { private fun acceptTerms(callback: Callback) {
Log.d(TAG, "acceptTerms") Log.d(TAG, "acceptTerms")
utils.executeRunnableStatusGoMethod({ Statusgo.acceptTerms() }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
"AcceptTerms",
"",
{ Statusgo.acceptTerms() },
callback
)
} }
@ReactMethod @ReactMethod
fun logout() { fun logout() {
Log.d(TAG, "logout") Log.d(TAG, "logout")
val runnable = Runnable { StatusBackendClient.executeStatusGoRequest(
val result = Statusgo.logout() endpoint = "Logout",
if (result.startsWith("{\"error\":\"\"")) { requestBody = "",
Log.d(TAG, "Logout result: $result") statusgoFunction = { Statusgo.logout() }
} else { )
Log.e(TAG, "Logout failed: $result")
}
}
StatusThreadPoolExecutor.getInstance().execute(runnable)
} }
@ReactMethod @ReactMethod
fun multiAccountStoreAccount(json: String, callback: Callback) { fun multiAccountStoreAccount(json: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountStoreAccount(json) }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "MultiAccountStoreAccount",
requestBody = json,
statusgoFunction = { Statusgo.multiAccountStoreAccount(json) },
callback = callback
)
} }
@ReactMethod @ReactMethod
fun multiAccountLoadAccount(json: String, callback: Callback) { fun multiAccountLoadAccount(json: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountLoadAccount(json) }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "MultiAccountLoadAccount",
requestBody = json,
statusgoFunction = { Statusgo.multiAccountLoadAccount(json) },
callback = callback
)
} }
@ReactMethod @ReactMethod
fun multiAccountDeriveAddresses(json: String, callback: Callback) { fun multiAccountDeriveAddresses(json: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountDeriveAddresses(json) }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "MultiAccountDeriveAddresses",
requestBody = json,
statusgoFunction = { Statusgo.multiAccountDeriveAddresses(json) },
callback = callback
)
} }
@ReactMethod @ReactMethod
fun multiAccountGenerateAndDeriveAddresses(json: String, callback: Callback) { fun multiAccountGenerateAndDeriveAddresses(json: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountGenerateAndDeriveAddresses(json) }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "MultiAccountGenerateAndDeriveAddresses",
requestBody = json,
statusgoFunction = { Statusgo.multiAccountGenerateAndDeriveAddresses(json) },
callback = callback
)
} }
@ReactMethod @ReactMethod
fun multiAccountStoreDerived(json: String, callback: Callback) { fun multiAccountStoreDerived(json: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountStoreDerivedAccounts(json) }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "MultiAccountStoreDerivedAccounts",
requestBody = json,
statusgoFunction = { Statusgo.multiAccountStoreDerivedAccounts(json) },
callback = callback
)
} }
@ReactMethod @ReactMethod
fun multiAccountImportMnemonic(json: String, callback: Callback) { fun multiAccountImportMnemonic(json: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountImportMnemonic(json) }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "MultiAccountImportMnemonic",
requestBody = json,
statusgoFunction = { Statusgo.multiAccountImportMnemonic(json) },
callback = callback
)
} }
@ReactMethod @ReactMethod
fun multiAccountImportPrivateKey(json: String, callback: Callback) { fun multiAccountImportPrivateKey(json: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountImportPrivateKey(json) }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "MultiAccountImportPrivateKey",
requestBody = json,
statusgoFunction = { Statusgo.multiAccountImportPrivateKey(json) },
callback = callback
)
} }
@ReactMethod @ReactMethod
fun deleteMultiaccount(keyUID: String, callback: Callback) { fun deleteMultiaccount(keyUID: String, callback: Callback) {
val keyStoreDir = utils.getKeyStorePath(keyUID) val keyStoreDir = utils.getKeyStorePath(keyUID)
utils.executeRunnableStatusGoMethod({ Statusgo.deleteMultiaccount(keyUID, keyStoreDir) }, callback) val params = JSONObject().apply {
put("keyUID", keyUID)
put("keyStoreDir", keyStoreDir)
}
val jsonString = params.toString()
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "DeleteMultiaccountV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.deleteMultiaccountV2(jsonString) },
callback
)
} }
@ReactMethod @ReactMethod
fun getRandomMnemonic(callback: Callback) { fun getRandomMnemonic(callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.getRandomMnemonic() }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
"GetRandomMnemonic",
"",
{ Statusgo.getRandomMnemonic() },
callback
)
} }
@ReactMethod @ReactMethod
fun createAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic: String, callback: Callback) { fun createAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic: String, callback: Callback) {
utils.executeRunnableStatusGoMethod( StatusBackendClient.executeStatusGoRequestWithCallback(
"CreateAccountFromMnemonicAndDeriveAccountsForPaths",
mnemonic,
{ Statusgo.createAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic) }, { Statusgo.createAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic) },
callback callback
) )
@ -329,7 +385,12 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
@ReactMethod @ReactMethod
fun createAccountFromPrivateKey(json: String, callback: Callback) { fun createAccountFromPrivateKey(json: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.createAccountFromPrivateKey(json) }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "CreateAccountFromPrivateKey",
requestBody = json,
statusgoFunction = { Statusgo.createAccountFromPrivateKey(json) },
callback = callback
)
} }
companion object { companion object {

View File

@ -9,6 +9,8 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod import com.facebook.react.bridge.ReactMethod
import statusgo.Statusgo import statusgo.Statusgo
import java.io.File import java.io.File
import org.json.JSONObject
import org.json.JSONException
class DatabaseManager(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { class DatabaseManager(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
@ -17,22 +19,43 @@ class DatabaseManager(private val reactContext: ReactApplicationContext) : React
override fun getName() = "DatabaseManager" override fun getName() = "DatabaseManager"
private fun getExportDBFile(): File { private fun getExportDBFile(): File {
StatusBackendClient.getInstance()?.let {
if (it.serverEnabled) {
return File(it.rootDataDir, exportDBFileName)
}
}
val pubDirectory = reactContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) val pubDirectory = reactContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
return File(pubDirectory, exportDBFileName) return File(pubDirectory, exportDBFileName)
} }
@ReactMethod @ReactMethod
fun exportUnencryptedDatabase(accountData: String, password: String, callback: Callback) { fun exportUnencryptedDatabase(accountData: String, password: String, callback: Callback) {
Log.d(TAG, "login") Log.d(TAG, "exportUnencryptedDatabase")
val newFile = getExportDBFile() val newFile = getExportDBFile()
utils.migrateKeyStoreDir(accountData, password) utils.migrateKeyStoreDir(accountData, password)
val result = Statusgo.exportUnencryptedDatabase(accountData, password, newFile.absolutePath)
if (result.startsWith("{\"error\":\"\"")) { try {
Log.d(TAG, "Login result: $result") val accountJson = JSONObject(accountData)
} else {
Log.e(TAG, "Login failed: $result") val params = JSONObject().apply {
put("account", accountJson)
put("password", password)
put("databasePath", newFile.absolutePath)
}
val jsonParams = params.toString()
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "ExportUnencryptedDatabaseV2",
requestBody = jsonParams,
statusgoFunction = { Statusgo.exportUnencryptedDatabaseV2(jsonParams) },
callback = null
)
callback.invoke(newFile.absolutePath)
} catch (e: JSONException) {
Log.e(TAG, "Error parsing account data: ${e.message}")
} }
} }
@ -43,11 +66,25 @@ class DatabaseManager(private val reactContext: ReactApplicationContext) : React
val newFile = getExportDBFile() val newFile = getExportDBFile()
utils.migrateKeyStoreDir(accountData, password) utils.migrateKeyStoreDir(accountData, password)
val result = Statusgo.importUnencryptedDatabase(accountData, password, newFile.absolutePath)
if (result.startsWith("{\"error\":\"\"")) { try {
Log.d(TAG, "import result: $result") val accountJson = JSONObject(accountData)
} else {
Log.e(TAG, "import failed: $result") val params = JSONObject().apply {
put("account", accountJson)
put("password", password)
put("databasePath", newFile.absolutePath)
}
val jsonParams = params.toString()
StatusBackendClient.executeStatusGoRequest(
endpoint = "ImportUnencryptedDatabaseV2",
requestBody = jsonParams,
statusgoFunction = { Statusgo.importUnencryptedDatabaseV2(jsonParams) }
)
} catch (e: JSONException) {
Log.e(TAG, "Error parsing account data: ${e.message}")
} }
} }

View File

@ -7,6 +7,7 @@ import com.facebook.react.bridge.Callback;
import android.util.Log; import android.util.Log;
import statusgo.Statusgo; import statusgo.Statusgo;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject;
import java.util.function.Function; import java.util.function.Function;
import android.app.Activity; import android.app.Activity;
import android.view.WindowManager; import android.view.WindowManager;
@ -39,67 +40,151 @@ public class EncryptionUtils extends ReactContextBaseJavaModule {
final String commonKeydir = this.utils.pathCombine(this.utils.getNoBackupDirectory(), "/keystore"); final String commonKeydir = this.utils.pathCombine(this.utils.getNoBackupDirectory(), "/keystore");
final String keydir = this.utils.pathCombine(commonKeydir, keyUID); final String keydir = this.utils.pathCombine(commonKeydir, keyUID);
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.initKeystore(keydir), callback); StatusBackendClient.executeStatusGoRequestWithCallback(
"InitKeystore",
keydir,
() -> Statusgo.initKeystore(keydir),
callback
);
} }
@ReactMethod @ReactMethod
public void reEncryptDbAndKeystore(final String keyUID, final String password, final String newPassword, final Callback callback) throws JSONException { 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); JSONObject params = new JSONObject();
params.put("keyUID", keyUID);
params.put("oldPassword", password);
params.put("newPassword", newPassword);
String jsonParams = params.toString();
StatusBackendClient.executeStatusGoRequestWithCallback(
"ChangeDatabasePasswordV2",
jsonParams,
() -> Statusgo.changeDatabasePasswordV2(jsonParams),
callback
);
} }
@ReactMethod @ReactMethod
public void convertToKeycardAccount(final String keyUID, final String accountData, final String options, final String keycardUID, final String password, 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 newPassword, final Callback callback) throws JSONException {
final String keyStoreDir = this.utils.getKeyStorePath(keyUID); final String keyStoreDir = this.utils.getKeyStorePath(keyUID);
this.utils.executeRunnableStatusGoMethod(() -> { JSONObject params = new JSONObject();
Statusgo.initKeystore(keyStoreDir); params.put("keyUID", keyUID);
return Statusgo.convertToKeycardAccount(accountData, options, keycardUID, password, newPassword); params.put("account", new JSONObject(accountData));
}, callback); params.put("settings", new JSONObject(options));
params.put("keycardUID", keycardUID);
params.put("oldPassword", password);
params.put("newPassword", newPassword);
final String jsonParams = params.toString();
StatusBackendClient.executeStatusGoRequest(
"InitKeystore",
keyStoreDir,
() -> Statusgo.initKeystore(keyStoreDir)
);
StatusBackendClient.executeStatusGoRequestWithCallback(
"ConvertToKeycardAccountV2",
jsonParams,
() -> Statusgo.convertToKeycardAccountV2(jsonParams),
callback
);
} }
@ReactMethod(isBlockingSynchronousMethod = true) @ReactMethod(isBlockingSynchronousMethod = true)
public String encodeTransfer(final String to, final String value) { public String encodeTransfer(final String to, final String value) {
return Statusgo.encodeTransfer(to, value); try {
JSONObject params = new JSONObject();
params.put("to", to);
params.put("value", value);
String jsonParams = params.toString();
return StatusBackendClient.executeStatusGoRequestWithResult(
"EncodeTransferV2",
jsonParams,
() -> Statusgo.encodeTransferV2(jsonParams)
);
} catch (JSONException e) {
Log.e(TAG, "Error creating JSON for encodeTransfer: " + e.getMessage());
return null;
}
} }
@ReactMethod(isBlockingSynchronousMethod = true) @ReactMethod(isBlockingSynchronousMethod = true)
public String encodeFunctionCall(final String method, final String paramsJSON) { public String encodeFunctionCall(final String method, final String paramsJSON) {
return Statusgo.encodeFunctionCall(method, paramsJSON); try {
JSONObject params = new JSONObject();
params.put("method", method);
params.put("paramsJSON", new JSONObject(paramsJSON));
String jsonString = params.toString();
return StatusBackendClient.executeStatusGoRequestWithResult(
"EncodeFunctionCallV2",
jsonString,
() -> Statusgo.encodeFunctionCallV2(jsonString)
);
} catch (JSONException e) {
Log.e(TAG, "Error creating JSON for encodeFunctionCall: " + e.getMessage());
return null;
}
} }
@ReactMethod(isBlockingSynchronousMethod = true) @ReactMethod(isBlockingSynchronousMethod = true)
public String decodeParameters(final String decodeParamJSON) { public String decodeParameters(final String decodeParamJSON) {
return Statusgo.decodeParameters(decodeParamJSON); return StatusBackendClient.executeStatusGoRequestWithResult(
"DecodeParameters",
decodeParamJSON,
() -> Statusgo.decodeParameters(decodeParamJSON)
);
} }
@ReactMethod(isBlockingSynchronousMethod = true) @ReactMethod(isBlockingSynchronousMethod = true)
public String hexToNumber(final String hex) { public String hexToNumber(final String hex) {
return Statusgo.hexToNumber(hex); return StatusBackendClient.executeStatusGoRequestWithResult(
"HexToNumber",
hex,
() -> Statusgo.hexToNumber(hex)
);
} }
@ReactMethod(isBlockingSynchronousMethod = true) @ReactMethod(isBlockingSynchronousMethod = true)
public String numberToHex(final String numString) { public String numberToHex(final String numString) {
return Statusgo.numberToHex(numString); return StatusBackendClient.executeStatusGoRequestWithResult(
"NumberToHex",
numString,
() -> Statusgo.numberToHex(numString)
);
} }
@ReactMethod(isBlockingSynchronousMethod = true) @ReactMethod(isBlockingSynchronousMethod = true)
public String sha3(final String str) { public String sha3(final String str) {
return Statusgo.sha3(str); return StatusBackendClient.executeStatusGoRequestWithResult(
"Sha3",
str,
() -> Statusgo.sha3(str)
);
} }
@ReactMethod(isBlockingSynchronousMethod = true) @ReactMethod(isBlockingSynchronousMethod = true)
public String utf8ToHex(final String str) { public String utf8ToHex(final String str) {
return Statusgo.utf8ToHex(str); return StatusBackendClient.executeStatusGoRequestWithResult(
"Utf8ToHex",
str,
() -> Statusgo.utf8ToHex(str)
);
} }
@ReactMethod(isBlockingSynchronousMethod = true) @ReactMethod(isBlockingSynchronousMethod = true)
public String hexToUtf8(final String str) { public String hexToUtf8(final String str) {
return Statusgo.hexToUtf8(str); return StatusBackendClient.executeStatusGoRequestWithResult(
"HexToUtf8",
str,
() -> Statusgo.hexToUtf8(str)
);
} }
@ReactMethod(isBlockingSynchronousMethod = true) @ReactMethod(isBlockingSynchronousMethod = true)
public String serializeLegacyKey(final String publicKey) { public String serializeLegacyKey(final String publicKey) {
return Statusgo.serializeLegacyKey(publicKey); return StatusBackendClient.executeStatusGoRequestWithResult(
"SerializeLegacyKey",
publicKey,
() -> Statusgo.serializeLegacyKey(publicKey)
);
} }
@ReactMethod @ReactMethod
@ -130,22 +215,46 @@ public class EncryptionUtils extends ReactContextBaseJavaModule {
@ReactMethod @ReactMethod
public void hashTransaction(final String txArgsJSON, final Callback callback) throws JSONException { public void hashTransaction(final String txArgsJSON, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.hashTransaction(txArgsJSON), callback); StatusBackendClient.executeStatusGoRequestWithCallback(
"HashTransaction",
txArgsJSON,
() -> Statusgo.hashTransaction(txArgsJSON),
callback
);
} }
@ReactMethod @ReactMethod
public void hashMessage(final String message, final Callback callback) throws JSONException { public void hashMessage(final String message, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.hashMessage(message), callback); StatusBackendClient.executeStatusGoRequestWithCallback(
"HashMessage",
message,
() -> Statusgo.hashMessage(message),
callback
);
} }
@ReactMethod @ReactMethod
public void multiformatDeserializePublicKey(final String multiCodecKey, final String base58btc, final Callback callback) throws JSONException { public void multiformatDeserializePublicKey(final String multiCodecKey, final String base58btc, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiformatDeserializePublicKey(multiCodecKey,base58btc), callback); JSONObject params = new JSONObject();
params.put("key", multiCodecKey);
params.put("outBase", base58btc);
String jsonParams = params.toString();
StatusBackendClient.executeStatusGoRequestWithCallback(
"MultiformatDeserializePublicKeyV2",
jsonParams,
() -> Statusgo.multiformatDeserializePublicKeyV2(jsonParams),
callback
);
} }
@ReactMethod @ReactMethod
public void deserializeAndCompressKey(final String desktopKey, final Callback callback) throws JSONException { public void deserializeAndCompressKey(final String desktopKey, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.deserializeAndCompressKey(desktopKey), callback); StatusBackendClient.executeStatusGoRequestWithCallback(
"DeserializeAndCompressKey",
desktopKey,
() -> Statusgo.deserializeAndCompressKey(desktopKey),
callback
);
} }
@ReactMethod @ReactMethod
@ -160,7 +269,12 @@ public class EncryptionUtils extends ReactContextBaseJavaModule {
@ReactMethod @ReactMethod
public void signMessage(final String rpcParams, final Callback callback) throws JSONException { public void signMessage(final String rpcParams, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.signMessage(rpcParams), callback); StatusBackendClient.executeStatusGoRequestWithCallback(
"SignMessage",
rpcParams,
() -> Statusgo.signMessage(rpcParams),
callback
);
} }
@ReactMethod @ReactMethod

View File

@ -206,7 +206,12 @@ class LogManager(private val reactContext: ReactApplicationContext) : ReactConte
put("LogRequestFile", getRequestLogFile().absolutePath) put("LogRequestFile", getRequestLogFile().absolutePath)
} }
val config = jsonConfig.toString() val config = jsonConfig.toString()
utils.executeRunnableStatusGoMethod({ Statusgo.initLogging(config) }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "InitLogging",
requestBody = config,
statusgoFunction = { Statusgo.initLogging(config) },
callback = callback
)
} }
@ReactMethod(isBlockingSynchronousMethod = true) @ReactMethod(isBlockingSynchronousMethod = true)

View File

@ -16,7 +16,12 @@ class NetworkManager(private val reactContext: ReactApplicationContext) : ReactC
@ReactMethod @ReactMethod
fun startSearchForLocalPairingPeers(callback: Callback) { fun startSearchForLocalPairingPeers(callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.startSearchForLocalPairingPeers() }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "StartSearchForLocalPairingPeers",
requestBody = "",
statusgoFunction = { Statusgo.startSearchForLocalPairingPeers() },
callback = callback
)
} }
@ReactMethod @ReactMethod
@ -26,48 +31,85 @@ class NetworkManager(private val reactContext: ReactApplicationContext) : ReactC
val keyUID = senderConfig.getString("keyUID") val keyUID = senderConfig.getString("keyUID")
val keyStorePath = utils.getKeyStorePath(keyUID) val keyStorePath = utils.getKeyStorePath(keyUID)
senderConfig.put("keystorePath", keyStorePath) senderConfig.put("keystorePath", keyStorePath)
val jsonString = jsonConfig.toString()
utils.executeRunnableStatusGoMethod( StatusBackendClient.executeStatusGoRequestWithCallback(
{ Statusgo.getConnectionStringForBootstrappingAnotherDevice(jsonConfig.toString()) }, endpoint = "GetConnectionStringForBootstrappingAnotherDevice",
requestBody = jsonString,
statusgoFunction = { Statusgo.getConnectionStringForBootstrappingAnotherDevice(jsonString) },
callback callback
) )
} }
@ReactMethod @ReactMethod
fun inputConnectionStringForBootstrapping(connectionString: String, configJSON: String, callback: Callback) { fun inputConnectionStringForBootstrapping(connectionString: String, configJSON: String, callback: Callback) {
val jsonConfig = JSONObject(configJSON) val receiverClientConfig = JSONObject(configJSON)
utils.executeRunnableStatusGoMethod( val params = JSONObject().apply {
{ Statusgo.inputConnectionStringForBootstrapping(connectionString, jsonConfig.toString()) }, put("connectionString", connectionString)
put("receiverClientConfig", receiverClientConfig)
}
val jsonString = params.toString()
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "InputConnectionStringForBootstrappingV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.inputConnectionStringForBootstrappingV2(jsonString) },
callback callback
) )
} }
@ReactMethod @ReactMethod
fun sendTransactionWithSignature(txArgsJSON: String, signature: String, callback: Callback) { fun sendTransactionWithSignature(txArgsJSON: String, signature: String, callback: Callback) {
utils.executeRunnableStatusGoMethod( StatusBackendClient.executeStatusGoRequestWithCallback(
{ Statusgo.sendTransactionWithSignature(txArgsJSON, signature) }, endpoint = "SendTransactionWithSignature",
requestBody = txArgsJSON,
statusgoFunction = { Statusgo.sendTransactionWithSignature(txArgsJSON, signature) },
callback callback
) )
} }
@ReactMethod @ReactMethod
fun sendTransaction(txArgsJSON: String, password: String, callback: Callback) { fun sendTransaction(txArgsJSON: String, password: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.sendTransaction(txArgsJSON, password) }, callback) val jsonParams = JSONObject().apply {
put("txArgs", JSONObject(txArgsJSON))
put("password", password)
}
val jsonString = jsonParams.toString()
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "SendTransactionV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.sendTransactionV2(jsonString) },
callback
)
} }
@ReactMethod @ReactMethod
fun callRPC(payload: String, callback: Callback) { fun callRPC(payload: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.callRPC(payload) }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "CallRPC",
requestBody = payload,
statusgoFunction = { Statusgo.callRPC(payload) },
callback = callback
)
} }
@ReactMethod @ReactMethod
fun callPrivateRPC(payload: String, callback: Callback) { fun callPrivateRPC(payload: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.callPrivateRPC(payload) }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "CallPrivateRPC",
requestBody = payload,
statusgoFunction = { Statusgo.callPrivateRPC(payload) },
callback = callback
)
} }
@ReactMethod @ReactMethod
fun recover(rpcParams: String, callback: Callback) { fun recover(rpcParams: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.recover(rpcParams) }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "Recover",
requestBody = rpcParams,
statusgoFunction = { Statusgo.recover(rpcParams) },
callback
)
} }
@ReactMethod @ReactMethod
@ -77,22 +119,33 @@ class NetworkManager(private val reactContext: ReactApplicationContext) : ReactC
val keyUID = senderConfig.getString("loggedInKeyUid") val keyUID = senderConfig.getString("loggedInKeyUid")
val keyStorePath = utils.getKeyStorePath(keyUID) val keyStorePath = utils.getKeyStorePath(keyUID)
senderConfig.put("keystorePath", keyStorePath) senderConfig.put("keystorePath", keyStorePath)
val jsonString = jsonConfig.toString()
utils.executeRunnableStatusGoMethod( StatusBackendClient.executeStatusGoRequestWithCallback(
{ Statusgo.getConnectionStringForExportingKeypairsKeystores(jsonConfig.toString()) }, endpoint = "GetConnectionStringForExportingKeypairsKeystores",
callback) requestBody = jsonString,
statusgoFunction = { Statusgo.getConnectionStringForExportingKeypairsKeystores(jsonString) },
callback = callback
)
} }
@ReactMethod @ReactMethod
fun inputConnectionStringForImportingKeypairsKeystores(connectionString: String, configJSON: String, callback: Callback) { fun inputConnectionStringForImportingKeypairsKeystores(connectionString: String, configJSON: String, callback: Callback) {
val jsonConfig = JSONObject(configJSON) val keystoreFilesReceiverClientConfig = JSONObject(configJSON)
val receiverConfig = jsonConfig.getJSONObject("receiverConfig") val receiverConfig = keystoreFilesReceiverClientConfig.getJSONObject("receiverConfig")
val keyStorePath = utils.pathCombine(utils.getNoBackupDirectory(), "/keystore") val keyStorePath = utils.pathCombine(utils.getNoBackupDirectory(), "/keystore")
receiverConfig.put("keystorePath", keyStorePath) receiverConfig.put("keystorePath", keyStorePath)
utils.executeRunnableStatusGoMethod( val params = JSONObject().apply {
{ Statusgo.inputConnectionStringForImportingKeypairsKeystores(connectionString, jsonConfig.toString()) }, put("connectionString", connectionString)
callback put("keystoreFilesReceiverClientConfig", keystoreFilesReceiverClientConfig)
}
val jsonString = params.toString()
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "InputConnectionStringForImportingKeypairsKeystoresV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.inputConnectionStringForImportingKeypairsKeystoresV2(jsonString) },
callback = callback
) )
} }
} }

View File

@ -0,0 +1,209 @@
package im.status.ethereum.module
import android.util.Log
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener
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 java.net.SocketException
import java.net.SocketTimeoutException
import java.util.concurrent.TimeUnit
class StatusBackendClient(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
companion object {
private const val TAG = "StatusBackendClient"
private val JSON = "application/json; charset=utf-8".toMediaType()
private const val TIMEOUT_SECONDS = 30L
@Volatile private var instance: StatusBackendClient? = null
private lateinit var utils: Utils
fun getInstance(): StatusBackendClient? = instance
@JvmStatic
fun executeStatusGoRequest(
endpoint: String,
requestBody: String,
statusgoFunction: () -> String
) {
val statusBackendClient = getInstance()
if (statusBackendClient?.serverEnabled == true) {
val result = statusBackendClient.request(endpoint, requestBody)
result.onSuccess { response ->
utils.handleStatusGoResponse(response, endpoint)
}.onFailure { error ->
Log.e(TAG, "request to $endpoint failed", error)
}
} else {
val result = statusgoFunction()
utils.handleStatusGoResponse(result, endpoint)
}
}
@JvmStatic
fun executeStatusGoRequestWithCallback(
endpoint: String,
requestBody: String,
statusgoFunction: () -> String,
callback: Callback?
) {
val statusBackendClient = getInstance()
if (statusBackendClient?.serverEnabled == true) {
val runnable = Runnable {
val result = statusBackendClient.request(endpoint, requestBody)
result.onSuccess { response ->
callback?.invoke(response)
}.onFailure { error ->
Log.e(TAG, "request to $endpoint failed", error)
callback?.invoke(false)
}
}
StatusThreadPoolExecutor.getInstance().execute(runnable)
} else {
utils.executeRunnableStatusGoMethod(statusgoFunction, callback)
}
}
@JvmStatic
fun executeStatusGoRequestWithResult(
endpoint: String,
requestBody: String,
statusgoFunction: () -> String
): String {
val statusBackendClient = getInstance()
return if (statusBackendClient?.serverEnabled == true) {
val result = statusBackendClient.request(endpoint, requestBody)
result.getOrElse { error ->
Log.e(TAG, "request to $endpoint failed", error)
""
}
} else {
statusgoFunction()
}
}
}
init {
instance = this
utils = Utils(reactContext)
}
override fun getName(): String = "StatusBackendClient"
private val httpClient = OkHttpClient.Builder()
.connectTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
.writeTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
.readTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build()
private val wsClient = OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.build()
private var webSocket: WebSocket? = null
@Volatile var serverEnabled = false
@Volatile private var statusGoEndpoint: String? = null
@Volatile private var signalEndpoint: String? = null
@Volatile var rootDataDir: String? = null
@ReactMethod
fun configStatusBackendServer(
serverEnabled: Boolean,
statusGoEndpoint: String,
signalEndpoint: String,
rootDataDir: String
) {
configure(serverEnabled, statusGoEndpoint, signalEndpoint, rootDataDir)
}
private fun configure(
serverEnabled: Boolean,
statusGoEndpoint: String,
signalEndpoint: String,
rootDataDir: String
) {
Log.d(TAG, "configure: serverEnabled=$serverEnabled, statusGoEndpoint=$statusGoEndpoint, " +
"signalEndpoint=$signalEndpoint, rootDataDir=$rootDataDir")
this.serverEnabled = serverEnabled
if (serverEnabled) {
this.statusGoEndpoint = statusGoEndpoint
this.signalEndpoint = signalEndpoint
this.rootDataDir = rootDataDir
connectWebSocket()
} else {
disconnectWebSocket()
this.statusGoEndpoint = null
this.signalEndpoint = null
this.rootDataDir = null
}
}
private fun connectWebSocket() {
if (!serverEnabled || signalEndpoint == null) {
return
}
val request = Request.Builder()
.url("$signalEndpoint")
.build()
webSocket = wsClient.newWebSocket(request, object : WebSocketListener() {
override fun onMessage(webSocket: WebSocket, text: String) {
StatusModule.getInstance()?.handleSignal(text)
}
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
Log.e(TAG, "WebSocket error: ${t.message}")
}
})
}
private fun disconnectWebSocket() {
webSocket?.cancel()
webSocket = null
}
fun request(endpoint: String, body: String): Result<String> {
if (!serverEnabled || statusGoEndpoint == null) {
return Result.failure(IllegalStateException("Status backend server is not enabled"))
}
val fullUrl = "$statusGoEndpoint$endpoint"
return try {
val request = Request.Builder()
.url(fullUrl)
.post(body.toRequestBody(JSON))
.build()
httpClient.newCall(request).execute().use { response ->
val responseBody = response.body?.string() ?: ""
if (response.isSuccessful) {
Log.d(TAG, "Request to $endpoint succeeded: $responseBody")
Result.success(responseBody)
} else {
val errorMsg = "Request failed with code ${response.code}: $responseBody"
Log.e(TAG, "Request to $endpoint failed: $errorMsg")
Result.failure(Exception(errorMsg))
}
}
} catch (e: Exception) {
when (e) {
is SocketTimeoutException -> Log.e(TAG, "Request to $endpoint timed out", e)
is SocketException -> Log.e(TAG, "Socket error for $endpoint", e)
else -> Log.e(TAG, "Request to $endpoint failed with exception", e)
}
Result.failure(e)
}
}
}

View File

@ -9,12 +9,17 @@ import statusgo.SignalHandler
import statusgo.Statusgo import statusgo.Statusgo
import org.json.JSONException import org.json.JSONException
import android.view.WindowManager import android.view.WindowManager
import org.json.JSONObject
class StatusModule(private val reactContext: ReactApplicationContext, private val rootedDevice: Boolean) : ReactContextBaseJavaModule(reactContext), LifecycleEventListener, SignalHandler { class StatusModule(private val reactContext: ReactApplicationContext, private val rootedDevice: Boolean) : ReactContextBaseJavaModule(reactContext), LifecycleEventListener, SignalHandler {
companion object { companion object {
private const val TAG = "StatusModule" private const val TAG = "StatusModule"
private var module: StatusModule? = null private var module: StatusModule? = null
fun getInstance(): StatusModule? {
return module
}
} }
private val utils: Utils = Utils(reactContext) private val utils: Utils = Utils(reactContext)
@ -56,45 +61,97 @@ class StatusModule(private val reactContext: ReactApplicationContext, private va
@ReactMethod @ReactMethod
fun connectionChange(type: String, isExpensive: Boolean) { fun connectionChange(type: String, isExpensive: Boolean) {
Log.d(TAG, "ConnectionChange: $type, is expensive $isExpensive") Log.d(TAG, "ConnectionChange: $type, is expensive $isExpensive")
Statusgo.connectionChange(type, if (isExpensive) 1 else 0) val params = JSONObject().apply {
put("type", type)
put("expensive", isExpensive)
}
val jsonString = params.toString()
StatusBackendClient.executeStatusGoRequest(
endpoint = "ConnectionChangeV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.connectionChangeV2(jsonString) }
)
} }
@ReactMethod @ReactMethod
fun appStateChange(type: String) { fun appStateChange(state: String) {
Log.d(TAG, "AppStateChange: $type") Log.d(TAG, "AppStateChange: $state")
Statusgo.appStateChange(type) val params = JSONObject().apply {
put("state", state)
}
val jsonString = params.toString()
StatusBackendClient.executeStatusGoRequest(
endpoint = "AppStateChangeV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.appStateChangeV2(jsonString) }
)
} }
@ReactMethod @ReactMethod
fun startLocalNotifications() { fun startLocalNotifications() {
Log.d(TAG, "startLocalNotifications") Log.d(TAG, "startLocalNotifications")
Statusgo.startLocalNotifications() StatusBackendClient.executeStatusGoRequest(
endpoint = "StartLocalNotifications",
requestBody = "",
statusgoFunction = { Statusgo.startLocalNotifications() }
)
} }
@ReactMethod @ReactMethod
fun getNodeConfig(callback: Callback) { fun getNodeConfig(callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.getNodeConfig() }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "GetNodeConfig",
requestBody = "",
statusgoFunction = { Statusgo.getNodeConfig() },
callback = callback
)
} }
@ReactMethod @ReactMethod
fun addCentralizedMetric(request: String, callback: Callback) { fun addCentralizedMetric(request: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.addCentralizedMetric(request) }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "AddCentralizedMetric",
requestBody = request,
statusgoFunction = { Statusgo.addCentralizedMetric(request) },
callback
)
} }
@ReactMethod @ReactMethod
fun toggleCentralizedMetrics(request: String, callback: Callback) { fun toggleCentralizedMetrics(request: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.toggleCentralizedMetrics(request) }, callback) StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "ToggleCentralizedMetrics",
requestBody = request,
statusgoFunction = { Statusgo.toggleCentralizedMetrics(request) },
callback
)
} }
@ReactMethod @ReactMethod
fun deleteImportedKey(keyUID: String, address: String, password: String, callback: Callback) { fun deleteImportedKey(keyUID: String, address: String, password: String, callback: Callback) {
val keyStoreDir = utils.getKeyStorePath(keyUID) val keyStoreDir = utils.getKeyStorePath(keyUID)
utils.executeRunnableStatusGoMethod({ Statusgo.deleteImportedKey(address, password, keyStoreDir) }, callback) val params = JSONObject().apply {
put("address", address)
put("password", password)
put("keyStoreDir", keyStoreDir)
}
val jsonString = params.toString()
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "DeleteImportedKeyV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.deleteImportedKeyV2(jsonString) },
callback
)
} }
@ReactMethod(isBlockingSynchronousMethod = true) @ReactMethod(isBlockingSynchronousMethod = true)
fun fleets(): String { fun fleets(): String {
return Statusgo.fleets() return StatusBackendClient.executeStatusGoRequestWithResult(
endpoint = "Fleets",
requestBody = "",
statusgoFunction = { Statusgo.fleets() }
)
} }
override fun getConstants(): Map<String, Any>? { override fun getConstants(): Map<String, Any>? {

View File

@ -9,7 +9,12 @@ import statusgo.Statusgo
class StatusPackage(private val rootedDevice: Boolean) : ReactPackage { class StatusPackage(private val rootedDevice: Boolean) : ReactPackage {
companion object { companion object {
fun getImageTLSCert(): String = Statusgo.imageServerTLSCert() fun getImageTLSCert(): String =
StatusBackendClient.executeStatusGoRequestWithResult(
endpoint = "ImageServerTLSCert",
requestBody = "",
statusgoFunction = { Statusgo.imageServerTLSCert() }
)
} }
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> { override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
@ -26,6 +31,7 @@ class StatusPackage(private val rootedDevice: Boolean) : ReactPackage {
add(NetworkManager(reactContext)) add(NetworkManager(reactContext))
add(MailManager(reactContext)) add(MailManager(reactContext))
add(RNSelectableTextInputModule(reactContext)) add(RNSelectableTextInputModule(reactContext))
add(StatusBackendClient(reactContext))
} }
return modules return modules

View File

@ -25,6 +25,11 @@ class Utils(private val reactContext: ReactApplicationContext) : ReactContextBas
} }
fun getNoBackupDirectory(): String { fun getNoBackupDirectory(): String {
StatusBackendClient.getInstance()?.let { client ->
if (client.serverEnabled && client.rootDataDir != null) {
return client.rootDataDir!!
}
}
return reactContext.noBackupFilesDir.absolutePath return reactContext.noBackupFilesDir.absolutePath
} }
@ -34,6 +39,11 @@ class Utils(private val reactContext: ReactApplicationContext) : ReactContextBas
} }
fun getPublicStorageDirectory(): File? { fun getPublicStorageDirectory(): File? {
StatusBackendClient.getInstance()?.let { client ->
if (client.serverEnabled && client.rootDataDir != null) {
return File(client.rootDataDir!!)
}
}
// Environment.getExternalStoragePublicDirectory doesn't work as expected on Android Q // Environment.getExternalStoragePublicDirectory doesn't work as expected on Android Q
// https://developer.android.com/reference/android/os/Environment#getExternalStoragePublicDirectory(java.lang.String) // https://developer.android.com/reference/android/os/Environment#getExternalStoragePublicDirectory(java.lang.String)
return reactContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) return reactContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
@ -69,8 +79,22 @@ class Utils(private val reactContext: ReactApplicationContext) : ReactContextBas
val keydirFile = File(keydir) val keydirFile = File(keydir)
if (!keydirFile.exists() || keydirFile.list().isEmpty()) { if (!keydirFile.exists() || keydirFile.list().isEmpty()) {
Log.d(TAG, "migrateKeyStoreDir") Log.d(TAG, "migrateKeyStoreDir")
Statusgo.migrateKeyStoreDir(accountData, password, commonKeydir, keydir) val jsonParams = JSONObject()
Statusgo.initKeystore(keydir) jsonParams.put("account", JSONObject(accountData)) // Remove 'new' keyword
jsonParams.put("password", password)
jsonParams.put("oldDir", commonKeydir)
jsonParams.put("newDir", keydir)
StatusBackendClient.executeStatusGoRequest(
endpoint = "MigrateKeyStoreDirV2",
requestBody = jsonParams.toString(),
statusgoFunction = { Statusgo.migrateKeyStoreDirV2(jsonParams.toString()) }
)
StatusBackendClient.executeStatusGoRequest(
endpoint = "InitKeystore",
requestBody = keydir,
statusgoFunction = { Statusgo.initKeystore(keydir) }
)
} }
} catch (e: JSONException) { } catch (e: JSONException) {
Log.e(TAG, "JSON conversion failed: ${e.message}") Log.e(TAG, "JSON conversion failed: ${e.message}")
@ -99,15 +123,15 @@ class Utils(private val reactContext: ReactApplicationContext) : ReactContextBas
return false return false
} }
fun executeRunnableStatusGoMethod(method: Supplier<String>, callback: Callback) { fun executeRunnableStatusGoMethod(method: Supplier<String>, callback: Callback?) {
if (!checkAvailability()) { if (!checkAvailability()) {
callback.invoke(false) callback?.invoke(false)
return return
} }
val runnableTask = Runnable { val runnableTask = Runnable {
val res = method.get() val res = method.get()
callback.invoke(res) callback?.invoke(res)
} }
StatusThreadPoolExecutor.getInstance().execute(runnableTask) StatusThreadPoolExecutor.getInstance().execute(runnableTask)
@ -115,7 +139,15 @@ class Utils(private val reactContext: ReactApplicationContext) : ReactContextBas
@ReactMethod @ReactMethod
fun validateMnemonic(seed: String, callback: Callback) { fun validateMnemonic(seed: String, callback: Callback) {
executeRunnableStatusGoMethod({ Statusgo.validateMnemonic(seed) }, callback) val jsonParams = JSONObject()
jsonParams.put("mnemonic", seed)
val jsonString = jsonParams.toString()
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "ValidateMnemonicV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.validateMnemonicV2(jsonString) },
callback
)
} }
fun is24Hour(): Boolean { fun is24Hour(): Boolean {
@ -124,17 +156,29 @@ class Utils(private val reactContext: ReactApplicationContext) : ReactContextBas
@ReactMethod(isBlockingSynchronousMethod = true) @ReactMethod(isBlockingSynchronousMethod = true)
fun checkAddressChecksum(address: String): String { fun checkAddressChecksum(address: String): String {
return Statusgo.checkAddressChecksum(address) return StatusBackendClient.executeStatusGoRequestWithResult(
endpoint = "CheckAddressChecksum",
requestBody = address,
statusgoFunction = { Statusgo.checkAddressChecksum(address) }
)
} }
@ReactMethod(isBlockingSynchronousMethod = true) @ReactMethod(isBlockingSynchronousMethod = true)
fun isAddress(address: String): String { fun isAddress(address: String): String {
return Statusgo.isAddress(address) return StatusBackendClient.executeStatusGoRequestWithResult(
endpoint = "IsAddress",
requestBody = address,
statusgoFunction = { Statusgo.isAddress(address) }
)
} }
@ReactMethod(isBlockingSynchronousMethod = true) @ReactMethod(isBlockingSynchronousMethod = true)
fun toChecksumAddress(address: String): String { fun toChecksumAddress(address: String): String {
return Statusgo.toChecksumAddress(address) return StatusBackendClient.executeStatusGoRequestWithResult(
endpoint = "ToChecksumAddress",
requestBody = address,
statusgoFunction = { Statusgo.toChecksumAddress(address) }
)
} }
fun readableArrayToStringArray(r: ReadableArray): Array<String> { fun readableArrayToStringArray(r: ReadableArray): Array<String> {
@ -150,6 +194,19 @@ class Utils(private val reactContext: ReactApplicationContext) : ReactContextBas
@ReactMethod(isBlockingSynchronousMethod = true) @ReactMethod(isBlockingSynchronousMethod = true)
fun validateConnectionString(connectionString: String): String { fun validateConnectionString(connectionString: String): String {
return Statusgo.validateConnectionString(connectionString) return StatusBackendClient.executeStatusGoRequestWithResult(
endpoint = "ValidateConnectionString",
requestBody = connectionString,
statusgoFunction = { Statusgo.validateConnectionString(connectionString) }
)
}
fun handleStatusGoResponse(response: String, source: String) {
//TODO(frank) we should remove sensitive data from the response
if (response.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "$source success: $response")
} else {
Log.e(TAG, "$source failed: $response")
}
} }
} }

View File

@ -3,6 +3,7 @@
#import "React/RCTEventDispatcher.h" #import "React/RCTEventDispatcher.h"
#import "Statusgo.h" #import "Statusgo.h"
#import "Utils.h" #import "Utils.h"
#import "StatusBackendClient.h"
@implementation AccountManager @implementation AccountManager
@ -12,23 +13,29 @@ RCT_EXPORT_METHOD(createAccountAndLogin:(NSString *)request) {
#if DEBUG #if DEBUG
NSLog(@"createAccountAndLogin() method called"); NSLog(@"createAccountAndLogin() method called");
#endif #endif
StatusgoCreateAccountAndLogin(request); [StatusBackendClient executeStatusGoRequest:@"CreateAccountAndLogin"
body:request
statusgoFunction:^NSString *{
return StatusgoCreateAccountAndLogin(request);
}];
} }
RCT_EXPORT_METHOD(restoreAccountAndLogin:(NSString *)request) { RCT_EXPORT_METHOD(restoreAccountAndLogin:(NSString *)request) {
#if DEBUG #if DEBUG
NSLog(@"restoreAccountAndLogin() method called"); NSLog(@"restoreAccountAndLogin() method called");
#endif #endif
StatusgoRestoreAccountAndLogin(request); [StatusBackendClient executeStatusGoRequest:@"RestoreAccountAndLogin"
body:request
statusgoFunction:^NSString *{
return StatusgoRestoreAccountAndLogin(request);
}];
} }
-(NSString *) prepareDirAndUpdateConfig:(NSString *)config -(NSString *) prepareDirAndUpdateConfig:(NSString *)config
withKeyUID:(NSString *)keyUID { withKeyUID:(NSString *)keyUID {
NSFileManager *fileManager = [NSFileManager defaultManager]; NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil; NSError *error = nil;
NSURL *rootUrl =[[fileManager NSURL *rootUrl =[Utils getRootUrl];
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *absTestnetFolderName = [rootUrl URLByAppendingPathComponent:@"ethereum/testnet"]; NSURL *absTestnetFolderName = [rootUrl URLByAppendingPathComponent:@"ethereum/testnet"];
if (![fileManager fileExistsAtPath:absTestnetFolderName.path]) if (![fileManager fileExistsAtPath:absTestnetFolderName.path])
@ -102,8 +109,24 @@ RCT_EXPORT_METHOD(deleteMultiaccount:(NSString *)keyUID
NSLog(@"DeleteMultiaccount() method called"); NSLog(@"DeleteMultiaccount() method called");
#endif #endif
NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID]; NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID];
NSString *result = StatusgoDeleteMultiaccount(keyUID, multiaccountKeystoreDir.path); NSDictionary *params = @{
callback(@[result]); @"keyUID": keyUID,
@"keyStoreDir": multiaccountKeystoreDir.path
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"DeleteMultiaccountV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoDeleteMultiaccountV2(jsonString);
}
callback:callback];
} }
RCT_EXPORT_METHOD(prepareDirAndUpdateConfig:(NSString *)keyUID RCT_EXPORT_METHOD(prepareDirAndUpdateConfig:(NSString *)keyUID
@ -163,36 +186,69 @@ RCT_EXPORT_METHOD(loginWithConfig:(NSString *)accountData
RCT_EXPORT_METHOD(loginAccount:(NSString *)request) { RCT_EXPORT_METHOD(loginAccount:(NSString *)request) {
#if DEBUG #if DEBUG
NSLog(@"LoginAccount() method called"); NSLog(@"loginAccount() method called");
#endif #endif
NSString *result = StatusgoLoginAccount(request); [StatusBackendClient executeStatusGoRequest:@"LoginAccount"
NSLog(@"%@", result); body:request
statusgoFunction:^NSString *{
return StatusgoLoginAccount(request);
}];
} }
RCT_EXPORT_METHOD(verify:(NSString *)address RCT_EXPORT_METHOD(verify:(NSString *)address
password:(NSString *)password password:(NSString *)password
callback:(RCTResponseSenderBlock)callback) { callback:(RCTResponseSenderBlock)callback) {
#if DEBUG #if DEBUG
NSLog(@"VerifyAccountPassword() method called"); NSLog(@"VerifyAccountPasswordV2() method called");
#endif #endif
NSFileManager *fileManager = [NSFileManager defaultManager]; NSURL *rootUrl = [Utils getRootUrl];
NSURL *rootUrl =[[fileManager NSString *keystorePath = [rootUrl.path stringByAppendingPathComponent:@"keystore"];
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *absKeystoreUrl = [rootUrl URLByAppendingPathComponent:@"keystore"];
NSString *result = StatusgoVerifyAccountPassword(absKeystoreUrl.path, address, password); NSDictionary *params = @{
callback(@[result]); @"keyStoreDir": keystorePath,
@"address": address,
@"password": password
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"VerifyAccountPasswordV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoVerifyAccountPasswordV2(jsonString);
}
callback:callback];
} }
RCT_EXPORT_METHOD(verifyDatabasePassword:(NSString *)keyUID RCT_EXPORT_METHOD(verifyDatabasePassword:(NSString *)keyUID
password:(NSString *)password password:(NSString *)password
callback:(RCTResponseSenderBlock)callback) { callback:(RCTResponseSenderBlock)callback) {
#if DEBUG #if DEBUG
NSLog(@"VerifyDatabasePassword() method called"); NSLog(@"VerifyDatabasePasswordV2() method called");
#endif #endif
NSString *result = StatusgoVerifyDatabasePassword(keyUID, password); NSDictionary *params = @{
callback(@[result]); @"keyUID": keyUID,
@"password": password
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"VerifyDatabasePasswordV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoVerifyDatabasePasswordV2(jsonString);
}
callback:callback];
} }
RCT_EXPORT_METHOD(initializeApplication:(NSString *)request RCT_EXPORT_METHOD(initializeApplication:(NSString *)request
@ -200,27 +256,31 @@ RCT_EXPORT_METHOD(initializeApplication:(NSString *)request
#if DEBUG #if DEBUG
NSLog(@"initializeApplication() method called"); NSLog(@"initializeApplication() method called");
#endif #endif
NSString *result = StatusgoInitializeApplication(request); [StatusBackendClient executeStatusGoRequestWithCallback:@"InitializeApplication"
callback(@[result]); body:request
statusgoFunction:^NSString *{
return StatusgoInitializeApplication(request);
}
callback:callback];
} }
RCT_EXPORT_METHOD(acceptTerms:(RCTResponseSenderBlock)callback) { RCT_EXPORT_METHOD(acceptTerms:(RCTResponseSenderBlock)callback) {
#if DEBUG #if DEBUG
NSLog(@"acceptTerms() method called"); NSLog(@"acceptTerms() method called");
#endif #endif
NSString *result = StatusgoAcceptTerms(); [StatusBackendClient executeStatusGoRequestWithCallback:@"AcceptTerms"
callback(@[result]); body:@""
statusgoFunction:^NSString *{
return StatusgoAcceptTerms();
}
callback:callback];
} }
RCT_EXPORT_METHOD(openAccounts:(RCTResponseSenderBlock)callback) { RCT_EXPORT_METHOD(openAccounts:(RCTResponseSenderBlock)callback) {
#if DEBUG #if DEBUG
NSLog(@"OpenAccounts() method called"); NSLog(@"OpenAccounts() method called");
#endif #endif
NSFileManager *fileManager = [NSFileManager defaultManager]; NSURL *rootUrl =[Utils getRootUrl];
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSString *result = StatusgoOpenAccounts(rootUrl.path); NSString *result = StatusgoOpenAccounts(rootUrl.path);
callback(@[result]); callback(@[result]);
} }
@ -229,33 +289,140 @@ RCT_EXPORT_METHOD(logout) {
#if DEBUG #if DEBUG
NSLog(@"Logout() method called"); NSLog(@"Logout() method called");
#endif #endif
NSString *result = StatusgoLogout(); [StatusBackendClient executeStatusGoRequest:@"Logout"
body:@""
statusgoFunction:^NSString *{
return StatusgoLogout();
}];
}
NSLog(@"%@", result); RCT_EXPORT_METHOD(multiAccountStoreAccount:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountStoreAccount() method called");
#endif
[StatusBackendClient executeStatusGoRequestWithCallback:@"MultiAccountStoreAccount"
body:json
statusgoFunction:^NSString *{
return StatusgoMultiAccountStoreAccount(json);
}
callback:callback];
}
RCT_EXPORT_METHOD(multiAccountLoadAccount:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountLoadAccount() method called");
#endif
[StatusBackendClient executeStatusGoRequestWithCallback:@"MultiAccountLoadAccount"
body:json
statusgoFunction:^NSString *{
return StatusgoMultiAccountLoadAccount(json);
}
callback:callback];
}
RCT_EXPORT_METHOD(multiAccountDeriveAddresses:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"multiAccountDeriveAddresses() method called");
#endif
[StatusBackendClient executeStatusGoRequestWithCallback:@"MultiAccountDeriveAddresses"
body:json
statusgoFunction:^NSString *{
return StatusgoMultiAccountDeriveAddresses(json);
}
callback:callback];
}
RCT_EXPORT_METHOD(multiAccountGenerateAndDeriveAddresses:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountGenerateAndDeriveAddresses() method called");
#endif
[StatusBackendClient executeStatusGoRequestWithCallback:@"MultiAccountGenerateAndDeriveAddresses"
body:json
statusgoFunction:^NSString *{
return StatusgoMultiAccountGenerateAndDeriveAddresses(json);
}
callback:callback];
}
RCT_EXPORT_METHOD(multiAccountStoreDerived:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountStoreDerived() method called");
#endif
[StatusBackendClient executeStatusGoRequestWithCallback:@"MultiAccountStoreDerivedAccounts"
body:json
statusgoFunction:^NSString *{
return StatusgoMultiAccountStoreDerivedAccounts(json);
}
callback:callback];
}
RCT_EXPORT_METHOD(multiAccountImportMnemonic:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountImportMnemonic() method called");
#endif
[StatusBackendClient executeStatusGoRequestWithCallback:@"MultiAccountImportMnemonic"
body:json
statusgoFunction:^NSString *{
return StatusgoMultiAccountImportMnemonic(json);
}
callback:callback];
}
RCT_EXPORT_METHOD(multiAccountImportPrivateKey:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountImportPrivateKey() method called");
#endif
[StatusBackendClient executeStatusGoRequestWithCallback:@"MultiAccountImportPrivateKey"
body:json
statusgoFunction:^NSString *{
return StatusgoMultiAccountImportPrivateKey(json);
}
callback:callback];
} }
RCT_EXPORT_METHOD(getRandomMnemonic:(RCTResponseSenderBlock)callback) { RCT_EXPORT_METHOD(getRandomMnemonic:(RCTResponseSenderBlock)callback) {
#if DEBUG #if DEBUG
NSLog(@"GetRandomMnemonic() method called"); NSLog(@"GetRandomMnemonic() method called");
#endif #endif
NSString *result = StatusgoGetRandomMnemonic(); [StatusBackendClient executeStatusGoRequestWithCallback:@"GetRandomMnemonic"
callback(@[result]); body:@""
statusgoFunction:^NSString *{
return StatusgoGetRandomMnemonic();
}
callback:callback];
} }
RCT_EXPORT_METHOD(createAccountFromMnemonicAndDeriveAccountsForPaths:(NSString *)mnemonic callback:(RCTResponseSenderBlock)callback) { RCT_EXPORT_METHOD(createAccountFromMnemonicAndDeriveAccountsForPaths:(NSString *)mnemonic
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG #if DEBUG
NSLog(@"createAccountFromMnemonicAndDeriveAccountsForPaths() method called"); NSLog(@"createAccountFromMnemonicAndDeriveAccountsForPaths() method called");
#endif #endif
NSString *result = StatusgoCreateAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic); [StatusBackendClient executeStatusGoRequestWithCallback:@"CreateAccountFromMnemonicAndDeriveAccountsForPaths"
callback(@[result]); body:mnemonic
statusgoFunction:^NSString *{
return StatusgoCreateAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic);
}
callback:callback];
} }
RCT_EXPORT_METHOD(createAccountFromPrivateKey:(NSString *)configJSON callback:(RCTResponseSenderBlock)callback) { RCT_EXPORT_METHOD(createAccountFromPrivateKey:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG #if DEBUG
NSLog(@"createAccountFromPrivateKey() method called"); NSLog(@"createAccountFromPrivateKey() method called");
#endif #endif
NSString *result = StatusgoCreateAccountFromPrivateKey(configJSON); [StatusBackendClient executeStatusGoRequestWithCallback:@"CreateAccountFromPrivateKey"
callback(@[result]); body:json
statusgoFunction:^NSString *{
return StatusgoCreateAccountFromPrivateKey(json);
}
callback:callback];
} }
@end @end

View File

@ -3,7 +3,7 @@
#import "React/RCTEventDispatcher.h" #import "React/RCTEventDispatcher.h"
#import "Statusgo.h" #import "Statusgo.h"
#import "Utils.h" #import "Utils.h"
#import "StatusBackendClient.h"
@implementation DatabaseManager @implementation DatabaseManager
RCT_EXPORT_MODULE(); RCT_EXPORT_MODULE();
@ -16,7 +16,30 @@ RCT_EXPORT_METHOD(exportUnencryptedDatabase:(NSString *)accountData
#endif #endif
NSString *filePath = [Utils getExportDbFilePath]; NSString *filePath = [Utils getExportDbFilePath];
StatusgoExportUnencryptedDatabase(accountData, password, filePath);
NSDictionary *params = @{
@"account": [NSJSONSerialization JSONObjectWithData:[accountData dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil],
@"password": password,
@"databasePath": filePath
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", [error localizedDescription]);
callback(@[filePath]);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"ExportUnencryptedDatabaseV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoExportUnencryptedDatabaseV2(jsonString);
}
callback:nil];
callback(@[filePath]); callback(@[filePath]);
} }
@ -26,7 +49,31 @@ RCT_EXPORT_METHOD(importUnencryptedDatabase:(NSString *)accountData
#if DEBUG #if DEBUG
NSLog(@"importUnencryptedDatabase() method called"); NSLog(@"importUnencryptedDatabase() method called");
#endif #endif
"";
NSString *filePath = [Utils getExportDbFilePath];
[Utils migrateKeystore:accountData password:password];
NSDictionary *params = @{
@"account": [NSJSONSerialization JSONObjectWithData:[accountData dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil],
@"password": password,
@"databasePath": filePath
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", [error localizedDescription]);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequest:@"ImportUnencryptedDatabaseV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoImportUnencryptedDatabaseV2(jsonString);
}];
} }

View File

@ -3,6 +3,7 @@
#import "React/RCTEventDispatcher.h" #import "React/RCTEventDispatcher.h"
#import "Statusgo.h" #import "Statusgo.h"
#import "Utils.h" #import "Utils.h"
#import "StatusBackendClient.h"
@implementation EncryptionUtils @implementation EncryptionUtils
@ -15,21 +16,14 @@ RCT_EXPORT_METHOD(initKeystore:(NSString *)keyUID
#if DEBUG #if DEBUG
NSLog(@"initKeystore() method called"); NSLog(@"initKeystore() method called");
#endif #endif
NSFileManager *fileManager = [NSFileManager defaultManager]; NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID];
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *commonKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"]; [StatusBackendClient executeStatusGoRequestWithCallback:@"InitKeystore"
NSURL *keystoreDir = [commonKeystoreDir URLByAppendingPathComponent:keyUID]; body:multiaccountKeystoreDir.path
statusgoFunction:^NSString *{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), return StatusgoInitKeystore(multiaccountKeystoreDir.path);
^(void) }
{ callback:callback];
NSString *res = StatusgoInitKeystore(keystoreDir.path);
NSLog(@"InitKeyStore result %@", res);
callback(@[]);
});
} }
RCT_EXPORT_METHOD(reEncryptDbAndKeystore:(NSString *)keyUID RCT_EXPORT_METHOD(reEncryptDbAndKeystore:(NSString *)keyUID
@ -39,9 +33,26 @@ RCT_EXPORT_METHOD(reEncryptDbAndKeystore:(NSString *)keyUID
#if DEBUG #if DEBUG
NSLog(@"reEncryptDbAndKeystore() method called"); NSLog(@"reEncryptDbAndKeystore() method called");
#endif #endif
// changes password and re-encrypts keystore // Construct params into JSON string
NSString *result = StatusgoChangeDatabasePassword(keyUID, currentPassword, newPassword); NSDictionary *params = @{
callback(@[result]); @"keyUID": keyUID,
@"oldPassword": currentPassword,
@"newPassword": newPassword
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"ChangeDatabasePasswordV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoChangeDatabasePasswordV2(jsonString);
}
callback:callback];
} }
RCT_EXPORT_METHOD(convertToKeycardAccount:(NSString *)keyUID RCT_EXPORT_METHOD(convertToKeycardAccount:(NSString *)keyUID
@ -55,47 +66,141 @@ RCT_EXPORT_METHOD(convertToKeycardAccount:(NSString *)keyUID
NSLog(@"convertToKeycardAccount() method called"); NSLog(@"convertToKeycardAccount() method called");
#endif #endif
NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID]; NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID];
StatusgoInitKeystore(multiaccountKeystoreDir.path);
NSString *result = StatusgoConvertToKeycardAccount(accountData, settings, keycardUID, currentPassword, newPassword); // First initialize keystore
callback(@[result]); [StatusBackendClient executeStatusGoRequest:@"InitKeystore"
body:multiaccountKeystoreDir.path
statusgoFunction:^NSString *{
return StatusgoInitKeystore(multiaccountKeystoreDir.path);
}];
// Prepare parameters for conversion
NSDictionary *params = @{
@"keyUID": keyUID,
@"account": [NSJSONSerialization JSONObjectWithData:[accountData dataUsingEncoding:NSUTF8StringEncoding]
options:0
error:nil],
@"settings": [NSJSONSerialization JSONObjectWithData:[settings dataUsingEncoding:NSUTF8StringEncoding]
options:0
error:nil],
@"keycardUID": keycardUID,
@"oldPassword": currentPassword,
@"newPassword": newPassword
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", [error localizedDescription]);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"ConvertToKeycardAccountV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoConvertToKeycardAccountV2(jsonString);
}
callback:callback];
} }
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(encodeTransfer:(NSString *)to RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(encodeTransfer:(NSString *)to
value:(NSString *)value) { value:(NSString *)value) {
return StatusgoEncodeTransfer(to,value); NSDictionary *params = @{
@"to": to,
@"value": value
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", [error localizedDescription]);
return nil;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
return [StatusBackendClient executeStatusGoRequestWithResult:@"EncodeTransferV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoEncodeTransferV2(jsonString);
}];
} }
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(encodeFunctionCall:(NSString *)method RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(encodeFunctionCall:(NSString *)method
paramsJSON:(NSString *)paramsJSON) { paramsJSON:(NSString *)paramsJSON) {
return StatusgoEncodeFunctionCall(method,paramsJSON); NSDictionary *params = @{
@"method": method,
@"paramsJSON": paramsJSON
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", [error localizedDescription]);
return nil;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
return [StatusBackendClient executeStatusGoRequestWithResult:@"EncodeFunctionCallV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoEncodeFunctionCallV2(jsonString);
}];
} }
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(decodeParameters:(NSString *)decodeParamJSON) { RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(decodeParameters:(NSString *)decodeParamJSON) {
return [StatusBackendClient executeStatusGoRequestWithResult:@"DecodeParameters"
body:decodeParamJSON
statusgoFunction:^NSString *{
return StatusgoDecodeParameters(decodeParamJSON); return StatusgoDecodeParameters(decodeParamJSON);
}];
} }
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(hexToNumber:(NSString *)hex) { RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(hexToNumber:(NSString *)hex) {
return [StatusBackendClient executeStatusGoRequestWithResult:@"HexToNumber"
body:hex
statusgoFunction:^NSString *{
return StatusgoHexToNumber(hex); return StatusgoHexToNumber(hex);
}];
} }
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(numberToHex:(NSString *)numString) { RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(numberToHex:(NSString *)numString) {
return [StatusBackendClient executeStatusGoRequestWithResult:@"NumberToHex"
body:numString
statusgoFunction:^NSString *{
return StatusgoNumberToHex(numString); return StatusgoNumberToHex(numString);
}];
} }
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(sha3:(NSString *)str) { RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(sha3:(NSString *)str) {
return [StatusBackendClient executeStatusGoRequestWithResult:@"Sha3"
body:str
statusgoFunction:^NSString *{
return StatusgoSha3(str); return StatusgoSha3(str);
}];
} }
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(utf8ToHex:(NSString *)str) { RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(utf8ToHex:(NSString *)str) {
return [StatusBackendClient executeStatusGoRequestWithResult:@"Utf8ToHex"
body:str
statusgoFunction:^NSString *{
return StatusgoUtf8ToHex(str); return StatusgoUtf8ToHex(str);
}];
} }
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(hexToUtf8:(NSString *)str) { RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(hexToUtf8:(NSString *)str) {
return [StatusBackendClient executeStatusGoRequestWithResult:@"HexToUtf8"
body:str
statusgoFunction:^NSString *{
return StatusgoHexToUtf8(str); return StatusgoHexToUtf8(str);
}];
} }
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(serializeLegacyKey:(NSString *)str) { RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(serializeLegacyKey:(NSString *)str) {
return [StatusBackendClient executeStatusGoRequestWithResult:@"SerializeLegacyKey"
body:str
statusgoFunction:^NSString *{
return StatusgoSerializeLegacyKey(str); return StatusgoSerializeLegacyKey(str);
}];
} }
RCT_EXPORT_METHOD(setBlankPreviewFlag:(BOOL *)newValue) RCT_EXPORT_METHOD(setBlankPreviewFlag:(BOOL *)newValue)
@ -110,10 +215,14 @@ RCT_EXPORT_METHOD(setBlankPreviewFlag:(BOOL *)newValue)
RCT_EXPORT_METHOD(hashTransaction:(NSString *)txArgsJSON RCT_EXPORT_METHOD(hashTransaction:(NSString *)txArgsJSON
callback:(RCTResponseSenderBlock)callback) { callback:(RCTResponseSenderBlock)callback) {
#if DEBUG #if DEBUG
NSLog(@"HashTransaction() method called"); NSLog(@"hashTransaction() method called");
#endif #endif
NSString *result = StatusgoHashTransaction(txArgsJSON); [StatusBackendClient executeStatusGoRequestWithCallback:@"HashTransaction"
callback(@[result]); body:txArgsJSON
statusgoFunction:^NSString *{
return StatusgoHashTransaction(txArgsJSON);
}
callback:callback];
} }
RCT_EXPORT_METHOD(hashMessage:(NSString *)message RCT_EXPORT_METHOD(hashMessage:(NSString *)message
@ -121,8 +230,12 @@ RCT_EXPORT_METHOD(hashMessage:(NSString *)message
#if DEBUG #if DEBUG
NSLog(@"hashMessage() method called"); NSLog(@"hashMessage() method called");
#endif #endif
NSString *result = StatusgoHashMessage(message); [StatusBackendClient executeStatusGoRequestWithCallback:@"HashMessage"
callback(@[result]); body:message
statusgoFunction:^NSString *{
return StatusgoHashMessage(message);
}
callback:callback];
} }
RCT_EXPORT_METHOD(localPairingPreflightOutboundCheck:(RCTResponseSenderBlock)callback) { RCT_EXPORT_METHOD(localPairingPreflightOutboundCheck:(RCTResponseSenderBlock)callback) {
@ -136,14 +249,34 @@ RCT_EXPORT_METHOD(localPairingPreflightOutboundCheck:(RCTResponseSenderBlock)cal
RCT_EXPORT_METHOD(multiformatDeserializePublicKey:(NSString *)multiCodecKey RCT_EXPORT_METHOD(multiformatDeserializePublicKey:(NSString *)multiCodecKey
base58btc:(NSString *)base58btc base58btc:(NSString *)base58btc
callback:(RCTResponseSenderBlock)callback) { callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoMultiformatDeserializePublicKey(multiCodecKey,base58btc); NSDictionary *params = @{
callback(@[result]); @"key": multiCodecKey,
@"outBase": base58btc
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"MultiformatDeserializePublicKeyV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoMultiformatDeserializePublicKeyV2(jsonString);
}
callback:callback];
} }
RCT_EXPORT_METHOD(deserializeAndCompressKey:(NSString *)desktopKey RCT_EXPORT_METHOD(deserializeAndCompressKey:(NSString *)desktopKey
callback:(RCTResponseSenderBlock)callback) { callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoDeserializeAndCompressKey(desktopKey); [StatusBackendClient executeStatusGoRequestWithCallback:@"DeserializeAndCompressKey"
callback(@[result]); body:desktopKey
statusgoFunction:^NSString *{
return StatusgoDeserializeAndCompressKey(desktopKey);
}
callback:callback];
} }
RCT_EXPORT_METHOD(hashTypedData:(NSString *)data RCT_EXPORT_METHOD(hashTypedData:(NSString *)data
@ -166,13 +299,14 @@ RCT_EXPORT_METHOD(hashTypedDataV4:(NSString *)data
#pragma mark - SignMessage #pragma mark - SignMessage
RCT_EXPORT_METHOD(signMessage:(NSString *)message RCT_EXPORT_METHOD(signMessage:(NSString *)rpcParams
callback:(RCTResponseSenderBlock)callback) { callback:(RCTResponseSenderBlock)callback) {
#if DEBUG [StatusBackendClient executeStatusGoRequestWithCallback:@"SignMessage"
NSLog(@"SignMessage() method called"); body:rpcParams
#endif statusgoFunction:^NSString *{
NSString *result = StatusgoSignMessage(message); return StatusgoSignMessage(rpcParams);
callback(@[result]); }
callback:callback];
} }
#pragma mark - SignTypedData #pragma mark - SignTypedData

View File

@ -4,6 +4,7 @@
#import "Statusgo.h" #import "Statusgo.h"
#import "Utils.h" #import "Utils.h"
#import "SSZipArchive.h" #import "SSZipArchive.h"
#import "StatusBackendClient.h"
@implementation LogManager @implementation LogManager
@ -19,9 +20,7 @@ RCT_EXPORT_METHOD(sendLogs:(NSString *)dbJson
#endif #endif
NSFileManager *fileManager = [NSFileManager defaultManager]; NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil; NSError *error = nil;
NSURL *rootUrl =[[fileManager NSURL *rootUrl =[Utils getRootUrl];
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *zipFile = [rootUrl URLByAppendingPathComponent:@"logs.zip"]; NSURL *zipFile = [rootUrl URLByAppendingPathComponent:@"logs.zip"];
[fileManager removeItemAtPath:zipFile.path error:nil]; [fileManager removeItemAtPath:zipFile.path error:nil];
@ -64,37 +63,36 @@ RCT_EXPORT_METHOD(initLogging:(BOOL)enabled
NSString *logFilePath = [logDirectory stringByAppendingPathComponent:@"geth.log"]; NSString *logFilePath = [logDirectory stringByAppendingPathComponent:@"geth.log"];
NSString *logRequestFilePath = [logDirectory stringByAppendingPathComponent:@"requests.log"]; NSString *logRequestFilePath = [logDirectory stringByAppendingPathComponent:@"requests.log"];
NSMutableDictionary *jsonConfig = [NSMutableDictionary dictionary]; NSDictionary *config = @{
jsonConfig[@"Enabled"] = @(enabled); @"Enabled": @(enabled),
jsonConfig[@"MobileSystem"] = @(mobileSystem); @"MobileSystem": @(mobileSystem),
jsonConfig[@"Level"] = logLevel; @"Level": logLevel,
jsonConfig[@"File"] = logFilePath; @"File": logFilePath,
jsonConfig[@"LogRequestGo"] = @(logRequestGo); @"LogRequestGo": @(logRequestGo),
jsonConfig[@"LogRequestFile"] = logRequestFilePath; @"LogRequestFile": logRequestFilePath
NSError *error = nil; };
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonConfig options:0 error:&error];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:config options:0 error:&error];
if (error) { if (error) {
// Handle JSON serialization error NSLog(@"Error creating JSON: %@", [error localizedDescription]);
callback(@[error.localizedDescription]);
return; return;
} }
NSString *config = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSString *configJson = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
// Call your native logging initialization method here [StatusBackendClient executeStatusGoRequestWithCallback:@"InitLogging"
NSString *initResult = StatusgoInitLogging(config); body:configJson
statusgoFunction:^NSString *{
callback(@[initResult]); return StatusgoInitLogging(configJson);
}
callback:callback];
} }
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(logFileDirectory) { RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(logFileDirectory) {
NSFileManager *fileManager = [NSFileManager defaultManager]; NSURL *rootUrl = [Utils getRootUrl];
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
return rootUrl.path; return rootUrl.path;
} }
@end @end

View File

@ -3,14 +3,18 @@
#import "React/RCTEventDispatcher.h" #import "React/RCTEventDispatcher.h"
#import "Statusgo.h" #import "Statusgo.h"
#import "Utils.h" #import "Utils.h"
#import "StatusBackendClient.h"
@implementation NetworkManager @implementation NetworkManager
RCT_EXPORT_MODULE(); RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(startSearchForLocalPairingPeers:(RCTResponseSenderBlock)callback) { RCT_EXPORT_METHOD(startSearchForLocalPairingPeers:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoStartSearchForLocalPairingPeers(); [StatusBackendClient executeStatusGoRequestWithCallback:@"StartSearchForLocalPairingPeers"
callback(@[result]); body:@""
statusgoFunction:^NSString *{
return StatusgoStartSearchForLocalPairingPeers();
}
callback:callback];
} }
RCT_EXPORT_METHOD(getConnectionStringForBootstrappingAnotherDevice:(NSString *)configJSON RCT_EXPORT_METHOD(getConnectionStringForBootstrappingAnotherDevice:(NSString *)configJSON
@ -19,6 +23,11 @@ RCT_EXPORT_METHOD(getConnectionStringForBootstrappingAnotherDevice:(NSString *)c
NSData *configData = [configJSON dataUsingEncoding:NSUTF8StringEncoding]; NSData *configData = [configJSON dataUsingEncoding:NSUTF8StringEncoding];
NSError *error; NSError *error;
NSMutableDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:&error]; NSMutableDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:&error];
if (error) {
NSLog(@"Error parsing JSON: %@", error);
return;
}
NSMutableDictionary *senderConfig = configDict[@"senderConfig"]; NSMutableDictionary *senderConfig = configDict[@"senderConfig"];
NSString *keyUID = senderConfig[@"keyUID"]; NSString *keyUID = senderConfig[@"keyUID"];
NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID]; NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID];
@ -27,16 +36,43 @@ RCT_EXPORT_METHOD(getConnectionStringForBootstrappingAnotherDevice:(NSString *)c
[senderConfig setValue:keystoreDir forKey:@"keystorePath"]; [senderConfig setValue:keystoreDir forKey:@"keystorePath"];
NSString *modifiedConfigJSON = [Utils jsonStringWithPrettyPrint:NO fromDictionary:configDict]; NSString *modifiedConfigJSON = [Utils jsonStringWithPrettyPrint:NO fromDictionary:configDict];
NSString *result = StatusgoGetConnectionStringForBootstrappingAnotherDevice(modifiedConfigJSON); [StatusBackendClient executeStatusGoRequestWithCallback:@"GetConnectionStringForBootstrappingAnotherDevice"
callback(@[result]); body:modifiedConfigJSON
statusgoFunction:^NSString *{
return StatusgoGetConnectionStringForBootstrappingAnotherDevice(modifiedConfigJSON);
}
callback:callback];
} }
RCT_EXPORT_METHOD(inputConnectionStringForBootstrapping:(NSString *)cs RCT_EXPORT_METHOD(inputConnectionStringForBootstrapping:(NSString *)cs
configJSON:(NSString *)configJSON configJSON:(NSString *)configJSON
callback:(RCTResponseSenderBlock)callback) { callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoInputConnectionStringForBootstrapping(cs, configJSON); NSData *configData = [configJSON dataUsingEncoding:NSUTF8StringEncoding];
callback(@[result]); NSError *jsonError;
NSDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:0 error:&jsonError];
if (jsonError) {
NSLog(@"Error parsing JSON: %@", jsonError);
return;
}
NSDictionary *params = @{
@"connectionString": cs,
@"receiverClientConfig": configDict
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"InputConnectionStringForBootstrappingV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoInputConnectionStringForBootstrappingV2(jsonString);
}
callback:callback];
} }
RCT_EXPORT_METHOD(sendTransactionWithSignature:(NSString *)txArgsJSON RCT_EXPORT_METHOD(sendTransactionWithSignature:(NSString *)txArgsJSON
@ -45,8 +81,12 @@ RCT_EXPORT_METHOD(sendTransactionWithSignature:(NSString *)txArgsJSON
#if DEBUG #if DEBUG
NSLog(@"sendTransactionWithSignature() method called"); NSLog(@"sendTransactionWithSignature() method called");
#endif #endif
NSString *result = StatusgoSendTransactionWithSignature(txArgsJSON, signature); [StatusBackendClient executeStatusGoRequestWithCallback:@"SendTransactionWithSignature"
callback(@[result]); body:txArgsJSON
statusgoFunction:^NSString *{
return StatusgoSendTransactionWithSignature(txArgsJSON, signature);
}
callback:callback];
} }
#pragma mark - SendTransaction #pragma mark - SendTransaction
@ -55,30 +95,53 @@ RCT_EXPORT_METHOD(sendTransaction:(NSString *)txArgsJSON
password:(NSString *)password password:(NSString *)password
callback:(RCTResponseSenderBlock)callback) { callback:(RCTResponseSenderBlock)callback) {
#if DEBUG #if DEBUG
NSLog(@"SendTransaction() method called"); NSLog(@"SendTransactionV2() method called");
#endif #endif
NSString *result = StatusgoSendTransaction(txArgsJSON, password); NSData *txArgsData = [txArgsJSON dataUsingEncoding:NSUTF8StringEncoding];
callback(@[result]); NSError *jsonError;
NSDictionary *txArgsDict = [NSJSONSerialization JSONObjectWithData:txArgsData options:0 error:&jsonError];
if (jsonError) {
NSLog(@"Error parsing JSON: %@", jsonError);
return;
}
NSDictionary *params = @{
@"txArgs": txArgsDict,
@"password": password
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"SendTransactionV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoSendTransactionV2(jsonString);
}
callback:callback];
} }
RCT_EXPORT_METHOD(callRPC:(NSString *)payload RCT_EXPORT_METHOD(callRPC:(NSString *)payload
callback:(RCTResponseSenderBlock)callback) { callback:(RCTResponseSenderBlock)callback) {
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [StatusBackendClient executeStatusGoRequestWithCallback:@"CallRPC"
NSString *result = StatusgoCallRPC(payload); body:payload
dispatch_async(dispatch_get_main_queue(), ^{ statusgoFunction:^NSString *{
callback(@[result]); return StatusgoCallRPC(payload);
}); }
}); callback:callback];
} }
RCT_EXPORT_METHOD(callPrivateRPC:(NSString *)payload RCT_EXPORT_METHOD(callPrivateRPC:(NSString *)payload
callback:(RCTResponseSenderBlock)callback) { callback:(RCTResponseSenderBlock)callback) {
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [StatusBackendClient executeStatusGoRequestWithCallback:@"CallPrivateRPC"
NSString *result = StatusgoCallPrivateRPC(payload); body:payload
dispatch_async(dispatch_get_main_queue(), ^{ statusgoFunction:^NSString *{
callback(@[result]); return StatusgoCallPrivateRPC(payload);
}); }
}); callback:callback];
} }
#pragma mark - Recover #pragma mark - Recover
@ -88,8 +151,12 @@ RCT_EXPORT_METHOD(recover:(NSString *)message
#if DEBUG #if DEBUG
NSLog(@"Recover() method called"); NSLog(@"Recover() method called");
#endif #endif
NSString *result = StatusgoRecover(message); [StatusBackendClient executeStatusGoRequestWithCallback:@"Recover"
callback(@[result]); body:message
statusgoFunction:^NSString *{
return StatusgoRecover(message);
}
callback:callback];
} }
RCT_EXPORT_METHOD(getConnectionStringForExportingKeypairsKeystores:(NSString *)configJSON RCT_EXPORT_METHOD(getConnectionStringForExportingKeypairsKeystores:(NSString *)configJSON
@ -106,8 +173,12 @@ RCT_EXPORT_METHOD(getConnectionStringForExportingKeypairsKeystores:(NSString *)c
[senderConfig setValue:keystoreDir forKey:@"keystorePath"]; [senderConfig setValue:keystoreDir forKey:@"keystorePath"];
NSString *modifiedConfigJSON = [Utils jsonStringWithPrettyPrint:NO fromDictionary:configDict]; NSString *modifiedConfigJSON = [Utils jsonStringWithPrettyPrint:NO fromDictionary:configDict];
NSString *result = StatusgoGetConnectionStringForExportingKeypairsKeystores(modifiedConfigJSON); [StatusBackendClient executeStatusGoRequestWithCallback:@"GetConnectionStringForExportingKeypairsKeystores"
callback(@[result]); body:modifiedConfigJSON
statusgoFunction:^NSString *{
return StatusgoGetConnectionStringForExportingKeypairsKeystores(modifiedConfigJSON);
}
callback:callback];
} }
RCT_EXPORT_METHOD(inputConnectionStringForImportingKeypairsKeystores:(NSString *)cs RCT_EXPORT_METHOD(inputConnectionStringForImportingKeypairsKeystores:(NSString *)cs
@ -119,14 +190,25 @@ RCT_EXPORT_METHOD(inputConnectionStringForImportingKeypairsKeystores:(NSString *
NSMutableDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:&error]; NSMutableDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:&error];
NSMutableDictionary *receiverConfig = configDict[@"receiverConfig"]; NSMutableDictionary *receiverConfig = configDict[@"receiverConfig"];
NSFileManager *fileManager = [NSFileManager defaultManager]; NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject]; NSURL *rootUrl =[Utils getRootUrl];
NSURL *multiaccountKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"]; NSURL *multiaccountKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
NSString *keystoreDir = multiaccountKeystoreDir.path; NSString *keystoreDir = multiaccountKeystoreDir.path;
[receiverConfig setValue:keystoreDir forKey:@"keystorePath"]; [receiverConfig setValue:keystoreDir forKey:@"keystorePath"];
NSString *modifiedConfigJSON = [Utils jsonStringWithPrettyPrint:NO fromDictionary:configDict]; NSString *modifiedConfigJSON = [Utils jsonStringWithPrettyPrint:NO fromDictionary:configDict];
NSString *result = StatusgoInputConnectionStringForImportingKeypairsKeystores(cs, modifiedConfigJSON);
callback(@[result]); NSDictionary *params = @{
@"connectionString": cs,
@"keystoreFilesReceiverClientConfig": modifiedConfigJSON
};
NSString *paramsJSON = [Utils jsonStringWithPrettyPrint:NO fromDictionary:params];
[StatusBackendClient executeStatusGoRequestWithCallback:@"InputConnectionStringForImportingKeypairsKeystoresV2"
body:paramsJSON
statusgoFunction:^NSString *{
return StatusgoInputConnectionStringForImportingKeypairsKeystoresV2(paramsJSON);
}
callback:callback];
} }
@end @end

View File

@ -5,5 +5,6 @@
#import "RCTLog.h" #import "RCTLog.h"
@interface Status : NSObject <RCTBridgeModule, StatusgoSignalHandler> @interface Status : NSObject <RCTBridgeModule, StatusgoSignalHandler>
+ (Status *)sharedInstance;
- (void)handleSignal:(NSString *)signal; - (void)handleSignal:(NSString *)signal;
@end @end

View File

@ -2,13 +2,22 @@
#import "React/RCTBridge.h" #import "React/RCTBridge.h"
#import "React/RCTEventDispatcher.h" #import "React/RCTEventDispatcher.h"
#import "Statusgo.h" #import "Statusgo.h"
#import "StatusBackendClient.h"
#import "Utils.h" #import "Utils.h"
static RCTBridge *bridge; static RCTBridge *bridge;
@implementation Status @implementation Status
+ (Status *)sharedInstance {
static Status *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype)init { - (instancetype)init {
self = [super init]; self = [super init];
if (!self) { if (!self) {
@ -73,74 +82,17 @@ RCT_EXPORT_METHOD(deleteImportedKey:(NSString *)keyUID
password:(NSString *)password password:(NSString *)password
callback:(RCTResponseSenderBlock)callback) { callback:(RCTResponseSenderBlock)callback) {
#if DEBUG #if DEBUG
NSLog(@"DeleteImportedKey() method called"); NSLog(@"DeleteImportedKeyV2() method called");
#endif #endif
NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID]; NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID];
NSString *result = StatusgoDeleteImportedKey(address, password, multiaccountKeystoreDir.path); NSString *jsonParams = [NSString stringWithFormat:@"{\"address\":\"%@\",\"password\":\"%@\",\"keyStoreDir\":\"%@\"}",
callback(@[result]); address, password, multiaccountKeystoreDir.path];
} [StatusBackendClient executeStatusGoRequestWithCallback:@"DeleteImportedKeyV2"
body:jsonParams
RCT_EXPORT_METHOD(multiAccountGenerateAndDeriveAddresses:(NSString *)json statusgoFunction:^NSString *{
callback:(RCTResponseSenderBlock)callback) { return StatusgoDeleteImportedKeyV2(jsonParams);
#if DEBUG }
NSLog(@"MultiAccountGenerateAndDeriveAddresses() method called"); callback:callback];
#endif
NSString *result = StatusgoMultiAccountGenerateAndDeriveAddresses(json);
callback(@[result]);
}
RCT_EXPORT_METHOD(multiAccountStoreAccount:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountStoreAccount() method called");
#endif
NSString *result = StatusgoMultiAccountStoreAccount(json);
callback(@[result]);
}
RCT_EXPORT_METHOD(multiAccountLoadAccount:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountLoadAccount() method called");
#endif
NSString *result = StatusgoMultiAccountLoadAccount(json);
callback(@[result]);
}
RCT_EXPORT_METHOD(multiAccountStoreDerived:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountStoreDerived() method called");
#endif
NSString *result = StatusgoMultiAccountStoreDerivedAccounts(json);
callback(@[result]);
}
RCT_EXPORT_METHOD(multiAccountImportPrivateKey:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountImportPrivateKey() method called");
#endif
NSString *result = StatusgoMultiAccountImportPrivateKey(json);
callback(@[result]);
}
RCT_EXPORT_METHOD(multiAccountImportMnemonic:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountImportMnemonic() method called");
#endif
NSString *result = StatusgoMultiAccountImportMnemonic(json);
callback(@[result]);
}
RCT_EXPORT_METHOD(multiAccountDeriveAddresses:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountDeriveAddresses() method called");
#endif
NSString *result = StatusgoMultiAccountDeriveAddresses(json);
callback(@[result]);
} }
#pragma mark - GetNodeConfig #pragma mark - GetNodeConfig
@ -149,12 +101,20 @@ RCT_EXPORT_METHOD(getNodeConfig:(RCTResponseSenderBlock)callback) {
#if DEBUG #if DEBUG
NSLog(@"GetNodeConfig() method called"); NSLog(@"GetNodeConfig() method called");
#endif #endif
NSString *result = StatusgoGetNodeConfig(); [StatusBackendClient executeStatusGoRequestWithCallback:@"GetNodeConfig"
callback(@[result]); body:@""
statusgoFunction:^NSString *{
return StatusgoGetNodeConfig();
}
callback:callback];
} }
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(fleets) { RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(fleets) {
return [StatusBackendClient executeStatusGoRequestWithResult:@"Fleets"
body:@""
statusgoFunction:^NSString *{
return StatusgoFleets(); return StatusgoFleets();
}];
} }
RCT_EXPORT_METHOD(closeApplication) { RCT_EXPORT_METHOD(closeApplication) {
@ -166,14 +126,55 @@ RCT_EXPORT_METHOD(connectionChange:(NSString *)type
#if DEBUG #if DEBUG
NSLog(@"ConnectionChange() method called"); NSLog(@"ConnectionChange() method called");
#endif #endif
StatusgoConnectionChange(type, isExpensive ? 1 : 0); NSDictionary *params = @{
@"type": type,
@"expensive": @(isExpensive)
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params
options:0
error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
if (jsonData) {
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequest:@"ConnectionChangeV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoConnectionChangeV2(jsonString);
}];
} else {
NSLog(@"Failed to create JSON data");
}
} }
RCT_EXPORT_METHOD(appStateChange:(NSString *)type) { RCT_EXPORT_METHOD(appStateChange:(NSString *)state) {
#if DEBUG #if DEBUG
NSLog(@"AppStateChange() method called"); NSLog(@"AppStateChange() method called");
#endif #endif
StatusgoAppStateChange(type); NSDictionary *params = @{@"state": state};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params
options:0
error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
if (jsonData) {
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequest:@"AppStateChangeV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoAppStateChangeV2(jsonString);
}];
} else {
NSLog(@"Failed to create JSON data");
}
} }
RCT_EXPORT_METHOD(addCentralizedMetric:(NSString *)request RCT_EXPORT_METHOD(addCentralizedMetric:(NSString *)request
@ -181,8 +182,12 @@ RCT_EXPORT_METHOD(addCentralizedMetric:(NSString *)request
#if DEBUG #if DEBUG
NSLog(@"addCentralizedMetric() method called"); NSLog(@"addCentralizedMetric() method called");
#endif #endif
NSString *result = StatusgoAddCentralizedMetric(request); [StatusBackendClient executeStatusGoRequestWithCallback:@"AddCentralizedMetric"
callback(@[result]); body:request
statusgoFunction:^NSString *{
return StatusgoAddCentralizedMetric(request);
}
callback:callback];
} }
RCT_EXPORT_METHOD(toggleCentralizedMetrics:(NSString *)request RCT_EXPORT_METHOD(toggleCentralizedMetrics:(NSString *)request
@ -190,15 +195,23 @@ RCT_EXPORT_METHOD(toggleCentralizedMetrics:(NSString *)request
#if DEBUG #if DEBUG
NSLog(@"toggleCentralizedMetrics() method called"); NSLog(@"toggleCentralizedMetrics() method called");
#endif #endif
NSString *result = StatusgoToggleCentralizedMetrics(request); [StatusBackendClient executeStatusGoRequestWithCallback:@"ToggleCentralizedMetrics"
callback(@[result]); body:request
statusgoFunction:^NSString *{
return StatusgoToggleCentralizedMetrics(request);
}
callback:callback];
} }
RCT_EXPORT_METHOD(startLocalNotifications) { RCT_EXPORT_METHOD(startLocalNotifications) {
#if DEBUG #if DEBUG
NSLog(@"StartLocalNotifications() method called"); NSLog(@"StartLocalNotifications() method called");
#endif #endif
StatusgoStartLocalNotifications(); [StatusBackendClient executeStatusGoRequest:@"StartLocalNotifications"
body:@""
statusgoFunction:^NSString *{
return StatusgoStartLocalNotifications();
}];
} }
#pragma mark - deviceinfo #pragma mark - deviceinfo

View File

@ -0,0 +1,31 @@
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
@interface StatusBackendClient : NSObject <RCTBridgeModule>
@property (nonatomic) BOOL serverEnabled;
@property (nonatomic, strong) NSString *statusGoEndpoint;
@property (nonatomic, strong) NSString *signalEndpoint;
@property (nonatomic, strong) NSString *rootDataDir;
@property (nonatomic, strong) NSURLSessionWebSocketTask *webSocket;
// Add sharedInstance class method declaration
+ (instancetype)sharedInstance;
- (void)request:(NSString *)endpoint
body:(NSString *)body
callback:(void (^)(NSString *response, NSError *error))callback;
+ (void)executeStatusGoRequest:(NSString *)endpoint
body:(NSString *)body
statusgoFunction:(NSString * (^)(void))statusgoFunction;
+ (void)executeStatusGoRequestWithCallback:(NSString *)endpoint
body:(NSString *)body
statusgoFunction:(NSString * (^)(void))statusgoFunction
callback:(RCTResponseSenderBlock)callback;
+ (NSString *)executeStatusGoRequestWithResult:(NSString *)endpoint
body:(NSString *)body
statusgoFunction:(NSString * (^)(void))statusgoFunction;
@end

View File

@ -0,0 +1,246 @@
#import "StatusBackendClient.h"
#import "RCTStatus.h"
#import "Utils.h"
@implementation StatusBackendClient {
NSURLSessionWebSocketTask *_webSocket;
BOOL _serverEnabled;
NSString *_statusGoEndpoint;
NSString *_signalEndpoint;
NSString *_rootDataDir;
}
RCT_EXPORT_MODULE();
+ (BOOL)requiresMainQueueSetup {
return YES;
}
+ (instancetype)allocWithZone:(NSZone *)zone {
static StatusBackendClient *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [super allocWithZone:zone];
});
return sharedInstance;
}
+ (instancetype)sharedInstance {
return [[self alloc] init];
}
- (instancetype)init {
static StatusBackendClient *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [super init];
if (sharedInstance) {
sharedInstance->_serverEnabled = NO;
sharedInstance->_statusGoEndpoint = nil;
sharedInstance->_signalEndpoint = nil;
sharedInstance->_rootDataDir = nil;
sharedInstance->_webSocket = nil;
}
});
return sharedInstance;
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (BOOL)serverEnabled {
return _serverEnabled;
}
- (NSString *)statusGoEndpoint {
return _statusGoEndpoint;
}
- (NSString *)signalEndpoint {
return _signalEndpoint;
}
- (NSString *)rootDataDir {
return _rootDataDir;
}
- (void)connectWebSocket {
if (!self.serverEnabled || !self.signalEndpoint) {
return;
}
NSString *fullUrl = [NSString stringWithFormat:@"%@", self.signalEndpoint];
NSURL *url = [NSURL URLWithString:fullUrl];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
self.webSocket = [session webSocketTaskWithURL:url];
[self.webSocket resume];
[self receiveMessage];
}
- (void)receiveMessage {
__weak typeof(self) weakSelf = self;
[self.webSocket receiveMessageWithCompletionHandler:^(NSURLSessionWebSocketMessage *message, NSError *error) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf || !strongSelf.webSocket) {
return;
}
if (error) {
NSLog(@"WebSocket error: %@", error);
// Attempt to reconnect after error
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[strongSelf connectWebSocket];
});
return;
}
if (message) {
if (message.type == NSURLSessionWebSocketMessageTypeString && message.string) {
[[Status sharedInstance] handleSignal:message.string];
}
// Continue receiving messages only if the connection is still active
if (strongSelf.webSocket) {
[strongSelf receiveMessage];
}
}
}];
}
- (void)disconnectWebSocket {
if (self.webSocket) {
[self.webSocket cancel];
self.webSocket = nil;
}
}
- (void)request:(NSString *)endpoint
body:(NSString *)body
callback:(void (^)(NSString *response, NSError *error))callback {
NSString *fullUrlString = [NSString stringWithFormat:@"%@%@", self.statusGoEndpoint, endpoint];
NSURL *url = [NSURL URLWithString:fullUrlString];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
NSData *bodyData = [body dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPBody = bodyData;
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"request error: %@", error);
callback(nil, error);
return;
}
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
callback(responseString, nil);
}];
[task resume];
}
RCT_EXPORT_METHOD(configStatusBackendServer:(BOOL)serverEnabled
statusGoEndpoint:(NSString *)statusGoEndpoint
signalEndpoint:(NSString *)signalEndpoint
rootDataDir:(NSString *)rootDataDir) {
[self configureWithEnabled:serverEnabled
statusGoEndpoint:statusGoEndpoint
signalEndpoint:signalEndpoint
rootDataDir:rootDataDir];
}
- (void)configureWithEnabled:(BOOL)serverEnabled
statusGoEndpoint:(NSString *)statusGoEndpoint
signalEndpoint:(NSString *)signalEndpoint
rootDataDir:(NSString *)rootDataDir {
_serverEnabled = serverEnabled;
if (serverEnabled) {
_statusGoEndpoint = statusGoEndpoint;
_signalEndpoint = signalEndpoint;
_rootDataDir = rootDataDir;
[self connectWebSocket];
} else {
[self disconnectWebSocket];
_statusGoEndpoint = nil;
_signalEndpoint = nil;
_rootDataDir = nil;
}
}
+ (void)executeStatusGoRequest:(NSString *)endpoint
body:(NSString *)body
statusgoFunction:(NSString * (^)(void))statusgoFunction {
StatusBackendClient *client = [StatusBackendClient sharedInstance];
if (client.serverEnabled) {
[client request:endpoint body:body callback:^(NSString *response, NSError *error) {
[Utils handleStatusGoResponse:response source:endpoint error:error];
}];
} else {
NSString *result = statusgoFunction();
[Utils handleStatusGoResponse:result source:endpoint error:nil];
}
}
+ (void)executeStatusGoRequestWithCallback:(NSString *)endpoint
body:(NSString *)body
statusgoFunction:(NSString * (^)(void))statusgoFunction
callback:(RCTResponseSenderBlock)callback {
StatusBackendClient *client = [StatusBackendClient sharedInstance];
if (client.serverEnabled) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[client request:endpoint body:body callback:^(NSString *response, NSError *error) {
if (error) {
NSLog(@"request to %@ failed: %@", endpoint, error);
if (callback) {
callback(@[@(NO)]);
}
} else {
if (callback) {
callback(@[response]);
}
}
}];
});
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *result = statusgoFunction();
if (callback) {
callback(@[result]);
}
});
}
}
+ (NSString *)executeStatusGoRequestWithResult:(NSString *)endpoint
body:(NSString *)body
statusgoFunction:(NSString * (^)(void))statusgoFunction {
StatusBackendClient *client = [StatusBackendClient sharedInstance];
if (client.serverEnabled) {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block NSString *resultString = @"";
[client request:endpoint body:body callback:^(NSString *response, NSError *error) {
if (error) {
NSLog(@"request to %@ failed: %@", endpoint, error);
resultString = @"";
} else {
resultString = response;
}
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return resultString;
} else {
return statusgoFunction();
}
}
@end

View File

@ -6,11 +6,13 @@
@interface Utils : NSObject <RCTBridgeModule> @interface Utils : NSObject <RCTBridgeModule>
+ (NSURL *)getRootUrl;
+ (NSString *)jsonStringWithPrettyPrint:(BOOL)prettyPrint fromDictionary:(NSDictionary *)dictionary; + (NSString *)jsonStringWithPrettyPrint:(BOOL)prettyPrint fromDictionary:(NSDictionary *)dictionary;
+ (NSString *)jsonStringWithPrettyPrint:(BOOL)prettyPrint fromArray:(NSArray *)array; + (NSString *)jsonStringWithPrettyPrint:(BOOL)prettyPrint fromArray:(NSArray *)array;
+ (NSURL *)getKeyStoreDirForKeyUID:(NSString *)keyUID; + (NSURL *)getKeyStoreDirForKeyUID:(NSString *)keyUID;
+ (NSString *)getExportDbFilePath; + (NSString *)getExportDbFilePath;
+ (NSString *)getKeyUID:(NSString *)jsonString; + (NSString *)getKeyUID:(NSString *)jsonString;
+ (void)migrateKeystore:(NSString *)accountData password:(NSString *)password; + (void)migrateKeystore:(NSString *)accountData password:(NSString *)password;
+ (void)handleStatusGoResponse:(NSString *)response source:(NSString *)source error:(NSError *)error;
@end @end

View File

@ -3,11 +3,28 @@
#import "React/RCTEventDispatcher.h" #import "React/RCTEventDispatcher.h"
#import "Statusgo.h" #import "Statusgo.h"
#import "Utils.h" #import "Utils.h"
#import "StatusBackendClient.h"
@implementation Utils @implementation Utils
RCT_EXPORT_MODULE(); RCT_EXPORT_MODULE();
#pragma mark - Private Methods
+ (NSURL *)getRootUrl {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl;
StatusBackendClient *client = [StatusBackendClient sharedInstance];
if (client.serverEnabled && client.rootDataDir) {
rootUrl = [NSURL fileURLWithPath:client.rootDataDir];
} else {
rootUrl = [[fileManager URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject];
}
return rootUrl;
}
+ (NSString *)jsonStringWithPrettyPrint:(BOOL)prettyPrint fromDictionary:(NSDictionary *)dictionary { + (NSString *)jsonStringWithPrettyPrint:(BOOL)prettyPrint fromDictionary:(NSDictionary *)dictionary {
NSError *error; NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary
@ -38,7 +55,7 @@ RCT_EXPORT_MODULE();
+ (NSURL *)getKeyStoreDirForKeyUID:(NSString *)keyUID { + (NSURL *)getKeyStoreDirForKeyUID:(NSString *)keyUID {
NSFileManager *fileManager = [NSFileManager defaultManager]; NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl = [[fileManager URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject]; NSURL *rootUrl = [self getRootUrl];
NSURL *oldKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"]; NSURL *oldKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
NSURL *multiaccountKeystoreDir = [oldKeystoreDir URLByAppendingPathComponent:keyUID]; NSURL *multiaccountKeystoreDir = [oldKeystoreDir URLByAppendingPathComponent:keyUID];
@ -57,6 +74,11 @@ RCT_EXPORT_MODULE();
} }
+ (NSString *) getExportDbFilePath { + (NSString *) getExportDbFilePath {
StatusBackendClient *client = [StatusBackendClient sharedInstance];
if (client.serverEnabled && client.rootDataDir) {
return [client.rootDataDir stringByAppendingPathComponent:@"export.db"];
}
NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"export.db"]; NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"export.db"];
NSFileManager *fileManager = [NSFileManager defaultManager]; NSFileManager *fileManager = [NSFileManager defaultManager];
@ -70,17 +92,36 @@ RCT_EXPORT_MODULE();
+ (void) migrateKeystore:(NSString *)accountData + (void) migrateKeystore:(NSString *)accountData
password:(NSString *)password { password:(NSString *)password {
NSFileManager *fileManager = [NSFileManager defaultManager]; NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager NSURL *rootUrl =[self getRootUrl];
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *keyUID = [self getKeyStoreDirForKeyUID:accountData]; NSData *jsonData = [accountData dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
NSDictionary *accountJson = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
if (error) {
NSLog(@"Error parsing accountData: %@", error);
return;
}
NSString *keyUID = [self getKeyUID:accountData];
NSURL *oldKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"]; NSURL *oldKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
NSURL *multiaccountKeystoreDir = [self getKeyStoreDirForKeyUID:keyUID.path]; NSURL *multiaccountKeystoreDir = [self getKeyStoreDirForKeyUID:keyUID];
NSArray *keys = [fileManager contentsOfDirectoryAtPath:multiaccountKeystoreDir.path error:nil]; NSArray *keys = [fileManager contentsOfDirectoryAtPath:multiaccountKeystoreDir.path error:nil];
if (keys.count == 0) { if (keys.count == 0) {
NSString *migrationResult = StatusgoMigrateKeyStoreDir(accountData, password, oldKeystoreDir.path, multiaccountKeystoreDir.path); NSDictionary *params = @{
@"account": accountJson,
@"password": password,
@"oldDir": oldKeystoreDir.path,
@"newDir": multiaccountKeystoreDir.path
};
NSData *paramsJsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating params JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:paramsJsonData encoding:NSUTF8StringEncoding];
NSString *migrationResult = StatusgoMigrateKeyStoreDirV2(jsonString);
NSLog(@"keystore migration result %@", migrationResult); NSLog(@"keystore migration result %@", migrationResult);
NSString *initKeystoreResult = StatusgoInitKeystore(multiaccountKeystoreDir.path); NSString *initKeystoreResult = StatusgoInitKeystore(multiaccountKeystoreDir.path);
@ -89,18 +130,19 @@ RCT_EXPORT_MODULE();
} }
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(backupDisabledDataDir) { RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(backupDisabledDataDir) {
StatusBackendClient *client = [StatusBackendClient sharedInstance];
if (client.serverEnabled && client.rootDataDir) {
return client.rootDataDir;
}
NSFileManager *fileManager = [NSFileManager defaultManager]; NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager NSURL *rootUrl = [Utils getRootUrl];
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
return rootUrl.path; return rootUrl.path;
} }
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(keystoreDir) { RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(keystoreDir) {
NSFileManager *fileManager = [NSFileManager defaultManager]; NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager NSURL *rootUrl =[Utils getRootUrl];
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *commonKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"]; NSURL *commonKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
@ -110,9 +152,17 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(keystoreDir) {
RCT_EXPORT_METHOD(validateMnemonic:(NSString *)seed RCT_EXPORT_METHOD(validateMnemonic:(NSString *)seed
callback:(RCTResponseSenderBlock)callback) { callback:(RCTResponseSenderBlock)callback) {
#if DEBUG #if DEBUG
NSLog(@"validateMnemonic() method called"); NSLog(@"validateMnemonicV2() method called");
#endif #endif
NSString *result = StatusgoValidateMnemonic(seed); NSDictionary *params = @{@"mnemonic": seed};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSString *result = StatusgoValidateMnemonicV2(jsonString);
callback(@[result]); callback(@[result]);
} }
@ -132,4 +182,17 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(validateConnectionString:(NSString *)cs)
return StatusgoValidateConnectionString(cs); return StatusgoValidateConnectionString(cs);
} }
+ (void)handleStatusGoResponse:(NSString *)response source:(NSString *)source error:(NSError *)error {
if (error) {
NSLog(@"%@ failed: %@", source, error);
return;
}
if ([response hasPrefix:@"{\"error\":\"\""]) {
NSLog(@"%@ success: %@", source, response);
} else {
NSLog(@"%@ failed: %@", source, response);
}
}
@end @end

View File

@ -9,7 +9,8 @@ if test -n "$INVALID_CHANGES"; then
exit 1 exit 1
fi fi
INVALID_CHANGES2=$(grep -E -r '(status-im\.)' --include '*.cljs' --include '*.clj' './src/utils') # Add exception for status-im.config in the utils package check
INVALID_CHANGES2=$(grep -E -r '(status-im\.)' --include '*.cljs' --include '*.clj' './src/utils' | grep -v 'status-im.config')
if test -n "$INVALID_CHANGES2"; then if test -n "$INVALID_CHANGES2"; then
echo "WARNING: status-im are not allowed in utils package" echo "WARNING: status-im are not allowed in utils package"

View File

@ -51,7 +51,8 @@
;; the target files (a.k.a hot reload). When false, you can manually ;; the target files (a.k.a hot reload). When false, you can manually
;; reload by calling `shadow.cljs.devtools.api/watch-compile-all!`. ;; reload by calling `shadow.cljs.devtools.api/watch-compile-all!`.
:devtools {:autobuild #shadow/env ["SHADOW_AUTOBUILD_ENABLED" :default true :as :bool]} :devtools {:autobuild #shadow/env ["SHADOW_AUTOBUILD_ENABLED" :default true :as :bool]}
:dev {:devtools {:before-load-async status-im.setup.hot-reload/before-reload :dev
{:devtools {:before-load-async status-im.setup.hot-reload/before-reload
:after-load-async status-im.setup.hot-reload/reload :after-load-async status-im.setup.hot-reload/reload
:build-notify status-im.setup.hot-reload/build-notify :build-notify status-im.setup.hot-reload/build-notify
:preloads [;; The official recommendation is to :preloads [;; The official recommendation is to
@ -59,16 +60,21 @@
flow-storm.api flow-storm.api
re-frisk-remote.preload re-frisk-remote.preload
status-im.setup.schema-preload status-im.setup.schema-preload
;; In order to use component test helpers in the REPL we ;; In order to use component test helpers in the REPL we need to
;; need to preload namespaces that are not normally required ;; preload namespaces that are not normally required by
;; by production code, such as ;; production code, such as @testing-library/react-native.
;; @testing-library/react-native.
test-helpers.component]} test-helpers.component]}
:closure-defines :closure-defines
{status-im.config/POKT_TOKEN #shadow/env "POKT_TOKEN" {status-im.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN" status-im.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN"
status-im.config/STATUS_BUILD_PROXY_USER #shadow/env "STATUS_BUILD_PROXY_USER" status-im.config/STATUS_BUILD_PROXY_USER #shadow/env "STATUS_BUILD_PROXY_USER"
status-im.config/STATUS_BUILD_PROXY_PASSWORD #shadow/env "STATUS_BUILD_PROXY_PASSWORD" status-im.config/STATUS_BUILD_PROXY_PASSWORD #shadow/env "STATUS_BUILD_PROXY_PASSWORD"
status-im.config/STATUS_BACKEND_SERVER_ENABLED #shadow/env "STATUS_BACKEND_SERVER_ENABLED"
status-im.config/STATUS_BACKEND_SERVER_HOST #shadow/env "STATUS_BACKEND_SERVER_HOST"
status-im.config/STATUS_BACKEND_SERVER_IMAGE_SERVER_URI_PREFIX
#shadow/env "STATUS_BACKEND_SERVER_IMAGE_SERVER_URI_PREFIX"
status-im.config/STATUS_BACKEND_SERVER_ROOT_DATA_DIR #shadow/env
"STATUS_BACKEND_SERVER_ROOT_DATA_DIR"
status-im.config/MIXPANEL_APP_ID #shadow/env "MIXPANEL_APP_ID" status-im.config/MIXPANEL_APP_ID #shadow/env "MIXPANEL_APP_ID"
status-im.config/MIXPANEL_TOKEN #shadow/env "MIXPANEL_TOKEN" status-im.config/MIXPANEL_TOKEN #shadow/env "MIXPANEL_TOKEN"
status-im.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY" status-im.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"

View File

@ -128,3 +128,16 @@
;; Alert banners are disabled for debug builds because alert banners overlay ;; Alert banners are disabled for debug builds because alert banners overlay
;; interfere with react-native debug tools, such as inspector and Perf monitor ;; interfere with react-native debug tools, such as inspector and Perf monitor
(def enable-alert-banner? (enabled? (get-config :ENABLE_ALERT_BANNER "0"))) (def enable-alert-banner? (enabled? (get-config :ENABLE_ALERT_BANNER "0")))
;; enable using status backend server or not, otherwise it will use built-in status-go library
;; see doc/use-status-backend-server.md for more details
(goog-define STATUS_BACKEND_SERVER_ENABLED "0")
;; The host should contain an IP address and a port separated by a colon.
;; The port comes from your running status backend server.
;; If you run it by PORT=60000 make run-status-backend , then host will likely be 127.0.0.1:60000
(goog-define STATUS_BACKEND_SERVER_HOST "")
;; /path/to/root/data/dir
;; make sure it exists, it should be in absolute path
(goog-define STATUS_BACKEND_SERVER_ROOT_DATA_DIR "")
;; if you're using android simulator, I suggest set the env variable to "http://10.0.2.2:"
(goog-define STATUS_BACKEND_SERVER_IMAGE_SERVER_URI_PREFIX "https://localhost:")

View File

@ -30,7 +30,8 @@
[status-im.setup.global-error :as global-error] [status-im.setup.global-error :as global-error]
[status-im.setup.interceptors :as interceptors] [status-im.setup.interceptors :as interceptors]
status-im.subs.root status-im.subs.root
[utils.i18n :as i18n])) [utils.i18n :as i18n]
[status-im.setup.status-backend-client :as status-backend-client]))
;;;; re-frame RN setup ;;;; re-frame RN setup
(set! interop/next-tick js/setTimeout) (set! interop/next-tick js/setTimeout)
@ -46,6 +47,7 @@
(defn init (defn init
[] []
(status-backend-client/init)
(navigation/init) (navigation/init)
(native-module/init #(re-frame/dispatch [:signals/signal-received %])) (native-module/init #(re-frame/dispatch [:signals/signal-received %]))
(when platform/android? (when platform/android?

View File

@ -0,0 +1,22 @@
(ns status-im.setup.status-backend-client
(:require ["react-native" :as react-native]
[status-im.config :as config]))
(def default-config
{:server-enabled? (config/enabled? config/STATUS_BACKEND_SERVER_ENABLED)
:status-go-endpoint (str "http://" config/STATUS_BACKEND_SERVER_HOST "/statusgo/")
:signal-endpoint (str "ws://" config/STATUS_BACKEND_SERVER_HOST "/signals")
:root-data-dir config/STATUS_BACKEND_SERVER_ROOT_DATA_DIR})
(defn set-config!
[{:keys [server-enabled? status-go-endpoint signal-endpoint root-data-dir]}]
(when-let [client (.-StatusBackendClient (.-NativeModules react-native))]
(.configStatusBackendServer client
server-enabled?
status-go-endpoint
signal-endpoint
root-data-dir)))
(defn init
[]
(set-config! default-config))

View File

@ -1,12 +1,16 @@
;; Exception here as referrenced status-im.config, the implementation related to the image
;; server and the qr components leave something to be desired. Added an exception to the lint
;; rule as quick fix. Feel free to improve it if you're a brave soul refactor
(ns utils.image-server (ns utils.image-server
(:require (:require
[quo.foundations.colors :as colors] [quo.foundations.colors :as colors]
[react-native.fs :as utils.fs] [react-native.fs :as utils.fs]
[react-native.platform :as platform] [react-native.platform :as platform]
[schema.core :as schema] [schema.core :as schema]
[status-im.config :as config]
[utils.datetime :as datetime])) [utils.datetime :as datetime]))
(def ^:const image-server-uri-prefix "https://localhost:") (def ^:const image-server-uri-prefix config/STATUS_BACKEND_SERVER_IMAGE_SERVER_URI_PREFIX)
(def ^:const account-images-action "/accountImages") (def ^:const account-images-action "/accountImages")
(def ^:const account-initials-action "/accountInitials") (def ^:const account-initials-action "/accountInitials")
(def ^:const contact-images-action "/contactImages") (def ^:const contact-images-action "/contactImages")

View File

@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>", "_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im", "owner": "status-im",
"repo": "status-go", "repo": "status-go",
"version": "v3.6.0", "version": "v3.8.0",
"commit-sha1": "00a8a72ac2cc0933503cdf88cc5eafa45ab5e182", "commit-sha1": "b3dbe91b5fab4fdab475ee94549629a6d2988ccc",
"src-sha256": "0ka6c7bg8mnwqpyn8rv15cba537vp2fm8yxlyl5s17lwai5hqnk5" "src-sha256": "0p104qd799rwhiqxfdkd6gh4phsby6zyay98mv0sapjxim3nz4xi"
} }