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

     1  package api
     2  
     3  import (
     4  	"context"
     5  	"crypto/ecdsa"
     6  	"database/sql"
     7  	"encoding/json"
     8  	"fmt"
     9  	"math/big"
    10  	"os"
    11  	"path/filepath"
    12  	"strings"
    13  	"sync"
    14  	"time"
    15  
    16  	"go.uber.org/zap"
    17  
    18  	"github.com/afex/hystrix-go/hystrix"
    19  	"github.com/pkg/errors"
    20  
    21  	"github.com/imdario/mergo"
    22  
    23  	"github.com/ethereum/go-ethereum/common"
    24  	"github.com/ethereum/go-ethereum/common/hexutil"
    25  	ethcrypto "github.com/ethereum/go-ethereum/crypto"
    26  	"github.com/ethereum/go-ethereum/log"
    27  	signercore "github.com/ethereum/go-ethereum/signer/core/apitypes"
    28  
    29  	"github.com/status-im/status-go/account"
    30  	"github.com/status-im/status-go/account/generator"
    31  	"github.com/status-im/status-go/appdatabase"
    32  	"github.com/status-im/status-go/centralizedmetrics"
    33  	centralizedmetricscommon "github.com/status-im/status-go/centralizedmetrics/common"
    34  	"github.com/status-im/status-go/common/dbsetup"
    35  	"github.com/status-im/status-go/connection"
    36  	"github.com/status-im/status-go/eth-node/crypto"
    37  	"github.com/status-im/status-go/eth-node/types"
    38  	"github.com/status-im/status-go/images"
    39  	"github.com/status-im/status-go/logutils"
    40  	"github.com/status-im/status-go/multiaccounts"
    41  	"github.com/status-im/status-go/multiaccounts/accounts"
    42  	multiacccommon "github.com/status-im/status-go/multiaccounts/common"
    43  	"github.com/status-im/status-go/multiaccounts/settings"
    44  	"github.com/status-im/status-go/node"
    45  	"github.com/status-im/status-go/nodecfg"
    46  	"github.com/status-im/status-go/params"
    47  	"github.com/status-im/status-go/protocol"
    48  	identityutils "github.com/status-im/status-go/protocol/identity"
    49  	"github.com/status-im/status-go/protocol/identity/colorhash"
    50  	"github.com/status-im/status-go/protocol/requests"
    51  	"github.com/status-im/status-go/rpc"
    52  	"github.com/status-im/status-go/server/pairing/statecontrol"
    53  	"github.com/status-im/status-go/services/ens"
    54  	"github.com/status-im/status-go/services/ext"
    55  	"github.com/status-im/status-go/services/personal"
    56  	"github.com/status-im/status-go/services/typeddata"
    57  	"github.com/status-im/status-go/services/wallet"
    58  	"github.com/status-im/status-go/signal"
    59  	"github.com/status-im/status-go/sqlite"
    60  	"github.com/status-im/status-go/transactions"
    61  	"github.com/status-im/status-go/walletdatabase"
    62  )
    63  
    64  var (
    65  	// ErrWhisperClearIdentitiesFailure clearing whisper identities has failed.
    66  	ErrWhisperClearIdentitiesFailure = errors.New("failed to clear whisper identities")
    67  	// ErrWhisperIdentityInjectionFailure injecting whisper identities has failed.
    68  	ErrWhisperIdentityInjectionFailure = errors.New("failed to inject identity into Whisper")
    69  	// ErrWakuIdentityInjectionFailure injecting whisper identities has failed.
    70  	ErrWakuIdentityInjectionFailure = errors.New("failed to inject identity into waku")
    71  	// ErrUnsupportedRPCMethod is for methods not supported by the RPC interface
    72  	ErrUnsupportedRPCMethod = errors.New("method is unsupported by RPC interface")
    73  	// ErrRPCClientUnavailable is returned if an RPC client can't be retrieved.
    74  	// This is a normal situation when a node is stopped.
    75  	ErrRPCClientUnavailable = errors.New("JSON-RPC client is unavailable")
    76  	// ErrDBNotAvailable is returned if a method is called before the DB is available for usage
    77  	ErrDBNotAvailable = errors.New("DB is unavailable")
    78  )
    79  
    80  var _ StatusBackend = (*GethStatusBackend)(nil)
    81  
    82  // GethStatusBackend implements the Status.im service over go-ethereum
    83  type GethStatusBackend struct {
    84  	mu sync.Mutex
    85  	// rootDataDir is the same for all networks.
    86  	rootDataDir string
    87  	appDB       *sql.DB
    88  	walletDB    *sql.DB
    89  	config      *params.NodeConfig
    90  
    91  	statusNode               *node.StatusNode
    92  	personalAPI              *personal.PublicAPI
    93  	multiaccountsDB          *multiaccounts.Database
    94  	account                  *multiaccounts.Account
    95  	accountManager           *account.GethManager
    96  	transactor               *transactions.Transactor
    97  	connectionState          connection.State
    98  	appState                 appState
    99  	selectedAccountKeyID     string
   100  	log                      log.Logger
   101  	allowAllRPC              bool // used only for tests, disables api method restrictions
   102  	LocalPairingStateManager *statecontrol.ProcessStateManager
   103  	centralizedMetrics       *centralizedmetrics.MetricService
   104  }
   105  
   106  // NewGethStatusBackend create a new GethStatusBackend instance
   107  func NewGethStatusBackend() *GethStatusBackend {
   108  	defer log.Info("Status backend initialized", "backend", "geth", "version", params.Version, "commit", params.GitCommit, "IpfsGatewayURL", params.IpfsGatewayURL)
   109  
   110  	backend := &GethStatusBackend{}
   111  	backend.initialize()
   112  	return backend
   113  }
   114  
   115  func (b *GethStatusBackend) initialize() {
   116  	accountManager := account.NewGethManager()
   117  	transactor := transactions.NewTransactor()
   118  	personalAPI := personal.NewAPI()
   119  	statusNode := node.New(transactor)
   120  
   121  	b.statusNode = statusNode
   122  	b.accountManager = accountManager
   123  	b.transactor = transactor
   124  	b.personalAPI = personalAPI
   125  	b.statusNode.SetMultiaccountsDB(b.multiaccountsDB)
   126  	b.log = log.New("package", "status-go/api.GethStatusBackend")
   127  	b.LocalPairingStateManager = new(statecontrol.ProcessStateManager)
   128  	b.LocalPairingStateManager.SetPairing(false)
   129  }
   130  
   131  // StatusNode returns reference to node manager
   132  func (b *GethStatusBackend) StatusNode() *node.StatusNode {
   133  	return b.statusNode
   134  }
   135  
   136  // AccountManager returns reference to account manager
   137  func (b *GethStatusBackend) AccountManager() *account.GethManager {
   138  	return b.accountManager
   139  }
   140  
   141  // Transactor returns reference to a status transactor
   142  func (b *GethStatusBackend) Transactor() *transactions.Transactor {
   143  	return b.transactor
   144  }
   145  
   146  // SelectedAccountKeyID returns a Whisper key ID of the selected chat key pair.
   147  func (b *GethStatusBackend) SelectedAccountKeyID() string {
   148  	return b.selectedAccountKeyID
   149  }
   150  
   151  // IsNodeRunning confirm that node is running
   152  func (b *GethStatusBackend) IsNodeRunning() bool {
   153  	return b.statusNode.IsRunning()
   154  }
   155  
   156  // StartNode start Status node, fails if node is already started
   157  func (b *GethStatusBackend) StartNode(config *params.NodeConfig) error {
   158  	b.mu.Lock()
   159  	defer b.mu.Unlock()
   160  	if err := b.startNode(config); err != nil {
   161  		signal.SendNodeCrashed(err)
   162  		return err
   163  	}
   164  	return nil
   165  }
   166  
   167  func (b *GethStatusBackend) UpdateRootDataDir(datadir string) {
   168  	b.mu.Lock()
   169  	defer b.mu.Unlock()
   170  	b.rootDataDir = datadir
   171  }
   172  
   173  func (b *GethStatusBackend) GetMultiaccountDB() *multiaccounts.Database {
   174  	return b.multiaccountsDB
   175  }
   176  
   177  func (b *GethStatusBackend) OpenAccounts() error {
   178  	b.mu.Lock()
   179  	defer b.mu.Unlock()
   180  	if b.multiaccountsDB != nil {
   181  		return nil
   182  	}
   183  	db, err := multiaccounts.InitializeDB(filepath.Join(b.rootDataDir, "accounts.sql"))
   184  	if err != nil {
   185  		b.log.Error("failed to initialize accounts db", "err", err)
   186  		return err
   187  	}
   188  	b.multiaccountsDB = db
   189  
   190  	b.centralizedMetrics = centralizedmetrics.NewDefaultMetricService(b.multiaccountsDB.DB())
   191  	err = b.centralizedMetrics.EnsureStarted()
   192  	if err != nil {
   193  		return err
   194  	}
   195  
   196  	// Probably we should iron out a bit better how to create/dispose of the status-service
   197  	b.statusNode.SetMultiaccountsDB(db)
   198  
   199  	err = b.statusNode.StartMediaServerWithoutDB()
   200  	if err != nil {
   201  		b.log.Error("failed to start media server without app db", "err", err)
   202  		return err
   203  	}
   204  
   205  	return nil
   206  }
   207  
   208  func (b *GethStatusBackend) CentralizedMetricsInfo() (*centralizedmetrics.MetricsInfo, error) {
   209  	if b.centralizedMetrics == nil {
   210  		return nil, errors.New("centralized metrics not initialized")
   211  	}
   212  
   213  	return b.centralizedMetrics.Info()
   214  }
   215  
   216  func (b *GethStatusBackend) ToggleCentralizedMetrics(isEnabled bool) error {
   217  	if b.centralizedMetrics == nil {
   218  		return errors.New("centralized metrics nil")
   219  	}
   220  
   221  	return b.centralizedMetrics.ToggleEnabled(isEnabled)
   222  }
   223  
   224  func (b *GethStatusBackend) AddCentralizedMetric(metric centralizedmetricscommon.Metric) error {
   225  	if b.centralizedMetrics == nil {
   226  		return errors.New("centralized metrics nil")
   227  	}
   228  	return b.centralizedMetrics.AddMetric(metric)
   229  
   230  }
   231  
   232  func (b *GethStatusBackend) GetAccounts() ([]multiaccounts.Account, error) {
   233  	b.mu.Lock()
   234  	defer b.mu.Unlock()
   235  	if b.multiaccountsDB == nil {
   236  		return nil, errors.New("accounts db wasn't initialized")
   237  	}
   238  	return b.multiaccountsDB.GetAccounts()
   239  }
   240  
   241  func (b *GethStatusBackend) getAccountByKeyUID(keyUID string) (*multiaccounts.Account, error) {
   242  	b.mu.Lock()
   243  	defer b.mu.Unlock()
   244  	if b.multiaccountsDB == nil {
   245  		return nil, errors.New("accounts db wasn't initialized")
   246  	}
   247  	as, err := b.multiaccountsDB.GetAccounts()
   248  	if err != nil {
   249  		return nil, err
   250  	}
   251  	for _, acc := range as {
   252  		if acc.KeyUID == keyUID {
   253  			return &acc, nil
   254  		}
   255  	}
   256  	return nil, fmt.Errorf("account with keyUID %s not found", keyUID)
   257  }
   258  
   259  func (b *GethStatusBackend) SaveAccount(account multiaccounts.Account) error {
   260  	b.mu.Lock()
   261  	defer b.mu.Unlock()
   262  	if b.multiaccountsDB == nil {
   263  		return errors.New("accounts db wasn't initialized")
   264  	}
   265  	return b.multiaccountsDB.SaveAccount(account)
   266  }
   267  
   268  func (b *GethStatusBackend) DeleteMultiaccount(keyUID string, keyStoreDir string) error {
   269  	b.mu.Lock()
   270  	defer b.mu.Unlock()
   271  	if b.multiaccountsDB == nil {
   272  		return errors.New("accounts db wasn't initialized")
   273  	}
   274  
   275  	err := b.multiaccountsDB.DeleteAccount(keyUID)
   276  	if err != nil {
   277  		return err
   278  	}
   279  
   280  	appDbPath, err := b.getAppDBPath(keyUID)
   281  	if err != nil {
   282  		return err
   283  	}
   284  
   285  	walletDbPath, err := b.getWalletDBPath(keyUID)
   286  	if err != nil {
   287  		return err
   288  	}
   289  
   290  	dbFiles := []string{
   291  		filepath.Join(b.rootDataDir, fmt.Sprintf("app-%x.sql", keyUID)),
   292  		filepath.Join(b.rootDataDir, fmt.Sprintf("app-%x.sql-shm", keyUID)),
   293  		filepath.Join(b.rootDataDir, fmt.Sprintf("app-%x.sql-wal", keyUID)),
   294  		filepath.Join(b.rootDataDir, fmt.Sprintf("%s.db", keyUID)),
   295  		filepath.Join(b.rootDataDir, fmt.Sprintf("%s.db-shm", keyUID)),
   296  		filepath.Join(b.rootDataDir, fmt.Sprintf("%s.db-wal", keyUID)),
   297  		appDbPath,
   298  		appDbPath + "-shm",
   299  		appDbPath + "-wal",
   300  		walletDbPath,
   301  		walletDbPath + "-shm",
   302  		walletDbPath + "-wal",
   303  	}
   304  	for _, path := range dbFiles {
   305  		if _, err := os.Stat(path); err == nil {
   306  			err = os.Remove(path)
   307  			if err != nil {
   308  				return err
   309  			}
   310  		}
   311  	}
   312  
   313  	if b.account != nil && b.account.KeyUID == keyUID {
   314  		// reset active account
   315  		b.account = nil
   316  	}
   317  
   318  	return os.RemoveAll(keyStoreDir)
   319  }
   320  
   321  func (b *GethStatusBackend) DeleteImportedKey(address, password, keyStoreDir string) error {
   322  	b.mu.Lock()
   323  	defer b.mu.Unlock()
   324  
   325  	err := filepath.Walk(keyStoreDir, func(path string, fileInfo os.FileInfo, err error) error {
   326  		if err != nil {
   327  			return err
   328  		}
   329  		if strings.Contains(fileInfo.Name(), address) {
   330  			_, err := b.accountManager.VerifyAccountPassword(keyStoreDir, "0x"+address, password)
   331  			if err != nil {
   332  				b.log.Error("failed to verify account", "account", address, "error", err)
   333  				return err
   334  			}
   335  
   336  			return os.Remove(path)
   337  		}
   338  		return nil
   339  	})
   340  
   341  	return err
   342  }
   343  
   344  func (b *GethStatusBackend) runDBFileMigrations(account multiaccounts.Account, password string) (string, error) {
   345  	// Migrate file path to fix issue https://github.com/status-im/status-go/issues/2027
   346  	unsupportedPath := filepath.Join(b.rootDataDir, fmt.Sprintf("app-%x.sql", account.KeyUID))
   347  	v3Path := filepath.Join(b.rootDataDir, fmt.Sprintf("%s.db", account.KeyUID))
   348  	v4Path, err := b.getAppDBPath(account.KeyUID)
   349  	if err != nil {
   350  		return "", err
   351  	}
   352  
   353  	_, err = os.Stat(unsupportedPath)
   354  	if err == nil {
   355  		err := os.Rename(unsupportedPath, v3Path)
   356  		if err != nil {
   357  			return "", err
   358  		}
   359  
   360  		// rename journals as well, but ignore errors
   361  		_ = os.Rename(unsupportedPath+"-shm", v3Path+"-shm")
   362  		_ = os.Rename(unsupportedPath+"-wal", v3Path+"-wal")
   363  	}
   364  
   365  	if _, err = os.Stat(v3Path); err == nil {
   366  		if err := appdatabase.MigrateV3ToV4(v3Path, v4Path, password, account.KDFIterations, signal.SendReEncryptionStarted, signal.SendReEncryptionFinished); err != nil {
   367  			_ = os.Remove(v4Path)
   368  			_ = os.Remove(v4Path + "-shm")
   369  			_ = os.Remove(v4Path + "-wal")
   370  			return "", errors.New("Failed to migrate v3 db to v4: " + err.Error())
   371  		}
   372  		_ = os.Remove(v3Path)
   373  		_ = os.Remove(v3Path + "-shm")
   374  		_ = os.Remove(v3Path + "-wal")
   375  	}
   376  
   377  	return v4Path, nil
   378  }
   379  
   380  func (b *GethStatusBackend) ensureDBsOpened(account multiaccounts.Account, password string) (err error) {
   381  	// After wallet DB initial migration, the tables moved to wallet DB are removed from appDB
   382  	// so better migrate wallet DB first to avoid removal if wallet DB migration fails
   383  	if err = b.ensureWalletDBOpened(account, password); err != nil {
   384  		return err
   385  	}
   386  
   387  	if err = b.ensureAppDBOpened(account, password); err != nil {
   388  		return err
   389  	}
   390  
   391  	return nil
   392  }
   393  
   394  func (b *GethStatusBackend) ensureAppDBOpened(account multiaccounts.Account, password string) (err error) {
   395  	b.mu.Lock()
   396  	defer b.mu.Unlock()
   397  	if b.appDB != nil {
   398  		return nil
   399  	}
   400  	if len(b.rootDataDir) == 0 {
   401  		return errors.New("root datadir wasn't provided")
   402  	}
   403  
   404  	dbFilePath, err := b.runDBFileMigrations(account, password)
   405  	if err != nil {
   406  		return errors.New("Failed to migrate db file: " + err.Error())
   407  	}
   408  
   409  	appdatabase.CurrentAppDBKeyUID = account.KeyUID
   410  	b.appDB, err = appdatabase.InitializeDB(dbFilePath, password, account.KDFIterations)
   411  	if err != nil {
   412  		b.log.Error("failed to initialize db", "err", err.Error())
   413  		return err
   414  	}
   415  	b.statusNode.SetAppDB(b.appDB)
   416  	return nil
   417  }
   418  
   419  func fileExists(path string) bool {
   420  	if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
   421  		return false
   422  	}
   423  
   424  	return true
   425  }
   426  
   427  func (b *GethStatusBackend) walletDBExists(keyUID string) bool {
   428  	path, err := b.getWalletDBPath(keyUID)
   429  	if err != nil {
   430  		return false
   431  	}
   432  
   433  	return fileExists(path)
   434  }
   435  
   436  func (b *GethStatusBackend) appDBExists(keyUID string) bool {
   437  	path, err := b.getAppDBPath(keyUID)
   438  	if err != nil {
   439  		return false
   440  	}
   441  
   442  	return fileExists(path)
   443  }
   444  
   445  func (b *GethStatusBackend) ensureWalletDBOpened(account multiaccounts.Account, password string) (err error) {
   446  	b.mu.Lock()
   447  	defer b.mu.Unlock()
   448  	if b.walletDB != nil {
   449  		return nil
   450  	}
   451  
   452  	dbWalletPath, err := b.getWalletDBPath(account.KeyUID)
   453  	if err != nil {
   454  		return err
   455  	}
   456  
   457  	b.walletDB, err = walletdatabase.InitializeDB(dbWalletPath, password, account.KDFIterations)
   458  	if err != nil {
   459  		b.log.Error("failed to initialize wallet db", "err", err.Error())
   460  		return err
   461  	}
   462  	b.statusNode.SetWalletDB(b.walletDB)
   463  	return nil
   464  }
   465  
   466  func (b *GethStatusBackend) setupLogSettings() error {
   467  	logSettings := logutils.LogSettings{
   468  		Enabled:         b.config.LogEnabled,
   469  		MobileSystem:    b.config.LogMobileSystem,
   470  		Level:           b.config.LogLevel,
   471  		File:            b.config.LogFile,
   472  		MaxSize:         b.config.LogMaxSize,
   473  		MaxBackups:      b.config.LogMaxBackups,
   474  		CompressRotated: b.config.LogCompressRotated,
   475  	}
   476  	if err := logutils.OverrideRootLogWithConfig(logSettings, false); err != nil {
   477  		return err
   478  	}
   479  	return nil
   480  }
   481  
   482  // Deprecated: Use StartNodeWithAccount instead.
   483  func (b *GethStatusBackend) StartNodeWithKey(acc multiaccounts.Account, password string, keyHex string, nodecfg *params.NodeConfig) error {
   484  	if acc.KDFIterations == 0 {
   485  		kdfIterations, err := b.multiaccountsDB.GetAccountKDFIterationsNumber(acc.KeyUID)
   486  		if err != nil {
   487  			return err
   488  		}
   489  
   490  		acc.KDFIterations = kdfIterations
   491  	}
   492  
   493  	chatKey, err := ethcrypto.HexToECDSA(keyHex)
   494  	if err != nil {
   495  		return err
   496  	}
   497  
   498  	err = b.startNodeWithAccount(acc, password, nodecfg, chatKey)
   499  	if err != nil {
   500  		// Stop node for clean up
   501  		_ = b.StopNode()
   502  	}
   503  	// get logged in
   504  	if b.LocalPairingStateManager.IsPairing() {
   505  		return nil
   506  	}
   507  	return b.LoggedIn(acc.KeyUID, err)
   508  }
   509  
   510  func (b *GethStatusBackend) OverwriteNodeConfigValues(conf *params.NodeConfig, n *params.NodeConfig) (*params.NodeConfig, error) {
   511  	if err := mergo.Merge(conf, n, mergo.WithOverride); err != nil {
   512  		return nil, err
   513  	}
   514  
   515  	conf.Networks = n.Networks
   516  
   517  	if err := b.saveNodeConfig(conf); err != nil {
   518  		return nil, err
   519  	}
   520  
   521  	return conf, nil
   522  }
   523  
   524  func (b *GethStatusBackend) updateAccountColorHashAndColorID(keyUID string, accountsDB *accounts.Database) (*multiaccounts.Account, error) {
   525  	multiAccount, err := b.getAccountByKeyUID(keyUID)
   526  	if err != nil {
   527  		return nil, err
   528  	}
   529  	if multiAccount.ColorHash == nil {
   530  		keypair, err := accountsDB.GetKeypairByKeyUID(keyUID)
   531  		if err != nil {
   532  			return nil, err
   533  		}
   534  		publicKey := keypair.GetChatPublicKey()
   535  		if publicKey == nil {
   536  			return nil, errors.New("chat public key not found")
   537  		}
   538  		if err = enrichMultiAccountByPublicKey(multiAccount, publicKey); err != nil {
   539  			return nil, err
   540  		}
   541  		if err = b.multiaccountsDB.UpdateAccount(*multiAccount); err != nil {
   542  			return nil, err
   543  		}
   544  	}
   545  	return multiAccount, nil
   546  }
   547  
   548  func (b *GethStatusBackend) overrideNetworks(conf *params.NodeConfig, request *requests.Login) {
   549  	conf.Networks = setRPCs(defaultNetworks(request.WalletSecretsConfig.StatusProxyStageName), &request.WalletSecretsConfig)
   550  }
   551  
   552  func (b *GethStatusBackend) LoginAccount(request *requests.Login) error {
   553  	err := b.loginAccount(request)
   554  	if err != nil {
   555  		// Stop node for clean up
   556  		_ = b.StopNode()
   557  	}
   558  	if b.LocalPairingStateManager.IsPairing() {
   559  		return nil
   560  	}
   561  	return b.LoggedIn(request.KeyUID, err)
   562  }
   563  
   564  func (b *GethStatusBackend) loginAccount(request *requests.Login) error {
   565  	if err := request.Validate(); err != nil {
   566  		return err
   567  	}
   568  
   569  	if request.Mnemonic != "" {
   570  		info, err := b.generateAccountInfo(request.Mnemonic)
   571  		if err != nil {
   572  			return errors.Wrap(err, "failed to generate account info")
   573  		}
   574  
   575  		derivedAddresses, err := b.getDerivedAddresses(info.ID)
   576  		if err != nil {
   577  			return errors.Wrap(err, "failed to get derived addresses")
   578  		}
   579  
   580  		request.Password = derivedAddresses[pathEncryption].PublicKey
   581  		request.KeycardWhisperPrivateKey = derivedAddresses[pathDefaultChat].PrivateKey
   582  	}
   583  
   584  	acc := multiaccounts.Account{
   585  		KeyUID:        request.KeyUID,
   586  		KDFIterations: request.KdfIterations,
   587  	}
   588  
   589  	if acc.KDFIterations == 0 {
   590  		acc.KDFIterations = dbsetup.ReducedKDFIterationsNumber
   591  	}
   592  
   593  	err := b.ensureDBsOpened(acc, request.Password)
   594  	if err != nil {
   595  		return errors.Wrap(err, "failed to open database")
   596  	}
   597  
   598  	defaultCfg := &params.NodeConfig{
   599  		// why we need this? relate PR: https://github.com/status-im/status-go/pull/4014
   600  		KeycardPairingDataFile: DefaultKeycardPairingDataFile,
   601  	}
   602  
   603  	defaultCfg.WalletConfig = buildWalletConfig(&request.WalletSecretsConfig, request.StatusProxyEnabled)
   604  
   605  	err = b.UpdateNodeConfigFleet(acc, request.Password, defaultCfg)
   606  	if err != nil {
   607  		return errors.Wrap(err, "failed to update node config fleet")
   608  	}
   609  
   610  	err = b.loadNodeConfig(defaultCfg)
   611  	if err != nil {
   612  		return errors.Wrap(err, "failed to load node config")
   613  	}
   614  
   615  	if request.RuntimeLogLevel != "" {
   616  		b.config.LogLevel = request.RuntimeLogLevel
   617  	}
   618  
   619  	if b.config.WakuV2Config.Enabled && request.WakuV2Nameserver != "" {
   620  		b.config.WakuV2Config.Nameserver = request.WakuV2Nameserver
   621  	}
   622  
   623  	b.config.ShhextConfig.BandwidthStatsEnabled = request.BandwidthStatsEnabled
   624  
   625  	b.overrideNetworks(b.config, request)
   626  
   627  	if request.APIConfig != nil {
   628  		overrideApiConfig(b.config, request.APIConfig)
   629  	}
   630  
   631  	err = b.setupLogSettings()
   632  	if err != nil {
   633  		return errors.Wrap(err, "failed to setup log settings")
   634  	}
   635  
   636  	accountsDB, err := accounts.NewDB(b.appDB)
   637  	if err != nil {
   638  		return errors.Wrap(err, "failed to create accounts db")
   639  	}
   640  
   641  	multiAccount, err := b.updateAccountColorHashAndColorID(acc.KeyUID, accountsDB)
   642  	if err != nil {
   643  		return errors.Wrap(err, "failed to update account color hash and color id")
   644  	}
   645  	b.account = multiAccount
   646  
   647  	chatAddr, err := accountsDB.GetChatAddress()
   648  	if err != nil {
   649  		return errors.Wrap(err, "failed to get chat address")
   650  	}
   651  	walletAddr, err := accountsDB.GetWalletAddress()
   652  	if err != nil {
   653  		return errors.Wrap(err, "failed to get wallet address")
   654  	}
   655  	watchAddrs, err := accountsDB.GetWalletAddresses()
   656  	if err != nil {
   657  		return errors.Wrap(err, "failed to get wallet addresses")
   658  	}
   659  	login := account.LoginParams{
   660  		Password:       request.Password,
   661  		ChatAddress:    chatAddr,
   662  		WatchAddresses: watchAddrs,
   663  		MainAccount:    walletAddr,
   664  	}
   665  
   666  	err = b.StartNode(b.config)
   667  	if err != nil {
   668  		b.log.Info("failed to start node")
   669  		return errors.Wrap(err, "failed to start node")
   670  	}
   671  
   672  	if chatKey := request.ChatPrivateKey(); chatKey == nil {
   673  		err = b.SelectAccount(login)
   674  		if err != nil {
   675  			return errors.Wrap(err, "failed to select account")
   676  		}
   677  	} else {
   678  		// In case of keycard, we don't have a keystore, instead we have private key loaded from the keycard
   679  		if err := b.accountManager.SetChatAccount(chatKey); err != nil {
   680  			return errors.Wrap(err, "failed to set chat account")
   681  		}
   682  		_, err = b.accountManager.SelectedChatAccount()
   683  		if err != nil {
   684  			return errors.Wrap(err, "failed to get selected chat account")
   685  		}
   686  
   687  		b.accountManager.SetAccountAddresses(walletAddr, watchAddrs...)
   688  		err = b.injectAccountsIntoServices()
   689  		if err != nil {
   690  			return errors.Wrap(err, "failed to inject accounts into services")
   691  		}
   692  	}
   693  
   694  	err = b.multiaccountsDB.UpdateAccountTimestamp(acc.KeyUID, time.Now().Unix())
   695  	if err != nil {
   696  		b.log.Error("failed to update account")
   697  		return errors.Wrap(err, "failed to update account")
   698  	}
   699  
   700  	return nil
   701  }
   702  
   703  // UpdateNodeConfigFleet loads the fleet from the settings and updates the node configuration
   704  // If the fleet in settings is empty, or not supported anymore, it will be overridden with the default fleet.
   705  // In that case settings fleet value remain the same, only runtime node configuration is updated.
   706  func (b *GethStatusBackend) UpdateNodeConfigFleet(acc multiaccounts.Account, password string, config *params.NodeConfig) error {
   707  	if config == nil {
   708  		return nil
   709  	}
   710  
   711  	err := b.ensureDBsOpened(acc, password)
   712  	if err != nil {
   713  		return err
   714  	}
   715  
   716  	accountSettings, err := b.GetSettings()
   717  	if err != nil {
   718  		return err
   719  	}
   720  
   721  	fleet := accountSettings.GetFleet()
   722  
   723  	if !params.IsFleetSupported(fleet) {
   724  		b.log.Warn("fleet is not supported, overriding with default value",
   725  			"fleet", fleet,
   726  			"defaultFleet", DefaultFleet)
   727  		fleet = DefaultFleet
   728  	}
   729  
   730  	err = SetFleet(fleet, config)
   731  	if err != nil {
   732  		return err
   733  	}
   734  
   735  	return nil
   736  }
   737  
   738  // Deprecated: Use loginAccount instead
   739  func (b *GethStatusBackend) startNodeWithAccount(acc multiaccounts.Account, password string, inputNodeCfg *params.NodeConfig, chatKey *ecdsa.PrivateKey) error {
   740  	err := b.ensureDBsOpened(acc, password)
   741  	if err != nil {
   742  		return err
   743  	}
   744  
   745  	err = b.loadNodeConfig(inputNodeCfg)
   746  	if err != nil {
   747  		return err
   748  	}
   749  
   750  	err = b.setupLogSettings()
   751  	if err != nil {
   752  		return err
   753  	}
   754  
   755  	accountsDB, err := accounts.NewDB(b.appDB)
   756  	if err != nil {
   757  		return err
   758  	}
   759  
   760  	if acc.ColorHash == nil {
   761  		multiAccount, err := b.updateAccountColorHashAndColorID(acc.KeyUID, accountsDB)
   762  		if err != nil {
   763  			return err
   764  		}
   765  		acc = *multiAccount
   766  	}
   767  
   768  	b.account = &acc
   769  
   770  	chatAddr, err := accountsDB.GetChatAddress()
   771  	if err != nil {
   772  		return err
   773  	}
   774  	walletAddr, err := accountsDB.GetWalletAddress()
   775  	if err != nil {
   776  		return err
   777  	}
   778  	watchAddrs, err := accountsDB.GetWalletAddresses()
   779  	if err != nil {
   780  		return err
   781  	}
   782  	login := account.LoginParams{
   783  		Password:       password,
   784  		ChatAddress:    chatAddr,
   785  		WatchAddresses: watchAddrs,
   786  		MainAccount:    walletAddr,
   787  	}
   788  
   789  	err = b.StartNode(b.config)
   790  	if err != nil {
   791  		b.log.Info("failed to start node")
   792  		return err
   793  	}
   794  
   795  	if chatKey == nil {
   796  		// Load account from keystore
   797  		err = b.SelectAccount(login)
   798  		if err != nil {
   799  			return err
   800  		}
   801  	} else {
   802  		// In case of keycard, we don't have keystore, but we directly have the private key
   803  		if err := b.accountManager.SetChatAccount(chatKey); err != nil {
   804  			return err
   805  		}
   806  		_, err = b.accountManager.SelectedChatAccount()
   807  		if err != nil {
   808  			return err
   809  		}
   810  
   811  		b.accountManager.SetAccountAddresses(walletAddr, watchAddrs...)
   812  		err = b.injectAccountsIntoServices()
   813  		if err != nil {
   814  			return err
   815  		}
   816  	}
   817  
   818  	err = b.multiaccountsDB.UpdateAccountTimestamp(acc.KeyUID, time.Now().Unix())
   819  	if err != nil {
   820  		b.log.Info("failed to update account")
   821  		return err
   822  	}
   823  
   824  	return nil
   825  }
   826  
   827  func (b *GethStatusBackend) accountsDB() (*accounts.Database, error) {
   828  	return accounts.NewDB(b.appDB)
   829  }
   830  
   831  func (b *GethStatusBackend) GetSettings() (*settings.Settings, error) {
   832  	accountsDB, err := b.accountsDB()
   833  	if err != nil {
   834  		return nil, err
   835  	}
   836  
   837  	settings, err := accountsDB.GetSettings()
   838  	if err != nil {
   839  		return nil, err
   840  	}
   841  
   842  	return &settings, nil
   843  }
   844  
   845  func (b *GethStatusBackend) GetEnsUsernames() ([]*ens.UsernameDetail, error) {
   846  	db := ens.NewEnsDatabase(b.appDB)
   847  	removed := false
   848  	return db.GetEnsUsernames(&removed)
   849  }
   850  
   851  func (b *GethStatusBackend) MigrateKeyStoreDir(acc multiaccounts.Account, password, oldDir, newDir string) error {
   852  	err := b.ensureDBsOpened(acc, password)
   853  	if err != nil {
   854  		return err
   855  	}
   856  
   857  	accountDB, err := accounts.NewDB(b.appDB)
   858  	if err != nil {
   859  		return err
   860  	}
   861  	accounts, err := accountDB.GetActiveAccounts()
   862  	if err != nil {
   863  		return err
   864  	}
   865  	settings, err := accountDB.GetSettings()
   866  	if err != nil {
   867  		return err
   868  	}
   869  	addresses := []string{settings.EIP1581Address.Hex(), settings.WalletRootAddress.Hex()}
   870  	for _, account := range accounts {
   871  		addresses = append(addresses, account.Address.Hex())
   872  	}
   873  	err = b.accountManager.MigrateKeyStoreDir(oldDir, newDir, addresses)
   874  	if err != nil {
   875  		return err
   876  	}
   877  
   878  	return nil
   879  }
   880  
   881  func (b *GethStatusBackend) Login(keyUID, password string) error {
   882  	return b.startNodeWithAccount(multiaccounts.Account{KeyUID: keyUID}, password, nil, nil)
   883  }
   884  
   885  func (b *GethStatusBackend) StartNodeWithAccount(acc multiaccounts.Account, password string, nodecfg *params.NodeConfig, chatKey *ecdsa.PrivateKey) error {
   886  	err := b.startNodeWithAccount(acc, password, nodecfg, chatKey)
   887  	if err != nil {
   888  		// Stop node for clean up
   889  		_ = b.StopNode()
   890  	}
   891  	// get logged in
   892  	if !b.LocalPairingStateManager.IsPairing() {
   893  		return b.LoggedIn(acc.KeyUID, err)
   894  	}
   895  	return err
   896  }
   897  
   898  func (b *GethStatusBackend) LoggedIn(keyUID string, err error) error {
   899  	if err != nil {
   900  		signal.SendLoggedIn(nil, nil, nil, err)
   901  		return err
   902  	}
   903  	settings, err := b.GetSettings()
   904  	if err != nil {
   905  		return err
   906  	}
   907  	account, err := b.getAccountByKeyUID(keyUID)
   908  	if err != nil {
   909  		return err
   910  	}
   911  
   912  	ensUsernames, err := b.GetEnsUsernames()
   913  	if err != nil {
   914  		return err
   915  	}
   916  	var ensUsernamesJSON json.RawMessage
   917  	if ensUsernames != nil {
   918  		ensUsernamesJSON, err = json.Marshal(ensUsernames)
   919  		if err != nil {
   920  			return err
   921  		}
   922  	}
   923  	signal.SendLoggedIn(account, settings, ensUsernamesJSON, nil)
   924  	return nil
   925  }
   926  
   927  func (b *GethStatusBackend) ExportUnencryptedDatabase(acc multiaccounts.Account, password, directory string) error {
   928  	b.mu.Lock()
   929  	defer b.mu.Unlock()
   930  	if b.appDB != nil {
   931  		return nil
   932  	}
   933  	if len(b.rootDataDir) == 0 {
   934  		return errors.New("root datadir wasn't provided")
   935  	}
   936  
   937  	dbPath, err := b.runDBFileMigrations(acc, password)
   938  	if err != nil {
   939  		return err
   940  	}
   941  
   942  	err = sqlite.DecryptDB(dbPath, directory, password, acc.KDFIterations)
   943  	if err != nil {
   944  		b.log.Error("failed to initialize db", "err", err)
   945  		return err
   946  	}
   947  	return nil
   948  }
   949  
   950  func (b *GethStatusBackend) ImportUnencryptedDatabase(acc multiaccounts.Account, password, databasePath string) error {
   951  	b.mu.Lock()
   952  	defer b.mu.Unlock()
   953  	if b.appDB != nil {
   954  		return nil
   955  	}
   956  
   957  	path, err := b.getAppDBPath(acc.KeyUID)
   958  	if err != nil {
   959  		return err
   960  	}
   961  
   962  	err = sqlite.EncryptDB(databasePath, path, password, acc.KDFIterations, signal.SendReEncryptionStarted, signal.SendReEncryptionFinished)
   963  	if err != nil {
   964  		b.log.Error("failed to initialize db", "err", err)
   965  		return err
   966  	}
   967  	return nil
   968  }
   969  
   970  func (b *GethStatusBackend) reEncryptKeyStoreDir(currentPassword string, newPassword string) error {
   971  	config := b.StatusNode().Config()
   972  	keyDir := ""
   973  	if config == nil {
   974  		keyDir = b.accountManager.Keydir
   975  	} else {
   976  		keyDir = config.KeyStoreDir
   977  	}
   978  
   979  	if keyDir != "" {
   980  		err := b.accountManager.ReEncryptKeyStoreDir(keyDir, currentPassword, newPassword)
   981  		if err != nil {
   982  			return fmt.Errorf("ReEncryptKeyStoreDir error: %v", err)
   983  		}
   984  	}
   985  	return nil
   986  }
   987  
   988  func (b *GethStatusBackend) ChangeDatabasePassword(keyUID string, password string, newPassword string) error {
   989  	account, err := b.multiaccountsDB.GetAccount(keyUID)
   990  	if err != nil {
   991  		return err
   992  	}
   993  
   994  	internalDbPath, err := dbsetup.GetDBFilename(b.appDB)
   995  	if err != nil {
   996  		return fmt.Errorf("failed to get database file name, %w", err)
   997  	}
   998  
   999  	appDBPath, err := b.getAppDBPath(keyUID)
  1000  	if err != nil {
  1001  		return err
  1002  	}
  1003  
  1004  	isCurrentAccount := appDBPath == internalDbPath
  1005  
  1006  	restartNode := func() {
  1007  		if isCurrentAccount {
  1008  			if err != nil {
  1009  				// TODO https://github.com/status-im/status-go/issues/3906
  1010  				// Fix restarting node, as it always fails but the error is ignored
  1011  				// because UI calls Logout and Quit afterwards. It should not be UI-dependent
  1012  				// and should be handled gracefully here if it makes sense to run dummy node after
  1013  				// logout
  1014  				_ = b.startNodeWithAccount(*account, password, nil, nil)
  1015  			} else {
  1016  				_ = b.startNodeWithAccount(*account, newPassword, nil, nil)
  1017  			}
  1018  		}
  1019  	}
  1020  	defer restartNode()
  1021  
  1022  	logout := func() {
  1023  		if isCurrentAccount {
  1024  			_ = b.Logout()
  1025  		}
  1026  	}
  1027  	noLogout := func() {}
  1028  
  1029  	// First change app DB password, because it also reencrypts the keystore,
  1030  	// otherwise if we call changeWalletDbPassword first and logout, we will fail
  1031  	// to reencrypt	the keystore
  1032  	err = b.changeAppDBPassword(account, logout, password, newPassword)
  1033  	if err != nil {
  1034  		return err
  1035  	}
  1036  
  1037  	// Already logged out but pass a param to decouple the logic for testing
  1038  	err = b.changeWalletDBPassword(account, noLogout, password, newPassword)
  1039  	if err != nil {
  1040  		// Revert the password to original
  1041  		err2 := b.changeAppDBPassword(account, noLogout, newPassword, password)
  1042  		if err2 != nil {
  1043  			log.Error("failed to revert app db password", "err", err2)
  1044  		}
  1045  
  1046  		return err
  1047  	}
  1048  
  1049  	return nil
  1050  }
  1051  
  1052  func (b *GethStatusBackend) changeAppDBPassword(account *multiaccounts.Account, logout func(), password string, newPassword string) error {
  1053  	tmpDbPath, cleanup, err := b.createTempDBFile("v4.db")
  1054  	if err != nil {
  1055  		return err
  1056  	}
  1057  	defer cleanup()
  1058  
  1059  	dbPath, err := b.getAppDBPath(account.KeyUID)
  1060  	if err != nil {
  1061  		return err
  1062  	}
  1063  
  1064  	// Exporting database to a temporary file with a new password
  1065  	err = sqlite.ExportDB(dbPath, password, account.KDFIterations, tmpDbPath, newPassword, signal.SendReEncryptionStarted, signal.SendReEncryptionFinished)
  1066  	if err != nil {
  1067  		return err
  1068  	}
  1069  
  1070  	err = b.reEncryptKeyStoreDir(password, newPassword)
  1071  	if err != nil {
  1072  		return err
  1073  	}
  1074  
  1075  	// Replacing the old database with the new one requires closing all connections to the database
  1076  	// This is done by stopping the node and restarting it with the new DB
  1077  	logout()
  1078  
  1079  	// Replacing the old database files with the new ones, ignoring the wal and shm errors
  1080  	replaceCleanup, err := replaceDBFile(dbPath, tmpDbPath)
  1081  	if replaceCleanup != nil {
  1082  		defer replaceCleanup()
  1083  	}
  1084  
  1085  	if err != nil {
  1086  		// Restore the old account
  1087  		_ = b.reEncryptKeyStoreDir(newPassword, password)
  1088  		return err
  1089  	}
  1090  
  1091  	return nil
  1092  }
  1093  
  1094  func (b *GethStatusBackend) changeWalletDBPassword(account *multiaccounts.Account, logout func(), password string, newPassword string) error {
  1095  	tmpDbPath, cleanup, err := b.createTempDBFile("wallet.db")
  1096  	if err != nil {
  1097  		return err
  1098  	}
  1099  	defer cleanup()
  1100  
  1101  	dbPath, err := b.getWalletDBPath(account.KeyUID)
  1102  	if err != nil {
  1103  		return err
  1104  	}
  1105  
  1106  	// Exporting database to a temporary file with a new password
  1107  	err = sqlite.ExportDB(dbPath, password, account.KDFIterations, tmpDbPath, newPassword, signal.SendReEncryptionStarted, signal.SendReEncryptionFinished)
  1108  	if err != nil {
  1109  		return err
  1110  	}
  1111  
  1112  	// Replacing the old database with the new one requires closing all connections to the database
  1113  	// This is done by stopping the node and restarting it with the new DB
  1114  	logout()
  1115  
  1116  	// Replacing the old database files with the new ones, ignoring the wal and shm errors
  1117  	replaceCleanup, err := replaceDBFile(dbPath, tmpDbPath)
  1118  	if replaceCleanup != nil {
  1119  		defer replaceCleanup()
  1120  	}
  1121  	return err
  1122  }
  1123  
  1124  func (b *GethStatusBackend) createTempDBFile(pattern string) (tmpDbPath string, cleanup func(), err error) {
  1125  	if len(b.rootDataDir) == 0 {
  1126  		err = errors.New("root datadir wasn't provided")
  1127  		return
  1128  	}
  1129  	rootDataDir := b.rootDataDir
  1130  	//On iOS, the rootDataDir value does not contain a trailing slash.
  1131  	//This is causing an incorrectly formatted temporary file path to be generated, leading to an "operation not permitted" error.
  1132  	//e.g. value of rootDataDir is `/var/mobile/.../12906D5A-E831-49E9-BBE7-5FFE8E805D8A/Library`,
  1133  	//the file path generated is something like `/var/mobile/.../12906D5A-E831-49E9-BBE7-5FFE8E805D8A/123-v4.db`
  1134  	//which removed `Library` from the path.
  1135  	if !strings.HasSuffix(rootDataDir, "/") {
  1136  		rootDataDir += "/"
  1137  	}
  1138  	file, err := os.CreateTemp(filepath.Dir(rootDataDir), "*-"+pattern)
  1139  	if err != nil {
  1140  		return
  1141  	}
  1142  	err = file.Close()
  1143  	if err != nil {
  1144  		return
  1145  	}
  1146  
  1147  	tmpDbPath = file.Name()
  1148  	cleanup = func() {
  1149  		filePath := file.Name()
  1150  		_ = os.Remove(filePath)
  1151  		_ = os.Remove(filePath + "-wal")
  1152  		_ = os.Remove(filePath + "-shm")
  1153  		_ = os.Remove(filePath + "-journal")
  1154  	}
  1155  	return
  1156  }
  1157  
  1158  func replaceDBFile(dbPath string, newDBPath string) (cleanup func(), err error) {
  1159  	err = os.Rename(newDBPath, dbPath)
  1160  	if err != nil {
  1161  		return
  1162  	}
  1163  
  1164  	cleanup = func() {
  1165  		_ = os.Remove(dbPath + "-wal")
  1166  		_ = os.Remove(dbPath + "-shm")
  1167  		_ = os.Rename(newDBPath+"-wal", dbPath+"-wal")
  1168  		_ = os.Rename(newDBPath+"-shm", dbPath+"-shm")
  1169  	}
  1170  
  1171  	return
  1172  }
  1173  
  1174  func (b *GethStatusBackend) ConvertToKeycardAccount(account multiaccounts.Account, s settings.Settings, keycardUID string, password string, newPassword string) error {
  1175  	messenger := b.Messenger()
  1176  	if messenger == nil {
  1177  		return errors.New("cannot resolve messenger instance")
  1178  	}
  1179  
  1180  	err := b.multiaccountsDB.UpdateAccountKeycardPairing(account.KeyUID, account.KeycardPairing)
  1181  	if err != nil {
  1182  		return err
  1183  	}
  1184  
  1185  	err = b.ensureDBsOpened(account, password)
  1186  	if err != nil {
  1187  		return err
  1188  	}
  1189  
  1190  	accountDB, err := accounts.NewDB(b.appDB)
  1191  	if err != nil {
  1192  		return err
  1193  	}
  1194  
  1195  	keypair, err := accountDB.GetKeypairByKeyUID(account.KeyUID)
  1196  	if err != nil {
  1197  		if err == accounts.ErrDbKeypairNotFound {
  1198  			return errors.New("cannot convert an unknown keypair")
  1199  		}
  1200  		return err
  1201  	}
  1202  
  1203  	err = accountDB.SaveSettingField(settings.KeycardInstanceUID, s.KeycardInstanceUID)
  1204  	if err != nil {
  1205  		return err
  1206  	}
  1207  
  1208  	err = accountDB.SaveSettingField(settings.KeycardPairedOn, s.KeycardPairedOn)
  1209  	if err != nil {
  1210  		return err
  1211  	}
  1212  
  1213  	err = accountDB.SaveSettingField(settings.KeycardPairing, s.KeycardPairing)
  1214  	if err != nil {
  1215  		return err
  1216  	}
  1217  
  1218  	err = accountDB.SaveSettingField(settings.Mnemonic, nil)
  1219  	if err != nil {
  1220  		return err
  1221  	}
  1222  
  1223  	err = accountDB.SaveSettingField(settings.ProfileMigrationNeeded, false)
  1224  	if err != nil {
  1225  		return err
  1226  	}
  1227  
  1228  	// This check is added due to mobile app cause it doesn't support a Keycard features as desktop app.
  1229  	// We should remove the following line once mobile and desktop app align.
  1230  	if len(keycardUID) > 0 {
  1231  		displayName, err := accountDB.DisplayName()
  1232  		if err != nil {
  1233  			return err
  1234  		}
  1235  
  1236  		position, err := accountDB.GetPositionForNextNewKeycard()
  1237  		if err != nil {
  1238  			return err
  1239  		}
  1240  
  1241  		kc := accounts.Keycard{
  1242  			KeycardUID:    keycardUID,
  1243  			KeycardName:   displayName,
  1244  			KeycardLocked: false,
  1245  			KeyUID:        account.KeyUID,
  1246  			Position:      position,
  1247  		}
  1248  
  1249  		for _, acc := range keypair.Accounts {
  1250  			kc.AccountsAddresses = append(kc.AccountsAddresses, acc.Address)
  1251  		}
  1252  		err = messenger.SaveOrUpdateKeycard(context.Background(), &kc)
  1253  		if err != nil {
  1254  			return err
  1255  		}
  1256  	}
  1257  
  1258  	masterAddress, err := accountDB.GetMasterAddress()
  1259  	if err != nil {
  1260  		return err
  1261  	}
  1262  
  1263  	eip1581Address, err := accountDB.GetEIP1581Address()
  1264  	if err != nil {
  1265  		return err
  1266  	}
  1267  
  1268  	walletRootAddress, err := accountDB.GetWalletRootAddress()
  1269  	if err != nil {
  1270  		return err
  1271  	}
  1272  
  1273  	err = b.closeDBs()
  1274  	if err != nil {
  1275  		return err
  1276  	}
  1277  
  1278  	err = b.ChangeDatabasePassword(account.KeyUID, password, newPassword)
  1279  	if err != nil {
  1280  		return err
  1281  	}
  1282  
  1283  	// We need to delete all accounts for the Keycard which is being added
  1284  	for _, acc := range keypair.Accounts {
  1285  		err = b.accountManager.DeleteAccount(acc.Address)
  1286  		if err != nil {
  1287  			return err
  1288  		}
  1289  	}
  1290  
  1291  	err = b.accountManager.DeleteAccount(masterAddress)
  1292  	if err != nil {
  1293  		return err
  1294  	}
  1295  
  1296  	err = b.accountManager.DeleteAccount(eip1581Address)
  1297  	if err != nil {
  1298  		return err
  1299  	}
  1300  
  1301  	err = b.accountManager.DeleteAccount(walletRootAddress)
  1302  	if err != nil {
  1303  		return err
  1304  	}
  1305  
  1306  	return nil
  1307  }
  1308  
  1309  func (b *GethStatusBackend) RestoreAccountAndLogin(request *requests.RestoreAccount) (*multiaccounts.Account, error) {
  1310  
  1311  	if err := request.Validate(); err != nil {
  1312  		return nil, err
  1313  	}
  1314  
  1315  	response, err := b.generateOrImportAccount(request.Mnemonic, 0, request.FetchBackup, &request.CreateAccount)
  1316  	if err != nil {
  1317  		return nil, err
  1318  	}
  1319  
  1320  	err = b.StartNodeWithAccountAndInitialConfig(
  1321  		*response.account,
  1322  		request.Password,
  1323  		*response.settings,
  1324  		response.nodeConfig,
  1325  		response.subAccounts,
  1326  		response.chatPrivateKey,
  1327  	)
  1328  
  1329  	if err != nil {
  1330  		b.log.Error("start node", err)
  1331  		return nil, err
  1332  	}
  1333  
  1334  	return response.account, nil
  1335  }
  1336  
  1337  func (b *GethStatusBackend) RestoreKeycardAccountAndLogin(request *requests.RestoreAccount) (*multiaccounts.Account, error) {
  1338  	if err := request.Validate(); err != nil {
  1339  		return nil, err
  1340  	}
  1341  
  1342  	keyStoreDir, err := b.InitKeyStoreDirWithAccount(request.RootDataDir, request.Keycard.KeyUID)
  1343  	if err != nil {
  1344  		return nil, err
  1345  	}
  1346  
  1347  	derivedAddresses := map[string]generator.AccountInfo{
  1348  		pathDefaultChat: {
  1349  			Address:    request.Keycard.WhisperAddress,
  1350  			PublicKey:  request.Keycard.WhisperPublicKey,
  1351  			PrivateKey: request.Keycard.WhisperPrivateKey,
  1352  		},
  1353  		pathWalletRoot: {
  1354  			Address: request.Keycard.WalletRootAddress,
  1355  		},
  1356  		pathDefaultWallet: {
  1357  			Address:   request.Keycard.WalletAddress,
  1358  			PublicKey: request.Keycard.WalletPublicKey,
  1359  		},
  1360  		pathEIP1581: {
  1361  			Address: request.Keycard.Eip1581Address,
  1362  		},
  1363  		pathEncryption: {
  1364  			PublicKey: request.Keycard.EncryptionPublicKey,
  1365  		},
  1366  	}
  1367  
  1368  	input := &prepareAccountInput{
  1369  		customizationColorClock: 0,
  1370  		accountID:               "", // empty for keycard
  1371  		keyUID:                  request.Keycard.KeyUID,
  1372  		address:                 request.Keycard.Address,
  1373  		mnemonic:                "",
  1374  		restoringAccount:        true,
  1375  		derivedAddresses:        derivedAddresses,
  1376  		fetchBackup:             request.FetchBackup, // WARNING: Ensure this value is correct
  1377  		keyStoreDir:             keyStoreDir,
  1378  	}
  1379  
  1380  	response, err := b.prepareNodeAccount(&request.CreateAccount, input)
  1381  	if err != nil {
  1382  		return nil, err
  1383  	}
  1384  
  1385  	err = b.StartNodeWithAccountAndInitialConfig(
  1386  		*response.account,
  1387  		request.Password,
  1388  		*response.settings,
  1389  		response.nodeConfig,
  1390  		response.subAccounts,
  1391  		response.chatPrivateKey, //request.WhisperPrivateKey,
  1392  	)
  1393  
  1394  	if err != nil {
  1395  		b.log.Error("start node", err)
  1396  		return nil, errors.Wrap(err, "failed to start node")
  1397  	}
  1398  
  1399  	return response.account, nil
  1400  }
  1401  
  1402  func (b *GethStatusBackend) GetKeyUIDByMnemonic(mnemonic string) (string, error) {
  1403  	accountGenerator := b.accountManager.AccountsGenerator()
  1404  
  1405  	info, err := accountGenerator.ImportMnemonic(mnemonic, "")
  1406  	if err != nil {
  1407  		return "", err
  1408  	}
  1409  
  1410  	return info.KeyUID, nil
  1411  }
  1412  
  1413  type prepareAccountInput struct {
  1414  	customizationColorClock uint64
  1415  	accountID               string
  1416  	keyUID                  string
  1417  	address                 string
  1418  	mnemonic                string
  1419  	restoringAccount        bool
  1420  	derivedAddresses        map[string]generator.AccountInfo
  1421  	fetchBackup             bool
  1422  	keyStoreDir             string
  1423  	opts                    []params.Option
  1424  }
  1425  
  1426  type accountBundle struct {
  1427  	account        *multiaccounts.Account
  1428  	settings       *settings.Settings
  1429  	nodeConfig     *params.NodeConfig
  1430  	subAccounts    []*accounts.Account
  1431  	chatPrivateKey *ecdsa.PrivateKey
  1432  }
  1433  
  1434  func (b *GethStatusBackend) generateOrImportAccount(mnemonic string, customizationColorClock uint64, fetchBackup bool, request *requests.CreateAccount, opts ...params.Option) (*accountBundle, error) {
  1435  	info, err := b.generateAccountInfo(mnemonic)
  1436  	if err != nil {
  1437  		return nil, err
  1438  	}
  1439  
  1440  	keyStoreDir, err := b.InitKeyStoreDirWithAccount(request.RootDataDir, info.KeyUID)
  1441  	if err != nil {
  1442  		return nil, err
  1443  	}
  1444  
  1445  	derivedAddresses, err := b.getDerivedAddresses(info.ID)
  1446  	if err != nil {
  1447  		return nil, err
  1448  	}
  1449  
  1450  	input := &prepareAccountInput{
  1451  		customizationColorClock: customizationColorClock,
  1452  		accountID:               info.ID,
  1453  		keyUID:                  info.KeyUID,
  1454  		address:                 info.Address,
  1455  		mnemonic:                info.Mnemonic,
  1456  		restoringAccount:        mnemonic != "",
  1457  		derivedAddresses:        derivedAddresses,
  1458  		fetchBackup:             fetchBackup,
  1459  		keyStoreDir:             keyStoreDir,
  1460  		opts:                    opts,
  1461  	}
  1462  
  1463  	return b.prepareNodeAccount(request, input)
  1464  }
  1465  
  1466  func (b *GethStatusBackend) prepareNodeAccount(request *requests.CreateAccount, input *prepareAccountInput) (*accountBundle, error) {
  1467  	var err error
  1468  	response := &accountBundle{}
  1469  
  1470  	if request.KeycardInstanceUID != "" {
  1471  		request.Password = input.derivedAddresses[pathEncryption].PublicKey
  1472  	}
  1473  
  1474  	// NOTE: I intentionally left this condition separately and not an `else` branch. Technically it's an `else`,
  1475  	// 		 but the statements inside are not the opposite statement of the first statement. It's just kinda like this:
  1476  	// 		 - replace password when we're using keycard
  1477  	// 		 - store account when we're not using keycard
  1478  	if request.KeycardInstanceUID == "" {
  1479  		err = b.storeAccount(input.accountID, request.Password, paths)
  1480  		if err != nil {
  1481  			return nil, err
  1482  		}
  1483  	}
  1484  
  1485  	response.account, err = b.buildAccount(request, input)
  1486  	if err != nil {
  1487  		return nil, errors.Wrap(err, "failed to build account")
  1488  	}
  1489  
  1490  	response.settings, err = b.prepareSettings(request, input)
  1491  	if err != nil {
  1492  		return nil, errors.Wrap(err, "failed to prepare settings")
  1493  	}
  1494  
  1495  	response.nodeConfig, err = b.prepareConfig(request, input, response.settings.InstallationID)
  1496  	if err != nil {
  1497  		return nil, errors.Wrap(err, "failed to prepare node config")
  1498  	}
  1499  
  1500  	response.subAccounts, err = b.prepareSubAccounts(request, input)
  1501  	if err != nil {
  1502  		return nil, errors.Wrap(err, "failed to prepare sub accounts")
  1503  	}
  1504  
  1505  	response, err = b.prepareForKeycard(request, input, response)
  1506  	if err != nil {
  1507  		return nil, errors.Wrap(err, "failed to prepare for keycard")
  1508  	}
  1509  
  1510  	return response, nil
  1511  }
  1512  
  1513  func (b *GethStatusBackend) InitKeyStoreDirWithAccount(rootDataDir, keyUID string) (string, error) {
  1514  	b.UpdateRootDataDir(rootDataDir)
  1515  	keyStoreRelativePath, keystoreAbsolutePath := DefaultKeystorePath(rootDataDir, keyUID)
  1516  	// Initialize keystore dir with account
  1517  	return keyStoreRelativePath, b.accountManager.InitKeystore(keystoreAbsolutePath)
  1518  }
  1519  
  1520  func (b *GethStatusBackend) generateAccountInfo(mnemonic string) (*generator.GeneratedAccountInfo, error) {
  1521  	accountGenerator := b.accountManager.AccountsGenerator()
  1522  
  1523  	var info generator.GeneratedAccountInfo
  1524  	var err error
  1525  	if mnemonic == "" {
  1526  		// generate 1(n) account with default mnemonic length and no passphrase
  1527  		generatedAccountInfos, err := accountGenerator.Generate(defaultMnemonicLength, 1, "")
  1528  		info = generatedAccountInfos[0]
  1529  
  1530  		if err != nil {
  1531  			return nil, err
  1532  		}
  1533  	} else {
  1534  
  1535  		info, err = accountGenerator.ImportMnemonic(mnemonic, "")
  1536  		if err != nil {
  1537  			return nil, err
  1538  		}
  1539  	}
  1540  
  1541  	return &info, nil
  1542  }
  1543  
  1544  func (b *GethStatusBackend) storeAccount(id string, password string, paths []string) error {
  1545  	accountGenerator := b.accountManager.AccountsGenerator()
  1546  
  1547  	_, err := accountGenerator.StoreAccount(id, password)
  1548  	if err != nil {
  1549  		return err
  1550  	}
  1551  
  1552  	_, err = accountGenerator.StoreDerivedAccounts(id, password, paths)
  1553  	if err != nil {
  1554  		return err
  1555  	}
  1556  
  1557  	return nil
  1558  }
  1559  
  1560  func (b *GethStatusBackend) buildAccount(request *requests.CreateAccount, input *prepareAccountInput) (*multiaccounts.Account, error) {
  1561  	err := b.OpenAccounts()
  1562  	if err != nil {
  1563  		return nil, err
  1564  	}
  1565  
  1566  	acc := &multiaccounts.Account{
  1567  		KeyUID:                  input.keyUID,
  1568  		Name:                    request.DisplayName,
  1569  		CustomizationColor:      multiacccommon.CustomizationColor(request.CustomizationColor),
  1570  		CustomizationColorClock: input.customizationColorClock,
  1571  		KDFIterations:           request.KdfIterations,
  1572  		Timestamp:               time.Now().Unix(),
  1573  	}
  1574  
  1575  	if acc.KDFIterations == 0 {
  1576  		acc.KDFIterations = dbsetup.ReducedKDFIterationsNumber
  1577  	}
  1578  
  1579  	if request.ImagePath != "" {
  1580  		imageCropRectangle := request.ImageCropRectangle
  1581  		if imageCropRectangle == nil {
  1582  			// Default crop rectangle used by mobile
  1583  			imageCropRectangle = &requests.ImageCropRectangle{
  1584  				Ax: 0,
  1585  				Ay: 0,
  1586  				Bx: 1000,
  1587  				By: 1000,
  1588  			}
  1589  		}
  1590  
  1591  		iis, err := images.GenerateIdentityImages(request.ImagePath,
  1592  			imageCropRectangle.Ax, imageCropRectangle.Ay, imageCropRectangle.Bx, imageCropRectangle.By)
  1593  
  1594  		if err != nil {
  1595  			return nil, err
  1596  		}
  1597  		acc.Images = iis
  1598  	}
  1599  
  1600  	return acc, nil
  1601  }
  1602  
  1603  func (b *GethStatusBackend) prepareSettings(request *requests.CreateAccount, input *prepareAccountInput) (*settings.Settings, error) {
  1604  	settings, err := defaultSettings(input.keyUID, input.address, input.derivedAddresses)
  1605  	if err != nil {
  1606  		return nil, err
  1607  	}
  1608  
  1609  	settings.DeviceName = request.DeviceName
  1610  	settings.DisplayName = request.DisplayName
  1611  	settings.PreviewPrivacy = request.PreviewPrivacy
  1612  	settings.CurrentNetwork = request.CurrentNetwork
  1613  	settings.TestNetworksEnabled = request.TestNetworksEnabled
  1614  	if !input.restoringAccount {
  1615  		settings.Mnemonic = &input.mnemonic
  1616  		// TODO(rasom): uncomment it as soon as address will be properly
  1617  		// marked as shown on mobile client
  1618  		//settings.MnemonicWasNotShown = true
  1619  	}
  1620  
  1621  	if request.WakuV2Fleet != "" {
  1622  		settings.Fleet = &request.WakuV2Fleet
  1623  	}
  1624  
  1625  	return settings, nil
  1626  }
  1627  
  1628  func (b *GethStatusBackend) prepareConfig(request *requests.CreateAccount, input *prepareAccountInput, installationID string) (*params.NodeConfig, error) {
  1629  	nodeConfig, err := DefaultNodeConfig(installationID, request, input.opts...)
  1630  	if err != nil {
  1631  		return nil, err
  1632  	}
  1633  	nodeConfig.ProcessBackedupMessages = input.fetchBackup
  1634  
  1635  	// when we set nodeConfig.KeyStoreDir, value of nodeConfig.KeyStoreDir should not contain the rootDataDir
  1636  	// loadNodeConfig will add rootDataDir to nodeConfig.KeyStoreDir
  1637  	nodeConfig.KeyStoreDir = input.keyStoreDir
  1638  
  1639  	return nodeConfig, nil
  1640  }
  1641  
  1642  func (b *GethStatusBackend) prepareSubAccounts(request *requests.CreateAccount, input *prepareAccountInput) ([]*accounts.Account, error) {
  1643  	emoji, err := randomWalletEmoji()
  1644  	if err != nil {
  1645  		return nil, errors.Wrap(err, "failed to generate random emoji")
  1646  	}
  1647  
  1648  	walletDerivedAccount := input.derivedAddresses[pathDefaultWallet]
  1649  	walletAccount := &accounts.Account{
  1650  		PublicKey:          types.Hex2Bytes(walletDerivedAccount.PublicKey),
  1651  		KeyUID:             input.keyUID,
  1652  		Address:            types.HexToAddress(walletDerivedAccount.Address),
  1653  		ColorID:            multiacccommon.CustomizationColor(request.CustomizationColor),
  1654  		Emoji:              emoji,
  1655  		Wallet:             true,
  1656  		Path:               pathDefaultWallet,
  1657  		Name:               walletAccountDefaultName,
  1658  		AddressWasNotShown: !input.restoringAccount,
  1659  	}
  1660  
  1661  	chatDerivedAccount := input.derivedAddresses[pathDefaultChat]
  1662  	chatAccount := &accounts.Account{
  1663  		PublicKey: types.Hex2Bytes(chatDerivedAccount.PublicKey),
  1664  		KeyUID:    input.keyUID,
  1665  		Address:   types.HexToAddress(chatDerivedAccount.Address),
  1666  		Name:      request.DisplayName,
  1667  		Chat:      true,
  1668  		Path:      pathDefaultChat,
  1669  	}
  1670  
  1671  	return []*accounts.Account{walletAccount, chatAccount}, nil
  1672  }
  1673  
  1674  func (b *GethStatusBackend) prepareForKeycard(request *requests.CreateAccount, input *prepareAccountInput, response *accountBundle) (*accountBundle, error) {
  1675  	if request.KeycardInstanceUID == "" {
  1676  		return response, nil
  1677  	}
  1678  
  1679  	kp := wallet.NewKeycardPairings()
  1680  	kp.SetKeycardPairingsFile(response.nodeConfig.KeycardPairingDataFile)
  1681  	pairings, err := kp.GetPairings()
  1682  	if err != nil {
  1683  		return nil, errors.Wrap(err, "failed to get keycard pairings")
  1684  	}
  1685  
  1686  	keycard, ok := pairings[request.KeycardInstanceUID]
  1687  	if !ok {
  1688  		return nil, errors.New("keycard not found in pairings file")
  1689  	}
  1690  
  1691  	response.settings.KeycardInstanceUID = request.KeycardInstanceUID
  1692  	response.settings.KeycardPairedOn = time.Now().Unix()
  1693  	response.settings.KeycardPairing = keycard.Key
  1694  	response.account.KeycardPairing = keycard.Key
  1695  
  1696  	privateKeyHex := strings.TrimPrefix(input.derivedAddresses[pathDefaultChat].PrivateKey, "0x")
  1697  	response.chatPrivateKey, err = crypto.HexToECDSA(privateKeyHex)
  1698  	if err != nil {
  1699  		return nil, errors.Wrap(err, "failed to parse chat private key hex")
  1700  	}
  1701  
  1702  	return response, nil
  1703  }
  1704  
  1705  func (b *GethStatusBackend) getDerivedAddresses(id string) (map[string]generator.AccountInfo, error) {
  1706  	accountGenerator := b.accountManager.AccountsGenerator()
  1707  	return accountGenerator.DeriveAddresses(id, paths)
  1708  }
  1709  
  1710  // CreateAccountAndLogin creates a new account and logs in with it.
  1711  // NOTE: requests.CreateAccount is used for public, params.Option maybe used for internal usage.
  1712  func (b *GethStatusBackend) CreateAccountAndLogin(request *requests.CreateAccount, opts ...params.Option) (*multiaccounts.Account, error) {
  1713  	validation := &requests.CreateAccountValidation{
  1714  		AllowEmptyDisplayName: false,
  1715  	}
  1716  	if err := request.Validate(validation); err != nil {
  1717  		return nil, err
  1718  	}
  1719  
  1720  	response, err := b.generateOrImportAccount("", 1, false, request, opts...)
  1721  	if err != nil {
  1722  		return nil, err
  1723  	}
  1724  
  1725  	err = b.StartNodeWithAccountAndInitialConfig(
  1726  		*response.account,
  1727  		request.Password,
  1728  		*response.settings,
  1729  		response.nodeConfig,
  1730  		response.subAccounts,
  1731  		response.chatPrivateKey,
  1732  	)
  1733  
  1734  	if err != nil {
  1735  		b.log.Error("start node", err)
  1736  		return nil, err
  1737  	}
  1738  
  1739  	return response.account, nil
  1740  }
  1741  
  1742  func (b *GethStatusBackend) ConvertToRegularAccount(mnemonic string, currPassword string, newPassword string) error {
  1743  	messenger := b.Messenger()
  1744  	if messenger == nil {
  1745  		return errors.New("cannot resolve messenger instance")
  1746  	}
  1747  
  1748  	mnemonicNoExtraSpaces := strings.Join(strings.Fields(mnemonic), " ")
  1749  	accountInfo, err := b.accountManager.AccountsGenerator().ImportMnemonic(mnemonicNoExtraSpaces, "")
  1750  	if err != nil {
  1751  		return err
  1752  	}
  1753  
  1754  	kdfIterations, err := b.multiaccountsDB.GetAccountKDFIterationsNumber(accountInfo.KeyUID)
  1755  	if err != nil {
  1756  		return err
  1757  	}
  1758  
  1759  	err = b.ensureDBsOpened(multiaccounts.Account{KeyUID: accountInfo.KeyUID, KDFIterations: kdfIterations}, currPassword)
  1760  	if err != nil {
  1761  		return err
  1762  	}
  1763  
  1764  	db, err := accounts.NewDB(b.appDB)
  1765  	if err != nil {
  1766  		return err
  1767  	}
  1768  
  1769  	knownAccounts, err := db.GetActiveAccounts()
  1770  	if err != nil {
  1771  		return err
  1772  	}
  1773  
  1774  	// We add these two paths, cause others will be added via `StoreAccount` function call
  1775  	const pathWalletRoot = "m/44'/60'/0'/0"
  1776  	const pathEIP1581 = "m/43'/60'/1581'"
  1777  	var paths []string
  1778  	paths = append(paths, pathWalletRoot, pathEIP1581)
  1779  	for _, acc := range knownAccounts {
  1780  		if accountInfo.KeyUID == acc.KeyUID {
  1781  			paths = append(paths, acc.Path)
  1782  		}
  1783  	}
  1784  
  1785  	_, err = b.accountManager.AccountsGenerator().StoreAccount(accountInfo.ID, currPassword)
  1786  	if err != nil {
  1787  		return err
  1788  	}
  1789  
  1790  	_, err = b.accountManager.AccountsGenerator().StoreDerivedAccounts(accountInfo.ID, currPassword, paths)
  1791  	if err != nil {
  1792  		return err
  1793  	}
  1794  
  1795  	err = b.multiaccountsDB.UpdateAccountKeycardPairing(accountInfo.KeyUID, "")
  1796  	if err != nil {
  1797  		return err
  1798  	}
  1799  
  1800  	err = messenger.DeleteAllKeycardsWithKeyUID(context.Background(), accountInfo.KeyUID)
  1801  	if err != nil {
  1802  		return err
  1803  	}
  1804  
  1805  	err = db.SaveSettingField(settings.KeycardInstanceUID, "")
  1806  	if err != nil {
  1807  		return err
  1808  	}
  1809  
  1810  	err = db.SaveSettingField(settings.KeycardPairedOn, 0)
  1811  	if err != nil {
  1812  		return err
  1813  	}
  1814  
  1815  	err = db.SaveSettingField(settings.KeycardPairing, "")
  1816  	if err != nil {
  1817  		return err
  1818  	}
  1819  
  1820  	err = db.SaveSettingField(settings.ProfileMigrationNeeded, false)
  1821  	if err != nil {
  1822  		return err
  1823  	}
  1824  
  1825  	err = b.closeDBs()
  1826  	if err != nil {
  1827  		return err
  1828  	}
  1829  
  1830  	return b.ChangeDatabasePassword(accountInfo.KeyUID, currPassword, newPassword)
  1831  }
  1832  
  1833  func (b *GethStatusBackend) VerifyDatabasePassword(keyUID string, password string) error {
  1834  	kdfIterations, err := b.multiaccountsDB.GetAccountKDFIterationsNumber(keyUID)
  1835  	if err != nil {
  1836  		return err
  1837  	}
  1838  
  1839  	if !b.appDBExists(keyUID) || !b.walletDBExists(keyUID) {
  1840  		return errors.New("One or more databases not created")
  1841  	}
  1842  
  1843  	err = b.ensureDBsOpened(multiaccounts.Account{KeyUID: keyUID, KDFIterations: kdfIterations}, password)
  1844  	if err != nil {
  1845  		return err
  1846  	}
  1847  
  1848  	err = b.closeDBs()
  1849  	if err != nil {
  1850  		return err
  1851  	}
  1852  
  1853  	return nil
  1854  }
  1855  
  1856  func enrichMultiAccountBySubAccounts(account *multiaccounts.Account, subaccs []*accounts.Account) error {
  1857  	if account.ColorHash != nil && account.ColorID != 0 {
  1858  		return nil
  1859  	}
  1860  
  1861  	for i, acc := range subaccs {
  1862  		subaccs[i].KeyUID = account.KeyUID
  1863  		if acc.Chat {
  1864  			pk := string(acc.PublicKey.Bytes())
  1865  			colorHash, err := colorhash.GenerateFor(pk)
  1866  			if err != nil {
  1867  				return err
  1868  			}
  1869  			account.ColorHash = colorHash
  1870  
  1871  			colorID, err := identityutils.ToColorID(pk)
  1872  			if err != nil {
  1873  				return err
  1874  			}
  1875  			account.ColorID = colorID
  1876  
  1877  			break
  1878  		}
  1879  	}
  1880  
  1881  	return nil
  1882  }
  1883  
  1884  func enrichMultiAccountByPublicKey(account *multiaccounts.Account, publicKey types.HexBytes) error {
  1885  	pk := string(publicKey.Bytes())
  1886  	colorHash, err := colorhash.GenerateFor(pk)
  1887  	if err != nil {
  1888  		return err
  1889  	}
  1890  	account.ColorHash = colorHash
  1891  
  1892  	colorID, err := identityutils.ToColorID(pk)
  1893  	if err != nil {
  1894  		return err
  1895  	}
  1896  	account.ColorID = colorID
  1897  
  1898  	return nil
  1899  }
  1900  
  1901  // Deprecated: Use CreateAccountAndLogin instead
  1902  func (b *GethStatusBackend) SaveAccountAndStartNodeWithKey(
  1903  	account multiaccounts.Account,
  1904  	password string,
  1905  	settings settings.Settings,
  1906  	nodecfg *params.NodeConfig,
  1907  	subaccs []*accounts.Account,
  1908  	keyHex string,
  1909  ) error {
  1910  	err := enrichMultiAccountBySubAccounts(&account, subaccs)
  1911  	if err != nil {
  1912  		return err
  1913  	}
  1914  	err = b.SaveAccount(account)
  1915  	if err != nil {
  1916  		return err
  1917  	}
  1918  	err = b.ensureDBsOpened(account, password)
  1919  	if err != nil {
  1920  		return err
  1921  	}
  1922  	err = b.saveAccountsAndSettings(settings, nodecfg, subaccs)
  1923  	if err != nil {
  1924  		return err
  1925  	}
  1926  	return b.StartNodeWithKey(account, password, keyHex, nodecfg)
  1927  }
  1928  
  1929  // StartNodeWithAccountAndInitialConfig is used after account and config was generated.
  1930  // In current setup account name and config is generated on the client side. Once/if it will be generated on
  1931  // status-go side this flow can be simplified.
  1932  // TODO: Consider passing accountBundle here directly
  1933  func (b *GethStatusBackend) StartNodeWithAccountAndInitialConfig(
  1934  	account multiaccounts.Account,
  1935  	password string,
  1936  	settings settings.Settings,
  1937  	nodecfg *params.NodeConfig,
  1938  	subaccs []*accounts.Account,
  1939  	chatKey *ecdsa.PrivateKey,
  1940  ) error {
  1941  	err := enrichMultiAccountBySubAccounts(&account, subaccs)
  1942  	if err != nil {
  1943  		return err
  1944  	}
  1945  	err = b.SaveAccount(account)
  1946  	if err != nil {
  1947  		return err
  1948  	}
  1949  	err = b.ensureDBsOpened(account, password)
  1950  	if err != nil {
  1951  		return err
  1952  	}
  1953  	err = b.saveAccountsAndSettings(settings, nodecfg, subaccs)
  1954  	if err != nil {
  1955  		return err
  1956  	}
  1957  	return b.StartNodeWithAccount(account, password, nodecfg, chatKey)
  1958  }
  1959  
  1960  // TODO: change in `saveAccountsAndSettings` function param `subaccs []*accounts.Account` parameter to `profileKeypair *accounts.Keypair` parameter
  1961  func (b *GethStatusBackend) saveAccountsAndSettings(settings settings.Settings, nodecfg *params.NodeConfig, subaccs []*accounts.Account) error {
  1962  	b.mu.Lock()
  1963  	defer b.mu.Unlock()
  1964  	accdb, err := accounts.NewDB(b.appDB)
  1965  	if err != nil {
  1966  		return err
  1967  	}
  1968  	err = accdb.CreateSettings(settings, *nodecfg)
  1969  	if err != nil {
  1970  		return err
  1971  	}
  1972  
  1973  	// In case of setting up new account either way (creating new, importing seed phrase, keycard account...) we should not
  1974  	// back up any data after login, as it was the case before, that's the reason why we're setting last backup time to the time
  1975  	// when an account was created.
  1976  	now := time.Now().Unix()
  1977  	err = accdb.SetLastBackup(uint64(now))
  1978  	if err != nil {
  1979  		return err
  1980  	}
  1981  
  1982  	keypair := &accounts.Keypair{
  1983  		KeyUID:                  settings.KeyUID,
  1984  		Name:                    settings.DisplayName,
  1985  		Type:                    accounts.KeypairTypeProfile,
  1986  		DerivedFrom:             settings.Address.String(),
  1987  		LastUsedDerivationIndex: 0,
  1988  	}
  1989  
  1990  	// When creating a new account, the chat account should have position -1, cause it doesn't participate
  1991  	// in the wallet view and default wallet account should be at position 0.
  1992  	for _, acc := range subaccs {
  1993  		if acc.Chat {
  1994  			acc.Position = -1
  1995  		}
  1996  		if acc.Wallet {
  1997  			acc.Position = 0
  1998  		}
  1999  		acc.Operable = accounts.AccountFullyOperable
  2000  		keypair.Accounts = append(keypair.Accounts, acc)
  2001  	}
  2002  
  2003  	return accdb.SaveOrUpdateKeypair(keypair)
  2004  }
  2005  
  2006  func (b *GethStatusBackend) loadNodeConfig(inputNodeCfg *params.NodeConfig) error {
  2007  	b.mu.Lock()
  2008  	defer b.mu.Unlock()
  2009  
  2010  	conf, err := nodecfg.GetNodeConfigFromDB(b.appDB)
  2011  	if err != nil {
  2012  		return err
  2013  	}
  2014  
  2015  	if inputNodeCfg != nil {
  2016  		// If an installationID is provided, we override it
  2017  		if conf != nil && conf.ShhextConfig.InstallationID != "" {
  2018  			inputNodeCfg.ShhextConfig.InstallationID = conf.ShhextConfig.InstallationID
  2019  		}
  2020  
  2021  		conf, err = b.OverwriteNodeConfigValues(conf, inputNodeCfg)
  2022  		if err != nil {
  2023  			return err
  2024  		}
  2025  	}
  2026  
  2027  	// Start WakuV1 if WakuV2 is not enabled
  2028  	conf.WakuConfig.Enabled = !conf.WakuV2Config.Enabled
  2029  	// NodeConfig.Version should be taken from params.Version
  2030  	// which is set at the compile time.
  2031  	// What's cached is usually outdated so we overwrite it here.
  2032  	conf.Version = params.Version
  2033  	conf.RootDataDir = b.rootDataDir
  2034  	conf.DataDir = filepath.Join(b.rootDataDir, conf.DataDir)
  2035  	conf.KeyStoreDir = filepath.Join(b.rootDataDir, conf.KeyStoreDir)
  2036  
  2037  	if _, err = os.Stat(conf.RootDataDir); os.IsNotExist(err) {
  2038  		if err := os.MkdirAll(conf.RootDataDir, os.ModePerm); err != nil {
  2039  			b.log.Warn("failed to create data directory", zap.Error(err))
  2040  			return err
  2041  		}
  2042  	}
  2043  
  2044  	if len(conf.LogDir) == 0 {
  2045  		conf.LogFile = filepath.Join(b.rootDataDir, conf.LogFile)
  2046  	} else {
  2047  		conf.LogFile = filepath.Join(conf.LogDir, conf.LogFile)
  2048  	}
  2049  
  2050  	b.config = conf
  2051  
  2052  	if inputNodeCfg != nil && inputNodeCfg.RuntimeLogLevel != "" {
  2053  		b.config.LogLevel = inputNodeCfg.RuntimeLogLevel
  2054  	}
  2055  
  2056  	return nil
  2057  }
  2058  
  2059  func (b *GethStatusBackend) saveNodeConfig(n *params.NodeConfig) error {
  2060  	err := nodecfg.SaveNodeConfig(b.appDB, n)
  2061  	if err != nil {
  2062  		return err
  2063  	}
  2064  	return nil
  2065  }
  2066  
  2067  func (b *GethStatusBackend) GetNodeConfig() (*params.NodeConfig, error) {
  2068  	return nodecfg.GetNodeConfigFromDB(b.appDB)
  2069  }
  2070  
  2071  func (b *GethStatusBackend) startNode(config *params.NodeConfig) (err error) {
  2072  	defer func() {
  2073  		if r := recover(); r != nil {
  2074  			err = fmt.Errorf("node crashed on start: %v", err)
  2075  		}
  2076  	}()
  2077  
  2078  	b.log.Info("status-go version details", "version", params.Version, "commit", params.GitCommit)
  2079  	b.log.Debug("starting node with config", "config", config)
  2080  	// Update config with some defaults.
  2081  	if err := config.UpdateWithDefaults(); err != nil {
  2082  		return err
  2083  	}
  2084  
  2085  	// Updating node config
  2086  	b.config = config
  2087  
  2088  	b.log.Debug("updated config with defaults", "config", config)
  2089  
  2090  	// Start by validating configuration
  2091  	if err := config.Validate(); err != nil {
  2092  		return err
  2093  	}
  2094  
  2095  	if b.accountManager.GetManager() == nil {
  2096  		err = b.accountManager.InitKeystore(config.KeyStoreDir)
  2097  		if err != nil {
  2098  			return err
  2099  		}
  2100  	}
  2101  
  2102  	manager := b.accountManager.GetManager()
  2103  	if manager == nil {
  2104  		return errors.New("ethereum accounts.Manager is nil")
  2105  	}
  2106  
  2107  	if err = b.statusNode.StartWithOptions(config, node.StartOptions{
  2108  		// The peers discovery protocols are started manually after
  2109  		// `node.ready` signal is sent.
  2110  		// It was discussed in https://github.com/status-im/status-go/pull/1333.
  2111  		StartDiscovery:  false,
  2112  		AccountsManager: manager,
  2113  	}); err != nil {
  2114  		return
  2115  	}
  2116  	b.accountManager.SetRPCClient(b.statusNode.RPCClient(), rpc.DefaultCallTimeout)
  2117  	signal.SendNodeStarted()
  2118  
  2119  	b.transactor.SetNetworkID(config.NetworkID)
  2120  	b.transactor.SetRPC(b.statusNode.RPCClient(), rpc.DefaultCallTimeout)
  2121  	b.personalAPI.SetRPC(b.statusNode.RPCClient(), rpc.DefaultCallTimeout)
  2122  
  2123  	if err = b.registerHandlers(); err != nil {
  2124  		b.log.Error("Handler registration failed", "err", err)
  2125  		return
  2126  	}
  2127  	b.log.Info("Handlers registered")
  2128  
  2129  	// Handle a case when a node is stopped and resumed.
  2130  	// If there is no account selected, an error is returned.
  2131  	if _, err := b.accountManager.SelectedChatAccount(); err == nil {
  2132  		if err := b.injectAccountsIntoServices(); err != nil {
  2133  			return err
  2134  		}
  2135  	} else if err != account.ErrNoAccountSelected {
  2136  		return err
  2137  	}
  2138  
  2139  	if b.statusNode.WalletService() != nil {
  2140  		b.statusNode.WalletService().KeycardPairings().SetKeycardPairingsFile(config.KeycardPairingDataFile)
  2141  	}
  2142  
  2143  	signal.SendNodeReady()
  2144  
  2145  	if err := b.statusNode.StartDiscovery(); err != nil {
  2146  		return err
  2147  	}
  2148  
  2149  	return nil
  2150  }
  2151  
  2152  // StopNode stop Status node. Stopped node cannot be resumed.
  2153  func (b *GethStatusBackend) StopNode() error {
  2154  	b.mu.Lock()
  2155  	defer b.mu.Unlock()
  2156  	return b.stopNode()
  2157  }
  2158  
  2159  func (b *GethStatusBackend) stopNode() error {
  2160  	if b.statusNode == nil || !b.IsNodeRunning() {
  2161  		return nil
  2162  	}
  2163  	if !b.LocalPairingStateManager.IsPairing() {
  2164  		defer signal.SendNodeStopped()
  2165  	}
  2166  
  2167  	return b.statusNode.Stop()
  2168  }
  2169  
  2170  // RestartNode restart running Status node, fails if node is not running
  2171  func (b *GethStatusBackend) RestartNode() error {
  2172  	b.mu.Lock()
  2173  	defer b.mu.Unlock()
  2174  
  2175  	if !b.IsNodeRunning() {
  2176  		return node.ErrNoRunningNode
  2177  	}
  2178  
  2179  	if err := b.stopNode(); err != nil {
  2180  		return err
  2181  	}
  2182  
  2183  	return b.startNode(b.config)
  2184  }
  2185  
  2186  // ResetChainData remove chain data from data directory.
  2187  // Node is stopped, and new node is started, with clean data directory.
  2188  func (b *GethStatusBackend) ResetChainData() error {
  2189  	b.mu.Lock()
  2190  	defer b.mu.Unlock()
  2191  
  2192  	if err := b.stopNode(); err != nil {
  2193  		return err
  2194  	}
  2195  	// config is cleaned when node is stopped
  2196  	if err := b.statusNode.ResetChainData(b.config); err != nil {
  2197  		return err
  2198  	}
  2199  	signal.SendChainDataRemoved()
  2200  	return b.startNode(b.config)
  2201  }
  2202  
  2203  // CallRPC executes public RPC requests on node's in-proc RPC server.
  2204  func (b *GethStatusBackend) CallRPC(inputJSON string) (string, error) {
  2205  	client := b.statusNode.RPCClient()
  2206  	if client == nil {
  2207  		return "", ErrRPCClientUnavailable
  2208  	}
  2209  	return client.CallRaw(inputJSON), nil
  2210  }
  2211  
  2212  // CallPrivateRPC executes public and private RPC requests on node's in-proc RPC server.
  2213  func (b *GethStatusBackend) CallPrivateRPC(inputJSON string) (string, error) {
  2214  	client := b.statusNode.RPCClient()
  2215  	if client == nil {
  2216  		return "", ErrRPCClientUnavailable
  2217  	}
  2218  	return client.CallRaw(inputJSON), nil
  2219  }
  2220  
  2221  // SendTransaction creates a new transaction and waits until it's complete.
  2222  func (b *GethStatusBackend) SendTransaction(sendArgs transactions.SendTxArgs, password string) (hash types.Hash, err error) {
  2223  	verifiedAccount, err := b.getVerifiedWalletAccount(sendArgs.From.String(), password)
  2224  	if err != nil {
  2225  		return hash, err
  2226  	}
  2227  
  2228  	hash, _, err = b.transactor.SendTransaction(sendArgs, verifiedAccount, -1)
  2229  	return hash, err
  2230  }
  2231  
  2232  func (b *GethStatusBackend) SendTransactionWithChainID(chainID uint64, sendArgs transactions.SendTxArgs, password string) (hash types.Hash, err error) {
  2233  	verifiedAccount, err := b.getVerifiedWalletAccount(sendArgs.From.String(), password)
  2234  	if err != nil {
  2235  		return hash, err
  2236  	}
  2237  
  2238  	hash, _, err = b.transactor.SendTransactionWithChainID(chainID, sendArgs, -1, verifiedAccount)
  2239  	return hash, err
  2240  }
  2241  
  2242  func (b *GethStatusBackend) SendTransactionWithSignature(sendArgs transactions.SendTxArgs, sig []byte) (hash types.Hash, err error) {
  2243  	txWithSignature, err := b.transactor.BuildTransactionWithSignature(b.transactor.NetworkID(), sendArgs, sig)
  2244  	if err != nil {
  2245  		return hash, err
  2246  	}
  2247  
  2248  	return b.transactor.SendTransactionWithSignature(common.Address(sendArgs.From), sendArgs.Symbol, sendArgs.MultiTransactionID, txWithSignature)
  2249  }
  2250  
  2251  // HashTransaction validate the transaction and returns new sendArgs and the transaction hash.
  2252  func (b *GethStatusBackend) HashTransaction(sendArgs transactions.SendTxArgs) (transactions.SendTxArgs, types.Hash, error) {
  2253  	return b.transactor.HashTransaction(sendArgs)
  2254  }
  2255  
  2256  // SignMessage checks the pwd vs the selected account and passes on the signParams
  2257  // to personalAPI for message signature
  2258  func (b *GethStatusBackend) SignMessage(rpcParams personal.SignParams) (types.HexBytes, error) {
  2259  	verifiedAccount, err := b.getVerifiedWalletAccount(rpcParams.Address, rpcParams.Password)
  2260  	if err != nil {
  2261  		return types.HexBytes{}, err
  2262  	}
  2263  	return b.personalAPI.Sign(rpcParams, verifiedAccount)
  2264  }
  2265  
  2266  // Recover calls the personalAPI to return address associated with the private
  2267  // key that was used to calculate the signature in the message
  2268  func (b *GethStatusBackend) Recover(rpcParams personal.RecoverParams) (types.Address, error) {
  2269  	return b.personalAPI.Recover(rpcParams)
  2270  }
  2271  
  2272  // SignTypedData accepts data and password. Gets verified account and signs typed data.
  2273  func (b *GethStatusBackend) SignTypedData(typed typeddata.TypedData, address string, password string) (types.HexBytes, error) {
  2274  	account, err := b.getVerifiedWalletAccount(address, password)
  2275  	if err != nil {
  2276  		return types.HexBytes{}, err
  2277  	}
  2278  	chain := new(big.Int).SetUint64(b.StatusNode().Config().NetworkID)
  2279  	sig, err := typeddata.Sign(typed, account.AccountKey.PrivateKey, chain)
  2280  	if err != nil {
  2281  		return types.HexBytes{}, err
  2282  	}
  2283  	return types.HexBytes(sig), err
  2284  }
  2285  
  2286  // SignTypedDataV4 accepts data and password. Gets verified account and signs typed data.
  2287  func (b *GethStatusBackend) SignTypedDataV4(typed signercore.TypedData, address string, password string) (types.HexBytes, error) {
  2288  	account, err := b.getVerifiedWalletAccount(address, password)
  2289  	if err != nil {
  2290  		return types.HexBytes{}, err
  2291  	}
  2292  	chain := new(big.Int).SetUint64(b.StatusNode().Config().NetworkID)
  2293  	sig, err := typeddata.SignTypedDataV4(typed, account.AccountKey.PrivateKey, chain)
  2294  	if err != nil {
  2295  		return types.HexBytes{}, err
  2296  	}
  2297  	return types.HexBytes(sig), err
  2298  }
  2299  
  2300  // HashTypedData generates the hash of TypedData.
  2301  func (b *GethStatusBackend) HashTypedData(typed typeddata.TypedData) (types.Hash, error) {
  2302  	chain := new(big.Int).SetUint64(b.StatusNode().Config().NetworkID)
  2303  	hash, err := typeddata.ValidateAndHash(typed, chain)
  2304  	if err != nil {
  2305  		return types.Hash{}, err
  2306  	}
  2307  	return types.Hash(hash), err
  2308  }
  2309  
  2310  // HashTypedDataV4 generates the hash of TypedData.
  2311  func (b *GethStatusBackend) HashTypedDataV4(typed signercore.TypedData) (types.Hash, error) {
  2312  	chain := new(big.Int).SetUint64(b.StatusNode().Config().NetworkID)
  2313  	hash, err := typeddata.HashTypedDataV4(typed, chain)
  2314  	if err != nil {
  2315  		return types.Hash{}, err
  2316  	}
  2317  	return types.Hash(hash), err
  2318  }
  2319  
  2320  func (b *GethStatusBackend) getVerifiedWalletAccount(address, password string) (*account.SelectedExtKey, error) {
  2321  	config := b.StatusNode().Config()
  2322  	db, err := accounts.NewDB(b.appDB)
  2323  	if err != nil {
  2324  		b.log.Error("failed to create new *Database instance", "error", err)
  2325  		return nil, err
  2326  	}
  2327  	exists, err := db.AddressExists(types.HexToAddress(address))
  2328  	if err != nil {
  2329  		b.log.Error("failed to query db for a given address", "address", address, "error", err)
  2330  		return nil, err
  2331  	}
  2332  
  2333  	if !exists {
  2334  		b.log.Error("failed to get a selected account", "err", transactions.ErrInvalidTxSender)
  2335  		return nil, transactions.ErrAccountDoesntExist
  2336  	}
  2337  
  2338  	key, err := b.accountManager.VerifyAccountPassword(config.KeyStoreDir, address, password)
  2339  	if _, ok := err.(*account.ErrCannotLocateKeyFile); ok {
  2340  		key, err = b.generatePartialAccountKey(db, address, password)
  2341  		if err != nil {
  2342  			return nil, err
  2343  		}
  2344  	}
  2345  
  2346  	if err != nil {
  2347  		b.log.Error("failed to verify account", "account", address, "error", err)
  2348  		return nil, err
  2349  	}
  2350  
  2351  	return &account.SelectedExtKey{
  2352  		Address:    key.Address,
  2353  		AccountKey: key,
  2354  	}, nil
  2355  }
  2356  
  2357  func (b *GethStatusBackend) generatePartialAccountKey(db *accounts.Database, address string, password string) (*types.Key, error) {
  2358  	dbPath, err := db.GetPath(types.HexToAddress(address))
  2359  	path := "m/" + dbPath[strings.LastIndex(dbPath, "/")+1:]
  2360  	if err != nil {
  2361  		b.log.Error("failed to get path for given account address", "account", address, "error", err)
  2362  		return nil, err
  2363  	}
  2364  
  2365  	rootAddress, err := db.GetWalletRootAddress()
  2366  	if err != nil {
  2367  		return nil, err
  2368  	}
  2369  	info, err := b.accountManager.AccountsGenerator().LoadAccount(rootAddress.Hex(), password)
  2370  	if err != nil {
  2371  		return nil, err
  2372  	}
  2373  	masterID := info.ID
  2374  
  2375  	accInfosMap, err := b.accountManager.AccountsGenerator().StoreDerivedAccounts(masterID, password, []string{path})
  2376  	if err != nil {
  2377  		return nil, err
  2378  	}
  2379  
  2380  	_, key, err := b.accountManager.AddressToDecryptedAccount(accInfosMap[path].Address, password)
  2381  	if err != nil {
  2382  		return nil, err
  2383  	}
  2384  
  2385  	return key, nil
  2386  }
  2387  
  2388  // registerHandlers attaches Status callback handlers to running node
  2389  func (b *GethStatusBackend) registerHandlers() error {
  2390  	var clients []*rpc.Client
  2391  
  2392  	if c := b.StatusNode().RPCClient(); c != nil {
  2393  		clients = append(clients, c)
  2394  	} else {
  2395  		return errors.New("RPC client unavailable")
  2396  	}
  2397  
  2398  	for _, client := range clients {
  2399  		client.RegisterHandler(
  2400  			params.AccountsMethodName,
  2401  			func(context.Context, uint64, ...interface{}) (interface{}, error) {
  2402  				return b.accountManager.Accounts()
  2403  			},
  2404  		)
  2405  
  2406  		if b.allowAllRPC {
  2407  			// this should only happen in unit-tests, this variable is not available outside this package
  2408  			continue
  2409  		}
  2410  		client.RegisterHandler(params.SendTransactionMethodName, unsupportedMethodHandler)
  2411  		client.RegisterHandler(params.PersonalSignMethodName, unsupportedMethodHandler)
  2412  		client.RegisterHandler(params.PersonalRecoverMethodName, unsupportedMethodHandler)
  2413  	}
  2414  
  2415  	return nil
  2416  }
  2417  
  2418  func unsupportedMethodHandler(ctx context.Context, chainID uint64, rpcParams ...interface{}) (interface{}, error) {
  2419  	return nil, ErrUnsupportedRPCMethod
  2420  }
  2421  
  2422  // ConnectionChange handles network state changes logic.
  2423  func (b *GethStatusBackend) ConnectionChange(typ string, expensive bool) {
  2424  	b.mu.Lock()
  2425  	defer b.mu.Unlock()
  2426  
  2427  	state := connection.State{
  2428  		Type:      connection.NewType(typ),
  2429  		Expensive: expensive,
  2430  	}
  2431  	if typ == connection.None {
  2432  		state.Offline = true
  2433  	}
  2434  
  2435  	b.log.Info("Network state change", "old", b.connectionState, "new", state)
  2436  
  2437  	if b.connectionState.Offline && !state.Offline {
  2438  		//  flush hystrix if we are going again online, since it doesn't behave
  2439  		// well when offline
  2440  		hystrix.Flush()
  2441  	}
  2442  
  2443  	b.connectionState = state
  2444  	b.statusNode.ConnectionChanged(state)
  2445  
  2446  	// logic of handling state changes here
  2447  	// restart node? force peers reconnect? etc
  2448  }
  2449  
  2450  // AppStateChange handles app state changes (background/foreground).
  2451  // state values: see https://facebook.github.io/react-native/docs/appstate.html
  2452  func (b *GethStatusBackend) AppStateChange(state string) {
  2453  	var messenger *protocol.Messenger
  2454  	s, err := parseAppState(state)
  2455  	if err != nil {
  2456  		log.Error("AppStateChange failed, ignoring", "error", err)
  2457  		return
  2458  	}
  2459  
  2460  	b.appState = s
  2461  
  2462  	if b.statusNode == nil {
  2463  		log.Warn("statusNode nil, not reporting app state change")
  2464  		return
  2465  	}
  2466  
  2467  	if b.statusNode.WakuExtService() != nil {
  2468  		messenger = b.statusNode.WakuExtService().Messenger()
  2469  	}
  2470  
  2471  	if b.statusNode.WakuV2ExtService() != nil {
  2472  		messenger = b.statusNode.WakuV2ExtService().Messenger()
  2473  	}
  2474  
  2475  	if messenger == nil {
  2476  		log.Warn("messenger nil, not reporting app state change")
  2477  		return
  2478  	}
  2479  
  2480  	if s == appStateForeground {
  2481  		messenger.ToForeground()
  2482  	} else {
  2483  		messenger.ToBackground()
  2484  	}
  2485  
  2486  	// TODO: put node in low-power mode if the app is in background (or inactive)
  2487  	// and normal mode if the app is in foreground.
  2488  }
  2489  
  2490  func (b *GethStatusBackend) StopLocalNotifications() error {
  2491  	if b.statusNode == nil {
  2492  		return nil
  2493  	}
  2494  	return b.statusNode.StopLocalNotifications()
  2495  }
  2496  
  2497  func (b *GethStatusBackend) StartLocalNotifications() error {
  2498  	if b.statusNode == nil {
  2499  		return nil
  2500  	}
  2501  	return b.statusNode.StartLocalNotifications()
  2502  
  2503  }
  2504  
  2505  // Logout clears whisper identities.
  2506  func (b *GethStatusBackend) Logout() error {
  2507  	b.mu.Lock()
  2508  	defer b.mu.Unlock()
  2509  
  2510  	b.log.Debug("logging out")
  2511  	err := b.cleanupServices()
  2512  	if err != nil {
  2513  		return err
  2514  	}
  2515  	err = b.closeDBs()
  2516  	if err != nil {
  2517  		return err
  2518  	}
  2519  
  2520  	b.AccountManager().Logout()
  2521  	b.account = nil
  2522  
  2523  	if b.statusNode != nil {
  2524  		if err := b.statusNode.Stop(); err != nil {
  2525  			return err
  2526  		}
  2527  		b.statusNode = nil
  2528  	}
  2529  
  2530  	if !b.LocalPairingStateManager.IsPairing() {
  2531  		signal.SendNodeStopped()
  2532  	}
  2533  
  2534  	// re-initialize the node, at some point we should better manage the lifecycle
  2535  	b.initialize()
  2536  
  2537  	err = b.statusNode.StartMediaServerWithoutDB()
  2538  	if err != nil {
  2539  		b.log.Error("failed to start media server without app db", "err", err)
  2540  		return err
  2541  	}
  2542  	return nil
  2543  }
  2544  
  2545  // cleanupServices stops parts of services that doesn't managed by a node and removes injected data from services.
  2546  func (b *GethStatusBackend) cleanupServices() error {
  2547  	b.selectedAccountKeyID = ""
  2548  	if b.statusNode == nil {
  2549  		return nil
  2550  	}
  2551  	return b.statusNode.Cleanup()
  2552  }
  2553  
  2554  func (b *GethStatusBackend) closeDBs() error {
  2555  	err := b.closeWalletDB()
  2556  	if err != nil {
  2557  		return err
  2558  	}
  2559  	return b.closeAppDB()
  2560  }
  2561  
  2562  func (b *GethStatusBackend) closeAppDB() error {
  2563  	if b.appDB != nil {
  2564  		err := b.appDB.Close()
  2565  		if err != nil {
  2566  			return err
  2567  		}
  2568  		b.appDB = nil
  2569  		return nil
  2570  	}
  2571  	return nil
  2572  }
  2573  
  2574  func (b *GethStatusBackend) closeWalletDB() error {
  2575  	if b.walletDB != nil {
  2576  		err := b.walletDB.Close()
  2577  		if err != nil {
  2578  			return err
  2579  		}
  2580  		b.walletDB = nil
  2581  	}
  2582  	return nil
  2583  }
  2584  
  2585  // SelectAccount selects current wallet and chat accounts, by verifying that each address has corresponding account which can be decrypted
  2586  // using provided password. Once verification is done, the decrypted chat key is injected into Whisper (as a single identity,
  2587  // all previous identities are removed).
  2588  func (b *GethStatusBackend) SelectAccount(loginParams account.LoginParams) error {
  2589  	b.mu.Lock()
  2590  	defer b.mu.Unlock()
  2591  
  2592  	b.AccountManager().RemoveOnboarding()
  2593  
  2594  	err := b.accountManager.SelectAccount(loginParams)
  2595  	if err != nil {
  2596  		return err
  2597  	}
  2598  
  2599  	if loginParams.MultiAccount != nil {
  2600  		b.account = loginParams.MultiAccount
  2601  	}
  2602  
  2603  	if err := b.injectAccountsIntoServices(); err != nil {
  2604  		return err
  2605  	}
  2606  
  2607  	return nil
  2608  }
  2609  
  2610  func (b *GethStatusBackend) GetActiveAccount() (*multiaccounts.Account, error) {
  2611  	if b.account == nil {
  2612  		return nil, errors.New("master key account is nil in the GethStatusBackend")
  2613  	}
  2614  
  2615  	return b.account, nil
  2616  }
  2617  
  2618  func (b *GethStatusBackend) LocalPairingStarted() error {
  2619  	if b.account == nil {
  2620  		return errors.New("master key account is nil in the GethStatusBackend")
  2621  	}
  2622  
  2623  	accountDB, err := accounts.NewDB(b.appDB)
  2624  	if err != nil {
  2625  		return err
  2626  	}
  2627  
  2628  	return accountDB.MnemonicWasShown()
  2629  }
  2630  
  2631  func (b *GethStatusBackend) injectAccountsIntoWakuService(w types.WakuKeyManager, st *ext.Service) error {
  2632  	chatAccount, err := b.accountManager.SelectedChatAccount()
  2633  	if err != nil {
  2634  		return err
  2635  	}
  2636  
  2637  	identity := chatAccount.AccountKey.PrivateKey
  2638  
  2639  	acc, err := b.GetActiveAccount()
  2640  	if err != nil {
  2641  		return err
  2642  	}
  2643  
  2644  	if err := w.DeleteKeyPairs(); err != nil { // err is not possible; method return value is incorrect
  2645  		return err
  2646  	}
  2647  	b.selectedAccountKeyID, err = w.AddKeyPair(identity)
  2648  	if err != nil {
  2649  		return ErrWakuIdentityInjectionFailure
  2650  	}
  2651  
  2652  	if st != nil {
  2653  		if err := st.InitProtocol(b.statusNode.GethNode().Config().Name, identity, b.appDB, b.walletDB, b.statusNode.HTTPServer(), b.multiaccountsDB, acc, b.accountManager, b.statusNode.RPCClient(), b.statusNode.WalletService(), b.statusNode.CommunityTokensService(), b.statusNode.WakuV2Service(), logutils.ZapLogger(), b.statusNode.AccountsFeed()); err != nil {
  2654  			return err
  2655  		}
  2656  		// Set initial connection state
  2657  		st.ConnectionChanged(b.connectionState)
  2658  
  2659  		messenger := st.Messenger()
  2660  		// Init public status api
  2661  		b.statusNode.StatusPublicService().Init(messenger)
  2662  		b.statusNode.AccountService().Init(messenger)
  2663  		// Init chat service
  2664  		accDB, err := accounts.NewDB(b.appDB)
  2665  		if err != nil {
  2666  			return err
  2667  		}
  2668  		b.statusNode.ChatService(accDB).Init(messenger)
  2669  		b.statusNode.EnsService().Init(messenger.SyncEnsNamesWithDispatchMessage)
  2670  		b.statusNode.CommunityTokensService().Init(messenger)
  2671  	}
  2672  
  2673  	return nil
  2674  }
  2675  
  2676  func (b *GethStatusBackend) InstallationID() string {
  2677  	m := b.Messenger()
  2678  	if m != nil {
  2679  		return m.InstallationID()
  2680  	}
  2681  	return ""
  2682  }
  2683  
  2684  func (b *GethStatusBackend) KeyUID() string {
  2685  	m := b.Messenger()
  2686  	if m != nil {
  2687  		return m.KeyUID()
  2688  	}
  2689  	return ""
  2690  }
  2691  
  2692  func (b *GethStatusBackend) injectAccountsIntoServices() error {
  2693  	if b.statusNode.WakuService() != nil {
  2694  		return b.injectAccountsIntoWakuService(b.statusNode.WakuService(), func() *ext.Service {
  2695  			if b.statusNode.WakuExtService() == nil {
  2696  				return nil
  2697  			}
  2698  			return b.statusNode.WakuExtService().Service
  2699  		}())
  2700  	}
  2701  
  2702  	if b.statusNode.WakuV2Service() != nil {
  2703  		return b.injectAccountsIntoWakuService(b.statusNode.WakuV2Service(), func() *ext.Service {
  2704  			if b.statusNode.WakuV2ExtService() == nil {
  2705  				return nil
  2706  			}
  2707  			return b.statusNode.WakuV2ExtService().Service
  2708  		}())
  2709  	}
  2710  
  2711  	return nil
  2712  }
  2713  
  2714  // ExtractGroupMembershipSignatures extract signatures from tuples of content/signature
  2715  func (b *GethStatusBackend) ExtractGroupMembershipSignatures(signaturePairs [][2]string) ([]string, error) {
  2716  	return crypto.ExtractSignatures(signaturePairs)
  2717  }
  2718  
  2719  // SignGroupMembership signs a piece of data containing membership information
  2720  func (b *GethStatusBackend) SignGroupMembership(content string) (string, error) {
  2721  	selectedChatAccount, err := b.accountManager.SelectedChatAccount()
  2722  	if err != nil {
  2723  		return "", err
  2724  	}
  2725  
  2726  	return crypto.SignStringAsHex(content, selectedChatAccount.AccountKey.PrivateKey)
  2727  }
  2728  
  2729  func (b *GethStatusBackend) Messenger() *protocol.Messenger {
  2730  	node := b.StatusNode()
  2731  	if node != nil {
  2732  		accountService := node.AccountService()
  2733  		if accountService != nil {
  2734  			return accountService.GetMessenger()
  2735  		}
  2736  	}
  2737  	return nil
  2738  }
  2739  
  2740  // SignHash exposes vanilla ECDSA signing for signing a message for Swarm
  2741  func (b *GethStatusBackend) SignHash(hexEncodedHash string) (string, error) {
  2742  	hash, err := hexutil.Decode(hexEncodedHash)
  2743  	if err != nil {
  2744  		return "", fmt.Errorf("SignHash: could not unmarshal the input: %v", err)
  2745  	}
  2746  
  2747  	chatAccount, err := b.accountManager.SelectedChatAccount()
  2748  	if err != nil {
  2749  		return "", fmt.Errorf("SignHash: could not select account: %v", err.Error())
  2750  	}
  2751  
  2752  	signature, err := ethcrypto.Sign(hash, chatAccount.AccountKey.PrivateKey)
  2753  	if err != nil {
  2754  		return "", fmt.Errorf("SignHash: could not sign the hash: %v", err)
  2755  	}
  2756  
  2757  	hexEncodedSignature := types.EncodeHex(signature)
  2758  	return hexEncodedSignature, nil
  2759  }
  2760  
  2761  func (b *GethStatusBackend) SwitchFleet(fleet string, conf *params.NodeConfig) error {
  2762  	if b.appDB == nil {
  2763  		return ErrDBNotAvailable
  2764  	}
  2765  
  2766  	accountDB, err := accounts.NewDB(b.appDB)
  2767  	if err != nil {
  2768  		return err
  2769  	}
  2770  
  2771  	err = accountDB.SaveSetting("fleet", fleet)
  2772  	if err != nil {
  2773  		return err
  2774  	}
  2775  
  2776  	err = nodecfg.SaveNodeConfig(b.appDB, conf)
  2777  	if err != nil {
  2778  		return err
  2779  	}
  2780  
  2781  	return nil
  2782  }
  2783  
  2784  func (b *GethStatusBackend) getAppDBPath(keyUID string) (string, error) {
  2785  	if len(b.rootDataDir) == 0 {
  2786  		return "", errors.New("root datadir wasn't provided")
  2787  	}
  2788  
  2789  	return filepath.Join(b.rootDataDir, fmt.Sprintf("%s-v4.db", keyUID)), nil
  2790  }
  2791  
  2792  func (b *GethStatusBackend) getWalletDBPath(keyUID string) (string, error) {
  2793  	if len(b.rootDataDir) == 0 {
  2794  		return "", errors.New("root datadir wasn't provided")
  2795  	}
  2796  
  2797  	return filepath.Join(b.rootDataDir, fmt.Sprintf("%s-wallet.db", keyUID)), nil
  2798  }