github.com/status-im/status-go@v1.1.0/protocol/communities_key_distributor.go (about) 1 package protocol 2 3 import ( 4 "context" 5 "crypto/ecdsa" 6 7 "github.com/status-im/status-go/protocol/common" 8 "github.com/status-im/status-go/protocol/communities" 9 "github.com/status-im/status-go/protocol/encryption" 10 "github.com/status-im/status-go/protocol/protobuf" 11 ) 12 13 type CommunitiesKeyDistributorImpl struct { 14 sender *common.MessageSender 15 encryptor *encryption.Protocol 16 } 17 18 func (ckd *CommunitiesKeyDistributorImpl) Generate(community *communities.Community, keyActions *communities.EncryptionKeyActions) error { 19 if !community.IsControlNode() { 20 return communities.ErrNotControlNode 21 } 22 return iterateActions(community, keyActions, ckd.generateKey) 23 } 24 25 func (ckd *CommunitiesKeyDistributorImpl) Distribute(community *communities.Community, keyActions *communities.EncryptionKeyActions) error { 26 if !community.IsControlNode() { 27 return communities.ErrNotControlNode 28 } 29 return iterateActions(community, keyActions, ckd.distributeKey) 30 } 31 32 func iterateActions(community *communities.Community, keyActions *communities.EncryptionKeyActions, fn func(community *communities.Community, hashRatchetGroupID []byte, keyAction *communities.EncryptionKeyAction) error) error { 33 err := fn(community, community.ID(), &keyActions.CommunityKeyAction) 34 if err != nil { 35 return err 36 } 37 38 for channelID := range keyActions.ChannelKeysActions { 39 keyAction := keyActions.ChannelKeysActions[channelID] 40 err := fn(community, []byte(community.IDString()+channelID), &keyAction) 41 if err != nil { 42 return err 43 } 44 } 45 46 return nil 47 } 48 49 func (ckd *CommunitiesKeyDistributorImpl) generateKey(community *communities.Community, hashRatchetGroupID []byte, keyAction *communities.EncryptionKeyAction) error { 50 if keyAction.ActionType != communities.EncryptionKeyAdd { 51 return nil 52 } 53 _, err := ckd.encryptor.GenerateHashRatchetKey(hashRatchetGroupID) 54 return err 55 } 56 57 func (ckd *CommunitiesKeyDistributorImpl) distributeKey(community *communities.Community, hashRatchetGroupID []byte, keyAction *communities.EncryptionKeyAction) error { 58 pubkeys := make([]*ecdsa.PublicKey, len(keyAction.Members)) 59 i := 0 60 for hex := range keyAction.Members { 61 pubkeys[i], _ = common.HexToPubkey(hex) 62 i++ 63 } 64 65 switch keyAction.ActionType { 66 case communities.EncryptionKeyAdd: 67 // key must be already generated 68 err := ckd.sendKeyExchangeMessage(community, hashRatchetGroupID, pubkeys, common.KeyExMsgReuse) 69 if err != nil { 70 return err 71 } 72 73 case communities.EncryptionKeyRekey: 74 err := ckd.sendKeyExchangeMessage(community, hashRatchetGroupID, pubkeys, common.KeyExMsgRekey) 75 if err != nil { 76 return err 77 } 78 79 case communities.EncryptionKeySendToMembers: 80 err := ckd.sendKeyExchangeMessage(community, hashRatchetGroupID, pubkeys, common.KeyExMsgReuse) 81 if err != nil { 82 return err 83 } 84 } 85 86 return nil 87 } 88 89 func (ckd *CommunitiesKeyDistributorImpl) sendKeyExchangeMessage(community *communities.Community, hashRatchetGroupID []byte, pubkeys []*ecdsa.PublicKey, msgType common.CommKeyExMsgType) error { 90 rawMessage := common.RawMessage{ 91 Sender: community.PrivateKey(), 92 SkipEncryptionLayer: false, 93 CommunityID: community.ID(), 94 CommunityKeyExMsgType: msgType, 95 Recipients: pubkeys, 96 MessageType: protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, 97 HashRatchetGroupID: hashRatchetGroupID, 98 PubsubTopic: community.PubsubTopic(), // TODO: confirm if it should be sent in community pubsub topic 99 } 100 _, err := ckd.sender.SendCommunityMessage(context.Background(), &rawMessage) 101 102 if err != nil { 103 return err 104 } 105 return nil 106 }