package whisper import ( "context" "errors" "testing" "github.com/stretchr/testify/suite" "github.com/ethereum/go-ethereum/crypto" "github.com/status-im/status-go/account" "github.com/status-im/status-go/eth-node/types" e2e "github.com/status-im/status-go/t/e2e" . "github.com/status-im/status-go/t/utils" "github.com/status-im/status-go/whisper/v6" ) func TestWhisperTestSuite(t *testing.T) { e2e.Init() suite.Run(t, new(WhisperTestSuite)) } type WhisperTestSuite struct { e2e.BackendTestSuite } func buildLoginParams(mainAccountAddress, chatAddress, password string) account.LoginParams { return account.LoginParams{ ChatAddress: types.HexToAddress(chatAddress), Password: password, MainAccount: types.HexToAddress(mainAccountAddress), } } // TODO(adam): can anyone explain what this test is testing? // I don't see any race condition testing here. func (s *WhisperTestSuite) TestWhisperFilterRace() { s.StartTestBackend() defer s.StopTestBackend() whisperService, err := s.Backend.StatusNode().WhisperService() s.NoError(err) accountManager := s.Backend.AccountManager() s.NotNil(accountManager) whisperAPI := whisper.NewPublicWhisperAPI(whisperService) // account1 _, accountKey1, err := accountManager.AddressToDecryptedAccount(TestConfig.Account1.ChatAddress, TestConfig.Account1.Password) s.NoError(err) accountKey1Byte := crypto.FromECDSAPub(&accountKey1.PrivateKey.PublicKey) key1ID, err := whisperService.AddKeyPair(accountKey1.PrivateKey) s.NoError(err) ok := whisperAPI.HasKeyPair(context.Background(), key1ID) s.True(ok, "identity not injected") // account2 _, accountKey2, err := accountManager.AddressToDecryptedAccount(TestConfig.Account2.ChatAddress, TestConfig.Account2.Password) s.NoError(err) key2ID, err := whisperService.AddKeyPair(accountKey2.PrivateKey) s.NoError(err) ok = whisperAPI.HasKeyPair(context.Background(), key2ID) s.True(ok, "identity not injected") // race filter addition filterAdded := make(chan struct{}) allFiltersAdded := make(chan struct{}) go func() { counter := 10 for range filterAdded { counter-- if counter <= 0 { break } } close(allFiltersAdded) }() for i := 0; i < 10; i++ { go func() { // nolint: errcheck whisperAPI.NewMessageFilter(whisper.Criteria{ Sig: accountKey1Byte, PrivateKeyID: key2ID, Topics: []whisper.TopicType{ {0x4e, 0x03, 0x65, 0x7a}, {0x34, 0x60, 0x7c, 0x9b}, {0x21, 0x41, 0x7d, 0xf9}, }, }) filterAdded <- struct{}{} }() } <-allFiltersAdded } func (s *WhisperTestSuite) TestSelectAccount() { s.StartTestBackend() defer s.StopTestBackend() whisperService, err := s.Backend.StatusNode().WhisperService() s.NoError(err) // create account 1 accountInfo1, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) s.NoError(err) // create account 2 accountInfo2, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account2.Password) s.NoError(err) // make sure that identities are not injected yet s.False(whisperService.HasKeyPair(accountInfo1.ChatPubKey), "identity already present in whisper") s.False(whisperService.HasKeyPair(accountInfo2.ChatPubKey), "identity already present in whisper") // try selecting with wrong password err = s.Backend.SelectAccount(buildLoginParams(accountInfo1.WalletAddress, accountInfo1.ChatAddress, "wrongpassword")) s.NotNil(err) // select account 1 err = s.Backend.SelectAccount(buildLoginParams(accountInfo1.WalletAddress, accountInfo1.ChatAddress, TestConfig.Account1.Password)) s.NoError(err) s.True(whisperService.HasKeyPair(accountInfo1.ChatPubKey), "identity not injected in whisper") // select account 2, make sure that previous account is wiped out from Whisper cache s.False(whisperService.HasKeyPair(accountInfo2.ChatPubKey), "identity already present in whisper") s.NoError(s.Backend.SelectAccount(buildLoginParams(accountInfo2.WalletAddress, accountInfo2.ChatAddress, TestConfig.Account2.Password))) s.True(whisperService.HasKeyPair(accountInfo2.ChatPubKey), "identity not injected into whisper") } func (s *WhisperTestSuite) TestLogout() { s.StartTestBackend() defer s.StopTestBackend() whisperService, err := s.Backend.StatusNode().WhisperService() s.NoError(err) // create an account accountInfo, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) s.NoError(err) // make sure that identity doesn't exist (yet) in Whisper s.False(whisperService.HasKeyPair(accountInfo.ChatPubKey), "identity already present in whisper") // it should exist only after selecting an account s.NoError(s.Backend.SelectAccount(buildLoginParams(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password))) s.True(whisperService.HasKeyPair(accountInfo.ChatPubKey), "identity not injected into whisper") s.NoError(s.Backend.Logout()) s.False(whisperService.HasKeyPair(accountInfo.ChatPubKey), "identity not cleared from whisper") } func (s *WhisperTestSuite) TestSelectedAccountOnRestart() { s.StartTestBackend() // we need to make sure that selected account is injected as identity into Whisper whisperService := s.WhisperService() // create test accounts accountInfo1, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) s.NoError(err) accountInfo2, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account2.Password) s.NoError(err) // make sure that identity is not (yet injected) s.False(whisperService.HasKeyPair(accountInfo1.ChatPubKey), "identity already present in whisper") // make sure that no wallet account is selected by default selectedWalletAccount, err := s.Backend.AccountManager().MainAccountAddress() s.EqualError(account.ErrNoAccountSelected, err.Error(), "account selected, but should not be") s.Equal(types.Address{}, selectedWalletAccount) // make sure that no chat account is selected by default selectedChatAccount, err := s.Backend.AccountManager().SelectedChatAccount() s.EqualError(account.ErrNoAccountSelected, err.Error(), "account selected, but should not be") s.Nil(selectedChatAccount) // select account with wrong password err = s.Backend.SelectAccount(buildLoginParams(accountInfo1.WalletAddress, accountInfo1.ChatAddress, "wrongPassword")) expectedErr := errors.New("cannot retrieve a valid key for a given account: could not decrypt key with given password") s.EqualError(expectedErr, err.Error()) // select account with right password s.NoError(s.Backend.SelectAccount(buildLoginParams(accountInfo1.WalletAddress, accountInfo1.ChatAddress, TestConfig.Account1.Password))) selectedChatAccount1, err := s.Backend.AccountManager().SelectedChatAccount() s.NoError(err) selectedChatPubKey1 := types.EncodeHex(crypto.FromECDSAPub(&selectedChatAccount1.AccountKey.PrivateKey.PublicKey)) s.Equal(selectedChatPubKey1, accountInfo1.ChatPubKey) s.True(whisperService.HasKeyPair(s.Backend.SelectedAccountKeyID()), "identity not injected into whisper") // select another account, make sure that previous account is wiped out from Whisper cache previousKeyID := s.Backend.SelectedAccountKeyID() s.NoError(s.Backend.SelectAccount(buildLoginParams(accountInfo2.WalletAddress, accountInfo2.ChatAddress, TestConfig.Account2.Password))) selectedChatAccount2, err := s.Backend.AccountManager().SelectedChatAccount() s.NoError(err) selectedChatPubKey2 := types.EncodeHex(crypto.FromECDSAPub(&selectedChatAccount2.AccountKey.PrivateKey.PublicKey)) s.Equal(selectedChatPubKey2, accountInfo2.ChatPubKey) s.True(whisperService.HasKeyPair(s.Backend.SelectedAccountKeyID()), "identity not injected into whisper") s.False(whisperService.HasKeyPair(previousKeyID), "identity should be removed, but it is still present in whisper") // stop node (and all of its sub-protocols) nodeConfig := s.Backend.StatusNode().Config() s.NotNil(nodeConfig) preservedNodeConfig := *nodeConfig s.NoError(s.Backend.StopNode()) // resume node s.Require().NoError(s.Backend.StartNode(&preservedNodeConfig)) // re-check selected account (account2 MUST be selected) selectedWalletAccount, err = s.Backend.AccountManager().MainAccountAddress() s.NoError(err) s.NotNil(selectedWalletAccount) s.Equal(selectedWalletAccount.String(), accountInfo2.WalletAddress, "incorrect wallet address selected") selectedChatAccount, err = s.Backend.AccountManager().SelectedChatAccount() s.NoError(err) s.NotNil(selectedChatAccount) s.Equal(selectedChatAccount.Address.Hex(), accountInfo2.ChatAddress, "incorrect chat address selected") // make sure that Whisper gets identity re-injected whisperService = s.WhisperService() s.True(whisperService.HasKeyPair(s.Backend.SelectedAccountKeyID()), "identity not injected into whisper") s.False(whisperService.HasKeyPair(previousKeyID), "identity should not be present, but it is still present in whisper") // now restart node using RestartNode() method, and make sure that account is still available s.RestartTestNode() defer s.StopTestBackend() whisperService = s.WhisperService() s.True(whisperService.HasKeyPair(s.Backend.SelectedAccountKeyID()), "identity not injected into whisper") s.False(whisperService.HasKeyPair(previousKeyID), "identity should not be present, but it is still present in whisper") // now logout, and make sure that on restart no account is selected (i.e. logout works properly) s.NoError(s.Backend.Logout()) s.RestartTestNode() whisperService = s.WhisperService() s.False(whisperService.HasKeyPair(s.Backend.SelectedAccountKeyID()), "identity not injected into whisper") s.False(whisperService.HasKeyPair(previousKeyID), "identity should not be present, but it is still present in whisper") selectedWalletAccount, err = s.Backend.AccountManager().MainAccountAddress() s.EqualError(account.ErrNoAccountSelected, err.Error()) s.Equal(types.Address{}, selectedWalletAccount) selectedChatAccount, err = s.Backend.AccountManager().SelectedChatAccount() s.EqualError(account.ErrNoAccountSelected, err.Error()) s.Nil(selectedChatAccount) } func (s *WhisperTestSuite) TestSelectedChatKeyIsUsedInWhisper() { s.StartTestBackend() defer s.StopTestBackend() whisperService, err := s.Backend.StatusNode().WhisperService() s.NoError(err) // create an account accountInfo, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) s.NoError(err) // select account s.NoError(s.Backend.SelectAccount(buildLoginParams(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password))) // Get the chat account selectedChatAccount, err := s.Backend.AccountManager().SelectedChatAccount() s.NoError(err) // chat key should be injected in whisper selectedChatPubKey := types.EncodeHex(crypto.FromECDSAPub(&selectedChatAccount.AccountKey.PrivateKey.PublicKey)) s.True(whisperService.HasKeyPair(selectedChatPubKey), "identity not injected in whisper") }