150 lines
4.5 KiB
Go
150 lines
4.5 KiB
Go
package communities
|
|
|
|
import "github.com/status-im/status-go/protocol/protobuf"
|
|
|
|
type KeyDistributor interface {
|
|
Generate(community *Community, keyActions *EncryptionKeyActions) error
|
|
Distribute(community *Community, keyActions *EncryptionKeyActions) error
|
|
}
|
|
|
|
type EncryptionKeyActionType int
|
|
|
|
const (
|
|
EncryptionKeyNone EncryptionKeyActionType = iota
|
|
EncryptionKeyAdd
|
|
EncryptionKeyRemove
|
|
EncryptionKeyRekey
|
|
EncryptionKeySendToMembers
|
|
)
|
|
|
|
type EncryptionKeyAction struct {
|
|
ActionType EncryptionKeyActionType
|
|
Members map[string]*protobuf.CommunityMember
|
|
}
|
|
|
|
type EncryptionKeyActions struct {
|
|
// community-level encryption key action
|
|
CommunityKeyAction EncryptionKeyAction
|
|
|
|
// channel-level encryption key actions
|
|
ChannelKeysActions map[string]EncryptionKeyAction // key is: chatID
|
|
}
|
|
|
|
func EvaluateCommunityEncryptionKeyActions(origin, modified *Community) *EncryptionKeyActions {
|
|
if origin == nil {
|
|
// `modified` is a new community, create empty `origin` community
|
|
origin = &Community{
|
|
config: &Config{
|
|
ID: modified.config.ID,
|
|
CommunityDescription: &protobuf.CommunityDescription{
|
|
Members: map[string]*protobuf.CommunityMember{},
|
|
Permissions: &protobuf.CommunityPermissions{},
|
|
Identity: &protobuf.ChatIdentity{},
|
|
Chats: map[string]*protobuf.CommunityChat{},
|
|
Categories: map[string]*protobuf.CommunityCategory{},
|
|
AdminSettings: &protobuf.CommunityAdminSettings{},
|
|
TokenPermissions: map[string]*protobuf.CommunityTokenPermission{},
|
|
CommunityTokensMetadata: []*protobuf.CommunityTokenMetadata{},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
changes := EvaluateCommunityChanges(origin, modified)
|
|
|
|
result := &EncryptionKeyActions{
|
|
CommunityKeyAction: *evaluateCommunityLevelEncryptionKeyAction(origin, modified, changes),
|
|
ChannelKeysActions: *evaluateChannelLevelEncryptionKeyActions(origin, modified, changes),
|
|
}
|
|
return result
|
|
}
|
|
|
|
func evaluateCommunityLevelEncryptionKeyAction(origin, modified *Community, changes *CommunityChanges) *EncryptionKeyAction {
|
|
return evaluateEncryptionKeyAction(
|
|
origin.Encrypted(),
|
|
modified.Encrypted(),
|
|
changes.ControlNodeChanged != nil,
|
|
modified.config.CommunityDescription.Members,
|
|
changes.MembersAdded,
|
|
changes.MembersRemoved,
|
|
)
|
|
}
|
|
|
|
func evaluateChannelLevelEncryptionKeyActions(origin, modified *Community, changes *CommunityChanges) *map[string]EncryptionKeyAction {
|
|
result := make(map[string]EncryptionKeyAction)
|
|
|
|
for channelID := range modified.config.CommunityDescription.Chats {
|
|
membersAdded := make(map[string]*protobuf.CommunityMember)
|
|
membersRemoved := make(map[string]*protobuf.CommunityMember)
|
|
|
|
chatChanges, ok := changes.ChatsModified[channelID]
|
|
if ok {
|
|
membersAdded = chatChanges.MembersAdded
|
|
membersRemoved = chatChanges.MembersRemoved
|
|
}
|
|
|
|
result[channelID] = *evaluateEncryptionKeyAction(
|
|
origin.ChannelEncrypted(channelID),
|
|
modified.ChannelEncrypted(channelID),
|
|
changes.ControlNodeChanged != nil,
|
|
modified.config.CommunityDescription.Chats[channelID].Members,
|
|
membersAdded,
|
|
membersRemoved,
|
|
)
|
|
}
|
|
|
|
return &result
|
|
}
|
|
|
|
func evaluateEncryptionKeyAction(originEncrypted, modifiedEncrypted, controlNodeChanged bool,
|
|
allMembers, membersAdded, membersRemoved map[string]*protobuf.CommunityMember) *EncryptionKeyAction {
|
|
result := &EncryptionKeyAction{
|
|
ActionType: EncryptionKeyNone,
|
|
Members: map[string]*protobuf.CommunityMember{},
|
|
}
|
|
|
|
copyMap := func(source map[string]*protobuf.CommunityMember) map[string]*protobuf.CommunityMember {
|
|
to := make(map[string]*protobuf.CommunityMember)
|
|
for pubKey, member := range source {
|
|
to[pubKey] = member
|
|
}
|
|
return to
|
|
}
|
|
|
|
// control node changed on closed community/channel
|
|
if controlNodeChanged && modifiedEncrypted {
|
|
result.ActionType = EncryptionKeyRekey
|
|
result.Members = copyMap(allMembers)
|
|
return result
|
|
}
|
|
|
|
// encryption was just added
|
|
if modifiedEncrypted && !originEncrypted {
|
|
result.ActionType = EncryptionKeyAdd
|
|
result.Members = copyMap(allMembers)
|
|
return result
|
|
}
|
|
|
|
// encryption was just removed
|
|
if !modifiedEncrypted && originEncrypted {
|
|
result.ActionType = EncryptionKeyRemove
|
|
result.Members = copyMap(allMembers)
|
|
return result
|
|
}
|
|
|
|
// open community/channel does not require any actions
|
|
if !modifiedEncrypted {
|
|
return result
|
|
}
|
|
|
|
if len(membersRemoved) > 0 {
|
|
result.ActionType = EncryptionKeyRekey
|
|
result.Members = copyMap(allMembers)
|
|
} else if len(membersAdded) > 0 {
|
|
result.ActionType = EncryptionKeySendToMembers
|
|
result.Members = copyMap(membersAdded)
|
|
}
|
|
|
|
return result
|
|
}
|