112 lines
3.7 KiB
Go
112 lines
3.7 KiB
Go
package communities
|
|
|
|
import (
|
|
"github.com/golang/protobuf/proto"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/status-im/status-go/eth-node/types"
|
|
"github.com/status-im/status-go/protocol/protobuf"
|
|
)
|
|
|
|
type DescriptionEncryptor interface {
|
|
encryptCommunityDescription(community *Community, d *protobuf.CommunityDescription) (string, []byte, error)
|
|
encryptCommunityDescriptionChannel(community *Community, channelID string, d *protobuf.CommunityDescription) (string, []byte, error)
|
|
decryptCommunityDescription(keyIDSeqNo string, d []byte) (*DecryptCommunityResponse, error)
|
|
}
|
|
|
|
// Encrypts members and chats
|
|
func encryptDescription(encryptor DescriptionEncryptor, community *Community, description *protobuf.CommunityDescription) error {
|
|
description.PrivateData = make(map[string][]byte)
|
|
|
|
for channelID, channel := range description.Chats {
|
|
if !community.channelEncrypted(channelID) {
|
|
continue
|
|
}
|
|
|
|
descriptionToEncrypt := &protobuf.CommunityDescription{
|
|
Chats: map[string]*protobuf.CommunityChat{
|
|
channelID: proto.Clone(channel).(*protobuf.CommunityChat),
|
|
},
|
|
}
|
|
|
|
keyIDSeqNo, encryptedDescription, err := encryptor.encryptCommunityDescriptionChannel(community, channelID, descriptionToEncrypt)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Set private data and cleanup unencrypted channel's members
|
|
description.PrivateData[keyIDSeqNo] = encryptedDescription
|
|
channel.Members = make(map[string]*protobuf.CommunityMember)
|
|
}
|
|
|
|
if community.Encrypted() {
|
|
descriptionToEncrypt := &protobuf.CommunityDescription{
|
|
Members: description.Members,
|
|
Chats: description.Chats,
|
|
}
|
|
|
|
keyIDSeqNo, encryptedDescription, err := encryptor.encryptCommunityDescription(community, descriptionToEncrypt)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Set private data and cleanup unencrypted members and chats
|
|
description.PrivateData[keyIDSeqNo] = encryptedDescription
|
|
description.Members = make(map[string]*protobuf.CommunityMember)
|
|
description.Chats = make(map[string]*protobuf.CommunityChat)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type CommunityPrivateDataFailedToDecrypt struct {
|
|
GroupID []byte
|
|
KeyID []byte
|
|
}
|
|
|
|
// Decrypts members and chats
|
|
func decryptDescription(id types.HexBytes, encryptor DescriptionEncryptor, description *protobuf.CommunityDescription, logger *zap.Logger) ([]*CommunityPrivateDataFailedToDecrypt, error) {
|
|
if len(description.PrivateData) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
var failedToDecrypt []*CommunityPrivateDataFailedToDecrypt
|
|
|
|
for keyIDSeqNo, encryptedDescription := range description.PrivateData {
|
|
decryptedDescriptionResponse, err := encryptor.decryptCommunityDescription(keyIDSeqNo, encryptedDescription)
|
|
if decryptedDescriptionResponse != nil && !decryptedDescriptionResponse.Decrypted {
|
|
failedToDecrypt = append(failedToDecrypt, &CommunityPrivateDataFailedToDecrypt{GroupID: id, KeyID: decryptedDescriptionResponse.KeyID})
|
|
}
|
|
if err != nil {
|
|
// ignore error, try to decrypt next data
|
|
logger.Debug("failed to decrypt community private data", zap.String("keyIDSeqNo", keyIDSeqNo), zap.Error(err))
|
|
continue
|
|
}
|
|
decryptedDescription := decryptedDescriptionResponse.Description
|
|
|
|
for pk, member := range decryptedDescription.Members {
|
|
if description.Members == nil {
|
|
description.Members = make(map[string]*protobuf.CommunityMember)
|
|
}
|
|
description.Members[pk] = member
|
|
}
|
|
|
|
for id, decryptedChannel := range decryptedDescription.Chats {
|
|
if description.Chats == nil {
|
|
description.Chats = make(map[string]*protobuf.CommunityChat)
|
|
}
|
|
|
|
if channel := description.Chats[id]; channel != nil {
|
|
if len(channel.Members) == 0 {
|
|
channel.Members = decryptedChannel.Members
|
|
}
|
|
} else {
|
|
description.Chats[id] = decryptedChannel
|
|
}
|
|
}
|
|
}
|
|
|
|
return failedToDecrypt, nil
|
|
}
|