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  }