diff --git a/protocol/communities/community.go b/protocol/communities/community.go index 40beaa574..b49278bac 100644 --- a/protocol/communities/community.go +++ b/protocol/communities/community.go @@ -2230,12 +2230,12 @@ func (o *Community) addMemberWithRevealedAccounts(memberKey string, roles []prot return changes } -func (o *Community) DeclineRequestToJoin(dbRequest *RequestToJoin) error { +func (o *Community) DeclineRequestToJoin(dbRequest *RequestToJoin) (adminEventCreated bool, err error) { o.mutex.Lock() defer o.mutex.Unlock() if !(o.IsControlNode() || o.hasPermissionToSendCommunityEvent(protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_REJECT)) { - return ErrNotAuthorized + return adminEventCreated, ErrNotAuthorized } if o.IsControlNode() { @@ -2252,13 +2252,15 @@ func (o *Community) DeclineRequestToJoin(dbRequest *RequestToJoin) error { CommunityChanges: o.emptyCommunityChanges(), RejectedRequestsToJoin: rejectedRequestsToJoin, } - err := o.addNewCommunityEvent(o.ToCommunityRequestToJoinRejectCommunityEvent(adminChanges)) + err = o.addNewCommunityEvent(o.ToCommunityRequestToJoinRejectCommunityEvent(adminChanges)) if err != nil { - return err + return adminEventCreated, err } + + adminEventCreated = true } - return nil + return adminEventCreated, err } func (o *Community) ValidateEvent(event *CommunityEvent, signer *ecdsa.PublicKey) error { diff --git a/protocol/communities/manager.go b/protocol/communities/manager.go index 41bab5835..a0c762888 100644 --- a/protocol/communities/manager.go +++ b/protocol/communities/manager.go @@ -1424,7 +1424,7 @@ func (m *Manager) handleCommunityDescriptionMessageCommon(community *Community, // We mark our requests as completed, though maybe we should mark // any request for any user that has been added as completed - if err := m.markRequestToJoin(&m.identity.PublicKey, community); err != nil { + if err := m.markRequestToJoinAsAccepted(&m.identity.PublicKey, community); err != nil { return nil, err } // Check if there's a change and we should be joining @@ -1702,18 +1702,11 @@ func (m *Manager) handleCommunityEventRequestAccepted(community *Community, comm return nil, err } - if community.IsControlNode() { - // If request to join exists in control node, save request as RequestToJoinStateAccepted - // If request to join does not exist in control node, save request as RequestToJoinStateAcceptedPending - // as privileged users don't have revealed addresses. This can happen if control node received - // community event message before user request to join - if existingRequestToJoin != nil { - requestToJoin.State = RequestToJoinStateAccepted + if existingRequestToJoin != nil { + alreadyProcessedByControlNode := existingRequestToJoin.State == RequestToJoinStateAccepted || existingRequestToJoin.State == RequestToJoinStateDeclined + if alreadyProcessedByControlNode || existingRequestToJoin.State == RequestToJoinStateCanceled { + continue } - } else if community.HasPermissionToSendCommunityEvents() && existingRequestToJoin.State != RequestToJoinStatePending { - // the request is already in some pending state or was processed by a control node, - // so we won't override it again - continue } requestUpdated, err := m.saveOrUpdateRequestToJoin(community.ID(), requestToJoin) @@ -1721,11 +1714,11 @@ func (m *Manager) handleCommunityEventRequestAccepted(community *Community, comm return nil, err } + // If request to join exists in control node, add request to acceptedRequestsToJoin. + // Otherwise keep the request as RequestToJoinStateAcceptedPending, + // as privileged users don't have revealed addresses. This can happen if control node received + // community event message before user request to join. if community.IsControlNode() && requestUpdated { - // We only collect requestToJoinIDs which had a state update. - // If there wasn't a state update, it means we've seen the request for the first time, - // which means we don't have revealed addresses here (as they aren't propagated by - // admin nodes), so we don't want to trigger an `AcceptRequestToJoin` in such cases. acceptedRequestsToJoin = append(acceptedRequestsToJoin, requestToJoin.ID) } @@ -1757,24 +1750,21 @@ func (m *Manager) handleCommunityEventRequestRejected(community *Community, comm return nil, err } - if community.IsControlNode() { - // If request to join exists in control node, save request as RequestToJoinStateDeclined - // If request to join does not exist in control node, save request as RequestToJoinStateDeclinedPending - // as privileged users don't have revealed addresses. This can happen if control node received - // community event message before user request to join - if existingRequestToJoin != nil { - requestToJoin.State = RequestToJoinStateDeclined + if existingRequestToJoin != nil { + alreadyProcessedByControlNode := existingRequestToJoin.State == RequestToJoinStateAccepted || existingRequestToJoin.State == RequestToJoinStateDeclined + if alreadyProcessedByControlNode || existingRequestToJoin.State == RequestToJoinStateCanceled { + continue } - } else if community.HasPermissionToSendCommunityEvents() && existingRequestToJoin.State != RequestToJoinStatePending { - // the request is already in some pending state or was processed by a control node, - // so we won't override it again - continue } requestUpdated, err := m.saveOrUpdateRequestToJoin(community.ID(), requestToJoin) if err != nil { return nil, err } + // If request to join exists in control node, add request to rejectedRequestsToJoin. + // Otherwise keep the request as RequestToJoinStateDeclinedPending, + // as privileged users don't have revealed addresses. This can happen if control node received + // community event message before user request to join. if community.IsControlNode() && requestUpdated { rejectedRequestsToJoin = append(rejectedRequestsToJoin, requestToJoin.ID) } @@ -1788,9 +1778,9 @@ func (m *Manager) handleCommunityEventRequestRejected(community *Community, comm return requestsToJoin, nil } -// markRequestToJoin marks all the pending requests to join as completed +// markRequestToJoinAsAccepted marks all the pending requests to join as completed // if we are members -func (m *Manager) markRequestToJoin(pk *ecdsa.PublicKey, community *Community) error { +func (m *Manager) markRequestToJoinAsAccepted(pk *ecdsa.PublicKey, community *Community) error { if community.HasMember(pk) { return m.persistence.SetRequestToJoinState(common.PubkeyToHex(pk), community.ID(), RequestToJoinStateAccepted) } @@ -1956,34 +1946,6 @@ func (m *Manager) AcceptRequestToJoin(dbRequest *RequestToJoin) (*Community, err return nil, err } - if community.hasPermissionToSendCommunityEvent(protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT) && !community.IsControlNode() { - if dbRequest.MarkedAsPendingByPrivilegedAccount() { - // if the request is in any pending state, it means our admin node has either - // already made a decision in the past, or previously received a decision by - // another admin, which in both cases means we're not allowed to override this - // state again - return nil, errors.New("request to join is already in pending state") - } - - // admins do not perform permission checks, they merely mark the - // request as accepted (pending) and forward their decision to the control node - acceptedRequestsToJoin := make(map[string]*protobuf.CommunityRequestToJoin) - acceptedRequestsToJoin[dbRequest.PublicKey] = dbRequest.ToCommunityRequestToJoinProtobuf() - - adminChanges := &CommunityEventChanges{ - AcceptedRequestsToJoin: acceptedRequestsToJoin, - } - - err := community.addNewCommunityEvent(community.ToCommunityRequestToJoinAcceptCommunityEvent(adminChanges)) - if err != nil { - return nil, err - } - - if err := m.markRequestToJoinAsAcceptedPending(pk, community); err != nil { - return nil, err - } - } - if community.IsControlNode() { revealedAccounts, err := m.persistence.GetRequestToJoinRevealedAddresses(dbRequest.ID) if err != nil { @@ -2021,17 +1983,10 @@ func (m *Manager) AcceptRequestToJoin(dbRequest *RequestToJoin) (*Community, err } } - if err := m.markRequestToJoin(pk, community); err != nil { + if err := m.markRequestToJoinAsAccepted(pk, community); err != nil { return nil, err } - } - err = m.saveAndPublish(community) - if err != nil { - return nil, err - } - - if community.IsControlNode() { if err = m.shareAcceptedRequestToJoinWithPrivilegedMembers(community, dbRequest); err != nil { return nil, err } @@ -2047,6 +2002,31 @@ func (m *Manager) AcceptRequestToJoin(dbRequest *RequestToJoin) (*Community, err return nil, err } } + } else if community.hasPermissionToSendCommunityEvent(protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT) { + // admins do not perform permission checks, they merely mark the + // request as accepted (pending) and forward their decision to the control node + acceptedRequestsToJoin := make(map[string]*protobuf.CommunityRequestToJoin) + acceptedRequestsToJoin[dbRequest.PublicKey] = dbRequest.ToCommunityRequestToJoinProtobuf() + + adminChanges := &CommunityEventChanges{ + AcceptedRequestsToJoin: acceptedRequestsToJoin, + } + + err := community.addNewCommunityEvent(community.ToCommunityRequestToJoinAcceptCommunityEvent(adminChanges)) + if err != nil { + return nil, err + } + + if err := m.markRequestToJoinAsAcceptedPending(pk, community); err != nil { + return nil, err + } + } else { + return nil, ErrNotAuthorized + } + + err = m.saveAndPublish(community) + if err != nil { + return nil, err } return community, nil @@ -2062,16 +2042,17 @@ func (m *Manager) DeclineRequestToJoin(dbRequest *RequestToJoin) (*Community, er return nil, err } - requestToJoinState := RequestToJoinStateDeclined - if community.HasPermissionToSendCommunityEvents() { - requestToJoinState = RequestToJoinStateDeclinedPending - } - err = m.persistence.SetRequestToJoinState(dbRequest.PublicKey, dbRequest.CommunityID, requestToJoinState) + adminEventCreated, err := community.DeclineRequestToJoin(dbRequest) if err != nil { return nil, err } - err = community.DeclineRequestToJoin(dbRequest) + requestToJoinState := RequestToJoinStateDeclined + if adminEventCreated { + requestToJoinState = RequestToJoinStateDeclinedPending // can only be declined by control node + } + + err = m.persistence.SetRequestToJoinState(dbRequest.PublicKey, dbRequest.CommunityID, requestToJoinState) if err != nil { return nil, err } @@ -2146,7 +2127,7 @@ func (m *Manager) HandleCommunityRequestToJoin(signer *ecdsa.PublicKey, receiver // don't process request as admin if community is configured as auto-accept if !community.IsControlNode() && community.AcceptRequestToJoinAutomatically() { - return nil, errors.New("ignoring request to join, community is set to auto-accept") + return nil, nil } // control node must receive requests to join only on community address @@ -2188,93 +2169,69 @@ func (m *Manager) HandleCommunityRequestToJoin(signer *ecdsa.PublicKey, receiver return nil, err } - if existingRequestToJoin != nil && existingRequestToJoin.State != RequestToJoinStateCanceled { + if existingRequestToJoin == nil || existingRequestToJoin.State == RequestToJoinStateCanceled { + if err := m.persistence.SaveRequestToJoin(requestToJoin); err != nil { + return nil, err + } + } + + if community.IsControlNode() { // request to join was already processed by an admin and waits to get // confirmation for its decision // // we're only interested in immediately declining any declined/pending // requests here, because if it's accepted/pending, we still need to perform // some checks - if existingRequestToJoin.State == RequestToJoinStateDeclinedPending { - if community.IsControlNode() { - requestToJoin.State = RequestToJoinStateDeclined - } + if existingRequestToJoin != nil && existingRequestToJoin.State == RequestToJoinStateDeclinedPending { + requestToJoin.State = RequestToJoinStateDeclined return requestToJoin, nil } - } else { - if err := m.persistence.SaveRequestToJoin(requestToJoin); err != nil { - return nil, err - } - } - if len(request.RevealedAccounts) > 0 && community.IsControlNode() { - // verify if revealed addresses indeed belong to requester - for _, revealedAccount := range request.RevealedAccounts { - recoverParams := account.RecoverParams{ - Message: types.EncodeHex(crypto.Keccak256(crypto.CompressPubkey(signer), community.ID(), requestToJoin.ID)), - Signature: types.EncodeHex(revealedAccount.Signature), + if len(request.RevealedAccounts) > 0 { + // verify if revealed addresses indeed belong to requester + for _, revealedAccount := range request.RevealedAccounts { + recoverParams := account.RecoverParams{ + Message: types.EncodeHex(crypto.Keccak256(crypto.CompressPubkey(signer), community.ID(), requestToJoin.ID)), + Signature: types.EncodeHex(revealedAccount.Signature), + } + + matching, err := m.accountsManager.CanRecover(recoverParams, types.HexToAddress(revealedAccount.Address)) + if err != nil { + return nil, err + } + if !matching { + // if ownership of only one wallet address cannot be verified, + // we mark the request as cancelled and stop + requestToJoin.State = RequestToJoinStateDeclined + return requestToJoin, nil + } } - matching, err := m.accountsManager.CanRecover(recoverParams, types.HexToAddress(revealedAccount.Address)) + // Save revealed addresses + signatures so they can later be added + // to the control node's local table of known revealed addresses + err = m.persistence.SaveRequestToJoinRevealedAddresses(requestToJoin.ID, requestToJoin.RevealedAccounts) if err != nil { return nil, err } - if !matching { - // if ownership of only one wallet address cannot be verified, - // we mark the request as cancelled and stop - requestToJoin.State = RequestToJoinStateDeclined - return requestToJoin, nil - } } - // Save revealed addresses + signatures so they can later be added - // to the control node's local table of known revealed addresses - err = m.persistence.SaveRequestToJoinRevealedAddresses(requestToJoin.ID, requestToJoin.RevealedAccounts) - if err != nil { - return nil, err - } - } - - // If user is already a member, then accept request automatically - // It may happen when member removes itself from community and then tries to rejoin - // More specifically, CommunityRequestToLeave may be delivered later than CommunityRequestToJoin, or not delivered at all - acceptAutomatically := community.AcceptRequestToJoinAutomatically() || community.HasMember(signer) - if acceptAutomatically { - if community.IsControlNode() { - err = m.markRequestToJoin(signer, community) + // If user is already a member, then accept request automatically + // It may happen when member removes itself from community and then tries to rejoin + // More specifically, CommunityRequestToLeave may be delivered later than CommunityRequestToJoin, or not delivered at all + acceptAutomatically := community.AcceptRequestToJoinAutomatically() || community.HasMember(signer) + // If the request to join was already accepted by another admin, + // we mark it as accepted so it won't be in pending state, even if the community + // is not set to auto-accept + acceptedByAdmin := existingRequestToJoin != nil && existingRequestToJoin.State == RequestToJoinStateAcceptedPending + if acceptAutomatically || acceptedByAdmin { + err = m.markRequestToJoinAsAccepted(signer, community) if err != nil { return nil, err } // Don't check permissions here, // it will be done further in the processing pipeline. requestToJoin.State = RequestToJoinStateAccepted - } else { - err = m.markRequestToJoinAsAcceptedPending(signer, community) - if err != nil { - return nil, err - } - requestToJoin.State = RequestToJoinStateAcceptedPending - } - return requestToJoin, nil - } - - if community.IsControlNode() && len(request.RevealedAccounts) > 0 { - permissionsSatisfied, _, err := m.accountsSatisfyPermissionsToJoin(community, request.RevealedAccounts) - if err != nil { - return nil, err - } - if !permissionsSatisfied { - requestToJoin.State = RequestToJoinStateDeclined - } - if permissionsSatisfied && existingRequestToJoin != nil && existingRequestToJoin.State == RequestToJoinStateAcceptedPending { - err = m.markRequestToJoin(signer, community) - if err != nil { - return nil, err - } - // if the request to join was already accepted by another admin, - // we mark it as accepted so it won't be in pending state, even if the community - // is not set to auto-accept - requestToJoin.State = RequestToJoinStateAccepted + return requestToJoin, nil } } @@ -2882,7 +2839,7 @@ func (m *Manager) HandleCommunityRequestToJoinResponse(signer *ecdsa.PublicKey, } if request.Accepted { - err = m.markRequestToJoin(&m.identity.PublicKey, community) + err = m.markRequestToJoinAsAccepted(&m.identity.PublicKey, community) if err != nil { return nil, err } diff --git a/protocol/communities/request_to_join.go b/protocol/communities/request_to_join.go index 9c7478b4c..0fae0e937 100644 --- a/protocol/communities/request_to_join.go +++ b/protocol/communities/request_to_join.go @@ -74,10 +74,6 @@ func (r *RequestToJoin) Empty() bool { return len(r.ID)+len(r.PublicKey)+int(r.Clock)+len(r.ENSName)+len(r.ChatID)+len(r.CommunityID)+int(r.State) == 0 } -func (r *RequestToJoin) MarkedAsPendingByPrivilegedAccount() bool { - return r.State == RequestToJoinStateAcceptedPending || r.State == RequestToJoinStateDeclinedPending -} - func AddTimeoutToRequestToJoinClock(clock uint64) (uint64, error) { requestToJoinClock, err := strconv.ParseInt(fmt.Sprint(clock), 10, 64) if err != nil { diff --git a/protocol/communities_events_owner_without_community_key_test.go b/protocol/communities_events_owner_without_community_key_test.go index 8e4dcedc8..8427476a3 100644 --- a/protocol/communities_events_owner_without_community_key_test.go +++ b/protocol/communities_events_owner_without_community_key_test.go @@ -147,15 +147,6 @@ func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerRejectMemberRequ testRejectMemberRequestToJoin(s, community, user) } -func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerRequestToJoinStateCannotBeOverridden() { - additionalOwner := s.newMessenger("", []string{}) - community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER, []*Messenger{additionalOwner}) - - // set up additional user that will send request to join - user := s.newMessenger("", []string{}) - testEventSenderCannotOverrideRequestToJoinState(s, community, user, additionalOwner) -} - func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerControlNodeHandlesMultipleEventSenderRequestToJoinDecisions() { additionalOwner := s.newMessenger("", []string{}) community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER, []*Messenger{additionalOwner}) diff --git a/protocol/communities_events_token_master_test.go b/protocol/communities_events_token_master_test.go index dc34e6643..d0a4b4f94 100644 --- a/protocol/communities_events_token_master_test.go +++ b/protocol/communities_events_token_master_test.go @@ -168,15 +168,6 @@ func (s *TokenMasterCommunityEventsSuite) TestTokenMasterRejectMemberRequestToJo testRejectMemberRequestToJoin(s, community, user) } -func (s *TokenMasterCommunityEventsSuite) TestTokenMasterRequestToJoinStateCannotBeOverridden() { - additionalTokenMaster := s.newMessenger("", []string{}) - community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{additionalTokenMaster}) - - // set up additional user that will send request to join - user := s.newMessenger("", []string{}) - testEventSenderCannotOverrideRequestToJoinState(s, community, user, additionalTokenMaster) -} - func (s *TokenMasterCommunityEventsSuite) TestTokenMasterControlNodeHandlesMultipleEventSenderRequestToJoinDecisions() { additionalTokenMaster := s.newMessenger("qwerty", []string{eventsSenderAccountAddress}) community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{additionalTokenMaster}) diff --git a/protocol/communities_events_utils_test.go b/protocol/communities_events_utils_test.go index 5b1a9453f..75aa34b3e 100644 --- a/protocol/communities_events_utils_test.go +++ b/protocol/communities_events_utils_test.go @@ -1211,6 +1211,26 @@ func testAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders(base Commu s.Require().NoError(err) s.Require().Len(acceptedPendingRequests, 1) s.Require().Equal(acceptedPendingRequests[0].PublicKey, common.PubkeyToHex(&user.identity.PublicKey)) + + // event sender 1 changes its mind and rejects the request + rejectRequestToJoin := &requests.DeclineRequestToJoinCommunity{ID: sentRequest.ID} + response, err = base.GetEventSender().DeclineRequestToJoinCommunity(rejectRequestToJoin) + s.Require().NoError(err) + s.Require().NotNil(response) + + // event sender 2 receives updated decision of other event sender + _, err = WaitOnMessengerResponse( + additionalEventSender, + func(r *MessengerResponse) bool { return len(r.Communities()) > 0 }, + "event sender did not receive community request to join", + ) + s.Require().NoError(err) + + // at this point, the request to join is in declined/pending state for event sender 2 + rejectedPendingRequests, err := additionalEventSender.DeclinedPendingRequestsToJoinForCommunity(community.ID()) + s.Require().NoError(err) + s.Require().Len(rejectedPendingRequests, 1) + s.Require().Equal(rejectedPendingRequests[0].PublicKey, common.PubkeyToHex(&user.identity.PublicKey)) } func testRejectMemberRequestToJoinResponseSharedWithOtherEventSenders(base CommunityEventsTestsInterface, community *communities.Community, user *Messenger, additionalEventSender *Messenger) { @@ -1269,6 +1289,27 @@ func testRejectMemberRequestToJoinResponseSharedWithOtherEventSenders(base Commu s.Require().NoError(err) s.Require().Len(rejectedPendingRequests, 1) s.Require().Equal(rejectedPendingRequests[0].PublicKey, common.PubkeyToHex(&user.identity.PublicKey)) + + // event sender 1 changes its mind and accepts the request + acceptRequestToJoin := &requests.AcceptRequestToJoinCommunity{ID: sentRequest.ID} + response, err = base.GetEventSender().AcceptRequestToJoinCommunity(acceptRequestToJoin) + s.Require().NoError(err) + s.Require().NotNil(response) + s.Require().Len(response.Communities(), 1) + + // event sender 2 receives updated decision of other event sender + _, err = WaitOnMessengerResponse( + additionalEventSender, + func(r *MessengerResponse) bool { return len(r.Communities()) > 0 }, + "event sender did not receive community request to join", + ) + s.Require().NoError(err) + + // at this point, the request to join is in accepted/pending state for event sender 2 + acceptedPendingRequests, err := additionalEventSender.AcceptedPendingRequestsToJoinForCommunity(community.ID()) + s.Require().NoError(err) + s.Require().Len(acceptedPendingRequests, 1) + s.Require().Equal(acceptedPendingRequests[0].PublicKey, common.PubkeyToHex(&user.identity.PublicKey)) } func testRejectMemberRequestToJoin(base CommunityEventsTestsInterface, community *communities.Community, user *Messenger) { @@ -1367,78 +1408,6 @@ func testRejectMemberRequestToJoin(base CommunityEventsTestsInterface, community s.Require().Len(declinedRequestsPending, 0) } -func testEventSenderCannotOverrideRequestToJoinState(base CommunityEventsTestsInterface, community *communities.Community, user *Messenger, additionalEventSender *Messenger) { - _, err := user.Start() - - s := base.GetSuite() - s.Require().NoError(err) - defer user.Shutdown() // nolint: errcheck - - advertiseCommunityTo(s, community, base.GetControlNode(), user) - - // user sends request to join - requestToJoin := &requests.RequestToJoinCommunity{CommunityID: community.ID()} - response, err := user.RequestToJoinCommunity(requestToJoin) - s.Require().NoError(err) - s.Require().NotNil(response) - s.Require().Len(response.RequestsToJoinCommunity, 1) - - sentRequest := response.RequestsToJoinCommunity[0] - - // event sender receives request to join - _, err = WaitOnMessengerResponse( - base.GetEventSender(), - func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity) > 0 }, - "event sender did not receive community request to join", - ) - s.Require().NoError(err) - - // event sender 2 receives request to join - _, err = WaitOnMessengerResponse( - additionalEventSender, - func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity) > 0 }, - "event sender did not receive community request to join", - ) - s.Require().NoError(err) - s.Require().Len(response.RequestsToJoinCommunity, 1) - - // request is pending for event sener 2 - pendingRequests, err := additionalEventSender.PendingRequestsToJoinForCommunity(community.ID()) - s.Require().NoError(err) - s.Require().NotNil(pendingRequests) - s.Require().Len(pendingRequests, 1) - - // event sender 1 rejects request to join - rejectRequestToJoin := &requests.DeclineRequestToJoinCommunity{ID: sentRequest.ID} - _, err = base.GetEventSender().DeclineRequestToJoinCommunity(rejectRequestToJoin) - s.Require().NoError(err) - - // request to join is now marked as rejected pending for event sender 1 - rejectedPendingRequests, err := base.GetEventSender().DeclinedPendingRequestsToJoinForCommunity(community.ID()) - s.Require().NoError(err) - s.Require().NotNil(rejectedPendingRequests) - s.Require().Len(rejectedPendingRequests, 1) - - // event sender 2 receives event sender 1's decision - _, err = WaitOnMessengerResponse( - additionalEventSender, - func(r *MessengerResponse) bool { return len(r.Communities()) > 0 }, - "event sender did not receive community request to join", - ) - s.Require().NoError(err) - - // request to join is now marked as rejected pending for event sender 2 - rejectedPendingRequests, err = additionalEventSender.DeclinedPendingRequestsToJoinForCommunity(community.ID()) - s.Require().NoError(err) - s.Require().NotNil(rejectedPendingRequests) - s.Require().Len(rejectedPendingRequests, 1) - - // event sender 2 should not be able to override that pending state - acceptRequestToJoin := &requests.AcceptRequestToJoinCommunity{ID: sentRequest.ID} - _, err = additionalEventSender.AcceptRequestToJoinCommunity(acceptRequestToJoin) - s.Require().Error(err) -} - func testControlNodeHandlesMultipleEventSenderRequestToJoinDecisions(base CommunityEventsTestsInterface, community *communities.Community, user *Messenger, additionalEventSender *Messenger) { _, err := user.Start() diff --git a/protocol/communities_messenger_admin_test.go b/protocol/communities_messenger_admin_test.go index fbd1d3429..79d1f9ee7 100644 --- a/protocol/communities_messenger_admin_test.go +++ b/protocol/communities_messenger_admin_test.go @@ -175,15 +175,6 @@ func (s *AdminCommunityEventsSuite) TestAdminRejectMemberRequestToJoin() { testRejectMemberRequestToJoin(s, community, user) } -func (s *AdminCommunityEventsSuite) TestAdminRequestToJoinStateCannotBeOverridden() { - additionalAdmin := s.newMessenger("qwerty", []string{eventsSenderAccountAddress}) - community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{additionalAdmin}) - - // set up additional user that will send request to join - user := s.newMessenger("", []string{}) - testEventSenderCannotOverrideRequestToJoinState(s, community, user, additionalAdmin) -} - func (s *AdminCommunityEventsSuite) TestAdminControlNodeHandlesMultipleEventSenderRequestToJoinDecisions() { additionalAdmin := s.newMessenger("qwerty", []string{eventsSenderAccountAddress}) community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{additionalAdmin}) @@ -402,7 +393,7 @@ func (s *AdminCommunityEventsSuite) TestAdminDoesNotHaveRejectedEventsLoop() { s.Require().NoError(err) // Update community clock without publishing new CommunityDescription - err = community.DeclineRequestToJoin(nil) + _, err = community.DeclineRequestToJoin(nil) s.Require().NoError(err) err = s.owner.communitiesManager.SaveCommunity(community) diff --git a/protocol/messenger_handler.go b/protocol/messenger_handler.go index 2a6009d1a..3d48f6bc7 100644 --- a/protocol/messenger_handler.go +++ b/protocol/messenger_handler.go @@ -1435,8 +1435,12 @@ func (m *Messenger) HandleCommunityRequestToJoin(state *ReceivedMessageState, re if err != nil { return err } + // not interested, stop further processing + if requestToJoin == nil { + return nil + } - if requestToJoin.State == communities.RequestToJoinStateAccepted || requestToJoin.State == communities.RequestToJoinStateAcceptedPending { + if requestToJoin.State == communities.RequestToJoinStateAccepted { accept := &requests.AcceptRequestToJoinCommunity{ ID: requestToJoin.ID, } @@ -1452,7 +1456,7 @@ func (m *Messenger) HandleCommunityRequestToJoin(state *ReceivedMessageState, re } } - if requestToJoin.State == communities.RequestToJoinStateDeclined || requestToJoin.State == communities.RequestToJoinStateDeclinedPending { + if requestToJoin.State == communities.RequestToJoinStateDeclined { cancel := &requests.DeclineRequestToJoinCommunity{ ID: requestToJoin.ID, }