github.com/status-im/status-go@v1.1.0/protocol/communities/communnity_privileged_member_sync_msg.go (about) 1 package communities 2 3 import ( 4 "crypto/ecdsa" 5 "database/sql" 6 "errors" 7 8 "go.uber.org/zap" 9 10 multiaccountscommon "github.com/status-im/status-go/multiaccounts/common" 11 12 "github.com/status-im/status-go/eth-node/types" 13 "github.com/status-im/status-go/protocol/common" 14 "github.com/status-im/status-go/protocol/protobuf" 15 ) 16 17 var ErrOutdatedSharedRequestToJoinClock = errors.New("outdated clock in shared request to join") 18 var ErrOutdatedSharedRequestToJoinState = errors.New("outdated state in shared request to join") 19 20 type CommunityPrivilegedMemberSyncMessage struct { 21 Receivers []*ecdsa.PublicKey 22 CommunityPrivilegedUserSyncMessage *protobuf.CommunityPrivilegedUserSyncMessage 23 } 24 25 func (m *Manager) HandleRequestToJoinPrivilegedUserSyncMessage(message *protobuf.CommunityPrivilegedUserSyncMessage, community *Community) ([]*RequestToJoin, error) { 26 var state RequestToJoinState 27 if message.Type == protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ACCEPT_REQUEST_TO_JOIN { 28 state = RequestToJoinStateAccepted 29 } else { 30 state = RequestToJoinStateDeclined 31 } 32 33 myPk := common.PubkeyToHex(&m.identity.PublicKey) 34 35 requestsToJoin := make([]*RequestToJoin, 0) 36 for signer, requestToJoinProto := range message.RequestToJoin { 37 if signer == myPk { 38 continue 39 } 40 41 requestToJoin := &RequestToJoin{ 42 PublicKey: signer, 43 Clock: requestToJoinProto.Clock, 44 ENSName: requestToJoinProto.EnsName, 45 CustomizationColor: multiaccountscommon.IDToColorFallbackToBlue(requestToJoinProto.CustomizationColor), 46 CommunityID: requestToJoinProto.CommunityId, 47 State: state, 48 RevealedAccounts: requestToJoinProto.RevealedAccounts, 49 } 50 requestToJoin.CalculateID() 51 52 err := m.processPrivilegedUserSharedRequestToJoin(community, requestToJoin) 53 if err != nil { 54 m.logger.Warn("error to handle shared request to join", 55 zap.String("communityID", community.IDString()), 56 zap.String("requestToJoinID", types.Bytes2Hex(requestToJoin.ID)), 57 zap.String("publicKey", requestToJoin.PublicKey), 58 zap.String("error", err.Error())) 59 continue 60 } 61 62 requestsToJoin = append(requestsToJoin, requestToJoin) 63 } 64 65 return requestsToJoin, nil 66 } 67 68 func (m *Manager) HandleSyncAllRequestToJoinForNewPrivilegedMember(message *protobuf.CommunityPrivilegedUserSyncMessage, community *Community) ([]*RequestToJoin, error) { 69 nonAcceptedRequestsToJoin := []*RequestToJoin{} 70 myPk := common.PubkeyToHex(&m.identity.PublicKey) 71 72 for _, syncRequestToJoin := range message.SyncRequestsToJoin { 73 if syncRequestToJoin.PublicKey == myPk { 74 continue 75 } 76 77 requestToJoin := new(RequestToJoin) 78 requestToJoin.InitFromSyncProtobuf(syncRequestToJoin) 79 80 err := m.processPrivilegedUserSharedRequestToJoin(community, requestToJoin) 81 if err != nil { 82 m.logger.Warn("error to handle shared request to join from sync all requests to join msg", 83 zap.String("communityID", community.IDString()), 84 zap.String("requestToJoinID", types.Bytes2Hex(requestToJoin.ID)), 85 zap.String("publicKey", requestToJoin.PublicKey), 86 zap.String("error", err.Error())) 87 continue 88 } 89 90 if requestToJoin.State != RequestToJoinStateAccepted { 91 nonAcceptedRequestsToJoin = append(nonAcceptedRequestsToJoin, requestToJoin) 92 } 93 } 94 return nonAcceptedRequestsToJoin, nil 95 } 96 97 func (m *Manager) HandleEditSharedAddressesPrivilegedUserSyncMessage(message *protobuf.CommunityPrivilegedUserSyncMessage, community *Community) error { 98 if !(community.IsTokenMaster() || community.IsOwner()) { 99 return ErrNotEnoughPermissions 100 } 101 102 publicKey := message.SyncEditSharedAddresses.PublicKey 103 editSharedAddress := message.SyncEditSharedAddresses.EditSharedAddress 104 if err := community.ValidateEditSharedAddresses(publicKey, editSharedAddress); err != nil { 105 return err 106 } 107 108 return m.handleCommunityEditSharedAddresses(publicKey, community.ID(), editSharedAddress.RevealedAccounts, message.Clock) 109 } 110 111 func (m *Manager) processPrivilegedUserSharedRequestToJoin(community *Community, requestToJoin *RequestToJoin) error { 112 existingRequestToJoin, err := m.persistence.GetCommunityRequestToJoinWithRevealedAddresses(requestToJoin.PublicKey, community.ID()) 113 if err != nil && err != sql.ErrNoRows { 114 return err 115 } 116 117 statusUpdate := existingRequestToJoin != nil && existingRequestToJoin.Clock == requestToJoin.Clock 118 119 if existingRequestToJoin != nil && existingRequestToJoin.Clock > requestToJoin.Clock { 120 return ErrOutdatedSharedRequestToJoinClock 121 } 122 123 revealedAccountsExists := requestToJoin.RevealedAccounts != nil && len(requestToJoin.RevealedAccounts) > 0 124 125 if member, memberExists := community.Members()[requestToJoin.PublicKey]; memberExists && member.LastUpdateClock > requestToJoin.Clock { 126 return ErrOutdatedSharedRequestToJoinClock 127 } 128 129 if statusUpdate { 130 isCurrentStateAccepted := existingRequestToJoin.State == RequestToJoinStateAccepted 131 isNewRequestAccepted := requestToJoin.State == RequestToJoinStateAccepted 132 isNewAcceptedRequestWithoutAccounts := isNewRequestAccepted && !revealedAccountsExists 133 isCurrentStateDeclined := existingRequestToJoin.State == RequestToJoinStateDeclined 134 135 if (isCurrentStateAccepted && (!isNewRequestAccepted || isNewAcceptedRequestWithoutAccounts)) || 136 (isCurrentStateDeclined && !isNewRequestAccepted) { 137 return ErrOutdatedSharedRequestToJoinState 138 } 139 140 err = m.persistence.SetRequestToJoinState(requestToJoin.PublicKey, community.ID(), requestToJoin.State) 141 if err != nil { 142 return err 143 } 144 } else { 145 err = m.persistence.SaveRequestToJoin(requestToJoin) 146 if err != nil { 147 return err 148 } 149 } 150 151 // If we are a token master or owner without private key and we received request to join without 152 // revealed accounts - there is a chance, that we lost our role and did't get 153 // CommunityDescription update. But it also can indicate, that we received an outdated 154 // request to join, when we were admins 155 // Decision - is not to delete existing revealed accounts 156 if (community.IsTokenMaster() || community.IsOwner()) && !revealedAccountsExists { 157 return nil 158 } 159 160 err = m.persistence.RemoveRequestToJoinRevealedAddresses(requestToJoin.ID) 161 if err != nil { 162 return err 163 } 164 165 if revealedAccountsExists { 166 return m.persistence.SaveRequestToJoinRevealedAddresses(requestToJoin.ID, requestToJoin.RevealedAccounts) 167 } 168 169 return nil 170 }