From 475b5f855ff708cc012e6d9845adc51c2b084419 Mon Sep 17 00:00:00 2001 From: yqrashawn Date: Tue, 7 Mar 2023 22:38:09 +0800 Subject: [PATCH] feat: allow group admin to delete others message (#3259) --- VERSION | 2 +- protocol/messenger_group_chat_test.go | 87 +++++++++++++++++++++++++++ protocol/messenger_handler.go | 14 +++-- protocol/messenger_messages.go | 19 +++++- 4 files changed, 115 insertions(+), 7 deletions(-) diff --git a/VERSION b/VERSION index 744a0d69f..7d07dbba4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.137.1 \ No newline at end of file +0.137.2 diff --git a/protocol/messenger_group_chat_test.go b/protocol/messenger_group_chat_test.go index 1bc241719..895ca0241 100644 --- a/protocol/messenger_group_chat_test.go +++ b/protocol/messenger_group_chat_test.go @@ -14,6 +14,7 @@ import ( "github.com/status-im/status-go/eth-node/types" userimage "github.com/status-im/status-go/images" "github.com/status-im/status-go/protocol/common" + "github.com/status-im/status-go/protocol/protobuf" "github.com/status-im/status-go/protocol/tt" "github.com/status-im/status-go/waku" ) @@ -356,3 +357,89 @@ func (s *MessengerGroupChatSuite) TestGroupChatEdit() { defer s.NoError(admin.Shutdown()) defer s.NoError(member.Shutdown()) } + +func (s *MessengerGroupChatSuite) TestGroupChatDeleteMemberMessage() { + admin := s.startNewMessenger() + member := s.startNewMessenger() + s.makeMutualContacts(admin, member) + + groupChat := s.createGroupChat(admin, "test_group_chat", []string{common.PubkeyToHex(&member.identity.PublicKey)}) + s.verifyGroupChatCreated(member, true) + + ctx := context.Background() + inputMessage := buildTestMessage(*groupChat) + _, err := member.SendChatMessage(ctx, inputMessage) + s.Require().NoError(err) + + response, err := WaitOnMessengerResponse( + admin, + func(r *MessengerResponse) bool { return len(r.Messages()) > 0 }, + "messages not received", + ) + s.Require().NoError(err) + s.Require().Len(response.Messages(), 1) + s.Require().Equal(inputMessage.Text, response.Messages()[0].Text) + + message := response.Messages()[0] + deleteMessageResponse, err := admin.DeleteMessageAndSend(ctx, message.ID) + s.Require().NoError(err) + + _, err = WaitOnMessengerResponse(member, func(response *MessengerResponse) bool { + return len(response.RemovedMessages()) > 0 + }, "removed messages not received") + s.Require().Equal(deleteMessageResponse.RemovedMessages()[0].DeletedBy, contactIDFromPublicKey(admin.IdentityPublicKey())) + s.Require().NoError(err) + message, err = member.MessageByID(message.ID) + s.Require().NoError(err) + s.Require().True(message.Deleted) + + defer s.NoError(admin.Shutdown()) + defer s.NoError(member.Shutdown()) +} + +func (s *MessengerGroupChatSuite) TestGroupChatHandleDeleteMemberMessage() { + admin := s.startNewMessenger() + member := s.startNewMessenger() + s.makeMutualContacts(admin, member) + + groupChat := s.createGroupChat(admin, "test_group_chat", []string{common.PubkeyToHex(&member.identity.PublicKey)}) + s.verifyGroupChatCreated(member, true) + + ctx := context.Background() + inputMessage := buildTestMessage(*groupChat) + _, err := member.SendChatMessage(ctx, inputMessage) + s.Require().NoError(err) + + response, err := WaitOnMessengerResponse( + admin, + func(r *MessengerResponse) bool { return len(r.Messages()) > 0 }, + "messages not received", + ) + s.Require().NoError(err) + s.Require().Len(response.Messages(), 1) + s.Require().Equal(inputMessage.Text, response.Messages()[0].Text) + + deleteMessage := DeleteMessage{ + DeleteMessage: protobuf.DeleteMessage{ + Clock: 2, + MessageType: protobuf.MessageType_PRIVATE_GROUP, + MessageId: inputMessage.ID, + ChatId: groupChat.ID, + }, + From: common.PubkeyToHex(&admin.identity.PublicKey), + } + + state := &ReceivedMessageState{ + Response: &MessengerResponse{}, + } + + err = member.HandleDeleteMessage(state, deleteMessage) + s.Require().NoError(err) + + removedMessages := state.Response.RemovedMessages() + s.Require().Len(removedMessages, 1) + s.Require().Equal(removedMessages[0].MessageID, inputMessage.ID) + + defer s.NoError(admin.Shutdown()) + defer s.NoError(member.Shutdown()) +} diff --git a/protocol/messenger_handler.go b/protocol/messenger_handler.go index 54b24fe6c..16d0d7126 100644 --- a/protocol/messenger_handler.go +++ b/protocol/messenger_handler.go @@ -1531,16 +1531,22 @@ func (m *Messenger) HandleDeleteMessage(state *ReceivedMessageState, deleteMessa var canDeleteMessageForEveryone = false if originalMessage.From != deleteMessage.From { + fromPublicKey, err := common.HexToPubkey(deleteMessage.From) + if err != nil { + return err + } if chat.ChatType == ChatTypeCommunityChat { - fromPublicKey, err := common.HexToPubkey(deleteMessage.From) - if err != nil { - return err + canDeleteMessageForEveryone = m.CanDeleteMessageForEveryoneInCommunity(chat.CommunityID, fromPublicKey) + if !canDeleteMessageForEveryone { + return ErrInvalidDeletePermission } - canDeleteMessageForEveryone = m.CanDeleteMessageForEveryone(chat.CommunityID, fromPublicKey) + } else if chat.ChatType == ChatTypePrivateGroupChat { + canDeleteMessageForEveryone = m.CanDeleteMessageForEveryoneInPrivateGroupChat(chat, fromPublicKey) if !canDeleteMessageForEveryone { return ErrInvalidDeletePermission } } + // Check edit is valid if !canDeleteMessageForEveryone { return errors.New("invalid delete, not the right author") diff --git a/protocol/messenger_messages.go b/protocol/messenger_messages.go index bdfac5607..c2572bec1 100644 --- a/protocol/messenger_messages.go +++ b/protocol/messenger_messages.go @@ -90,7 +90,7 @@ func (m *Messenger) EditMessage(ctx context.Context, request *requests.EditMessa return response, nil } -func (m *Messenger) CanDeleteMessageForEveryone(communityID string, publicKey *ecdsa.PublicKey) bool { +func (m *Messenger) CanDeleteMessageForEveryoneInCommunity(communityID string, publicKey *ecdsa.PublicKey) bool { if communityID != "" { community, err := m.communitiesManager.GetByIDString(communityID) if err != nil { @@ -102,6 +102,16 @@ func (m *Messenger) CanDeleteMessageForEveryone(communityID string, publicKey *e return false } +func (m *Messenger) CanDeleteMessageForEveryoneInPrivateGroupChat(chat *Chat, publicKey *ecdsa.PublicKey) bool { + group, err := newProtocolGroupFromChat(chat) + if err != nil { + m.logger.Error("failed to find group", zap.String("chatID", chat.ID), zap.Error(err)) + return false + } + admins := group.Admins() + return stringSliceContains(admins, common.PubkeyToHex(publicKey)) +} + func (m *Messenger) DeleteMessageAndSend(ctx context.Context, messageID string) (*MessengerResponse, error) { message, err := m.persistence.MessageByID(messageID) if err != nil { @@ -119,7 +129,12 @@ func (m *Messenger) DeleteMessageAndSend(ctx context.Context, messageID string) if message.From != common.PubkeyToHex(&m.identity.PublicKey) { if message.MessageType == protobuf.MessageType_COMMUNITY_CHAT { communityID := chat.CommunityID - canDeleteMessageForEveryone = m.CanDeleteMessageForEveryone(communityID, &m.identity.PublicKey) + canDeleteMessageForEveryone = m.CanDeleteMessageForEveryoneInCommunity(communityID, &m.identity.PublicKey) + if !canDeleteMessageForEveryone { + return nil, ErrInvalidDeletePermission + } + } else if message.MessageType == protobuf.MessageType_PRIVATE_GROUP { + canDeleteMessageForEveryone = m.CanDeleteMessageForEveryoneInPrivateGroupChat(chat, &m.identity.PublicKey) if !canDeleteMessageForEveryone { return nil, ErrInvalidDeletePermission }