diff --git a/protocol/communities/community.go b/protocol/communities/community.go index 5da5e0f54..e1da2a9a3 100644 --- a/protocol/communities/community.go +++ b/protocol/communities/community.go @@ -1427,6 +1427,17 @@ func (o *Community) Description() *protobuf.CommunityDescription { return o.config.CommunityDescription } +func (o *Community) EncryptedDescription() (*protobuf.CommunityDescription, error) { + clone := proto.Clone(o.config.CommunityDescription).(*protobuf.CommunityDescription) + if o.encryptor != nil { + err := encryptDescription(o.encryptor, o, clone) + if err != nil { + return nil, err + } + } + return clone, nil +} + func (o *Community) DescriptionProtocolMessage() []byte { return o.config.CommunityDescriptionProtocolMessage } diff --git a/protocol/communities/community_description_encryption.go b/protocol/communities/community_description_encryption.go index 39140d9d1..859bf9df9 100644 --- a/protocol/communities/community_description_encryption.go +++ b/protocol/communities/community_description_encryption.go @@ -1,8 +1,6 @@ package communities import ( - "github.com/golang/protobuf/proto" - "go.uber.org/zap" "github.com/status-im/status-go/eth-node/types" @@ -26,7 +24,7 @@ func encryptDescription(encryptor DescriptionEncryptor, community *Community, de descriptionToEncrypt := &protobuf.CommunityDescription{ Chats: map[string]*protobuf.CommunityChat{ - channelID: proto.Clone(channel).(*protobuf.CommunityChat), + channelID: channel, }, } @@ -42,8 +40,10 @@ func encryptDescription(encryptor DescriptionEncryptor, community *Community, de if community.Encrypted() { descriptionToEncrypt := &protobuf.CommunityDescription{ - Members: description.Members, - Chats: description.Chats, + Members: description.Members, + ActiveMembersCount: description.ActiveMembersCount, + Chats: description.Chats, + Categories: description.Categories, } keyIDSeqNo, encryptedDescription, err := encryptor.encryptCommunityDescription(community, descriptionToEncrypt) @@ -51,10 +51,12 @@ func encryptDescription(encryptor DescriptionEncryptor, community *Community, de return err } - // Set private data and cleanup unencrypted members and chats + // Set private data and cleanup unencrypted members, chats and categories description.PrivateData[keyIDSeqNo] = encryptedDescription description.Members = make(map[string]*protobuf.CommunityMember) + description.ActiveMembersCount = 0 description.Chats = make(map[string]*protobuf.CommunityChat) + description.Categories = make(map[string]*protobuf.CommunityCategory) } return nil @@ -85,11 +87,12 @@ func decryptDescription(id types.HexBytes, encryptor DescriptionEncryptor, descr } decryptedDescription := decryptedDescriptionResponse.Description - for pk, member := range decryptedDescription.Members { - if description.Members == nil { - description.Members = make(map[string]*protobuf.CommunityMember) - } - description.Members[pk] = member + if len(decryptedDescription.Members) > 0 { + description.Members = decryptedDescription.Members + } + + if decryptedDescription.ActiveMembersCount > 0 { + description.ActiveMembersCount = decryptedDescription.ActiveMembersCount } for id, decryptedChannel := range decryptedDescription.Chats { @@ -98,13 +101,17 @@ func decryptDescription(id types.HexBytes, encryptor DescriptionEncryptor, descr } if channel := description.Chats[id]; channel != nil { - if len(channel.Members) == 0 { + if len(decryptedChannel.Members) > 0 { channel.Members = decryptedChannel.Members } } else { description.Chats[id] = decryptedChannel } } + + if len(decryptedDescription.Categories) > 0 { + description.Categories = decryptedDescription.Categories + } } return failedToDecrypt, nil diff --git a/protocol/communities/community_description_encryption_test.go b/protocol/communities/community_description_encryption_test.go index 122c45bf8..fcf255220 100644 --- a/protocol/communities/community_description_encryption_test.go +++ b/protocol/communities/community_description_encryption_test.go @@ -50,13 +50,13 @@ type DescriptionEncryptorMock struct { func (dem *DescriptionEncryptorMock) encryptCommunityDescription(community *Community, d *protobuf.CommunityDescription) (string, []byte, error) { keyIDSeqNo := uuid.New().String() - dem.descriptions[keyIDSeqNo] = d + dem.descriptions[keyIDSeqNo] = proto.Clone(d).(*protobuf.CommunityDescription) return keyIDSeqNo, []byte("encryptedDescription"), nil } func (dem *DescriptionEncryptorMock) encryptCommunityDescriptionChannel(community *Community, channelID string, d *protobuf.CommunityDescription) (string, []byte, error) { keyIDSeqNo := uuid.New().String() - dem.descriptions[keyIDSeqNo] = d + dem.descriptions[keyIDSeqNo] = proto.Clone(d).(*protobuf.CommunityDescription) dem.channelIDToKeyIDSeqNo[channelID] = keyIDSeqNo return keyIDSeqNo, []byte("encryptedDescription"), nil } @@ -86,6 +86,7 @@ func (s *CommunityEncryptionDescriptionSuite) description() *protobuf.CommunityD "memberA": &protobuf.CommunityMember{}, "memberB": &protobuf.CommunityMember{}, }, + ActiveMembersCount: 1, Chats: map[string]*protobuf.CommunityChat{ "channelA": &protobuf.CommunityChat{ Members: map[string]*protobuf.CommunityMember{ @@ -99,6 +100,13 @@ func (s *CommunityEncryptionDescriptionSuite) description() *protobuf.CommunityD }, }, }, + Categories: map[string]*protobuf.CommunityCategory{ + "categoryA": &protobuf.CommunityCategory{ + CategoryId: "categoryA", + Name: "categoryA", + Position: 0, + }, + }, PrivateData: map[string][]byte{}, // ensure community and channel encryption @@ -128,18 +136,23 @@ func (s *CommunityEncryptionDescriptionSuite) TestEncryptionDecryption() { s.Require().NoError(err) s.Require().Len(description.PrivateData, 2) - // members and chats should become empty (encrypted) + // members, chats, categories should become empty (encrypted) s.Require().Empty(description.Members) + s.Require().Empty(description.ActiveMembersCount) s.Require().Empty(description.Chats) + s.Require().Empty(description.Categories) s.Require().Equal(description.IntroMessage, "one of not encrypted fields") // members and chats should be brought back _, err = decryptDescription([]byte("some-id"), s.descriptionEncryptor, description, s.logger) s.Require().NoError(err) s.Require().Len(description.Members, 2) + s.Require().EqualValues(description.ActiveMembersCount, 1) s.Require().Len(description.Chats, 2) s.Require().Len(description.Chats["channelA"].Members, 2) s.Require().Len(description.Chats["channelB"].Members, 1) + s.Require().Len(description.Categories, 1) + s.Require().Equal(description.Categories["categoryA"].Name, "categoryA") s.Require().Equal(description.IntroMessage, "one of not encrypted fields") } @@ -163,19 +176,24 @@ func (s *CommunityEncryptionDescriptionSuite) TestDecryption_NoKeys() { _, err := decryptDescription([]byte("some-id"), s.descriptionEncryptor, description, s.logger) s.Require().NoError(err) s.Require().Len(description.Members, 2) + s.Require().EqualValues(description.ActiveMembersCount, 1) s.Require().Len(description.Chats, 2) s.Require().Len(description.Chats["channelA"].Members, 2) s.Require().Len(description.Chats["channelB"].Members, 0) // encrypted channel + s.Require().Len(description.Categories, 1) + s.Require().Equal(description.Categories["categoryA"].Name, "categoryA") s.Require().Equal(description.IntroMessage, "one of not encrypted fields") description = proto.Clone(encryptedDescription).(*protobuf.CommunityDescription) - // forget the keys, so chats and members can't be decrypted + // forget the keys, so members, chats, categories can't be decrypted s.descriptionEncryptor.forgetAllKeys() - // members and chats should be empty + // members, chats, categories should be empty _, err = decryptDescription([]byte("some-id"), s.descriptionEncryptor, description, s.logger) s.Require().NoError(err) s.Require().Empty(description.Members) + s.Require().Empty(description.ActiveMembersCount) s.Require().Empty(description.Chats) + s.Require().Empty(description.Categories) s.Require().Equal(description.IntroMessage, "one of not encrypted fields") } diff --git a/protocol/messenger_communities.go b/protocol/messenger_communities.go index bc8573e69..ad9d6333b 100644 --- a/protocol/messenger_communities.go +++ b/protocol/messenger_communities.go @@ -1550,11 +1550,16 @@ func (m *Messenger) acceptRequestToJoinCommunity(requestToJoin *communities.Requ } } + encryptedDescription, err := community.EncryptedDescription() + if err != nil { + return nil, err + } + requestToJoinResponseProto := &protobuf.CommunityRequestToJoinResponse{ Clock: community.Clock(), Accepted: true, CommunityId: community.ID(), - Community: community.Description(), + Community: encryptedDescription, Grant: grant, ProtectedTopicPrivateKey: crypto.FromECDSA(key), Shard: community.Shard().Protobuffer(),