2023-07-17 16:40:09 +00:00
|
|
|
package protocol
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/ecdsa"
|
|
|
|
|
|
|
|
"github.com/status-im/status-go/protocol/common"
|
|
|
|
"github.com/status-im/status-go/protocol/communities"
|
|
|
|
"github.com/status-im/status-go/protocol/encryption"
|
|
|
|
"github.com/status-im/status-go/protocol/protobuf"
|
|
|
|
)
|
|
|
|
|
|
|
|
type CommunitiesKeyDistributor interface {
|
|
|
|
Distribute(community *communities.Community, keyActions *communities.EncryptionKeyActions) error
|
|
|
|
Rekey(community *communities.Community) error
|
|
|
|
}
|
|
|
|
|
|
|
|
type CommunitiesKeyDistributorImpl struct {
|
|
|
|
sender *common.MessageSender
|
|
|
|
encryptor *encryption.Protocol
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ckd *CommunitiesKeyDistributorImpl) Distribute(community *communities.Community, keyActions *communities.EncryptionKeyActions) error {
|
|
|
|
if !community.IsControlNode() {
|
|
|
|
return communities.ErrNotControlNode
|
|
|
|
}
|
|
|
|
|
2023-05-22 21:38:02 +00:00
|
|
|
err := ckd.distributeKey(community, community.ID(), &keyActions.CommunityKeyAction)
|
2023-07-17 16:40:09 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-06-23 10:49:26 +00:00
|
|
|
for channelID := range keyActions.ChannelKeysActions {
|
|
|
|
keyAction := keyActions.ChannelKeysActions[channelID]
|
2023-05-22 21:38:02 +00:00
|
|
|
err := ckd.distributeKey(community, []byte(community.IDString()+channelID), &keyAction)
|
2023-07-17 16:40:09 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ckd *CommunitiesKeyDistributorImpl) Rekey(community *communities.Community) error {
|
|
|
|
if !community.IsControlNode() {
|
|
|
|
return communities.ErrNotControlNode
|
|
|
|
}
|
|
|
|
|
2023-05-22 21:38:02 +00:00
|
|
|
err := ckd.distributeKey(community, community.ID(), &communities.EncryptionKeyAction{
|
2023-07-17 16:40:09 +00:00
|
|
|
ActionType: communities.EncryptionKeyRekey,
|
|
|
|
Members: community.Members(),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for channelID, channel := range community.Chats() {
|
2023-05-22 21:38:02 +00:00
|
|
|
err := ckd.distributeKey(community, []byte(community.IDString()+channelID), &communities.EncryptionKeyAction{
|
2023-07-17 16:40:09 +00:00
|
|
|
ActionType: communities.EncryptionKeyRekey,
|
|
|
|
Members: channel.Members,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-05-22 21:38:02 +00:00
|
|
|
func (ckd *CommunitiesKeyDistributorImpl) distributeKey(community *communities.Community, hashRatchetGroupID []byte, keyAction *communities.EncryptionKeyAction) error {
|
2023-07-17 16:40:09 +00:00
|
|
|
pubkeys := make([]*ecdsa.PublicKey, len(keyAction.Members))
|
|
|
|
i := 0
|
|
|
|
for hex := range keyAction.Members {
|
|
|
|
pubkeys[i], _ = common.HexToPubkey(hex)
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
|
|
|
|
switch keyAction.ActionType {
|
|
|
|
case communities.EncryptionKeyAdd:
|
|
|
|
_, err := ckd.encryptor.GenerateHashRatchetKey(hashRatchetGroupID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-05-22 21:38:02 +00:00
|
|
|
err = ckd.sendKeyExchangeMessage(community, hashRatchetGroupID, pubkeys, common.KeyExMsgReuse)
|
2023-07-17 16:40:09 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
case communities.EncryptionKeyRekey:
|
2023-05-22 21:38:02 +00:00
|
|
|
err := ckd.sendKeyExchangeMessage(community, hashRatchetGroupID, pubkeys, common.KeyExMsgRekey)
|
2023-07-17 16:40:09 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
case communities.EncryptionKeySendToMembers:
|
2023-05-22 21:38:02 +00:00
|
|
|
err := ckd.sendKeyExchangeMessage(community, hashRatchetGroupID, pubkeys, common.KeyExMsgReuse)
|
2023-07-17 16:40:09 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-05-22 21:38:02 +00:00
|
|
|
func (ckd *CommunitiesKeyDistributorImpl) sendKeyExchangeMessage(community *communities.Community, hashRatchetGroupID []byte, pubkeys []*ecdsa.PublicKey, msgType common.CommKeyExMsgType) error {
|
2023-07-17 16:40:09 +00:00
|
|
|
rawMessage := common.RawMessage{
|
2023-10-12 15:45:23 +00:00
|
|
|
Sender: community.PrivateKey(),
|
2023-07-17 16:40:09 +00:00
|
|
|
SkipProtocolLayer: false,
|
2023-05-22 21:38:02 +00:00
|
|
|
CommunityID: community.ID(),
|
2023-07-17 16:40:09 +00:00
|
|
|
CommunityKeyExMsgType: msgType,
|
|
|
|
Recipients: pubkeys,
|
|
|
|
MessageType: protobuf.ApplicationMetadataMessage_CHAT_MESSAGE,
|
2023-06-23 10:49:26 +00:00
|
|
|
HashRatchetGroupID: hashRatchetGroupID,
|
2023-05-22 21:38:02 +00:00
|
|
|
PubsubTopic: community.PubsubTopic(), // TODO: confirm if it should be sent in community pubsub topic
|
2023-07-17 16:40:09 +00:00
|
|
|
}
|
|
|
|
_, err := ckd.sender.SendCommunityMessage(context.Background(), rawMessage)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|