package statusgo import ( "encoding/hex" "encoding/json" "errors" "fmt" "unsafe" "go.uber.org/zap" validator "gopkg.in/go-playground/validator.v9" "github.com/ethereum/go-ethereum/signer/core/apitypes" "github.com/status-im/zxcvbn-go" "github.com/status-im/zxcvbn-go/scoring" abi_spec "github.com/status-im/status-go/abi-spec" "github.com/status-im/status-go/account" "github.com/status-im/status-go/api" "github.com/status-im/status-go/api/multiformat" "github.com/status-im/status-go/centralizedmetrics" "github.com/status-im/status-go/centralizedmetrics/providers" "github.com/status-im/status-go/eth-node/crypto" "github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/exportlogs" "github.com/status-im/status-go/extkeys" "github.com/status-im/status-go/images" "github.com/status-im/status-go/logutils" "github.com/status-im/status-go/logutils/requestlog" m_requests "github.com/status-im/status-go/mobile/requests" "github.com/status-im/status-go/multiaccounts" "github.com/status-im/status-go/multiaccounts/accounts" "github.com/status-im/status-go/multiaccounts/settings" "github.com/status-im/status-go/params" "github.com/status-im/status-go/profiling" "github.com/status-im/status-go/protocol" "github.com/status-im/status-go/protocol/common" identityUtils "github.com/status-im/status-go/protocol/identity" "github.com/status-im/status-go/protocol/identity/alias" "github.com/status-im/status-go/protocol/identity/colorhash" "github.com/status-im/status-go/protocol/identity/emojihash" "github.com/status-im/status-go/protocol/requests" "github.com/status-im/status-go/server" "github.com/status-im/status-go/server/pairing" "github.com/status-im/status-go/server/pairing/preflight" "github.com/status-im/status-go/services/personal" "github.com/status-im/status-go/services/typeddata" "github.com/status-im/status-go/services/wallet/wallettypes" "github.com/status-im/status-go/signal" "github.com/status-im/status-go/mobile/callog" ) func call(fn any, params ...any) any { return callog.Call(logutils.ZapLogger(), requestlog.GetRequestLogger(), fn, params...) } func callWithResponse(fn any, params ...any) string { return callog.CallWithResponse(logutils.ZapLogger(), requestlog.GetRequestLogger(), fn, params...) } type InitializeApplicationResponse struct { Accounts []multiaccounts.Account `json:"accounts"` CentralizedMetricsInfo *centralizedmetrics.MetricsInfo `json:"centralizedMetricsInfo"` } func InitializeApplication(requestJSON string) string { return callWithResponse(initializeApplication, requestJSON) } func initializeApplication(requestJSON string) string { var request requests.InitializeApplication err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } err = request.Validate() if err != nil { return makeJSONResponse(err) } // initialize metrics providers.MixpanelAppID = request.MixpanelAppID providers.MixpanelToken = request.MixpanelToken statusBackend.StatusNode().SetMediaServerEnableTLS(request.MediaServerEnableTLS) statusBackend.UpdateRootDataDir(request.DataDir) err = statusBackend.OpenAccounts() if err != nil { return makeJSONResponse(err) } accs, err := statusBackend.GetAccounts() if err != nil { return makeJSONResponse(err) } centralizedMetricsInfo, err := statusBackend.CentralizedMetricsInfo() if err != nil { return makeJSONResponse(err) } response := &InitializeApplicationResponse{ Accounts: accs, CentralizedMetricsInfo: centralizedMetricsInfo, } data, err := json.Marshal(response) if err != nil { return makeJSONResponse(err) } return string(data) } // Deprecated: Use InitializeApplication instead. func OpenAccounts(datadir string) string { return callWithResponse(openAccounts, datadir) } // DEPRECATED: use InitializeApplication // openAccounts opens database and returns accounts list. func openAccounts(datadir string) string { statusBackend.UpdateRootDataDir(datadir) err := statusBackend.OpenAccounts() if err != nil { return makeJSONResponse(err) } accs, err := statusBackend.GetAccounts() if err != nil { return makeJSONResponse(err) } data, err := json.Marshal(accs) if err != nil { return makeJSONResponse(err) } return string(data) } func ExtractGroupMembershipSignatures(signaturePairsStr string) string { return callWithResponse(extractGroupMembershipSignatures, signaturePairsStr) } // ExtractGroupMembershipSignatures extract public keys from tuples of content/signature. func extractGroupMembershipSignatures(signaturePairsStr string) string { var signaturePairs [][2]string if err := json.Unmarshal([]byte(signaturePairsStr), &signaturePairs); err != nil { return makeJSONResponse(err) } identities, err := statusBackend.ExtractGroupMembershipSignatures(signaturePairs) if err != nil { return makeJSONResponse(err) } data, err := json.Marshal(struct { Identities []string `json:"identities"` }{Identities: identities}) if err != nil { return makeJSONResponse(err) } return string(data) } func SignGroupMembership(content string) string { return callWithResponse(signGroupMembership, content) } // signGroupMembership signs a string containing group membership information. func signGroupMembership(content string) string { signature, err := statusBackend.SignGroupMembership(content) if err != nil { return makeJSONResponse(err) } data, err := json.Marshal(struct { Signature string `json:"signature"` }{Signature: signature}) if err != nil { return makeJSONResponse(err) } return string(data) } func GetNodeConfig() string { return callWithResponse(getNodeConfig) } // getNodeConfig returns the current config of the Status node func getNodeConfig() string { conf, err := statusBackend.GetNodeConfig() if err != nil { return makeJSONResponse(err) } respJSON, err := json.Marshal(conf) if err != nil { return makeJSONResponse(err) } return string(respJSON) } func ValidateNodeConfig(configJSON string) string { return callWithResponse(validateNodeConfig, configJSON) } // validateNodeConfig validates config for the Status node. func validateNodeConfig(configJSON string) string { var resp APIDetailedResponse _, err := params.NewConfigFromJSON(configJSON) // Convert errors to APIDetailedResponse switch err := err.(type) { case validator.ValidationErrors: resp = APIDetailedResponse{ Message: "validation: validation failed", FieldErrors: make([]APIFieldError, len(err)), } for i, ve := range err { resp.FieldErrors[i] = APIFieldError{ Parameter: ve.Namespace(), Errors: []APIError{ { Message: fmt.Sprintf("field validation failed on the '%s' tag", ve.Tag()), }, }, } } case error: resp = APIDetailedResponse{ Message: fmt.Sprintf("validation: %s", err.Error()), } case nil: resp = APIDetailedResponse{ Status: true, } } respJSON, err := json.Marshal(resp) if err != nil { return makeJSONResponse(err) } return string(respJSON) } func ResetChainData() string { return callWithResponse(resetChainData) } // resetChainData removes chain data from data directory. func resetChainData() string { api.RunAsync(statusBackend.ResetChainData) return makeJSONResponse(nil) } func CallRPC(inputJSON string) string { return callWithResponse(callRPC, inputJSON) } // callRPC calls public APIs via RPC. func callRPC(inputJSON string) string { resp, err := statusBackend.CallRPC(inputJSON) if err != nil { return makeJSONResponse(err) } return resp } func CallPrivateRPC(inputJSON string) string { return callWithResponse(callPrivateRPC, inputJSON) } // callPrivateRPC calls both public and private APIs via RPC. func callPrivateRPC(inputJSON string) string { resp, err := statusBackend.CallPrivateRPC(inputJSON) if err != nil { return makeJSONResponse(err) } return resp } // Deprecated: Use VerifyAccountPasswordV2 instead func VerifyAccountPassword(keyStoreDir, address, password string) string { return verifyAccountPassword(keyStoreDir, address, password) } // verifyAccountPassword verifies account password. func verifyAccountPassword(keyStoreDir, address, password string) string { _, err := statusBackend.AccountManager().VerifyAccountPassword(keyStoreDir, address, password) return makeJSONResponse(err) } func VerifyAccountPasswordV2(requestJSON string) string { return callWithResponse(verifyAccountPasswordV2, requestJSON) } func verifyAccountPasswordV2(requestJSON string) string { var request requests.VerifyAccountPassword err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } err = request.Validate() if err != nil { return makeJSONResponse(err) } _, err = statusBackend.AccountManager().VerifyAccountPassword(request.KeyStoreDir, request.Address, request.Password) return makeJSONResponse(err) } func VerifyDatabasePasswordV2(requestJSON string) string { return callWithResponse(verifyDatabasePasswordV2, requestJSON) } func verifyDatabasePasswordV2(requestJSON string) string { var request requests.VerifyDatabasePassword err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } err = request.Validate() if err != nil { return makeJSONResponse(err) } err = statusBackend.VerifyDatabasePassword(request.KeyUID, request.Password) return makeJSONResponse(err) } // Deprecated: use VerifyDatabasePasswordV2 instead func VerifyDatabasePassword(keyUID, password string) string { return verifyDatabasePassword(keyUID, password) } // verifyDatabasePassword verifies database password. func verifyDatabasePassword(keyUID, password string) string { err := statusBackend.VerifyDatabasePassword(keyUID, password) return makeJSONResponse(err) } func MigrateKeyStoreDirV2(requestJSON string) string { return callWithResponse(migrateKeyStoreDirV2, requestJSON) } func migrateKeyStoreDirV2(requestJSON string) string { var request requests.MigrateKeystoreDir err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } err = request.Validate() if err != nil { return makeJSONResponse(err) } err = statusBackend.MigrateKeyStoreDir(request.Account, request.Password, request.OldDir, request.NewDir) return makeJSONResponse(err) } // Deprecated: Use MigrateKeyStoreDirV2 instead func MigrateKeyStoreDir(accountData, password, oldDir, newDir string) string { return migrateKeyStoreDir(accountData, password, oldDir, newDir) } // migrateKeyStoreDir migrates key files to a new directory func migrateKeyStoreDir(accountData, password, oldDir, newDir string) string { var account multiaccounts.Account err := json.Unmarshal([]byte(accountData), &account) if err != nil { return makeJSONResponse(err) } err = statusBackend.MigrateKeyStoreDir(account, password, oldDir, newDir) return makeJSONResponse(err) } // login deprecated as Login and LoginWithConfig are deprecated func login(accountData, password, configJSON string) error { var account multiaccounts.Account err := json.Unmarshal([]byte(accountData), &account) if err != nil { return err } var conf params.NodeConfig if configJSON != "" { err = json.Unmarshal([]byte(configJSON), &conf) if err != nil { return err } } api.RunAsync(func() error { logutils.ZapLogger().Debug("start a node with account", zap.String("key-uid", account.KeyUID)) err := statusBackend.UpdateNodeConfigFleet(account, password, &conf) if err != nil { logutils.ZapLogger().Error("failed to update node config fleet", zap.String("key-uid", account.KeyUID), zap.Error(err)) return statusBackend.LoggedIn(account.KeyUID, err) } err = statusBackend.StartNodeWithAccount(account, password, &conf, nil) if err != nil { logutils.ZapLogger().Error("failed to start a node", zap.String("key-uid", account.KeyUID), zap.Error(err)) return err } logutils.ZapLogger().Debug("started a node with", zap.String("key-uid", account.KeyUID)) return nil }) return nil } // Login loads a key file (for a given address), tries to decrypt it using the password, // to verify ownership if verified, purges all the previous identities from Whisper, // and injects verified key as shh identity. // // Deprecated: Use LoginAccount instead. func Login(accountData, password string) string { err := login(accountData, password, "") if err != nil { return makeJSONResponse(err) } return makeJSONResponse(nil) } // LoginWithConfig loads a key file (for a given address), tries to decrypt it using the password, // to verify ownership if verified, purges all the previous identities from Whisper, // and injects verified key as shh identity. It then updates the accounts node db configuration // mergin the values received in the configJSON parameter // // Deprecated: Use LoginAccount instead. func LoginWithConfig(accountData, password, configJSON string) string { err := login(accountData, password, configJSON) if err != nil { return makeJSONResponse(err) } return makeJSONResponse(nil) } func CreateAccountAndLogin(requestJSON string) string { return callWithResponse(createAccountAndLogin, requestJSON) } func createAccountAndLogin(requestJSON string) string { var request requests.CreateAccount err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } err = request.Validate(&requests.CreateAccountValidation{ AllowEmptyDisplayName: false, }) if err != nil { return makeJSONResponse(err) } api.RunAsync(func() error { logutils.ZapLogger().Debug("starting a node and creating config") _, err := statusBackend.CreateAccountAndLogin(&request) if err != nil { logutils.ZapLogger().Error("failed to create account", zap.Error(err)) return err } logutils.ZapLogger().Debug("started a node, and created account") return nil }) return makeJSONResponse(nil) } func AcceptTerms() string { return callWithResponse(acceptTerms) } func acceptTerms() string { err := statusBackend.AcceptTerms() return makeJSONResponse(err) } func LoginAccount(requestJSON string) string { return callWithResponse(loginAccount, requestJSON) } func loginAccount(requestJSON string) string { var request requests.Login err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } err = request.Validate() if err != nil { return makeJSONResponse(err) } api.RunAsync(func() error { err := statusBackend.LoginAccount(&request) if err != nil { logutils.ZapLogger().Error("loginAccount failed", zap.Error(err)) return err } logutils.ZapLogger().Debug("loginAccount started node") return nil }) return makeJSONResponse(nil) } func RestoreAccountAndLogin(requestJSON string) string { return callWithResponse(restoreAccountAndLogin, requestJSON) } func restoreAccountAndLogin(requestJSON string) string { var request requests.RestoreAccount err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } err = request.Validate() if err != nil { return makeJSONResponse(err) } api.RunAsync(func() error { logutils.ZapLogger().Debug("starting a node and restoring account") if request.Keycard != nil { _, err = statusBackend.RestoreKeycardAccountAndLogin(&request) } else { _, err = statusBackend.RestoreAccountAndLogin(&request) } if err != nil { logutils.ZapLogger().Error("failed to restore account", zap.Error(err)) return err } logutils.ZapLogger().Debug("started a node, and restored account") return nil }) return makeJSONResponse(nil) } // SaveAccountAndLogin saves account in status-go database. // Deprecated: Use CreateAccountAndLogin instead. func SaveAccountAndLogin(accountData, password, settingsJSON, configJSON, subaccountData string) string { var account multiaccounts.Account err := json.Unmarshal([]byte(accountData), &account) if err != nil { return makeJSONResponse(err) } var settings settings.Settings err = json.Unmarshal([]byte(settingsJSON), &settings) if err != nil { return makeJSONResponse(err) } if *settings.Mnemonic != "" { settings.MnemonicWasNotShown = true } var conf params.NodeConfig err = json.Unmarshal([]byte(configJSON), &conf) if err != nil { return makeJSONResponse(err) } var subaccs []*accounts.Account err = json.Unmarshal([]byte(subaccountData), &subaccs) if err != nil { return makeJSONResponse(err) } api.RunAsync(func() error { logutils.ZapLogger().Debug("starting a node, and saving account with configuration", zap.String("key-uid", account.KeyUID)) err := statusBackend.StartNodeWithAccountAndInitialConfig(account, password, settings, &conf, subaccs, nil) if err != nil { logutils.ZapLogger().Error("failed to start node and save account", zap.String("key-uid", account.KeyUID), zap.Error(err)) return err } logutils.ZapLogger().Debug("started a node, and saved account", zap.String("key-uid", account.KeyUID)) return nil }) return makeJSONResponse(nil) } // Deprecated: Use DeleteMultiaccountV2 instead func DeleteMultiaccount(keyUID, keyStoreDir string) string { return callWithResponse(deleteMultiaccount, keyUID, keyStoreDir) } // deleteMultiaccount func deleteMultiaccount(keyUID, keyStoreDir string) string { err := statusBackend.DeleteMultiaccount(keyUID, keyStoreDir) return makeJSONResponse(err) } func DeleteMultiaccountV2(requestJSON string) string { return callWithResponse(deleteMultiaccountV2, requestJSON) } func deleteMultiaccountV2(requestJSON string) string { var request requests.DeleteMultiaccount err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } err = request.Validate() if err != nil { return makeJSONResponse(err) } err = statusBackend.DeleteMultiaccount(request.KeyUID, request.KeyStoreDir) return makeJSONResponse(err) } func DeleteImportedKeyV2(requestJSON string) string { return callWithResponse(deleteImportedKeyV2, requestJSON) } func deleteImportedKeyV2(requestJSON string) string { var request requests.DeleteImportedKey err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } err = request.Validate() if err != nil { return makeJSONResponse(err) } err = statusBackend.DeleteImportedKey(request.Address, request.Password, request.KeyStoreDir) return makeJSONResponse(err) } // Deprecated: Use DeleteImportedKeyV2 instead func DeleteImportedKey(address, password, keyStoreDir string) string { return deleteImportedKey(address, password, keyStoreDir) } // deleteImportedKey func deleteImportedKey(address, password, keyStoreDir string) string { err := statusBackend.DeleteImportedKey(address, password, keyStoreDir) return makeJSONResponse(err) } func InitKeystore(keydir string) string { return callWithResponse(initKeystore, keydir) } // initKeystore initialize keystore before doing any operations with keys. func initKeystore(keydir string) string { err := statusBackend.AccountManager().InitKeystore(keydir) return makeJSONResponse(err) } // SaveAccountAndLoginWithKeycard saves account in status-go database. // Deprecated: Use CreateAndAccountAndLogin with required keycard properties. func SaveAccountAndLoginWithKeycard(accountData, password, settingsJSON, configJSON, subaccountData string, keyHex string) string { var account multiaccounts.Account err := json.Unmarshal([]byte(accountData), &account) if err != nil { return makeJSONResponse(err) } var settings settings.Settings err = json.Unmarshal([]byte(settingsJSON), &settings) if err != nil { return makeJSONResponse(err) } var conf params.NodeConfig err = json.Unmarshal([]byte(configJSON), &conf) if err != nil { return makeJSONResponse(err) } var subaccs []*accounts.Account err = json.Unmarshal([]byte(subaccountData), &subaccs) if err != nil { return makeJSONResponse(err) } api.RunAsync(func() error { logutils.ZapLogger().Debug("starting a node, and saving account with configuration", zap.String("key-uid", account.KeyUID)) err := statusBackend.SaveAccountAndStartNodeWithKey(account, password, settings, &conf, subaccs, keyHex) if err != nil { logutils.ZapLogger().Error("failed to start node and save account", zap.String("key-uid", account.KeyUID), zap.Error(err)) return err } logutils.ZapLogger().Debug("started a node, and saved account", zap.String("key-uid", account.KeyUID)) return nil }) return makeJSONResponse(nil) } // LoginWithKeycard initializes an account with a chat key and encryption key used for PFS. // It purges all the previous identities from Whisper, and injects the key as shh identity. // Deprecated: Use LoginAccount instead. func LoginWithKeycard(accountData, password, keyHex string, configJSON string) string { var account multiaccounts.Account err := json.Unmarshal([]byte(accountData), &account) if err != nil { return makeJSONResponse(err) } var conf params.NodeConfig err = json.Unmarshal([]byte(configJSON), &conf) if err != nil { return makeJSONResponse(err) } api.RunAsync(func() error { logutils.ZapLogger().Debug("start a node with account", zap.String("key-uid", account.KeyUID)) err := statusBackend.StartNodeWithKey(account, password, keyHex, &conf) if err != nil { logutils.ZapLogger().Error("failed to start a node", zap.String("key-uid", account.KeyUID), zap.Error(err)) return err } logutils.ZapLogger().Debug("started a node with", zap.String("key-uid", account.KeyUID)) return nil }) return makeJSONResponse(nil) } func Logout() string { return callWithResponse(logout) } // logout is equivalent to clearing whisper identities. func logout() string { return makeJSONResponse(statusBackend.Logout()) } func SignMessage(rpcParams string) string { return callWithResponse(signMessage, rpcParams) } // signMessage unmarshals rpc params {data, address, password} and // passes them onto backend.SignMessage. func signMessage(rpcParams string) string { var params personal.SignParams err := json.Unmarshal([]byte(rpcParams), ¶ms) if err != nil { return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) } result, err := statusBackend.SignMessage(params) return prepareJSONResponse(result.String(), err) } // SignTypedData unmarshall data into TypedData, validate it and signs with selected account, // if password matches selected account. func SignTypedData(data, address, password string) string { return signTypedData(data, address, password) } func signTypedData(data, address, password string) string { var typed typeddata.TypedData err := json.Unmarshal([]byte(data), &typed) if err != nil { return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) } if err := typed.Validate(); err != nil { return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) } result, err := statusBackend.SignTypedData(typed, address, password) return prepareJSONResponse(result.String(), err) } // HashTypedData unmarshalls data into TypedData, validates it and hashes it. // //export HashTypedData func HashTypedData(data string) string { return callWithResponse(hashTypedData, data) } func hashTypedData(data string) string { var typed typeddata.TypedData err := json.Unmarshal([]byte(data), &typed) if err != nil { return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) } if err := typed.Validate(); err != nil { return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) } result, err := statusBackend.HashTypedData(typed) return prepareJSONResponse(result.String(), err) } // SignTypedDataV4 unmarshall data into TypedData, validate it and signs with selected account, // if password matches selected account. // //export SignTypedDataV4 func SignTypedDataV4(data, address, password string) string { return signTypedDataV4(data, address, password) } func signTypedDataV4(data, address, password string) string { var typed apitypes.TypedData err := json.Unmarshal([]byte(data), &typed) if err != nil { return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) } result, err := statusBackend.SignTypedDataV4(typed, address, password) return prepareJSONResponse(result.String(), err) } // HashTypedDataV4 unmarshalls data into TypedData, validates it and hashes it. // //export HashTypedDataV4 func HashTypedDataV4(data string) string { return callWithResponse(hashTypedDataV4, data) } func hashTypedDataV4(data string) string { var typed apitypes.TypedData err := json.Unmarshal([]byte(data), &typed) if err != nil { return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) } result, err := statusBackend.HashTypedDataV4(typed) return prepareJSONResponse(result.String(), err) } func Recover(rpcParams string) string { return callWithResponse(recoverWithRPCParams, rpcParams) } // recoverWithRPCParams unmarshals rpc params {signDataString, signedData} and passes // them onto backend. func recoverWithRPCParams(rpcParams string) string { var params personal.RecoverParams err := json.Unmarshal([]byte(rpcParams), ¶ms) if err != nil { return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) } addr, err := statusBackend.Recover(params) return prepareJSONResponse(addr.String(), err) } // SendTransactionWithChainID converts RPC args and calls backend.SendTransactionWithChainID. func SendTransactionWithChainID(chainID int, txArgsJSON, password string) string { return sendTransactionWithChainID(chainID, txArgsJSON, password) } // sendTransactionWithChainID converts RPC args and calls backend.SendTransactionWithChainID. func sendTransactionWithChainID(chainID int, txArgsJSON, password string) string { var params wallettypes.SendTxArgs err := json.Unmarshal([]byte(txArgsJSON), ¶ms) if err != nil { return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) } hash, err := statusBackend.SendTransactionWithChainID(uint64(chainID), params, password) code := codeUnknown if c, ok := errToCodeMap[err]; ok { code = c } return prepareJSONResponseWithCode(hash.String(), err, code) } // Deprecated: Use SendTransactionV2 instead. func SendTransaction(txArgsJSON, password string) string { return sendTransaction(txArgsJSON, password) } // sendTransaction converts RPC args and calls backend.SendTransaction. // Deprecated: Use sendTransactionV2 instead. func sendTransaction(txArgsJSON, password string) string { var params wallettypes.SendTxArgs err := json.Unmarshal([]byte(txArgsJSON), ¶ms) if err != nil { return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) } hash, err := statusBackend.SendTransaction(params, password) code := codeUnknown if c, ok := errToCodeMap[err]; ok { code = c } return prepareJSONResponseWithCode(hash.String(), err, code) } func SendTransactionV2(requestJSON string) string { return callWithResponse(sendTransactionV2, requestJSON) } func sendTransactionV2(requestJSON string) string { var request requests.SendTransaction err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) } err = request.Validate() if err != nil { return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) } hash, err := statusBackend.SendTransaction(request.TxArgs, request.Password) code := codeUnknown if c, ok := errToCodeMap[err]; ok { code = c } return prepareJSONResponseWithCode(hash.String(), err, code) } func SendTransactionWithSignature(txArgsJSON, sigString string) string { return callWithResponse(sendTransactionWithSignature, txArgsJSON, sigString) } // sendTransactionWithSignature converts RPC args and calls backend.SendTransactionWithSignature func sendTransactionWithSignature(txArgsJSON, sigString string) string { var params wallettypes.SendTxArgs err := json.Unmarshal([]byte(txArgsJSON), ¶ms) if err != nil { return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) } sig, err := hex.DecodeString(sigString) if err != nil { return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) } hash, err := statusBackend.SendTransactionWithSignature(params, sig) code := codeUnknown if c, ok := errToCodeMap[err]; ok { code = c } return prepareJSONResponseWithCode(hash.String(), err, code) } func HashTransaction(txArgsJSON string) string { return callWithResponse(hashTransaction, txArgsJSON) } // hashTransaction validate the transaction and returns new txArgs and the transaction hash. func hashTransaction(txArgsJSON string) string { var params wallettypes.SendTxArgs err := json.Unmarshal([]byte(txArgsJSON), ¶ms) if err != nil { return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) } newTxArgs, hash, err := statusBackend.HashTransaction(params) code := codeUnknown if c, ok := errToCodeMap[err]; ok { code = c } result := struct { Transaction wallettypes.SendTxArgs `json:"transaction"` Hash types.Hash `json:"hash"` }{ Transaction: newTxArgs, Hash: hash, } return prepareJSONResponseWithCode(result, err, code) } func HashMessage(message string) string { return callWithResponse(hashMessage, message) } // hashMessage calculates the hash of a message to be safely signed by the keycard // The hash is calulcated as // // keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). // // This gives context to the signed message and prevents signing of transactions. func hashMessage(message string) string { hash, err := api.HashMessage(message) code := codeUnknown if c, ok := errToCodeMap[err]; ok { code = c } return prepareJSONResponseWithCode(fmt.Sprintf("0x%x", hash), err, code) } func StartCPUProfile(dataDir string) string { return callWithResponse(startCPUProfile, dataDir) } // startCPUProfile runs pprof for CPU. func startCPUProfile(dataDir string) string { err := profiling.StartCPUProfile(dataDir) return makeJSONResponse(err) } func StopCPUProfiling() string { return callWithResponse(stopCPUProfiling) } // stopCPUProfiling stops pprof for cpu. func stopCPUProfiling() string { //nolint: deadcode err := profiling.StopCPUProfile() return makeJSONResponse(err) } func WriteHeapProfile(dataDir string) string { return callWithResponse(writeHeapProfile, dataDir) } // writeHeapProfile starts pprof for heap func writeHeapProfile(dataDir string) string { //nolint: deadcode err := profiling.WriteHeapFile(dataDir) return makeJSONResponse(err) } func makeJSONResponse(err error) string { errString := "" if err != nil { logutils.ZapLogger().Error("error in makeJSONResponse", zap.Error(err)) errString = err.Error() } out := APIResponse{ Error: errString, } outBytes, _ := json.Marshal(out) return string(outBytes) } func AddPeer(enode string) string { return callWithResponse(addPeer, enode) } // addPeer adds an enode as a peer. func addPeer(enode string) string { err := statusBackend.StatusNode().AddPeer(enode) return makeJSONResponse(err) } // Deprecated: Use ConnectionChangeV2 instead. func ConnectionChange(typ string, expensive int) { call(connectionChange, typ, expensive) } // connectionChange handles network state changes as reported // by ReactNative (see https://facebook.github.io/react-native/docs/netinfo.html) func connectionChange(typ string, expensive int) { statusBackend.ConnectionChange(typ, expensive == 1) } func ConnectionChangeV2(requestJSON string) string { return callWithResponse(connectionChangeV2, requestJSON) } func connectionChangeV2(requestJSON string) string { var request requests.ConnectionChange err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } statusBackend.ConnectionChange(request.Type, request.Expensive) return makeJSONResponse(nil) } // Deprecated: Use AppStateChangeV2 instead. func AppStateChange(state string) { call(appStateChange, state) } // appStateChange handles app state changes (background/foreground). func appStateChange(state string) { s, err := api.ParseAppState(state) if err != nil { logutils.ZapLogger().Error("parse app state failed, ignoring", zap.Error(err)) return } statusBackend.AppStateChange(s) } func AppStateChangeV2(requestJSON string) string { return callWithResponse(appStateChangeV2, requestJSON) } func appStateChangeV2(requestJSON string) string { var request m_requests.AppStateChange err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } err = request.Validate() if err != nil { return makeJSONResponse(err) } statusBackend.AppStateChange(request.State) return makeJSONResponse(nil) } func StartLocalNotifications() string { return callWithResponse(startLocalNotifications) } // startLocalNotifications func startLocalNotifications() string { err := statusBackend.StartLocalNotifications() return makeJSONResponse(err) } func StopLocalNotifications() string { return callWithResponse(stopLocalNotifications) } // stopLocalNotifications func stopLocalNotifications() string { err := statusBackend.StopLocalNotifications() return makeJSONResponse(err) } func SetMobileSignalHandler(handler SignalHandler) { call(setMobileSignalHandler, handler) } // setMobileSignalHandler setup geth callback to notify about new signal // used for gomobile builds func setMobileSignalHandler(handler SignalHandler) { signal.SetMobileSignalHandler(func(data []byte) { if len(data) > 0 { handler.HandleSignal(string(data)) } }) } func SetSignalEventCallback(cb unsafe.Pointer) { call(setSignalEventCallback, cb) } // setSignalEventCallback setup geth callback to notify about new signal func setSignalEventCallback(cb unsafe.Pointer) { signal.SetSignalEventCallback(cb) } // ExportNodeLogs reads current node log and returns content to a caller. // //export ExportNodeLogs func ExportNodeLogs() string { return callWithResponse(exportNodeLogs) } func exportNodeLogs() string { node := statusBackend.StatusNode() if node == nil { return makeJSONResponse(errors.New("node is not running")) } config := node.Config() if config == nil { return makeJSONResponse(errors.New("config and log file are not available")) } data, err := json.Marshal(exportlogs.ExportFromBaseFile(config.LogFile)) if err != nil { return makeJSONResponse(fmt.Errorf("error marshalling to json: %v", err)) } return string(data) } func SignHash(hexEncodedHash string) string { return callWithResponse(signHash, hexEncodedHash) } // signHash exposes vanilla ECDSA signing required for Swarm messages func signHash(hexEncodedHash string) string { hexEncodedSignature, err := statusBackend.SignHash(hexEncodedHash) if err != nil { return makeJSONResponse(err) } return hexEncodedSignature } func GenerateAlias(pk string) string { return callWithResponse(generateAlias, pk) } func generateAlias(pk string) string { // We ignore any error, empty string is considered an error name, _ := protocol.GenerateAlias(pk) return name } func IsAlias(value string) string { return callWithResponse(isAlias, value) } func isAlias(value string) string { return prepareJSONResponse(alias.IsAlias(value), nil) } func Identicon(pk string) string { return callWithResponse(identicon, pk) } func identicon(pk string) string { // We ignore any error, empty string is considered an error identicon, _ := protocol.Identicon(pk) return identicon } func EmojiHash(pk string) string { return callWithResponse(emojiHash, pk) } func emojiHash(pk string) string { return prepareJSONResponse(emojihash.GenerateFor(pk)) } func ColorHash(pk string) string { return callWithResponse(colorHash, pk) } func colorHash(pk string) string { return prepareJSONResponse(colorhash.GenerateFor(pk)) } func ColorID(pk string) string { return callWithResponse(colorID, pk) } func colorID(pk string) string { return prepareJSONResponse(identityUtils.ToColorID(pk)) } // Deprecated: Use ValidateMnemonicV2 instead. func ValidateMnemonic(mnemonic string) string { return validateMnemonic(mnemonic) } func validateMnemonic(mnemonic string) string { m := extkeys.NewMnemonic() err := m.ValidateMnemonic(mnemonic, extkeys.Language(0)) if err != nil { return makeJSONResponse(err) } keyUID, err := statusBackend.GetKeyUIDByMnemonic(mnemonic) if err != nil { return makeJSONResponse(err) } response := &APIKeyUIDResponse{KeyUID: keyUID} data, err := json.Marshal(response) if err != nil { return makeJSONResponse(err) } return string(data) } func ValidateMnemonicV2(requestJSON string) string { return callWithResponse(validateMnemonicV2, requestJSON) } func validateMnemonicV2(requestJSON string) string { var request requests.ValidateMnemonic err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } return validateMnemonic(request.Mnemonic) } func DecompressPublicKey(key string) string { return callWithResponse(decompressPublicKey, key) } // decompressPublicKey decompresses 33-byte compressed format to uncompressed 65-byte format. func decompressPublicKey(key string) string { decoded, err := types.DecodeHex(key) if err != nil { return makeJSONResponse(err) } const compressionBytesNumber = 33 if len(decoded) != compressionBytesNumber { return makeJSONResponse(errors.New("key is not 33 bytes long")) } pubKey, err := crypto.DecompressPubkey(decoded) if err != nil { return makeJSONResponse(err) } return types.EncodeHex(crypto.FromECDSAPub(pubKey)) } func CompressPublicKey(key string) string { return callWithResponse(compressPublicKey, key) } // compressPublicKey compresses uncompressed 65-byte format to 33-byte compressed format. func compressPublicKey(key string) string { pubKey, err := common.HexToPubkey(key) if err != nil { return makeJSONResponse(err) } return types.EncodeHex(crypto.CompressPubkey(pubKey)) } func SerializeLegacyKey(key string) string { return callWithResponse(serializeLegacyKey, key) } // serializeLegacyKey compresses an old format public key (0x04...) to the new one zQ... func serializeLegacyKey(key string) string { cpk, err := multiformat.SerializeLegacyKey(key) if err != nil { return makeJSONResponse(err) } return cpk } func MultiformatSerializePublicKey(key, outBase string) string { return callWithResponse(multiformatSerializePublicKey, key, outBase) } // SerializePublicKey compresses an uncompressed multibase encoded multicodec identified EC public key // For details on usage see specs https://specs.status.im/spec/2#public-key-serialization func multiformatSerializePublicKey(key, outBase string) string { cpk, err := multiformat.SerializePublicKey(key, outBase) if err != nil { return makeJSONResponse(err) } return cpk } // Deprecated: Use MultiformatDeserializePublicKeyV2 instead. func MultiformatDeserializePublicKey(key, outBase string) string { return callWithResponse(multiformatDeserializePublicKey, key, outBase) } // DeserializePublicKey decompresses a compressed multibase encoded multicodec identified EC public key // For details on usage see specs https://specs.status.im/spec/2#public-key-serialization func multiformatDeserializePublicKey(key, outBase string) string { pk, err := multiformat.DeserializePublicKey(key, outBase) if err != nil { return makeJSONResponse(err) } return pk } func MultiformatDeserializePublicKeyV2(requestJSON string) string { return callWithResponse(multiformatDeserializePublicKeyV2, requestJSON) } func multiformatDeserializePublicKeyV2(requestJSON string) string { var request requests.MultiformatDeserializePublicKey err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } return multiformatDeserializePublicKey(request.Key, request.OutBase) } // Deprecated: Use ExportUnencryptedDatabaseV2 instead. func ExportUnencryptedDatabase(accountData, password, databasePath string) string { return exportUnencryptedDatabase(accountData, password, databasePath) } // exportUnencryptedDatabase exports the database unencrypted to the given path func exportUnencryptedDatabase(accountData, password, databasePath string) string { var account multiaccounts.Account err := json.Unmarshal([]byte(accountData), &account) if err != nil { return makeJSONResponse(err) } err = statusBackend.ExportUnencryptedDatabase(account, password, databasePath) return makeJSONResponse(err) } func ExportUnencryptedDatabaseV2(requestJSON string) string { return callWithResponse(exportUnencryptedDatabaseV2, requestJSON) } func exportUnencryptedDatabaseV2(requestJSON string) string { var request requests.ExportUnencryptedDatabase err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } err = statusBackend.ExportUnencryptedDatabase(request.Account, request.Password, request.DatabasePath) return makeJSONResponse(err) } // Deprecated: Use ImportUnencryptedDatabaseV2 instead. func ImportUnencryptedDatabase(accountData, password, databasePath string) string { return importUnencryptedDatabase(accountData, password, databasePath) } // importUnencryptedDatabase imports the database unencrypted to the given directory func importUnencryptedDatabase(accountData, password, databasePath string) string { var account multiaccounts.Account err := json.Unmarshal([]byte(accountData), &account) if err != nil { return makeJSONResponse(err) } err = statusBackend.ImportUnencryptedDatabase(account, password, databasePath) return makeJSONResponse(err) } func ImportUnencryptedDatabaseV2(requestJSON string) string { return callWithResponse(importUnencryptedDatabaseV2, requestJSON) } func importUnencryptedDatabaseV2(requestJSON string) string { var request requests.ImportUnencryptedDatabase err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } err = statusBackend.ImportUnencryptedDatabase(request.Account, request.Password, request.DatabasePath) return makeJSONResponse(err) } // Deprecated: Use ChangeDatabasePasswordV2 instead. func ChangeDatabasePassword(keyUID, password, newPassword string) string { return changeDatabasePassword(keyUID, password, newPassword) } // changeDatabasePassword changes the password of the database func changeDatabasePassword(keyUID, password, newPassword string) string { err := statusBackend.ChangeDatabasePassword(keyUID, password, newPassword) return makeJSONResponse(err) } func ChangeDatabasePasswordV2(requestJSON string) string { return callWithResponse(changeDatabasePasswordV2, requestJSON) } func changeDatabasePasswordV2(requestJSON string) string { var request requests.ChangeDatabasePassword err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } return changeDatabasePassword(request.KeyUID, request.OldPassword, request.NewPassword) } // Deprecated: Use ConvertToKeycardAccountV2 instead. func ConvertToKeycardAccount(accountData, settingsJSON, keycardUID, password, newPassword string) string { return convertToKeycardAccount(accountData, settingsJSON, keycardUID, password, newPassword) } // convertToKeycardAccount converts the account to a keycard account func convertToKeycardAccount(accountData, settingsJSON, keycardUID, password, newPassword string) string { var account multiaccounts.Account err := json.Unmarshal([]byte(accountData), &account) if err != nil { return makeJSONResponse(err) } var settings settings.Settings err = json.Unmarshal([]byte(settingsJSON), &settings) if err != nil { return makeJSONResponse(err) } err = statusBackend.ConvertToKeycardAccount(account, settings, keycardUID, password, newPassword) return makeJSONResponse(err) } func ConvertToKeycardAccountV2(requestJSON string) string { return callWithResponse(convertToKeycardAccountV2, requestJSON) } func convertToKeycardAccountV2(requestJSON string) string { var request requests.ConvertToKeycardAccount err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } err = statusBackend.ConvertToKeycardAccount(request.Account, request.Settings, request.KeycardUID, request.OldPassword, request.NewPassword) return makeJSONResponse(err) } // Deprecated: Use ConvertToRegularAccountV2 instead. func ConvertToRegularAccount(mnemonic, currPassword, newPassword string) string { return convertToRegularAccount(mnemonic, currPassword, newPassword) } // convertToRegularAccount converts the account to a regular account func convertToRegularAccount(mnemonic, currPassword, newPassword string) string { err := statusBackend.ConvertToRegularAccount(mnemonic, currPassword, newPassword) return makeJSONResponse(err) } func ConvertToRegularAccountV2(requestJSON string) string { return callWithResponse(convertToRegularAccountV2, requestJSON) } func convertToRegularAccountV2(requestJSON string) string { var request requests.ConvertToRegularAccount err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } return convertToRegularAccount(request.Mnemonic, request.CurrPassword, request.NewPassword) } func ImageServerTLSCert() string { cert, err := server.PublicMediaTLSCert() if err != nil { return makeJSONResponse(err) } return cert } type GetPasswordStrengthRequest struct { Password string `json:"password"` UserInputs []string `json:"userInputs"` } type PasswordScoreResponse struct { Score int `json:"score"` } // GetPasswordStrength uses zxcvbn module and generates a JSON containing information about the quality of the given password // (Entropy, CrackTime, CrackTimeDisplay, Score, MatchSequence and CalcTime). // userInputs argument can be whatever list of strings like user's personal info or site-specific vocabulary that zxcvbn will // make use to determine the result. // For more details on usage see https://github.com/status-im/zxcvbn-go func GetPasswordStrength(paramsJSON string) string { var requestParams GetPasswordStrengthRequest err := json.Unmarshal([]byte(paramsJSON), &requestParams) if err != nil { return makeJSONResponse(err) } data, err := json.Marshal(zxcvbn.PasswordStrength(requestParams.Password, requestParams.UserInputs)) if err != nil { return makeJSONResponse(fmt.Errorf("Error marshalling to json: %v", err)) } return string(data) } // GetPasswordStrengthScore uses zxcvbn module and gets the score information about the given password. // userInputs argument can be whatever list of strings like user's personal info or site-specific vocabulary that zxcvbn will // make use to determine the result. // For more details on usage see https://github.com/status-im/zxcvbn-go func GetPasswordStrengthScore(paramsJSON string) string { var requestParams GetPasswordStrengthRequest var quality scoring.MinEntropyMatch err := json.Unmarshal([]byte(paramsJSON), &requestParams) if err != nil { return makeJSONResponse(err) } quality = zxcvbn.PasswordStrength(requestParams.Password, requestParams.UserInputs) data, err := json.Marshal(PasswordScoreResponse{ Score: quality.Score, }) if err != nil { return makeJSONResponse(fmt.Errorf("Error marshalling to json: %v", err)) } return string(data) } type FleetDescription struct { DefaultFleet string `json:"defaultFleet"` Fleets map[string]map[string][]string `json:"fleets"` } func Fleets() string { return callWithResponse(fleets) } func fleets() string { fleets := FleetDescription{ DefaultFleet: api.DefaultFleet, Fleets: params.GetSupportedFleets(), } data, err := json.Marshal(fleets) if err != nil { return makeJSONResponse(fmt.Errorf("Error marshalling to json: %v", err)) } return string(data) } // Deprecated: Use SwitchFleetV2 instead. func SwitchFleet(fleet string, configJSON string) string { return callWithResponse(switchFleet, fleet, configJSON) } func switchFleet(fleet string, configJSON string) string { var conf params.NodeConfig if configJSON != "" { err := json.Unmarshal([]byte(configJSON), &conf) if err != nil { return makeJSONResponse(err) } } clusterConfig, err := params.LoadClusterConfigFromFleet(fleet) if err != nil { return makeJSONResponse(err) } conf.ClusterConfig.Fleet = fleet conf.ClusterConfig.ClusterID = clusterConfig.ClusterID err = statusBackend.SwitchFleet(fleet, &conf) return makeJSONResponse(err) } func SwitchFleetV2(requestJSON string) string { return callWithResponse(switchFleetV2, requestJSON) } func switchFleetV2(requestJSON string) string { var request requests.SwitchFleet err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } return switchFleet(request.Fleet, request.ConfigJSON) } // Deprecated: Use GenerateImagesV2 instead. func GenerateImages(filepath string, aX, aY, bX, bY int) string { return generateImages(filepath, aX, aY, bX, bY) } func GenerateImagesV2(requestJSON string) string { return callWithResponse(generateImagesV2, requestJSON) } func generateImagesV2(requestJSON string) string { var request requests.GenerateImages err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } return generateImages(request.Filepath, request.AX, request.AY, request.BX, request.BY) } func generateImages(filepath string, aX, aY, bX, bY int) string { iis, err := images.GenerateIdentityImages(filepath, aX, aY, bX, bY) if err != nil { return makeJSONResponse(err) } data, err := json.Marshal(iis) if err != nil { return makeJSONResponse(fmt.Errorf("Error marshalling to json: %v", err)) } return string(data) } func LocalPairingPreflightOutboundCheck() string { return callWithResponse(localPairingPreflightOutboundCheck) } // localPairingPreflightOutboundCheck creates a local tls server accessible via an outbound network address. // The function creates a client and makes an outbound network call to the local server. This function should be // triggered to ensure that the device has permissions to access its LAN or to make outbound network calls. // // In addition, the functionality attempts to address an issue with iOS devices https://stackoverflow.com/a/64242745 func localPairingPreflightOutboundCheck() string { err := preflight.CheckOutbound() return makeJSONResponse(err) } func StartSearchForLocalPairingPeers() string { return callWithResponse(startSearchForLocalPairingPeers) } // startSearchForLocalPairingPeers starts a UDP multicast beacon that both listens for and broadcasts to LAN peers // on discovery the beacon will emit a signal with the details of the discovered peer. // // Currently, beacons are configured to search for 2 minutes pinging the network every 500 ms; // - If no peer discovery is made before this time elapses the operation will terminate. // - If a peer is discovered the pairing.PeerNotifier will terminate operation after 5 seconds, giving the peer // reasonable time to discover this device. // // Peer details are represented by a json.Marshal peers.LocalPairingPeerHello func startSearchForLocalPairingPeers() string { pn := pairing.NewPeerNotifier() err := pn.Search() return makeJSONResponse(err) } func GetConnectionStringForBeingBootstrapped(configJSON string) string { return callWithResponse(getConnectionStringForBeingBootstrapped, configJSON) } // getConnectionStringForBeingBootstrapped starts a pairing.ReceiverServer // then generates a pairing.ConnectionParams. Used when the device is Logged out or has no Account keys // and the device has no camera to read a QR code with // // Example: A desktop device (device without camera) receiving account data from mobile (device with camera) func getConnectionStringForBeingBootstrapped(configJSON string) string { if configJSON == "" { return makeJSONResponse(fmt.Errorf("no config given, PayloadSourceConfig is expected")) } statusBackend.LocalPairingStateManager.SetPairing(true) defer func() { statusBackend.LocalPairingStateManager.SetPairing(false) }() cs, err := pairing.StartUpReceiverServer(statusBackend, configJSON) if err != nil { return makeJSONResponse(err) } err = statusBackend.Logout() if err != nil { return makeJSONResponse(err) } return cs } func GetConnectionStringForBootstrappingAnotherDevice(configJSON string) string { return callWithResponse(getConnectionStringForBootstrappingAnotherDevice, configJSON) } // getConnectionStringForBootstrappingAnotherDevice starts a pairing.SenderServer // then generates a pairing.ConnectionParams. Used when the device is Logged in and therefore has Account keys // and the device might not have a camera // // Example: A mobile or desktop device (devices that MAY have a camera but MUST have a screen) // sending account data to a mobile (device with camera) func getConnectionStringForBootstrappingAnotherDevice(configJSON string) string { if configJSON == "" { return makeJSONResponse(fmt.Errorf("no config given, SendingServerConfig is expected")) } statusBackend.LocalPairingStateManager.SetPairing(true) defer func() { statusBackend.LocalPairingStateManager.SetPairing(false) }() cs, err := pairing.StartUpSenderServer(statusBackend, configJSON) if err != nil { return makeJSONResponse(err) } return cs } type inputConnectionStringForBootstrappingResponse struct { InstallationID string `json:"installationId"` KeyUID string `json:"keyUID"` Error error `json:"error"` } func (i *inputConnectionStringForBootstrappingResponse) toJSON(err error) string { i.Error = err j, _ := json.Marshal(i) return string(j) } // Deprecated: Use InputConnectionStringForBootstrappingV2 instead. func InputConnectionStringForBootstrapping(cs, configJSON string) string { return callWithResponse(inputConnectionStringForBootstrapping, cs, configJSON) } // inputConnectionStringForBootstrapping starts a pairing.ReceiverClient // The given server.ConnectionParams string will determine the server.Mode // // server.Mode = server.Sending // Used when the device is Logged out or has no Account keys and has a camera to read a QR code // // Example: A mobile device (device with a camera) receiving account data from // a device with a screen (mobile or desktop devices) func inputConnectionStringForBootstrapping(cs, configJSON string) string { var err error if configJSON == "" { return makeJSONResponse(fmt.Errorf("no config given, ReceiverClientConfig is expected")) } params := &pairing.ConnectionParams{} err = params.FromString(cs) if err != nil { response := &inputConnectionStringForBootstrappingResponse{} return response.toJSON(fmt.Errorf("could not parse connection string")) } response := &inputConnectionStringForBootstrappingResponse{ InstallationID: params.InstallationID(), KeyUID: params.KeyUID(), } err = statusBackend.LocalPairingStateManager.StartPairing(cs) defer func() { statusBackend.LocalPairingStateManager.StopPairing(cs, err) }() if err != nil { return response.toJSON(err) } var conf pairing.ReceiverClientConfig err = json.Unmarshal([]byte(configJSON), &conf) if err != nil { return response.toJSON(err) } err = pairing.StartUpReceivingClient(statusBackend, cs, &conf) if err != nil { return response.toJSON(err) } return response.toJSON(statusBackend.Logout()) } func InputConnectionStringForBootstrappingV2(requestJSON string) string { return callWithResponse(inputConnectionStringForBootstrappingV2, requestJSON) } func inputConnectionStringForBootstrappingV2(requestJSON string) string { var request m_requests.InputConnectionStringForBootstrapping err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } if err := request.Validate(); err != nil { return makeJSONResponse(err) } params := &pairing.ConnectionParams{} err = params.FromString(request.ConnectionString) if err != nil { response := &inputConnectionStringForBootstrappingResponse{} return response.toJSON(fmt.Errorf("could not parse connection string")) } response := &inputConnectionStringForBootstrappingResponse{ InstallationID: params.InstallationID(), KeyUID: params.KeyUID(), } err = statusBackend.LocalPairingStateManager.StartPairing(request.ConnectionString) defer func() { statusBackend.LocalPairingStateManager.StopPairing(request.ConnectionString, err) }() if err != nil { return response.toJSON(err) } err = pairing.StartUpReceivingClient(statusBackend, request.ConnectionString, request.ReceiverClientConfig) if err != nil { return response.toJSON(err) } return response.toJSON(statusBackend.Logout()) } // Deprecated: Use InputConnectionStringForBootstrappingAnotherDeviceV2 instead. func InputConnectionStringForBootstrappingAnotherDevice(cs, configJSON string) string { return callWithResponse(inputConnectionStringForBootstrappingAnotherDevice, cs, configJSON) } // inputConnectionStringForBootstrappingAnotherDevice starts a pairing.SendingClient // The given server.ConnectionParams string will determine the server.Mode // // server.Mode = server.Receiving // Used when the device is Logged in and therefore has Account keys and the has a camera to read a QR code // // Example: A mobile (device with camera) sending account data to a desktop device (device without camera) func inputConnectionStringForBootstrappingAnotherDevice(cs, configJSON string) string { var err error if configJSON == "" { return makeJSONResponse(fmt.Errorf("no config given, SenderClientConfig is expected")) } err = statusBackend.LocalPairingStateManager.StartPairing(cs) defer func() { statusBackend.LocalPairingStateManager.StopPairing(cs, err) }() if err != nil { return makeJSONResponse(err) } var conf pairing.SenderClientConfig err = json.Unmarshal([]byte(configJSON), &conf) if err != nil { return makeJSONResponse(err) } err = pairing.StartUpSendingClient(statusBackend, cs, &conf) return makeJSONResponse(err) } func InputConnectionStringForBootstrappingAnotherDeviceV2(requestJSON string) string { return callWithResponse(inputConnectionStringForBootstrappingAnotherDeviceV2, requestJSON) } func inputConnectionStringForBootstrappingAnotherDeviceV2(requestJSON string) string { var request m_requests.InputConnectionStringForBootstrappingAnotherDevice err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } if err := request.Validate(); err != nil { return makeJSONResponse(err) } err = statusBackend.LocalPairingStateManager.StartPairing(request.ConnectionString) defer func() { statusBackend.LocalPairingStateManager.StopPairing(request.ConnectionString, err) }() if err != nil { return makeJSONResponse(err) } err = pairing.StartUpSendingClient(statusBackend, request.ConnectionString, request.SenderClientConfig) return makeJSONResponse(err) } func GetConnectionStringForExportingKeypairsKeystores(configJSON string) string { return callWithResponse(getConnectionStringForExportingKeypairsKeystores, configJSON) } // getConnectionStringForExportingKeypairsKeystores starts a pairing.SenderServer // then generates a pairing.ConnectionParams. Used when the device is Logged in and therefore has Account keys // and the device might not have a camera, to transfer kestore files of provided key uids. func getConnectionStringForExportingKeypairsKeystores(configJSON string) string { if configJSON == "" { return makeJSONResponse(fmt.Errorf("no config given, SendingServerConfig is expected")) } cs, err := pairing.StartUpKeystoreFilesSenderServer(statusBackend, configJSON) if err != nil { return makeJSONResponse(err) } return cs } // Deprecated: Use InputConnectionStringForImportingKeypairsKeystoresV2 instead. func InputConnectionStringForImportingKeypairsKeystores(cs, configJSON string) string { return callWithResponse(inputConnectionStringForImportingKeypairsKeystores, cs, configJSON) } // inputConnectionStringForImportingKeypairsKeystores starts a pairing.ReceiverClient // The given server.ConnectionParams string will determine the server.Mode // Used when the device is Logged in and has Account keys and has a camera to read a QR code // // Example: A mobile device (device with a camera) receiving account data from // a device with a screen (mobile or desktop devices) func inputConnectionStringForImportingKeypairsKeystores(cs, configJSON string) string { if configJSON == "" { return makeJSONResponse(fmt.Errorf("no config given, ReceiverClientConfig is expected")) } var conf pairing.KeystoreFilesReceiverClientConfig err := json.Unmarshal([]byte(configJSON), &conf) if err != nil { return makeJSONResponse(err) } err = pairing.StartUpKeystoreFilesReceivingClient(statusBackend, cs, &conf) return makeJSONResponse(err) } func InputConnectionStringForImportingKeypairsKeystoresV2(requestJSON string) string { return callWithResponse(inputConnectionStringForImportingKeypairsKeystoresV2, requestJSON) } func inputConnectionStringForImportingKeypairsKeystoresV2(requestJSON string) string { var request m_requests.InputConnectionStringForImportingKeypairsKeystores err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } if err := request.Validate(); err != nil { return makeJSONResponse(err) } err = pairing.StartUpKeystoreFilesReceivingClient(statusBackend, request.ConnectionString, request.KeystoreFilesReceiverClientConfig) return makeJSONResponse(err) } func ValidateConnectionString(cs string) string { return callWithResponse(validateConnectionString, cs) } func validateConnectionString(cs string) string { err := pairing.ValidateConnectionString(cs) if err == nil { return "" } return err.Error() } // Deprecated: Use EncodeTransferV2 instead. func EncodeTransfer(to string, value string) string { return callWithResponse(encodeTransfer, to, value) } func encodeTransfer(to string, value string) string { result, err := abi_spec.EncodeTransfer(to, value) if err != nil { logutils.ZapLogger().Error("failed to encode transfer", zap.String("to", to), zap.String("value", value), zap.Error(err)) return "" } return result } func EncodeTransferV2(requestJSON string) string { return callWithResponse(encodeTransferV2, requestJSON) } func encodeTransferV2(requestJSON string) string { var request requests.EncodeTransfer err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } return encodeTransfer(request.To, request.Value) } // Deprecated: Use EncodeFunctionCallV2 instead. func EncodeFunctionCall(method string, paramsJSON string) string { return callWithResponse(encodeFunctionCall, method, paramsJSON) } func encodeFunctionCall(method string, paramsJSON string) string { result, err := abi_spec.Encode(method, paramsJSON) if err != nil { logutils.ZapLogger().Error("failed to encode function call", zap.String("method", method), zap.String("paramsJSON", paramsJSON), zap.Error(err)) return "" } return result } func EncodeFunctionCallV2(requestJSON string) string { return callWithResponse(encodeFunctionCallV2, requestJSON) } func encodeFunctionCallV2(requestJSON string) string { var request requests.EncodeFunctionCall err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } return encodeFunctionCall(request.Method, request.ParamsJSON) } func DecodeParameters(decodeParamJSON string) string { return decodeParameters(decodeParamJSON) } func decodeParameters(decodeParamJSON string) string { decodeParam := struct { BytesString string `json:"bytesString"` Types []string `json:"types"` }{} err := json.Unmarshal([]byte(decodeParamJSON), &decodeParam) if err != nil { logutils.ZapLogger().Error("failed to unmarshal json when decoding parameters", zap.String("decodeParamJSON", decodeParamJSON), zap.Error(err)) return "" } result, err := abi_spec.Decode(decodeParam.BytesString, decodeParam.Types) if err != nil { logutils.ZapLogger().Error("failed to decode parameters", zap.String("decodeParamJSON", decodeParamJSON), zap.Error(err)) return "" } bytes, err := json.Marshal(result) if err != nil { logutils.ZapLogger().Error("failed to marshal result", zap.Any("result", result), zap.String("decodeParamJSON", decodeParamJSON), zap.Error(err)) return "" } return string(bytes) } func HexToNumber(hex string) string { return callWithResponse(hexToNumber, hex) } func hexToNumber(hex string) string { return abi_spec.HexToNumber(hex) } func NumberToHex(numString string) string { return callWithResponse(numberToHex, numString) } func numberToHex(numString string) string { return abi_spec.NumberToHex(numString) } func Sha3(str string) string { return "0x" + abi_spec.Sha3(str) } func Utf8ToHex(str string) string { return callWithResponse(utf8ToHex, str) } func utf8ToHex(str string) string { hexString, err := abi_spec.Utf8ToHex(str) if err != nil { logutils.ZapLogger().Error("failed to convert utf8 to hex", zap.String("str", str), zap.Error(err)) } return hexString } func HexToUtf8(hexString string) string { return callWithResponse(hexToUtf8, hexString) } func hexToUtf8(hexString string) string { str, err := abi_spec.HexToUtf8(hexString) if err != nil { logutils.ZapLogger().Error("failed to convert hex to utf8", zap.String("hexString", hexString), zap.Error(err)) } return str } func CheckAddressChecksum(address string) string { return callWithResponse(checkAddressChecksum, address) } func checkAddressChecksum(address string) string { valid, err := abi_spec.CheckAddressChecksum(address) if err != nil { logutils.ZapLogger().Error("failed to invoke check address checksum", zap.String("address", address), zap.Error(err)) } result, _ := json.Marshal(valid) return string(result) } func IsAddress(address string) string { return callWithResponse(isAddress, address) } func isAddress(address string) string { valid, err := abi_spec.IsAddress(address) if err != nil { logutils.ZapLogger().Error("failed to invoke IsAddress", zap.String("address", address), zap.Error(err)) } result, _ := json.Marshal(valid) return string(result) } func ToChecksumAddress(address string) string { return callWithResponse(toChecksumAddress, address) } func toChecksumAddress(address string) string { address, err := abi_spec.ToChecksumAddress(address) if err != nil { logutils.ZapLogger().Error("failed to convert to checksum address", zap.String("address", address), zap.Error(err)) } return address } func DeserializeAndCompressKey(DesktopKey string) string { return callWithResponse(deserializeAndCompressKey, DesktopKey) } func deserializeAndCompressKey(DesktopKey string) string { deserialisedKey := MultiformatDeserializePublicKey(DesktopKey, "f") sanitisedKey := "0x" + deserialisedKey[5:] return CompressPublicKey(sanitisedKey) } type InitLoggingRequest struct { logutils.LogSettings LogRequestGo bool `json:"LogRequestGo"` LogRequestFile string `json:"LogRequestFile"` } // InitLogging The InitLogging function should be called when the application starts. // This ensures that we can capture logs before the user login. Subsequent calls will update the logger settings. // Before this, we can only capture logs after user login since we will only configure the logging after the login process. func InitLogging(logSettingsJSON string) string { var logSettings InitLoggingRequest var err error if err = json.Unmarshal([]byte(logSettingsJSON), &logSettings); err != nil { return makeJSONResponse(err) } if err = logutils.OverrideRootLoggerWithConfig(logSettings.LogSettings); err == nil { logutils.ZapLogger().Info("logging initialised", zap.String("logSettings", logSettingsJSON)) } if logSettings.LogRequestGo { err = requestlog.ConfigureAndEnableRequestLogging(logSettings.LogRequestFile) if err != nil { return makeJSONResponse(err) } } return makeJSONResponse(err) } func GetRandomMnemonic() string { mnemonic, err := account.GetRandomMnemonic() if err != nil { return makeJSONResponse(err) } return mnemonic } func ToggleCentralizedMetrics(requestJSON string) string { return callWithResponse(toggleCentralizedMetrics, requestJSON) } func toggleCentralizedMetrics(requestJSON string) string { var request requests.ToggleCentralizedMetrics err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } err = request.Validate() if err != nil { return makeJSONResponse(err) } err = statusBackend.ToggleCentralizedMetrics(request.Enabled) if err != nil { return makeJSONResponse(err) } return makeJSONResponse(nil) } func CentralizedMetricsInfo() string { return callWithResponse(centralizedMetricsInfo) } func centralizedMetricsInfo() string { metricsInfo, err := statusBackend.CentralizedMetricsInfo() if err != nil { return makeJSONResponse(err) } data, err := json.Marshal(metricsInfo) if err != nil { return makeJSONResponse(err) } return string(data) } func AddCentralizedMetric(requestJSON string) string { return callWithResponse(addCentralizedMetric, requestJSON) } func addCentralizedMetric(requestJSON string) string { var request requests.AddCentralizedMetric err := json.Unmarshal([]byte(requestJSON), &request) if err != nil { return makeJSONResponse(err) } err = request.Validate() if err != nil { return makeJSONResponse(err) } metric := request.Metric metric.EnsureID() err = statusBackend.AddCentralizedMetric(*metric) if err != nil { return makeJSONResponse(err) } return metric.ID }