diff --git a/api/backend_test.go b/api/backend_test.go index 147134154..de5db82e1 100644 --- a/api/backend_test.go +++ b/api/backend_test.go @@ -555,12 +555,25 @@ func TestBackendGetVerifiedAccount(t *testing.T) { pkey, err := crypto.GenerateKey() require.NoError(t, err) address := crypto.PubkeyToAddress(pkey.PublicKey) + keyUIDHex := sha256.Sum256(gethcrypto.FromECDSAPub(&pkey.PublicKey)) + keyUID := types.EncodeHex(keyUIDHex[:]) + db, err := accounts.NewDB(backend.appDB) require.NoError(t, err) _, err = backend.AccountManager().ImportAccount(pkey, password) require.NoError(t, err) - require.NoError(t, db.SaveAccounts([]*accounts.Account{{Address: address}})) + require.NoError(t, db.SaveOrUpdateKeypair(&accounts.Keypair{ + KeyUID: keyUID, + Name: "private key keypair", + Type: accounts.KeypairTypeKey, + Accounts: []*accounts.Account{ + &accounts.Account{ + Address: address, + KeyUID: keyUID, + }, + }, + })) key, err := backend.getVerifiedWalletAccount(address.String(), "wrong-password") require.EqualError(t, err, "could not decrypt key with given password") require.Nil(t, key) @@ -580,32 +593,53 @@ func TestBackendGetVerifiedAccount(t *testing.T) { require.NoError(t, err) derivedInfo := derivedInfos[newPath] - partialAcc := &accounts.Account{ - Address: types.HexToAddress(derivedInfo.Address), - Type: accounts.AccountTypeGenerated, - PublicKey: types.Hex2Bytes(derivedInfo.PublicKey), - Path: newPath, - Wallet: false, - Name: "PartialAccount", + keypair := &accounts.Keypair{ + KeyUID: walletInfo.KeyUID, + Name: "profile keypair", + Type: accounts.KeypairTypeProfile, + Accounts: []*accounts.Account{ + &accounts.Account{ + Address: types.HexToAddress(derivedInfo.Address), + KeyUID: walletInfo.KeyUID, + Type: accounts.AccountTypeGenerated, + PublicKey: types.Hex2Bytes(derivedInfo.PublicKey), + Path: newPath, + Wallet: false, + Name: "PartialAccount", + }, + }, } - require.NoError(t, db.SaveAccounts([]*accounts.Account{partialAcc})) + require.NoError(t, db.SaveOrUpdateKeypair(keypair)) // With partial account we need to dynamically generate private key - key, err := backend.getVerifiedWalletAccount(partialAcc.Address.Hex(), password) + key, err := backend.getVerifiedWalletAccount(keypair.Accounts[0].Address.Hex(), password) require.NoError(t, err) - require.Equal(t, partialAcc.Address, key.Address) + require.Equal(t, keypair.Accounts[0].Address, key.Address) }) t.Run("Success", func(t *testing.T) { pkey, err := crypto.GenerateKey() require.NoError(t, err) address := crypto.PubkeyToAddress(pkey.PublicKey) + keyUIDHex := sha256.Sum256(gethcrypto.FromECDSAPub(&pkey.PublicKey)) + keyUID := types.EncodeHex(keyUIDHex[:]) + db, err := accounts.NewDB(backend.appDB) require.NoError(t, err) defer db.Close() _, err = backend.AccountManager().ImportAccount(pkey, password) require.NoError(t, err) - require.NoError(t, db.SaveAccounts([]*accounts.Account{{Address: address}})) + require.NoError(t, db.SaveOrUpdateKeypair(&accounts.Keypair{ + KeyUID: keyUID, + Name: "private key keypair", + Type: accounts.KeypairTypeKey, + Accounts: []*accounts.Account{ + &accounts.Account{ + Address: address, + KeyUID: keyUID, + }, + }, + })) key, err := backend.getVerifiedWalletAccount(address.String(), password) require.NoError(t, err) require.Equal(t, address, key.Address) @@ -636,7 +670,12 @@ func TestLoginWithKey(t *testing.T) { require.NotNil(t, b.statusNode.HTTPServer()) address := crypto.PubkeyToAddress(walletKey.PublicKey) - require.NoError(t, b.SaveAccountAndStartNodeWithKey(main, "test-pass", testSettings, conf, []*accounts.Account{{Address: address, Wallet: true}}, keyhex)) + + settings := testSettings + settings.KeyUID = keyUID + settings.Address = crypto.PubkeyToAddress(walletKey.PublicKey) + + require.NoError(t, b.SaveAccountAndStartNodeWithKey(main, "test-pass", settings, conf, []*accounts.Account{{Address: address, KeyUID: keyUID, Wallet: true}}, keyhex)) require.NoError(t, b.Logout()) require.NoError(t, b.StopNode()) @@ -677,7 +716,12 @@ func TestVerifyDatabasePassword(t *testing.T) { require.NoError(t, b.OpenAccounts()) address := crypto.PubkeyToAddress(walletKey.PublicKey) - require.NoError(t, b.SaveAccountAndStartNodeWithKey(main, "test-pass", testSettings, conf, []*accounts.Account{{Address: address, Wallet: true}}, keyhex)) + + settings := testSettings + settings.KeyUID = keyUID + settings.Address = crypto.PubkeyToAddress(walletKey.PublicKey) + + require.NoError(t, b.SaveAccountAndStartNodeWithKey(main, "test-pass", settings, conf, []*accounts.Account{{Address: address, KeyUID: keyUID, Wallet: true}}, keyhex)) require.NoError(t, b.Logout()) require.NoError(t, b.StopNode()) @@ -738,7 +782,8 @@ func TestDeleteMultiaccount(t *testing.T) { s, ¶ms.NodeConfig{}, nil) - require.NoError(t, err) + require.Error(t, err) + require.True(t, err == accounts.ErrKeypairWithoutAccounts) err = backend.OpenAccounts() require.NoError(t, err) @@ -839,17 +884,22 @@ func TestConvertAccount(t *testing.T) { found = keystoreContainsFileForAccount(keyStoreDir, chatAddress) require.True(t, found) - var accountsToStore []*accounts.Account - accountsToStore = append(accountsToStore, &accounts.Account{ - Address: types.HexToAddress(chatAddress), - DerivedFrom: masterAddress, + profileKeypair := &accounts.Keypair{ KeyUID: genAccInfo.KeyUID, - Type: accounts.AccountTypeGenerated, - PublicKey: types.Hex2Bytes(accountInfo.PublicKey), - Path: pathEIP1581Chat, - Wallet: false, - Chat: true, - Name: "GeneratedAccount", + Name: "Profile Name", + Type: accounts.KeypairTypeProfile, + DerivedFrom: masterAddress, + } + + profileKeypair.Accounts = append(profileKeypair.Accounts, &accounts.Account{ + Address: types.HexToAddress(chatAddress), + KeyUID: profileKeypair.KeyUID, + Type: accounts.AccountTypeGenerated, + PublicKey: types.Hex2Bytes(accountInfo.PublicKey), + Path: pathEIP1581Chat, + Wallet: false, + Chat: true, + Name: "GeneratedAccount", }) for p, dAccInfo := range derivedAccounts { @@ -860,25 +910,24 @@ func TestConvertAccount(t *testing.T) { if p == pathDefaultWalletAccount || p == customWalletPath1 || p == customWalletPath2 { - accountsToStore = append(accountsToStore, &accounts.Account{ - Address: types.HexToAddress(dAccInfo.Address), - KeyUID: genAccInfo.KeyUID, - Wallet: false, - Chat: false, - Type: accounts.AccountTypeGenerated, - Path: p, - Name: "derivacc" + p, - Hidden: false, - DerivedFrom: masterAddress, - Removed: false, + profileKeypair.Accounts = append(profileKeypair.Accounts, &accounts.Account{ + Address: types.HexToAddress(dAccInfo.Address), + KeyUID: genAccInfo.KeyUID, + Wallet: false, + Chat: false, + Type: accounts.AccountTypeGenerated, + Path: p, + Name: "derivacc" + p, + Hidden: false, + Removed: false, }) } } account := multiaccounts.Account{ - Name: "foo", + Name: profileKeypair.Name, Timestamp: 1, - KeyUID: genAccInfo.KeyUID, + KeyUID: profileKeypair.KeyUID, } err = backend.ensureAppDBOpened(account, password) @@ -904,7 +953,7 @@ func TestConvertAccount(t *testing.T) { err = backend.saveAccountsAndSettings( s, ¶ms.NodeConfig{}, - accountsToStore) + profileKeypair.Accounts) require.NoError(t, err) err = backend.OpenAccounts() diff --git a/api/test_helpers.go b/api/test_helpers.go index 30bafcf6c..1d2d444f6 100644 --- a/api/test_helpers.go +++ b/api/test_helpers.go @@ -7,6 +7,7 @@ import ( "github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/multiaccounts" + "github.com/status-im/status-go/multiaccounts/accounts" "github.com/status-im/status-go/multiaccounts/settings" "github.com/status-im/status-go/params" @@ -84,7 +85,8 @@ func setupWalletTest(t *testing.T, password string) (backend *GethStatusBackend, WalletRootAddress: types.HexToAddress(walletRootAddress)} err = backend.saveAccountsAndSettings(s, config, nil) - require.NoError(t, err) + require.Error(t, err) + require.True(t, err == accounts.ErrKeypairWithoutAccounts) // this is for StatusNode().Config() call inside of the getVerifiedWalletAccount err = backend.StartNode(config) diff --git a/multiaccounts/accounts/account_test.go b/multiaccounts/accounts/account_test.go index 18530fb3e..b021bd883 100644 --- a/multiaccounts/accounts/account_test.go +++ b/multiaccounts/accounts/account_test.go @@ -38,24 +38,38 @@ func TestIsOwnAccount(t *testing.T) { func TestUnmarshal(t *testing.T) { data := ` { + "key-uid": "0xbc14c321b74652e57c7f26eb30d597ea27cbdf36cba5c85d24f12748153a035e", "public-key": "0x0465f6d4f1172524fc057954c8a3f8e34f991558b3d1097189975062f67adda7835da61acb5cda3348b41d211ed0cb07aba668eb12e19e29d98745bebf68d93b61", "address": "0xf09c9f5Fb9faa22d0C6C593e7157Ceac8B2b0fe4", "color": "#4360df", "wallet": true, + "chat": true, "path": "m/44'/60'/0'/0/0", "name": "Status account", - "derived-from": "0x6f015A79890Dcb38eFeC1D83772d57159D2eb58b" + "type": "generated", + "emoji": "some-emoji", + "hidden": true, + "clock": 1234, + "removed": true, + "operable": "fully" } ` var account Account err := json.Unmarshal([]byte(data), &account) require.NoError(t, err) + require.Equal(t, "0xbc14c321b74652e57c7f26eb30d597ea27cbdf36cba5c85d24f12748153a035e", account.KeyUID) require.Equal(t, []byte("0x0465f6d4f1172524fc057954c8a3f8e34f991558b3d1097189975062f67adda7835da61acb5cda3348b41d211ed0cb07aba668eb12e19e29d98745bebf68d93b61"), account.PublicKey.Bytes()) require.Equal(t, "0xf09c9f5Fb9faa22d0C6C593e7157Ceac8B2b0fe4", account.Address.String()) require.Equal(t, "#4360df", account.Color) require.Equal(t, true, account.Wallet) + require.Equal(t, true, account.Chat) require.Equal(t, "m/44'/60'/0'/0/0", account.Path) require.Equal(t, "Status account", account.Name) - require.Equal(t, "0x6f015A79890Dcb38eFeC1D83772d57159D2eb58b", account.DerivedFrom) + require.Equal(t, "generated", account.Type.String()) + require.Equal(t, "some-emoji", account.Emoji) + require.Equal(t, true, account.Hidden) + require.Equal(t, uint64(1234), account.Clock) + require.Equal(t, true, account.Removed) + require.Equal(t, "fully", account.Operable.String()) } diff --git a/multiaccounts/accounts/database_test.go b/multiaccounts/accounts/database_test.go index de539402a..d677e55b7 100644 --- a/multiaccounts/accounts/database_test.go +++ b/multiaccounts/accounts/database_test.go @@ -8,7 +8,6 @@ import ( "github.com/status-im/status-go/appdatabase" "github.com/status-im/status-go/eth-node/types" - "github.com/status-im/status-go/multiaccounts/errors" ) func setupTestDB(t *testing.T) (*Database, func()) { @@ -29,77 +28,6 @@ func setupTestDB(t *testing.T) (*Database, func()) { } } -func TestSaveAccounts(t *testing.T) { - type testCase struct { - description string - accounts []*Account - err error - } - for _, tc := range []testCase{ - { - description: "NoError", - accounts: []*Account{ - {Address: types.Address{0x01}, Chat: true, Wallet: true}, - {Address: types.Address{0x02}}, - }, - }, - { - description: "UniqueChat", - accounts: []*Account{ - {Address: types.Address{0x01}, Chat: true}, - {Address: types.Address{0x02}, Chat: true}, - }, - err: errors.ErrChatNotUnique, - }, - { - description: "UniqueWallet", - accounts: []*Account{ - {Address: types.Address{0x01}, Wallet: true}, - {Address: types.Address{0x02}, Wallet: true}, - }, - err: errors.ErrWalletNotUnique, - }, - } { - t.Run(tc.description, func(t *testing.T) { - db, stop := setupTestDB(t) - defer stop() - require.Equal(t, tc.err, db.SaveAccounts(tc.accounts)) - }) - } -} - -func TestUpdateAccounts(t *testing.T) { - db, stop := setupTestDB(t) - defer stop() - accounts := []*Account{ - {Address: types.Address{0x01}, Chat: true, Wallet: true}, - {Address: types.Address{0x02}}, - } - require.NoError(t, db.SaveAccounts(accounts)) - accounts[0].Chat = false - accounts[1].Chat = true - require.NoError(t, db.SaveAccounts(accounts)) - rst, err := db.GetAccounts() - require.NoError(t, err) - require.Equal(t, accounts, rst) -} - -func TestDeleteAccount(t *testing.T) { - db, stop := setupTestDB(t) - defer stop() - accounts := []*Account{ - {Address: types.Address{0x01}, Chat: true, Wallet: true}, - } - require.NoError(t, db.SaveAccounts(accounts)) - rst, err := db.GetAccounts() - require.NoError(t, err) - require.Equal(t, 1, len(rst)) - require.NoError(t, db.DeleteAccount(types.Address{0x01})) - rst2, err := db.GetAccounts() - require.NoError(t, err) - require.Equal(t, 0, len(rst2)) -} - func TestGetAddresses(t *testing.T) { db, stop := setupTestDB(t) defer stop() @@ -107,7 +35,7 @@ func TestGetAddresses(t *testing.T) { {Address: types.Address{0x01}, Chat: true, Wallet: true}, {Address: types.Address{0x02}}, } - require.NoError(t, db.SaveAccounts(accounts)) + require.NoError(t, db.SaveOrUpdateAccounts(accounts)) addresses, err := db.GetAddresses() require.NoError(t, err) require.Equal(t, []types.Address{{0x01}, {0x02}}, addresses) @@ -119,7 +47,7 @@ func TestGetWalletAddress(t *testing.T) { address := types.Address{0x01} _, err := db.GetWalletAddress() require.Equal(t, err, sql.ErrNoRows) - require.NoError(t, db.SaveAccounts([]*Account{{Address: address, Wallet: true}})) + require.NoError(t, db.SaveOrUpdateAccounts([]*Account{{Address: address, Wallet: true}})) wallet, err := db.GetWalletAddress() require.NoError(t, err) require.Equal(t, address, wallet) @@ -131,44 +59,12 @@ func TestGetChatAddress(t *testing.T) { address := types.Address{0x01} _, err := db.GetChatAddress() require.Equal(t, err, sql.ErrNoRows) - require.NoError(t, db.SaveAccounts([]*Account{{Address: address, Chat: true}})) + require.NoError(t, db.SaveOrUpdateAccounts([]*Account{{Address: address, Chat: true}})) chat, err := db.GetChatAddress() require.NoError(t, err) require.Equal(t, address, chat) } -func TestGetAccounts(t *testing.T) { - db, stop := setupTestDB(t) - defer stop() - accounts := []*Account{ - {Address: types.Address{0x01}, Chat: true, Wallet: true}, - {Address: types.Address{0x02}, PublicKey: types.HexBytes{0x01, 0x02}}, - {Address: types.Address{0x03}, PublicKey: types.HexBytes{0x02, 0x03}}, - } - require.NoError(t, db.SaveAccounts(accounts)) - rst, err := db.GetAccounts() - require.NoError(t, err) - require.Equal(t, accounts, rst) -} - -func TestGetAccountByAddress(t *testing.T) { - db, stop := setupTestDB(t) - defer stop() - address := types.Address{0x01} - account := &Account{Address: address, Chat: true, Wallet: true} - dilute := []*Account{ - {Address: types.Address{0x02}, PublicKey: types.HexBytes{0x01, 0x02}}, - {Address: types.Address{0x03}, PublicKey: types.HexBytes{0x02, 0x03}}, - } - - accounts := append(dilute, account) - - require.NoError(t, db.SaveAccounts(accounts)) - rst, err := db.GetAccountByAddress(address) - require.NoError(t, err) - require.Equal(t, account, rst) -} - func TestAddressExists(t *testing.T) { db, stop := setupTestDB(t) defer stop() @@ -176,7 +72,7 @@ func TestAddressExists(t *testing.T) { accounts := []*Account{ {Address: types.Address{0x01}, Chat: true, Wallet: true}, } - require.NoError(t, db.SaveAccounts(accounts)) + require.NoError(t, db.SaveOrUpdateAccounts(accounts)) exists, err := db.AddressExists(accounts[0].Address) require.NoError(t, err) @@ -191,74 +87,260 @@ func TestAddressDoesntExist(t *testing.T) { require.False(t, exists) } -func TestKeypairNameAndIndexWhenAddingNewAccount(t *testing.T) { +func TestWatchOnlyAccounts(t *testing.T) { db, stop := setupTestDB(t) defer stop() - accountsRegular := []*Account{ - // chat account - {Address: types.Address{0x01}, Chat: true, Wallet: false, KeyUID: "0x0001"}, - // Status Profile keypair - {Address: types.Address{0x02}, Chat: false, Wallet: true, KeyUID: "0x0001", Path: "m/44'/60'/0'/0/0", LastUsedDerivationIndex: 0, DerivedFrom: "0x1111", KeypairName: "Status Profile"}, - {Address: types.Address{0x03}, Chat: false, Wallet: false, KeyUID: "0x0001", Path: "m/44'/60'/0'/0/1", LastUsedDerivationIndex: 1, DerivedFrom: "0x1111", KeypairName: "Status Profile"}, - {Address: types.Address{0x04}, Chat: false, Wallet: false, KeyUID: "0x0001", Path: "m/44'/60'/0'/0/2", LastUsedDerivationIndex: 2, DerivedFrom: "0x1111", KeypairName: "Status Profile"}, + + // check the db + dbAccounts, err := db.GetAccounts() + require.NoError(t, err) + require.Equal(t, 0, len(dbAccounts)) + + woAccounts := GetWatchOnlyAccountsForTest() + + // try to save keypair with watch only accounts + kp := &Keypair{} + kp.Accounts = append(kp.Accounts, woAccounts...) + err = db.SaveOrUpdateKeypair(kp) + require.Error(t, err) + + // check the db after that trying to save keypair with watch only accounts + dbAccounts, err = db.GetAccounts() + require.NoError(t, err) + require.Equal(t, 0, len(dbAccounts)) + + // save watch only accounts + err = db.SaveOrUpdateAccounts(woAccounts) + require.NoError(t, err) + _, err = db.GetKeypairByKeyUID(woAccounts[0].KeyUID) + require.Error(t, err) + require.True(t, err == ErrDbKeypairNotFound) + dbAccounts, err = db.GetAccounts() + require.NoError(t, err) + require.Equal(t, len(woAccounts), len(dbAccounts)) + require.Equal(t, woAccounts, dbAccounts) + + // try to save the same watch only account again + err = db.SaveOrUpdateAccounts(woAccounts[:1]) + require.NoError(t, err) + dbAccounts, err = db.GetAccounts() + require.NoError(t, err) + require.Equal(t, len(woAccounts), len(dbAccounts)) + dbAcc, err := db.GetAccountByAddress(woAccounts[:1][0].Address) + require.NoError(t, err) + require.Equal(t, woAccounts[:1][0], dbAcc) + + // try to save new watch only account + wo4 := &Account{ + Address: types.Address{0x14}, + Type: AccountTypeWatch, + Name: "WatchOnlyAcc4", + Color: "blue", + Emoji: "emoji-1", } - accountsCustom := []*Account{ - // Keypair1 - {Address: types.Address{0x11}, Chat: false, Wallet: false, KeyUID: "0x0002", Path: "m/44'/60'/0'/0/10", LastUsedDerivationIndex: 0, DerivedFrom: "0x2222", KeypairName: "Keypair11"}, - {Address: types.Address{0x12}, Chat: false, Wallet: false, KeyUID: "0x0002", Path: "m/44'/60'/0'/0/11", LastUsedDerivationIndex: 0, DerivedFrom: "0x2222", KeypairName: "Keypair12"}, - // Keypair2 out of the default Status' derivation tree - {Address: types.Address{0x22}, Chat: false, Wallet: false, KeyUID: "0x0003", Path: "m/44'/60'/0'/0/0/100", LastUsedDerivationIndex: 0, DerivedFrom: "0x3333", KeypairName: "Keypair21"}, - {Address: types.Address{0x23}, Chat: false, Wallet: false, KeyUID: "0x0003", Path: "m/44'/60'/0'/0/1/100", LastUsedDerivationIndex: 0, DerivedFrom: "0x3333", KeypairName: "Keypair22"}, - } - - err := db.SaveAccounts(accountsRegular) + err = db.SaveOrUpdateAccounts([]*Account{wo4}) require.NoError(t, err) - err = db.SaveAccounts(accountsCustom) + dbAccounts, err = db.GetAccounts() require.NoError(t, err) - accs, err := db.GetAccounts() + require.Equal(t, len(woAccounts)+1, len(dbAccounts)) + dbAcc, err = db.GetAccountByAddress(wo4.Address) require.NoError(t, err) + require.Equal(t, wo4, dbAcc) - for _, acc := range accs { - if acc.Chat { - continue - } - if acc.KeyUID == accountsRegular[0].KeyUID { - require.Equal(t, uint64(2), acc.LastUsedDerivationIndex) - require.Equal(t, "Status Profile", acc.KeypairName) - } else if acc.KeyUID == accountsCustom[1].KeyUID { - require.Equal(t, uint64(0), acc.LastUsedDerivationIndex) - require.Equal(t, "Keypair12", acc.KeypairName) - } else if acc.KeyUID == accountsCustom[3].KeyUID { - require.Equal(t, uint64(0), acc.LastUsedDerivationIndex) - require.Equal(t, "Keypair22", acc.KeypairName) - } - } - - accountsCustom = []*Account{ - // Status Profile keypair - {Address: types.Address{0x05}, Chat: false, Wallet: false, KeyUID: "0x0001", Path: "m/44'/60'/0'/0/100/1", LastUsedDerivationIndex: 2, DerivedFrom: "0x1111", KeypairName: "Status Profile"}, - } - - err = db.SaveAccounts(accountsCustom) + // updated watch onl to save the same account after it's saved + wo4.Name = wo4.Name + "updated" + wo4.Color = "lightgreen" + wo4.Emoji = wo4.Emoji + "updated" + err = db.SaveOrUpdateAccounts([]*Account{wo4}) require.NoError(t, err) - - result, err := db.GetAccountsByKeyUID(accountsCustom[0].KeyUID) + dbAccounts, err = db.GetAccounts() require.NoError(t, err) - require.Equal(t, 5, len(result)) - require.Equal(t, uint64(2), accountsCustom[0].LastUsedDerivationIndex) - require.Equal(t, "Status Profile", accountsCustom[0].KeypairName) - - accountsRegular = []*Account{ - // Status Profile keypair - {Address: types.Address{0x06}, Chat: false, Wallet: false, KeyUID: "0x0001", Path: "m/44'/60'/0'/0/3", LastUsedDerivationIndex: 3, DerivedFrom: "0x1111", KeypairName: "Status Profile"}, - } - - err = db.SaveAccounts(accountsRegular) + require.Equal(t, len(woAccounts)+1, len(dbAccounts)) + dbAcc, err = db.GetAccountByAddress(wo4.Address) require.NoError(t, err) + require.Equal(t, wo4, dbAcc) - result, err = db.GetAccountsByKeyUID(accountsCustom[0].KeyUID) + // try to delete keypair for watch only account + err = db.DeleteKeypair(wo4.KeyUID) + require.Error(t, err) + require.True(t, err == ErrDbKeypairNotFound) + + // try to delete watch only account + err = db.DeleteAccount(wo4.Address) require.NoError(t, err) - require.Equal(t, 6, len(result)) - require.Equal(t, uint64(3), accountsRegular[0].LastUsedDerivationIndex) - require.Equal(t, "Status Profile", accountsRegular[0].KeypairName) + dbAccounts, err = db.GetAccounts() + require.NoError(t, err) + require.Equal(t, len(woAccounts), len(dbAccounts)) + _, err = db.GetAccountByAddress(wo4.Address) + require.Error(t, err) + require.True(t, err == ErrDbAccountNotFound) +} + +func TestKeypairs(t *testing.T) { + keypairs := []*Keypair{ + GetProfileKeypairForTest(false), + GetSeedImportedKeypair1ForTest(), + GetPrivKeyImportedKeypairForTest(), // in this context (when testing db functions) there is not limitations for private key imported keypair + } + + for _, kp := range keypairs { + t.Run("test keypair "+kp.Name, func(t *testing.T) { + db, stop := setupTestDB(t) + defer stop() + + // check the db + dbKeypairs, err := db.GetKeypairs() + require.NoError(t, err) + require.Equal(t, 0, len(dbKeypairs)) + dbAccounts, err := db.GetAccounts() + require.NoError(t, err) + require.Equal(t, 0, len(dbAccounts)) + + expectedLastUsedDerivationIndex := uint64(len(kp.Accounts) - 1) + if kp.Type == KeypairTypeProfile { + expectedLastUsedDerivationIndex-- // subtract one more in case of profile keypair because of chat account + } + + // save keypair + err = db.SaveOrUpdateKeypair(kp) + require.NoError(t, err) + dbKeypairs, err = db.GetKeypairs() + require.NoError(t, err) + require.Equal(t, 1, len(dbKeypairs)) + dbKp, err := db.GetKeypairByKeyUID(kp.KeyUID) + require.NoError(t, err) + require.Equal(t, len(kp.Accounts), len(dbKp.Accounts)) + kp.LastUsedDerivationIndex = expectedLastUsedDerivationIndex + require.Equal(t, kp, dbKp) + dbAccounts, err = db.GetAccounts() + require.NoError(t, err) + require.Equal(t, len(kp.Accounts), len(dbAccounts)) + + // delete keypair + err = db.DeleteKeypair(kp.KeyUID) + require.NoError(t, err) + _, err = db.GetKeypairByKeyUID(kp.KeyUID) + require.Error(t, err) + require.True(t, err == ErrDbKeypairNotFound) + + // save keypair again to test the flow below + err = db.SaveOrUpdateKeypair(kp) + require.NoError(t, err) + dbKeypairs, err = db.GetKeypairs() + require.NoError(t, err) + require.Equal(t, 1, len(dbKeypairs)) + + ind := len(kp.Accounts) - 1 + accToUpdate := kp.Accounts[ind] + + // try to save the same account again + err = db.SaveOrUpdateAccounts([]*Account{accToUpdate}) + require.NoError(t, err) + dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID) + require.NoError(t, err) + require.Equal(t, len(kp.Accounts), len(dbKp.Accounts)) + require.Equal(t, kp, dbKp) + dbAccounts, err = db.GetAccounts() + require.NoError(t, err) + require.Equal(t, len(kp.Accounts), len(dbAccounts)) + + // update an existing account + accToUpdate.Name = accToUpdate.Name + "updated" + accToUpdate.Color = "green" + accToUpdate.Emoji = accToUpdate.Emoji + "updated" + + err = db.SaveOrUpdateAccounts([]*Account{accToUpdate}) + require.NoError(t, err) + dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID) + require.NoError(t, err) + require.Equal(t, len(kp.Accounts), len(dbKp.Accounts)) + dbAccounts, err = db.GetAccounts() + require.NoError(t, err) + require.Equal(t, len(kp.Accounts), len(dbAccounts)) + dbAcc, err := db.GetAccountByAddress(accToUpdate.Address) + require.NoError(t, err) + require.Equal(t, accToUpdate, dbAcc) + + // update keypair name + kpToUpdate := kp + kpToUpdate.Name = kpToUpdate.Name + "updated" + err = db.SaveOrUpdateKeypair(kp) + require.NoError(t, err) + dbKeypairs, err = db.GetKeypairs() + require.NoError(t, err) + require.Equal(t, 1, len(dbKeypairs)) + dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID) + require.NoError(t, err) + require.Equal(t, len(kp.Accounts), len(dbKp.Accounts)) + require.Equal(t, kpToUpdate, dbKp) + + // save new account to an existing keypair which is out of the default Status' derivation root path + accToAdd := kp.Accounts[ind] + accToAdd.Address = types.Address{0x08} + accToAdd.Path = "m/44'/60'/0'/0/10" + accToAdd.PublicKey = types.Hex2Bytes("0x000000008") + accToAdd.Name = "Generated Acc 8" + + err = db.SaveOrUpdateAccounts([]*Account{accToAdd}) + require.NoError(t, err) + dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID) + require.NoError(t, err) + require.Equal(t, len(kp.Accounts)+1, len(dbKp.Accounts)) + require.Equal(t, kp.LastUsedDerivationIndex, dbKp.LastUsedDerivationIndex) + dbAccounts, err = db.GetAccounts() + require.NoError(t, err) + require.Equal(t, len(kp.Accounts)+1, len(dbAccounts)) + dbAcc, err = db.GetAccountByAddress(accToUpdate.Address) + require.NoError(t, err) + require.Equal(t, accToAdd, dbAcc) + + // save new account to an existing keypair which follows Status' default derivation root path + accToAdd = kp.Accounts[ind] + accToAdd.Address = types.Address{0x09} + accToAdd.Path = "m/44'/60'/0'/0/3" + accToAdd.PublicKey = types.Hex2Bytes("0x000000009") + accToAdd.Name = "Generated Acc 9" + + expectedLastUsedDerivationIndex = 3 + if kp.Type == KeypairTypeSeed { + accToAdd.Path = "m/44'/60'/0'/0/2" + expectedLastUsedDerivationIndex = 2 + } else if kp.Type == KeypairTypeKey { + accToAdd.Path = "m/44'/60'/0'/0/1" + expectedLastUsedDerivationIndex = 1 + } + + err = db.SaveOrUpdateAccounts([]*Account{accToAdd}) + require.NoError(t, err) + dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID) + require.NoError(t, err) + require.Equal(t, len(kp.Accounts)+2, len(dbKp.Accounts)) + require.Equal(t, expectedLastUsedDerivationIndex, dbKp.LastUsedDerivationIndex) + dbAccounts, err = db.GetAccounts() + require.NoError(t, err) + require.Equal(t, len(kp.Accounts)+2, len(dbAccounts)) + dbAcc, err = db.GetAccountByAddress(accToUpdate.Address) + require.NoError(t, err) + require.Equal(t, accToAdd, dbAcc) + + // delete account + err = db.DeleteAccount(accToAdd.Address) + require.NoError(t, err) + dbAccounts, err = db.GetAccounts() + require.NoError(t, err) + require.Equal(t, len(kp.Accounts)+1, len(dbAccounts)) + _, err = db.GetAccountByAddress(accToAdd.Address) + require.Error(t, err) + require.True(t, err == ErrDbAccountNotFound) + + for _, acc := range dbAccounts { + err = db.DeleteAccount(acc.Address) + require.NoError(t, err) + } + + _, err = db.GetKeypairByKeyUID(kp.KeyUID) + require.Error(t, err) + require.True(t, err == ErrDbKeypairNotFound) + }) + } } diff --git a/multiaccounts/keycards/database_test.go b/multiaccounts/accounts/keycard_database_test.go similarity index 63% rename from multiaccounts/keycards/database_test.go rename to multiaccounts/accounts/keycard_database_test.go index e57fefc8e..6cecb556b 100644 --- a/multiaccounts/keycards/database_test.go +++ b/multiaccounts/accounts/keycard_database_test.go @@ -1,98 +1,76 @@ -package keycards +package accounts import ( "testing" "github.com/stretchr/testify/require" - "github.com/status-im/status-go/appdatabase" "github.com/status-im/status-go/eth-node/types" ) -func setupTestDB(t *testing.T) (*Keycards, func()) { - db, stop, err := appdatabase.SetupTestSQLDB("settings-tests-") - if err != nil { - require.NoError(t, stop()) - } - require.NoError(t, err) - - d := NewKeycards(db) - - return d, func() { - require.NoError(t, stop()) - } -} - func TestKeycards(t *testing.T) { db, stop := setupTestDB(t) defer stop() keycardUID := "00000000000000000000000000000000" - keycard1 := Keycard{ - KeycardUID: "00000000000000000000000000000001", - KeycardName: "Card01", - KeycardLocked: false, - AccountsAddresses: []types.Address{{0x01}, {0x02}, {0x03}, {0x04}}, - KeyUID: "0000000000000000000000000000000000000000000000000000000000000001", - LastUpdateClock: 100, - } - keycard2 := Keycard{ - KeycardUID: "00000000000000000000000000000002", - KeycardName: "Card02", - KeycardLocked: false, - AccountsAddresses: []types.Address{{0x01}, {0x02}}, - KeyUID: "0000000000000000000000000000000000000000000000000000000000000002", - LastUpdateClock: 200, - } - keycard3 := Keycard{ - KeycardUID: "00000000000000000000000000000003", - KeycardName: "Card02 Copy", - KeycardLocked: false, - AccountsAddresses: []types.Address{{0x01}, {0x02}}, - KeyUID: "0000000000000000000000000000000000000000000000000000000000000002", - LastUpdateClock: 300, - } - keycard4 := Keycard{ - KeycardUID: "00000000000000000000000000000004", - KeycardName: "Card04", - KeycardLocked: false, - AccountsAddresses: []types.Address{{0x01}, {0x02}, {0x03}}, - KeyUID: "0000000000000000000000000000000000000000000000000000000000000004", - LastUpdateClock: 400, - } + + kp1 := GetProfileKeypairForTest(false) + keycard1 := GetProfileKeycardForTest() + + kp2 := GetSeedImportedKeypair1ForTest() + keycard2 := GetKeycardForSeedImportedKeypair1ForTest() + + keycard2Copy := GetKeycardForSeedImportedKeypair1ForTest() + keycard2Copy.KeycardUID = keycard2Copy.KeycardUID + "C" + keycard2Copy.KeycardName = keycard2Copy.KeycardName + "Copy" + keycard2Copy.LastUpdateClock = keycard2Copy.LastUpdateClock + 1 + + kp3 := GetSeedImportedKeypair2ForTest() + keycard3 := GetKeycardForSeedImportedKeypair2ForTest() + + // Pre-condition + err := db.SaveOrUpdateKeypair(kp1) + require.NoError(t, err) + err = db.SaveOrUpdateKeypair(kp2) + require.NoError(t, err) + err = db.SaveOrUpdateKeypair(kp3) + require.NoError(t, err) + dbKeypairs, err := db.GetKeypairs() + require.NoError(t, err) + require.Equal(t, 3, len(dbKeypairs)) // Test adding key pairs - addedKc, addedAccs, err := db.AddKeycardOrAddAccountsIfKeycardIsAdded(keycard1) + addedKc, addedAccs, err := db.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) require.NoError(t, err) require.Equal(t, true, addedKc) require.Equal(t, false, addedAccs) - addedKc, addedAccs, err = db.AddKeycardOrAddAccountsIfKeycardIsAdded(keycard2) + addedKc, addedAccs, err = db.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2) require.NoError(t, err) require.Equal(t, true, addedKc) require.Equal(t, false, addedAccs) - addedKc, addedAccs, err = db.AddKeycardOrAddAccountsIfKeycardIsAdded(keycard3) + addedKc, addedAccs, err = db.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2Copy) require.NoError(t, err) require.Equal(t, true, addedKc) require.Equal(t, false, addedAccs) // this should be added addedKc, addedAccs, err = db.AddKeycardOrAddAccountsIfKeycardIsAdded(Keycard{ - KeycardUID: keycard3.KeycardUID, + KeycardUID: keycard2Copy.KeycardUID, AccountsAddresses: []types.Address{{0x03}}, - LastUpdateClock: keycard3.LastUpdateClock + 1, + LastUpdateClock: keycard2Copy.LastUpdateClock + 1, }) require.NoError(t, err) require.Equal(t, false, addedKc) require.Equal(t, true, addedAccs) // this should not be added as it has clock value less than last updated clock value addedKc, addedAccs, err = db.AddKeycardOrAddAccountsIfKeycardIsAdded(Keycard{ - KeycardUID: keycard3.KeycardUID, + KeycardUID: keycard2Copy.KeycardUID, AccountsAddresses: []types.Address{{0x04}}, - LastUpdateClock: keycard3.LastUpdateClock, + LastUpdateClock: keycard2Copy.LastUpdateClock, }) require.NoError(t, err) require.Equal(t, false, addedKc) require.Equal(t, false, addedAccs) - addedKc, addedAccs, err = db.AddKeycardOrAddAccountsIfKeycardIsAdded(keycard4) + addedKc, addedAccs, err = db.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard3) require.NoError(t, err) require.Equal(t, true, addedKc) require.Equal(t, false, addedAccs) @@ -113,10 +91,10 @@ func TestKeycards(t *testing.T) { require.Equal(t, keycard2.KeycardLocked, kp.KeycardLocked) require.Equal(t, len(keycard2.AccountsAddresses)+1, len(kp.AccountsAddresses)) // Add 1, cause one account is additionally added for the same keycard. } else { - require.Equal(t, keycard4.KeycardUID, kp.KeycardUID) - require.Equal(t, keycard4.KeycardName, kp.KeycardName) - require.Equal(t, keycard4.KeycardLocked, kp.KeycardLocked) - require.Equal(t, len(keycard4.AccountsAddresses), len(kp.AccountsAddresses)) + require.Equal(t, keycard3.KeycardUID, kp.KeycardUID) + require.Equal(t, keycard3.KeycardName, kp.KeycardName) + require.Equal(t, keycard3.KeycardLocked, kp.KeycardLocked) + require.Equal(t, len(keycard3.AccountsAddresses), len(kp.AccountsAddresses)) } } @@ -146,18 +124,18 @@ func TestKeycards(t *testing.T) { require.Equal(t, keycard2.KeycardLocked, kp.KeycardLocked) require.Equal(t, len(keycard2.AccountsAddresses), len(kp.AccountsAddresses)) require.Equal(t, keycard2.LastUpdateClock, kp.LastUpdateClock) - } else if kp.KeycardUID == keycard3.KeycardUID { + } else if kp.KeycardUID == keycard2Copy.KeycardUID { + require.Equal(t, keycard2Copy.KeycardUID, kp.KeycardUID) + require.Equal(t, keycard2Copy.KeycardName, kp.KeycardName) + require.Equal(t, keycard2Copy.KeycardLocked, kp.KeycardLocked) + require.Equal(t, len(keycard2Copy.AccountsAddresses)+1, len(kp.AccountsAddresses)) // Add 1, cause one account is additionally added. + require.Equal(t, keycard2Copy.LastUpdateClock+1, kp.LastUpdateClock) + } else { require.Equal(t, keycard3.KeycardUID, kp.KeycardUID) require.Equal(t, keycard3.KeycardName, kp.KeycardName) require.Equal(t, keycard3.KeycardLocked, kp.KeycardLocked) - require.Equal(t, len(keycard3.AccountsAddresses)+1, len(kp.AccountsAddresses)) // Add 1, cause one account is additionally added. - require.Equal(t, keycard3.LastUpdateClock+1, kp.LastUpdateClock) - } else { - require.Equal(t, keycard4.KeycardUID, kp.KeycardUID) - require.Equal(t, keycard4.KeycardName, kp.KeycardName) - require.Equal(t, keycard4.KeycardLocked, kp.KeycardLocked) - require.Equal(t, len(keycard4.AccountsAddresses), len(kp.AccountsAddresses)) - require.Equal(t, keycard4.LastUpdateClock, kp.LastUpdateClock) + require.Equal(t, len(keycard3.AccountsAddresses), len(kp.AccountsAddresses)) + require.Equal(t, keycard3.LastUpdateClock, kp.LastUpdateClock) } } @@ -212,20 +190,20 @@ func TestKeycards(t *testing.T) { require.Equal(t, len(keycard1.AccountsAddresses)-numOfAccountsToRemove, len(rows[0].AccountsAddresses)) // Test deleting accounts one by one, with the last deleted account keycard should be delete as well - for i, addr := range keycard4.AccountsAddresses { - err = db.RemoveMigratedAccountsForKeycard(keycard4.KeycardUID, []types.Address{addr}, 1003+uint64(i)) + for i, addr := range keycard3.AccountsAddresses { + err = db.RemoveMigratedAccountsForKeycard(keycard3.KeycardUID, []types.Address{addr}, 1003+uint64(i)) require.NoError(t, err) } rows, err = db.GetAllKnownKeycardsGroupedByKeyUID() require.NoError(t, err) // Test if correct keycard is deleted - deletedKeycard4 := true + deletedKeycard3 := true for _, kp := range rows { - if kp.KeycardUID == keycard4.KeycardUID { - deletedKeycard4 = false + if kp.KeycardUID == keycard3.KeycardUID { + deletedKeycard3 = false } } - require.Equal(t, true, deletedKeycard4) + require.Equal(t, true, deletedKeycard3) // Test update keycard uid err = db.UpdateKeycardUID(keycard1.KeycardUID, keycardUID, 1100) @@ -273,3 +251,77 @@ func TestKeycards(t *testing.T) { } require.Equal(t, true, deletedKeycard2And3) } + +func TestKeycardsRemovalWhenDeletingKeypair(t *testing.T) { + db, stop := setupTestDB(t) + defer stop() + + kp2 := &Keypair{ + KeyUID: "0000000000000000000000000000000000000000000000000000000000000002", + Name: "Keypair Name 2", + Type: KeypairTypeSeed, + DerivedFrom: "0x0001", + } + kp2.Accounts = append(kp2.Accounts, &Account{Address: types.Address{0x11}, KeyUID: kp2.KeyUID}) + kp2.Accounts = append(kp2.Accounts, &Account{Address: types.Address{0x12}, KeyUID: kp2.KeyUID}) + + keycard2 := Keycard{ + KeycardUID: "00000000000000000000000000000002", + KeycardName: "Card02", + KeycardLocked: false, + AccountsAddresses: []types.Address{{0x11}, {0x12}}, + KeyUID: kp2.KeyUID, + LastUpdateClock: 200, + } + keycard3 := Keycard{ + KeycardUID: "00000000000000000000000000000003", + KeycardName: "Card02 Copy", + KeycardLocked: false, + AccountsAddresses: []types.Address{{0x11}, {0x12}}, + KeyUID: kp2.KeyUID, + LastUpdateClock: 300, + } + + // Pre-condition - save keypair + err := db.SaveOrUpdateKeypair(kp2) + require.NoError(t, err) + dbKeypairs, err := db.GetKeypairs() + require.NoError(t, err) + require.Equal(t, 1, len(dbKeypairs)) + + // Pre-condition - save keycards referring to previously added keypair + addedKc, addedAccs, err := db.AddKeycardOrAddAccountsIfKeycardIsAdded(keycard2) + require.NoError(t, err) + require.Equal(t, true, addedKc) + require.Equal(t, false, addedAccs) + addedKc, addedAccs, err = db.AddKeycardOrAddAccountsIfKeycardIsAdded(keycard3) + require.NoError(t, err) + require.Equal(t, true, addedKc) + require.Equal(t, false, addedAccs) + + // Check db state + keycardsWithSameKeyUID, err := db.GetAllKnownKeycards() + require.NoError(t, err) + require.Equal(t, 2, len(keycardsWithSameKeyUID)) + + require.Equal(t, len(kp2.KeyUID), len(dbKeypairs[0].KeyUID)) + require.Equal(t, len(kp2.KeyUID), len(keycardsWithSameKeyUID[0].KeyUID)) + require.Equal(t, len(kp2.KeyUID), len(keycardsWithSameKeyUID[1].KeyUID)) + + require.Equal(t, len(kp2.Accounts), len(dbKeypairs[0].Accounts)) + require.Equal(t, len(kp2.Accounts), len(keycardsWithSameKeyUID[0].AccountsAddresses)) + require.Equal(t, len(kp2.Accounts), len(keycardsWithSameKeyUID[1].AccountsAddresses)) + + // Remove keypair + err = db.DeleteKeypair(kp2.KeyUID) + require.NoError(t, err) + + // Check db state after deletion + dbKeypairs, err = db.GetKeypairs() + require.NoError(t, err) + require.Equal(t, 0, len(dbKeypairs)) + + keycardsWithSameKeyUID, err = db.GetAllKnownKeycards() + require.NoError(t, err) + require.Equal(t, 0, len(keycardsWithSameKeyUID)) +} diff --git a/multiaccounts/accounts/test_helper.go b/multiaccounts/accounts/test_helper.go new file mode 100644 index 000000000..c6c453d15 --- /dev/null +++ b/multiaccounts/accounts/test_helper.go @@ -0,0 +1,397 @@ +package accounts + +import ( + "github.com/status-im/status-go/eth-node/types" +) + +func GetWatchOnlyAccountsForTest() []*Account { + wo1 := &Account{ + Address: types.Address{0x11}, + Type: AccountTypeWatch, + Name: "WatchOnlyAcc1", + Color: "blue", + Emoji: "emoji-1", + } + wo2 := &Account{ + Address: types.Address{0x12}, + Type: AccountTypeWatch, + Name: "WatchOnlyAcc2", + Color: "blue", + Emoji: "emoji-1", + } + wo3 := &Account{ + Address: types.Address{0x13}, + Type: AccountTypeWatch, + Name: "WatchOnlyAcc3", + Color: "blue", + Emoji: "emoji-1", + } + + return []*Account{wo1, wo2, wo3} +} + +func GetProfileKeypairForTest(onlyChatAndDefaultWalletAccount bool) *Keypair { + kp := &Keypair{ + KeyUID: "0000000000000000000000000000000000000000000000000000000000000001", + Name: "Profile Name", + Type: KeypairTypeProfile, + DerivedFrom: "0x0001", + } + + profileAccount := &Account{ + Address: types.Address{0x01}, + KeyUID: kp.KeyUID, + Wallet: false, + Chat: true, + Type: AccountTypeGenerated, + Path: "m/43'/60'/1581'/0'/0", + PublicKey: types.Hex2Bytes("0x000000001"), + Name: "Profile Name", + Operable: AccountFullyOperable, + } + kp.Accounts = append(kp.Accounts, profileAccount) + + defaultWalletAccount := &Account{ + Address: types.Address{0x02}, + KeyUID: kp.KeyUID, + Wallet: true, + Chat: false, + Type: AccountTypeGenerated, + Path: "m/44'/60'/0'/0/0", + PublicKey: types.Hex2Bytes("0x000000002"), + Name: "Generated Acc 1", + Emoji: "emoji-1", + Color: "blue", + Hidden: false, + Clock: 0, + Removed: false, + Operable: AccountFullyOperable, + } + kp.Accounts = append(kp.Accounts, defaultWalletAccount) + kp.LastUsedDerivationIndex = 0 + + if !onlyChatAndDefaultWalletAccount { + generatedWalletAccount1 := &Account{ + Address: types.Address{0x03}, + KeyUID: kp.KeyUID, + Wallet: false, + Chat: false, + Type: AccountTypeGenerated, + Path: "m/44'/60'/0'/0/1", + PublicKey: types.Hex2Bytes("0x000000003"), + Name: "Generated Acc 2", + Emoji: "emoji-2", + Color: "blue", + Hidden: false, + Clock: 0, + Removed: false, + Operable: AccountFullyOperable, + } + kp.Accounts = append(kp.Accounts, generatedWalletAccount1) + kp.LastUsedDerivationIndex = 1 + + generatedWalletAccount2 := &Account{ + Address: types.Address{0x04}, + KeyUID: kp.KeyUID, + Wallet: false, + Chat: false, + Type: AccountTypeGenerated, + Path: "m/44'/60'/0'/0/2", + PublicKey: types.Hex2Bytes("0x000000004"), + Name: "Generated Acc 3", + Emoji: "emoji-3", + Color: "blue", + Hidden: false, + Clock: 0, + Removed: false, + Operable: AccountFullyOperable, + } + kp.Accounts = append(kp.Accounts, generatedWalletAccount2) + kp.LastUsedDerivationIndex = 2 + } + + return kp +} + +func GetSeedImportedKeypair1ForTest() *Keypair { + kp := &Keypair{ + KeyUID: "0000000000000000000000000000000000000000000000000000000000000002", + Name: "Seed Imported 1", + Type: KeypairTypeSeed, + DerivedFrom: "0x0002", + } + + seedGeneratedWalletAccount1 := &Account{ + Address: types.Address{0x21}, + KeyUID: kp.KeyUID, + Wallet: false, + Chat: false, + Type: AccountTypeSeed, + Path: "m/44'/60'/0'/0/0", + PublicKey: types.Hex2Bytes("0x000000021"), + Name: "Seed Impo 1 Acc 1", + Emoji: "emoji-1", + Color: "blue", + Hidden: false, + Clock: 0, + Removed: false, + Operable: AccountFullyOperable, + } + kp.Accounts = append(kp.Accounts, seedGeneratedWalletAccount1) + kp.LastUsedDerivationIndex = 0 + + seedGeneratedWalletAccount2 := &Account{ + Address: types.Address{0x22}, + KeyUID: kp.KeyUID, + Wallet: false, + Chat: false, + Type: AccountTypeSeed, + Path: "m/44'/60'/0'/0/1", + PublicKey: types.Hex2Bytes("0x000000022"), + Name: "Seed Impo 1 Acc 2", + Emoji: "emoji-2", + Color: "blue", + Hidden: false, + Clock: 0, + Removed: false, + Operable: AccountFullyOperable, + } + kp.Accounts = append(kp.Accounts, seedGeneratedWalletAccount2) + kp.LastUsedDerivationIndex = 1 + + return kp +} + +func GetSeedImportedKeypair2ForTest() *Keypair { + kp := &Keypair{ + KeyUID: "0000000000000000000000000000000000000000000000000000000000000003", + Name: "Seed Imported 2", + Type: KeypairTypeSeed, + DerivedFrom: "0x0003", + } + + seedGeneratedWalletAccount1 := &Account{ + Address: types.Address{0x31}, + KeyUID: kp.KeyUID, + Wallet: false, + Chat: false, + Type: AccountTypeSeed, + Path: "m/44'/60'/0'/0/0", + PublicKey: types.Hex2Bytes("0x000000031"), + Name: "Seed Impo 2 Acc 1", + Emoji: "emoji-1", + Color: "blue", + Hidden: false, + Clock: 0, + Removed: false, + Operable: AccountFullyOperable, + } + kp.Accounts = append(kp.Accounts, seedGeneratedWalletAccount1) + kp.LastUsedDerivationIndex = 0 + + seedGeneratedWalletAccount2 := &Account{ + Address: types.Address{0x32}, + KeyUID: kp.KeyUID, + Wallet: false, + Chat: false, + Type: AccountTypeSeed, + Path: "m/44'/60'/0'/0/1", + PublicKey: types.Hex2Bytes("0x000000032"), + Name: "Seed Impo 2 Acc 2", + Emoji: "emoji-2", + Color: "blue", + Hidden: false, + Clock: 0, + Removed: false, + Operable: AccountFullyOperable, + } + kp.Accounts = append(kp.Accounts, seedGeneratedWalletAccount2) + kp.LastUsedDerivationIndex = 1 + + return kp +} + +func GetPrivKeyImportedKeypairForTest() *Keypair { + kp := &Keypair{ + KeyUID: "0000000000000000000000000000000000000000000000000000000000000004", + Name: "Priv Key Imported", + Type: KeypairTypeKey, + DerivedFrom: "", // no derived from for private key imported kp + } + + privKeyWalletAccount := &Account{ + Address: types.Address{0x41}, + KeyUID: kp.KeyUID, + Wallet: false, + Chat: false, + Type: AccountTypeKey, + Path: "m", + PublicKey: types.Hex2Bytes("0x000000041"), + Name: "Priv Key Impo Acc", + Emoji: "emoji-1", + Color: "blue", + Hidden: false, + Clock: 0, + Removed: false, + Operable: AccountFullyOperable, + } + kp.Accounts = append(kp.Accounts, privKeyWalletAccount) + + return kp +} + +func GetProfileKeycardForTest() *Keycard { + profileKp := GetProfileKeypairForTest(false) + keycard1Addresses := []types.Address{} + for _, acc := range profileKp.Accounts { + keycard1Addresses = append(keycard1Addresses, acc.Address) + } + return &Keycard{ + KeycardUID: "00000000000000000000000000000001", + KeycardName: "Card01", + KeycardLocked: false, + AccountsAddresses: keycard1Addresses, + KeyUID: profileKp.KeyUID, + LastUpdateClock: 100, + } +} + +func GetKeycardForSeedImportedKeypair1ForTest() *Keycard { + seed1Kp := GetSeedImportedKeypair1ForTest() + keycard2Addresses := []types.Address{} + for _, acc := range seed1Kp.Accounts { + keycard2Addresses = append(keycard2Addresses, acc.Address) + } + return &Keycard{ + KeycardUID: "00000000000000000000000000000002", + KeycardName: "Card02", + KeycardLocked: false, + AccountsAddresses: keycard2Addresses, + KeyUID: seed1Kp.KeyUID, + LastUpdateClock: 200, + } +} + +func GetKeycardForSeedImportedKeypair2ForTest() *Keycard { + seed2Kp := GetSeedImportedKeypair2ForTest() + keycard4Addresses := []types.Address{} + for _, acc := range seed2Kp.Accounts { + keycard4Addresses = append(keycard4Addresses, acc.Address) + } + return &Keycard{ + KeycardUID: "00000000000000000000000000000003", + KeycardName: "Card03", + KeycardLocked: false, + AccountsAddresses: keycard4Addresses, + KeyUID: seed2Kp.KeyUID, + LastUpdateClock: 300, + } +} + +func SameAccounts(expected, real *Account) bool { + return expected.Address == real.Address && + expected.KeyUID == real.KeyUID && + expected.Wallet == real.Wallet && + expected.Chat == real.Chat && + expected.Type == real.Type && + expected.Path == real.Path && + string(expected.PublicKey) == string(real.PublicKey) && + expected.Name == real.Name && + expected.Emoji == real.Emoji && + expected.Color == real.Color && + expected.Hidden == real.Hidden && + expected.Clock == real.Clock && + expected.Removed == real.Removed +} + +func SameAccountsWithDifferentOperable(expected, real *Account, expectedOperableValue AccountOperable) bool { + return SameAccounts(expected, real) && real.Operable == expectedOperableValue +} + +func SameKeypairs(expected, real *Keypair) bool { + same := expected.KeyUID == real.KeyUID && + expected.Name == real.Name && + expected.Type == real.Type && + expected.DerivedFrom == real.DerivedFrom && + expected.LastUsedDerivationIndex == real.LastUsedDerivationIndex && + expected.Clock == real.Clock && + len(expected.Accounts) == len(real.Accounts) + + if same { + for i := range expected.Accounts { + found := false + for j := range real.Accounts { + if SameAccounts(expected.Accounts[i], real.Accounts[j]) { + found = true + break + } + } + + if !found { + return false + } + } + } + + return same +} + +func SameKeypairsWithDifferentSyncedFrom(expected, real *Keypair, ignoreSyncedFrom bool, expectedSyncedFromValue string, + expectedOperableValue AccountOperable) bool { + same := expected.KeyUID == real.KeyUID && + expected.Name == real.Name && + expected.Type == real.Type && + expected.DerivedFrom == real.DerivedFrom && + expected.LastUsedDerivationIndex == real.LastUsedDerivationIndex && + expected.Clock == real.Clock && + len(expected.Accounts) == len(real.Accounts) + + if same && !ignoreSyncedFrom { + same = same && real.SyncedFrom == expectedSyncedFromValue + } + + if same { + for i := range expected.Accounts { + found := false + for j := range real.Accounts { + if SameAccountsWithDifferentOperable(expected.Accounts[i], real.Accounts[j], expectedOperableValue) { + found = true + break + } + } + + if !found { + return false + } + } + } + + return same +} + +func SameKeycards(expected, real *Keycard) bool { + same := expected.KeycardUID == real.KeycardUID && + expected.KeyUID == real.KeyUID && + expected.KeycardName == real.KeycardName && + expected.KeycardLocked == real.KeycardLocked && + expected.LastUpdateClock == real.LastUpdateClock && + len(expected.AccountsAddresses) == len(real.AccountsAddresses) + + if same { + for i := range expected.AccountsAddresses { + found := false + for j := range real.AccountsAddresses { + if expected.AccountsAddresses[i] == real.AccountsAddresses[j] { + found = true + break + } + } + + if !found { + return false + } + } + } + + return same +} diff --git a/protocol/messenger_backup_test.go b/protocol/messenger_backup_test.go index 88bc69201..f970c4eaa 100644 --- a/protocol/messenger_backup_test.go +++ b/protocol/messenger_backup_test.go @@ -16,6 +16,7 @@ import ( "github.com/status-im/status-go/eth-node/crypto" "github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/images" + "github.com/status-im/status-go/multiaccounts/accounts" "github.com/status-im/status-go/multiaccounts/settings" "github.com/status-im/status-go/protocol/protobuf" "github.com/status-im/status-go/protocol/requests" @@ -671,14 +672,25 @@ func (s *MessengerBackupSuite) TestBackupCommunities() { s.Require().Equal(clock, lastBackup) } -func (s *MessengerBackupSuite) TestBackupWalletAccounts() { +func (s *MessengerBackupSuite) TestBackupKeypairs() { // Create bob1 bob1 := s.m - walletAccounts := getWalletAccountsForTest() - s.NoError(bob1.settings.SaveAccounts(walletAccounts)) - bob1Accs, err := bob1.settings.GetAccounts() - s.Require().NoError(err, "bob1.settings.GetAccounts") - s.Len(bob1Accs, len(walletAccounts), "must have all wallet accounts") + profileKp := accounts.GetProfileKeypairForTest(false) + seedKp := accounts.GetSeedImportedKeypair1ForTest() + + // Create a main account on bob1 + err := bob1.settings.SaveOrUpdateKeypair(profileKp) + s.Require().NoError(err, "profile keypair bob1") + err = bob1.settings.SaveOrUpdateKeypair(seedKp) + s.Require().NoError(err, "seed keypair bob1") + + // Check account is present in the db for bob1 + dbProfileKp1, err := bob1.settings.GetKeypairByKeyUID(profileKp.KeyUID) + s.Require().NoError(err) + s.Require().True(accounts.SameKeypairs(profileKp, dbProfileKp1)) + dbSeedKp1, err := bob1.settings.GetKeypairByKeyUID(seedKp.KeyUID) + s.Require().NoError(err) + s.Require().True(accounts.SameKeypairs(seedKp, dbSeedKp1)) // Create bob2 bob2, err := newMessengerWithKey(s.shh, bob1.identity, s.logger, nil) @@ -700,43 +712,69 @@ func (s *MessengerBackupSuite) TestBackupWalletAccounts() { ) s.Require().NoError(err) - bob2Accs, err := bob2.settings.GetAccounts() - s.Require().NoError(err, "bob2.settings.GetAccounts") - s.Len(bob2Accs, len(walletAccounts), "must have all wallet accounts") + // Check account is present in the db for bob2 + dbProfileKp2, err := bob2.settings.GetKeypairByKeyUID(profileKp.KeyUID) + s.Require().NoError(err) + s.Require().Equal(profileKp.Name, dbProfileKp2.Name) + s.Require().Equal(accounts.SyncedFromBackup, dbProfileKp2.SyncedFrom) - for _, syncedAcc := range bob2Accs { - if syncedAcc.Chat { + for _, acc := range profileKp.Accounts { + if acc.Chat { continue } - found := false - for _, sentAcc := range walletAccounts { - if syncedAcc.Address == sentAcc.Address { - // Check account values match the expected values - s.Require().Equal(sentAcc.Address, syncedAcc.Address) - s.Require().Equal(sentAcc.Path, syncedAcc.Path) - s.Require().Equal(sentAcc.KeyUID, syncedAcc.KeyUID) - s.Require().Equal(sentAcc.Name, syncedAcc.Name) - s.Require().Equal(sentAcc.Color, syncedAcc.Color) - s.Require().Equal(sentAcc.Type, syncedAcc.Type) - s.Require().Equal(sentAcc.KeypairName, syncedAcc.KeypairName) - s.Require().Equal(sentAcc.DerivedFrom, syncedAcc.DerivedFrom) - found = true - } - } - s.Require().True(found) + s.Require().True(contains(dbProfileKp2.Accounts, acc, accounts.SameAccounts)) } + + dbSeedKp2, err := bob2.settings.GetKeypairByKeyUID(seedKp.KeyUID) + s.Require().NoError(err) + s.Require().True(accounts.SameKeypairsWithDifferentSyncedFrom(seedKp, dbSeedKp2, false, accounts.SyncedFromBackup, accounts.AccountNonOperable)) } func (s *MessengerBackupSuite) TestBackupKeycards() { // Create bob1 bob1 := s.m - allKeycardsToSync := getKeycardsForTest() - for _, kp := range allKeycardsToSync { - addedKc, addedAccs, err := bob1.settings.AddKeycardOrAddAccountsIfKeycardIsAdded(*kp) - s.Require().NoError(err) - s.Require().Equal(true, addedKc) - s.Require().Equal(false, addedAccs) - } + + kp1 := accounts.GetProfileKeypairForTest(false) + keycard1 := accounts.GetProfileKeycardForTest() + + kp2 := accounts.GetSeedImportedKeypair1ForTest() + keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest() + + keycard2Copy := accounts.GetKeycardForSeedImportedKeypair1ForTest() + keycard2Copy.KeycardUID = keycard2Copy.KeycardUID + "C" + keycard2Copy.KeycardName = keycard2Copy.KeycardName + "Copy" + keycard2Copy.LastUpdateClock = keycard2Copy.LastUpdateClock + 1 + + kp3 := accounts.GetSeedImportedKeypair2ForTest() + keycard3 := accounts.GetKeycardForSeedImportedKeypair2ForTest() + + // Pre-condition + err := bob1.settings.SaveOrUpdateKeypair(kp1) + s.Require().NoError(err) + err = bob1.settings.SaveOrUpdateKeypair(kp2) + s.Require().NoError(err) + err = bob1.settings.SaveOrUpdateKeypair(kp3) + s.Require().NoError(err) + dbKeypairs, err := bob1.settings.GetKeypairs() + s.Require().NoError(err) + s.Require().Equal(3, len(dbKeypairs)) + + addedKc, addedAccs, err := bob1.settings.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + addedKc, addedAccs, err = bob1.settings.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + addedKc, addedAccs, err = bob1.settings.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2Copy) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + addedKc, addedAccs, err = bob1.settings.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard3) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) // Create bob2 bob2, err := newMessengerWithKey(s.shh, bob1.identity, s.logger, nil) @@ -760,6 +798,47 @@ func (s *MessengerBackupSuite) TestBackupKeycards() { syncedKeycards, err := bob2.settings.GetAllKnownKeycards() s.Require().NoError(err) - s.Require().Equal(len(allKeycardsToSync), len(syncedKeycards)) - s.Require().True(haveSameElements(syncedKeycards, allKeycardsToSync, sameKeycards)) + s.Require().Equal(4, len(syncedKeycards)) + s.Require().True(contains(syncedKeycards, keycard1, accounts.SameKeycards)) + s.Require().True(contains(syncedKeycards, keycard2, accounts.SameKeycards)) + s.Require().True(contains(syncedKeycards, keycard2Copy, accounts.SameKeycards)) + s.Require().True(contains(syncedKeycards, keycard3, accounts.SameKeycards)) +} + +func (s *MessengerBackupSuite) TestBackupWatchOnlyAccounts() { + // Create bob1 + bob1 := s.m + + woAccounts := accounts.GetWatchOnlyAccountsForTest() + err := bob1.settings.SaveOrUpdateAccounts(woAccounts) + s.Require().NoError(err) + dbWoAccounts1, err := bob1.settings.GetWatchOnlyAccounts() + s.Require().NoError(err) + s.Require().Equal(len(woAccounts), len(dbWoAccounts1)) + s.Require().True(haveSameElements(woAccounts, dbWoAccounts1, accounts.SameAccounts)) + + // Create bob2 + bob2, err := newMessengerWithKey(s.shh, bob1.identity, s.logger, nil) + s.Require().NoError(err) + _, err = bob2.Start() + s.Require().NoError(err) + + // Backup + _, err = bob1.BackupData(context.Background()) + s.Require().NoError(err) + + // Wait for the message to reach its destination + _, err = WaitOnMessengerResponse( + bob2, + func(r *MessengerResponse) bool { + return r.BackupHandled + }, + "no messages", + ) + s.Require().NoError(err) + + dbWoAccounts2, err := bob2.settings.GetWatchOnlyAccounts() + s.Require().NoError(err) + s.Require().Equal(len(woAccounts), len(dbWoAccounts2)) + s.Require().True(haveSameElements(woAccounts, dbWoAccounts2, accounts.SameAccounts)) } diff --git a/protocol/messenger_sync_keycard_change_test.go b/protocol/messenger_sync_keycard_change_test.go index 16ca96e40..aa684443e 100644 --- a/protocol/messenger_sync_keycard_change_test.go +++ b/protocol/messenger_sync_keycard_change_test.go @@ -11,6 +11,7 @@ import ( gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" "github.com/status-im/status-go/eth-node/crypto" "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/multiaccounts/accounts" "github.com/status-im/status-go/protocol/encryption/multidevice" "github.com/status-im/status-go/protocol/tt" "github.com/status-im/status-go/waku" @@ -73,6 +74,31 @@ func (s *MessengerSyncKeycardChangeSuite) SetupTest() { err = s.main.EnableInstallation(s.other.installationID) s.Require().NoError(err) + + // Pre-condition - both sides have to know about keypairs migrated to a keycards + kp1 := accounts.GetProfileKeypairForTest(false) + kp2 := accounts.GetSeedImportedKeypair1ForTest() + // kp3 := accounts.GetSeedImportedKeypair2ForTest() + + err = s.main.settings.SaveOrUpdateKeypair(kp1) + s.Require().NoError(err) + err = s.main.settings.SaveOrUpdateKeypair(kp2) + s.Require().NoError(err) + // err = s.main.settings.SaveOrUpdateKeypair(kp3) + // s.Require().NoError(err) + dbKeypairs, err := s.main.settings.GetKeypairs() + s.Require().NoError(err) + s.Require().Equal(2, len(dbKeypairs)) + + err = s.other.SaveOrUpdateKeypair(kp1) + s.Require().NoError(err) + err = s.other.SaveOrUpdateKeypair(kp2) + s.Require().NoError(err) + // err = s.other.SaveOrUpdateKeypair(kp3) + // s.Require().NoError(err) + dbKeypairs, err = s.other.settings.GetKeypairs() + s.Require().NoError(err) + s.Require().Equal(2, len(dbKeypairs)) } func (s *MessengerSyncKeycardChangeSuite) TearDownTest() { @@ -94,57 +120,66 @@ func (s *MessengerSyncKeycardChangeSuite) TestAddingNewKeycards() { dbOnReceiver := s.other.settings // Add key cards on sender - allKeycardsToSync := getKeycardsForTest()[:2] - for _, kp := range allKeycardsToSync { - added, err := s.main.AddKeycardOrAddAccountsIfKeycardIsAdded(context.Background(), kp) - s.Require().NoError(err) - s.Require().Equal(true, added) - } + keycard1 := accounts.GetProfileKeycardForTest() + + keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest() + + added, err := s.main.AddKeycardOrAddAccountsIfKeycardIsAdded(context.Background(), keycard1) + s.Require().NoError(err) + s.Require().Equal(true, added) + + added, err = s.main.AddKeycardOrAddAccountsIfKeycardIsAdded(context.Background(), keycard2) + s.Require().NoError(err) + s.Require().Equal(true, added) // Wait for the response - _, err := WaitOnMessengerResponse( + _, err = WaitOnMessengerResponse( s.other, func(r *MessengerResponse) bool { - return len(r.KeycardActions()) == len(allKeycardsToSync) + return len(r.KeycardActions()) == 2 }, "expected to receive keycard activities", ) s.Require().NoError(err) + senderKeycards, err := s.main.settings.GetAllKnownKeycards() + s.Require().NoError(err) + s.Require().Equal(2, len(senderKeycards)) + s.Require().True(contains(senderKeycards, keycard1, accounts.SameKeycards)) + s.Require().True(contains(senderKeycards, keycard2, accounts.SameKeycards)) + syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) - s.Require().Equal(len(allKeycardsToSync), len(syncedKeycards)) - s.Require().True(haveSameElements(syncedKeycards, allKeycardsToSync, sameKeycards)) + s.Require().Equal(2, len(syncedKeycards)) + s.Require().True(contains(syncedKeycards, keycard1, accounts.SameKeycards)) + s.Require().True(contains(syncedKeycards, keycard2, accounts.SameKeycards)) } func (s *MessengerSyncKeycardChangeSuite) TestAddingAccountsToKeycard() { senderDb := s.main.settings dbOnReceiver := s.other.settings + keycard1 := accounts.GetProfileKeycardForTest() + + keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest() + // Add keycard on sender - keycardToSync := getKeycardsForTest()[:1][0] - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) // Add the same keycard on receiver - addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) // Add additional accounts to sender - updatedKeycard := getKeycardsForTest()[:1][0] - updatedKeycard.AccountsAddresses = []types.Address{{0x011}, {0x022}, {0x033}, {0x044}} - - added, err := s.main.AddKeycardOrAddAccountsIfKeycardIsAdded(context.Background(), updatedKeycard) + added, err := s.main.AddKeycardOrAddAccountsIfKeycardIsAdded(context.Background(), keycard2) s.Require().NoError(err) s.Require().Equal(true, added) - // Add accounts that we can check for results later - updatedKeycard.AccountsAddresses = append(updatedKeycard.AccountsAddresses, keycardToSync.AccountsAddresses...) - // Wait for the response _, err = WaitOnMessengerResponse( s.other, @@ -155,35 +190,44 @@ func (s *MessengerSyncKeycardChangeSuite) TestAddingAccountsToKeycard() { ) s.Require().NoError(err) + senderKeycards, err := senderDb.GetAllKnownKeycards() + s.Require().NoError(err) + s.Require().Equal(2, len(senderKeycards)) + s.Require().True(contains(senderKeycards, keycard1, accounts.SameKeycards)) + s.Require().True(contains(senderKeycards, keycard2, accounts.SameKeycards)) + syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) - s.Require().Equal(1, len(syncedKeycards)) - s.Require().True(sameKeycards(syncedKeycards[0], updatedKeycard)) + s.Require().Equal(2, len(syncedKeycards)) + s.Require().True(contains(syncedKeycards, keycard1, accounts.SameKeycards)) + s.Require().True(contains(syncedKeycards, keycard2, accounts.SameKeycards)) } func (s *MessengerSyncKeycardChangeSuite) TestRemovingAccountsFromKeycard() { senderDb := s.main.settings dbOnReceiver := s.other.settings + keycard1 := accounts.GetProfileKeycardForTest() + // Add keycard on sender - keycardToSync := getKeycardsForTest()[:1][0] - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) // Add the same keycard on receiver - addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) - // Remove accounts from sender - updatedKeycard := getKeycardsForTest()[:1][0] - updatedKeycard.AccountsAddresses = updatedKeycard.AccountsAddresses[2:] + // Prepare expected keycard for comparison + updatedKeycard1 := accounts.GetProfileKeycardForTest() + updatedKeycard1.AccountsAddresses = updatedKeycard1.AccountsAddresses[2:] - err = s.main.RemoveMigratedAccountsForKeycard(context.Background(), keycardToSync.KeycardUID, - keycardToSync.AccountsAddresses[:2], keycardToSync.LastUpdateClock) + // Remove accounts from sender + err = s.main.RemoveMigratedAccountsForKeycard(context.Background(), keycard1.KeycardUID, + keycard1.AccountsAddresses[:2], updatedKeycard1.LastUpdateClock) s.Require().NoError(err) // Wait for the response @@ -196,32 +240,38 @@ func (s *MessengerSyncKeycardChangeSuite) TestRemovingAccountsFromKeycard() { ) s.Require().NoError(err) + senderKeycards, err := senderDb.GetAllKnownKeycards() + s.Require().NoError(err) + s.Require().Equal(1, len(senderKeycards)) + s.Require().True(contains(senderKeycards, updatedKeycard1, accounts.SameKeycards)) + syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) s.Require().Equal(1, len(syncedKeycards)) - s.Require().True(sameKeycards(updatedKeycard, syncedKeycards[0])) + s.Require().True(contains(syncedKeycards, updatedKeycard1, accounts.SameKeycards)) } func (s *MessengerSyncKeycardChangeSuite) TestRemovingAllAccountsFromKeycard() { senderDb := s.main.settings dbOnReceiver := s.other.settings + keycard1 := accounts.GetProfileKeycardForTest() + // Add keycard on sender - keycardToSync := getKeycardsForTest()[:1][0] - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) // Add the same keycard on receiver - addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) // Remove all accounts from sender - err = s.main.RemoveMigratedAccountsForKeycard(context.Background(), keycardToSync.KeycardUID, - keycardToSync.AccountsAddresses, keycardToSync.LastUpdateClock) + err = s.main.RemoveMigratedAccountsForKeycard(context.Background(), keycard1.KeycardUID, + keycard1.AccountsAddresses, keycard1.LastUpdateClock) s.Require().NoError(err) // Wait for the response @@ -234,6 +284,10 @@ func (s *MessengerSyncKeycardChangeSuite) TestRemovingAllAccountsFromKeycard() { ) s.Require().NoError(err) + senderKeycards, err := senderDb.GetAllKnownKeycards() + s.Require().NoError(err) + s.Require().Equal(0, len(senderKeycards)) + syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) s.Require().Equal(0, len(syncedKeycards)) @@ -243,21 +297,22 @@ func (s *MessengerSyncKeycardChangeSuite) TestDeleteKeycard() { senderDb := s.main.settings dbOnReceiver := s.other.settings + keycard1 := accounts.GetProfileKeycardForTest() + // Add keycard on sender - keycardToSync := getKeycardsForTest()[:1][0] - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) // Add the same keycard on receiver - addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) // Remove keycard from sender - err = s.main.DeleteKeycard(context.Background(), keycardToSync.KeycardUID, keycardToSync.LastUpdateClock) + err = s.main.DeleteKeycard(context.Background(), keycard1.KeycardUID, keycard1.LastUpdateClock) s.Require().NoError(err) // Wait for the response @@ -270,6 +325,10 @@ func (s *MessengerSyncKeycardChangeSuite) TestDeleteKeycard() { ) s.Require().NoError(err) + senderKeycards, err := senderDb.GetAllKnownKeycards() + s.Require().NoError(err) + s.Require().Equal(0, len(senderKeycards)) + syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) s.Require().Equal(0, len(syncedKeycards)) @@ -279,26 +338,27 @@ func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardName() { senderDb := s.main.settings dbOnReceiver := s.other.settings + keycard1 := accounts.GetProfileKeycardForTest() + // Add keycard on sender - keycardToSync := getKeycardsForTest()[:1][0] - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) // Add the same keycard on receiver - addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) - // Set new keycard name to sender - updatedKeycard := getKeycardsForTest()[:1][0] - updatedKeycard.KeycardName = "New Keycard Name" - updatedKeycard.LastUpdateClock = updatedKeycard.LastUpdateClock + 1 + // Prepare expected keycard for comparison + updatedKeycard1 := accounts.GetProfileKeycardForTest() + updatedKeycard1.KeycardName = "New Keycard Name" - err = s.main.SetKeycardName(context.Background(), updatedKeycard.KeycardUID, updatedKeycard.KeycardName, - updatedKeycard.LastUpdateClock) + // Set new keycard name to sender + err = s.main.SetKeycardName(context.Background(), updatedKeycard1.KeycardUID, updatedKeycard1.KeycardName, + updatedKeycard1.LastUpdateClock) s.Require().NoError(err) // Wait for the response @@ -311,36 +371,43 @@ func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardName() { ) s.Require().NoError(err) + senderKeycards, err := senderDb.GetAllKnownKeycards() + s.Require().NoError(err) + s.Require().Equal(1, len(senderKeycards)) + s.Require().True(accounts.SameKeycards(updatedKeycard1, senderKeycards[0])) + syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) s.Require().Equal(1, len(syncedKeycards)) - s.Require().True(sameKeycards(updatedKeycard, syncedKeycards[0])) + s.Require().True(accounts.SameKeycards(updatedKeycard1, syncedKeycards[0])) } func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardNameWithOlderClock() { senderDb := s.main.settings dbOnReceiver := s.other.settings + keycard1 := accounts.GetProfileKeycardForTest() + // Add keycard on sender - keycardToSync := getKeycardsForTest()[:1][0] - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) // Add the same keycard on receiver - addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) - // Set new keycard name to sender - updatedKeycard := getKeycardsForTest()[:1][0] - updatedKeycard.KeycardName = "New Keycard Name" - updatedKeycard.LastUpdateClock = updatedKeycard.LastUpdateClock - 1 + // Prepare expected keycard for comparison + updatedKeycard1 := accounts.GetProfileKeycardForTest() + updatedKeycard1.KeycardName = "New Keycard Name" + updatedKeycard1.LastUpdateClock = updatedKeycard1.LastUpdateClock - 1 - err = s.main.SetKeycardName(context.Background(), updatedKeycard.KeycardUID, updatedKeycard.KeycardName, - updatedKeycard.LastUpdateClock) + // Set new keycard name to sender + err = s.main.SetKeycardName(context.Background(), updatedKeycard1.KeycardUID, updatedKeycard1.KeycardName, + updatedKeycard1.LastUpdateClock) s.Require().NoError(err) // Wait for the response @@ -353,35 +420,40 @@ func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardNameWithOlderClock() ) s.Require().NoError(err) + senderKeycards, err := senderDb.GetAllKnownKeycards() + s.Require().NoError(err) + s.Require().Equal(1, len(senderKeycards)) + s.Require().True(accounts.SameKeycards(keycard1, senderKeycards[0])) + syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) s.Require().Equal(1, len(syncedKeycards)) - s.Require().True(sameKeycards(keycardToSync, syncedKeycards[0])) + s.Require().True(accounts.SameKeycards(keycard1, syncedKeycards[0])) } func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardLocked() { senderDb := s.main.settings dbOnReceiver := s.other.settings + keycard1 := accounts.GetProfileKeycardForTest() + // Add keycard on sender - keycardToSync := getKeycardsForTest()[:1][0] - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) // Add the same keycard on receiver - addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) - // Set keycard locked on sender - updatedKeycard := getKeycardsForTest()[:1][0] - updatedKeycard.KeycardLocked = true - updatedKeycard.LastUpdateClock = updatedKeycard.LastUpdateClock + 1 + // Prepare expected keycard for comparison + updatedKeycard1 := accounts.GetProfileKeycardForTest() + updatedKeycard1.KeycardLocked = true - err = s.main.KeycardLocked(context.Background(), updatedKeycard.KeycardUID, updatedKeycard.LastUpdateClock) + err = s.main.KeycardLocked(context.Background(), updatedKeycard1.KeycardUID, updatedKeycard1.LastUpdateClock) s.Require().NoError(err) // Wait for the response @@ -394,35 +466,41 @@ func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardLocked() { ) s.Require().NoError(err) + senderKeycards, err := senderDb.GetAllKnownKeycards() + s.Require().NoError(err) + s.Require().Equal(1, len(senderKeycards)) + s.Require().True(accounts.SameKeycards(updatedKeycard1, senderKeycards[0])) + syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) s.Require().Equal(1, len(syncedKeycards)) - s.Require().True(sameKeycards(updatedKeycard, syncedKeycards[0])) + s.Require().True(accounts.SameKeycards(updatedKeycard1, syncedKeycards[0])) } func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardLockedOlderClock() { senderDb := s.main.settings dbOnReceiver := s.other.settings + keycard1 := accounts.GetProfileKeycardForTest() + // Add keycard on sender - keycardToSync := getKeycardsForTest()[:1][0] - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) // Add the same keycard on receiver - addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) - // Set keycard locked on sender - updatedKeycard := getKeycardsForTest()[:1][0] - updatedKeycard.KeycardLocked = true - updatedKeycard.LastUpdateClock = updatedKeycard.LastUpdateClock - 1 + // Prepare expected keycard for comparison + updatedKeycard1 := accounts.GetProfileKeycardForTest() + updatedKeycard1.KeycardLocked = true + updatedKeycard1.LastUpdateClock = updatedKeycard1.LastUpdateClock - 1 - err = s.main.KeycardLocked(context.Background(), updatedKeycard.KeycardUID, updatedKeycard.LastUpdateClock) + err = s.main.KeycardLocked(context.Background(), updatedKeycard1.KeycardUID, updatedKeycard1.LastUpdateClock) s.Require().NoError(err) // Wait for the response @@ -435,36 +513,41 @@ func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardLockedOlderClock() { ) s.Require().NoError(err) + senderKeycards, err := senderDb.GetAllKnownKeycards() + s.Require().NoError(err) + s.Require().Equal(1, len(senderKeycards)) + s.Require().True(accounts.SameKeycards(keycard1, senderKeycards[0])) + syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) s.Require().Equal(1, len(syncedKeycards)) - s.Require().True(sameKeycards(keycardToSync, syncedKeycards[0])) + s.Require().True(accounts.SameKeycards(keycard1, syncedKeycards[0])) } func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardUnlocked() { senderDb := s.main.settings dbOnReceiver := s.other.settings + keycard1 := accounts.GetProfileKeycardForTest() + keycard1.KeycardLocked = true + // Add keycard on sender - keycardToSync := getKeycardsForTest()[:1][0] - keycardToSync.KeycardLocked = true - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) // Add the same keycard on receiver - addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) - // Set keycard unlocked on sender - updatedKeycard := getKeycardsForTest()[:1][0] - updatedKeycard.KeycardLocked = false - updatedKeycard.LastUpdateClock = updatedKeycard.LastUpdateClock + 1 + // Prepare expected keycard for comparison + updatedKeycard1 := accounts.GetProfileKeycardForTest() + updatedKeycard1.KeycardLocked = false - err = s.main.KeycardUnlocked(context.Background(), updatedKeycard.KeycardUID, updatedKeycard.LastUpdateClock) + err = s.main.KeycardUnlocked(context.Background(), updatedKeycard1.KeycardUID, updatedKeycard1.LastUpdateClock) s.Require().NoError(err) // Wait for the response @@ -477,36 +560,42 @@ func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardUnlocked() { ) s.Require().NoError(err) + senderKeycards, err := senderDb.GetAllKnownKeycards() + s.Require().NoError(err) + s.Require().Equal(1, len(senderKeycards)) + s.Require().True(accounts.SameKeycards(updatedKeycard1, senderKeycards[0])) + syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) s.Require().Equal(1, len(syncedKeycards)) - s.Require().True(sameKeycards(updatedKeycard, syncedKeycards[0])) + s.Require().True(accounts.SameKeycards(updatedKeycard1, syncedKeycards[0])) } func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardUnlockedOlderClock() { senderDb := s.main.settings dbOnReceiver := s.other.settings + keycard1 := accounts.GetProfileKeycardForTest() + keycard1.KeycardLocked = true + // Add keycard on sender - keycardToSync := getKeycardsForTest()[:1][0] - keycardToSync.KeycardLocked = true - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) // Add the same keycard on receiver - addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) - // Set keycard unlocked on sender - updatedKeycard := getKeycardsForTest()[:1][0] - updatedKeycard.KeycardLocked = false - updatedKeycard.LastUpdateClock = updatedKeycard.LastUpdateClock - 1 + // Prepare expected keycard for comparison + updatedKeycard1 := accounts.GetProfileKeycardForTest() + updatedKeycard1.KeycardLocked = false + updatedKeycard1.LastUpdateClock = updatedKeycard1.LastUpdateClock - 1 - err = s.main.KeycardLocked(context.Background(), updatedKeycard.KeycardUID, updatedKeycard.LastUpdateClock) + err = s.main.KeycardUnlocked(context.Background(), updatedKeycard1.KeycardUID, updatedKeycard1.LastUpdateClock) s.Require().NoError(err) // Wait for the response @@ -519,36 +608,42 @@ func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardUnlockedOlderClock() ) s.Require().NoError(err) + senderKeycards, err := senderDb.GetAllKnownKeycards() + s.Require().NoError(err) + s.Require().Equal(1, len(senderKeycards)) + s.Require().True(accounts.SameKeycards(keycard1, senderKeycards[0])) + syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) s.Require().Equal(1, len(syncedKeycards)) - s.Require().True(sameKeycards(keycardToSync, syncedKeycards[0])) + s.Require().True(accounts.SameKeycards(keycard1, syncedKeycards[0])) } func (s *MessengerSyncKeycardChangeSuite) TestUpdatingKeycardUid() { senderDb := s.main.settings dbOnReceiver := s.other.settings + keycard1 := accounts.GetProfileKeycardForTest() + // Add keycard on sender - keycardToSync := getKeycardsForTest()[:1][0] - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) // Add the same keycard on receiver - addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) - // Set keycard unlocked on sender - updatedKeycard := getKeycardsForTest()[:1][0] - updatedKeycard.KeycardUID = "00000000000000000000000000000000" - updatedKeycard.LastUpdateClock = updatedKeycard.LastUpdateClock + 1 + // Prepare expected keycard for comparison + updatedKeycard1 := accounts.GetProfileKeycardForTest() + updatedKeycard1.KeycardUID = "00000000000000000000000000000000" - err = s.main.UpdateKeycardUID(context.Background(), keycardToSync.KeycardUID, updatedKeycard.KeycardUID, - updatedKeycard.LastUpdateClock) + // Update keycard uid on sender + err = s.main.UpdateKeycardUID(context.Background(), keycard1.KeycardUID, updatedKeycard1.KeycardUID, + updatedKeycard1.LastUpdateClock) s.Require().NoError(err) // Wait for the response @@ -561,36 +656,43 @@ func (s *MessengerSyncKeycardChangeSuite) TestUpdatingKeycardUid() { ) s.Require().NoError(err) + senderKeycards, err := senderDb.GetAllKnownKeycards() + s.Require().NoError(err) + s.Require().Equal(1, len(senderKeycards)) + s.Require().True(accounts.SameKeycards(updatedKeycard1, senderKeycards[0])) + syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) s.Require().Equal(1, len(syncedKeycards)) - s.Require().True(sameKeycards(updatedKeycard, syncedKeycards[0])) + s.Require().True(accounts.SameKeycards(updatedKeycard1, syncedKeycards[0])) } func (s *MessengerSyncKeycardChangeSuite) TestUpdatingKeycardUidOldClock() { senderDb := s.main.settings dbOnReceiver := s.other.settings + keycard1 := accounts.GetProfileKeycardForTest() + // Add keycard on sender - keycardToSync := getKeycardsForTest()[:1][0] - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) // Add the same keycard on receiver - addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardToSync) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) s.Require().NoError(err) s.Require().Equal(true, addedKc) s.Require().Equal(false, addedAccs) - // Set keycard unlocked on sender - updatedKeycard := getKeycardsForTest()[:1][0] - updatedKeycard.KeycardUID = "00000000000000000000000000000000" - updatedKeycard.LastUpdateClock = updatedKeycard.LastUpdateClock - 1 + // Prepare expected keycard for comparison + updatedKeycard1 := accounts.GetProfileKeycardForTest() + updatedKeycard1.KeycardUID = "00000000000000000000000000000000" + updatedKeycard1.LastUpdateClock = updatedKeycard1.LastUpdateClock - 1 - err = s.main.UpdateKeycardUID(context.Background(), keycardToSync.KeycardUID, updatedKeycard.KeycardUID, - updatedKeycard.LastUpdateClock) + // Update keycard uid on sender + err = s.main.UpdateKeycardUID(context.Background(), keycard1.KeycardUID, updatedKeycard1.KeycardUID, + updatedKeycard1.LastUpdateClock) s.Require().NoError(err) // Wait for the response @@ -603,8 +705,13 @@ func (s *MessengerSyncKeycardChangeSuite) TestUpdatingKeycardUidOldClock() { ) s.Require().NoError(err) + senderKeycards, err := senderDb.GetAllKnownKeycards() + s.Require().NoError(err) + s.Require().Equal(1, len(senderKeycards)) + s.Require().True(accounts.SameKeycards(keycard1, senderKeycards[0])) + syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) s.Require().Equal(1, len(syncedKeycards)) - s.Require().True(sameKeycards(keycardToSync, syncedKeycards[0])) + s.Require().True(accounts.SameKeycards(keycard1, syncedKeycards[0])) } diff --git a/protocol/messenger_sync_keycards_state_test.go b/protocol/messenger_sync_keycards_state_test.go index 84084d9fc..3520dc33a 100644 --- a/protocol/messenger_sync_keycards_state_test.go +++ b/protocol/messenger_sync_keycards_state_test.go @@ -11,7 +11,7 @@ import ( gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" "github.com/status-im/status-go/eth-node/crypto" "github.com/status-im/status-go/eth-node/types" - "github.com/status-im/status-go/multiaccounts/keycards" + "github.com/status-im/status-go/multiaccounts/accounts" "github.com/status-im/status-go/protocol/encryption/multidevice" "github.com/status-im/status-go/protocol/tt" "github.com/status-im/status-go/waku" @@ -74,6 +74,31 @@ func (s *MessengerSyncKeycardsStateSuite) SetupTest() { err = s.main.EnableInstallation(s.other.installationID) s.Require().NoError(err) + + // Pre-condition - both sides have to know about keypairs migrated to a keycards + kp1 := accounts.GetProfileKeypairForTest(false) + kp2 := accounts.GetSeedImportedKeypair1ForTest() + kp3 := accounts.GetSeedImportedKeypair2ForTest() + + err = s.main.settings.SaveOrUpdateKeypair(kp1) + s.Require().NoError(err) + err = s.main.settings.SaveOrUpdateKeypair(kp2) + s.Require().NoError(err) + err = s.main.settings.SaveOrUpdateKeypair(kp3) + s.Require().NoError(err) + dbKeypairs, err := s.main.settings.GetKeypairs() + s.Require().NoError(err) + s.Require().Equal(3, len(dbKeypairs)) + + err = s.other.SaveOrUpdateKeypair(kp1) + s.Require().NoError(err) + err = s.other.SaveOrUpdateKeypair(kp2) + s.Require().NoError(err) + err = s.other.SaveOrUpdateKeypair(kp3) + s.Require().NoError(err) + dbKeypairs, err = s.other.settings.GetKeypairs() + s.Require().NoError(err) + s.Require().Equal(3, len(dbKeypairs)) } func (s *MessengerSyncKeycardsStateSuite) TearDownTest() { @@ -91,92 +116,48 @@ func (s *MessengerSyncKeycardsStateSuite) newMessenger(shh types.Waku) *Messenge return messenger } -func sameKeycards(a, b *keycards.Keycard) bool { - same := a.KeycardUID == b.KeycardUID && - a.KeyUID == b.KeyUID && - a.KeycardName == b.KeycardName && - a.KeycardLocked == b.KeycardLocked && - a.LastUpdateClock == b.LastUpdateClock && - len(a.AccountsAddresses) == len(b.AccountsAddresses) - - if same { - for i := range a.AccountsAddresses { - found := false - for j := range b.AccountsAddresses { - if a.AccountsAddresses[i] == b.AccountsAddresses[j] { - found = true - break - } - } - - if !found { - return false - } - } - } - - return same -} - -func getKeycardsForTest() []*keycards.Keycard { - keycard1 := keycards.Keycard{ - KeycardUID: "00000000000000000000000000000001", - KeycardName: "Card01", - KeycardLocked: false, - AccountsAddresses: []types.Address{{0x01}, {0x02}, {0x03}, {0x04}}, - KeyUID: "0000000000000000000000000000000000000000000000000000000000000001", - LastUpdateClock: 100, - } - keycard2 := keycards.Keycard{ - KeycardUID: "00000000000000000000000000000002", - KeycardName: "Card02", - KeycardLocked: false, - AccountsAddresses: []types.Address{{0x01}, {0x02}}, - KeyUID: "0000000000000000000000000000000000000000000000000000000000000002", - LastUpdateClock: 200, - } - keycard3 := keycards.Keycard{ - KeycardUID: "00000000000000000000000000000003", - KeycardName: "Card02 Copy", - KeycardLocked: false, - AccountsAddresses: []types.Address{{0x01}, {0x02}}, - KeyUID: "0000000000000000000000000000000000000000000000000000000000000002", - LastUpdateClock: 300, - } - keycard4 := keycards.Keycard{ - KeycardUID: "00000000000000000000000000000004", - KeycardName: "Card04", - KeycardLocked: false, - AccountsAddresses: []types.Address{{0x01}, {0x02}, {0x03}}, - KeyUID: "0000000000000000000000000000000000000000000000000000000000000004", - LastUpdateClock: 400, - } - - return []*keycards.Keycard{&keycard1, &keycard2, &keycard3, &keycard4} -} - func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasNoKeycards() { senderDb := s.main.settings dbOnReceiver := s.other.settings + keycard1 := accounts.GetProfileKeycardForTest() + + keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest() + + keycard2Copy := accounts.GetKeycardForSeedImportedKeypair1ForTest() + keycard2Copy.KeycardUID = keycard2Copy.KeycardUID + "C" + keycard2Copy.KeycardName = keycard2Copy.KeycardName + "Copy" + keycard2Copy.LastUpdateClock = keycard2Copy.LastUpdateClock + 1 + + keycard3 := accounts.GetKeycardForSeedImportedKeypair2ForTest() + // Add keycards on sender - allKeycardsToSync := getKeycardsForTest() - for _, kp := range allKeycardsToSync { - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*kp) - s.Require().NoError(err) - s.Require().Equal(true, addedKc) - s.Require().Equal(false, addedAccs) - } + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + addedKc, addedAccs, err = senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + addedKc, addedAccs, err = senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2Copy) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + addedKc, addedAccs, err = senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard3) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) // Trigger's a sync between devices - err := s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil) + err = s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil) s.Require().NoError(err) // Wait for the response _, err = WaitOnMessengerResponse( s.other, func(r *MessengerResponse) bool { - return len(r.AllKnownKeycards()) == len(allKeycardsToSync) + return len(r.Keypairs) == 3 && len(r.Keycards) == 4 }, "expected to receive keycards", ) @@ -184,47 +165,59 @@ func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasNoKeycard syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) - s.Require().Equal(len(allKeycardsToSync), len(syncedKeycards)) - s.Require().True(haveSameElements(syncedKeycards, allKeycardsToSync, sameKeycards)) + s.Require().Equal(4, len(syncedKeycards)) + s.Require().True(contains(syncedKeycards, keycard1, accounts.SameKeycards)) + s.Require().True(contains(syncedKeycards, keycard2, accounts.SameKeycards)) + s.Require().True(contains(syncedKeycards, keycard2Copy, accounts.SameKeycards)) + s.Require().True(contains(syncedKeycards, keycard3, accounts.SameKeycards)) } func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasKeycardsOlderThanSender() { senderDb := s.main.settings dbOnReceiver := s.other.settings + keycard1 := accounts.GetProfileKeycardForTest() + + keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest() + // Add keycards on sender - allKeycardsToSync := getKeycardsForTest() - for _, kp := range allKeycardsToSync { - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*kp) - s.Require().NoError(err) - s.Require().Equal(true, addedKc) - s.Require().Equal(false, addedAccs) - } + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + addedKc, addedAccs, err = senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) - // Add keycards on receiver - keycardsOnReceiver := getKeycardsForTest()[:2] - keycardsOnReceiver[0].KeycardName = "CardNameToBeChanged-0" - keycardsOnReceiver[0].AccountsAddresses = keycardsOnReceiver[0].AccountsAddresses[2:3] - keycardsOnReceiver[0].LastUpdateClock = keycardsOnReceiver[0].LastUpdateClock - 1 - keycardsOnReceiver[1].KeycardName = "CardNameToBeChanged-1" - keycardsOnReceiver[1].LastUpdateClock = keycardsOnReceiver[1].LastUpdateClock - 1 + // Add keycards on receiver - partially + keycardR1 := accounts.GetProfileKeycardForTest() + keycardR1.KeycardName = "CardNameToBeChanged-0" + keycardR1.AccountsAddresses = keycardR1.AccountsAddresses[2:3] + keycardR1.LastUpdateClock = keycardR1.LastUpdateClock - 1 - for _, kp := range keycardsOnReceiver { - addedKc, addedAccs, err := dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*kp) - s.Require().NoError(err) - s.Require().Equal(true, addedKc) - s.Require().Equal(false, addedAccs) - } + keycardR2 := accounts.GetKeycardForSeedImportedKeypair1ForTest() + keycardR2.KeycardName = "CardNameToBeChanged-1" + keycardR2.LastUpdateClock = keycardR2.LastUpdateClock - 1 + + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardR1) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardR2) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) // Trigger's a sync between devices - err := s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil) + err = s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil) s.Require().NoError(err) // Wait for the response _, err = WaitOnMessengerResponse( s.other, func(r *MessengerResponse) bool { - return len(r.AllKnownKeycards()) == len(allKeycardsToSync) + return len(r.Keypairs) == 3 && len(r.Keycards) == 2 }, "expected to receive keycards", ) @@ -232,8 +225,67 @@ func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasKeycardsO syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) - s.Require().Equal(len(allKeycardsToSync), len(syncedKeycards)) - s.Require().True(haveSameElements(syncedKeycards, allKeycardsToSync, sameKeycards)) + s.Require().Equal(2, len(syncedKeycards)) + s.Require().True(contains(syncedKeycards, keycard1, accounts.SameKeycards)) + s.Require().True(contains(syncedKeycards, keycard2, accounts.SameKeycards)) +} + +func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasKeycardsNewerThanSender() { + senderDb := s.main.settings + dbOnReceiver := s.other.settings + + keycard1 := accounts.GetProfileKeycardForTest() + + keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest() + + // Add keycards on sender + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + addedKc, addedAccs, err = senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + + // Add keycards on receiver - partially + keycardR1 := accounts.GetProfileKeycardForTest() + keycardR1.KeycardName = "CardNameToBeChanged-0" + keycardR1.AccountsAddresses = keycardR1.AccountsAddresses[2:3] + keycardR1.LastUpdateClock = keycardR1.LastUpdateClock + 1 + + keycardR2 := accounts.GetKeycardForSeedImportedKeypair1ForTest() + keycardR2.KeycardName = "CardNameToBeChanged-1" + keycardR2.LastUpdateClock = keycardR2.LastUpdateClock + 1 + + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardR1) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardR2) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + + // Trigger's a sync between devices + err = s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil) + s.Require().NoError(err) + + // Wait for the response + _, err = WaitOnMessengerResponse( + s.other, + func(r *MessengerResponse) bool { + return len(r.Keypairs) == 3 && len(r.Keycards) == 2 + }, + "expected to receive keycards", + ) + s.Require().NoError(err) + + syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() + s.Require().NoError(err) + s.Require().Equal(2, len(syncedKeycards)) + s.Require().True(contains(syncedKeycards, keycardR1, accounts.SameKeycards)) + s.Require().True(contains(syncedKeycards, keycardR2, accounts.SameKeycards)) } func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfKeycardsWereDeletedOnSenderSide() { @@ -241,79 +293,54 @@ func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfKeycardsWereDeletedO dbOnReceiver := s.other.settings // Add keycards on sender - allKeycardsToSync := getKeycardsForTest()[:2] - for _, kp := range allKeycardsToSync { - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*kp) - s.Require().NoError(err) - s.Require().Equal(true, addedKc) - s.Require().Equal(false, addedAccs) - } + keycard1 := accounts.GetProfileKeycardForTest() - // Add keycards on receiver - keycardsOnReceiver := getKeycardsForTest() - for _, kp := range keycardsOnReceiver { - addedKc, addedAccs, err := dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*kp) - s.Require().NoError(err) - s.Require().Equal(true, addedKc) - s.Require().Equal(false, addedAccs) - } + keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest() - // Trigger's a sync between devices - err := s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil) - s.Require().NoError(err) + keycard2Copy := accounts.GetKeycardForSeedImportedKeypair1ForTest() + keycard2Copy.KeycardUID = keycard2Copy.KeycardUID + "C" + keycard2Copy.KeycardName = keycard2Copy.KeycardName + "Copy" + keycard2Copy.LastUpdateClock = keycard2Copy.LastUpdateClock + 1 - // Wait for the response - _, err = WaitOnMessengerResponse( - s.other, - func(r *MessengerResponse) bool { - return len(r.AllKnownKeycards()) == len(allKeycardsToSync) - }, - "expected to receive keycards", - ) - s.Require().NoError(err) - - syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() - s.Require().NoError(err) - s.Require().Equal(len(allKeycardsToSync), len(syncedKeycards)) - s.Require().True(haveSameElements(syncedKeycards, allKeycardsToSync, sameKeycards)) -} - -func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasNewerKeycardsThanTheSameAreDeletedOnSenderSide() { - senderDb := s.main.settings - dbOnReceiver := s.other.settings + keycard3 := accounts.GetKeycardForSeedImportedKeypair2ForTest() // Add keycards on sender - allKeycardsToSync := getKeycardsForTest()[:2] - for _, kp := range allKeycardsToSync { - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*kp) - s.Require().NoError(err) - s.Require().Equal(true, addedKc) - s.Require().Equal(false, addedAccs) - } + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + addedKc, addedAccs, err = senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) // Add keycards on receiver - keycardsOnReceiver := getKeycardsForTest() - clock, _ := s.other.getLastClockWithRelatedChat() - keycardsOnReceiver[2].KeycardName = "NewerCardName-2" - keycardsOnReceiver[2].LastUpdateClock = clock + 1000 - keycardsOnReceiver[3].KeycardName = "NewerCardName-3" - keycardsOnReceiver[3].LastUpdateClock = clock + 1000 - for _, kp := range keycardsOnReceiver { - addedKc, addedAccs, err := dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*kp) - s.Require().NoError(err) - s.Require().Equal(true, addedKc) - s.Require().Equal(false, addedAccs) - } + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2Copy) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard3) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) // Trigger's a sync between devices - err := s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil) + err = s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil) s.Require().NoError(err) // Wait for the response _, err = WaitOnMessengerResponse( s.other, func(r *MessengerResponse) bool { - return len(r.AllKnownKeycards()) >= len(allKeycardsToSync) + return len(r.Keypairs) == 3 && len(r.Keycards) == 2 }, "expected to receive keycards", ) @@ -321,13 +348,9 @@ func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasNewerKeyc syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) - s.Require().Equal(len(keycardsOnReceiver), len(syncedKeycards)) - for _, kc := range allKeycardsToSync { - s.Require().True(contains(syncedKeycards, kc, sameKeycards)) - } - for _, kc := range keycardsOnReceiver { - s.Require().True(contains(syncedKeycards, kc, sameKeycards)) - } + s.Require().Equal(2, len(syncedKeycards)) + s.Require().True(contains(syncedKeycards, keycard1, accounts.SameKeycards)) + s.Require().True(contains(syncedKeycards, keycard2, accounts.SameKeycards)) } func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverAndSenderHasNoKeycardsInCommon() { @@ -335,91 +358,46 @@ func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverAndSenderHas dbOnReceiver := s.other.settings // Add keycards on sender - allKeycardsToSync := getKeycardsForTest()[:2] - for _, kp := range allKeycardsToSync { - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*kp) - s.Require().NoError(err) - s.Require().Equal(true, addedKc) - s.Require().Equal(false, addedAccs) - } + keycard1 := accounts.GetProfileKeycardForTest() - // Add keycards on receiver - keycardsOnReceiver := getKeycardsForTest()[2:] - clock, _ := s.other.getLastClockWithRelatedChat() - keycardsOnReceiver[0].KeycardName = "NewerCardName-0" - keycardsOnReceiver[0].LastUpdateClock = clock + 1000 - keycardsOnReceiver[1].KeycardName = "NewerCardName-1" - keycardsOnReceiver[1].LastUpdateClock = clock + 1000 + keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest() - for _, kp := range keycardsOnReceiver { - addedKc, addedAccs, err := dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*kp) - s.Require().NoError(err) - s.Require().Equal(true, addedKc) - s.Require().Equal(false, addedAccs) - } + keycard2Copy := accounts.GetKeycardForSeedImportedKeypair1ForTest() + keycard2Copy.KeycardUID = keycard2Copy.KeycardUID + "C" + keycard2Copy.KeycardName = keycard2Copy.KeycardName + "Copy" + keycard2Copy.LastUpdateClock = keycard2Copy.LastUpdateClock + 1 - // Trigger's a sync between devices - err := s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil) - s.Require().NoError(err) - - // Wait for the response - _, err = WaitOnMessengerResponse( - s.other, - func(r *MessengerResponse) bool { - return len(r.AllKnownKeycards()) >= len(allKeycardsToSync) - }, - "expected to receive keycards", - ) - s.Require().NoError(err) - - syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() - s.Require().NoError(err) - s.Require().Equal(len(allKeycardsToSync)+len(keycardsOnReceiver), len(syncedKeycards)) - for _, kc := range allKeycardsToSync { - s.Require().True(contains(syncedKeycards, kc, sameKeycards)) - } - for _, kc := range keycardsOnReceiver { - s.Require().True(contains(syncedKeycards, kc, sameKeycards)) - } -} - -func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasNewerKeycardThanSender() { - senderDb := s.main.settings - dbOnReceiver := s.other.settings + keycard3 := accounts.GetKeycardForSeedImportedKeypair2ForTest() // Add keycards on sender - allKeycardsToSync := getKeycardsForTest() - for _, kp := range allKeycardsToSync { - addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*kp) - s.Require().NoError(err) - s.Require().Equal(true, addedKc) - s.Require().Equal(false, addedAccs) - } + addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + addedKc, addedAccs, err = senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2Copy) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) // Add keycards on receiver - keycardsOnReceiver := getKeycardsForTest()[2:] - clock, _ := s.other.getLastClockWithRelatedChat() - keycardsOnReceiver[0].KeycardName = "NewerCardName-0" - keycardsOnReceiver[0].LastUpdateClock = clock + 1000 - keycardsOnReceiver[1].KeycardName = "NewerCardName-1" - keycardsOnReceiver[1].LastUpdateClock = clock + 1000 - - for _, kp := range keycardsOnReceiver { - addedKc, addedAccs, err := dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*kp) - s.Require().NoError(err) - s.Require().Equal(true, addedKc) - s.Require().Equal(false, addedAccs) - } + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) + addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard3) + s.Require().NoError(err) + s.Require().Equal(true, addedKc) + s.Require().Equal(false, addedAccs) // Trigger's a sync between devices - err := s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil) + err = s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil) s.Require().NoError(err) // Wait for the response _, err = WaitOnMessengerResponse( s.other, func(r *MessengerResponse) bool { - return len(r.AllKnownKeycards()) == len(allKeycardsToSync) + return len(r.Keypairs) == 3 && len(r.Keycards) == 2 }, "expected to receive keycards", ) @@ -427,11 +405,7 @@ func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasNewerKeyc syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards() s.Require().NoError(err) - s.Require().Equal(len(allKeycardsToSync), len(syncedKeycards)) - for _, kc := range allKeycardsToSync[:2] { - s.Require().True(contains(syncedKeycards, kc, sameKeycards)) - } - for _, kc := range keycardsOnReceiver { - s.Require().True(contains(syncedKeycards, kc, sameKeycards)) - } + s.Require().Equal(2, len(syncedKeycards)) + s.Require().True(contains(syncedKeycards, keycard2, accounts.SameKeycards)) + s.Require().True(contains(syncedKeycards, keycard2Copy, accounts.SameKeycards)) } diff --git a/protocol/messenger_sync_wallets_test.go b/protocol/messenger_sync_wallets_test.go index 9ca198095..3a689eeb4 100644 --- a/protocol/messenger_sync_wallets_test.go +++ b/protocol/messenger_sync_wallets_test.go @@ -65,145 +65,31 @@ func (s *MessengerSyncWalletSuite) newMessenger(shh types.Waku) *Messenger { return messenger } -func getWalletAccountsForTest() []*accounts.Account { - defaultAccount := &accounts.Account{ - Address: types.Address{0x11}, - KeyUID: "0000000000000000000000000000000000000000000000000000000000000001", - Wallet: true, - Chat: false, - Path: "m/44'/60'/0'/0/0", - Name: "Default Account", - Color: "blue", - DerivedFrom: "0x0001", - KeypairName: "Profile Keypair", - LastUsedDerivationIndex: 0, - } - generatedFromDefaultAccount1 := &accounts.Account{ - Address: types.Address{0x12}, - Type: accounts.AccountTypeGenerated, - KeyUID: defaultAccount.KeyUID, - Path: "m/44'/60'/0'/0/1", - Name: "Generated Acc 1", - Color: "blue", - DerivedFrom: defaultAccount.DerivedFrom, - KeypairName: defaultAccount.KeypairName, - LastUsedDerivationIndex: 1, - } - generatedFromDefaultAccount2 := &accounts.Account{ - Address: types.Address{0x13}, - Type: accounts.AccountTypeGenerated, - KeyUID: defaultAccount.KeyUID, - Path: "m/44'/60'/0'/0/2", - Name: "Generated Acc 2", - Color: "blue", - DerivedFrom: defaultAccount.DerivedFrom, - KeypairName: defaultAccount.KeypairName, - LastUsedDerivationIndex: 2, - } - seedImportedAccount := &accounts.Account{ - Address: types.Address{0x14}, - Type: accounts.AccountTypeSeed, - KeyUID: "0000000000000000000000000000000000000000000000000000000000000002", - Path: "m/44'/60'/0'/0/0", - Name: "Seed Imported Account", - Color: "green", - DerivedFrom: "0x0002", - KeypairName: "Seed Keypair", - LastUsedDerivationIndex: 0, - } - generatedFromSeedImportedAccount1 := &accounts.Account{ - Address: types.Address{0x15}, - Type: accounts.AccountTypeSeed, - KeyUID: seedImportedAccount.KeyUID, - Path: "m/44'/60'/0'/0/1", - Name: "Generated Seed Account 1", - Color: "green", - DerivedFrom: seedImportedAccount.DerivedFrom, - KeypairName: seedImportedAccount.KeypairName, - LastUsedDerivationIndex: 1, - } - generatedFromSeedImportedAccount2 := &accounts.Account{ - Address: types.Address{0x16}, - Type: accounts.AccountTypeSeed, - KeyUID: seedImportedAccount.KeyUID, - Path: "m/44'/60'/0'/0/2", - Name: "Generated Seed Account 2", - Color: "green", - DerivedFrom: seedImportedAccount.DerivedFrom, - KeypairName: seedImportedAccount.KeypairName, - LastUsedDerivationIndex: 2, - } - keyImportedAccount := &accounts.Account{ - Address: types.Address{0x17}, - Type: accounts.AccountTypeKey, - KeyUID: "0000000000000000000000000000000000000000000000000000000000000003", - Path: "m", - Name: "Key Imported Account", - Color: "blue", - KeypairName: "Private Key Keypair", - } - watchOnlyAccount1 := &accounts.Account{ - Address: types.Address{0x18}, - Type: accounts.AccountTypeWatch, - Name: "Watch Only Account 1", - Color: "green", - } - watchOnlyAccount2 := &accounts.Account{ - Address: types.Address{0x19}, - Type: accounts.AccountTypeWatch, - Name: "Watch Only Account 1", - Color: "green", - } - - return []*accounts.Account{ - defaultAccount, - generatedFromDefaultAccount1, - generatedFromDefaultAccount2, - seedImportedAccount, - generatedFromSeedImportedAccount1, - generatedFromSeedImportedAccount2, - keyImportedAccount, - watchOnlyAccount1, - watchOnlyAccount2, - } -} - func (s *MessengerSyncWalletSuite) TestSyncWallets() { - mainAccount := &accounts.Account{ - Address: types.Address{0x01}, - Wallet: false, - Chat: true, - } + profileKp := accounts.GetProfileKeypairForTest(false) // Create a main account on alice - s.NoError(s.m.settings.SaveAccounts([]*accounts.Account{mainAccount})) + err := s.m.settings.SaveOrUpdateKeypair(profileKp) + s.Require().NoError(err, "profile keypair alice.settings.SaveOrUpdateKeypair") // Check account is present in the db - acc1, err := s.m.settings.GetAccounts() - s.Require().NoError(err, "alice.settings.GetAccounts") - s.Len(acc1, 1, "Must have 1 main account") - - // Check account values match the expected values - s.Require().Equal(mainAccount.Address, acc1[0].Address) - s.Require().Equal(mainAccount.Name, acc1[0].Name) - s.Require().Equal(mainAccount.Color, acc1[0].Color) - s.Require().Equal(mainAccount.Type, acc1[0].Type) + dbProfileKp1, err := s.m.settings.GetKeypairByKeyUID(profileKp.KeyUID) + s.Require().NoError(err) + s.Require().True(accounts.SameKeypairs(profileKp, dbProfileKp1)) // Create new device and add main account to alicesOtherDevice, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, nil) s.Require().NoError(err) - s.NoError(alicesOtherDevice.settings.SaveAccounts([]*accounts.Account{mainAccount}), true) + // Store only chat and default wallet account on other device + profileKpOtherDevice := accounts.GetProfileKeypairForTest(true) + err = alicesOtherDevice.settings.SaveOrUpdateKeypair(profileKpOtherDevice) + s.Require().NoError(err, "profile keypair alicesOtherDevice.settings.SaveOrUpdateKeypair") - acc2, err := alicesOtherDevice.settings.GetAccounts() - s.Require().NoError(err, "alicesOtherDevice.settings.GetAccounts") - s.Len(acc2, 1, "Must have 1 main account") - - // Check account values match the expected values - s.Require().Equal(mainAccount.Address, acc2[0].Address) - s.Require().Equal(mainAccount.Name, acc2[0].Name) - s.Require().Equal(mainAccount.Color, acc2[0].Color) - s.Require().Equal(mainAccount.Type, acc2[0].Type) + // Check account is present in the db + dbProfileKp2, err := alicesOtherDevice.settings.GetKeypairByKeyUID(profileKpOtherDevice.KeyUID) + s.Require().NoError(err) + s.Require().True(accounts.SameKeypairs(profileKpOtherDevice, dbProfileKp2)) // Pair devices im1 := &multidevice.InstallationMetadata{ @@ -235,13 +121,36 @@ func (s *MessengerSyncWalletSuite) TestSyncWallets() { err = s.m.EnableInstallation(alicesOtherDevice.installationID) s.Require().NoError(err) - // Store wallet accounts on alice's device - walletAccounts := getWalletAccountsForTest() - expectedTotalNumOfAccounts := len(walletAccounts) + 1 // plus one for the Status profile account - s.NoError(s.m.settings.SaveAccounts(walletAccounts)) - acc1, err = s.m.settings.GetAccounts() - s.Require().NoError(err, "alice.settings.GetAccounts") - s.Len(acc1, expectedTotalNumOfAccounts, "Must have all wallet accounts plus one for the Status profile account") + // Store seed phrase keypair with accounts on alice's device + seedPhraseKp := accounts.GetSeedImportedKeypair1ForTest() + err = s.m.settings.SaveOrUpdateKeypair(seedPhraseKp) + s.Require().NoError(err, "seed phrase keypair alice.settings.SaveOrUpdateKeypair") + + dbSeedPhraseKp1, err := s.m.settings.GetKeypairByKeyUID(seedPhraseKp.KeyUID) + s.Require().NoError(err) + s.Require().True(accounts.SameKeypairs(seedPhraseKp, dbSeedPhraseKp1)) + + // Store private key keypair with accounts on alice's device + privKeyKp := accounts.GetPrivKeyImportedKeypairForTest() + err = s.m.settings.SaveOrUpdateKeypair(privKeyKp) + s.Require().NoError(err, "private key keypair alice.settings.SaveOrUpdateKeypair") + + dbPrivKeyKp1, err := s.m.settings.GetKeypairByKeyUID(privKeyKp.KeyUID) + s.Require().NoError(err) + s.Require().True(accounts.SameKeypairs(privKeyKp, dbPrivKeyKp1)) + + // Store watch only accounts on alice's device + woAccounts := accounts.GetWatchOnlyAccountsForTest() + err = s.m.settings.SaveOrUpdateAccounts(woAccounts) + s.Require().NoError(err) + dbWoAccounts1, err := s.m.settings.GetWatchOnlyAccounts() + s.Require().NoError(err) + s.Require().Equal(len(woAccounts), len(dbWoAccounts1)) + s.Require().True(haveSameElements(woAccounts, dbWoAccounts1, accounts.SameAccounts)) + + dbAccounts1, err := s.m.settings.GetAccounts() + s.Require().NoError(err) + s.Require().Equal(len(profileKp.Accounts)+len(seedPhraseKp.Accounts)+len(privKeyKp.Accounts)+len(woAccounts), len(dbAccounts1)) // Trigger's a sync between devices err = s.m.SyncDevices(context.Background(), "ens-name", "profile-image", nil) @@ -253,45 +162,43 @@ func (s *MessengerSyncWalletSuite) TestSyncWallets() { return err } - if len(response.Accounts) != len(walletAccounts) { + if len(response.Keypairs) != 3 || // 3 keypairs (profile, seed, priv key) + len(response.Accounts) != len(woAccounts) { return errors.New("no sync wallet account received") } return nil }) s.Require().NoError(err) - acc2, err = alicesOtherDevice.settings.GetAccounts() - s.Require().NoError(err, "alicesOtherDevice.settings.GetAccounts") - s.Len(acc2, expectedTotalNumOfAccounts, "Must have all wallet accounts plus one for the Status profile account") + dbProfileKp2, err = s.m.settings.GetKeypairByKeyUID(profileKp.KeyUID) + s.Require().NoError(err) + s.Require().True(accounts.SameKeypairsWithDifferentSyncedFrom(profileKp, dbProfileKp2, true, "", accounts.AccountFullyOperable)) - for _, syncedAcc := range acc2 { - if syncedAcc.Chat { - continue - } - found := false - for _, sentAcc := range walletAccounts { - if syncedAcc.Address == sentAcc.Address { - // Check account values match the expected values - s.Require().Equal(sentAcc.Address, syncedAcc.Address) - s.Require().Equal(sentAcc.Path, syncedAcc.Path) - s.Require().Equal(sentAcc.KeyUID, syncedAcc.KeyUID) - s.Require().Equal(sentAcc.Name, syncedAcc.Name) - s.Require().Equal(sentAcc.Color, syncedAcc.Color) - s.Require().Equal(sentAcc.Type, syncedAcc.Type) - s.Require().Equal(sentAcc.KeypairName, syncedAcc.KeypairName) - s.Require().Equal(sentAcc.DerivedFrom, syncedAcc.DerivedFrom) - found = true - } - } - s.Require().True(found) - } + dbSeedPhraseKp2, err := alicesOtherDevice.settings.GetKeypairByKeyUID(seedPhraseKp.KeyUID) + s.Require().NoError(err) + s.Require().True(accounts.SameKeypairsWithDifferentSyncedFrom(seedPhraseKp, dbSeedPhraseKp2, true, "", accounts.AccountNonOperable)) - // Updates alice's accounts attributes - for _, acc := range walletAccounts { - acc.Name = acc.Name + "New" - acc.Color = "lightblue" - s.Require().NoError(s.m.SaveAccount(acc)) - } + dbPrivKeyKp2, err := alicesOtherDevice.settings.GetKeypairByKeyUID(privKeyKp.KeyUID) + s.Require().NoError(err) + s.Require().True(accounts.SameKeypairsWithDifferentSyncedFrom(privKeyKp, dbPrivKeyKp2, true, "", accounts.AccountNonOperable)) + + dbWoAccounts2, err := alicesOtherDevice.settings.GetWatchOnlyAccounts() + s.Require().NoError(err) + s.Require().Equal(len(woAccounts), len(dbWoAccounts2)) + s.Require().True(haveSameElements(woAccounts, dbWoAccounts2, accounts.SameAccounts)) + + dbAccounts2, err := alicesOtherDevice.settings.GetAccounts() + s.Require().NoError(err) + s.Require().Equal(len(profileKp.Accounts)+len(seedPhraseKp.Accounts)+len(privKeyKp.Accounts)+len(woAccounts), len(dbAccounts2)) + + s.Require().True(haveSameElements(dbAccounts1, dbAccounts2, accounts.SameAccounts)) + + // Update keypair name on alice's primary device + profileKpUpdated := accounts.GetProfileKeypairForTest(true) + profileKpUpdated.Name = profileKp.Name + "Updated" + profileKpUpdated.Accounts = profileKp.Accounts[:0] + err = s.m.SaveOrUpdateKeypair(profileKpUpdated) + s.Require().NoError(err, "updated keypair name on alice primary device") // Sync between devices is triggered automatically // via watch account changes subscription @@ -302,36 +209,46 @@ func (s *MessengerSyncWalletSuite) TestSyncWallets() { return err } - if len(response.Accounts) != 1 { + if len(response.Keypairs) != 1 { return errors.New("no sync wallet account received") } return nil }) s.Require().NoError(err) - acc2, err = alicesOtherDevice.settings.GetAccounts() - s.Require().NoError(err, "alicesOtherDevice.settings.GetAccounts") - s.Len(acc2, expectedTotalNumOfAccounts, "Must have all wallet accounts plus one for the Status profile account") + // check on alice's other device + dbProfileKp2, err = alicesOtherDevice.settings.GetKeypairByKeyUID(profileKp.KeyUID) + s.Require().NoError(err) + s.Require().Equal(profileKpUpdated.Name, dbProfileKp2.Name) - for _, syncedAcc := range acc2 { - if syncedAcc.Chat { - continue + // Update accounts on alice's primary device + profileKpUpdated = accounts.GetProfileKeypairForTest(false) + accountsToUpdate := profileKpUpdated.Accounts[2:] + for _, acc := range accountsToUpdate { + acc.Name = acc.Name + "Updated" + acc.Color = acc.Color + "Updated" + acc.Emoji = acc.Emoji + "Updated" + err = s.m.SaveOrUpdateAccount(acc) + s.Require().NoError(err, "updated account on alice primary device") + } + + err = tt.RetryWithBackOff(func() error { + response, err := alicesOtherDevice.RetrieveAll() + if err != nil { + return err } - found := false - for _, sentAcc := range walletAccounts { - if syncedAcc.Address == sentAcc.Address { - // Check account values match the expected values - s.Require().Equal(sentAcc.Address, syncedAcc.Address) - s.Require().Equal(sentAcc.Path, syncedAcc.Path) - s.Require().Equal(sentAcc.KeyUID, syncedAcc.KeyUID) - s.Require().Equal(sentAcc.Name, syncedAcc.Name) - s.Require().Equal(sentAcc.Color, syncedAcc.Color) - s.Require().Equal(sentAcc.Type, syncedAcc.Type) - s.Require().Equal(sentAcc.KeypairName, syncedAcc.KeypairName) - s.Require().Equal(sentAcc.DerivedFrom, syncedAcc.DerivedFrom) - found = true - } + + if len(response.Accounts) != len(accountsToUpdate) { + return errors.New("no sync wallet account received") } - s.Require().True(found) + return nil + }) + s.Require().NoError(err) + + // check on alice's other device + dbProfileKp2, err = alicesOtherDevice.settings.GetKeypairByKeyUID(profileKp.KeyUID) + s.Require().NoError(err) + for _, acc := range accountsToUpdate { + s.Require().True(contains(dbProfileKp2.Accounts, acc, accounts.SameAccounts)) } }