github.com/status-im/status-go@v1.1.0/mobile/status.go (about)

     1  package statusgo
     2  
     3  import (
     4  	"encoding/hex"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"unsafe"
     9  
    10  	validator "gopkg.in/go-playground/validator.v9"
    11  
    12  	"github.com/ethereum/go-ethereum/log"
    13  	"github.com/ethereum/go-ethereum/signer/core/apitypes"
    14  
    15  	"github.com/status-im/zxcvbn-go"
    16  	"github.com/status-im/zxcvbn-go/scoring"
    17  
    18  	abi_spec "github.com/status-im/status-go/abi-spec"
    19  	"github.com/status-im/status-go/account"
    20  	"github.com/status-im/status-go/api"
    21  	"github.com/status-im/status-go/api/multiformat"
    22  	"github.com/status-im/status-go/centralizedmetrics"
    23  	"github.com/status-im/status-go/centralizedmetrics/providers"
    24  	"github.com/status-im/status-go/eth-node/crypto"
    25  	"github.com/status-im/status-go/eth-node/types"
    26  	"github.com/status-im/status-go/exportlogs"
    27  	"github.com/status-im/status-go/extkeys"
    28  	"github.com/status-im/status-go/images"
    29  	"github.com/status-im/status-go/logutils"
    30  	"github.com/status-im/status-go/logutils/requestlog"
    31  	"github.com/status-im/status-go/multiaccounts"
    32  	"github.com/status-im/status-go/multiaccounts/accounts"
    33  	"github.com/status-im/status-go/multiaccounts/settings"
    34  	"github.com/status-im/status-go/params"
    35  	"github.com/status-im/status-go/profiling"
    36  	"github.com/status-im/status-go/protocol"
    37  	"github.com/status-im/status-go/protocol/common"
    38  	identityUtils "github.com/status-im/status-go/protocol/identity"
    39  	"github.com/status-im/status-go/protocol/identity/alias"
    40  	"github.com/status-im/status-go/protocol/identity/colorhash"
    41  	"github.com/status-im/status-go/protocol/identity/emojihash"
    42  	"github.com/status-im/status-go/protocol/requests"
    43  	"github.com/status-im/status-go/server"
    44  	"github.com/status-im/status-go/server/pairing"
    45  	"github.com/status-im/status-go/server/pairing/preflight"
    46  	"github.com/status-im/status-go/services/personal"
    47  	"github.com/status-im/status-go/services/typeddata"
    48  	"github.com/status-im/status-go/signal"
    49  	"github.com/status-im/status-go/transactions"
    50  )
    51  
    52  type InitializeApplicationResponse struct {
    53  	Accounts               []multiaccounts.Account         `json:"accounts"`
    54  	CentralizedMetricsInfo *centralizedmetrics.MetricsInfo `json:"centralizedMetricsInfo"`
    55  }
    56  
    57  func InitializeApplication(requestJSON string) string {
    58  	return logAndCallString(initializeApplication, requestJSON)
    59  }
    60  
    61  func initializeApplication(requestJSON string) string {
    62  	var request requests.InitializeApplication
    63  	err := json.Unmarshal([]byte(requestJSON), &request)
    64  	if err != nil {
    65  		return makeJSONResponse(err)
    66  	}
    67  	err = request.Validate()
    68  	if err != nil {
    69  		return makeJSONResponse(err)
    70  	}
    71  
    72  	// initialize metrics
    73  	providers.MixpanelAppID = request.MixpanelAppID
    74  	providers.MixpanelToken = request.MixpanelToken
    75  
    76  	datadir := request.DataDir
    77  
    78  	statusBackend.UpdateRootDataDir(datadir)
    79  	err = statusBackend.OpenAccounts()
    80  	if err != nil {
    81  		return makeJSONResponse(err)
    82  	}
    83  	accs, err := statusBackend.GetAccounts()
    84  	if err != nil {
    85  		return makeJSONResponse(err)
    86  	}
    87  	centralizedMetricsInfo, err := statusBackend.CentralizedMetricsInfo()
    88  	if err != nil {
    89  		return makeJSONResponse(err)
    90  	}
    91  	response := &InitializeApplicationResponse{
    92  		Accounts:               accs,
    93  		CentralizedMetricsInfo: centralizedMetricsInfo,
    94  	}
    95  	data, err := json.Marshal(response)
    96  	if err != nil {
    97  		return makeJSONResponse(err)
    98  	}
    99  	return string(data)
   100  }
   101  
   102  func OpenAccounts(datadir string) string {
   103  	return logAndCallString(openAccounts, datadir)
   104  }
   105  
   106  // DEPRECATED: use InitializeApplication
   107  // openAccounts opens database and returns accounts list.
   108  func openAccounts(datadir string) string {
   109  	statusBackend.UpdateRootDataDir(datadir)
   110  	err := statusBackend.OpenAccounts()
   111  	if err != nil {
   112  		return makeJSONResponse(err)
   113  	}
   114  	accs, err := statusBackend.GetAccounts()
   115  	if err != nil {
   116  		return makeJSONResponse(err)
   117  	}
   118  	data, err := json.Marshal(accs)
   119  	if err != nil {
   120  		return makeJSONResponse(err)
   121  	}
   122  	return string(data)
   123  }
   124  
   125  func ExtractGroupMembershipSignatures(signaturePairsStr string) string {
   126  	return logAndCallString(extractGroupMembershipSignatures, signaturePairsStr)
   127  }
   128  
   129  // ExtractGroupMembershipSignatures extract public keys from tuples of content/signature.
   130  func extractGroupMembershipSignatures(signaturePairsStr string) string {
   131  	var signaturePairs [][2]string
   132  
   133  	if err := json.Unmarshal([]byte(signaturePairsStr), &signaturePairs); err != nil {
   134  		return makeJSONResponse(err)
   135  	}
   136  
   137  	identities, err := statusBackend.ExtractGroupMembershipSignatures(signaturePairs)
   138  	if err != nil {
   139  		return makeJSONResponse(err)
   140  	}
   141  
   142  	data, err := json.Marshal(struct {
   143  		Identities []string `json:"identities"`
   144  	}{Identities: identities})
   145  	if err != nil {
   146  		return makeJSONResponse(err)
   147  	}
   148  
   149  	return string(data)
   150  }
   151  
   152  func SignGroupMembership(content string) string {
   153  	return logAndCallString(signGroupMembership, content)
   154  }
   155  
   156  // signGroupMembership signs a string containing group membership information.
   157  func signGroupMembership(content string) string {
   158  	signature, err := statusBackend.SignGroupMembership(content)
   159  	if err != nil {
   160  		return makeJSONResponse(err)
   161  	}
   162  
   163  	data, err := json.Marshal(struct {
   164  		Signature string `json:"signature"`
   165  	}{Signature: signature})
   166  	if err != nil {
   167  		return makeJSONResponse(err)
   168  	}
   169  
   170  	return string(data)
   171  }
   172  
   173  func GetNodeConfig() string {
   174  	return logAndCallString(getNodeConfig)
   175  }
   176  
   177  // getNodeConfig returns the current config of the Status node
   178  func getNodeConfig() string {
   179  	conf, err := statusBackend.GetNodeConfig()
   180  	if err != nil {
   181  		return makeJSONResponse(err)
   182  	}
   183  
   184  	respJSON, err := json.Marshal(conf)
   185  	if err != nil {
   186  		return makeJSONResponse(err)
   187  	}
   188  
   189  	return string(respJSON)
   190  }
   191  
   192  func ValidateNodeConfig(configJSON string) string {
   193  	return logAndCallString(validateNodeConfig, configJSON)
   194  }
   195  
   196  // validateNodeConfig validates config for the Status node.
   197  func validateNodeConfig(configJSON string) string {
   198  	var resp APIDetailedResponse
   199  
   200  	_, err := params.NewConfigFromJSON(configJSON)
   201  
   202  	// Convert errors to APIDetailedResponse
   203  	switch err := err.(type) {
   204  	case validator.ValidationErrors:
   205  		resp = APIDetailedResponse{
   206  			Message:     "validation: validation failed",
   207  			FieldErrors: make([]APIFieldError, len(err)),
   208  		}
   209  
   210  		for i, ve := range err {
   211  			resp.FieldErrors[i] = APIFieldError{
   212  				Parameter: ve.Namespace(),
   213  				Errors: []APIError{
   214  					{
   215  						Message: fmt.Sprintf("field validation failed on the '%s' tag", ve.Tag()),
   216  					},
   217  				},
   218  			}
   219  		}
   220  	case error:
   221  		resp = APIDetailedResponse{
   222  			Message: fmt.Sprintf("validation: %s", err.Error()),
   223  		}
   224  	case nil:
   225  		resp = APIDetailedResponse{
   226  			Status: true,
   227  		}
   228  	}
   229  
   230  	respJSON, err := json.Marshal(resp)
   231  	if err != nil {
   232  		return makeJSONResponse(err)
   233  	}
   234  
   235  	return string(respJSON)
   236  }
   237  
   238  func ResetChainData() string {
   239  	return logAndCallString(resetChainData)
   240  }
   241  
   242  // resetChainData removes chain data from data directory.
   243  func resetChainData() string {
   244  	api.RunAsync(statusBackend.ResetChainData)
   245  	return makeJSONResponse(nil)
   246  }
   247  
   248  func CallRPC(inputJSON string) string {
   249  	return logAndCallString(callRPC, inputJSON)
   250  }
   251  
   252  // callRPC calls public APIs via RPC.
   253  func callRPC(inputJSON string) string {
   254  	resp, err := statusBackend.CallRPC(inputJSON)
   255  	if err != nil {
   256  		return makeJSONResponse(err)
   257  	}
   258  	return resp
   259  }
   260  
   261  func CallPrivateRPC(inputJSON string) string {
   262  	return logAndCallString(callPrivateRPC, inputJSON)
   263  }
   264  
   265  // callPrivateRPC calls both public and private APIs via RPC.
   266  func callPrivateRPC(inputJSON string) string {
   267  	resp, err := statusBackend.CallPrivateRPC(inputJSON)
   268  	if err != nil {
   269  		return makeJSONResponse(err)
   270  	}
   271  	return resp
   272  }
   273  
   274  func VerifyAccountPassword(keyStoreDir, address, password string) string {
   275  	return logAndCallString(verifyAccountPassword, keyStoreDir, address, password)
   276  }
   277  
   278  // verifyAccountPassword verifies account password.
   279  func verifyAccountPassword(keyStoreDir, address, password string) string {
   280  	_, err := statusBackend.AccountManager().VerifyAccountPassword(keyStoreDir, address, password)
   281  	return makeJSONResponse(err)
   282  }
   283  
   284  func VerifyDatabasePassword(keyUID, password string) string {
   285  	return logAndCallString(verifyDatabasePassword, keyUID, password)
   286  }
   287  
   288  // verifyDatabasePassword verifies database password.
   289  func verifyDatabasePassword(keyUID, password string) string {
   290  	err := statusBackend.VerifyDatabasePassword(keyUID, password)
   291  	return makeJSONResponse(err)
   292  }
   293  
   294  func MigrateKeyStoreDir(accountData, password, oldDir, newDir string) string {
   295  	return logAndCallString(migrateKeyStoreDir, accountData, password, oldDir, newDir)
   296  }
   297  
   298  // migrateKeyStoreDir migrates key files to a new directory
   299  func migrateKeyStoreDir(accountData, password, oldDir, newDir string) string {
   300  	var account multiaccounts.Account
   301  	err := json.Unmarshal([]byte(accountData), &account)
   302  	if err != nil {
   303  		return makeJSONResponse(err)
   304  	}
   305  
   306  	err = statusBackend.MigrateKeyStoreDir(account, password, oldDir, newDir)
   307  	return makeJSONResponse(err)
   308  }
   309  
   310  // login deprecated as Login and LoginWithConfig are deprecated
   311  func login(accountData, password, configJSON string) error {
   312  	var account multiaccounts.Account
   313  	err := json.Unmarshal([]byte(accountData), &account)
   314  	if err != nil {
   315  		return err
   316  	}
   317  
   318  	var conf params.NodeConfig
   319  	if configJSON != "" {
   320  		err = json.Unmarshal([]byte(configJSON), &conf)
   321  		if err != nil {
   322  			return err
   323  		}
   324  	}
   325  
   326  	api.RunAsync(func() error {
   327  		log.Debug("start a node with account", "key-uid", account.KeyUID)
   328  		err := statusBackend.UpdateNodeConfigFleet(account, password, &conf)
   329  		if err != nil {
   330  			log.Error("failed to update node config fleet", "key-uid", account.KeyUID, "error", err)
   331  			return statusBackend.LoggedIn(account.KeyUID, err)
   332  		}
   333  
   334  		err = statusBackend.StartNodeWithAccount(account, password, &conf, nil)
   335  		if err != nil {
   336  			log.Error("failed to start a node", "key-uid", account.KeyUID, "error", err)
   337  			return err
   338  		}
   339  		log.Debug("started a node with", "key-uid", account.KeyUID)
   340  		return nil
   341  	})
   342  
   343  	return nil
   344  }
   345  
   346  // Login loads a key file (for a given address), tries to decrypt it using the password,
   347  // to verify ownership if verified, purges all the previous identities from Whisper,
   348  // and injects verified key as shh identity.
   349  //
   350  // Deprecated: Use LoginAccount instead.
   351  func Login(accountData, password string) string {
   352  	err := login(accountData, password, "")
   353  	if err != nil {
   354  		return makeJSONResponse(err)
   355  	}
   356  	return makeJSONResponse(nil)
   357  }
   358  
   359  // LoginWithConfig loads a key file (for a given address), tries to decrypt it using the password,
   360  // to verify ownership if verified, purges all the previous identities from Whisper,
   361  // and injects verified key as shh identity. It then updates the accounts node db configuration
   362  // mergin the values received in the configJSON parameter
   363  //
   364  // Deprecated: Use LoginAccount instead.
   365  func LoginWithConfig(accountData, password, configJSON string) string {
   366  	err := login(accountData, password, configJSON)
   367  	if err != nil {
   368  		return makeJSONResponse(err)
   369  	}
   370  	return makeJSONResponse(nil)
   371  }
   372  
   373  func CreateAccountAndLogin(requestJSON string) string {
   374  	return logAndCallString(createAccountAndLogin, requestJSON)
   375  }
   376  
   377  func createAccountAndLogin(requestJSON string) string {
   378  	var request requests.CreateAccount
   379  	err := json.Unmarshal([]byte(requestJSON), &request)
   380  	if err != nil {
   381  		return makeJSONResponse(err)
   382  	}
   383  
   384  	err = request.Validate(&requests.CreateAccountValidation{
   385  		AllowEmptyDisplayName: false,
   386  	})
   387  	if err != nil {
   388  		return makeJSONResponse(err)
   389  	}
   390  
   391  	api.RunAsync(func() error {
   392  		log.Debug("starting a node and creating config")
   393  		_, err := statusBackend.CreateAccountAndLogin(&request)
   394  		if err != nil {
   395  			log.Error("failed to create account", "error", err)
   396  			return err
   397  		}
   398  		log.Debug("started a node, and created account")
   399  		return nil
   400  	})
   401  	return makeJSONResponse(nil)
   402  }
   403  
   404  func LoginAccount(requestJSON string) string {
   405  	return logAndCallString(loginAccount, requestJSON)
   406  }
   407  
   408  func loginAccount(requestJSON string) string {
   409  	var request requests.Login
   410  	err := json.Unmarshal([]byte(requestJSON), &request)
   411  	if err != nil {
   412  		return makeJSONResponse(err)
   413  	}
   414  
   415  	err = request.Validate()
   416  	if err != nil {
   417  		return makeJSONResponse(err)
   418  	}
   419  
   420  	api.RunAsync(func() error {
   421  		err := statusBackend.LoginAccount(&request)
   422  		if err != nil {
   423  			log.Error("loginAccount failed", "error", err)
   424  			return err
   425  		}
   426  		log.Debug("loginAccount started node")
   427  		return nil
   428  	})
   429  	return makeJSONResponse(nil)
   430  }
   431  
   432  func RestoreAccountAndLogin(requestJSON string) string {
   433  	return logAndCallString(restoreAccountAndLogin, requestJSON)
   434  }
   435  
   436  func restoreAccountAndLogin(requestJSON string) string {
   437  	var request requests.RestoreAccount
   438  	err := json.Unmarshal([]byte(requestJSON), &request)
   439  	if err != nil {
   440  		return makeJSONResponse(err)
   441  	}
   442  
   443  	err = request.Validate()
   444  	if err != nil {
   445  		return makeJSONResponse(err)
   446  	}
   447  
   448  	api.RunAsync(func() error {
   449  		log.Debug("starting a node and restoring account")
   450  
   451  		if request.Keycard != nil {
   452  			_, err = statusBackend.RestoreKeycardAccountAndLogin(&request)
   453  		} else {
   454  			_, err = statusBackend.RestoreAccountAndLogin(&request)
   455  		}
   456  
   457  		if err != nil {
   458  			log.Error("failed to restore account", "error", err)
   459  			return err
   460  		}
   461  		log.Debug("started a node, and restored account")
   462  		return nil
   463  	})
   464  
   465  	return makeJSONResponse(nil)
   466  }
   467  
   468  // SaveAccountAndLogin saves account in status-go database.
   469  // Deprecated: Use CreateAccountAndLogin instead.
   470  func SaveAccountAndLogin(accountData, password, settingsJSON, configJSON, subaccountData string) string {
   471  	var account multiaccounts.Account
   472  	err := json.Unmarshal([]byte(accountData), &account)
   473  	if err != nil {
   474  		return makeJSONResponse(err)
   475  	}
   476  	var settings settings.Settings
   477  	err = json.Unmarshal([]byte(settingsJSON), &settings)
   478  	if err != nil {
   479  		return makeJSONResponse(err)
   480  	}
   481  
   482  	if *settings.Mnemonic != "" {
   483  		settings.MnemonicWasNotShown = true
   484  	}
   485  
   486  	var conf params.NodeConfig
   487  	err = json.Unmarshal([]byte(configJSON), &conf)
   488  	if err != nil {
   489  		return makeJSONResponse(err)
   490  	}
   491  	var subaccs []*accounts.Account
   492  	err = json.Unmarshal([]byte(subaccountData), &subaccs)
   493  	if err != nil {
   494  		return makeJSONResponse(err)
   495  	}
   496  
   497  	api.RunAsync(func() error {
   498  		log.Debug("starting a node, and saving account with configuration", "key-uid", account.KeyUID)
   499  		err := statusBackend.StartNodeWithAccountAndInitialConfig(account, password, settings, &conf, subaccs, nil)
   500  		if err != nil {
   501  			log.Error("failed to start node and save account", "key-uid", account.KeyUID, "error", err)
   502  			return err
   503  		}
   504  		log.Debug("started a node, and saved account", "key-uid", account.KeyUID)
   505  		return nil
   506  	})
   507  	return makeJSONResponse(nil)
   508  }
   509  
   510  func DeleteMultiaccount(keyUID, keyStoreDir string) string {
   511  	return logAndCallString(deleteMultiaccount, keyUID, keyStoreDir)
   512  }
   513  
   514  // deleteMultiaccount
   515  func deleteMultiaccount(keyUID, keyStoreDir string) string {
   516  	err := statusBackend.DeleteMultiaccount(keyUID, keyStoreDir)
   517  	return makeJSONResponse(err)
   518  }
   519  
   520  func DeleteImportedKey(address, password, keyStoreDir string) string {
   521  	return logAndCallString(deleteImportedKey, address, password, keyStoreDir)
   522  }
   523  
   524  // deleteImportedKey
   525  func deleteImportedKey(address, password, keyStoreDir string) string {
   526  	err := statusBackend.DeleteImportedKey(address, password, keyStoreDir)
   527  	return makeJSONResponse(err)
   528  }
   529  
   530  func InitKeystore(keydir string) string {
   531  	return logAndCallString(initKeystore, keydir)
   532  }
   533  
   534  // initKeystore initialize keystore before doing any operations with keys.
   535  func initKeystore(keydir string) string {
   536  	err := statusBackend.AccountManager().InitKeystore(keydir)
   537  	return makeJSONResponse(err)
   538  }
   539  
   540  // SaveAccountAndLoginWithKeycard saves account in status-go database.
   541  // Deprecated: Use CreateAndAccountAndLogin with required keycard properties.
   542  func SaveAccountAndLoginWithKeycard(accountData, password, settingsJSON, configJSON, subaccountData string, keyHex string) string {
   543  	var account multiaccounts.Account
   544  	err := json.Unmarshal([]byte(accountData), &account)
   545  	if err != nil {
   546  		return makeJSONResponse(err)
   547  	}
   548  	var settings settings.Settings
   549  	err = json.Unmarshal([]byte(settingsJSON), &settings)
   550  	if err != nil {
   551  		return makeJSONResponse(err)
   552  	}
   553  	var conf params.NodeConfig
   554  	err = json.Unmarshal([]byte(configJSON), &conf)
   555  	if err != nil {
   556  		return makeJSONResponse(err)
   557  	}
   558  	var subaccs []*accounts.Account
   559  	err = json.Unmarshal([]byte(subaccountData), &subaccs)
   560  	if err != nil {
   561  		return makeJSONResponse(err)
   562  	}
   563  
   564  	api.RunAsync(func() error {
   565  		log.Debug("starting a node, and saving account with configuration", "key-uid", account.KeyUID)
   566  		err := statusBackend.SaveAccountAndStartNodeWithKey(account, password, settings, &conf, subaccs, keyHex)
   567  		if err != nil {
   568  			log.Error("failed to start node and save account", "key-uid", account.KeyUID, "error", err)
   569  			return err
   570  		}
   571  		log.Debug("started a node, and saved account", "key-uid", account.KeyUID)
   572  		return nil
   573  	})
   574  	return makeJSONResponse(nil)
   575  }
   576  
   577  // LoginWithKeycard initializes an account with a chat key and encryption key used for PFS.
   578  // It purges all the previous identities from Whisper, and injects the key as shh identity.
   579  // Deprecated: Use LoginAccount instead.
   580  func LoginWithKeycard(accountData, password, keyHex string, configJSON string) string {
   581  	var account multiaccounts.Account
   582  	err := json.Unmarshal([]byte(accountData), &account)
   583  	if err != nil {
   584  		return makeJSONResponse(err)
   585  	}
   586  	var conf params.NodeConfig
   587  	err = json.Unmarshal([]byte(configJSON), &conf)
   588  	if err != nil {
   589  		return makeJSONResponse(err)
   590  	}
   591  	api.RunAsync(func() error {
   592  		log.Debug("start a node with account", "key-uid", account.KeyUID)
   593  		err := statusBackend.StartNodeWithKey(account, password, keyHex, &conf)
   594  		if err != nil {
   595  			log.Error("failed to start a node", "key-uid", account.KeyUID, "error", err)
   596  			return err
   597  		}
   598  		log.Debug("started a node with", "key-uid", account.KeyUID)
   599  		return nil
   600  	})
   601  	return makeJSONResponse(nil)
   602  }
   603  
   604  func Logout() string {
   605  	return logAndCallString(logout)
   606  }
   607  
   608  // logout is equivalent to clearing whisper identities.
   609  func logout() string {
   610  	return makeJSONResponse(statusBackend.Logout())
   611  }
   612  
   613  func SignMessage(rpcParams string) string {
   614  	return logAndCallString(signMessage, rpcParams)
   615  }
   616  
   617  // signMessage unmarshals rpc params {data, address, password} and
   618  // passes them onto backend.SignMessage.
   619  func signMessage(rpcParams string) string {
   620  	var params personal.SignParams
   621  	err := json.Unmarshal([]byte(rpcParams), &params)
   622  	if err != nil {
   623  		return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
   624  	}
   625  	result, err := statusBackend.SignMessage(params)
   626  	return prepareJSONResponse(result.String(), err)
   627  }
   628  
   629  // SignTypedData unmarshall data into TypedData, validate it and signs with selected account,
   630  // if password matches selected account.
   631  //
   632  //export SignTypedData
   633  func SignTypedData(data, address, password string) string {
   634  	return logAndCallString(signTypedData, data, address, password)
   635  }
   636  
   637  func signTypedData(data, address, password string) string {
   638  	var typed typeddata.TypedData
   639  	err := json.Unmarshal([]byte(data), &typed)
   640  	if err != nil {
   641  		return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
   642  	}
   643  	if err := typed.Validate(); err != nil {
   644  		return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
   645  	}
   646  	result, err := statusBackend.SignTypedData(typed, address, password)
   647  	return prepareJSONResponse(result.String(), err)
   648  }
   649  
   650  // HashTypedData unmarshalls data into TypedData, validates it and hashes it.
   651  //
   652  //export HashTypedData
   653  func HashTypedData(data string) string {
   654  	return logAndCallString(hashTypedData, data)
   655  }
   656  
   657  func hashTypedData(data string) string {
   658  	var typed typeddata.TypedData
   659  	err := json.Unmarshal([]byte(data), &typed)
   660  	if err != nil {
   661  		return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
   662  	}
   663  	if err := typed.Validate(); err != nil {
   664  		return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
   665  	}
   666  	result, err := statusBackend.HashTypedData(typed)
   667  	return prepareJSONResponse(result.String(), err)
   668  }
   669  
   670  // SignTypedDataV4 unmarshall data into TypedData, validate it and signs with selected account,
   671  // if password matches selected account.
   672  //
   673  //export SignTypedDataV4
   674  func SignTypedDataV4(data, address, password string) string {
   675  	return logAndCallString(signTypedDataV4, data, address, password)
   676  }
   677  
   678  func signTypedDataV4(data, address, password string) string {
   679  	var typed apitypes.TypedData
   680  	err := json.Unmarshal([]byte(data), &typed)
   681  	if err != nil {
   682  		return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
   683  	}
   684  	result, err := statusBackend.SignTypedDataV4(typed, address, password)
   685  	return prepareJSONResponse(result.String(), err)
   686  }
   687  
   688  // HashTypedDataV4 unmarshalls data into TypedData, validates it and hashes it.
   689  //
   690  //export HashTypedDataV4
   691  func HashTypedDataV4(data string) string {
   692  	return logAndCallString(hashTypedDataV4, data)
   693  }
   694  
   695  func hashTypedDataV4(data string) string {
   696  	var typed apitypes.TypedData
   697  	err := json.Unmarshal([]byte(data), &typed)
   698  	if err != nil {
   699  		return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
   700  	}
   701  	result, err := statusBackend.HashTypedDataV4(typed)
   702  	return prepareJSONResponse(result.String(), err)
   703  }
   704  
   705  func Recover(rpcParams string) string {
   706  	return logAndCallString(recoverWithRPCParams, rpcParams)
   707  }
   708  
   709  // recoverWithRPCParams unmarshals rpc params {signDataString, signedData} and passes
   710  // them onto backend.
   711  func recoverWithRPCParams(rpcParams string) string {
   712  	var params personal.RecoverParams
   713  	err := json.Unmarshal([]byte(rpcParams), &params)
   714  	if err != nil {
   715  		return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
   716  	}
   717  	addr, err := statusBackend.Recover(params)
   718  	return prepareJSONResponse(addr.String(), err)
   719  }
   720  
   721  func SendTransactionWithChainID(chainID int, txArgsJSON, password string) string {
   722  	return logAndCallString(sendTransactionWithChainID, chainID, txArgsJSON, password)
   723  }
   724  
   725  // sendTransactionWithChainID converts RPC args and calls backend.SendTransactionWithChainID.
   726  func sendTransactionWithChainID(chainID int, txArgsJSON, password string) string {
   727  	var params transactions.SendTxArgs
   728  	err := json.Unmarshal([]byte(txArgsJSON), &params)
   729  	if err != nil {
   730  		return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
   731  	}
   732  	hash, err := statusBackend.SendTransactionWithChainID(uint64(chainID), params, password)
   733  	code := codeUnknown
   734  	if c, ok := errToCodeMap[err]; ok {
   735  		code = c
   736  	}
   737  	return prepareJSONResponseWithCode(hash.String(), err, code)
   738  }
   739  
   740  func SendTransaction(txArgsJSON, password string) string {
   741  	return logAndCallString(sendTransaction, txArgsJSON, password)
   742  }
   743  
   744  // sendTransaction converts RPC args and calls backend.SendTransaction.
   745  func sendTransaction(txArgsJSON, password string) string {
   746  	var params transactions.SendTxArgs
   747  	err := json.Unmarshal([]byte(txArgsJSON), &params)
   748  	if err != nil {
   749  		return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
   750  	}
   751  	hash, err := statusBackend.SendTransaction(params, password)
   752  	code := codeUnknown
   753  	if c, ok := errToCodeMap[err]; ok {
   754  		code = c
   755  	}
   756  	return prepareJSONResponseWithCode(hash.String(), err, code)
   757  }
   758  
   759  func SendTransactionWithSignature(txArgsJSON, sigString string) string {
   760  	return logAndCallString(sendTransactionWithSignature, txArgsJSON, sigString)
   761  }
   762  
   763  // sendTransactionWithSignature converts RPC args and calls backend.SendTransactionWithSignature
   764  func sendTransactionWithSignature(txArgsJSON, sigString string) string {
   765  	var params transactions.SendTxArgs
   766  	err := json.Unmarshal([]byte(txArgsJSON), &params)
   767  	if err != nil {
   768  		return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
   769  	}
   770  
   771  	sig, err := hex.DecodeString(sigString)
   772  	if err != nil {
   773  		return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
   774  	}
   775  
   776  	hash, err := statusBackend.SendTransactionWithSignature(params, sig)
   777  	code := codeUnknown
   778  	if c, ok := errToCodeMap[err]; ok {
   779  		code = c
   780  	}
   781  	return prepareJSONResponseWithCode(hash.String(), err, code)
   782  }
   783  
   784  func HashTransaction(txArgsJSON string) string {
   785  	return logAndCallString(hashTransaction, txArgsJSON)
   786  }
   787  
   788  // hashTransaction validate the transaction and returns new txArgs and the transaction hash.
   789  func hashTransaction(txArgsJSON string) string {
   790  	var params transactions.SendTxArgs
   791  	err := json.Unmarshal([]byte(txArgsJSON), &params)
   792  	if err != nil {
   793  		return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
   794  	}
   795  
   796  	newTxArgs, hash, err := statusBackend.HashTransaction(params)
   797  	code := codeUnknown
   798  	if c, ok := errToCodeMap[err]; ok {
   799  		code = c
   800  	}
   801  
   802  	result := struct {
   803  		Transaction transactions.SendTxArgs `json:"transaction"`
   804  		Hash        types.Hash              `json:"hash"`
   805  	}{
   806  		Transaction: newTxArgs,
   807  		Hash:        hash,
   808  	}
   809  
   810  	return prepareJSONResponseWithCode(result, err, code)
   811  }
   812  
   813  func HashMessage(message string) string {
   814  	return logAndCallString(hashMessage, message)
   815  }
   816  
   817  // hashMessage calculates the hash of a message to be safely signed by the keycard
   818  // The hash is calulcated as
   819  //
   820  //	keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
   821  //
   822  // This gives context to the signed message and prevents signing of transactions.
   823  func hashMessage(message string) string {
   824  	hash, err := api.HashMessage(message)
   825  	code := codeUnknown
   826  	if c, ok := errToCodeMap[err]; ok {
   827  		code = c
   828  	}
   829  	return prepareJSONResponseWithCode(fmt.Sprintf("0x%x", hash), err, code)
   830  }
   831  
   832  func StartCPUProfile(dataDir string) string {
   833  	return logAndCallString(startCPUProfile, dataDir)
   834  }
   835  
   836  // startCPUProfile runs pprof for CPU.
   837  func startCPUProfile(dataDir string) string {
   838  	err := profiling.StartCPUProfile(dataDir)
   839  	return makeJSONResponse(err)
   840  }
   841  
   842  func StopCPUProfiling() string {
   843  	return logAndCallString(stopCPUProfiling)
   844  }
   845  
   846  // stopCPUProfiling stops pprof for cpu.
   847  func stopCPUProfiling() string { //nolint: deadcode
   848  	err := profiling.StopCPUProfile()
   849  	return makeJSONResponse(err)
   850  }
   851  
   852  func WriteHeapProfile(dataDir string) string {
   853  	return logAndCallString(writeHeapProfile, dataDir)
   854  }
   855  
   856  // writeHeapProfile starts pprof for heap
   857  func writeHeapProfile(dataDir string) string { //nolint: deadcode
   858  	err := profiling.WriteHeapFile(dataDir)
   859  	return makeJSONResponse(err)
   860  }
   861  
   862  func makeJSONResponse(err error) string {
   863  	errString := ""
   864  	if err != nil {
   865  		log.Error("error in makeJSONResponse", "error", err)
   866  		errString = err.Error()
   867  	}
   868  
   869  	out := APIResponse{
   870  		Error: errString,
   871  	}
   872  	outBytes, _ := json.Marshal(out)
   873  
   874  	return string(outBytes)
   875  }
   876  
   877  func AddPeer(enode string) string {
   878  	return logAndCallString(addPeer, enode)
   879  }
   880  
   881  // addPeer adds an enode as a peer.
   882  func addPeer(enode string) string {
   883  	err := statusBackend.StatusNode().AddPeer(enode)
   884  	return makeJSONResponse(err)
   885  }
   886  
   887  func ConnectionChange(typ string, expensive int) {
   888  	logAndCall(connectionChange, typ, expensive)
   889  }
   890  
   891  // connectionChange handles network state changes as reported
   892  // by ReactNative (see https://facebook.github.io/react-native/docs/netinfo.html)
   893  func connectionChange(typ string, expensive int) {
   894  	statusBackend.ConnectionChange(typ, expensive == 1)
   895  }
   896  
   897  func AppStateChange(state string) {
   898  	logAndCall(appStateChange, state)
   899  }
   900  
   901  // appStateChange handles app state changes (background/foreground).
   902  func appStateChange(state string) {
   903  	statusBackend.AppStateChange(state)
   904  }
   905  
   906  func StartLocalNotifications() string {
   907  	return logAndCallString(startLocalNotifications)
   908  }
   909  
   910  // startLocalNotifications
   911  func startLocalNotifications() string {
   912  	err := statusBackend.StartLocalNotifications()
   913  	return makeJSONResponse(err)
   914  }
   915  
   916  func StopLocalNotifications() string {
   917  	return logAndCallString(stopLocalNotifications)
   918  }
   919  
   920  // stopLocalNotifications
   921  func stopLocalNotifications() string {
   922  	err := statusBackend.StopLocalNotifications()
   923  	return makeJSONResponse(err)
   924  }
   925  
   926  func SetMobileSignalHandler(handler SignalHandler) {
   927  	logAndCall(setMobileSignalHandler, handler)
   928  }
   929  
   930  // setMobileSignalHandler setup geth callback to notify about new signal
   931  // used for gomobile builds
   932  func setMobileSignalHandler(handler SignalHandler) {
   933  	signal.SetMobileSignalHandler(func(data []byte) {
   934  		if len(data) > 0 {
   935  			handler.HandleSignal(string(data))
   936  		}
   937  	})
   938  }
   939  
   940  func SetSignalEventCallback(cb unsafe.Pointer) {
   941  	logAndCall(setSignalEventCallback, cb)
   942  }
   943  
   944  // setSignalEventCallback setup geth callback to notify about new signal
   945  func setSignalEventCallback(cb unsafe.Pointer) {
   946  	signal.SetSignalEventCallback(cb)
   947  }
   948  
   949  // ExportNodeLogs reads current node log and returns content to a caller.
   950  //
   951  //export ExportNodeLogs
   952  func ExportNodeLogs() string {
   953  	return logAndCallString(exportNodeLogs)
   954  }
   955  
   956  func exportNodeLogs() string {
   957  	node := statusBackend.StatusNode()
   958  	if node == nil {
   959  		return makeJSONResponse(errors.New("node is not running"))
   960  	}
   961  	config := node.Config()
   962  	if config == nil {
   963  		return makeJSONResponse(errors.New("config and log file are not available"))
   964  	}
   965  	data, err := json.Marshal(exportlogs.ExportFromBaseFile(config.LogFile))
   966  	if err != nil {
   967  		return makeJSONResponse(fmt.Errorf("error marshalling to json: %v", err))
   968  	}
   969  	return string(data)
   970  }
   971  
   972  func SignHash(hexEncodedHash string) string {
   973  	return logAndCallString(signHash, hexEncodedHash)
   974  }
   975  
   976  // signHash exposes vanilla ECDSA signing required for Swarm messages
   977  func signHash(hexEncodedHash string) string {
   978  	hexEncodedSignature, err := statusBackend.SignHash(hexEncodedHash)
   979  	if err != nil {
   980  		return makeJSONResponse(err)
   981  	}
   982  	return hexEncodedSignature
   983  }
   984  
   985  func GenerateAlias(pk string) string {
   986  	return logAndCallString(generateAlias, pk)
   987  }
   988  
   989  func generateAlias(pk string) string {
   990  	// We ignore any error, empty string is considered an error
   991  	name, _ := protocol.GenerateAlias(pk)
   992  	return name
   993  }
   994  
   995  func IsAlias(value string) string {
   996  	return logAndCallString(isAlias, value)
   997  }
   998  
   999  func isAlias(value string) string {
  1000  	return prepareJSONResponse(alias.IsAlias(value), nil)
  1001  }
  1002  
  1003  func Identicon(pk string) string {
  1004  	return logAndCallString(identicon, pk)
  1005  }
  1006  
  1007  func identicon(pk string) string {
  1008  	// We ignore any error, empty string is considered an error
  1009  	identicon, _ := protocol.Identicon(pk)
  1010  	return identicon
  1011  }
  1012  
  1013  func EmojiHash(pk string) string {
  1014  	return logAndCallString(emojiHash, pk)
  1015  }
  1016  
  1017  func emojiHash(pk string) string {
  1018  	return prepareJSONResponse(emojihash.GenerateFor(pk))
  1019  }
  1020  
  1021  func ColorHash(pk string) string {
  1022  	return logAndCallString(colorHash, pk)
  1023  }
  1024  
  1025  func colorHash(pk string) string {
  1026  	return prepareJSONResponse(colorhash.GenerateFor(pk))
  1027  }
  1028  
  1029  func ColorID(pk string) string {
  1030  	return logAndCallString(colorID, pk)
  1031  }
  1032  
  1033  func colorID(pk string) string {
  1034  	return prepareJSONResponse(identityUtils.ToColorID(pk))
  1035  }
  1036  
  1037  func ValidateMnemonic(mnemonic string) string {
  1038  	return logAndCallString(validateMnemonic, mnemonic)
  1039  }
  1040  
  1041  func validateMnemonic(mnemonic string) string {
  1042  	m := extkeys.NewMnemonic()
  1043  	err := m.ValidateMnemonic(mnemonic, extkeys.Language(0))
  1044  	if err != nil {
  1045  		return makeJSONResponse(err)
  1046  	}
  1047  
  1048  	keyUID, err := statusBackend.GetKeyUIDByMnemonic(mnemonic)
  1049  	if err != nil {
  1050  		return makeJSONResponse(err)
  1051  	}
  1052  
  1053  	response := &APIKeyUIDResponse{KeyUID: keyUID}
  1054  	data, err := json.Marshal(response)
  1055  	if err != nil {
  1056  		return makeJSONResponse(err)
  1057  	}
  1058  	return string(data)
  1059  }
  1060  
  1061  func DecompressPublicKey(key string) string {
  1062  	return logAndCallString(decompressPublicKey, key)
  1063  }
  1064  
  1065  // decompressPublicKey decompresses 33-byte compressed format to uncompressed 65-byte format.
  1066  func decompressPublicKey(key string) string {
  1067  	decoded, err := types.DecodeHex(key)
  1068  	if err != nil {
  1069  		return makeJSONResponse(err)
  1070  	}
  1071  	const compressionBytesNumber = 33
  1072  	if len(decoded) != compressionBytesNumber {
  1073  		return makeJSONResponse(errors.New("key is not 33 bytes long"))
  1074  	}
  1075  	pubKey, err := crypto.DecompressPubkey(decoded)
  1076  	if err != nil {
  1077  		return makeJSONResponse(err)
  1078  	}
  1079  	return types.EncodeHex(crypto.FromECDSAPub(pubKey))
  1080  }
  1081  
  1082  func CompressPublicKey(key string) string {
  1083  	return logAndCallString(compressPublicKey, key)
  1084  }
  1085  
  1086  // compressPublicKey compresses uncompressed 65-byte format to 33-byte compressed format.
  1087  func compressPublicKey(key string) string {
  1088  	pubKey, err := common.HexToPubkey(key)
  1089  	if err != nil {
  1090  		return makeJSONResponse(err)
  1091  	}
  1092  	return types.EncodeHex(crypto.CompressPubkey(pubKey))
  1093  }
  1094  
  1095  func SerializeLegacyKey(key string) string {
  1096  	return logAndCallString(serializeLegacyKey, key)
  1097  }
  1098  
  1099  // serializeLegacyKey compresses an old format public key (0x04...) to the new one zQ...
  1100  func serializeLegacyKey(key string) string {
  1101  	cpk, err := multiformat.SerializeLegacyKey(key)
  1102  	if err != nil {
  1103  		return makeJSONResponse(err)
  1104  	}
  1105  	return cpk
  1106  }
  1107  
  1108  func MultiformatSerializePublicKey(key, outBase string) string {
  1109  	return logAndCallString(multiformatSerializePublicKey, key, outBase)
  1110  }
  1111  
  1112  // SerializePublicKey compresses an uncompressed multibase encoded multicodec identified EC public key
  1113  // For details on usage see specs https://specs.status.im/spec/2#public-key-serialization
  1114  func multiformatSerializePublicKey(key, outBase string) string {
  1115  	cpk, err := multiformat.SerializePublicKey(key, outBase)
  1116  	if err != nil {
  1117  		return makeJSONResponse(err)
  1118  	}
  1119  	return cpk
  1120  }
  1121  
  1122  func MultiformatDeserializePublicKey(key, outBase string) string {
  1123  	return logAndCallString(multiformatDeserializePublicKey, key, outBase)
  1124  }
  1125  
  1126  // DeserializePublicKey decompresses a compressed multibase encoded multicodec identified EC public key
  1127  // For details on usage see specs https://specs.status.im/spec/2#public-key-serialization
  1128  func multiformatDeserializePublicKey(key, outBase string) string {
  1129  	pk, err := multiformat.DeserializePublicKey(key, outBase)
  1130  	if err != nil {
  1131  		return makeJSONResponse(err)
  1132  	}
  1133  	return pk
  1134  }
  1135  
  1136  func ExportUnencryptedDatabase(accountData, password, databasePath string) string {
  1137  	return logAndCallString(exportUnencryptedDatabase, accountData, password, databasePath)
  1138  }
  1139  
  1140  // exportUnencryptedDatabase exports the database unencrypted to the given path
  1141  func exportUnencryptedDatabase(accountData, password, databasePath string) string {
  1142  	var account multiaccounts.Account
  1143  	err := json.Unmarshal([]byte(accountData), &account)
  1144  	if err != nil {
  1145  		return makeJSONResponse(err)
  1146  	}
  1147  	err = statusBackend.ExportUnencryptedDatabase(account, password, databasePath)
  1148  	return makeJSONResponse(err)
  1149  }
  1150  
  1151  func ImportUnencryptedDatabase(accountData, password, databasePath string) string {
  1152  	return logAndCallString(importUnencryptedDatabase, accountData, password, databasePath)
  1153  }
  1154  
  1155  // importUnencryptedDatabase imports the database unencrypted to the given directory
  1156  func importUnencryptedDatabase(accountData, password, databasePath string) string {
  1157  	var account multiaccounts.Account
  1158  	err := json.Unmarshal([]byte(accountData), &account)
  1159  	if err != nil {
  1160  		return makeJSONResponse(err)
  1161  	}
  1162  	err = statusBackend.ImportUnencryptedDatabase(account, password, databasePath)
  1163  	return makeJSONResponse(err)
  1164  }
  1165  
  1166  func ChangeDatabasePassword(KeyUID, password, newPassword string) string {
  1167  	return logAndCallString(changeDatabasePassword, KeyUID, password, newPassword)
  1168  }
  1169  
  1170  // changeDatabasePassword changes the password of the database
  1171  func changeDatabasePassword(KeyUID, password, newPassword string) string {
  1172  	err := statusBackend.ChangeDatabasePassword(KeyUID, password, newPassword)
  1173  	return makeJSONResponse(err)
  1174  }
  1175  
  1176  func ConvertToKeycardAccount(accountData, settingsJSON, keycardUID, password, newPassword string) string {
  1177  	return logAndCallString(convertToKeycardAccount, accountData, settingsJSON, keycardUID, password, newPassword)
  1178  }
  1179  
  1180  // convertToKeycardAccount converts the account to a keycard account
  1181  func convertToKeycardAccount(accountData, settingsJSON, keycardUID, password, newPassword string) string {
  1182  	var account multiaccounts.Account
  1183  	err := json.Unmarshal([]byte(accountData), &account)
  1184  	if err != nil {
  1185  		return makeJSONResponse(err)
  1186  	}
  1187  	var settings settings.Settings
  1188  	err = json.Unmarshal([]byte(settingsJSON), &settings)
  1189  	if err != nil {
  1190  		return makeJSONResponse(err)
  1191  	}
  1192  
  1193  	err = statusBackend.ConvertToKeycardAccount(account, settings, keycardUID, password, newPassword)
  1194  	return makeJSONResponse(err)
  1195  }
  1196  
  1197  func ConvertToRegularAccount(mnemonic, currPassword, newPassword string) string {
  1198  	return logAndCallString(convertToRegularAccount, mnemonic, currPassword, newPassword)
  1199  }
  1200  
  1201  // convertToRegularAccount converts the account to a regular account
  1202  func convertToRegularAccount(mnemonic, currPassword, newPassword string) string {
  1203  	err := statusBackend.ConvertToRegularAccount(mnemonic, currPassword, newPassword)
  1204  	return makeJSONResponse(err)
  1205  }
  1206  
  1207  func ImageServerTLSCert() string {
  1208  	cert, err := server.PublicMediaTLSCert()
  1209  	if err != nil {
  1210  		return makeJSONResponse(err)
  1211  	}
  1212  	return cert
  1213  }
  1214  
  1215  type GetPasswordStrengthRequest struct {
  1216  	Password   string   `json:"password"`
  1217  	UserInputs []string `json:"userInputs"`
  1218  }
  1219  
  1220  type PasswordScoreResponse struct {
  1221  	Score int `json:"score"`
  1222  }
  1223  
  1224  // GetPasswordStrength uses zxcvbn module and generates a JSON containing information about the quality of the given password
  1225  // (Entropy, CrackTime, CrackTimeDisplay, Score, MatchSequence and CalcTime).
  1226  // userInputs argument can be whatever list of strings like user's personal info or site-specific vocabulary that zxcvbn will
  1227  // make use to determine the result.
  1228  // For more details on usage see https://github.com/status-im/zxcvbn-go
  1229  func GetPasswordStrength(paramsJSON string) string {
  1230  	var requestParams GetPasswordStrengthRequest
  1231  
  1232  	err := json.Unmarshal([]byte(paramsJSON), &requestParams)
  1233  	if err != nil {
  1234  		return makeJSONResponse(err)
  1235  	}
  1236  
  1237  	data, err := json.Marshal(zxcvbn.PasswordStrength(requestParams.Password, requestParams.UserInputs))
  1238  	if err != nil {
  1239  		return makeJSONResponse(fmt.Errorf("Error marshalling to json: %v", err))
  1240  	}
  1241  	return string(data)
  1242  }
  1243  
  1244  // GetPasswordStrengthScore uses zxcvbn module and gets the score information about the given password.
  1245  // userInputs argument can be whatever list of strings like user's personal info or site-specific vocabulary that zxcvbn will
  1246  // make use to determine the result.
  1247  // For more details on usage see https://github.com/status-im/zxcvbn-go
  1248  func GetPasswordStrengthScore(paramsJSON string) string {
  1249  	var requestParams GetPasswordStrengthRequest
  1250  	var quality scoring.MinEntropyMatch
  1251  
  1252  	err := json.Unmarshal([]byte(paramsJSON), &requestParams)
  1253  	if err != nil {
  1254  		return makeJSONResponse(err)
  1255  	}
  1256  
  1257  	quality = zxcvbn.PasswordStrength(requestParams.Password, requestParams.UserInputs)
  1258  
  1259  	data, err := json.Marshal(PasswordScoreResponse{
  1260  		Score: quality.Score,
  1261  	})
  1262  	if err != nil {
  1263  		return makeJSONResponse(fmt.Errorf("Error marshalling to json: %v", err))
  1264  	}
  1265  	return string(data)
  1266  }
  1267  
  1268  type FleetDescription struct {
  1269  	DefaultFleet string                         `json:"defaultFleet"`
  1270  	Fleets       map[string]map[string][]string `json:"fleets"`
  1271  }
  1272  
  1273  func Fleets() string {
  1274  	return logAndCallString(fleets)
  1275  }
  1276  
  1277  func fleets() string {
  1278  	fleets := FleetDescription{
  1279  		DefaultFleet: api.DefaultFleet,
  1280  		Fleets:       params.GetSupportedFleets(),
  1281  	}
  1282  
  1283  	data, err := json.Marshal(fleets)
  1284  	if err != nil {
  1285  		return makeJSONResponse(fmt.Errorf("Error marshalling to json: %v", err))
  1286  	}
  1287  	return string(data)
  1288  }
  1289  
  1290  func SwitchFleet(fleet string, configJSON string) string {
  1291  	return logAndCallString(switchFleet, fleet, configJSON)
  1292  }
  1293  
  1294  func switchFleet(fleet string, configJSON string) string {
  1295  	var conf params.NodeConfig
  1296  	if configJSON != "" {
  1297  		err := json.Unmarshal([]byte(configJSON), &conf)
  1298  		if err != nil {
  1299  			return makeJSONResponse(err)
  1300  		}
  1301  	}
  1302  
  1303  	clusterConfig, err := params.LoadClusterConfigFromFleet(fleet)
  1304  	if err != nil {
  1305  		return makeJSONResponse(err)
  1306  	}
  1307  
  1308  	conf.ClusterConfig.Fleet = fleet
  1309  	conf.ClusterConfig.ClusterID = clusterConfig.ClusterID
  1310  
  1311  	err = statusBackend.SwitchFleet(fleet, &conf)
  1312  
  1313  	return makeJSONResponse(err)
  1314  }
  1315  
  1316  func GenerateImages(filepath string, aX, aY, bX, bY int) string {
  1317  	iis, err := images.GenerateIdentityImages(filepath, aX, aY, bX, bY)
  1318  	if err != nil {
  1319  		return makeJSONResponse(err)
  1320  	}
  1321  
  1322  	data, err := json.Marshal(iis)
  1323  	if err != nil {
  1324  		return makeJSONResponse(fmt.Errorf("Error marshalling to json: %v", err))
  1325  	}
  1326  	return string(data)
  1327  }
  1328  
  1329  func LocalPairingPreflightOutboundCheck() string {
  1330  	return logAndCallString(localPairingPreflightOutboundCheck)
  1331  }
  1332  
  1333  // localPairingPreflightOutboundCheck creates a local tls server accessible via an outbound network address.
  1334  // The function creates a client and makes an outbound network call to the local server. This function should be
  1335  // triggered to ensure that the device has permissions to access its LAN or to make outbound network calls.
  1336  //
  1337  // In addition, the functionality attempts to address an issue with iOS devices https://stackoverflow.com/a/64242745
  1338  func localPairingPreflightOutboundCheck() string {
  1339  	err := preflight.CheckOutbound()
  1340  	return makeJSONResponse(err)
  1341  }
  1342  
  1343  func StartSearchForLocalPairingPeers() string {
  1344  	return logAndCallString(startSearchForLocalPairingPeers)
  1345  }
  1346  
  1347  // startSearchForLocalPairingPeers starts a UDP multicast beacon that both listens for and broadcasts to LAN peers
  1348  // on discovery the beacon will emit a signal with the details of the discovered peer.
  1349  //
  1350  // Currently, beacons are configured to search for 2 minutes pinging the network every 500 ms;
  1351  //   - If no peer discovery is made before this time elapses the operation will terminate.
  1352  //   - If a peer is discovered the pairing.PeerNotifier will terminate operation after 5 seconds, giving the peer
  1353  //     reasonable time to discover this device.
  1354  //
  1355  // Peer details are represented by a json.Marshal peers.LocalPairingPeerHello
  1356  func startSearchForLocalPairingPeers() string {
  1357  	pn := pairing.NewPeerNotifier()
  1358  	err := pn.Search()
  1359  	return makeJSONResponse(err)
  1360  }
  1361  
  1362  func GetConnectionStringForBeingBootstrapped(configJSON string) string {
  1363  	return logAndCallString(getConnectionStringForBeingBootstrapped, configJSON)
  1364  }
  1365  
  1366  // getConnectionStringForBeingBootstrapped starts a pairing.ReceiverServer
  1367  // then generates a pairing.ConnectionParams. Used when the device is Logged out or has no Account keys
  1368  // and the device has no camera to read a QR code with
  1369  //
  1370  // Example: A desktop device (device without camera) receiving account data from mobile (device with camera)
  1371  func getConnectionStringForBeingBootstrapped(configJSON string) string {
  1372  	if configJSON == "" {
  1373  		return makeJSONResponse(fmt.Errorf("no config given, PayloadSourceConfig is expected"))
  1374  	}
  1375  
  1376  	statusBackend.LocalPairingStateManager.SetPairing(true)
  1377  	defer func() {
  1378  		statusBackend.LocalPairingStateManager.SetPairing(false)
  1379  	}()
  1380  
  1381  	cs, err := pairing.StartUpReceiverServer(statusBackend, configJSON)
  1382  	if err != nil {
  1383  		return makeJSONResponse(err)
  1384  	}
  1385  
  1386  	err = statusBackend.Logout()
  1387  	if err != nil {
  1388  		return makeJSONResponse(err)
  1389  	}
  1390  
  1391  	return cs
  1392  }
  1393  
  1394  func GetConnectionStringForBootstrappingAnotherDevice(configJSON string) string {
  1395  	return logAndCallString(getConnectionStringForBootstrappingAnotherDevice, configJSON)
  1396  }
  1397  
  1398  // getConnectionStringForBootstrappingAnotherDevice starts a pairing.SenderServer
  1399  // then generates a pairing.ConnectionParams. Used when the device is Logged in and therefore has Account keys
  1400  // and the device might not have a camera
  1401  //
  1402  // Example: A mobile or desktop device (devices that MAY have a camera but MUST have a screen)
  1403  // sending account data to a mobile (device with camera)
  1404  func getConnectionStringForBootstrappingAnotherDevice(configJSON string) string {
  1405  	if configJSON == "" {
  1406  		return makeJSONResponse(fmt.Errorf("no config given, SendingServerConfig is expected"))
  1407  	}
  1408  
  1409  	statusBackend.LocalPairingStateManager.SetPairing(true)
  1410  	defer func() {
  1411  		statusBackend.LocalPairingStateManager.SetPairing(false)
  1412  	}()
  1413  
  1414  	cs, err := pairing.StartUpSenderServer(statusBackend, configJSON)
  1415  	if err != nil {
  1416  		return makeJSONResponse(err)
  1417  	}
  1418  	return cs
  1419  }
  1420  
  1421  type inputConnectionStringForBootstrappingResponse struct {
  1422  	InstallationID string `json:"installationId"`
  1423  	KeyUID         string `json:"keyUID"`
  1424  	Error          error  `json:"error"`
  1425  }
  1426  
  1427  func (i *inputConnectionStringForBootstrappingResponse) toJSON(err error) string {
  1428  	i.Error = err
  1429  	j, _ := json.Marshal(i)
  1430  	return string(j)
  1431  }
  1432  
  1433  func InputConnectionStringForBootstrapping(cs, configJSON string) string {
  1434  	return logAndCallString(inputConnectionStringForBootstrapping, cs, configJSON)
  1435  }
  1436  
  1437  // inputConnectionStringForBootstrapping starts a pairing.ReceiverClient
  1438  // The given server.ConnectionParams string will determine the server.Mode
  1439  //
  1440  // server.Mode = server.Sending
  1441  // Used when the device is Logged out or has no Account keys and has a camera to read a QR code
  1442  //
  1443  // Example: A mobile device (device with a camera) receiving account data from
  1444  // a device with a screen (mobile or desktop devices)
  1445  func inputConnectionStringForBootstrapping(cs, configJSON string) string {
  1446  	var err error
  1447  	if configJSON == "" {
  1448  		return makeJSONResponse(fmt.Errorf("no config given, ReceiverClientConfig is expected"))
  1449  	}
  1450  
  1451  	params := &pairing.ConnectionParams{}
  1452  	err = params.FromString(cs)
  1453  	if err != nil {
  1454  		response := &inputConnectionStringForBootstrappingResponse{}
  1455  		return response.toJSON(fmt.Errorf("could not parse connection string"))
  1456  	}
  1457  	response := &inputConnectionStringForBootstrappingResponse{
  1458  		InstallationID: params.InstallationID(),
  1459  		KeyUID:         params.KeyUID(),
  1460  	}
  1461  
  1462  	err = statusBackend.LocalPairingStateManager.StartPairing(cs)
  1463  	defer func() { statusBackend.LocalPairingStateManager.StopPairing(cs, err) }()
  1464  	if err != nil {
  1465  		return response.toJSON(err)
  1466  	}
  1467  
  1468  	err = pairing.StartUpReceivingClient(statusBackend, cs, configJSON)
  1469  	if err != nil {
  1470  		return response.toJSON(err)
  1471  	}
  1472  
  1473  	return response.toJSON(statusBackend.Logout())
  1474  }
  1475  
  1476  func InputConnectionStringForBootstrappingAnotherDevice(cs, configJSON string) string {
  1477  	return logAndCallString(inputConnectionStringForBootstrappingAnotherDevice, cs, configJSON)
  1478  }
  1479  
  1480  // inputConnectionStringForBootstrappingAnotherDevice starts a pairing.SendingClient
  1481  // The given server.ConnectionParams string will determine the server.Mode
  1482  //
  1483  // server.Mode = server.Receiving
  1484  // Used when the device is Logged in and therefore has Account keys and the has a camera to read a QR code
  1485  //
  1486  // Example: A mobile (device with camera) sending account data to a desktop device (device without camera)
  1487  func inputConnectionStringForBootstrappingAnotherDevice(cs, configJSON string) string {
  1488  	var err error
  1489  	if configJSON == "" {
  1490  		return makeJSONResponse(fmt.Errorf("no config given, SenderClientConfig is expected"))
  1491  	}
  1492  
  1493  	err = statusBackend.LocalPairingStateManager.StartPairing(cs)
  1494  	defer func() { statusBackend.LocalPairingStateManager.StopPairing(cs, err) }()
  1495  	if err != nil {
  1496  		return makeJSONResponse(err)
  1497  	}
  1498  
  1499  	err = pairing.StartUpSendingClient(statusBackend, cs, configJSON)
  1500  	return makeJSONResponse(err)
  1501  }
  1502  
  1503  func GetConnectionStringForExportingKeypairsKeystores(configJSON string) string {
  1504  	return logAndCallString(getConnectionStringForExportingKeypairsKeystores, configJSON)
  1505  }
  1506  
  1507  // getConnectionStringForExportingKeypairsKeystores starts a pairing.SenderServer
  1508  // then generates a pairing.ConnectionParams. Used when the device is Logged in and therefore has Account keys
  1509  // and the device might not have a camera, to transfer kestore files of provided key uids.
  1510  func getConnectionStringForExportingKeypairsKeystores(configJSON string) string {
  1511  	if configJSON == "" {
  1512  		return makeJSONResponse(fmt.Errorf("no config given, SendingServerConfig is expected"))
  1513  	}
  1514  
  1515  	cs, err := pairing.StartUpKeystoreFilesSenderServer(statusBackend, configJSON)
  1516  	if err != nil {
  1517  		return makeJSONResponse(err)
  1518  	}
  1519  	return cs
  1520  }
  1521  
  1522  func InputConnectionStringForImportingKeypairsKeystores(cs, configJSON string) string {
  1523  	return logAndCallString(inputConnectionStringForImportingKeypairsKeystores, cs, configJSON)
  1524  }
  1525  
  1526  // inputConnectionStringForImportingKeypairsKeystores starts a pairing.ReceiverClient
  1527  // The given server.ConnectionParams string will determine the server.Mode
  1528  // Used when the device is Logged in and has Account keys and has a camera to read a QR code
  1529  //
  1530  // Example: A mobile device (device with a camera) receiving account data from
  1531  // a device with a screen (mobile or desktop devices)
  1532  func inputConnectionStringForImportingKeypairsKeystores(cs, configJSON string) string {
  1533  	if configJSON == "" {
  1534  		return makeJSONResponse(fmt.Errorf("no config given, ReceiverClientConfig is expected"))
  1535  	}
  1536  
  1537  	err := pairing.StartUpKeystoreFilesReceivingClient(statusBackend, cs, configJSON)
  1538  	return makeJSONResponse(err)
  1539  }
  1540  
  1541  func ValidateConnectionString(cs string) string {
  1542  	return logAndCallString(validateConnectionString, cs)
  1543  }
  1544  
  1545  func validateConnectionString(cs string) string {
  1546  	err := pairing.ValidateConnectionString(cs)
  1547  	if err == nil {
  1548  		return ""
  1549  	}
  1550  	return err.Error()
  1551  }
  1552  
  1553  func EncodeTransfer(to string, value string) string {
  1554  	return logAndCallString(encodeTransfer, to, value)
  1555  }
  1556  
  1557  func encodeTransfer(to string, value string) string {
  1558  	result, err := abi_spec.EncodeTransfer(to, value)
  1559  	if err != nil {
  1560  		log.Error("failed to encode transfer", "to", to, "value", value, "error", err)
  1561  		return ""
  1562  	}
  1563  	return result
  1564  }
  1565  
  1566  func EncodeFunctionCall(method string, paramsJSON string) string {
  1567  	return logAndCallString(encodeFunctionCall, method, paramsJSON)
  1568  }
  1569  
  1570  func encodeFunctionCall(method string, paramsJSON string) string {
  1571  	result, err := abi_spec.Encode(method, paramsJSON)
  1572  	if err != nil {
  1573  		log.Error("failed to encode function call", "method", method, "paramsJSON", paramsJSON, "error", err)
  1574  		return ""
  1575  	}
  1576  	return result
  1577  }
  1578  
  1579  func DecodeParameters(decodeParamJSON string) string {
  1580  	return decodeParameters(decodeParamJSON)
  1581  }
  1582  
  1583  func decodeParameters(decodeParamJSON string) string {
  1584  	decodeParam := struct {
  1585  		BytesString string   `json:"bytesString"`
  1586  		Types       []string `json:"types"`
  1587  	}{}
  1588  	err := json.Unmarshal([]byte(decodeParamJSON), &decodeParam)
  1589  	if err != nil {
  1590  		log.Error("failed to unmarshal json when decoding parameters", "decodeParamJSON", decodeParamJSON, "error", err)
  1591  		return ""
  1592  	}
  1593  	result, err := abi_spec.Decode(decodeParam.BytesString, decodeParam.Types)
  1594  	if err != nil {
  1595  		log.Error("failed to decode parameters", "decodeParamJSON", decodeParamJSON, "error", err)
  1596  		return ""
  1597  	}
  1598  	bytes, err := json.Marshal(result)
  1599  	if err != nil {
  1600  		log.Error("failed to marshal result", "result", result, "decodeParamJSON", decodeParamJSON, "error", err)
  1601  		return ""
  1602  	}
  1603  	return string(bytes)
  1604  }
  1605  
  1606  func HexToNumber(hex string) string {
  1607  	return logAndCallString(hexToNumber, hex)
  1608  }
  1609  
  1610  func hexToNumber(hex string) string {
  1611  	return abi_spec.HexToNumber(hex)
  1612  }
  1613  
  1614  func NumberToHex(numString string) string {
  1615  	return logAndCallString(numberToHex, numString)
  1616  }
  1617  
  1618  func numberToHex(numString string) string {
  1619  	return abi_spec.NumberToHex(numString)
  1620  }
  1621  
  1622  func Sha3(str string) string {
  1623  	return "0x" + abi_spec.Sha3(str)
  1624  }
  1625  
  1626  func Utf8ToHex(str string) string {
  1627  	return logAndCallString(utf8ToHex, str)
  1628  }
  1629  
  1630  func utf8ToHex(str string) string {
  1631  	hexString, err := abi_spec.Utf8ToHex(str)
  1632  	if err != nil {
  1633  		log.Error("failed to convert utf8 to hex", "str", str, "error", err)
  1634  	}
  1635  	return hexString
  1636  }
  1637  
  1638  func HexToUtf8(hexString string) string {
  1639  	return logAndCallString(hexToUtf8, hexString)
  1640  }
  1641  
  1642  func hexToUtf8(hexString string) string {
  1643  	str, err := abi_spec.HexToUtf8(hexString)
  1644  	if err != nil {
  1645  		log.Error("failed to convert hex to utf8", "hexString", hexString, "error", err)
  1646  	}
  1647  	return str
  1648  }
  1649  
  1650  func CheckAddressChecksum(address string) string {
  1651  	return logAndCallString(checkAddressChecksum, address)
  1652  }
  1653  
  1654  func checkAddressChecksum(address string) string {
  1655  	valid, err := abi_spec.CheckAddressChecksum(address)
  1656  	if err != nil {
  1657  		log.Error("failed to invoke check address checksum", "address", address, "error", err)
  1658  	}
  1659  	result, _ := json.Marshal(valid)
  1660  	return string(result)
  1661  }
  1662  
  1663  func IsAddress(address string) string {
  1664  	return logAndCallString(isAddress, address)
  1665  }
  1666  
  1667  func isAddress(address string) string {
  1668  	valid, err := abi_spec.IsAddress(address)
  1669  	if err != nil {
  1670  		log.Error("failed to invoke IsAddress", "address", address, "error", err)
  1671  	}
  1672  	result, _ := json.Marshal(valid)
  1673  	return string(result)
  1674  }
  1675  
  1676  func ToChecksumAddress(address string) string {
  1677  	return logAndCallString(toChecksumAddress, address)
  1678  }
  1679  
  1680  func toChecksumAddress(address string) string {
  1681  	address, err := abi_spec.ToChecksumAddress(address)
  1682  	if err != nil {
  1683  		log.Error("failed to convert to checksum address", "address", address, "error", err)
  1684  	}
  1685  	return address
  1686  }
  1687  
  1688  func DeserializeAndCompressKey(DesktopKey string) string {
  1689  	return logAndCallString(deserializeAndCompressKey, DesktopKey)
  1690  }
  1691  
  1692  func deserializeAndCompressKey(DesktopKey string) string {
  1693  	deserialisedKey := MultiformatDeserializePublicKey(DesktopKey, "f")
  1694  	sanitisedKey := "0x" + deserialisedKey[5:]
  1695  	return CompressPublicKey(sanitisedKey)
  1696  }
  1697  
  1698  type InitLoggingRequest struct {
  1699  	logutils.LogSettings
  1700  	LogRequestGo   bool   `json:"LogRequestGo"`
  1701  	LogRequestFile string `json:"LogRequestFile"`
  1702  }
  1703  
  1704  // InitLogging The InitLogging function should be called when the application starts.
  1705  // This ensures that we can capture logs before the user login. Subsequent calls will update the logger settings.
  1706  // Before this, we can only capture logs after user login since we will only configure the logging after the login process.
  1707  func InitLogging(logSettingsJSON string) string {
  1708  	var logSettings InitLoggingRequest
  1709  	var err error
  1710  	if err = json.Unmarshal([]byte(logSettingsJSON), &logSettings); err != nil {
  1711  		return makeJSONResponse(err)
  1712  	}
  1713  
  1714  	if err = logutils.OverrideRootLogWithConfig(logSettings.LogSettings, false); err == nil {
  1715  		log.Info("logging initialised", "logSettings", logSettingsJSON)
  1716  	}
  1717  
  1718  	if logSettings.LogRequestGo {
  1719  		err = requestlog.ConfigureAndEnableRequestLogging(logSettings.LogRequestFile)
  1720  		if err != nil {
  1721  			return makeJSONResponse(err)
  1722  		}
  1723  	}
  1724  
  1725  	return makeJSONResponse(err)
  1726  }
  1727  
  1728  func GetRandomMnemonic() string {
  1729  	mnemonic, err := account.GetRandomMnemonic()
  1730  	if err != nil {
  1731  		return makeJSONResponse(err)
  1732  	}
  1733  	return mnemonic
  1734  }
  1735  
  1736  func ToggleCentralizedMetrics(requestJSON string) string {
  1737  	return logAndCallString(toggleCentralizedMetrics, requestJSON)
  1738  }
  1739  
  1740  func toggleCentralizedMetrics(requestJSON string) string {
  1741  	var request requests.ToggleCentralizedMetrics
  1742  	err := json.Unmarshal([]byte(requestJSON), &request)
  1743  	if err != nil {
  1744  		return makeJSONResponse(err)
  1745  	}
  1746  
  1747  	err = request.Validate()
  1748  	if err != nil {
  1749  		return makeJSONResponse(err)
  1750  	}
  1751  
  1752  	err = statusBackend.ToggleCentralizedMetrics(request.Enabled)
  1753  	if err != nil {
  1754  		return makeJSONResponse(err)
  1755  	}
  1756  
  1757  	return makeJSONResponse(nil)
  1758  }
  1759  
  1760  func CentralizedMetricsInfo() string {
  1761  	return logAndCallString(centralizedMetricsInfo)
  1762  }
  1763  
  1764  func centralizedMetricsInfo() string {
  1765  	metricsInfo, err := statusBackend.CentralizedMetricsInfo()
  1766  	if err != nil {
  1767  		return makeJSONResponse(err)
  1768  	}
  1769  	data, err := json.Marshal(metricsInfo)
  1770  	if err != nil {
  1771  		return makeJSONResponse(err)
  1772  	}
  1773  	return string(data)
  1774  }
  1775  
  1776  func AddCentralizedMetric(requestJSON string) string {
  1777  	return logAndCallString(addCentralizedMetric, requestJSON)
  1778  }
  1779  
  1780  func addCentralizedMetric(requestJSON string) string {
  1781  	var request requests.AddCentralizedMetric
  1782  	err := json.Unmarshal([]byte(requestJSON), &request)
  1783  	if err != nil {
  1784  		return makeJSONResponse(err)
  1785  	}
  1786  
  1787  	err = request.Validate()
  1788  	if err != nil {
  1789  		return makeJSONResponse(err)
  1790  	}
  1791  	metric := request.Metric
  1792  
  1793  	metric.EnsureID()
  1794  	err = statusBackend.AddCentralizedMetric(*metric)
  1795  	if err != nil {
  1796  		return makeJSONResponse(err)
  1797  	}
  1798  
  1799  	return metric.ID
  1800  }