From 96532f97c460f849ed8b1ed5d2507593e3ca5c1c Mon Sep 17 00:00:00 2001 From: Mikhail Rogachev Date: Tue, 25 Apr 2023 15:27:15 +0400 Subject: [PATCH] Unifying the endpoints for contact flows (#3379) * fix: Contact requests flows fix: pending CR notification fix: use CR as message with provided text * fix: Remove legacy default contact request * fix: Add test case sending CR after removal from contacts * fix: refactor contact request tests to have common steps * fix: activate chat on sender side after receiveing the CR * chore: Return defaultContactRequestID function * fix: force activate chat on reciever's side * fix: ensure AC notification's name for CR notifiaction match contact's primary name --- VERSION | 2 +- protocol/communities_messenger_test.go | 2 +- protocol/messenger_contact_requests_test.go | 2166 ++++++----------- .../messenger_contact_verification_test.go | 18 +- protocol/messenger_contacts.go | 116 +- protocol/messenger_handler.go | 122 +- 6 files changed, 779 insertions(+), 1647 deletions(-) diff --git a/VERSION b/VERSION index ea6b298fc..0b642282a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.146.6 +0.147.0 diff --git a/protocol/communities_messenger_test.go b/protocol/communities_messenger_test.go index 46af4d045..fbd6d1d08 100644 --- a/protocol/communities_messenger_test.go +++ b/protocol/communities_messenger_test.go @@ -2312,7 +2312,7 @@ func (s *MessengerCommunitiesSuite) TestShareCommunity() { s.Require().Len(response.Messages(), 1) // Add bob to contacts so it does not go on activity center - bobPk := common.PubkeyToHex(&s.alice.identity.PublicKey) + bobPk := common.PubkeyToHex(&s.bob.identity.PublicKey) request := &requests.AddContact{ID: bobPk} _, err = s.alice.AddContact(context.Background(), request) s.Require().NoError(err) diff --git a/protocol/messenger_contact_requests_test.go b/protocol/messenger_contact_requests_test.go index 6c872bb5e..edb90f04d 100644 --- a/protocol/messenger_contact_requests_test.go +++ b/protocol/messenger_contact_requests_test.go @@ -61,61 +61,74 @@ func (s *MessengerContactRequestSuite) newMessenger(shh types.Waku) *Messenger { return messenger } -func (s *MessengerContactRequestSuite) TestReceiveAndAcceptContactRequest() { //nolint: unused - - messageText := "hello!" - - theirMessenger := s.newMessenger(s.shh) - _, err := theirMessenger.Start() - s.Require().NoError(err) - - contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) - request := &requests.SendContactRequest{ - ID: contactID, - Message: messageText, - } - +func (s *MessengerContactRequestSuite) sendContactRequest(request *requests.SendContactRequest, messenger *Messenger) { // Send contact request - resp, err := s.m.SendContactRequest(context.Background(), request) + resp, err := messenger.SendContactRequest(context.Background(), request) s.Require().NoError(err) - s.Require().NotNil(resp) + + // Check CR message s.Require().Len(resp.Messages(), 1) - s.Require().Equal(common.ContactRequestStatePending, resp.Messages()[0].ContactRequestState) + contactRequest := resp.Messages()[0] + s.Require().Equal(common.ContactRequestStatePending, contactRequest.ContactRequestState) + s.Require().Equal(request.Message, contactRequest.Text) + + // Check pending notification + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) + s.Require().Equal(contactRequest.ID, resp.ActivityCenterNotifications()[0].Message.ID) + s.Require().Equal(contactRequest.ContactRequestState, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, true) + + // Check contacts + s.Require().Len(resp.Contacts, 1) + contact := resp.Contacts[0] + s.Require().False(contact.mutual()) // Make sure it's not returned as coming from us - contactRequests, _, err := s.m.PendingContactRequests("", 10) + contactRequests, _, err := messenger.PendingContactRequests("", 10) s.Require().NoError(err) s.Require().Len(contactRequests, 0) // Make sure contact is added on the sender side - contacts := s.m.AddedContacts() + contacts := messenger.AddedContacts() s.Require().Len(contacts, 1) s.Require().Equal(ContactRequestStateSent, contacts[0].ContactRequestLocalState) + s.Require().NotNil(contacts[0].DisplayName) + // Check contact's primary name matches notifiaction's name + s.Require().Equal(resp.ActivityCenterNotifications()[0].Name, contacts[0].PrimaryName()) +} + +func (s *MessengerContactRequestSuite) receiveContactRequest(messageText string, theirMessenger *Messenger) *common.Message { // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( + resp, err := WaitOnMessengerResponse( theirMessenger, func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 && len(r.Messages()) > 0 && len(r.ActivityCenterNotifications()) > 0 + return len(r.Contacts) == 1 && len(r.Messages()) == 1 && len(r.ActivityCenterNotifications()) == 1 }, "no messages", ) // Check contact request has been received s.Require().NoError(err) + s.Require().NotNil(resp) + + // Check CR message + s.Require().Len(resp.Messages(), 1) + contactRequest := resp.Messages()[0] + s.Require().Equal(common.ContactRequestStatePending, contactRequest.ContactRequestState) + s.Require().Equal(messageText, contactRequest.Text) // Check activity center notification is of the right type s.Require().Len(resp.ActivityCenterNotifications(), 1) s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - s.Require().Equal(common.ContactRequestStatePending, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) + s.Require().Equal(contactRequest.ID, resp.ActivityCenterNotifications()[0].Message.ID) + s.Require().Equal(contactRequest.ContactRequestState, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, false) s.Require().Equal(resp.ActivityCenterNotifications()[0].Accepted, false) s.Require().Equal(resp.ActivityCenterNotifications()[0].Dismissed, false) - s.Require().Equal(common.ContactRequestStatePending, resp.Messages()[0].ContactRequestState) - notifications, err := theirMessenger.ActivityCenterNotifications(ActivityCenterNotificationsRequest{ Cursor: "", Limit: 10, @@ -124,34 +137,40 @@ func (s *MessengerContactRequestSuite) TestReceiveAndAcceptContactRequest() { // }, ) s.Require().NoError(err) - s.Require().Len(notifications.Notifications, 1) - - s.Require().NotNil(common.ContactRequestStatePending, notifications.Notifications[0].Message) - s.Require().Equal(common.ContactRequestStatePending, notifications.Notifications[0].Message.ContactRequestState) + s.Require().Equal(contactRequest.ID, notifications.Notifications[0].Message.ID) + s.Require().Equal(contactRequest.ContactRequestState, notifications.Notifications[0].Message.ContactRequestState) // Check the contact state is correctly set s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) + contact := resp.Contacts[0] + s.Require().Equal(ContactRequestStateReceived, contact.ContactRequestRemoteState) - // Make sure it's the pending contact requests - contactRequests, _, err = theirMessenger.PendingContactRequests("", 10) + // Check contact's primary name matches notifiaction's name + s.Require().Equal(resp.ActivityCenterNotifications()[0].Name, contact.PrimaryName()) + + // Make sure it's the latest pending contact requests + contactRequests, _, err := theirMessenger.PendingContactRequests("", 10) s.Require().NoError(err) - s.Require().Len(contactRequests, 1) - s.Require().Equal(contactRequests[0].ContactRequestState, common.ContactRequestStatePending) + s.Require().Greater(len(contactRequests), 0) + s.Require().Equal(contactRequests[0].ID, contactRequest.ID) + return contactRequest +} + +func (s *MessengerContactRequestSuite) acceptContactRequest(contactRequest *common.Message, theirMessenger *Messenger) { // Accept contact request, receiver side - resp, err = theirMessenger.AcceptContactRequest(context.Background(), &requests.AcceptContactRequest{ID: types.Hex2Bytes(contactRequests[0].ID)}) + resp, err := theirMessenger.AcceptContactRequest(context.Background(), &requests.AcceptContactRequest{ID: types.Hex2Bytes(contactRequest.ID)}) s.Require().NoError(err) // Make sure the message is updated s.Require().NotNil(resp) s.Require().Len(resp.Messages(), 1) - s.Require().Equal(resp.Messages()[0].ID, contactRequests[0].ID) + s.Require().Equal(resp.Messages()[0].ID, contactRequest.ID) s.Require().Equal(common.ContactRequestStateAccepted, resp.Messages()[0].ContactRequestState) s.Require().Len(resp.ActivityCenterNotifications(), 1) - s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequests[0].ID) + s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequest.ID) s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) @@ -159,8 +178,16 @@ func (s *MessengerContactRequestSuite) TestReceiveAndAcceptContactRequest() { // s.Require().Len(resp.Contacts, 1) s.Require().True(resp.Contacts[0].mutual()) + // Check contact's primary name matches notifiaction's name + s.Require().Equal(resp.ActivityCenterNotifications()[0].Name, resp.Contacts[0].PrimaryName()) + + // Check we have active chat in the response + s.Require().Len(resp.Chats(), 2) + s.Require().True(resp.Chats()[0].Active) // This is unactive profile chat + s.Require().True(resp.Chats()[1].Active) + // Make sure the sender is added to our contacts - contacts = theirMessenger.AddedContacts() + contacts := theirMessenger.AddedContacts() s.Require().Len(contacts, 1) // Make sure we consider them a mutual contact, receiver side @@ -171,34 +198,27 @@ func (s *MessengerContactRequestSuite) TestReceiveAndAcceptContactRequest() { // resp, err = WaitOnMessengerResponse( s.m, func(r *MessengerResponse) bool { - return len(r.Contacts) == 1 && len(r.Messages()) == 2 && len(r.ActivityCenterNotifications()) == 1 + return len(r.Contacts) == 1 && len(r.Messages()) == 1 && len(r.ActivityCenterNotifications()) == 1 }, "no messages", ) s.Require().NoError(err) // Check activity center notification is of the right type + s.Require().Len(resp.ActivityCenterNotifications(), 1) s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, true) s.Require().Equal(resp.ActivityCenterNotifications()[0].Accepted, true) s.Require().Equal(resp.ActivityCenterNotifications()[0].Dismissed, false) // Make sure the message is updated, sender s2de - s.Require().NotNil(resp) - - var message *common.Message - - for _, m := range resp.Messages() { - if m.ID == contactRequests[0].ID { - message = m - } - } - s.Require().NotNil(message) - - s.Require().Equal(message.ID, contactRequests[0].ID) - s.Require().Equal(common.ContactRequestStateAccepted, message.ContactRequestState) + s.Require().Len(resp.Messages(), 1) + s.Require().NotNil(resp.Messages()[0]) + s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) + s.Require().Equal(contactRequest.ID, resp.Messages()[0].ID) + s.Require().Equal(contactRequest.Text, resp.Messages()[0].Text) + s.Require().Equal(common.ContactRequestStateAccepted, resp.Messages()[0].ContactRequestState) // Make sure we consider them a mutual contact, sender side mutualContacts = s.m.MutualContacts() @@ -206,77 +226,29 @@ func (s *MessengerContactRequestSuite) TestReceiveAndAcceptContactRequest() { // // Check the contact state is correctly set s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) + contact := resp.Contacts[0] + s.Require().True(contact.mutual()) + + // Check contact's primary name matches notifiaction's name + s.Require().Equal(resp.ActivityCenterNotifications()[0].Name, contact.PrimaryName()) + + // Sender's side chat should be active after the accepting the CR + chat, ok := s.m.allChats.Load(contact.ID) + s.Require().True(ok) + s.Require().NotNil(chat) + s.Require().True(chat.Active) + + // Receiver's side chat should be also active after the accepting the CR + myID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) + chat, ok = theirMessenger.allChats.Load(myID) + s.Require().True(ok) + s.Require().NotNil(chat) + s.Require().True(chat.Active) } -func (s *MessengerContactRequestSuite) TestReceiveAndDismissContactRequest() { - - messageText := "hello!" - - theirMessenger := s.newMessenger(s.shh) - _, err := theirMessenger.Start() - s.Require().NoError(err) - - contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) - request := &requests.SendContactRequest{ - ID: contactID, - Message: messageText, - } - - // Send contact request - resp, err := s.m.SendContactRequest(context.Background(), request) - s.Require().NoError(err) - - s.Require().NotNil(resp) - s.Require().Len(resp.Messages(), 1) - s.Require().Equal(common.ContactRequestStatePending, resp.Messages()[0].ContactRequestState) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateSent, resp.Contacts[0].ContactRequestLocalState) - - // Make sure it's not returned as coming from us - contactRequests, _, err := s.m.PendingContactRequests("", 10) - s.Require().NoError(err) - s.Require().Len(contactRequests, 0) - - // Make sure contact is added on the sender side - contacts := s.m.AddedContacts() - s.Require().Len(contacts, 1) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - theirMessenger, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 && len(r.ActivityCenterNotifications()) > 0 - }, - "no messages", - ) - s.Require().NoError(err) - - // Check activity center notification is of the right type - s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - s.Require().Equal(common.ContactRequestStatePending, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, false) - s.Require().Equal(resp.ActivityCenterNotifications()[0].Accepted, false) - s.Require().Equal(resp.ActivityCenterNotifications()[0].Dismissed, false) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) - - // Check contact request has been received - s.Require().NoError(err) - - // Make sure it's the pending contact requests - contactRequests, _, err = theirMessenger.PendingContactRequests("", 10) - s.Require().NoError(err) - s.Require().Len(contactRequests, 1) - s.Require().Equal(contactRequests[0].ContactRequestState, common.ContactRequestStatePending) - +func (s *MessengerContactRequestSuite) declineContactRequest(contactRequest *common.Message, theirMessenger *Messenger) { // Dismiss contact request, receiver side - resp, err = theirMessenger.DeclineContactRequest(context.Background(), &requests.DeclineContactRequest{ID: types.Hex2Bytes(contactRequests[0].ID)}) + resp, err := theirMessenger.DeclineContactRequest(context.Background(), &requests.DeclineContactRequest{ID: types.Hex2Bytes(contactRequest.ID)}) s.Require().NoError(err) // Check the contact state is correctly set @@ -286,154 +258,27 @@ func (s *MessengerContactRequestSuite) TestReceiveAndDismissContactRequest() { // Make sure the message is updated s.Require().NotNil(resp) s.Require().Len(resp.Messages(), 1) - s.Require().Equal(resp.Messages()[0].ID, contactRequests[0].ID) + s.Require().Equal(resp.Messages()[0].ID, contactRequest.ID) s.Require().Equal(common.ContactRequestStateDismissed, resp.Messages()[0].ContactRequestState) s.Require().Len(resp.ActivityCenterNotifications(), 1) - s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequests[0].ID) + s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequest.ID) s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, true) s.Require().Equal(resp.ActivityCenterNotifications()[0].Accepted, false) s.Require().Equal(resp.ActivityCenterNotifications()[0].Dismissed, true) s.Require().Equal(common.ContactRequestStateDismissed, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) + // Check contact's primary name matches notifiaction's name + s.Require().Equal(resp.ActivityCenterNotifications()[0].Name, resp.Contacts[0].PrimaryName()) + // Make sure the sender is not added to our contacts - contacts = theirMessenger.AddedContacts() + contacts := theirMessenger.AddedContacts() s.Require().Len(contacts, 0) } -func (s *MessengerContactRequestSuite) TestReceiveAcceptAndRetractContactRequest() { //nolint: unused - - messageText := "hello!" - - theirMessenger := s.newMessenger(s.shh) - _, err := theirMessenger.Start() - s.Require().NoError(err) - - s.Require().NoError(theirMessenger.settings.SaveSettingField(settings.MutualContactEnabled, true)) - - contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) - request := &requests.SendContactRequest{ - ID: contactID, - Message: messageText, - } - - // Send contact request - resp, err := s.m.SendContactRequest(context.Background(), request) - s.Require().NoError(err) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateSent, resp.Contacts[0].ContactRequestLocalState) - - s.Require().NotNil(resp) - s.Require().Len(resp.Messages(), 1) - s.Require().Equal(common.ContactRequestStatePending, resp.Messages()[0].ContactRequestState) - - // Make sure it's not returned as coming from us - contactRequests, _, err := s.m.PendingContactRequests("", 10) - s.Require().NoError(err) - s.Require().Len(contactRequests, 0) - - // Make sure contact is added on the sender side - contacts := s.m.AddedContacts() - s.Require().Len(contacts, 1) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - theirMessenger, - func(r *MessengerResponse) bool { - return len(r.Messages()) > 0 && len(r.ActivityCenterNotifications()) > 0 - }, - "no messages", - ) - - // Check contact request has been received - s.Require().NoError(err) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) - - // Check activity center notification is of the right type - s.Require().Len(resp.ActivityCenterNotifications(), 1) - s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - s.Require().Equal(common.ContactRequestStatePending, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - - // Make sure it's the pending contact requests - contactRequests, _, err = theirMessenger.PendingContactRequests("", 10) - s.Require().NoError(err) - s.Require().Len(contactRequests, 1) - s.Require().Equal(contactRequests[0].ContactRequestState, common.ContactRequestStatePending) - - cid := resp.ActivityCenterNotifications()[0].Message.ID - // Accept contact request, receiver side - resp, err = theirMessenger.AcceptContactRequest(context.Background(), &requests.AcceptContactRequest{ID: types.Hex2Bytes(cid)}) - s.Require().NoError(err) - - // Make sure the message is updated - s.Require().NotNil(resp) - s.Require().Len(resp.Messages(), 1) - s.Require().Equal(resp.Messages()[0].ID, contactRequests[0].ID) - s.Require().Equal(common.ContactRequestStateAccepted, resp.Messages()[0].ContactRequestState) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) - - s.Require().Len(resp.ActivityCenterNotifications(), 1) - s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequests[0].ID) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - - // Make sure the sender is added to our contacts - contacts = theirMessenger.AddedContacts() - s.Require().Len(contacts, 1) - - // Make sure we consider them a mutual contact, receiver side - mutualContacts := theirMessenger.MutualContacts() - s.Require().Len(mutualContacts, 1) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - s.m, - func(r *MessengerResponse) bool { - return len(r.Messages()) == 2 && len(r.ActivityCenterNotifications()) == 1 && len(r.Contacts) == 1 - }, - "no messages", - ) - s.Require().NoError(err) - - // Check activity center notification is of the right type - s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) - - // Make sure the message is updated, sender side - s.Require().NotNil(resp) - - var message *common.Message - - for _, m := range resp.Messages() { - if m.ID == contactRequests[0].ID { - message = m - } - } - s.Require().NotNil(message) - - s.Require().Equal(message.ID, contactRequests[0].ID) - s.Require().Equal(common.ContactRequestStateAccepted, message.ContactRequestState) - - // Make sure we consider them a mutual contact, sender side - mutualContacts = s.m.MutualContacts() - s.Require().Len(mutualContacts, 1) - - resp, err = s.m.RetractContactRequest(&requests.RetractContactRequest{ID: types.Hex2Bytes(contactID)}) +func (s *MessengerContactRequestSuite) retractContactRequest(contactID string, theirMessenger *Messenger) { + resp, err := s.m.RetractContactRequest(&requests.RetractContactRequest{ID: types.Hex2Bytes(contactID)}) s.Require().NoError(err) s.Require().NotNil(resp) s.Require().Len(resp.Contacts, 1) @@ -469,6 +314,592 @@ func (s *MessengerContactRequestSuite) TestReceiveAcceptAndRetractContactRequest s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestRemoteState) } +func (s *MessengerContactRequestSuite) TestReceiveAndAcceptContactRequest() { //nolint: unused + messageText := "hello!" + + theirMessenger := s.newMessenger(s.shh) + _, err := theirMessenger.Start() + s.Require().NoError(err) + + contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageText, + } + s.sendContactRequest(request, s.m) + contactRequest := s.receiveContactRequest(messageText, theirMessenger) + s.acceptContactRequest(contactRequest, theirMessenger) +} + +func (s *MessengerContactRequestSuite) TestReceiveAndDismissContactRequest() { + messageText := "hello!" + + theirMessenger := s.newMessenger(s.shh) + _, err := theirMessenger.Start() + s.Require().NoError(err) + + contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageText, + } + s.sendContactRequest(request, s.m) + contactRequest := s.receiveContactRequest(messageText, theirMessenger) + s.declineContactRequest(contactRequest, theirMessenger) +} + +func (s *MessengerContactRequestSuite) TestReceiveAcceptAndRetractContactRequest() { //nolint: unused + messageText := "hello!" + + theirMessenger := s.newMessenger(s.shh) + _, err := theirMessenger.Start() + s.Require().NoError(err) + + s.Require().NoError(theirMessenger.settings.SaveSettingField(settings.MutualContactEnabled, true)) + + contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageText, + } + s.sendContactRequest(request, s.m) + contactRequest := s.receiveContactRequest(messageText, theirMessenger) + s.acceptContactRequest(contactRequest, theirMessenger) + s.retractContactRequest(contactID, theirMessenger) +} + +func (s *MessengerContactRequestSuite) TestReceiveAndAcceptContactRequestTwice() { //nolint: unused + messageText := "hello!" + + theirMessenger := s.newMessenger(s.shh) + _, err := theirMessenger.Start() + s.Require().NoError(err) + + contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageText, + } + s.sendContactRequest(request, s.m) + contactRequest := s.receiveContactRequest(messageText, theirMessenger) + s.acceptContactRequest(contactRequest, theirMessenger) + + // Resend contact request with higher clock value + resp, err := s.m.SendContactRequest(context.Background(), request) + s.Require().NoError(err) + + // Wait for the message to reach its destination + resp, err = WaitOnMessengerResponse( + theirMessenger, + func(r *MessengerResponse) bool { + return len(r.Messages()) == 1 && r.Messages()[0].ID == resp.Messages()[0].ID + }, + "no messages", + ) + s.Require().NoError(err) + + // Nothing should have changed, on both sides + mutualContacts := s.m.MutualContacts() + s.Require().Len(mutualContacts, 1) + + mutualContacts = theirMessenger.MutualContacts() + s.Require().Len(mutualContacts, 1) +} + +func (s *MessengerContactRequestSuite) TestAcceptLatestContactRequestForContact() { + messageText := "hello!" + + theirMessenger := s.newMessenger(s.shh) + _, err := theirMessenger.Start() + s.Require().NoError(err) + + contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageText, + } + s.sendContactRequest(request, s.m) + contactRequest := s.receiveContactRequest(messageText, theirMessenger) + + // Accept latest contact request, receiver side + myID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) + resp, err := theirMessenger.AcceptLatestContactRequestForContact(context.Background(), &requests.AcceptLatestContactRequestForContact{ID: types.Hex2Bytes(myID)}) + s.Require().NoError(err) + + // Make sure the message is updated + s.Require().NotNil(resp) + s.Require().Len(resp.Messages(), 1) + s.Require().Equal(resp.Messages()[0].ID, contactRequest.ID) + s.Require().Equal(common.ContactRequestStateAccepted, resp.Messages()[0].ContactRequestState) + + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequest.ID) + s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) + s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) + + // Check the contact state is correctly set + s.Require().Len(resp.Contacts, 1) + s.Require().True(resp.Contacts[0].mutual()) + + // Make sure the sender is added to our contacts + contacts := theirMessenger.AddedContacts() + s.Require().Len(contacts, 1) + + // Make sure we consider them a mutual contact, receiver side + mutualContacts := theirMessenger.MutualContacts() + s.Require().Len(mutualContacts, 1) + + // Wait for the message to reach its destination + resp, err = WaitOnMessengerResponse( + s.m, + func(r *MessengerResponse) bool { + return len(r.Contacts) == 1 && len(r.Messages()) == 1 && len(r.ActivityCenterNotifications()) == 1 + }, + "no messages", + ) + s.Require().NoError(err) + + // Make sure the message is updated, sender side + s.Require().NotNil(resp) + + s.Require().Len(resp.Messages(), 1) + s.Require().Equal(messageText, resp.Messages()[0].Text) + s.Require().Equal(common.ContactRequestStateAccepted, resp.Messages()[0].ContactRequestState) + + // Check activity center notification is of the right type + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) + s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) + s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) + + // Make sure we consider them a mutual contact, sender side + mutualContacts = s.m.MutualContacts() + s.Require().Len(mutualContacts, 1) + + // Check the contact state is correctly set + s.Require().Len(resp.Contacts, 1) + s.Require().True(resp.Contacts[0].mutual()) +} + +func (s *MessengerContactRequestSuite) TestDismissLatestContactRequestForContact() { + messageText := "hello!" + + theirMessenger := s.newMessenger(s.shh) + _, err := theirMessenger.Start() + s.Require().NoError(err) + + contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageText, + } + s.sendContactRequest(request, s.m) + contactRequest := s.receiveContactRequest(messageText, theirMessenger) + + // Dismiss latest contact request, receiver side + myID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) + resp, err := theirMessenger.DismissLatestContactRequestForContact(context.Background(), &requests.DismissLatestContactRequestForContact{ID: types.Hex2Bytes(myID)}) + s.Require().NoError(err) + + // Make sure the message is updated + s.Require().NotNil(resp) + s.Require().Len(resp.Messages(), 1) + s.Require().Equal(resp.Messages()[0].ID, contactRequest.ID) + s.Require().Equal(common.ContactRequestStateDismissed, resp.Messages()[0].ContactRequestState) + + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequest.ID) + s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) + s.Require().Equal(common.ContactRequestStateDismissed, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) +} + +func (s *MessengerContactRequestSuite) TestPairedDevicesRemoveContact() { + messageText := "hello!" + + alice1 := s.m + alice2, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, nil) + s.Require().NoError(err) + + _, err = alice2.Start() + s.Require().NoError(err) + + prepAliceMessengersForPairing(&s.Suite, alice1, alice2) + + pairTwoDevices(&s.Suite, alice1, alice2) + pairTwoDevices(&s.Suite, alice2, alice1) + + bob := s.newMessenger(s.shh) + _, err = bob.Start() + s.Require().NoError(err) + + // Alice sends a contact request to bob + contactID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageText, + } + s.sendContactRequest(request, alice1) + contactRequest := s.receiveContactRequest(messageText, bob) + s.acceptContactRequest(contactRequest, bob) + + // Wait for the message to reach its destination + resp, err := WaitOnMessengerResponse( + alice2, + func(r *MessengerResponse) bool { + return len(r.Contacts) > 0 + }, + "no messages", + ) + s.Require().NoError(err) + + // Make sure we consider them a mutual contact, sender side + mutualContacts := alice2.MutualContacts() + s.Require().Len(mutualContacts, 1) + + // Check the contact state is correctly set + s.Require().Len(resp.Contacts, 1) + s.Require().True(resp.Contacts[0].mutual()) + + s.retractContactRequest(contactID, bob) + + // Check on alice2 side + resp, err = WaitOnMessengerResponse( + alice2, + func(r *MessengerResponse) bool { + return len(r.Contacts) > 0 + }, + "no messages", + ) + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Contacts, 1) + + // Check the contact state is correctly set + s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestLocalState) + s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestRemoteState) +} + +// The scenario tested is as follow: +// 1) Alice sends a contact request to Bob +// 2) Bob accepts the contact request +// 3) Alice restores state on a different device +// 4) Alice sends a contact request to bob +// Bob will need to help Alice recover her state, since as far as he can see +// that's an already accepted contact request +func (s *MessengerContactRequestSuite) TestAliceRecoverStateSendContactRequest() { + messageText := "hello!" + + alice1 := s.m + + bob := s.newMessenger(s.shh) + _, err := bob.Start() + s.Require().NoError(err) + + bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) + + // Alice sends a contact request to bob + request := &requests.SendContactRequest{ + ID: bobID, + Message: messageText, + } + s.sendContactRequest(request, alice1) + + contactRequest := s.receiveContactRequest(messageText, bob) + s.Require().NotNil(contactRequest) + + // Bob accepts the contact request + s.acceptContactRequest(contactRequest, bob) + + // Alice resets her device + alice2, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, nil) + s.Require().NoError(err) + + _, err = alice2.Start() + s.Require().NoError(err) + + // adds bob again to her device + s.sendContactRequest(request, alice2) + + // Wait for the message to reach its destination + _, err = WaitOnMessengerResponse( + bob, + func(r *MessengerResponse) bool { + return len(r.Contacts) > 0 + }, + "no messages", + ) + s.Require().NoError(err) + + // Bob should be a mutual contact with alice, nothing has changed + s.Require().Len(bob.MutualContacts(), 1) + + // Alice retrieves her messages, she should have been notified by + // dear bobby that they were contacts + resp, err := WaitOnMessengerResponse( + alice2, + func(r *MessengerResponse) bool { + return len(r.Contacts) > 0 + }, + "no messages", + ) + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Contacts, 1) + + // Check the contact state is correctly set + s.Require().True(resp.Contacts[0].mutual()) +} + +// The scenario tested is as follow: +// 1) Alice sends a contact request to Bob +// 2) Bob accepts the contact request +// 3) Alice restores state on a different device +// 4) Bob sends a message to alice +// Alice will show a contact request from bob +func (s *MessengerContactRequestSuite) TestAliceRecoverStateReceiveContactRequest() { + messageText := "hello!" + + alice1 := s.m + + bob := s.newMessenger(s.shh) + _, err := bob.Start() + s.Require().NoError(err) + + bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) + + // Alice sends a contact request to bob + request := &requests.SendContactRequest{ + ID: bobID, + Message: messageText, + } + s.sendContactRequest(request, alice1) + + contactRequest := s.receiveContactRequest(messageText, bob) + s.Require().NotNil(contactRequest) + + // Bob accepts the contact request + s.acceptContactRequest(contactRequest, bob) + + // Alice resets her device + alice2, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, nil) + s.Require().NoError(err) + + _, err = alice2.Start() + s.Require().NoError(err) + + // We want to facilitate the discovery of the x3dh bundl here, since bob does not know about alice device + + alice2Bundle, err := alice2.encryptor.GetBundle(alice2.identity) + s.Require().NoError(err) + + _, err = bob.encryptor.ProcessPublicBundle(bob.identity, alice2Bundle) + s.Require().NoError(err) + + // Bob sends a chat message to alice + + var chat Chat + chats := bob.Chats() + for i, c := range chats { + if c.ID == alice1.myHexIdentity() && c.OneToOne() { + chat = *chats[i] + } + } + s.Require().NotNil(chat) + + inputMessage := buildTestMessage(chat) + _, err = bob.SendChatMessage(context.Background(), inputMessage) + s.NoError(err) + + // Alice retrieves the chat message, it should be + resp, err := WaitOnMessengerResponse( + alice2, + func(r *MessengerResponse) bool { + return len(r.ActivityCenterNotifications()) == 1 + }, + "no messages", + ) + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) + s.Require().Len(resp.Contacts, 1) + + // Check the contact state is correctly set + s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestLocalState) + s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) +} + +// The scenario tested is as follow: +// 1) Alice sends a contact request to Bob +// 2) Bob accepts the contact request +// 3) Bob goes offline +// 4) Alice retracts the contact request +// 5) Alice adds bob back to her contacts +// 6) Bob goes online, they receive 4 and 5 in the correct order +func (s *MessengerContactRequestSuite) TestAliceOfflineRetractsAndAddsCorrectOrder() { + messageText := "hello!" + + alice1 := s.m + + bob := s.newMessenger(s.shh) + _, err := bob.Start() + s.Require().NoError(err) + + bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) + + // Alice sends a contact request to bob + request := &requests.SendContactRequest{ + ID: bobID, + Message: messageText, + } + s.sendContactRequest(request, alice1) + + contactRequest := s.receiveContactRequest(messageText, bob) + s.Require().NotNil(contactRequest) + + // Bob accepts the contact request + s.acceptContactRequest(contactRequest, bob) + + // Alice removes Bob from contacts + _, err = alice1.RetractContactRequest(&requests.RetractContactRequest{ID: types.Hex2Bytes(bob.myHexIdentity())}) + s.Require().NoError(err) + + // Adds bob again to her device + s.sendContactRequest(request, alice1) + + // Wait for the message to reach its destination + _, err = WaitOnMessengerResponse( + bob, + func(r *MessengerResponse) bool { + return len(r.ActivityCenterNotifications()) > 0 + }, + "no messages", + ) + s.Require().NoError(err) +} + +// The scenario tested is as follow: +// 1) Alice sends a contact request to Bob +// 2) Bob accepts the contact request +// 3) Bob goes offline +// 4) Alice retracts the contact request +// 5) Alice adds bob back to her contacts +// 6) Bob goes online, they receive 4 and 5 in the wrong order +func (s *MessengerContactRequestSuite) TestAliceOfflineRetractsAndAddsWrongOrder() { + messageText := "hello!" + + alice1 := s.m + + bob := s.newMessenger(s.shh) + _, err := bob.Start() + s.Require().NoError(err) + + bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) + + // Alice sends a contact request to bob + request := &requests.SendContactRequest{ + ID: bobID, + Message: messageText, + } + s.sendContactRequest(request, alice1) + + contactRequest := s.receiveContactRequest(messageText, bob) + s.Require().NotNil(contactRequest) + + // Bob accepts the contact request + s.acceptContactRequest(contactRequest, bob) + + // Alice removes Bob from contacts + _, err = alice1.RetractContactRequest(&requests.RetractContactRequest{ID: types.Hex2Bytes(bob.myHexIdentity())}) + s.Require().NoError(err) + + // Adds bob again to her device + s.sendContactRequest(request, alice1) + + // Get alice perspective of bob + bobFromAlice := alice1.AddedContacts()[0] + + // Get bob perspective of alice + aliceFromBob := bob.MutualContacts()[0] + + s.Require().NotNil(bobFromAlice) + s.Require().NotNil(aliceFromBob) + + // We can't simulate out-of-order messages easily, so we need to do + // things manually here + result := aliceFromBob.ContactRequestPropagatedStateReceived(bobFromAlice.ContactRequestPropagatedState()) + s.Require().True(result.newContactRequestReceived) +} + +// The scenario tested is as follow: +// 1) Alice sends a contact request to Bob +// 2) Bob accepts the contact request +// 3) Alice removes Bob from contacts +// 4) Make sure Alice and Bob are not mutual contacts +// 5) Alice sends new contact request +// 6) Bob accepts new contact request +func (s *MessengerContactRequestSuite) TestAliceResendsContactRequestAfterRemovingBobFromContacts() { + messageTextFirst := "hello 1!" + + theirMessenger := s.newMessenger(s.shh) + _, err := theirMessenger.Start() + s.Require().NoError(err) + + contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) + + // Alice sends a contact request to Bob + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageTextFirst, + } + s.sendContactRequest(request, s.m) + + // Bob accepts the contact request + contactRequest := s.receiveContactRequest(messageTextFirst, theirMessenger) + s.Require().NotNil(contactRequest) + s.acceptContactRequest(contactRequest, theirMessenger) + + // Alice removes Bob from contacts + s.retractContactRequest(contactID, theirMessenger) + + // Send new contact request + messageTextSecond := "hello 2!" + + // Alice sends new contact request + request = &requests.SendContactRequest{ + ID: contactID, + Message: messageTextSecond, + } + s.sendContactRequest(request, s.m) + + // Make sure bob and alice are not mutual after sending CR + s.Require().Len(s.m.MutualContacts(), 0) + s.Require().Len(theirMessenger.MutualContacts(), 0) + + // Bob accepts new contact request + contactRequest = s.receiveContactRequest(messageTextSecond, theirMessenger) + s.Require().NotNil(contactRequest) + s.acceptContactRequest(contactRequest, theirMessenger) + + // Make sure bob and alice are not mutual after sending CR + s.Require().Len(s.m.MutualContacts(), 1) + s.Require().Len(theirMessenger.MutualContacts(), 1) +} + +func (s *MessengerContactRequestSuite) TestBuildContact() { + contactID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) + contact, err := s.m.BuildContact(&requests.BuildContact{PublicKey: contactID}) + s.Require().NoError(err) + + s.Require().Equal(contact.EnsName, "") + s.Require().False(contact.ENSVerified) + + contact, err = s.m.BuildContact(&requests.BuildContact{PublicKey: contactID, ENSName: "foobar"}) + s.Require().NoError(err) + + s.Require().Equal(contact.EnsName, "foobar") + s.Require().True(contact.ENSVerified) +} + func (s *MessengerContactRequestSuite) TestReceiveAcceptAndRetractContactRequestOutOfOrder() { message := protobuf.ChatMessage{ Clock: 4, @@ -514,1226 +945,3 @@ func (s *MessengerContactRequestSuite) TestReceiveAcceptAndRetractContactRequest s.Require().Len(contacts, 1) s.Require().Equal(ContactRequestStateReceived, contacts[0].ContactRequestRemoteState) } - -func (s *MessengerContactRequestSuite) TestReceiveAndAcceptContactRequestTwice() { //nolint: unused - - messageText := "hello!" - - theirMessenger := s.newMessenger(s.shh) - _, err := theirMessenger.Start() - s.Require().NoError(err) - - contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) - request := &requests.SendContactRequest{ - ID: contactID, - Message: messageText, - } - - // Send contact request - resp, err := s.m.SendContactRequest(context.Background(), request) - s.Require().NoError(err) - - s.Require().NotNil(resp) - s.Require().Len(resp.Messages(), 1) - s.Require().Equal(common.ContactRequestStatePending, resp.Messages()[0].ContactRequestState) - - // Make sure it's not returned as coming from us - contactRequests, _, err := s.m.PendingContactRequests("", 10) - s.Require().NoError(err) - s.Require().Len(contactRequests, 0) - - // Make sure contact is added on the sender side - contacts := s.m.AddedContacts() - s.Require().Len(contacts, 1) - s.Require().Equal(ContactRequestStateSent, contacts[0].ContactRequestLocalState) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - theirMessenger, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 && len(r.Messages()) > 0 && len(r.ActivityCenterNotifications()) > 0 - }, - "no messages", - ) - - // Check contact request has been received - s.Require().NoError(err) - - // Check activity center notification is of the right type - s.Require().Len(resp.ActivityCenterNotifications(), 1) - s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - s.Require().Equal(common.ContactRequestStatePending, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) - - // Make sure it's the pending contact requests - contactRequests, _, err = theirMessenger.PendingContactRequests("", 10) - s.Require().NoError(err) - s.Require().Len(contactRequests, 1) - s.Require().Equal(contactRequests[0].ContactRequestState, common.ContactRequestStatePending) - - // Accept contact request, receiver side - resp, err = theirMessenger.AcceptContactRequest(context.Background(), &requests.AcceptContactRequest{ID: types.Hex2Bytes(contactRequests[0].ID)}) - s.Require().NoError(err) - - // Make sure the message is updated - s.Require().NotNil(resp) - s.Require().Len(resp.Messages(), 1) - s.Require().Equal(resp.Messages()[0].ID, contactRequests[0].ID) - s.Require().Equal(common.ContactRequestStateAccepted, resp.Messages()[0].ContactRequestState) - - s.Require().Len(resp.ActivityCenterNotifications(), 1) - s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequests[0].ID) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) - - // Make sure the sender is added to our contacts - contacts = theirMessenger.AddedContacts() - s.Require().Len(contacts, 1) - - // Make sure we consider them a mutual contact, receiver side - mutualContacts := theirMessenger.MutualContacts() - s.Require().Len(mutualContacts, 1) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - s.m, - func(r *MessengerResponse) bool { - return len(r.Contacts) == 1 && len(r.Messages()) == 2 && len(r.ActivityCenterNotifications()) == 1 - }, - "no messages", - ) - s.Require().NoError(err) - - // Check activity center notification is of the right type - s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - - // Make sure the message is updated, sender s2de - s.Require().NotNil(resp) - s.Require().Len(resp.Messages(), 2) - - var message *common.Message - - for _, m := range resp.Messages() { - if m.ID == contactRequests[0].ID { - message = m - } - } - s.Require().NotNil(message) - - s.Require().Equal(message.ID, contactRequests[0].ID) - s.Require().Equal(common.ContactRequestStateAccepted, message.ContactRequestState) - - // Make sure we consider them a mutual contact, sender side - mutualContacts = s.m.MutualContacts() - s.Require().Len(mutualContacts, 1) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) - - // Resend contact request with higher clock value - resp, err = s.m.SendContactRequest(context.Background(), request) - s.Require().NoError(err) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - theirMessenger, - func(r *MessengerResponse) bool { - return len(r.Messages()) == 1 && r.Messages()[0].ID == resp.Messages()[0].ID - }, - "no messages", - ) - s.Require().NoError(err) - - // Nothing should have changed, on both sides - mutualContacts = s.m.MutualContacts() - s.Require().Len(mutualContacts, 1) - - mutualContacts = theirMessenger.MutualContacts() - s.Require().Len(mutualContacts, 1) -} - -func (s *MessengerContactRequestSuite) TestAcceptLatestContactRequestForContact() { - - messageText := "hello!" - - theirMessenger := s.newMessenger(s.shh) - _, err := theirMessenger.Start() - s.Require().NoError(err) - - contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) - myID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) - - request := &requests.SendContactRequest{ - ID: contactID, - Message: messageText, - } - - // Send contact request - resp, err := s.m.SendContactRequest(context.Background(), request) - s.Require().NoError(err) - - s.Require().NotNil(resp) - s.Require().Len(resp.Messages(), 1) - s.Require().Equal(common.ContactRequestStatePending, resp.Messages()[0].ContactRequestState) - - // Make sure it's not returned - contactRequests, _, err := s.m.PendingContactRequests("", 10) - s.Require().NoError(err) - s.Require().Len(contactRequests, 0) - - // Make sure contact is added on the sender side - contacts := s.m.AddedContacts() - s.Require().Len(contacts, 1) - s.Require().Equal(ContactRequestStateSent, contacts[0].ContactRequestLocalState) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - theirMessenger, - func(r *MessengerResponse) bool { - return len(r.Contacts) == 1 && len(r.ActivityCenterNotifications()) == 1 - }, - "no messages", - ) - - // Check contact request has been received - s.Require().NoError(err) - - // Check activity center notification is of the right type - s.Require().Len(resp.ActivityCenterNotifications(), 1) - s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - s.Require().Equal(common.ContactRequestStatePending, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) - - // Make sure it's the pending contact requests - contactRequests, _, err = theirMessenger.PendingContactRequests("", 10) - s.Require().NoError(err) - s.Require().Len(contactRequests, 1) - s.Require().Equal(contactRequests[0].ContactRequestState, common.ContactRequestStatePending) - - // Accept latest contact request, receiver side - resp, err = theirMessenger.AcceptLatestContactRequestForContact(context.Background(), &requests.AcceptLatestContactRequestForContact{ID: types.Hex2Bytes(myID)}) - s.Require().NoError(err) - - // Make sure the message is updated - s.Require().NotNil(resp) - s.Require().Len(resp.Messages(), 1) - s.Require().Equal(resp.Messages()[0].ID, contactRequests[0].ID) - s.Require().Equal(common.ContactRequestStateAccepted, resp.Messages()[0].ContactRequestState) - - s.Require().Len(resp.ActivityCenterNotifications(), 1) - s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequests[0].ID) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) - - // Make sure the sender is added to our contacts - contacts = theirMessenger.AddedContacts() - s.Require().Len(contacts, 1) - - // Make sure we consider them a mutual contact, receiver side - mutualContacts := theirMessenger.MutualContacts() - s.Require().Len(mutualContacts, 1) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - s.m, - func(r *MessengerResponse) bool { - return len(r.Messages()) == 2 && len(r.ActivityCenterNotifications()) == 1 - }, - "no messages", - ) - s.Require().NoError(err) - - // Make sure the message is updated, sender side - s.Require().NotNil(resp) - s.Require().Len(resp.ActivityCenterNotifications(), 1) - // We receive two messages, one for the default contact request, that - // is dispatched for backward compatibility, and one for the updated - // contact request that we sent - s.Require().Len(resp.Messages(), 2) - var message *common.Message - - for _, m := range resp.Messages() { - if m.ID == contactRequests[0].ID { - message = m - } - } - s.Require().NotNil(message) - s.Require().Equal(common.ContactRequestStateAccepted, message.ContactRequestState) - - // Check activity center notification is of the right type - s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - - // Make sure we consider them a mutual contact, sender side - mutualContacts = s.m.MutualContacts() - s.Require().Len(mutualContacts, 1) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) -} - -func (s *MessengerContactRequestSuite) TestDismissLatestContactRequestForContact() { - - messageText := "hello!" - - theirMessenger := s.newMessenger(s.shh) - _, err := theirMessenger.Start() - s.Require().NoError(err) - - contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) - myID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) - - request := &requests.SendContactRequest{ - ID: contactID, - Message: messageText, - } - - // Send contact request - resp, err := s.m.SendContactRequest(context.Background(), request) - s.Require().NoError(err) - - s.Require().NotNil(resp) - s.Require().Len(resp.Messages(), 1) - s.Require().Equal(common.ContactRequestStatePending, resp.Messages()[0].ContactRequestState) - - // Make sure it's not returned as coming from us - contactRequests, _, err := s.m.PendingContactRequests("", 10) - s.Require().NoError(err) - s.Require().Len(contactRequests, 0) - - // Make sure contact is added on the sender side - contacts := s.m.AddedContacts() - s.Require().Len(contacts, 1) - s.Require().Equal(ContactRequestStateSent, contacts[0].ContactRequestLocalState) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - theirMessenger, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 && len(r.Messages()) > 0 && len(r.ActivityCenterNotifications()) > 0 - }, - "no messages", - ) - - // Check contact request has been received - s.Require().NoError(err) - - // Check activity center notification is of the right type - s.Require().Len(resp.ActivityCenterNotifications(), 1) - s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - s.Require().Equal(common.ContactRequestStatePending, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) - - // Make sure it's the pending contact requests - contactRequests, _, err = theirMessenger.PendingContactRequests("", 10) - s.Require().NoError(err) - s.Require().Len(contactRequests, 1) - s.Require().Equal(contactRequests[0].ContactRequestState, common.ContactRequestStatePending) - - // Dismiss latest contact request, receiver side - resp, err = theirMessenger.DismissLatestContactRequestForContact(context.Background(), &requests.DismissLatestContactRequestForContact{ID: types.Hex2Bytes(myID)}) - s.Require().NoError(err) - - // Make sure the message is updated - s.Require().NotNil(resp) - s.Require().Len(resp.Messages(), 1) - s.Require().Equal(resp.Messages()[0].ID, contactRequests[0].ID) - s.Require().Equal(common.ContactRequestStateDismissed, resp.Messages()[0].ContactRequestState) - - s.Require().Len(resp.ActivityCenterNotifications(), 1) - s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequests[0].ID) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - s.Require().Equal(common.ContactRequestStateDismissed, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - -} - -func (s *MessengerContactRequestSuite) TestReceiveAndAcceptLegacyContactRequest() { - - theirMessenger := s.newMessenger(s.shh) - _, err := theirMessenger.Start() - s.Require().NoError(err) - - contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) - request := &requests.AddContact{ - ID: contactID, - } - - // Send contact request - resp, err := s.m.AddContact(context.Background(), request) - s.Require().NoError(err) - - s.Require().NotNil(resp) - - // Make sure contact is added on the sender side - contacts := s.m.AddedContacts() - s.Require().Len(contacts, 1) - s.Require().Equal(ContactRequestStateSent, contacts[0].ContactRequestLocalState) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - theirMessenger, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 && len(r.ActivityCenterNotifications()) == 1 - }, - "no messages", - ) - - s.Require().NoError(err) - - notification := resp.ActivityCenterNotifications()[0] - - // Check contact request has been received - s.Require().NoError(err) - - // Check activity center notification is of the right type - s.Require().Equal(ActivityCenterNotificationTypeContactRequest, notification.Type) - s.Require().NotNil(notification.Type) - s.Require().Equal(common.ContactRequestStatePending, notification.Message.ContactRequestState) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) - - // Accept contact request, receiver side - resp, err = theirMessenger.AcceptContactRequest(context.Background(), &requests.AcceptContactRequest{ID: types.Hex2Bytes(notification.Message.ID)}) - s.Require().NoError(err) - - // Make sure the message is updated - s.Require().NotNil(resp) - - s.Require().Len(resp.ActivityCenterNotifications(), 1) - s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), notification.Message.ID) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) - - // Make sure the sender is added to our contacts - contacts = theirMessenger.AddedContacts() - s.Require().Len(contacts, 1) - - // Make sure we consider them a mutual contact, receiver side - mutualContacts := theirMessenger.MutualContacts() - s.Require().Len(mutualContacts, 1) -} - -func (s *MessengerContactRequestSuite) TestLegacyContactRequestNotifications() { - - theirMessenger := s.newMessenger(s.shh) - _, err := theirMessenger.Start() - s.Require().NoError(err) - - contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) - request := &requests.AddContact{ - ID: contactID, - } - - // Send legacy contact request - resp, err := s.m.AddContact(context.Background(), request) - s.Require().NoError(err) - - s.Require().NotNil(resp) - - // Make sure contact is added on the sender side - contacts := s.m.AddedContacts() - s.Require().Len(contacts, 1) - s.Require().Equal(ContactRequestStateSent, contacts[0].ContactRequestLocalState) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - theirMessenger, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 && len(r.ActivityCenterNotifications()) == 1 - }, - "no messages", - ) - - s.Require().NoError(err) - - notification := resp.ActivityCenterNotifications()[0] - - // Check contact request has been received - s.Require().NoError(err) - - // Check activity center notification is of the right type - s.Require().Equal(ActivityCenterNotificationTypeContactRequest, notification.Type) - s.Require().NotNil(notification.Type) - s.Require().Equal(common.ContactRequestStatePending, notification.Message.ContactRequestState) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) -} - -func (s *MessengerContactRequestSuite) TestReceiveMultipleLegacy() { - - theirMessenger := s.newMessenger(s.shh) - _, err := theirMessenger.Start() - s.Require().NoError(err) - - s.Require().NoError(theirMessenger.settings.SaveSettingField(settings.MutualContactEnabled, true)) - s.Require().NoError(s.m.settings.SaveSettingField(settings.MutualContactEnabled, true)) - - contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) - request := &requests.AddContact{ - ID: contactID, - } - - // Send legacy contact request - resp, err := s.m.AddContact(context.Background(), request) - s.Require().NoError(err) - - s.Require().NotNil(resp) - - // Make sure contact is added on the sender side - contacts := s.m.AddedContacts() - s.Require().Len(contacts, 1) - s.Require().Equal(ContactRequestStateSent, contacts[0].ContactRequestLocalState) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - theirMessenger, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 && len(r.ActivityCenterNotifications()) == 1 - }, - "no messages", - ) - - s.Require().NoError(err) - - notification := resp.ActivityCenterNotifications()[0] - - // Check contact request has been received - s.Require().NoError(err) - - // Check activity center notification is of the right type - s.Require().Equal(ActivityCenterNotificationTypeContactRequest, notification.Type) - s.Require().NotNil(notification.Type) - s.Require().Equal(common.ContactRequestStatePending, notification.Message.ContactRequestState) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) - - // Remove contact - - _, err = s.m.RetractContactRequest(&requests.RetractContactRequest{ID: types.Hex2Bytes(contactID)}) - s.Require().NoError(err) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - theirMessenger, - func(r *MessengerResponse) bool { - return len(r.Contacts) == 1 - }, - "no messages", - ) - s.Require().NoError(err) - - // Make sure it's not a contact anymore - s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestLocalState) - s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestRemoteState) - - // Re-add user - resp, err = s.m.AddContact(context.Background(), request) - s.Require().NoError(err) - s.Require().NotNil(resp) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - theirMessenger, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 && len(r.ActivityCenterNotifications()) == 1 - }, - "no messages", - ) - - s.Require().NoError(err) - - notification = resp.ActivityCenterNotifications()[0] - - // Check contact request has been received - s.Require().NoError(err) - - // Check activity center notification is of the right type - s.Require().Equal(ActivityCenterNotificationTypeContactRequest, notification.Type) - s.Require().NotNil(notification.Type) - s.Require().Equal(common.ContactRequestStatePending, notification.Message.ContactRequestState) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) - -} - -func (s *MessengerContactRequestSuite) TestAcceptLatestLegacyContactRequestForContact() { // nolint: unused - - theirMessenger := s.newMessenger(s.shh) - _, err := theirMessenger.Start() - s.Require().NoError(err) - - contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) - myID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) - - request := &requests.AddContact{ - ID: contactID, - } - - // Send contact request - _, err = s.m.AddContact(context.Background(), request) - s.Require().NoError(err) - - // Wait for the message to reach its destination - resp, err := WaitOnMessengerResponse( - theirMessenger, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 && len(r.Messages()) > 0 && len(r.ActivityCenterNotifications()) > 0 - }, - "no messages", - ) - - // Check contact request has been received - s.Require().NoError(err) - - // Check activity center notification is of the right type - s.Require().Len(resp.ActivityCenterNotifications(), 1) - s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - s.Require().Equal(common.ContactRequestStatePending, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) - - // Accept latest contact request, receiver side - resp, err = theirMessenger.AcceptLatestContactRequestForContact(context.Background(), &requests.AcceptLatestContactRequestForContact{ID: types.Hex2Bytes(myID)}) - s.Require().NoError(err) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) - - // Make sure the sender is added to our contacts - contacts := theirMessenger.AddedContacts() - s.Require().Len(contacts, 1) - - // Make sure we consider them a mutual contact, receiver side - mutualContacts := theirMessenger.MutualContacts() - s.Require().Len(mutualContacts, 1) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - s.m, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 - }, - "no messages", - ) - s.Require().NoError(err) - - // Make sure we consider them a mutual contact, sender side - mutualContacts = s.m.MutualContacts() - s.Require().Len(mutualContacts, 1) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) -} - -func (s *MessengerContactRequestSuite) TestPairedDevicesRemoveContact() { - alice1 := s.m - alice2, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, nil) - s.Require().NoError(err) - - _, err = alice2.Start() - s.Require().NoError(err) - - prepAliceMessengersForPairing(&s.Suite, alice1, alice2) - - pairTwoDevices(&s.Suite, alice1, alice2) - pairTwoDevices(&s.Suite, alice2, alice1) - - bob := s.newMessenger(s.shh) - _, err = bob.Start() - s.Require().NoError(err) - - contactID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) - myID := types.EncodeHex(crypto.FromECDSAPub(&alice1.identity.PublicKey)) - - request := &requests.AddContact{ - ID: contactID, - } - - // Send contact request - _, err = alice1.AddContact(context.Background(), request) - s.Require().NoError(err) - - // it should show up on device 2 - resp, err := WaitOnMessengerResponse( - alice2, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 - }, - "no messages", - ) - s.Require().NoError(err) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(resp.Contacts[0].ContactRequestLocalState, ContactRequestStateSent) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - bob, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 && len(r.Messages()) > 0 && len(r.ActivityCenterNotifications()) > 0 - }, - "no messages", - ) - - // Check contact request has been received - s.Require().NoError(err) - - // Check activity center notification is of the right type - s.Require().Len(resp.ActivityCenterNotifications(), 1) - s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) - s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - s.Require().Equal(common.ContactRequestStatePending, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) - - // Accept latest contact request, receiver side - resp, err = bob.AcceptLatestContactRequestForContact(context.Background(), &requests.AcceptLatestContactRequestForContact{ID: types.Hex2Bytes(myID)}) - s.Require().NoError(err) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) - - // Make sure the sender is added to our contacts - contacts := bob.AddedContacts() - s.Require().Len(contacts, 1) - - // Make sure we consider them a mutual contact, receiver side - mutualContacts := bob.MutualContacts() - s.Require().Len(mutualContacts, 1) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - alice1, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 - }, - "no messages", - ) - s.Require().NoError(err) - - // Make sure we consider them a mutual contact, sender side - mutualContacts = alice1.MutualContacts() - s.Require().Len(mutualContacts, 1) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) - - // Wait for the message to reach its destination - resp, err = WaitOnMessengerResponse( - alice2, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 - }, - "no messages", - ) - s.Require().NoError(err) - - // Make sure we consider them a mutual contact, sender side - mutualContacts = alice2.MutualContacts() - s.Require().Len(mutualContacts, 1) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) - - resp, err = alice1.RetractContactRequest(&requests.RetractContactRequest{ID: types.Hex2Bytes(bob.myHexIdentity())}) - s.Require().NoError(err) - s.Require().NotNil(resp) - s.Require().Len(resp.Contacts, 1) - s.Require().False(resp.Contacts[0].hasAddedUs()) - s.Require().False(resp.Contacts[0].added()) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestLocalState) - s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestRemoteState) - - // Check on bob side - resp, err = WaitOnMessengerResponse( - bob, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 - }, - "no messages", - ) - s.Require().NoError(err) - s.Require().NotNil(resp) - s.Require().Len(resp.Contacts, 1) - - // Check the contact state is correctly set - s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestLocalState) - s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestRemoteState) - - // Check on alice2 side - resp, err = WaitOnMessengerResponse( - alice2, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 - }, - "no messages", - ) - s.Require().NoError(err) - s.Require().NotNil(resp) - s.Require().Len(resp.Contacts, 1) - - // Check the contact state is correctly set - s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestLocalState) - s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestRemoteState) -} - -// The scenario tested is as follow: -// 1) Alice sends a contact request to Bob -// 2) Bob accepts the contact request -// 3) Alice restores state on a different device -// 4) Alice sends a contact request to bob -// Bob will need to help Alice recover her state, since as far as he can see -// that's an already accepted contact request -func (s *MessengerContactRequestSuite) TestAliceRecoverStateSendContactRequest() { - // Alice sends a contact request to bob - alice1 := s.m - - bob := s.newMessenger(s.shh) - _, err := bob.Start() - s.Require().NoError(err) - - bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) - myID := types.EncodeHex(crypto.FromECDSAPub(&alice1.identity.PublicKey)) - - request := &requests.AddContact{ - ID: bobID, - } - - _, err = alice1.AddContact(context.Background(), request) - s.Require().NoError(err) - - // Wait for the message to reach its destination - resp, err := WaitOnMessengerResponse( - bob, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 && len(r.Messages()) > 0 && len(r.ActivityCenterNotifications()) > 0 - }, - "no messages", - ) - - // Check contact request has been received - s.Require().NoError(err) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) - - // Bob accepts the contact request - _, err = bob.AcceptLatestContactRequestForContact(context.Background(), &requests.AcceptLatestContactRequestForContact{ID: types.Hex2Bytes(myID)}) - s.Require().NoError(err) - - // Alice receives the accepted confirmation - resp, err = WaitOnMessengerResponse( - alice1, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 - }, - "no messages", - ) - s.Require().NoError(err) - - // Make sure we consider them a mutual contact, sender side - mutualContacts := alice1.MutualContacts() - s.Require().Len(mutualContacts, 1) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) - - // Alice resets her device - alice2, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, nil) - s.Require().NoError(err) - - _, err = alice2.Start() - s.Require().NoError(err) - - // adds bob again to her device - request = &requests.AddContact{ - ID: bobID, - } - - _, err = alice2.AddContact(context.Background(), request) - s.Require().NoError(err) - - // Wait for the message to reach its destination - _, err = WaitOnMessengerResponse( - bob, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 - }, - "no messages", - ) - s.Require().NoError(err) - - // Bob should be a mutual contact with alice, nothing has changed - s.Require().Len(bob.MutualContacts(), 1) - - // Alice retrieves her messages, she should have been notified by - // dear bobby that they were contacts - resp, err = WaitOnMessengerResponse( - alice2, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 - }, - "no messages", - ) - s.Require().NoError(err) - s.Require().NotNil(resp) - s.Require().Len(resp.Contacts, 1) - - // Check the contact state is correctly set - s.Require().True(resp.Contacts[0].mutual()) -} - -// The scenario tested is as follow: -// 1) Alice sends a contact request to Bob -// 2) Bob accepts the contact request -// 3) Alice restores state on a different device -// 4) Bob sends a message to alice -// Alice will show a contact request from bob -func (s *MessengerContactRequestSuite) TestAliceRecoverStateReceiveContactRequest() { - // Alice sends a contact request to bob - alice1 := s.m - - bob := s.newMessenger(s.shh) - _, err := bob.Start() - s.Require().NoError(err) - - bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) - myID := types.EncodeHex(crypto.FromECDSAPub(&alice1.identity.PublicKey)) - - request := &requests.AddContact{ - ID: bobID, - } - - _, err = alice1.AddContact(context.Background(), request) - s.Require().NoError(err) - - // Wait for the message to reach its destination - resp, err := WaitOnMessengerResponse( - bob, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 && len(r.Messages()) > 0 && len(r.ActivityCenterNotifications()) > 0 - }, - "no messages", - ) - - // Check contact request has been received - s.Require().NoError(err) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) - - // Bob accepts the contact request - _, err = bob.AcceptLatestContactRequestForContact(context.Background(), &requests.AcceptLatestContactRequestForContact{ID: types.Hex2Bytes(myID)}) - s.Require().NoError(err) - - // Alice receives the accepted confirmation - resp, err = WaitOnMessengerResponse( - alice1, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 - }, - "no messages", - ) - s.Require().NoError(err) - - // Make sure we consider them a mutual contact, sender side - mutualContacts := alice1.MutualContacts() - s.Require().Len(mutualContacts, 1) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) - - // Alice resets her device - alice2, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, nil) - s.Require().NoError(err) - - _, err = alice2.Start() - s.Require().NoError(err) - - // We want to facilitate the discovery of the x3dh bundl here, since bob does not know about alice device - - alice2Bundle, err := alice2.encryptor.GetBundle(alice2.identity) - s.Require().NoError(err) - - _, err = bob.encryptor.ProcessPublicBundle(bob.identity, alice2Bundle) - s.Require().NoError(err) - - // Bob sends a chat message to alice - - var chat Chat - chats := bob.Chats() - for i, c := range chats { - if c.ID == alice1.myHexIdentity() && c.OneToOne() { - chat = *chats[i] - } - } - s.Require().NotNil(chat) - - inputMessage := buildTestMessage(chat) - _, err = bob.SendChatMessage(context.Background(), inputMessage) - s.NoError(err) - - // Alice retrieves the chat message, it should be - resp, err = WaitOnMessengerResponse( - alice2, - func(r *MessengerResponse) bool { - return len(r.ActivityCenterNotifications()) == 1 - }, - "no messages", - ) - s.Require().NoError(err) - s.Require().NotNil(resp) - s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) - s.Require().Len(resp.Contacts, 1) - - // Check the contact state is correctly set - s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestLocalState) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) -} - -// The scenario tested is as follow: -// 1) Alice sends a contact request to Bob -// 2) Bob accepts the contact request -// 3) Bob goes offline -// 4) Alice retracts the contact request -// 5) Alice adds bob back to her contacts -// 6) Bob goes online, they receive 4 and 5 in the correct order -func (s *MessengerContactRequestSuite) TestAliceOfflineRetractsAndAddsCorrectOrder() { - // Alice sends a contact request to bob - alice1 := s.m - - bob := s.newMessenger(s.shh) - _, err := bob.Start() - s.Require().NoError(err) - - bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) - myID := types.EncodeHex(crypto.FromECDSAPub(&alice1.identity.PublicKey)) - - request := &requests.AddContact{ - ID: bobID, - } - - _, err = alice1.AddContact(context.Background(), request) - s.Require().NoError(err) - - // Wait for the message to reach its destination - resp, err := WaitOnMessengerResponse( - bob, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 && len(r.Messages()) > 0 && len(r.ActivityCenterNotifications()) > 0 - }, - "no messages", - ) - - // Check contact request has been received - s.Require().NoError(err) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) - - // Bob accepts the contact request - _, err = bob.AcceptLatestContactRequestForContact(context.Background(), &requests.AcceptLatestContactRequestForContact{ID: types.Hex2Bytes(myID)}) - s.Require().NoError(err) - - // Alice receives the accepted confirmation - resp, err = WaitOnMessengerResponse( - alice1, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 - }, - "no messages", - ) - s.Require().NoError(err) - - // Make sure we consider them a mutual contact, sender side - mutualContacts := alice1.MutualContacts() - s.Require().Len(mutualContacts, 1) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) - - _, err = alice1.RetractContactRequest(&requests.RetractContactRequest{ID: types.Hex2Bytes(bob.myHexIdentity())}) - s.Require().NoError(err) - - // adds bob again to her device - request = &requests.AddContact{ - ID: bobID, - } - - _, err = alice1.AddContact(context.Background(), request) - s.Require().NoError(err) - - // Wait for the message to reach its destination - _, err = WaitOnMessengerResponse( - bob, - func(r *MessengerResponse) bool { - return len(r.ActivityCenterNotifications()) > 0 - }, - "no messages", - ) - s.Require().NoError(err) - -} - -// The scenario tested is as follow: -// 1) Alice sends a contact request to Bob -// 2) Bob accepts the contact request -// 3) Bob goes offline -// 4) Alice retracts the contact request -// 5) Alice adds bob back to her contacts -// 6) Bob goes online, they receive 4 and 5 in the wrong order -func (s *MessengerContactRequestSuite) TestAliceOfflineRetractsAndAddsWrongOrder() { - // Alice sends a contact request to bob - alice1 := s.m - - bob := s.newMessenger(s.shh) - _, err := bob.Start() - s.Require().NoError(err) - - bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) - myID := types.EncodeHex(crypto.FromECDSAPub(&alice1.identity.PublicKey)) - - request := &requests.AddContact{ - ID: bobID, - } - - _, err = alice1.AddContact(context.Background(), request) - s.Require().NoError(err) - - // Wait for the message to reach its destination - resp, err := WaitOnMessengerResponse( - bob, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 && len(r.Messages()) > 0 && len(r.ActivityCenterNotifications()) > 0 - }, - "no messages", - ) - - // Check contact request has been received - s.Require().NoError(err) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) - - // Bob accepts the contact request - _, err = bob.AcceptLatestContactRequestForContact(context.Background(), &requests.AcceptLatestContactRequestForContact{ID: types.Hex2Bytes(myID)}) - s.Require().NoError(err) - - // Alice receives the accepted confirmation - resp, err = WaitOnMessengerResponse( - alice1, - func(r *MessengerResponse) bool { - return len(r.Contacts) > 0 - }, - "no messages", - ) - s.Require().NoError(err) - - // Make sure we consider them a mutual contact, sender side - mutualContacts := alice1.MutualContacts() - s.Require().Len(mutualContacts, 1) - - // Check the contact state is correctly set - s.Require().Len(resp.Contacts, 1) - s.Require().True(resp.Contacts[0].mutual()) - - _, err = alice1.RetractContactRequest(&requests.RetractContactRequest{ID: types.Hex2Bytes(bob.myHexIdentity())}) - s.Require().NoError(err) - - // adds bob again to her device - request = &requests.AddContact{ - ID: bobID, - } - - _, err = alice1.AddContact(context.Background(), request) - s.Require().NoError(err) - - // Get alice perspective of bob - bobFromAlice := alice1.AddedContacts()[0] - - // Get bob perspective of alice - aliceFromBob := bob.MutualContacts()[0] - - s.Require().NotNil(bobFromAlice) - s.Require().NotNil(aliceFromBob) - - // We can't simulate out-of-order messages easily, so we need to do - // things manually here - - result := aliceFromBob.ContactRequestPropagatedStateReceived(bobFromAlice.ContactRequestPropagatedState()) - s.Require().True(result.newContactRequestReceived) - -} - -func (s *MessengerContactRequestSuite) TestBuildContact() { - contactID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) - contact, err := s.m.BuildContact(&requests.BuildContact{PublicKey: contactID}) - s.Require().NoError(err) - - s.Require().Equal(contact.EnsName, "") - s.Require().False(contact.ENSVerified) - - contact, err = s.m.BuildContact(&requests.BuildContact{PublicKey: contactID, ENSName: "foobar"}) - s.Require().NoError(err) - - s.Require().Equal(contact.EnsName, "foobar") - s.Require().True(contact.ENSVerified) -} diff --git a/protocol/messenger_contact_verification_test.go b/protocol/messenger_contact_verification_test.go index 98a78733b..d23dd22d2 100644 --- a/protocol/messenger_contact_verification_test.go +++ b/protocol/messenger_contact_verification_test.go @@ -135,7 +135,7 @@ func (s *MessengerVerificationRequests) mutualContact(theirMessenger *Messenger) resp, err = WaitOnMessengerResponse( s.m, func(r *MessengerResponse) bool { - return len(r.Contacts) == 1 && len(r.Messages()) == 2 && len(r.ActivityCenterNotifications()) == 1 + return len(r.Contacts) == 1 && len(r.Messages()) == 1 && len(r.ActivityCenterNotifications()) == 1 }, "no messages", ) @@ -148,18 +148,9 @@ func (s *MessengerVerificationRequests) mutualContact(theirMessenger *Messenger) // Make sure the message is updated, sender s2de s.Require().NotNil(resp) - s.Require().Len(resp.Messages(), 2) - var message *common.Message - - for _, m := range resp.Messages() { - if m.ID == contactRequests[0].ID { - message = m - } - } - s.Require().NotNil(message) - - s.Require().Equal(message.ID, contactRequests[0].ID) - s.Require().Equal(common.ContactRequestStateAccepted, message.ContactRequestState) + s.Require().Len(resp.Messages(), 1) + s.Require().Equal(resp.Messages()[0].ID, contactRequests[0].ID) + s.Require().Equal(common.ContactRequestStateAccepted, resp.Messages()[0].ContactRequestState) // Make sure we consider them a mutual contact, sender side mutualContacts = s.m.MutualContacts() @@ -168,7 +159,6 @@ func (s *MessengerVerificationRequests) mutualContact(theirMessenger *Messenger) // Check the contact state is correctly set s.Require().Len(resp.Contacts, 1) s.Require().True(resp.Contacts[0].mutual()) - } func (s *MessengerVerificationRequests) TestAcceptVerificationRequests() { diff --git a/protocol/messenger_contacts.go b/protocol/messenger_contacts.go index 63528ff3d..2301f6178 100644 --- a/protocol/messenger_contacts.go +++ b/protocol/messenger_contacts.go @@ -16,7 +16,7 @@ import ( "github.com/status-im/status-go/protocol/transport" ) -func (m *Messenger) acceptContactRequest(requestID string, syncing bool) (*MessengerResponse, error) { +func (m *Messenger) acceptContactRequest(ctx context.Context, requestID string, syncing bool) (*MessengerResponse, error) { contactRequest, err := m.persistence.MessageByID(requestID) if err != nil { m.logger.Error("could not find contact request message", zap.Error(err)) @@ -24,9 +24,30 @@ func (m *Messenger) acceptContactRequest(requestID string, syncing bool) (*Messe } m.logger.Info("acceptContactRequest") - // We send a contact update for compatibility with 0.90 desktop, once that's - // not an issue anymore, we can set the last bool flag to `false` - return m.addContact(contactRequest.From, "", "", "", contactRequest.ID, "", syncing, true, false) + + response, err := m.addContact(ctx, contactRequest.From, "", "", "", contactRequest.ID, "", syncing, false, false) + if err != nil { + return nil, err + } + + // Force activate chat + chat, ok := m.allChats.Load(contactRequest.From) + if !ok { + publicKey, err := common.HexToPubkey(contactRequest.From) + if err != nil { + return nil, err + } + + chat = OneToOneFromPublicKey(publicKey, m.getTimesource()) + } + + chat.Active = true + if err := m.saveChat(chat); err != nil { + return nil, err + } + response.AddChat(chat) + + return response, nil } func (m *Messenger) AcceptContactRequest(ctx context.Context, request *requests.AcceptContactRequest) (*MessengerResponse, error) { @@ -35,7 +56,7 @@ func (m *Messenger) AcceptContactRequest(ctx context.Context, request *requests. return nil, err } - response, err := m.acceptContactRequest(request.ID.String(), false) + response, err := m.acceptContactRequest(ctx, request.ID.String(), false) if err != nil { return nil, err } @@ -89,6 +110,7 @@ func (m *Messenger) declineContactRequest(requestID string, syncing bool) (*Mess return nil, err } if notification != nil { + notification.Name = contact.PrimaryName() notification.Message = contactRequest notification.Read = true notification.Dismissed = true @@ -133,7 +155,8 @@ func (m *Messenger) SendContactRequest(ctx context.Context, request *requests.Se return nil, err } - response, err := m.addContact( + return m.addContact( + ctx, chatID, "", "", @@ -142,50 +165,8 @@ func (m *Messenger) SendContactRequest(ctx context.Context, request *requests.Se request.Message, false, false, - false, + true, ) - if err != nil { - return nil, err - } - - publicKey, err := common.HexToPubkey(chatID) - if err != nil { - return nil, err - } - - // A valid added chat is required. - _, ok := m.allChats.Load(chatID) - if !ok { - // Create a one to one chat and set active to false - chat := CreateOneToOneChat(chatID, publicKey, m.getTimesource()) - chat.Active = false - err = m.initChatSyncFields(chat) - if err != nil { - return nil, err - } - err = m.saveChat(chat) - if err != nil { - return nil, err - } - } - - chatMessage := &common.Message{} - chatMessage.ChatId = chatID - chatMessage.Text = request.Message - chatMessage.ContentType = protobuf.ChatMessage_CONTACT_REQUEST - chatMessage.ContactRequestState = common.ContactRequestStatePending - - messageResponse, err := m.sendChatMessage(ctx, chatMessage) - if err != nil { - return nil, err - } - - err = response.Merge(messageResponse) - if err != nil { - return nil, err - } - - return response, nil } func (m *Messenger) updateAcceptedContactRequest(response *MessengerResponse, contactRequestID string) (*MessengerResponse, error) { @@ -239,6 +220,7 @@ func (m *Messenger) updateAcceptedContactRequest(response *MessengerResponse, co } if notification != nil { + notification.Name = contact.PrimaryName() notification.Message = contactRequest notification.Read = true notification.Accepted = true @@ -256,7 +238,7 @@ func (m *Messenger) updateAcceptedContactRequest(response *MessengerResponse, co return response, nil } -func (m *Messenger) addContact(pubKey, ensName, nickname, displayName, contactRequestID string, contactRequestText string, syncing bool, sendContactUpdate bool, createOutgoingContactRequestNotification bool) (*MessengerResponse, error) { +func (m *Messenger) addContact(ctx context.Context, pubKey, ensName, nickname, displayName, contactRequestID string, contactRequestText string, syncing bool, sendContactUpdate bool, createOutgoingContactRequestNotification bool) (*MessengerResponse, error) { contact, err := m.BuildContact(&requests.BuildContact{PublicKey: pubKey}) if err != nil { return nil, err @@ -323,6 +305,7 @@ func (m *Messenger) addContact(pubKey, ensName, nickname, displayName, contactRe if err != nil { return nil, err } + if err := m.saveChat(profileChat); err != nil { return nil, err } @@ -403,13 +386,17 @@ func (m *Messenger) addContact(pubKey, ensName, nickname, displayName, contactRe // Add outgoing contact request notification if createOutgoingContactRequestNotification { clock, timestamp := chat.NextClockAndTimestamp(m.transport) - contactRequest, err := m.generateContactRequest(clock, timestamp, contact, contactRequestText) + contactRequest, err := m.generateContactRequest(clock, timestamp, contact, contactRequestText, true) if err != nil { return nil, err } - response.AddMessage(contactRequest) - err = m.persistence.SaveMessages([]*common.Message{contactRequest}) + messageResponse, err := m.sendChatMessage(ctx, contactRequest) + if err != nil { + return nil, err + } + + err = response.Merge(messageResponse) if err != nil { return nil, err } @@ -423,24 +410,27 @@ func (m *Messenger) addContact(pubKey, ensName, nickname, displayName, contactRe // Add contact response.AddContact(contact) - return response, nil } -func (m *Messenger) generateContactRequest(clock uint64, timestamp uint64, contact *Contact, text string) (*common.Message, error) { +func (m *Messenger) generateContactRequest(clock uint64, timestamp uint64, contact *Contact, text string, outgoing bool) (*common.Message, error) { if contact == nil { return nil, errors.New("contact cannot be nil") } contactRequest := &common.Message{} + contactRequest.ChatId = contact.ID contactRequest.WhisperTimestamp = timestamp contactRequest.Seen = true contactRequest.Text = text - contactRequest.From = contact.ID + if outgoing { + contactRequest.From = m.myHexIdentity() + } else { + contactRequest.From = contact.ID + } contactRequest.LocalChatID = contact.ID contactRequest.ContentType = protobuf.ChatMessage_CONTACT_REQUEST contactRequest.Clock = clock - contactRequest.ID = defaultContactRequestID(contact.ID) if contact.mutual() { contactRequest.ContactRequestState = common.ContactRequestStateAccepted } else { @@ -459,7 +449,9 @@ func (m *Messenger) generateOutgoingContactRequestNotification(contact *Contact, Message: contactRequest, Timestamp: m.getTimesource().GetCurrentTime(), ChatID: contact.ID, - Read: contactRequest.ContactRequestState == common.ContactRequestStateAccepted || contactRequest.ContactRequestState == common.ContactRequestStateDismissed, + Read: contactRequest.ContactRequestState == common.ContactRequestStateAccepted || + contactRequest.ContactRequestState == common.ContactRequestStateDismissed || + contactRequest.ContactRequestState == common.ContactRequestStatePending, Accepted: contactRequest.ContactRequestState == common.ContactRequestStateAccepted, Dismissed: contactRequest.ContactRequestState == common.ContactRequestStateDismissed, } @@ -477,6 +469,7 @@ func (m *Messenger) AddContact(ctx context.Context, request *requests.AddContact } return m.addContact( + ctx, id, request.ENSName, request.Nickname, @@ -944,9 +937,6 @@ func (m *Messenger) AcceptLatestContactRequestForContact(ctx context.Context, re if err != nil { return nil, err } - if contactRequestID == "" { - contactRequestID = defaultContactRequestID(request.ID.String()) - } return m.AcceptContactRequest(ctx, &requests.AcceptContactRequest{ID: types.Hex2Bytes(contactRequestID)}) } @@ -961,10 +951,6 @@ func (m *Messenger) DismissLatestContactRequestForContact(ctx context.Context, r return nil, err } - if contactRequestID == "" { - contactRequestID = defaultContactRequestID(request.ID.String()) - } - return m.DeclineContactRequest(ctx, &requests.DeclineContactRequest{ID: types.Hex2Bytes(contactRequestID)}) } diff --git a/protocol/messenger_handler.go b/protocol/messenger_handler.go index e8fd00480..d3bbd2c85 100644 --- a/protocol/messenger_handler.go +++ b/protocol/messenger_handler.go @@ -270,8 +270,33 @@ func (m *Messenger) PendingNotificationContactRequest(contactID string) (*Activi return m.persistence.ActiveContactRequestNotification(contactID) } +func (m *Messenger) createContactRequestForContactUpdate(contact *Contact, messageState *ReceivedMessageState) (*common.Message, error) { + contactRequest, err := m.generateContactRequest( + messageState.CurrentMessageState.Message.Clock, + messageState.CurrentMessageState.WhisperTimestamp, + contact, + "Please add me to your contacts", + false, + ) + if err != nil { + return nil, err + } + + contactRequest.ID = defaultContactRequestID(contact.ID) + + // save this message + messageState.Response.AddMessage(contactRequest) + err = m.persistence.SaveMessages([]*common.Message{contactRequest}) + + if err != nil { + return nil, err + } + + return contactRequest, nil +} + func (m *Messenger) createIncomingContactRequestNotification(contact *Contact, messageState *ReceivedMessageState, contactRequest *common.Message, createNewNotification bool) error { - if contactRequest != nil && contactRequest.ContactRequestState == common.ContactRequestStateAccepted { + if contactRequest.ContactRequestState == common.ContactRequestStateAccepted { // Pull one from the db if there notification, err := m.persistence.GetActivityCenterNotificationByID(types.FromHex(contactRequest.ID)) if err != nil { @@ -279,6 +304,7 @@ func (m *Messenger) createIncomingContactRequestNotification(contact *Contact, m } if notification != nil { + notification.Name = contact.PrimaryName() notification.Message = contactRequest notification.Read = true notification.Accepted = true @@ -293,82 +319,6 @@ func (m *Messenger) createIncomingContactRequestNotification(contact *Contact, m return nil } - if contactRequest == nil || contactRequest.ContactRequestState == common.ContactRequestStatePending { - notification, err := m.PendingNotificationContactRequest(contact.ID) - if err != nil { - return err - } - - // If there's already a notification, we will check whether is a default notification - // that has not been dismissed (nor accepted???) - // If it is, we replace it with a non-default, since it contains a message - if notification != nil { - // Check if it's the default notification - if notification.Message.ID == defaultContactRequestID(contact.ID) { - // Nothing to do, we already have a default notification - if contactRequest == nil { - return nil - } - // We first dismiss it in the database - err := m.persistence.DismissActivityCenterNotifications([]types.HexBytes{types.Hex2Bytes(notification.Message.ID)}) - if err != nil { - return err - } - // we mark the notification as dismissed & read - notification.Dismissed = true - notification.Read = true - // We remove it from the response, since the client has never seen it, better to just remove it - found := messageState.Response.RemoveActivityCenterNotification(notification.Message.ID) - // Otherwise, it means we have already passed it to the client, so we add it with a `dismissed` flag - // so it can clean up - if !found { - messageState.Response.AddActivityCenterNotification(notification) - } - } - } - } - - // Legacy//ContactUpdate contact request - if contactRequest == nil { - if messageState.CurrentMessageState == nil || messageState.CurrentMessageState.MessageID == "" { - return errors.New("no available id") - } - // We use a known id so that we can check if already in the database - defaultID := defaultContactRequestID(contact.ID) - - // Pull one from the db if there - notification, err := m.persistence.GetActivityCenterNotificationByID(types.FromHex(defaultID)) - if err != nil { - return err - } - - // if the notification is accepted, we clear it, as this one will replace it - if notification != nil && notification.Accepted { - err = m.persistence.DeleteActivityCenterNotification(types.FromHex(defaultID)) - if err != nil { - return err - } - } - - // generate request message - contactRequest, err = m.generateContactRequest( - messageState.CurrentMessageState.Message.Clock, - messageState.CurrentMessageState.WhisperTimestamp, - contact, - "Please add me to your contacts", - ) - if err != nil { - return err - } - - // save this message - messageState.Response.AddMessage(contactRequest) - err = m.persistence.SaveMessages([]*common.Message{contactRequest}) - if err != nil { - return err - } - } - if !createNewNotification { return nil } @@ -829,7 +779,7 @@ func (m *Messenger) handleAcceptContactRequestMessage(state *ReceivedMessageStat // If the state has changed from non-mutual contact, to mutual contact // we want to notify the user - if processingResponse.newContactRequestReceived && contact.mutual() { + if contact.mutual() { // We set the chat as active, this is currently the expected behavior // for mobile, it might change as we implement further the activity // center @@ -874,14 +824,7 @@ func (m *Messenger) handleAcceptContactRequestMessage(state *ReceivedMessageStat } func (m *Messenger) HandleAcceptContactRequest(state *ReceivedMessageState, message protobuf.AcceptContactRequest, senderID string) error { - // outgoing contact requests are created on the side of a sender - err := m.handleAcceptContactRequestMessage(state, message.Clock, defaultContactRequestID(senderID), true) - if err != nil { - m.logger.Warn("could not accept contact request", zap.Error(err)) - } - - // legacy contact requests: the ones that are send with SendContactRequest - err = m.handleAcceptContactRequestMessage(state, message.Clock, message.Id, false) + err := m.handleAcceptContactRequestMessage(state, message.Clock, message.Id, false) if err != nil { m.logger.Warn("could not accept contact request", zap.Error(err)) } @@ -965,12 +908,17 @@ func (m *Messenger) HandleContactUpdate(state *ReceivedMessageState, message pro } if result.newContactRequestReceived { - err = m.createIncomingContactRequestNotification(contact, state, nil, true) + contactRequest, err := m.createContactRequestForContactUpdate(contact, state) if err != nil { return err } + err = m.createIncomingContactRequestNotification(contact, state, contactRequest, true) + if err != nil { + return err + } } + logger.Debug("handled propagated state", zap.Any("state after update", contact.ContactRequestPropagatedState())) state.ModifiedContacts.Store(contact.ID, true) state.AllContacts.Store(contact.ID, contact)