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

     1  package api
     2  
     3  import (
     4  	"context"
     5  	"crypto/sha256"
     6  	"database/sql"
     7  	"encoding/hex"
     8  	"encoding/json"
     9  	"fmt"
    10  	"io/ioutil"
    11  	"math/rand"
    12  	"os"
    13  	"path"
    14  	"path/filepath"
    15  	"strings"
    16  	"sync"
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/stretchr/testify/assert"
    21  	"github.com/stretchr/testify/require"
    22  
    23  	gethcrypto "github.com/ethereum/go-ethereum/crypto"
    24  
    25  	"github.com/status-im/status-go/appdatabase"
    26  	"github.com/status-im/status-go/connection"
    27  	"github.com/status-im/status-go/eth-node/crypto"
    28  	"github.com/status-im/status-go/eth-node/types"
    29  	"github.com/status-im/status-go/multiaccounts"
    30  	"github.com/status-im/status-go/multiaccounts/accounts"
    31  	"github.com/status-im/status-go/multiaccounts/settings"
    32  	"github.com/status-im/status-go/node"
    33  	"github.com/status-im/status-go/params"
    34  	"github.com/status-im/status-go/protocol/requests"
    35  	"github.com/status-im/status-go/rpc"
    36  	"github.com/status-im/status-go/services/typeddata"
    37  	"github.com/status-im/status-go/services/wallet"
    38  	walletservice "github.com/status-im/status-go/services/wallet"
    39  	"github.com/status-im/status-go/signal"
    40  	"github.com/status-im/status-go/sqlite"
    41  	"github.com/status-im/status-go/t/helpers"
    42  	"github.com/status-im/status-go/t/utils"
    43  	"github.com/status-im/status-go/transactions"
    44  	"github.com/status-im/status-go/walletdatabase"
    45  )
    46  
    47  var (
    48  	networks     = json.RawMessage("{}")
    49  	testSettings = settings.Settings{
    50  		Address:           types.HexToAddress("0xeC540f3745Ff2964AFC1171a5A0DD726d1F6B472"),
    51  		DisplayName:       "UserDisplayName",
    52  		CurrentNetwork:    "mainnet_rpc",
    53  		DappsAddress:      types.HexToAddress("0xe1300f99fDF7346986CbC766903245087394ecd0"),
    54  		EIP1581Address:    types.HexToAddress("0xe1DDDE9235a541d1344550d969715CF43982de9f"),
    55  		InstallationID:    "d3efcff6-cffa-560e-a547-21d3858cbc51",
    56  		KeyUID:            "0x4e8129f3edfc004875be17bf468a784098a9f69b53c095be1f52deff286935ab",
    57  		LatestDerivedPath: 0,
    58  		Name:              "Jittery Cornflowerblue Kingbird",
    59  		Networks:          &networks,
    60  		PhotoPath:         "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAAjklEQVR4nOzXwQmFMBAAUZXUYh32ZB32ZB02sxYQQSZGsod55/91WFgSS0RM+SyjA56ZRZhFmEWYRRT6h+M6G16zrxv6fdJpmUWYRbxsYr13dKfanpN0WmYRZhGzXz6AWYRZRIfbaX26fT9Jk07LLMIsosPt9I/dTDotswizCG+nhFmEWYRZhFnEHQAA///z1CFkYamgfQAAAABJRU5ErkJggg==",
    61  		PreviewPrivacy:    false,
    62  		PublicKey:         "0x04211fe0f69772ecf7eb0b5bfc7678672508a9fb01f2d699096f0d59ef7fe1a0cb1e648a80190db1c0f5f088872444d846f2956d0bd84069f3f9f69335af852ac0",
    63  		SigningPhrase:     "yurt joey vibe",
    64  		WalletRootAddress: types.HexToAddress("0xeB591fd819F86D0A6a2EF2Bcb94f77807a7De1a6")}
    65  )
    66  
    67  func setupTestDB() (*sql.DB, func() error, error) {
    68  	return helpers.SetupTestSQLDB(appdatabase.DbInitializer{}, "tests")
    69  }
    70  
    71  func setupTestWalletDB() (*sql.DB, func() error, error) {
    72  	return helpers.SetupTestSQLDB(walletdatabase.DbInitializer{}, "tests")
    73  }
    74  
    75  func setupTestMultiDB() (*multiaccounts.Database, func() error, error) {
    76  	tmpfile, err := ioutil.TempFile("", "tests")
    77  	if err != nil {
    78  		return nil, nil, err
    79  	}
    80  	db, err := multiaccounts.InitializeDB(tmpfile.Name())
    81  	if err != nil {
    82  		return nil, nil, err
    83  	}
    84  	return db, func() error {
    85  		err := db.Close()
    86  		if err != nil {
    87  			return err
    88  		}
    89  		return os.Remove(tmpfile.Name())
    90  	}, nil
    91  }
    92  
    93  func setupGethStatusBackend() (*GethStatusBackend, func() error, func() error, func() error, error) {
    94  	db, stop1, err := setupTestDB()
    95  	if err != nil {
    96  		return nil, nil, nil, nil, err
    97  	}
    98  	backend := NewGethStatusBackend()
    99  	backend.StatusNode().SetAppDB(db)
   100  
   101  	ma, stop2, err := setupTestMultiDB()
   102  	if err != nil {
   103  		return nil, nil, nil, nil, err
   104  	}
   105  	backend.StatusNode().SetMultiaccountsDB(ma)
   106  
   107  	walletDb, stop3, err := setupTestWalletDB()
   108  	if err != nil {
   109  		return nil, nil, nil, nil, err
   110  	}
   111  	backend.StatusNode().SetWalletDB(walletDb)
   112  
   113  	return backend, stop1, stop2, stop3, err
   114  }
   115  
   116  func TestBackendStartNodeConcurrently(t *testing.T) {
   117  	utils.Init()
   118  
   119  	backend, stop1, stop2, stop3, err := setupGethStatusBackend()
   120  	defer func() {
   121  		err := stop1()
   122  		if err != nil {
   123  			require.NoError(t, backend.StopNode())
   124  		}
   125  	}()
   126  	defer func() {
   127  		err := stop2()
   128  		if err != nil {
   129  			require.NoError(t, backend.StopNode())
   130  		}
   131  	}()
   132  	defer func() {
   133  		err := stop3()
   134  		if err != nil {
   135  			require.NoError(t, backend.StopNode())
   136  		}
   137  	}()
   138  	require.NoError(t, err)
   139  
   140  	config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
   141  	require.NoError(t, err)
   142  	require.NoError(t, backend.AccountManager().InitKeystore(config.KeyStoreDir))
   143  	count := 2
   144  	resultCh := make(chan error)
   145  
   146  	var wg sync.WaitGroup
   147  	wg.Add(count)
   148  
   149  	for i := 0; i < count; i++ {
   150  		go func() {
   151  			resultCh <- backend.StartNode(config)
   152  			wg.Done()
   153  		}()
   154  	}
   155  
   156  	// close channel as otherwise for loop never finishes
   157  	go func() { wg.Wait(); close(resultCh) }()
   158  
   159  	var results []error
   160  	for err := range resultCh {
   161  		results = append(results, err)
   162  	}
   163  
   164  	require.Contains(t, results, nil)
   165  	require.Contains(t, results, node.ErrNodeRunning)
   166  
   167  	err = backend.StopNode()
   168  	require.NoError(t, err)
   169  }
   170  
   171  func TestBackendRestartNodeConcurrently(t *testing.T) {
   172  	utils.Init()
   173  
   174  	backend, stop1, stop2, stopWallet, err := setupGethStatusBackend()
   175  	defer func() {
   176  		err := stop1()
   177  		if err != nil {
   178  			require.NoError(t, backend.StopNode())
   179  		}
   180  	}()
   181  	defer func() {
   182  		err := stop2()
   183  		if err != nil {
   184  			require.NoError(t, backend.StopNode())
   185  		}
   186  	}()
   187  	defer func() {
   188  		err := stopWallet()
   189  		if err != nil {
   190  			require.NoError(t, backend.StopNode())
   191  		}
   192  	}()
   193  	require.NoError(t, err)
   194  
   195  	config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
   196  	require.NoError(t, err)
   197  	count := 3
   198  	require.NoError(t, backend.AccountManager().InitKeystore(config.KeyStoreDir))
   199  	require.NoError(t, backend.StartNode(config))
   200  	defer func() {
   201  		require.NoError(t, backend.StopNode())
   202  	}()
   203  
   204  	var wg sync.WaitGroup
   205  	wg.Add(count)
   206  
   207  	for i := 0; i < count; i++ {
   208  		go func(idx int) {
   209  			assert.NoError(t, backend.RestartNode())
   210  			wg.Done()
   211  		}(i)
   212  	}
   213  
   214  	wg.Wait()
   215  }
   216  
   217  // TODO(adam): add concurrent tests for ResetChainData()
   218  
   219  func TestBackendGettersConcurrently(t *testing.T) {
   220  	utils.Init()
   221  
   222  	backend, stop1, stop2, stopWallet, err := setupGethStatusBackend()
   223  	defer func() {
   224  		err := stop1()
   225  		if err != nil {
   226  			require.NoError(t, backend.StopNode())
   227  		}
   228  	}()
   229  	defer func() {
   230  		err := stop2()
   231  		if err != nil {
   232  			require.NoError(t, backend.StopNode())
   233  		}
   234  	}()
   235  	defer func() {
   236  		err := stopWallet()
   237  		if err != nil {
   238  			require.NoError(t, backend.StopNode())
   239  		}
   240  	}()
   241  	require.NoError(t, err)
   242  
   243  	config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
   244  	require.NoError(t, err)
   245  	require.NoError(t, backend.AccountManager().InitKeystore(config.KeyStoreDir))
   246  	err = backend.StartNode(config)
   247  	require.NoError(t, err)
   248  	defer func() {
   249  		require.NoError(t, backend.StopNode())
   250  	}()
   251  
   252  	var wg sync.WaitGroup
   253  
   254  	wg.Add(1)
   255  	go func() {
   256  		assert.NotNil(t, backend.StatusNode())
   257  		wg.Done()
   258  	}()
   259  
   260  	wg.Add(1)
   261  	go func() {
   262  		assert.NotNil(t, backend.AccountManager())
   263  		wg.Done()
   264  	}()
   265  
   266  	wg.Add(1)
   267  	go func() {
   268  		assert.NotNil(t, backend.personalAPI)
   269  		wg.Done()
   270  	}()
   271  
   272  	wg.Add(1)
   273  	go func() {
   274  		assert.NotNil(t, backend.Transactor())
   275  		wg.Done()
   276  	}()
   277  
   278  	wg.Add(1)
   279  	go func() {
   280  		assert.True(t, backend.IsNodeRunning())
   281  		wg.Done()
   282  	}()
   283  
   284  	wg.Add(1)
   285  	go func() {
   286  		assert.True(t, backend.IsNodeRunning())
   287  		wg.Done()
   288  	}()
   289  
   290  	wg.Wait()
   291  }
   292  
   293  func TestBackendConnectionChangesConcurrently(t *testing.T) {
   294  	connections := [...]string{connection.Wifi, connection.Cellular, connection.Unknown}
   295  	backend := NewGethStatusBackend()
   296  	count := 3
   297  
   298  	var wg sync.WaitGroup
   299  
   300  	for i := 0; i < count; i++ {
   301  		wg.Add(1)
   302  		go func() {
   303  			connIdx := rand.Intn(len(connections)) // nolint: gosec
   304  			backend.ConnectionChange(connections[connIdx], false)
   305  			wg.Done()
   306  		}()
   307  	}
   308  
   309  	wg.Wait()
   310  }
   311  
   312  func TestBackendConnectionChangesToOffline(t *testing.T) {
   313  	b := NewGethStatusBackend()
   314  	b.ConnectionChange(connection.None, false)
   315  	assert.True(t, b.connectionState.Offline)
   316  
   317  	b.ConnectionChange(connection.Wifi, false)
   318  	assert.False(t, b.connectionState.Offline)
   319  
   320  	b.ConnectionChange("unknown-state", false)
   321  	assert.False(t, b.connectionState.Offline)
   322  }
   323  
   324  func TestBackendCallRPCConcurrently(t *testing.T) {
   325  	utils.Init()
   326  
   327  	backend, stop1, stop2, stopWallet, err := setupGethStatusBackend()
   328  	defer func() {
   329  		err := stop1()
   330  		if err != nil {
   331  			require.NoError(t, backend.StopNode())
   332  		}
   333  	}()
   334  	defer func() {
   335  		err := stop2()
   336  		if err != nil {
   337  			require.NoError(t, backend.StopNode())
   338  		}
   339  	}()
   340  	defer func() {
   341  		err := stopWallet()
   342  		if err != nil {
   343  			require.NoError(t, backend.StopNode())
   344  		}
   345  	}()
   346  	require.NoError(t, err)
   347  
   348  	config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
   349  	require.NoError(t, err)
   350  	require.NoError(t, backend.AccountManager().InitKeystore(config.KeyStoreDir))
   351  	count := 3
   352  
   353  	err = backend.StartNode(config)
   354  	require.NoError(t, err)
   355  	defer func() {
   356  		require.NoError(t, backend.StopNode())
   357  	}()
   358  
   359  	var wg sync.WaitGroup
   360  
   361  	for i := 0; i < count; i++ {
   362  		wg.Add(1)
   363  		go func(idx int) {
   364  			result, err := backend.CallRPC(fmt.Sprintf(
   365  				`{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":%d}`,
   366  				idx+1,
   367  			))
   368  			assert.NoError(t, err)
   369  			assert.NotContains(t, result, "error")
   370  			wg.Done()
   371  		}(i)
   372  
   373  		wg.Add(1)
   374  		go func(idx int) {
   375  			result, err := backend.CallPrivateRPC(fmt.Sprintf(
   376  				`{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":%d}`,
   377  				idx+1,
   378  			))
   379  			assert.NoError(t, err)
   380  			assert.NotContains(t, result, "error")
   381  			wg.Done()
   382  		}(i)
   383  	}
   384  
   385  	wg.Wait()
   386  }
   387  
   388  func TestAppStateChange(t *testing.T) {
   389  	backend := NewGethStatusBackend()
   390  
   391  	var testCases = []struct {
   392  		name          string
   393  		fromState     appState
   394  		toState       appState
   395  		expectedState appState
   396  	}{
   397  		{
   398  			name:          "success",
   399  			fromState:     appStateInactive,
   400  			toState:       appStateBackground,
   401  			expectedState: appStateBackground,
   402  		},
   403  		{
   404  			name:          "invalid state",
   405  			fromState:     appStateInactive,
   406  			toState:       "unexisting",
   407  			expectedState: appStateInactive,
   408  		},
   409  	}
   410  
   411  	for _, tc := range testCases {
   412  		t.Run(tc.name, func(t *testing.T) {
   413  			backend.appState = tc.fromState
   414  			backend.AppStateChange(tc.toState.String())
   415  			assert.Equal(t, tc.expectedState.String(), backend.appState.String())
   416  		})
   417  	}
   418  }
   419  
   420  func TestBlockedRPCMethods(t *testing.T) {
   421  	utils.Init()
   422  
   423  	backend, stop1, stop2, stopWallet, err := setupGethStatusBackend()
   424  	defer func() {
   425  		err := stop1()
   426  		if err != nil {
   427  			require.NoError(t, backend.StopNode())
   428  		}
   429  	}()
   430  	defer func() {
   431  		err := stop2()
   432  		if err != nil {
   433  			require.NoError(t, backend.StopNode())
   434  		}
   435  	}()
   436  	defer func() {
   437  		err := stopWallet()
   438  		if err != nil {
   439  			require.NoError(t, backend.StopNode())
   440  		}
   441  	}()
   442  	require.NoError(t, err)
   443  
   444  	config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
   445  	require.NoError(t, err)
   446  	require.NoError(t, backend.AccountManager().InitKeystore(config.KeyStoreDir))
   447  	err = backend.StartNode(config)
   448  	require.NoError(t, err)
   449  	defer func() { require.NoError(t, backend.StopNode()) }()
   450  
   451  	for idx, m := range rpc.BlockedMethods() {
   452  		result, err := backend.CallRPC(fmt.Sprintf(
   453  			`{"jsonrpc":"2.0","method":"%s","params":[],"id":%d}`,
   454  			m,
   455  			idx+1,
   456  		))
   457  		assert.NoError(t, err)
   458  		assert.Contains(t, result, fmt.Sprintf(`{"code":-32700,"message":"%s"}`, rpc.ErrMethodNotFound))
   459  	}
   460  }
   461  
   462  func TestCallRPCWithStoppedNode(t *testing.T) {
   463  	backend := NewGethStatusBackend()
   464  
   465  	resp, err := backend.CallRPC(
   466  		`{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":1}`,
   467  	)
   468  	assert.Equal(t, ErrRPCClientUnavailable, err)
   469  	assert.Equal(t, "", resp)
   470  
   471  	resp, err = backend.CallPrivateRPC(
   472  		`{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":1}`,
   473  	)
   474  	assert.Equal(t, ErrRPCClientUnavailable, err)
   475  	assert.Equal(t, "", resp)
   476  }
   477  
   478  // TODO(adam): add concurrent tests for: SendTransaction
   479  
   480  func TestStartStopMultipleTimes(t *testing.T) {
   481  	utils.Init()
   482  
   483  	backend, stop1, stop2, stopWallet, err := setupGethStatusBackend()
   484  	defer func() {
   485  		err := stop1()
   486  		if err != nil {
   487  			require.NoError(t, backend.StopNode())
   488  		}
   489  	}()
   490  	defer func() {
   491  		err := stop2()
   492  		if err != nil {
   493  			require.NoError(t, backend.StopNode())
   494  		}
   495  	}()
   496  	defer func() {
   497  		err := stopWallet()
   498  		if err != nil {
   499  			require.NoError(t, backend.StopNode())
   500  		}
   501  	}()
   502  	require.NoError(t, err)
   503  
   504  	config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
   505  	require.NoError(t, err)
   506  	require.NoError(t, backend.AccountManager().InitKeystore(config.KeyStoreDir))
   507  	config.NoDiscovery = false
   508  	// doesn't have to be running. just any valid enode to bypass validation.
   509  	config.ClusterConfig.BootNodes = []string{
   510  		"enode://e8a7c03b58911e98bbd66accb2a55d57683f35b23bf9dfca89e5e244eb5cc3f25018b4112db507faca34fb69ffb44b362f79eda97a669a8df29c72e654416784@0.0.0.0:30404",
   511  	}
   512  	require.NoError(t, err)
   513  	require.NoError(t, backend.StartNode(config))
   514  	require.NoError(t, backend.StopNode())
   515  	require.NoError(t, backend.StartNode(config))
   516  	require.NoError(t, backend.StopNode())
   517  }
   518  
   519  func TestHashTypedData(t *testing.T) {
   520  	utils.Init()
   521  
   522  	backend, stop1, stop2, stopWallet, err := setupGethStatusBackend()
   523  	defer func() {
   524  		err := stop1()
   525  		if err != nil {
   526  			require.NoError(t, backend.StopNode())
   527  		}
   528  	}()
   529  	defer func() {
   530  		err := stop2()
   531  		if err != nil {
   532  			require.NoError(t, backend.StopNode())
   533  		}
   534  	}()
   535  	defer func() {
   536  		err := stopWallet()
   537  		if err != nil {
   538  			require.NoError(t, backend.StopNode())
   539  		}
   540  	}()
   541  	require.NoError(t, err)
   542  
   543  	config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
   544  	require.NoError(t, err)
   545  	require.NoError(t, backend.AccountManager().InitKeystore(config.KeyStoreDir))
   546  	err = backend.StartNode(config)
   547  	require.NoError(t, err)
   548  	defer func() {
   549  		require.NoError(t, backend.StopNode())
   550  	}()
   551  
   552  	eip712Domain := "EIP712Domain"
   553  	mytypes := typeddata.Types{
   554  		eip712Domain: []typeddata.Field{
   555  			{Name: "name", Type: "string"},
   556  			{Name: "version", Type: "string"},
   557  			{Name: "chainId", Type: "uint256"},
   558  			{Name: "verifyingContract", Type: "address"},
   559  		},
   560  		"Text": []typeddata.Field{
   561  			{Name: "body", Type: "string"},
   562  		},
   563  	}
   564  
   565  	domain := map[string]json.RawMessage{
   566  		"name":              json.RawMessage(`"Ether Text"`),
   567  		"version":           json.RawMessage(`"1"`),
   568  		"chainId":           json.RawMessage(fmt.Sprintf("%d", params.StatusChainNetworkID)),
   569  		"verifyingContract": json.RawMessage(`"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"`),
   570  	}
   571  	msg := map[string]json.RawMessage{
   572  		"body": json.RawMessage(`"Hello, Bob!"`),
   573  	}
   574  
   575  	typed := typeddata.TypedData{
   576  		Types:       mytypes,
   577  		PrimaryType: "Text",
   578  		Domain:      domain,
   579  		Message:     msg,
   580  	}
   581  
   582  	hash, err := backend.HashTypedData(typed)
   583  	require.NoError(t, err)
   584  	assert.NotEqual(t, types.Hash{}, hash)
   585  }
   586  
   587  func TestBackendGetVerifiedAccount(t *testing.T) {
   588  	utils.Init()
   589  
   590  	password := "test"
   591  	backend, defers, err := setupWalletTest(t, password)
   592  	require.NoError(t, err)
   593  	defer defers()
   594  
   595  	t.Run("AccountDoesntExist", func(t *testing.T) {
   596  		pkey, err := gethcrypto.GenerateKey()
   597  		require.NoError(t, err)
   598  		address := gethcrypto.PubkeyToAddress(pkey.PublicKey)
   599  		key, err := backend.getVerifiedWalletAccount(address.String(), password)
   600  		require.EqualError(t, err, transactions.ErrAccountDoesntExist.Error())
   601  		require.Nil(t, key)
   602  	})
   603  
   604  	t.Run("PasswordDoesntMatch", func(t *testing.T) {
   605  		pkey, err := crypto.GenerateKey()
   606  		require.NoError(t, err)
   607  		address := crypto.PubkeyToAddress(pkey.PublicKey)
   608  		keyUIDHex := sha256.Sum256(gethcrypto.FromECDSAPub(&pkey.PublicKey))
   609  		keyUID := types.EncodeHex(keyUIDHex[:])
   610  
   611  		db, err := accounts.NewDB(backend.appDB)
   612  
   613  		require.NoError(t, err)
   614  		_, err = backend.AccountManager().ImportAccount(pkey, password)
   615  		require.NoError(t, err)
   616  		require.NoError(t, db.SaveOrUpdateKeypair(&accounts.Keypair{
   617  			KeyUID: keyUID,
   618  			Name:   "private key keypair",
   619  			Type:   accounts.KeypairTypeKey,
   620  			Accounts: []*accounts.Account{
   621  				&accounts.Account{
   622  					Address: address,
   623  					KeyUID:  keyUID,
   624  				},
   625  			},
   626  		}))
   627  		key, err := backend.getVerifiedWalletAccount(address.String(), "wrong-password")
   628  		require.EqualError(t, err, "could not decrypt key with given password")
   629  		require.Nil(t, key)
   630  	})
   631  
   632  	t.Run("PartialAccount", func(t *testing.T) {
   633  		// Create a derived wallet account without storing the keys
   634  		db, err := accounts.NewDB(backend.appDB)
   635  		require.NoError(t, err)
   636  		newPath := "m/0"
   637  		walletRootAddress, err := db.GetWalletRootAddress()
   638  		require.NoError(t, err)
   639  
   640  		walletInfo, err := backend.AccountManager().AccountsGenerator().LoadAccount(walletRootAddress.String(), password)
   641  		require.NoError(t, err)
   642  		derivedInfos, err := backend.AccountManager().AccountsGenerator().DeriveAddresses(walletInfo.ID, []string{newPath})
   643  		require.NoError(t, err)
   644  		derivedInfo := derivedInfos[newPath]
   645  
   646  		keypair := &accounts.Keypair{
   647  			KeyUID: walletInfo.KeyUID,
   648  			Name:   "profile keypair",
   649  			Type:   accounts.KeypairTypeProfile,
   650  			Accounts: []*accounts.Account{
   651  				&accounts.Account{
   652  					Address:   types.HexToAddress(derivedInfo.Address),
   653  					KeyUID:    walletInfo.KeyUID,
   654  					Type:      accounts.AccountTypeGenerated,
   655  					PublicKey: types.Hex2Bytes(derivedInfo.PublicKey),
   656  					Path:      newPath,
   657  					Wallet:    false,
   658  					Name:      "PartialAccount",
   659  				},
   660  			},
   661  		}
   662  		require.NoError(t, db.SaveOrUpdateKeypair(keypair))
   663  
   664  		// With partial account we need to dynamically generate private key
   665  		key, err := backend.getVerifiedWalletAccount(keypair.Accounts[0].Address.Hex(), password)
   666  		require.NoError(t, err)
   667  		require.Equal(t, keypair.Accounts[0].Address, key.Address)
   668  	})
   669  
   670  	t.Run("Success", func(t *testing.T) {
   671  		pkey, err := crypto.GenerateKey()
   672  		require.NoError(t, err)
   673  		address := crypto.PubkeyToAddress(pkey.PublicKey)
   674  		keyUIDHex := sha256.Sum256(gethcrypto.FromECDSAPub(&pkey.PublicKey))
   675  		keyUID := types.EncodeHex(keyUIDHex[:])
   676  
   677  		db, err := accounts.NewDB(backend.appDB)
   678  		require.NoError(t, err)
   679  		defer db.Close()
   680  		_, err = backend.AccountManager().ImportAccount(pkey, password)
   681  		require.NoError(t, err)
   682  		require.NoError(t, db.SaveOrUpdateKeypair(&accounts.Keypair{
   683  			KeyUID: keyUID,
   684  			Name:   "private key keypair",
   685  			Type:   accounts.KeypairTypeKey,
   686  			Accounts: []*accounts.Account{
   687  				&accounts.Account{
   688  					Address: address,
   689  					KeyUID:  keyUID,
   690  				},
   691  			},
   692  		}))
   693  		key, err := backend.getVerifiedWalletAccount(address.String(), password)
   694  		require.NoError(t, err)
   695  		require.Equal(t, address, key.Address)
   696  	})
   697  }
   698  
   699  func TestRuntimeLogLevelIsNotWrittenToDatabase(t *testing.T) {
   700  	utils.Init()
   701  
   702  	b := NewGethStatusBackend()
   703  	chatKey, err := gethcrypto.GenerateKey()
   704  	require.NoError(t, err)
   705  	walletKey, err := gethcrypto.GenerateKey()
   706  	require.NoError(t, err)
   707  	keyUIDHex := sha256.Sum256(gethcrypto.FromECDSAPub(&chatKey.PublicKey))
   708  	keyUID := types.EncodeHex(keyUIDHex[:])
   709  	main := multiaccounts.Account{
   710  		KeyUID: keyUID,
   711  	}
   712  
   713  	tmpdir := t.TempDir()
   714  
   715  	json := `{
   716  		"NetworkId": 3,
   717  		"DataDir": "` + tmpdir + `",
   718  		"KeyStoreDir": "` + tmpdir + `",
   719  		"KeycardPairingDataFile": "` + path.Join(tmpdir, "keycard/pairings.json") + `",
   720  		"NoDiscovery": true,
   721  		"TorrentConfig": {
   722  			"Port": 9025,
   723  			"Enabled": false,
   724  			"DataDir": "` + tmpdir + `/archivedata",
   725  			"TorrentDir": "` + tmpdir + `/torrents"
   726  		},
   727  		"RuntimeLogLevel": "INFO",
   728  		"LogLevel": "DEBUG"
   729  	}`
   730  
   731  	conf, err := params.NewConfigFromJSON(json)
   732  	require.NoError(t, err)
   733  	require.Equal(t, "INFO", conf.RuntimeLogLevel)
   734  	keyhex := hex.EncodeToString(gethcrypto.FromECDSA(chatKey))
   735  
   736  	require.NoError(t, b.AccountManager().InitKeystore(conf.KeyStoreDir))
   737  	b.UpdateRootDataDir(conf.DataDir)
   738  	require.NoError(t, b.OpenAccounts())
   739  	require.NotNil(t, b.statusNode.HTTPServer())
   740  
   741  	address := crypto.PubkeyToAddress(walletKey.PublicKey)
   742  
   743  	settings := testSettings
   744  	settings.KeyUID = keyUID
   745  	settings.Address = crypto.PubkeyToAddress(walletKey.PublicKey)
   746  
   747  	chatPubKey := crypto.FromECDSAPub(&chatKey.PublicKey)
   748  	require.NoError(t, b.SaveAccountAndStartNodeWithKey(main, "test-pass", settings, conf,
   749  		[]*accounts.Account{
   750  			{Address: address, KeyUID: keyUID, Wallet: true},
   751  			{Address: crypto.PubkeyToAddress(chatKey.PublicKey), KeyUID: keyUID, Chat: true, PublicKey: chatPubKey}}, keyhex))
   752  	require.NoError(t, b.Logout())
   753  	require.NoError(t, b.StopNode())
   754  
   755  	require.NoError(t, b.StartNodeWithKey(main, "test-pass", keyhex, conf))
   756  	defer func() {
   757  		assert.NoError(t, b.Logout())
   758  		assert.NoError(t, b.StopNode())
   759  	}()
   760  
   761  	c, err := b.GetNodeConfig()
   762  	require.NoError(t, err)
   763  	require.Equal(t, "", c.RuntimeLogLevel)
   764  	require.Equal(t, "DEBUG", c.LogLevel)
   765  }
   766  
   767  func TestLoginWithKey(t *testing.T) {
   768  	utils.Init()
   769  
   770  	b := NewGethStatusBackend()
   771  	chatKey, err := gethcrypto.GenerateKey()
   772  	require.NoError(t, err)
   773  	walletKey, err := gethcrypto.GenerateKey()
   774  	require.NoError(t, err)
   775  	keyUIDHex := sha256.Sum256(gethcrypto.FromECDSAPub(&chatKey.PublicKey))
   776  	keyUID := types.EncodeHex(keyUIDHex[:])
   777  	main := multiaccounts.Account{
   778  		KeyUID: keyUID,
   779  	}
   780  	tmpdir := t.TempDir()
   781  	conf, err := params.NewNodeConfig(tmpdir, 1777)
   782  	require.NoError(t, err)
   783  	keyhex := hex.EncodeToString(gethcrypto.FromECDSA(chatKey))
   784  
   785  	require.NoError(t, b.AccountManager().InitKeystore(conf.KeyStoreDir))
   786  	b.UpdateRootDataDir(conf.DataDir)
   787  	require.NoError(t, b.OpenAccounts())
   788  	require.NotNil(t, b.statusNode.HTTPServer())
   789  
   790  	address := crypto.PubkeyToAddress(walletKey.PublicKey)
   791  
   792  	settings := testSettings
   793  	settings.KeyUID = keyUID
   794  	settings.Address = crypto.PubkeyToAddress(walletKey.PublicKey)
   795  
   796  	chatPubKey := crypto.FromECDSAPub(&chatKey.PublicKey)
   797  	require.NoError(t, b.SaveAccountAndStartNodeWithKey(main, "test-pass", settings, conf,
   798  		[]*accounts.Account{
   799  			{Address: address, KeyUID: keyUID, Wallet: true},
   800  			{Address: crypto.PubkeyToAddress(chatKey.PublicKey), KeyUID: keyUID, Chat: true, PublicKey: chatPubKey}}, keyhex))
   801  	require.NoError(t, b.Logout())
   802  	require.NoError(t, b.StopNode())
   803  
   804  	require.NoError(t, b.AccountManager().InitKeystore(conf.KeyStoreDir))
   805  	b.UpdateRootDataDir(conf.DataDir)
   806  	require.NoError(t, b.OpenAccounts())
   807  
   808  	require.NoError(t, b.StartNodeWithKey(main, "test-pass", keyhex, conf))
   809  	defer func() {
   810  		assert.NoError(t, b.Logout())
   811  		assert.NoError(t, b.StopNode())
   812  	}()
   813  	extkey, err := b.accountManager.SelectedChatAccount()
   814  	require.NoError(t, err)
   815  	require.Equal(t, crypto.PubkeyToAddress(chatKey.PublicKey), extkey.Address)
   816  
   817  	activeAccount, err := b.GetActiveAccount()
   818  	require.NoError(t, err)
   819  	require.NotNil(t, activeAccount.ColorHash)
   820  }
   821  
   822  func TestLoginAccount(t *testing.T) {
   823  	utils.Init()
   824  	password := "some-password"
   825  	tmpdir := t.TempDir()
   826  	nameserver := "8.8.8.8"
   827  
   828  	b := NewGethStatusBackend()
   829  	createAccountRequest := &requests.CreateAccount{
   830  		DisplayName:        "some-display-name",
   831  		CustomizationColor: "#ffffff",
   832  		Password:           password,
   833  		RootDataDir:        tmpdir,
   834  		LogFilePath:        tmpdir + "/log",
   835  		WakuV2Nameserver:   &nameserver,
   836  		WakuV2Fleet:        "status.staging",
   837  	}
   838  	c := make(chan interface{}, 10)
   839  	signal.SetMobileSignalHandler(func(data []byte) {
   840  		if strings.Contains(string(data), signal.EventLoggedIn) {
   841  			require.Contains(t, string(data), "status.staging")
   842  			c <- struct{}{}
   843  		}
   844  	})
   845  	t.Cleanup(signal.ResetMobileSignalHandler)
   846  	waitForLogin := func(chan interface{}) {
   847  		select {
   848  		case <-c:
   849  			break
   850  		case <-time.After(5 * time.Second):
   851  			t.FailNow()
   852  		}
   853  	}
   854  
   855  	acc, err := b.CreateAccountAndLogin(createAccountRequest)
   856  	require.NoError(t, err)
   857  	require.Equal(t, nameserver, b.config.WakuV2Config.Nameserver)
   858  
   859  	waitForLogin(c)
   860  	require.NoError(t, b.Logout())
   861  	require.NoError(t, b.StopNode())
   862  
   863  	accounts, err := b.GetAccounts()
   864  	require.NoError(t, err)
   865  	require.Len(t, accounts, 1)
   866  
   867  	require.NotEmpty(t, accounts[0].KeyUID)
   868  	require.Equal(t, acc.KeyUID, accounts[0].KeyUID)
   869  
   870  	loginAccountRequest := &requests.Login{
   871  		KeyUID:           accounts[0].KeyUID,
   872  		Password:         password,
   873  		WakuV2Nameserver: nameserver,
   874  	}
   875  	err = b.LoginAccount(loginAccountRequest)
   876  	require.NoError(t, err)
   877  	waitForLogin(c)
   878  
   879  	require.Equal(t, nameserver, b.config.WakuV2Config.Nameserver)
   880  }
   881  
   882  func TestVerifyDatabasePassword(t *testing.T) {
   883  	utils.Init()
   884  
   885  	b := NewGethStatusBackend()
   886  	chatKey, err := gethcrypto.GenerateKey()
   887  	require.NoError(t, err)
   888  	walletKey, err := gethcrypto.GenerateKey()
   889  	require.NoError(t, err)
   890  	keyUIDHex := sha256.Sum256(gethcrypto.FromECDSAPub(&chatKey.PublicKey))
   891  	keyUID := types.EncodeHex(keyUIDHex[:])
   892  	main := multiaccounts.Account{
   893  		KeyUID: keyUID,
   894  	}
   895  	tmpdir := t.TempDir()
   896  	conf, err := params.NewNodeConfig(tmpdir, 1777)
   897  	require.NoError(t, err)
   898  	keyhex := hex.EncodeToString(gethcrypto.FromECDSA(chatKey))
   899  
   900  	require.NoError(t, b.AccountManager().InitKeystore(conf.KeyStoreDir))
   901  	b.UpdateRootDataDir(conf.DataDir)
   902  	require.NoError(t, b.OpenAccounts())
   903  
   904  	address := crypto.PubkeyToAddress(walletKey.PublicKey)
   905  
   906  	settings := testSettings
   907  	settings.KeyUID = keyUID
   908  	settings.Address = crypto.PubkeyToAddress(walletKey.PublicKey)
   909  
   910  	chatPubKey := crypto.FromECDSAPub(&chatKey.PublicKey)
   911  
   912  	require.NoError(t, b.SaveAccountAndStartNodeWithKey(main, "test-pass", settings, conf, []*accounts.Account{
   913  		{Address: address, KeyUID: keyUID, Wallet: true},
   914  		{Address: crypto.PubkeyToAddress(chatKey.PublicKey), KeyUID: keyUID, Chat: true, PublicKey: chatPubKey}}, keyhex))
   915  	require.NoError(t, b.Logout())
   916  	require.NoError(t, b.StopNode())
   917  
   918  	require.Error(t, b.VerifyDatabasePassword(main.KeyUID, "wrong-pass"))
   919  	require.NoError(t, b.VerifyDatabasePassword(main.KeyUID, "test-pass"))
   920  }
   921  
   922  func TestDeleteMultiaccount(t *testing.T) {
   923  	backend := NewGethStatusBackend()
   924  
   925  	rootDataDir := t.TempDir()
   926  
   927  	keyStoreDir := filepath.Join(rootDataDir, "keystore")
   928  
   929  	backend.rootDataDir = rootDataDir
   930  
   931  	err := backend.AccountManager().InitKeystore(keyStoreDir)
   932  	require.NoError(t, err)
   933  
   934  	backend.AccountManager()
   935  	accs, err := backend.AccountManager().
   936  		AccountsGenerator().
   937  		GenerateAndDeriveAddresses(12, 1, "", []string{"m/44'/60'/0'/0"})
   938  	require.NoError(t, err)
   939  
   940  	generateAccount := accs[0]
   941  	accountInfo, err := backend.AccountManager().
   942  		AccountsGenerator().
   943  		StoreAccount(generateAccount.ID, "123123")
   944  	require.NoError(t, err)
   945  
   946  	account := multiaccounts.Account{
   947  		Name:           "foo",
   948  		Timestamp:      1,
   949  		KeycardPairing: "pairing",
   950  		KeyUID:         generateAccount.KeyUID,
   951  	}
   952  
   953  	err = backend.ensureAppDBOpened(account, "123123")
   954  	require.NoError(t, err)
   955  
   956  	s := settings.Settings{
   957  		Address:           types.HexToAddress(accountInfo.Address),
   958  		CurrentNetwork:    "mainnet_rpc",
   959  		DappsAddress:      types.HexToAddress(accountInfo.Address),
   960  		EIP1581Address:    types.HexToAddress(accountInfo.Address),
   961  		InstallationID:    "d3efcff6-cffa-560e-a547-21d3858cbc51",
   962  		KeyUID:            account.KeyUID,
   963  		LatestDerivedPath: 0,
   964  		Name:              "Jittery Cornflowerblue Kingbird",
   965  		Networks:          &networks,
   966  		PhotoPath:         "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAAjklEQVR4nOzXwQmFMBAAUZXUYh32ZB32ZB02sxYQQSZGsod55/91WFgSS0RM+SyjA56ZRZhFmEWYRRT6h+M6G16zrxv6fdJpmUWYRbxsYr13dKfanpN0WmYRZhGzXz6AWYRZRIfbaX26fT9Jk07LLMIsosPt9I/dTDotswizCG+nhFmEWYRZhFnEHQAA///z1CFkYamgfQAAAABJRU5ErkJggg==",
   967  		PreviewPrivacy:    false,
   968  		PublicKey:         accountInfo.PublicKey,
   969  		SigningPhrase:     "yurt joey vibe",
   970  		WalletRootAddress: types.HexToAddress(accountInfo.Address)}
   971  
   972  	err = backend.saveAccountsAndSettings(
   973  		s,
   974  		&params.NodeConfig{},
   975  		nil)
   976  	require.Error(t, err)
   977  	require.True(t, err == accounts.ErrKeypairWithoutAccounts)
   978  
   979  	err = backend.OpenAccounts()
   980  	require.NoError(t, err)
   981  
   982  	err = backend.SaveAccount(account)
   983  	require.NoError(t, err)
   984  
   985  	files, err := ioutil.ReadDir(rootDataDir)
   986  	require.NoError(t, err)
   987  	require.NotEqual(t, 3, len(files))
   988  
   989  	err = backend.DeleteMultiaccount(account.KeyUID, keyStoreDir)
   990  	require.NoError(t, err)
   991  
   992  	files, err = ioutil.ReadDir(rootDataDir)
   993  	require.NoError(t, err)
   994  	require.Equal(t, 3, len(files))
   995  }
   996  
   997  func TestConvertAccount(t *testing.T) {
   998  	const mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
   999  	const password = "111111"        // represents password for a regular user
  1000  	const keycardPassword = "222222" // represents password for a keycard user
  1001  	const keycardUID = "1234"
  1002  	const pathEIP1581Root = "m/43'/60'/1581'"
  1003  	const pathEIP1581Chat = pathEIP1581Root + "/0'/0"
  1004  	const pathWalletRoot = "m/44'/60'/0'/0"
  1005  	const pathDefaultWalletAccount = pathWalletRoot + "/0"
  1006  	const customWalletPath1 = pathWalletRoot + "/1"
  1007  	const customWalletPath2 = pathWalletRoot + "/2"
  1008  	var allGeneratedPaths []string
  1009  	allGeneratedPaths = append(allGeneratedPaths, pathEIP1581Root, pathEIP1581Chat, pathWalletRoot, pathDefaultWalletAccount, customWalletPath1, customWalletPath2)
  1010  
  1011  	var err error
  1012  
  1013  	keystoreContainsFileForAccount := func(keyStoreDir string, hexAddress string) bool {
  1014  		addrWithoutPrefix := strings.ToLower(hexAddress[2:])
  1015  		found := false
  1016  		err = filepath.Walk(keyStoreDir, func(path string, fileInfo os.FileInfo, err error) error {
  1017  			if err != nil {
  1018  				return err
  1019  			}
  1020  			if !fileInfo.IsDir() && strings.Contains(strings.ToUpper(path), strings.ToUpper(addrWithoutPrefix)) {
  1021  				found = true
  1022  			}
  1023  			return nil
  1024  		})
  1025  		return found
  1026  	}
  1027  
  1028  	rootDataDir := t.TempDir()
  1029  
  1030  	keyStoreDir := filepath.Join(rootDataDir, "keystore")
  1031  
  1032  	utils.Init()
  1033  
  1034  	backend, stop1, stop2, stopWallet, err := setupGethStatusBackend()
  1035  	defer func() {
  1036  		err := stop1()
  1037  		if err != nil {
  1038  			require.NoError(t, backend.StopNode())
  1039  		}
  1040  	}()
  1041  	defer func() {
  1042  		err := stop2()
  1043  		if err != nil {
  1044  			require.NoError(t, backend.StopNode())
  1045  		}
  1046  	}()
  1047  	defer func() {
  1048  		err := stopWallet()
  1049  		if err != nil {
  1050  			require.NoError(t, backend.StopNode())
  1051  		}
  1052  	}()
  1053  	require.NoError(t, err)
  1054  
  1055  	backend.rootDataDir = rootDataDir
  1056  	require.NoError(t, backend.AccountManager().InitKeystore(keyStoreDir))
  1057  	err = backend.OpenAccounts()
  1058  	require.NoError(t, err)
  1059  
  1060  	genAccInfo, err := backend.AccountManager().AccountsGenerator().ImportMnemonic(mnemonic, "")
  1061  	assert.NoError(t, err)
  1062  
  1063  	masterAddress := genAccInfo.Address
  1064  
  1065  	accountInfo, err := backend.AccountManager().AccountsGenerator().StoreAccount(genAccInfo.ID, password)
  1066  	assert.NoError(t, err)
  1067  
  1068  	found := keystoreContainsFileForAccount(keyStoreDir, accountInfo.Address)
  1069  	require.True(t, found)
  1070  
  1071  	derivedAccounts, err := backend.AccountManager().AccountsGenerator().StoreDerivedAccounts(genAccInfo.ID, password, allGeneratedPaths)
  1072  	assert.NoError(t, err)
  1073  
  1074  	chatKey := derivedAccounts[pathEIP1581Chat].PrivateKey[2:]
  1075  	chatAddress := derivedAccounts[pathEIP1581Chat].Address
  1076  	found = keystoreContainsFileForAccount(keyStoreDir, chatAddress)
  1077  	require.True(t, found)
  1078  
  1079  	defaultSettings, err := defaultSettings(genAccInfo.KeyUID, genAccInfo.Address, derivedAccounts)
  1080  	require.NoError(t, err)
  1081  	nodeConfig, err := DefaultNodeConfig(defaultSettings.InstallationID, &requests.CreateAccount{
  1082  		LogLevel: defaultSettings.LogLevel,
  1083  	})
  1084  	require.NoError(t, err)
  1085  	nodeConfig.DataDir = rootDataDir
  1086  	nodeConfig.KeyStoreDir = keyStoreDir
  1087  
  1088  	profileKeypair := &accounts.Keypair{
  1089  		KeyUID:      genAccInfo.KeyUID,
  1090  		Name:        "Profile Name",
  1091  		Type:        accounts.KeypairTypeProfile,
  1092  		DerivedFrom: masterAddress,
  1093  	}
  1094  
  1095  	profileKeypair.Accounts = append(profileKeypair.Accounts, &accounts.Account{
  1096  		Address:   types.HexToAddress(chatAddress),
  1097  		KeyUID:    profileKeypair.KeyUID,
  1098  		Type:      accounts.AccountTypeGenerated,
  1099  		PublicKey: types.Hex2Bytes(accountInfo.PublicKey),
  1100  		Path:      pathEIP1581Chat,
  1101  		Wallet:    false,
  1102  		Chat:      true,
  1103  		Name:      "GeneratedAccount",
  1104  	})
  1105  
  1106  	for p, dAccInfo := range derivedAccounts {
  1107  		found = keystoreContainsFileForAccount(keyStoreDir, dAccInfo.Address)
  1108  		require.NoError(t, err)
  1109  		require.True(t, found)
  1110  
  1111  		if p == pathDefaultWalletAccount ||
  1112  			p == customWalletPath1 ||
  1113  			p == customWalletPath2 {
  1114  			wAcc := &accounts.Account{
  1115  				Address: types.HexToAddress(dAccInfo.Address),
  1116  				KeyUID:  genAccInfo.KeyUID,
  1117  				Wallet:  false,
  1118  				Chat:    false,
  1119  				Type:    accounts.AccountTypeGenerated,
  1120  				Path:    p,
  1121  				Name:    "derivacc" + p,
  1122  				Hidden:  false,
  1123  				Removed: false,
  1124  			}
  1125  			if p == pathDefaultWalletAccount {
  1126  				wAcc.Wallet = true
  1127  			}
  1128  			profileKeypair.Accounts = append(profileKeypair.Accounts, wAcc)
  1129  		}
  1130  	}
  1131  
  1132  	account := multiaccounts.Account{
  1133  		Name:      profileKeypair.Name,
  1134  		Timestamp: 1,
  1135  		KeyUID:    profileKeypair.KeyUID,
  1136  	}
  1137  
  1138  	err = backend.ensureAppDBOpened(account, password)
  1139  	require.NoError(t, err)
  1140  
  1141  	err = backend.StartNodeWithAccountAndInitialConfig(account, password, *defaultSettings, nodeConfig, profileKeypair.Accounts, nil)
  1142  	require.NoError(t, err)
  1143  	multiaccounts, err := backend.GetAccounts()
  1144  	require.NoError(t, err)
  1145  	require.NotEmpty(t, multiaccounts[0].ColorHash)
  1146  	serverMessenger := backend.Messenger()
  1147  	require.NotNil(t, serverMessenger)
  1148  
  1149  	files, err := ioutil.ReadDir(rootDataDir)
  1150  	require.NoError(t, err)
  1151  	require.NotEqual(t, 3, len(files))
  1152  
  1153  	keycardAccount := account
  1154  	keycardAccount.KeycardPairing = "pairing"
  1155  
  1156  	keycardSettings := settings.Settings{
  1157  		KeycardInstanceUID: "0xdeadbeef",
  1158  		KeycardPairedOn:    1,
  1159  		KeycardPairing:     "pairing",
  1160  	}
  1161  
  1162  	// Ensure we're able to open the DB
  1163  	err = backend.ensureAppDBOpened(keycardAccount, keycardPassword)
  1164  	require.NoError(t, err)
  1165  
  1166  	// db creation
  1167  	db, err := accounts.NewDB(backend.appDB)
  1168  	require.NoError(t, err)
  1169  
  1170  	// Check that there is no registered keycards
  1171  	keycards, err := db.GetKeycardsWithSameKeyUID(genAccInfo.KeyUID)
  1172  	require.NoError(t, err)
  1173  	require.Equal(t, 0, len(keycards))
  1174  
  1175  	// Converting to a keycard account
  1176  	err = backend.ConvertToKeycardAccount(keycardAccount, keycardSettings, keycardUID, password, keycardPassword)
  1177  	require.NoError(t, err)
  1178  
  1179  	// Validating results of converting to a keycard account.
  1180  	// All keystore files for the account which is migrated need to be removed.
  1181  	found = keystoreContainsFileForAccount(keyStoreDir, masterAddress)
  1182  	require.False(t, found)
  1183  
  1184  	for _, dAccInfo := range derivedAccounts {
  1185  		found = keystoreContainsFileForAccount(keyStoreDir, dAccInfo.Address)
  1186  		require.False(t, found)
  1187  	}
  1188  
  1189  	require.NoError(t, backend.Logout())
  1190  	require.NoError(t, backend.StopNode())
  1191  
  1192  	require.NoError(t, backend.AccountManager().InitKeystore(keyStoreDir))
  1193  	require.NoError(t, backend.OpenAccounts())
  1194  
  1195  	require.NoError(t, backend.StartNodeWithKey(account, keycardPassword, chatKey, nodeConfig))
  1196  	defer func() {
  1197  		assert.NoError(t, backend.Logout())
  1198  		assert.NoError(t, backend.StopNode())
  1199  	}()
  1200  
  1201  	// Ensure we're able to open the DB
  1202  	err = backend.ensureAppDBOpened(keycardAccount, keycardPassword)
  1203  	require.NoError(t, err)
  1204  
  1205  	// db creation after re-encryption
  1206  	db1, err := accounts.NewDB(backend.appDB)
  1207  	require.NoError(t, err)
  1208  
  1209  	// Check that there is a registered keycard
  1210  	keycards, err = db1.GetKeycardsWithSameKeyUID(genAccInfo.KeyUID)
  1211  	require.NoError(t, err)
  1212  	require.Equal(t, 1, len(keycards))
  1213  
  1214  	// Converting to a regular account
  1215  	err = backend.ConvertToRegularAccount(mnemonic, keycardPassword, password)
  1216  	require.NoError(t, err)
  1217  
  1218  	// Validating results of converting to a regular account.
  1219  	// All keystore files for need to be created.
  1220  	found = keystoreContainsFileForAccount(keyStoreDir, accountInfo.Address)
  1221  	require.True(t, found)
  1222  
  1223  	for _, dAccInfo := range derivedAccounts {
  1224  		found = keystoreContainsFileForAccount(keyStoreDir, dAccInfo.Address)
  1225  		require.True(t, found)
  1226  	}
  1227  
  1228  	found = keystoreContainsFileForAccount(keyStoreDir, masterAddress)
  1229  	require.True(t, found)
  1230  
  1231  	// Ensure we're able to open the DB
  1232  	err = backend.ensureAppDBOpened(keycardAccount, password)
  1233  	require.NoError(t, err)
  1234  
  1235  	// db creation after re-encryption
  1236  	db2, err := accounts.NewDB(backend.appDB)
  1237  	require.NoError(t, err)
  1238  
  1239  	// Check that there is no registered keycards
  1240  	keycards, err = db2.GetKeycardsWithSameKeyUID(genAccInfo.KeyUID)
  1241  	require.NoError(t, err)
  1242  	require.Equal(t, 0, len(keycards))
  1243  }
  1244  
  1245  func copyFile(srcFolder string, dstFolder string, fileName string, t *testing.T) {
  1246  	data, err := ioutil.ReadFile(path.Join(srcFolder, fileName))
  1247  	if err != nil {
  1248  		t.Fail()
  1249  	}
  1250  
  1251  	err = ioutil.WriteFile(path.Join(dstFolder, fileName), data, 0600)
  1252  	if err != nil {
  1253  		t.Fail()
  1254  	}
  1255  }
  1256  
  1257  func copyDir(srcFolder string, dstFolder string, t *testing.T) {
  1258  	files, err := ioutil.ReadDir(srcFolder)
  1259  	require.NoError(t, err)
  1260  	for _, file := range files {
  1261  		if !file.IsDir() {
  1262  			copyFile(srcFolder, dstFolder, file.Name(), t)
  1263  		} else {
  1264  			childFolder := path.Join(srcFolder, file.Name())
  1265  			newFolder := path.Join(dstFolder, file.Name())
  1266  			err = os.MkdirAll(newFolder, os.ModePerm)
  1267  			require.NoError(t, err)
  1268  			copyDir(childFolder, newFolder, t)
  1269  		}
  1270  	}
  1271  }
  1272  
  1273  func loginDesktopUser(t *testing.T, conf *params.NodeConfig) {
  1274  	// The following passwords and DB used in this test unit are only
  1275  	// used to determine if login process works correctly after a migration
  1276  
  1277  	// Expected account data:
  1278  	keyUID := "0x7c46c8f6f059ab72d524f2a6d356904db30bb0392636172ab3929a6bd2220f84" // #nosec G101
  1279  	username := "TestUser"
  1280  	passwd := "0xC888C9CE9E098D5864D3DED6EBCC140A12142263BACE3A23A36F9905F12BD64A" // #nosec G101
  1281  
  1282  	b := NewGethStatusBackend()
  1283  
  1284  	require.NoError(t, b.AccountManager().InitKeystore(conf.KeyStoreDir))
  1285  	b.UpdateRootDataDir(conf.DataDir)
  1286  
  1287  	require.NoError(t, b.OpenAccounts())
  1288  
  1289  	accounts, err := b.GetAccounts()
  1290  	require.NoError(t, err)
  1291  
  1292  	require.Len(t, accounts, 1)
  1293  	require.Equal(t, username, accounts[0].Name)
  1294  	require.Equal(t, keyUID, accounts[0].KeyUID)
  1295  
  1296  	wg := sync.WaitGroup{}
  1297  	wg.Add(1)
  1298  	go func() {
  1299  		defer wg.Done()
  1300  		err := b.StartNodeWithAccount(accounts[0], passwd, conf, nil)
  1301  		require.NoError(t, err)
  1302  	}()
  1303  
  1304  	wg.Wait()
  1305  	require.NoError(t, b.Logout())
  1306  	require.NotNil(t, b.statusNode.HTTPServer())
  1307  	require.NoError(t, b.StopNode())
  1308  
  1309  }
  1310  
  1311  func TestLoginAndMigrationsStillWorkWithExistingDesktopUser(t *testing.T) {
  1312  	utils.Init()
  1313  
  1314  	srcFolder := "../static/test-0.132.0-account/"
  1315  
  1316  	tmpdir := t.TempDir()
  1317  
  1318  	copyDir(srcFolder, tmpdir, t)
  1319  
  1320  	conf, err := params.NewNodeConfig(tmpdir, 1777)
  1321  	require.NoError(t, err)
  1322  
  1323  	loginDesktopUser(t, conf)
  1324  	loginDesktopUser(t, conf) // Login twice to catch weird errors that only appear after logout
  1325  }
  1326  
  1327  func TestChangeDatabasePassword(t *testing.T) {
  1328  	oldPassword := "password"
  1329  	newPassword := "newPassword"
  1330  
  1331  	backend := NewGethStatusBackend()
  1332  	backend.UpdateRootDataDir(t.TempDir())
  1333  
  1334  	// Setup keystore to test decryption of it
  1335  	keyStoreDir := t.TempDir()
  1336  	require.NoError(t, backend.accountManager.InitKeystore(keyStoreDir))
  1337  
  1338  	_, accountInfo, _, err := backend.accountManager.CreateAccount(oldPassword)
  1339  	require.NoError(t, err)
  1340  
  1341  	account := multiaccounts.Account{
  1342  		Name:          "TestAccount",
  1343  		Timestamp:     1,
  1344  		KeyUID:        "0x7c46c8f6f059ab72d524f2a6d356904db30bb0392636172ab3929a6bd2220f84",
  1345  		KDFIterations: 1,
  1346  	}
  1347  
  1348  	// Initialize accounts DB
  1349  	err = backend.OpenAccounts()
  1350  	require.NoError(t, err)
  1351  	err = backend.SaveAccount(account)
  1352  	require.NoError(t, err)
  1353  
  1354  	// Created DBs with old password
  1355  	err = backend.ensureDBsOpened(account, oldPassword)
  1356  	require.NoError(t, err)
  1357  
  1358  	// Change password
  1359  	err = backend.ChangeDatabasePassword(account.KeyUID, oldPassword, newPassword)
  1360  	require.NoError(t, err)
  1361  
  1362  	// Test that DBs can be opened with new password
  1363  	appDbPath, err := backend.getAppDBPath(account.KeyUID)
  1364  	require.NoError(t, err)
  1365  	appDb, err := sqlite.OpenDB(appDbPath, newPassword, account.KDFIterations)
  1366  	require.NoError(t, err)
  1367  	appDb.Close()
  1368  
  1369  	walletDbPath, err := backend.getWalletDBPath(account.KeyUID)
  1370  	require.NoError(t, err)
  1371  	walletDb, err := sqlite.OpenDB(walletDbPath, newPassword, account.KDFIterations)
  1372  	require.NoError(t, err)
  1373  	walletDb.Close()
  1374  
  1375  	// Test that keystore can be decrypted with the new password
  1376  	acc, key, err := backend.accountManager.AddressToDecryptedAccount(accountInfo.WalletAddress, newPassword)
  1377  	require.NoError(t, err)
  1378  	require.NotNil(t, acc)
  1379  	require.NotNil(t, key)
  1380  	require.Equal(t, acc.Address, key.Address)
  1381  }
  1382  
  1383  func TestCreateWallet(t *testing.T) {
  1384  	utils.Init()
  1385  	password := "some-password2" // nolint: goconst
  1386  	tmpdir := t.TempDir()
  1387  
  1388  	b := NewGethStatusBackend()
  1389  	defer func() {
  1390  		require.NoError(t, b.StopNode())
  1391  	}()
  1392  
  1393  	createAccountRequest := &requests.CreateAccount{
  1394  		DisplayName:        "some-display-name",
  1395  		CustomizationColor: "#ffffff",
  1396  		Password:           password,
  1397  		RootDataDir:        tmpdir,
  1398  		LogFilePath:        tmpdir + "/log",
  1399  	}
  1400  	c := make(chan interface{}, 10)
  1401  	signal.SetMobileSignalHandler(func(data []byte) {
  1402  		if strings.Contains(string(data), "node.login") {
  1403  			c <- struct{}{}
  1404  		}
  1405  	})
  1406  	t.Cleanup(signal.ResetMobileSignalHandler)
  1407  
  1408  	account, err := b.CreateAccountAndLogin(createAccountRequest)
  1409  	require.NoError(t, err)
  1410  	statusNode := b.statusNode
  1411  	require.NotNil(t, statusNode)
  1412  
  1413  	walletService := statusNode.WalletService()
  1414  	require.NotNil(t, walletService)
  1415  	walletAPI := walletservice.NewAPI(walletService)
  1416  
  1417  	paths := []string{"m/44'/60'/0'/0/1"}
  1418  
  1419  	db, err := accounts.NewDB(b.appDB)
  1420  	require.NoError(t, err)
  1421  	walletRootAddress, err := db.GetWalletRootAddress()
  1422  	require.NoError(t, err)
  1423  
  1424  	mnemonic, err := db.Mnemonic()
  1425  	require.NoError(t, err)
  1426  	require.NotEmpty(t, mnemonic)
  1427  
  1428  	derivedAddress, err := walletAPI.GetDerivedAddresses(context.Background(), password, walletRootAddress.String(), paths)
  1429  	require.NoError(t, err)
  1430  	require.Len(t, derivedAddress, 1)
  1431  
  1432  	accountsService := statusNode.AccountService()
  1433  	require.NotNil(t, accountsService)
  1434  	accountsAPI := accountsService.AccountsAPI()
  1435  
  1436  	err = accountsAPI.AddAccount(context.Background(), password, &accounts.Account{
  1437  		KeyUID:    account.KeyUID,
  1438  		Type:      accounts.AccountTypeGenerated,
  1439  		PublicKey: derivedAddress[0].PublicKey,
  1440  		Emoji:     "some",
  1441  		ColorID:   "so",
  1442  		Name:      "some name",
  1443  		Path:      derivedAddress[0].Path,
  1444  	})
  1445  	require.NoError(t, err)
  1446  }
  1447  
  1448  func TestSetFleet(t *testing.T) {
  1449  	utils.Init()
  1450  	password := "some-password2" // nolint: goconst
  1451  	tmpdir := t.TempDir()
  1452  
  1453  	b := NewGethStatusBackend()
  1454  	createAccountRequest := &requests.CreateAccount{
  1455  		DisplayName:        "some-display-name",
  1456  		CustomizationColor: "#ffffff",
  1457  		Password:           password,
  1458  		RootDataDir:        tmpdir,
  1459  		LogFilePath:        tmpdir + "/log",
  1460  	}
  1461  	c := make(chan interface{}, 10)
  1462  	signal.SetMobileSignalHandler(func(data []byte) {
  1463  		if strings.Contains(string(data), "node.login") {
  1464  			c <- struct{}{}
  1465  		}
  1466  	})
  1467  	t.Cleanup(signal.ResetMobileSignalHandler)
  1468  
  1469  	newAccount, err := b.CreateAccountAndLogin(createAccountRequest)
  1470  	require.NoError(t, err)
  1471  	statusNode := b.statusNode
  1472  	require.NotNil(t, statusNode)
  1473  
  1474  	savedSettings, err := b.GetSettings()
  1475  	require.NoError(t, err)
  1476  	require.Empty(t, savedSettings.Fleet)
  1477  
  1478  	accountsDB, err := b.accountsDB()
  1479  	require.NoError(t, err)
  1480  	err = accountsDB.SaveSettingField(settings.Fleet, params.FleetStatusProd)
  1481  	require.NoError(t, err)
  1482  
  1483  	savedSettings, err = b.GetSettings()
  1484  	require.NoError(t, err)
  1485  	require.NotEmpty(t, savedSettings.Fleet)
  1486  	require.Equal(t, params.FleetStatusProd, *savedSettings.Fleet)
  1487  
  1488  	require.NoError(t, b.Logout())
  1489  
  1490  	loginAccountRequest := &requests.Login{
  1491  		KeyUID:   newAccount.KeyUID,
  1492  		Password: password,
  1493  	}
  1494  	require.NoError(t, b.LoginAccount(loginAccountRequest))
  1495  	select {
  1496  	case <-c:
  1497  		break
  1498  	case <-time.After(5 * time.Second):
  1499  		t.FailNow()
  1500  	}
  1501  	// Check is using the right fleet
  1502  	require.Equal(t, b.config.ClusterConfig.WakuNodes, params.DefaultWakuNodes(params.FleetStatusProd))
  1503  
  1504  	require.NoError(t, b.Logout())
  1505  }
  1506  
  1507  func TestWalletConfigOnLoginAccount(t *testing.T) {
  1508  	utils.Init()
  1509  	password := "some-password2" // nolint: goconst
  1510  	tmpdir := t.TempDir()
  1511  	poktToken := "grove-token"    // nolint: goconst
  1512  	infuraToken := "infura-token" // nolint: goconst
  1513  	alchemyEthereumMainnetToken := "alchemy-ethereum-mainnet-token"
  1514  	alchemyEthereumSepoliaToken := "alchemy-ethereum-sepolia-token"
  1515  	alchemyArbitrumMainnetToken := "alchemy-arbitrum-mainnet-token"
  1516  	alchemyArbitrumSepoliaToken := "alchemy-arbitrum-sepolia-token"
  1517  	alchemyOptimismMainnetToken := "alchemy-optimism-mainnet-token"
  1518  	alchemyOptimismSepoliaToken := "alchemy-optimism-sepolia-token"
  1519  	raribleMainnetAPIKey := "rarible-mainnet-api-key" // nolint: gosec
  1520  	raribleTestnetAPIKey := "rarible-testnet-api-key" // nolint: gosec
  1521  
  1522  	b := NewGethStatusBackend()
  1523  	createAccountRequest := &requests.CreateAccount{
  1524  		DisplayName:        "some-display-name",
  1525  		CustomizationColor: "#ffffff",
  1526  		Password:           password,
  1527  		RootDataDir:        tmpdir,
  1528  		LogFilePath:        tmpdir + "/log",
  1529  	}
  1530  	c := make(chan interface{}, 10)
  1531  	signal.SetMobileSignalHandler(func(data []byte) {
  1532  		if strings.Contains(string(data), "node.login") {
  1533  			c <- struct{}{}
  1534  		}
  1535  	})
  1536  	t.Cleanup(signal.ResetMobileSignalHandler)
  1537  
  1538  	newAccount, err := b.CreateAccountAndLogin(createAccountRequest)
  1539  	require.NoError(t, err)
  1540  	statusNode := b.statusNode
  1541  	require.NotNil(t, statusNode)
  1542  
  1543  	require.NoError(t, b.Logout())
  1544  
  1545  	loginAccountRequest := &requests.Login{
  1546  		KeyUID:   newAccount.KeyUID,
  1547  		Password: password,
  1548  		WalletSecretsConfig: requests.WalletSecretsConfig{
  1549  			PoktToken:                   poktToken,
  1550  			InfuraToken:                 infuraToken,
  1551  			AlchemyEthereumMainnetToken: alchemyEthereumMainnetToken,
  1552  			AlchemyEthereumSepoliaToken: alchemyEthereumSepoliaToken,
  1553  			AlchemyArbitrumMainnetToken: alchemyArbitrumMainnetToken,
  1554  			AlchemyArbitrumSepoliaToken: alchemyArbitrumSepoliaToken,
  1555  			AlchemyOptimismMainnetToken: alchemyOptimismMainnetToken,
  1556  			AlchemyOptimismSepoliaToken: alchemyOptimismSepoliaToken,
  1557  			RaribleMainnetAPIKey:        raribleMainnetAPIKey,
  1558  			RaribleTestnetAPIKey:        raribleTestnetAPIKey,
  1559  		},
  1560  	}
  1561  
  1562  	require.NoError(t, b.LoginAccount(loginAccountRequest))
  1563  	select {
  1564  	case <-c:
  1565  		break
  1566  	case <-time.After(5 * time.Second):
  1567  		t.FailNow()
  1568  	}
  1569  
  1570  	require.Equal(t, b.config.WalletConfig.InfuraAPIKey, infuraToken)
  1571  	require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[mainnetChainID], alchemyEthereumMainnetToken)
  1572  	require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[sepoliaChainID], alchemyEthereumSepoliaToken)
  1573  	require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[arbitrumChainID], alchemyArbitrumMainnetToken)
  1574  	require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[arbitrumSepoliaChainID], alchemyArbitrumSepoliaToken)
  1575  	require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[optimismChainID], alchemyOptimismMainnetToken)
  1576  	require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[optimismSepoliaChainID], alchemyOptimismSepoliaToken)
  1577  	require.Equal(t, b.config.WalletConfig.RaribleMainnetAPIKey, raribleMainnetAPIKey)
  1578  	require.Equal(t, b.config.WalletConfig.RaribleTestnetAPIKey, raribleTestnetAPIKey)
  1579  
  1580  	require.NoError(t, b.Logout())
  1581  }
  1582  
  1583  func TestTestnetEnabledSettingOnCreateAccount(t *testing.T) {
  1584  	utils.Init()
  1585  	tmpdir := t.TempDir()
  1586  
  1587  	b := NewGethStatusBackend()
  1588  
  1589  	// Creating an account with test networks enabled
  1590  	createAccountRequest1 := &requests.CreateAccount{
  1591  		DisplayName:         "User-1",
  1592  		CustomizationColor:  "#ffffff",
  1593  		Password:            "password123",
  1594  		RootDataDir:         tmpdir,
  1595  		LogFilePath:         tmpdir + "/log",
  1596  		TestNetworksEnabled: true,
  1597  	}
  1598  	_, err := b.CreateAccountAndLogin(createAccountRequest1)
  1599  	require.NoError(t, err)
  1600  	statusNode := b.statusNode
  1601  	require.NotNil(t, statusNode)
  1602  
  1603  	settings, err := b.GetSettings()
  1604  	require.NoError(t, err)
  1605  	require.True(t, settings.TestNetworksEnabled)
  1606  
  1607  	require.NoError(t, b.Logout())
  1608  
  1609  	// Creating an account with test networks disabled
  1610  	createAccountRequest2 := &requests.CreateAccount{
  1611  		DisplayName:        "User-2",
  1612  		CustomizationColor: "#ffffff",
  1613  		Password:           "password",
  1614  		RootDataDir:        tmpdir,
  1615  		LogFilePath:        tmpdir + "/log",
  1616  	}
  1617  	_, err = b.CreateAccountAndLogin(createAccountRequest2)
  1618  	require.NoError(t, err)
  1619  	statusNode = b.statusNode
  1620  	require.NotNil(t, statusNode)
  1621  
  1622  	settings, err = b.GetSettings()
  1623  	require.NoError(t, err)
  1624  	require.False(t, settings.TestNetworksEnabled)
  1625  
  1626  	require.NoError(t, b.Logout())
  1627  }
  1628  
  1629  func TestRestoreAccountAndLogin(t *testing.T) {
  1630  	utils.Init()
  1631  	tmpdir := t.TempDir()
  1632  
  1633  	backend := NewGethStatusBackend()
  1634  
  1635  	// Test case 1: Valid restore account request
  1636  	restoreRequest := &requests.RestoreAccount{
  1637  		Mnemonic:    "test test test test test test test test test test test test",
  1638  		FetchBackup: false,
  1639  		CreateAccount: requests.CreateAccount{
  1640  			DisplayName:        "Account1",
  1641  			DeviceName:         "StatusIM",
  1642  			Password:           "password",
  1643  			CustomizationColor: "0x000000",
  1644  			RootDataDir:        tmpdir,
  1645  		},
  1646  	}
  1647  	account, err := backend.RestoreAccountAndLogin(restoreRequest)
  1648  	require.NoError(t, err)
  1649  	require.NotNil(t, account)
  1650  
  1651  	// Test case 2: Invalid restore account request
  1652  	invalidRequest := &requests.RestoreAccount{}
  1653  	_, err = backend.RestoreAccountAndLogin(invalidRequest)
  1654  	require.Error(t, err)
  1655  
  1656  	db, err := accounts.NewDB(backend.appDB)
  1657  	require.NoError(t, err)
  1658  	mnemonic, err := db.Mnemonic()
  1659  	require.NoError(t, err)
  1660  	require.Empty(t, mnemonic)
  1661  }
  1662  
  1663  func TestCreateAccountPathsValidation(t *testing.T) {
  1664  	tmpdir := t.TempDir()
  1665  
  1666  	validation := &requests.CreateAccountValidation{
  1667  		AllowEmptyDisplayName: false,
  1668  	}
  1669  
  1670  	request := &requests.CreateAccount{
  1671  		DisplayName:        "User-1",
  1672  		Password:           "password123",
  1673  		CustomizationColor: "#ffffff",
  1674  		RootDataDir:        tmpdir,
  1675  	}
  1676  
  1677  	err := request.Validate(validation)
  1678  	require.NoError(t, err)
  1679  
  1680  	request.RootDataDir = ""
  1681  	err = request.Validate(validation)
  1682  	require.ErrorIs(t, err, requests.ErrCreateAccountInvalidRootDataDir)
  1683  }
  1684  
  1685  func TestRestoreKeycardAccountAndLogin(t *testing.T) {
  1686  	utils.Init()
  1687  	tmpdir := t.TempDir()
  1688  
  1689  	exampleKeycardEvent := map[string]interface{}{
  1690  		"error":       "",
  1691  		"instanceUID": "a84599394887b742eed9a99d3834a797",
  1692  		"applicationInfo": map[string]interface{}{
  1693  			"initialized":    false,
  1694  			"instanceUID":    "",
  1695  			"version":        0,
  1696  			"availableSlots": 0,
  1697  			"keyUID":         "",
  1698  		},
  1699  		"seedPhraseIndexes": []interface{}{},
  1700  		"freePairingSlots":  0,
  1701  		"keyUid":            "0x579324c53f347e18961c775a00ec13ed7d59a225b1859d5125ff36b450b8778d",
  1702  		"pinRetries":        0,
  1703  		"pukRetries":        0,
  1704  		"cardMetadata": map[string]interface{}{
  1705  			"name":           "",
  1706  			"walletAccounts": []interface{}{},
  1707  		},
  1708  		"generatedWalletAccount": map[string]interface{}{
  1709  			"address":    "",
  1710  			"publicKey":  "",
  1711  			"privateKey": "",
  1712  		},
  1713  		"generatedWalletAccounts": []interface{}{},
  1714  		"txSignature": map[string]interface{}{
  1715  			"r": "",
  1716  			"s": "",
  1717  			"v": "",
  1718  		},
  1719  		"eip1581Key": map[string]interface{}{
  1720  			"address":    "0xA8d50f0B3bc581298446be8FBfF5c71684Ea6c01",
  1721  			"publicKey":  "0x040d7e6e3761ab3d17c220e484ede2f3fa02998b859d4d0e9d34216c6e41b03dc94996fdea23a9233092cee50a768e7428d5de7bd42e8e32c10d6b0e36b10f0e7a",
  1722  			"privateKey": "",
  1723  		},
  1724  		"encryptionKey": map[string]interface{}{
  1725  			"address":    "0x1ec12f2b323ddDD076A1127cEc8FA0B592c46cD3",
  1726  			"publicKey":  "0x04c4b16f670b51702dc130673bf9c64ffd1f69383cef2127dfa05031b9b1359120f7342134af9a350465126a85e87cb003b7c4f93d2ba2ff98bb73277b119c7a87",
  1727  			"privateKey": "68c830d5b327382a65e6c302594744ec0d28b01d1ea8124f49714f05c9625ddd"},
  1728  		"masterKey": map[string]interface{}{
  1729  			"address":    "0xbf9dE86774051537b2192Ce9c8d2496f129bA24b",
  1730  			"publicKey":  "0x040d909a07ecca18bbfa7d53d10a86bd956f54b8b446eabd94940e642ae18421b516ec5b63677c4ce65e0e266b58bdb716d8266b25356154eb61713ecb23824075",
  1731  			"privateKey": "",
  1732  		},
  1733  		"walletKey": map[string]interface{}{
  1734  			"address":    "0xB9E1998e1A8854887CA327D1aF5894B6CB0AC07D",
  1735  			"publicKey":  "0x04c16e7748f34e0ab2c9c13350d7872d928e942934dd8b8abd3fb12b8c742a5ee8cf0919731e800907068afec25f577bde3a9c534795e359ee48097e4e55f4aaca",
  1736  			"privateKey": "",
  1737  		},
  1738  		"walletRootKey": map[string]interface{}{
  1739  			"address":    "0xFf59db9F2f97Db7104A906C390D33C342a1309C8",
  1740  			"publicKey":  "0x04c436532398e19ed14b4eb41545b82014435d60e7db4449a371fd80d0d5cd557f60d81f6c2b35ca5440aa60934c23b70489b0e7963e63ec66b51a7e52db711262",
  1741  			"privateKey": "",
  1742  		},
  1743  		"whisperKey": map[string]interface{}{
  1744  			"address":    "0xBa122B9c0Ef560813b5D2C0961094aC36289f846",
  1745  			"publicKey":  "0x0441468c39b579259676350b9736b01cdadb740f67bfd022fa2b985123b1d66fc3191cfe73205e3d3d84148f0248f9a2978afeeda16d7c3db90bd2579f0de33459",
  1746  			"privateKey": "5a42b4f15ff1a5da95d116442ce11a31e9020f562224bf60b1d8d3a99d90653d",
  1747  		},
  1748  		"masterKeyAddress": "",
  1749  	}
  1750  
  1751  	exampleRequest := map[string]interface{}{
  1752  		"mnemonic":    "",
  1753  		"fetchBackup": true,
  1754  		"createAccountRequest": map[string]interface{}{
  1755  			"rootDataDir":   tmpdir,
  1756  			"kdfIterations": 256000,
  1757  			"deviceName":    "",
  1758  			"displayName":   "",
  1759  			"password":      "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
  1760  			"imagePath":     "",
  1761  			"imageCropRectangle": map[string]interface{}{
  1762  				"ax": 0, "ay": 0, "bx": 0, "by": 0},
  1763  			"customizationColor":       "primary",
  1764  			"emoji":                    "",
  1765  			"wakuV2Nameserver":         nil,
  1766  			"wakuV2LightClient":        false,
  1767  			"logLevel":                 "DEBUG",
  1768  			"logFilePath":              "",
  1769  			"logEnabled":               false,
  1770  			"previewPrivacy":           true,
  1771  			"verifyTransactionURL":     nil,
  1772  			"verifyENSURL":             nil,
  1773  			"verifyENSContractAddress": nil,
  1774  			"verifyTransactionChainID": nil,
  1775  			"upstreamConfig":           "",
  1776  			"networkID":                nil,
  1777  			"walletSecretsConfig": map[string]interface{}{
  1778  				"poktToken":                   "1234567890",
  1779  				"infuraToken":                 "1234567890",
  1780  				"infuraSecret":                "",
  1781  				"openseaApiKey":               "",
  1782  				"raribleMainnetApiKey":        "",
  1783  				"raribleTestnetApiKey":        "",
  1784  				"alchemyEthereumMainnetToken": "",
  1785  				"alchemyEthereumGoerliToken":  "",
  1786  				"alchemyEthereumSepoliaToken": "",
  1787  				"alchemyArbitrumMainnetToken": "",
  1788  				"alchemyArbitrumGoerliToken":  "",
  1789  				"alchemyArbitrumSepoliaToken": "",
  1790  				"alchemyOptimismMainnetToken": "",
  1791  				"alchemyOptimismGoerliToken":  "",
  1792  				"alchemyOptimismSepoliaToken": "",
  1793  			},
  1794  			"torrentConfigEnabled":   false,
  1795  			"torrentConfigPort":      0,
  1796  			"keycardInstanceUID":     "a84599394887b742eed9a99d3834a797",
  1797  			"keycardPairingDataFile": path.Join(tmpdir, DefaultKeycardPairingDataFile),
  1798  		},
  1799  	}
  1800  
  1801  	require.NotNil(t, exampleKeycardEvent)
  1802  	require.NotNil(t, exampleRequest)
  1803  
  1804  	conf, err := params.NewNodeConfig(tmpdir, 1777)
  1805  	require.NoError(t, err)
  1806  
  1807  	backend := NewGethStatusBackend()
  1808  
  1809  	require.NoError(t, backend.AccountManager().InitKeystore(conf.KeyStoreDir))
  1810  	backend.UpdateRootDataDir(conf.DataDir)
  1811  
  1812  	require.NoError(t, backend.OpenAccounts())
  1813  
  1814  	keycardPairingDataFile := exampleRequest["createAccountRequest"].(map[string]interface{})["keycardPairingDataFile"].(string)
  1815  
  1816  	kp := wallet.NewKeycardPairings()
  1817  	kp.SetKeycardPairingsFile(keycardPairingDataFile)
  1818  
  1819  	err = kp.SetPairingsJSONFileContent([]byte(`{"a84599394887b742eed9a99d3834a797":{"key":"785d52957b05482477728380d9b4bbb5dc9a8ed978ab4a4098e1a279c855d3c6","index":1}}`))
  1820  	require.NoError(t, err)
  1821  
  1822  	request := &requests.RestoreAccount{
  1823  		Keycard: &requests.KeycardData{
  1824  			KeyUID:              exampleKeycardEvent["keyUid"].(string),
  1825  			Address:             exampleKeycardEvent["masterKey"].(map[string]interface{})["address"].(string),
  1826  			WhisperPrivateKey:   exampleKeycardEvent["whisperKey"].(map[string]interface{})["privateKey"].(string),
  1827  			WhisperPublicKey:    exampleKeycardEvent["whisperKey"].(map[string]interface{})["publicKey"].(string),
  1828  			WhisperAddress:      exampleKeycardEvent["whisperKey"].(map[string]interface{})["address"].(string),
  1829  			WalletPublicKey:     exampleKeycardEvent["walletKey"].(map[string]interface{})["publicKey"].(string),
  1830  			WalletAddress:       exampleKeycardEvent["walletKey"].(map[string]interface{})["address"].(string),
  1831  			WalletRootAddress:   exampleKeycardEvent["walletRootKey"].(map[string]interface{})["address"].(string),
  1832  			Eip1581Address:      exampleKeycardEvent["eip1581Key"].(map[string]interface{})["address"].(string),
  1833  			EncryptionPublicKey: exampleKeycardEvent["encryptionKey"].(map[string]interface{})["publicKey"].(string),
  1834  		},
  1835  		CreateAccount: requests.CreateAccount{
  1836  			DisplayName:            "User-1",
  1837  			Password:               "password123",
  1838  			CustomizationColor:     "#ffffff",
  1839  			RootDataDir:            tmpdir,
  1840  			KeycardInstanceUID:     exampleKeycardEvent["instanceUID"].(string),
  1841  			KeycardPairingDataFile: &keycardPairingDataFile,
  1842  		},
  1843  	}
  1844  
  1845  	acc, err := backend.RestoreKeycardAccountAndLogin(request)
  1846  	require.NoError(t, err)
  1847  	require.NotNil(t, acc)
  1848  }