fix: don't store ourselves as a contact (#3627)
This commit is contained in:
parent
ff0628c23b
commit
244b4273de
|
@ -451,6 +451,12 @@ func NewMessenger(
|
|||
|
||||
savedAddressesManager := wallet.NewSavedAddressesManager(c.db)
|
||||
|
||||
myPublicKeyString := types.EncodeHex(crypto.FromECDSAPub(&identity.PublicKey))
|
||||
myContact, err := buildContact(myPublicKeyString, &identity.PublicKey)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to build contact of ourself: " + err.Error())
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
messenger = &Messenger{
|
||||
|
@ -472,7 +478,10 @@ func NewMessenger(
|
|||
featureFlags: c.featureFlags,
|
||||
systemMessagesTranslations: c.systemMessagesTranslations,
|
||||
allChats: new(chatMap),
|
||||
allContacts: new(contactMap),
|
||||
allContacts: &contactMap{
|
||||
logger: logger,
|
||||
me: myContact,
|
||||
},
|
||||
allInstallations: new(installationMap),
|
||||
installationID: installationID,
|
||||
modifiedInstallations: new(stringBoolMap),
|
||||
|
@ -825,6 +834,10 @@ func (m *Messenger) IdentityPublicKeyCompressed() []byte {
|
|||
return crypto.CompressPubkey(m.IdentityPublicKey())
|
||||
}
|
||||
|
||||
func (m *Messenger) IdentityPublicKeyString() string {
|
||||
return types.EncodeHex(crypto.FromECDSAPub(m.IdentityPublicKey()))
|
||||
}
|
||||
|
||||
// cleanTopics remove any topic that does not have a Listen flag set
|
||||
func (m *Messenger) cleanTopics() error {
|
||||
if m.mailserversDatabase == nil {
|
||||
|
@ -3423,10 +3436,13 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
|
|||
}
|
||||
|
||||
senderID := contactIDFromPublicKey(publicKey)
|
||||
m.logger.Info("processing message", zap.Any("type", msg.Type), zap.String("senderID", senderID))
|
||||
|
||||
contact, contactFound := messageState.AllContacts.Load(senderID)
|
||||
|
||||
if _, ok := m.requestedContacts[senderID]; !ok {
|
||||
// Check for messages from blocked users
|
||||
if contact, ok := messageState.AllContacts.Load(senderID); ok && contact.Blocked {
|
||||
if contactFound && contact.Blocked {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -3442,10 +3458,7 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
|
|||
continue
|
||||
}
|
||||
|
||||
var contact *Contact
|
||||
if c, ok := messageState.AllContacts.Load(senderID); ok {
|
||||
contact = c
|
||||
} else {
|
||||
if !contactFound {
|
||||
c, err := buildContact(senderID, publicKey)
|
||||
if err != nil {
|
||||
logger.Info("failed to build contact", zap.Error(err))
|
||||
|
|
|
@ -62,12 +62,7 @@ func (s *MessengerContactRequestSuite) newMessenger(shh types.Waku) *Messenger {
|
|||
}
|
||||
|
||||
func (s *MessengerContactRequestSuite) findFirstByContentType(messages []*common.Message, contentType protobuf.ChatMessage_ContentType) *common.Message {
|
||||
for _, message := range messages {
|
||||
if message.ContentType == contentType {
|
||||
return message
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return FindFirstByContentType(messages, contentType)
|
||||
}
|
||||
|
||||
func (s *MessengerContactRequestSuite) sendContactRequest(request *requests.SendContactRequest, messenger *Messenger) {
|
||||
|
|
|
@ -267,8 +267,12 @@ func (m *Messenger) SendContactRequest(ctx context.Context, request *requests.Se
|
|||
}
|
||||
|
||||
func (m *Messenger) updateAcceptedContactRequest(response *MessengerResponse, contactRequestID string) (*MessengerResponse, error) {
|
||||
|
||||
m.logger.Debug("updateAcceptedContactRequest", zap.String("contactRequestID", contactRequestID))
|
||||
|
||||
contactRequest, err := m.persistence.MessageByID(contactRequestID)
|
||||
if err != nil {
|
||||
m.logger.Error("contact request not found", zap.String("contactRequestID", contactRequestID), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -279,7 +283,11 @@ func (m *Messenger) updateAcceptedContactRequest(response *MessengerResponse, co
|
|||
return nil, err
|
||||
}
|
||||
|
||||
contact, _ := m.allContacts.Load(contactRequest.From)
|
||||
contact, ok := m.allContacts.Load(contactRequest.From)
|
||||
if !ok {
|
||||
m.logger.Error("failed to update contact request: contact not found", zap.String("contact id", contactRequest.From))
|
||||
return nil, errors.New("failed to update contact request: contact not found")
|
||||
}
|
||||
|
||||
_, clock, err := m.getOneToOneAndNextClock(contact)
|
||||
if err != nil {
|
||||
|
|
|
@ -456,6 +456,7 @@ func (m *Messenger) handleCommandMessage(state *ReceivedMessageState, message *c
|
|||
}
|
||||
|
||||
func (m *Messenger) syncContactRequestForInstallationContact(contact *Contact, state *ReceivedMessageState, chat *Chat, outgoing bool) error {
|
||||
|
||||
if chat == nil {
|
||||
return fmt.Errorf("no chat restored during the contact synchronisation, contact.ID = %s", contact.ID)
|
||||
}
|
||||
|
@ -466,6 +467,7 @@ func (m *Messenger) syncContactRequestForInstallationContact(contact *Contact, s
|
|||
}
|
||||
|
||||
if contactRequestID != "" {
|
||||
m.logger.Warn("syncContactRequestForInstallationContact: skipping as contact request found", zap.String("contactRequestID", contactRequestID))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -501,7 +503,9 @@ func (m *Messenger) syncContactRequestForInstallationContact(contact *Contact, s
|
|||
|
||||
func (m *Messenger) HandleSyncInstallationContact(state *ReceivedMessageState, message protobuf.SyncInstallationContactV2) error {
|
||||
// Ignore own contact installation
|
||||
|
||||
if message.Id == m.myHexIdentity() {
|
||||
m.logger.Warn("HandleSyncInstallationContact: skipping own contact")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ package protocol
|
|||
import (
|
||||
"sync"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/status-im/status-go/protocol/encryption/multidevice"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
)
|
||||
|
@ -54,9 +56,15 @@ func (cm *chatMap) Delete(chatID string) {
|
|||
|
||||
type contactMap struct {
|
||||
sm sync.Map
|
||||
me *Contact
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
func (cm *contactMap) Load(contactID string) (*Contact, bool) {
|
||||
if contactID == cm.me.ID {
|
||||
cm.logger.Warn("contacts map: loading own identity", zap.String("contactID", contactID))
|
||||
return cm.me, true
|
||||
}
|
||||
contact, ok := cm.sm.Load(contactID)
|
||||
if contact == nil {
|
||||
return nil, ok
|
||||
|
@ -65,6 +73,10 @@ func (cm *contactMap) Load(contactID string) (*Contact, bool) {
|
|||
}
|
||||
|
||||
func (cm *contactMap) Store(contactID string, contact *Contact) {
|
||||
if contactID == cm.me.ID {
|
||||
cm.logger.Warn("contacts map: storing own identity", zap.String("contactID", contactID))
|
||||
return
|
||||
}
|
||||
cm.sm.Store(contactID, contact)
|
||||
}
|
||||
|
||||
|
@ -76,6 +88,10 @@ func (cm *contactMap) Range(f func(contactID string, contact *Contact) (shouldCo
|
|||
}
|
||||
|
||||
func (cm *contactMap) Delete(contactID string) {
|
||||
if contactID == cm.me.ID {
|
||||
cm.logger.Warn("contacts map: deleting own identity", zap.String("contactID", contactID))
|
||||
return
|
||||
}
|
||||
cm.sm.Delete(contactID)
|
||||
}
|
||||
|
||||
|
|
|
@ -2439,24 +2439,3 @@ type testTimeSource struct{}
|
|||
func (t *testTimeSource) GetCurrentTime() uint64 {
|
||||
return uint64(time.Now().Unix())
|
||||
}
|
||||
|
||||
// WaitOnMessengerResponse Wait until the condition is true or the timeout is reached.
|
||||
func WaitOnMessengerResponse(m *Messenger, condition func(*MessengerResponse) bool, errorMessage string) (*MessengerResponse, error) {
|
||||
response := &MessengerResponse{}
|
||||
err := tt.RetryWithBackOff(func() error {
|
||||
var err error
|
||||
r, err := m.RetrieveAll()
|
||||
if err := response.Merge(r); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err == nil && !condition(response) {
|
||||
err = errors.New(errorMessage)
|
||||
}
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package protocol
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
"github.com/status-im/status-go/protocol/tt"
|
||||
)
|
||||
|
||||
// WaitOnMessengerResponse Wait until the condition is true or the timeout is reached.
|
||||
func WaitOnMessengerResponse(m *Messenger, condition func(*MessengerResponse) bool, errorMessage string) (*MessengerResponse, error) {
|
||||
response := &MessengerResponse{}
|
||||
err := tt.RetryWithBackOff(func() error {
|
||||
var err error
|
||||
r, err := m.RetrieveAll()
|
||||
if err := response.Merge(r); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err == nil && !condition(response) {
|
||||
err = errors.New(errorMessage)
|
||||
}
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func FindFirstByContentType(messages []*common.Message, contentType protobuf.ChatMessage_ContentType) *common.Message {
|
||||
for _, message := range messages {
|
||||
if message.ContentType == contentType {
|
||||
return message
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -7,6 +7,11 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/protocol/tt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
@ -48,15 +53,19 @@ func TestSyncDeviceSuite(t *testing.T) {
|
|||
|
||||
type SyncDeviceSuite struct {
|
||||
suite.Suite
|
||||
logger *zap.Logger
|
||||
password string
|
||||
clientAsSenderTmpdir string
|
||||
clientAsReceiverTmpdir string
|
||||
pairThreeDevicesTmpdir string
|
||||
}
|
||||
|
||||
func (s *SyncDeviceSuite) SetupTest() {
|
||||
s.logger = tt.MustCreateTestLogger()
|
||||
s.password = "password"
|
||||
s.clientAsSenderTmpdir = s.T().TempDir()
|
||||
s.clientAsReceiverTmpdir = s.T().TempDir()
|
||||
s.pairThreeDevicesTmpdir = s.T().TempDir()
|
||||
}
|
||||
|
||||
func (s *SyncDeviceSuite) prepareBackendWithAccount(tmpdir string) *api.GethStatusBackend {
|
||||
|
@ -123,6 +132,128 @@ func (s *SyncDeviceSuite) prepareBackendWithoutAccount(tmpdir string) *api.GethS
|
|||
return backend
|
||||
}
|
||||
|
||||
func (s *SyncDeviceSuite) pairAccounts(serverBackend *api.GethStatusBackend, serverDir string,
|
||||
clientBackend *api.GethStatusBackend, clientDir string) {
|
||||
|
||||
// Start sender server
|
||||
|
||||
serverActiveAccount, err := serverBackend.GetActiveAccount()
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
serverKeystorePath := filepath.Join(serverDir, keystoreDir, serverActiveAccount.KeyUID)
|
||||
serverConfig := &SenderServerConfig{
|
||||
SenderConfig: &SenderConfig{
|
||||
KeystorePath: serverKeystorePath,
|
||||
DeviceType: "desktop",
|
||||
KeyUID: serverActiveAccount.KeyUID,
|
||||
Password: s.password,
|
||||
},
|
||||
ServerConfig: new(ServerConfig),
|
||||
}
|
||||
|
||||
configBytes, err := json.Marshal(serverConfig)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
connectionString, err := StartUpSenderServer(serverBackend, string(configBytes))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
// Start receiving client
|
||||
|
||||
err = clientBackend.AccountManager().InitKeystore(filepath.Join(clientDir, keystoreDir))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
err = clientBackend.OpenAccounts()
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
clientNodeConfig, err := defaultNodeConfig(uuid.New().String(), "")
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
expectedKDFIterations := 2048
|
||||
clientKeystoreDir := filepath.Join(clientDir, keystoreDir)
|
||||
clientPayloadSourceConfig := ReceiverClientConfig{
|
||||
ReceiverConfig: &ReceiverConfig{
|
||||
KeystorePath: clientKeystoreDir,
|
||||
DeviceType: "desktop",
|
||||
KDFIterations: expectedKDFIterations,
|
||||
NodeConfig: clientNodeConfig,
|
||||
SettingCurrentNetwork: currentNetwork,
|
||||
},
|
||||
ClientConfig: new(ClientConfig),
|
||||
}
|
||||
clientNodeConfig.RootDataDir = clientDir
|
||||
|
||||
clientConfigBytes, err := json.Marshal(clientPayloadSourceConfig)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
err = StartUpReceivingClient(clientBackend, connectionString, string(clientConfigBytes))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
require.True(s.T(), serverBackend.Messenger().HasPairedDevices())
|
||||
require.True(s.T(), clientBackend.Messenger().HasPairedDevices())
|
||||
}
|
||||
|
||||
func (s *SyncDeviceSuite) sendContactRequest(request *requests.SendContactRequest, messenger *protocol.Messenger) {
|
||||
senderPublicKey := common.PubkeyToHex(messenger.IdentityPublicKey())
|
||||
s.logger.Info("sendContactRequest", zap.String("sender", senderPublicKey), zap.String("receiver", request.ID))
|
||||
|
||||
resp, err := messenger.SendContactRequest(context.Background(), request)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(resp)
|
||||
}
|
||||
|
||||
func (s *SyncDeviceSuite) receiveContactRequest(messageText string, messenger *protocol.Messenger) *common.Message {
|
||||
receiverPublicKey := types.EncodeHex(crypto.FromECDSAPub(messenger.IdentityPublicKey()))
|
||||
s.logger.Info("receiveContactRequest", zap.String("receiver", receiverPublicKey))
|
||||
|
||||
// Wait for the message to reach its destination
|
||||
resp, err := protocol.WaitOnMessengerResponse(
|
||||
messenger,
|
||||
func(r *protocol.MessengerResponse) bool {
|
||||
return len(r.Contacts) == 1 && len(r.Messages()) == 2 && len(r.ActivityCenterNotifications()) == 1
|
||||
},
|
||||
"no messages",
|
||||
)
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(resp)
|
||||
|
||||
contactRequest := protocol.FindFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST)
|
||||
s.Require().NotNil(contactRequest)
|
||||
|
||||
return contactRequest
|
||||
}
|
||||
|
||||
func (s *SyncDeviceSuite) acceptContactRequest(contactRequest *common.Message, sender *protocol.Messenger, receiver *protocol.Messenger) {
|
||||
senderPublicKey := types.EncodeHex(crypto.FromECDSAPub(sender.IdentityPublicKey()))
|
||||
receiverPublicKey := types.EncodeHex(crypto.FromECDSAPub(receiver.IdentityPublicKey()))
|
||||
s.logger.Info("acceptContactRequest", zap.String("sender", senderPublicKey), zap.String("receiver", receiverPublicKey))
|
||||
|
||||
_, err := receiver.AcceptContactRequest(context.Background(), &requests.AcceptContactRequest{ID: types.Hex2Bytes(contactRequest.ID)})
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Wait for the message to reach its destination
|
||||
resp, err := protocol.WaitOnMessengerResponse(
|
||||
sender,
|
||||
func(r *protocol.MessengerResponse) bool {
|
||||
return len(r.Contacts) == 1 && len(r.Messages()) == 2 && len(r.ActivityCenterNotifications()) == 1
|
||||
},
|
||||
"no messages",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(resp)
|
||||
}
|
||||
|
||||
func (s *SyncDeviceSuite) checkMutualContact(backend *api.GethStatusBackend, contactPublicKey string) {
|
||||
messenger := backend.Messenger()
|
||||
contacts := messenger.MutualContacts()
|
||||
s.Require().Len(contacts, 1)
|
||||
contact := contacts[0]
|
||||
s.Require().Equal(contactPublicKey, contact.ID)
|
||||
s.Require().Equal(protocol.ContactRequestStateSent, contact.ContactRequestLocalState)
|
||||
s.Require().Equal(protocol.ContactRequestStateReceived, contact.ContactRequestRemoteState)
|
||||
s.Require().NotNil(contact.DisplayName)
|
||||
}
|
||||
|
||||
func (s *SyncDeviceSuite) TestPairingSyncDeviceClientAsSender() {
|
||||
clientTmpDir := filepath.Join(s.clientAsSenderTmpdir, "client")
|
||||
clientBackend := s.prepareBackendWithAccount(clientTmpDir)
|
||||
|
@ -379,6 +510,63 @@ func (s *SyncDeviceSuite) TestPairingSyncDeviceClientAsReceiver() {
|
|||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func (s *SyncDeviceSuite) TestPairingThreeDevices() {
|
||||
bobTmpDir := filepath.Join(s.pairThreeDevicesTmpdir, "bob")
|
||||
bobBackend := s.prepareBackendWithAccount(bobTmpDir)
|
||||
bobMessenger := bobBackend.Messenger()
|
||||
_, err := bobMessenger.Start()
|
||||
s.Require().NoError(err)
|
||||
|
||||
alice1TmpDir := filepath.Join(s.pairThreeDevicesTmpdir, "alice1")
|
||||
alice1Backend := s.prepareBackendWithAccount(alice1TmpDir)
|
||||
alice1Messenger := alice1Backend.Messenger()
|
||||
_, err = alice1Messenger.Start()
|
||||
s.Require().NoError(err)
|
||||
|
||||
alice2TmpDir := filepath.Join(s.pairThreeDevicesTmpdir, "alice2")
|
||||
alice2Backend := s.prepareBackendWithoutAccount(alice2TmpDir)
|
||||
|
||||
alice3TmpDir := filepath.Join(s.pairThreeDevicesTmpdir, "alice3")
|
||||
alice3Backend := s.prepareBackendWithAccount(alice3TmpDir)
|
||||
|
||||
defer func() {
|
||||
require.NoError(s.T(), bobBackend.Logout())
|
||||
require.NoError(s.T(), alice1Backend.Logout())
|
||||
require.NoError(s.T(), alice2Backend.Logout())
|
||||
require.NoError(s.T(), alice3Backend.Logout())
|
||||
}()
|
||||
|
||||
// Make Alice and Bob mutual contacts
|
||||
messageText := "hello!"
|
||||
bobPublicKey := types.EncodeHex(crypto.FromECDSAPub(bobMessenger.IdentityPublicKey()))
|
||||
request := &requests.SendContactRequest{
|
||||
ID: bobPublicKey,
|
||||
Message: messageText,
|
||||
}
|
||||
s.sendContactRequest(request, alice1Messenger)
|
||||
contactRequest := s.receiveContactRequest(messageText, bobMessenger)
|
||||
s.acceptContactRequest(contactRequest, alice1Messenger, bobMessenger)
|
||||
s.checkMutualContact(alice1Backend, bobPublicKey)
|
||||
|
||||
// We shouldn't sync ourselves as a contact, so we check there's only Bob
|
||||
// https://github.com/status-im/status-go/issues/3667
|
||||
s.Require().Equal(1, len(alice1Backend.Messenger().Contacts()))
|
||||
|
||||
// Pair alice-1 <-> alice-2
|
||||
s.logger.Info("pairing Alice-1 and Alice-2")
|
||||
s.pairAccounts(alice1Backend, alice1TmpDir, alice2Backend, alice2TmpDir)
|
||||
|
||||
s.checkMutualContact(alice2Backend, bobPublicKey)
|
||||
s.Require().Equal(1, len(alice2Backend.Messenger().Contacts()))
|
||||
|
||||
// Pair Alice-2 <-> ALice-3
|
||||
s.logger.Info("pairing Alice-2 and Alice-3")
|
||||
s.pairAccounts(alice2Backend, alice2TmpDir, alice3Backend, alice3TmpDir)
|
||||
|
||||
s.checkMutualContact(alice3Backend, bobPublicKey)
|
||||
s.Require().Equal(1, len(alice3Backend.Messenger().Contacts()))
|
||||
}
|
||||
|
||||
func defaultSettings(generatedAccountInfo generator.GeneratedAccountInfo, derivedAddresses map[string]generator.AccountInfo, mnemonic *string) (*settings.Settings, error) {
|
||||
chatKeyString := derivedAddresses[pathDefaultChat].PublicKey
|
||||
|
||||
|
|
Loading…
Reference in New Issue