github.com/status-im/status-go@v1.1.0/protocol/communities/community_description_encryption.go (about)

     1  package communities
     2  
     3  import (
     4  	"go.uber.org/zap"
     5  
     6  	"github.com/status-im/status-go/eth-node/types"
     7  	"github.com/status-im/status-go/protocol/protobuf"
     8  )
     9  
    10  type DescriptionEncryptor interface {
    11  	encryptCommunityDescription(community *Community, d *protobuf.CommunityDescription) (string, []byte, error)
    12  	encryptCommunityDescriptionChannel(community *Community, channelID string, d *protobuf.CommunityDescription) (string, []byte, error)
    13  	decryptCommunityDescription(keyIDSeqNo string, d []byte) (*DecryptCommunityResponse, error)
    14  }
    15  
    16  // Encrypts members and chats
    17  func encryptDescription(encryptor DescriptionEncryptor, community *Community, description *protobuf.CommunityDescription) error {
    18  	description.PrivateData = make(map[string][]byte)
    19  
    20  	for channelID, channel := range description.Chats {
    21  		if !community.channelEncrypted(channelID) {
    22  			continue
    23  		}
    24  
    25  		descriptionToEncrypt := &protobuf.CommunityDescription{
    26  			Chats: map[string]*protobuf.CommunityChat{
    27  				channelID: channel,
    28  			},
    29  		}
    30  
    31  		keyIDSeqNo, encryptedDescription, err := encryptor.encryptCommunityDescriptionChannel(community, channelID, descriptionToEncrypt)
    32  		if err != nil {
    33  			return err
    34  		}
    35  
    36  		// Set private data and cleanup unencrypted channel's members
    37  		description.PrivateData[keyIDSeqNo] = encryptedDescription
    38  		channel.Members = make(map[string]*protobuf.CommunityMember)
    39  	}
    40  
    41  	if community.Encrypted() {
    42  		descriptionToEncrypt := &protobuf.CommunityDescription{
    43  			Members:            description.Members,
    44  			ActiveMembersCount: description.ActiveMembersCount,
    45  			Chats:              description.Chats,
    46  			Categories:         description.Categories,
    47  		}
    48  
    49  		keyIDSeqNo, encryptedDescription, err := encryptor.encryptCommunityDescription(community, descriptionToEncrypt)
    50  		if err != nil {
    51  			return err
    52  		}
    53  
    54  		// Set private data and cleanup unencrypted members, chats and categories
    55  		description.PrivateData[keyIDSeqNo] = encryptedDescription
    56  		description.Members = make(map[string]*protobuf.CommunityMember)
    57  		description.ActiveMembersCount = 0
    58  		description.Chats = make(map[string]*protobuf.CommunityChat)
    59  		description.Categories = make(map[string]*protobuf.CommunityCategory)
    60  	}
    61  
    62  	return nil
    63  }
    64  
    65  type CommunityPrivateDataFailedToDecrypt struct {
    66  	GroupID []byte
    67  	KeyID   []byte
    68  }
    69  
    70  // Decrypts members and chats
    71  func decryptDescription(id types.HexBytes, encryptor DescriptionEncryptor, description *protobuf.CommunityDescription, logger *zap.Logger) ([]*CommunityPrivateDataFailedToDecrypt, error) {
    72  	if len(description.PrivateData) == 0 {
    73  		return nil, nil
    74  	}
    75  
    76  	var failedToDecrypt []*CommunityPrivateDataFailedToDecrypt
    77  
    78  	for keyIDSeqNo, encryptedDescription := range description.PrivateData {
    79  		decryptedDescriptionResponse, err := encryptor.decryptCommunityDescription(keyIDSeqNo, encryptedDescription)
    80  		if decryptedDescriptionResponse != nil && !decryptedDescriptionResponse.Decrypted {
    81  			failedToDecrypt = append(failedToDecrypt, &CommunityPrivateDataFailedToDecrypt{GroupID: id, KeyID: decryptedDescriptionResponse.KeyID})
    82  		}
    83  		if err != nil {
    84  			// ignore error, try to decrypt next data
    85  			logger.Debug("failed to decrypt community private data", zap.String("keyIDSeqNo", keyIDSeqNo), zap.Error(err))
    86  			continue
    87  		}
    88  		decryptedDescription := decryptedDescriptionResponse.Description
    89  
    90  		if len(decryptedDescription.Members) > 0 {
    91  			description.Members = decryptedDescription.Members
    92  		}
    93  
    94  		if decryptedDescription.ActiveMembersCount > 0 {
    95  			description.ActiveMembersCount = decryptedDescription.ActiveMembersCount
    96  		}
    97  
    98  		for id, decryptedChannel := range decryptedDescription.Chats {
    99  			if description.Chats == nil {
   100  				description.Chats = make(map[string]*protobuf.CommunityChat)
   101  			}
   102  
   103  			if channel := description.Chats[id]; channel != nil {
   104  				if len(decryptedChannel.Members) > 0 {
   105  					channel.Members = decryptedChannel.Members
   106  				}
   107  			} else {
   108  				description.Chats[id] = decryptedChannel
   109  			}
   110  		}
   111  
   112  		if len(decryptedDescription.Categories) > 0 {
   113  			description.Categories = decryptedDescription.Categories
   114  		}
   115  	}
   116  
   117  	return failedToDecrypt, nil
   118  }