diff --git a/protocol/communities/manager.go b/protocol/communities/manager.go index 71dd392c0..9725039f9 100644 --- a/protocol/communities/manager.go +++ b/protocol/communities/manager.go @@ -2853,7 +2853,7 @@ func (m *Manager) HandleCommunityRequestToJoinResponse(signer *ecdsa.PublicKey, return nil, err } - isControlNodeSigner := common.IsPubKeyEqual(community.PublicKey(), signer) + isControlNodeSigner := common.IsPubKeyEqual(community.ControlNode(), signer) if !isControlNodeSigner { return nil, ErrNotAuthorized } diff --git a/protocol/communities_messenger_signers_test.go b/protocol/communities_messenger_signers_test.go index 747f82eee..f15bcfdc2 100644 --- a/protocol/communities_messenger_signers_test.go +++ b/protocol/communities_messenger_signers_test.go @@ -1,6 +1,7 @@ package protocol import ( + "context" "crypto/ecdsa" "testing" "time" @@ -451,3 +452,102 @@ func (s *MessengerCommunitiesSignersSuite) TestAutoAcceptOnOwnershipChangeReques // s.Require().False(community.IsControlNode()) // s.Require().False(community.IsOwner()) } + +func (s *MessengerCommunitiesSignersSuite) TestNewOwnerAcceptRequestToJoin() { + // Create a community + // Transfer ownership + // New owner accepts new request to join + community := s.createCommunity(s.john) + + s.advertiseCommunityTo(s.john, community, s.alice) + + s.joinCommunity(s.john, community, s.alice) + + // john mints owner token + var chainID uint64 = 1 + tokenAddress := "token-address" + tokenName := "tokenName" + tokenSymbol := "TSM" + _, err := s.john.SaveCommunityToken(&token.CommunityToken{ + TokenType: protobuf.CommunityTokenType_ERC721, + CommunityID: community.IDString(), + Address: tokenAddress, + ChainID: int(chainID), + Name: tokenName, + Supply: &bigint.BigInt{}, + Symbol: tokenSymbol, + PrivilegesLevel: token.OwnerLevel, + }, nil) + s.Require().NoError(err) + + // john adds minted owner token to community + err = s.john.AddCommunityToken(community.IDString(), int(chainID), tokenAddress) + s.Require().NoError(err) + + // update mock - the signer for the community returned by the contracts should be john + s.collectiblesServiceMock.SetSignerPubkeyForCommunity(community.ID(), common.PubkeyToHex(&s.john.identity.PublicKey)) + s.collectiblesServiceMock.SetMockCollectibleContractData(chainID, tokenAddress, + &communitytokens.CollectibleContractData{TotalSupply: &bigint.BigInt{}}) + + // alice accepts community update + _, err = WaitOnSignaledMessengerResponse( + s.alice, + func(r *MessengerResponse) bool { + return len(r.Communities()) > 0 && len(r.Communities()[0].TokenPermissions()) == 1 + }, + "no communities", + ) + s.Require().NoError(err) + + // Ownership token will be transferred to Alice and she will kick all members + // and request kicked members to rejoin + // the signer for the community returned by the contracts should be alice + s.collectiblesServiceMock.SetSignerPubkeyForCommunity(community.ID(), common.PubkeyToHex(&s.alice.identity.PublicKey)) + + response, err := s.alice.PromoteSelfToControlNode(community.ID()) + s.Require().NoError(err) + s.Require().NotNil(response) + + community, err = s.alice.communitiesManager.GetByID(community.ID()) + s.Require().NoError(err) + s.Require().True(community.IsControlNode()) + s.Require().True(common.IsPubKeyEqual(community.ControlNode(), &s.alice.identity.PublicKey)) + s.Require().True(community.IsOwner()) + + // check that John received kick event, also he will receive + // request to share RevealedAddresses and send request to join to the control node + _, err = WaitOnSignaledMessengerResponse( + s.john, + func(r *MessengerResponse) bool { + return len(r.Communities()) > 0 && !r.Communities()[0].HasMember(&s.john.identity.PublicKey) + }, + "John was not kicked from the community", + ) + s.Require().NoError(err) + + // Alice advertises community to Bob + chat := CreateOneToOneChat(common.PubkeyToHex(&s.bob.identity.PublicKey), &s.bob.identity.PublicKey, s.bob.transport) + + inputMessage := common.NewMessage() + inputMessage.ChatId = chat.ID + inputMessage.Text = "some text" + inputMessage.CommunityID = community.IDString() + + err = s.alice.SaveChat(chat) + s.Require().NoError(err) + _, err = s.alice.SendChatMessage(context.Background(), inputMessage) + s.Require().NoError(err) + + _, err = WaitOnSignaledMessengerResponse( + s.bob, + func(r *MessengerResponse) bool { + return len(r.Communities()) > 0 + }, + "Community was not advertised to Bob", + ) + s.Require().NoError(err) + + // Bob joins the community + s.joinCommunity(s.alice, community, s.bob) + +} diff --git a/protocol/messenger_communities.go b/protocol/messenger_communities.go index 57c5693f7..3be317cad 100644 --- a/protocol/messenger_communities.go +++ b/protocol/messenger_communities.go @@ -1047,12 +1047,11 @@ func (m *Messenger) RequestToJoinCommunity(request *requests.RequestToJoinCommun PubsubTopic: shard.DefaultNonProtectedPubsubTopic(), } - _, err = m.sender.SendCommunityMessage(context.Background(), rawMessage) + _, err = m.SendMessageToControlNode(community, rawMessage) if err != nil { return nil, err } - // send request to join to privileged members if !community.AutoAccept() { privilegedMembers := community.GetFilteredPrivilegedMembers(map[string]struct{}{}) @@ -1202,7 +1201,7 @@ func (m *Messenger) EditSharedAddressesForCommunity(request *requests.EditShared PubsubTopic: community.PubsubTopic(), // TODO: confirm if it should be sent in community pubsub topic } - _, err = m.sender.SendCommunityMessage(context.Background(), rawMessage) + _, err = m.SendMessageToControlNode(community, rawMessage) if err != nil { return nil, err } @@ -1365,8 +1364,8 @@ func (m *Messenger) CancelRequestToJoinCommunity(ctx context.Context, request *r MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_CANCEL_REQUEST_TO_JOIN, PubsubTopic: shard.DefaultNonProtectedPubsubTopic(), } - _, err = m.sender.SendCommunityMessage(context.Background(), rawMessage) + _, err = m.SendMessageToControlNode(community, rawMessage) if err != nil { return nil, err } @@ -1655,7 +1654,8 @@ func (m *Messenger) LeaveCommunity(communityID types.HexBytes) (*MessengerRespon MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_REQUEST_TO_LEAVE, PubsubTopic: community.PubsubTopic(), // TODO: confirm if it should be sent in the community pubsub topic } - _, err = m.sender.SendCommunityMessage(context.Background(), rawMessage) + + _, err = m.SendMessageToControlNode(community, rawMessage) if err != nil { return nil, err } @@ -4200,3 +4200,11 @@ func (m *Messenger) CreateResponseWithACNotification(communityID string, acType return response, nil } + +func (m *Messenger) SendMessageToControlNode(community *communities.Community, rawMessage common.RawMessage) ([]byte, error) { + if !community.PublicKey().Equal(community.ControlNode()) { + return m.sender.SendPrivate(context.Background(), community.ControlNode(), &rawMessage) + } + + return m.sender.SendCommunityMessage(context.Background(), rawMessage) +}