-
Notifications
You must be signed in to change notification settings - Fork 246
/
community_description_encryption.go
111 lines (90 loc) · 3.65 KB
/
community_description_encryption.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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
}