fix: encrypt community's Categories and ActiveMembersCount
fixes: #4943 fixes: #4944
This commit is contained in:
parent
894eb5758e
commit
0aed93ff04
|
@ -1427,6 +1427,17 @@ func (o *Community) Description() *protobuf.CommunityDescription {
|
||||||
return o.config.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 {
|
func (o *Community) DescriptionProtocolMessage() []byte {
|
||||||
return o.config.CommunityDescriptionProtocolMessage
|
return o.config.CommunityDescriptionProtocolMessage
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package communities
|
package communities
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
@ -26,7 +24,7 @@ func encryptDescription(encryptor DescriptionEncryptor, community *Community, de
|
||||||
|
|
||||||
descriptionToEncrypt := &protobuf.CommunityDescription{
|
descriptionToEncrypt := &protobuf.CommunityDescription{
|
||||||
Chats: map[string]*protobuf.CommunityChat{
|
Chats: map[string]*protobuf.CommunityChat{
|
||||||
channelID: proto.Clone(channel).(*protobuf.CommunityChat),
|
channelID: channel,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +41,9 @@ func encryptDescription(encryptor DescriptionEncryptor, community *Community, de
|
||||||
if community.Encrypted() {
|
if community.Encrypted() {
|
||||||
descriptionToEncrypt := &protobuf.CommunityDescription{
|
descriptionToEncrypt := &protobuf.CommunityDescription{
|
||||||
Members: description.Members,
|
Members: description.Members,
|
||||||
|
ActiveMembersCount: description.ActiveMembersCount,
|
||||||
Chats: description.Chats,
|
Chats: description.Chats,
|
||||||
|
Categories: description.Categories,
|
||||||
}
|
}
|
||||||
|
|
||||||
keyIDSeqNo, encryptedDescription, err := encryptor.encryptCommunityDescription(community, descriptionToEncrypt)
|
keyIDSeqNo, encryptedDescription, err := encryptor.encryptCommunityDescription(community, descriptionToEncrypt)
|
||||||
|
@ -51,10 +51,12 @@ func encryptDescription(encryptor DescriptionEncryptor, community *Community, de
|
||||||
return err
|
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.PrivateData[keyIDSeqNo] = encryptedDescription
|
||||||
description.Members = make(map[string]*protobuf.CommunityMember)
|
description.Members = make(map[string]*protobuf.CommunityMember)
|
||||||
|
description.ActiveMembersCount = 0
|
||||||
description.Chats = make(map[string]*protobuf.CommunityChat)
|
description.Chats = make(map[string]*protobuf.CommunityChat)
|
||||||
|
description.Categories = make(map[string]*protobuf.CommunityCategory)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -85,11 +87,12 @@ func decryptDescription(id types.HexBytes, encryptor DescriptionEncryptor, descr
|
||||||
}
|
}
|
||||||
decryptedDescription := decryptedDescriptionResponse.Description
|
decryptedDescription := decryptedDescriptionResponse.Description
|
||||||
|
|
||||||
for pk, member := range decryptedDescription.Members {
|
if len(decryptedDescription.Members) > 0 {
|
||||||
if description.Members == nil {
|
description.Members = decryptedDescription.Members
|
||||||
description.Members = make(map[string]*protobuf.CommunityMember)
|
|
||||||
}
|
}
|
||||||
description.Members[pk] = member
|
|
||||||
|
if decryptedDescription.ActiveMembersCount > 0 {
|
||||||
|
description.ActiveMembersCount = decryptedDescription.ActiveMembersCount
|
||||||
}
|
}
|
||||||
|
|
||||||
for id, decryptedChannel := range decryptedDescription.Chats {
|
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 channel := description.Chats[id]; channel != nil {
|
||||||
if len(channel.Members) == 0 {
|
if len(decryptedChannel.Members) > 0 {
|
||||||
channel.Members = decryptedChannel.Members
|
channel.Members = decryptedChannel.Members
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
description.Chats[id] = decryptedChannel
|
description.Chats[id] = decryptedChannel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(decryptedDescription.Categories) > 0 {
|
||||||
|
description.Categories = decryptedDescription.Categories
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return failedToDecrypt, nil
|
return failedToDecrypt, nil
|
||||||
|
|
|
@ -50,13 +50,13 @@ type DescriptionEncryptorMock struct {
|
||||||
|
|
||||||
func (dem *DescriptionEncryptorMock) encryptCommunityDescription(community *Community, d *protobuf.CommunityDescription) (string, []byte, error) {
|
func (dem *DescriptionEncryptorMock) encryptCommunityDescription(community *Community, d *protobuf.CommunityDescription) (string, []byte, error) {
|
||||||
keyIDSeqNo := uuid.New().String()
|
keyIDSeqNo := uuid.New().String()
|
||||||
dem.descriptions[keyIDSeqNo] = d
|
dem.descriptions[keyIDSeqNo] = proto.Clone(d).(*protobuf.CommunityDescription)
|
||||||
return keyIDSeqNo, []byte("encryptedDescription"), nil
|
return keyIDSeqNo, []byte("encryptedDescription"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dem *DescriptionEncryptorMock) encryptCommunityDescriptionChannel(community *Community, channelID string, d *protobuf.CommunityDescription) (string, []byte, error) {
|
func (dem *DescriptionEncryptorMock) encryptCommunityDescriptionChannel(community *Community, channelID string, d *protobuf.CommunityDescription) (string, []byte, error) {
|
||||||
keyIDSeqNo := uuid.New().String()
|
keyIDSeqNo := uuid.New().String()
|
||||||
dem.descriptions[keyIDSeqNo] = d
|
dem.descriptions[keyIDSeqNo] = proto.Clone(d).(*protobuf.CommunityDescription)
|
||||||
dem.channelIDToKeyIDSeqNo[channelID] = keyIDSeqNo
|
dem.channelIDToKeyIDSeqNo[channelID] = keyIDSeqNo
|
||||||
return keyIDSeqNo, []byte("encryptedDescription"), nil
|
return keyIDSeqNo, []byte("encryptedDescription"), nil
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,7 @@ func (s *CommunityEncryptionDescriptionSuite) description() *protobuf.CommunityD
|
||||||
"memberA": &protobuf.CommunityMember{},
|
"memberA": &protobuf.CommunityMember{},
|
||||||
"memberB": &protobuf.CommunityMember{},
|
"memberB": &protobuf.CommunityMember{},
|
||||||
},
|
},
|
||||||
|
ActiveMembersCount: 1,
|
||||||
Chats: map[string]*protobuf.CommunityChat{
|
Chats: map[string]*protobuf.CommunityChat{
|
||||||
"channelA": &protobuf.CommunityChat{
|
"channelA": &protobuf.CommunityChat{
|
||||||
Members: map[string]*protobuf.CommunityMember{
|
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{},
|
PrivateData: map[string][]byte{},
|
||||||
|
|
||||||
// ensure community and channel encryption
|
// ensure community and channel encryption
|
||||||
|
@ -128,18 +136,23 @@ func (s *CommunityEncryptionDescriptionSuite) TestEncryptionDecryption() {
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().Len(description.PrivateData, 2)
|
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.Members)
|
||||||
|
s.Require().Empty(description.ActiveMembersCount)
|
||||||
s.Require().Empty(description.Chats)
|
s.Require().Empty(description.Chats)
|
||||||
|
s.Require().Empty(description.Categories)
|
||||||
s.Require().Equal(description.IntroMessage, "one of not encrypted fields")
|
s.Require().Equal(description.IntroMessage, "one of not encrypted fields")
|
||||||
|
|
||||||
// members and chats should be brought back
|
// members and chats should be brought back
|
||||||
_, err = decryptDescription([]byte("some-id"), s.descriptionEncryptor, description, s.logger)
|
_, err = decryptDescription([]byte("some-id"), s.descriptionEncryptor, description, s.logger)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().Len(description.Members, 2)
|
s.Require().Len(description.Members, 2)
|
||||||
|
s.Require().EqualValues(description.ActiveMembersCount, 1)
|
||||||
s.Require().Len(description.Chats, 2)
|
s.Require().Len(description.Chats, 2)
|
||||||
s.Require().Len(description.Chats["channelA"].Members, 2)
|
s.Require().Len(description.Chats["channelA"].Members, 2)
|
||||||
s.Require().Len(description.Chats["channelB"].Members, 1)
|
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")
|
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)
|
_, err := decryptDescription([]byte("some-id"), s.descriptionEncryptor, description, s.logger)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().Len(description.Members, 2)
|
s.Require().Len(description.Members, 2)
|
||||||
|
s.Require().EqualValues(description.ActiveMembersCount, 1)
|
||||||
s.Require().Len(description.Chats, 2)
|
s.Require().Len(description.Chats, 2)
|
||||||
s.Require().Len(description.Chats["channelA"].Members, 2)
|
s.Require().Len(description.Chats["channelA"].Members, 2)
|
||||||
s.Require().Len(description.Chats["channelB"].Members, 0) // encrypted channel
|
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")
|
s.Require().Equal(description.IntroMessage, "one of not encrypted fields")
|
||||||
|
|
||||||
description = proto.Clone(encryptedDescription).(*protobuf.CommunityDescription)
|
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()
|
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)
|
_, err = decryptDescription([]byte("some-id"), s.descriptionEncryptor, description, s.logger)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().Empty(description.Members)
|
s.Require().Empty(description.Members)
|
||||||
|
s.Require().Empty(description.ActiveMembersCount)
|
||||||
s.Require().Empty(description.Chats)
|
s.Require().Empty(description.Chats)
|
||||||
|
s.Require().Empty(description.Categories)
|
||||||
s.Require().Equal(description.IntroMessage, "one of not encrypted fields")
|
s.Require().Equal(description.IntroMessage, "one of not encrypted fields")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1550,11 +1550,16 @@ func (m *Messenger) acceptRequestToJoinCommunity(requestToJoin *communities.Requ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
encryptedDescription, err := community.EncryptedDescription()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
requestToJoinResponseProto := &protobuf.CommunityRequestToJoinResponse{
|
requestToJoinResponseProto := &protobuf.CommunityRequestToJoinResponse{
|
||||||
Clock: community.Clock(),
|
Clock: community.Clock(),
|
||||||
Accepted: true,
|
Accepted: true,
|
||||||
CommunityId: community.ID(),
|
CommunityId: community.ID(),
|
||||||
Community: community.Description(),
|
Community: encryptedDescription,
|
||||||
Grant: grant,
|
Grant: grant,
|
||||||
ProtectedTopicPrivateKey: crypto.FromECDSA(key),
|
ProtectedTopicPrivateKey: crypto.FromECDSA(key),
|
||||||
Shard: community.Shard().Protobuffer(),
|
Shard: community.Shard().Protobuffer(),
|
||||||
|
|
Loading…
Reference in New Issue