github.com/status-im/status-go@v1.1.0/protocol/communities/community_encryption_key_action.go (about) 1 package communities 2 3 import ( 4 "github.com/status-im/status-go/protocol/protobuf" 5 ) 6 7 type KeyDistributor interface { 8 Generate(community *Community, keyActions *EncryptionKeyActions) error 9 Distribute(community *Community, keyActions *EncryptionKeyActions) error 10 } 11 12 type EncryptionKeyActionType int 13 14 const ( 15 EncryptionKeyNone EncryptionKeyActionType = iota 16 EncryptionKeyAdd 17 EncryptionKeyRemove 18 EncryptionKeyRekey 19 EncryptionKeySendToMembers 20 ) 21 22 type EncryptionKeyAction struct { 23 ActionType EncryptionKeyActionType 24 Members map[string]*protobuf.CommunityMember 25 RemovedMembers map[string]*protobuf.CommunityMember 26 } 27 28 type EncryptionKeyActions struct { 29 // community-level encryption key action 30 CommunityKeyAction EncryptionKeyAction 31 32 // channel-level encryption key actions 33 ChannelKeysActions map[string]EncryptionKeyAction // key is: chatID 34 } 35 36 func EvaluateCommunityEncryptionKeyActions(origin, modified *Community) *EncryptionKeyActions { 37 if origin == nil { 38 // `modified` is a new community, create empty `origin` community 39 origin = &Community{ 40 config: &Config{ 41 ID: modified.config.ID, 42 CommunityDescription: &protobuf.CommunityDescription{ 43 Members: map[string]*protobuf.CommunityMember{}, 44 Permissions: &protobuf.CommunityPermissions{}, 45 Identity: &protobuf.ChatIdentity{}, 46 Chats: map[string]*protobuf.CommunityChat{}, 47 Categories: map[string]*protobuf.CommunityCategory{}, 48 AdminSettings: &protobuf.CommunityAdminSettings{}, 49 TokenPermissions: map[string]*protobuf.CommunityTokenPermission{}, 50 CommunityTokensMetadata: []*protobuf.CommunityTokenMetadata{}, 51 }, 52 }, 53 } 54 } 55 56 changes := EvaluateCommunityChanges(origin, modified) 57 58 result := &EncryptionKeyActions{ 59 CommunityKeyAction: *evaluateCommunityLevelEncryptionKeyAction(origin, modified, changes), 60 ChannelKeysActions: *evaluateChannelLevelEncryptionKeyActions(origin, modified, changes), 61 } 62 return result 63 } 64 65 func evaluateCommunityLevelEncryptionKeyAction(origin, modified *Community, changes *CommunityChanges) *EncryptionKeyAction { 66 return evaluateEncryptionKeyAction( 67 origin.Encrypted(), 68 modified.Encrypted(), 69 changes.ControlNodeChanged != nil, 70 modified.config.CommunityDescription.Members, 71 changes.MembersAdded, 72 changes.MembersRemoved, 73 ) 74 } 75 76 func evaluateChannelLevelEncryptionKeyActions(origin, modified *Community, changes *CommunityChanges) *map[string]EncryptionKeyAction { 77 result := make(map[string]EncryptionKeyAction) 78 79 for channelID := range modified.config.CommunityDescription.Chats { 80 membersAdded := make(map[string]*protobuf.CommunityMember) 81 membersRemoved := make(map[string]*protobuf.CommunityMember) 82 83 chatChanges, ok := changes.ChatsModified[channelID] 84 if ok { 85 membersAdded = chatChanges.MembersAdded 86 membersRemoved = chatChanges.MembersRemoved 87 } 88 89 result[channelID] = *evaluateEncryptionKeyAction( 90 origin.ChannelEncrypted(channelID), 91 modified.ChannelEncrypted(channelID), 92 changes.ControlNodeChanged != nil, 93 modified.config.CommunityDescription.Chats[channelID].Members, 94 membersAdded, 95 membersRemoved, 96 ) 97 } 98 99 return &result 100 } 101 102 func evaluateEncryptionKeyAction(originEncrypted, modifiedEncrypted, controlNodeChanged bool, 103 allMembers, membersAdded, membersRemoved map[string]*protobuf.CommunityMember) *EncryptionKeyAction { 104 result := &EncryptionKeyAction{ 105 ActionType: EncryptionKeyNone, 106 Members: map[string]*protobuf.CommunityMember{}, 107 } 108 109 copyMap := func(source map[string]*protobuf.CommunityMember) map[string]*protobuf.CommunityMember { 110 to := make(map[string]*protobuf.CommunityMember) 111 for pubKey, member := range source { 112 to[pubKey] = member 113 } 114 return to 115 } 116 117 // control node changed on closed community/channel 118 if controlNodeChanged && modifiedEncrypted { 119 result.ActionType = EncryptionKeyRekey 120 result.Members = copyMap(allMembers) 121 return result 122 } 123 124 // encryption was just added 125 if modifiedEncrypted && !originEncrypted { 126 result.ActionType = EncryptionKeyAdd 127 result.Members = copyMap(allMembers) 128 return result 129 } 130 131 // encryption was just removed 132 if !modifiedEncrypted && originEncrypted { 133 result.ActionType = EncryptionKeyRemove 134 result.Members = copyMap(allMembers) 135 return result 136 } 137 138 // open community/channel does not require any actions 139 if !modifiedEncrypted { 140 return result 141 } 142 143 if len(membersRemoved) > 0 { 144 result.ActionType = EncryptionKeyRekey 145 result.Members = copyMap(allMembers) 146 result.RemovedMembers = copyMap(membersRemoved) 147 } else if len(membersAdded) > 0 { 148 result.ActionType = EncryptionKeySendToMembers 149 result.Members = copyMap(membersAdded) 150 } 151 152 return result 153 }