feat: allow for pending community request state changes

iterates: status-im/status-desktop#11842
This commit is contained in:
Patryk Osmaczko 2023-10-04 21:02:17 +02:00 committed by osmaczko
parent a17ee052fb
commit bb7273cf6f
8 changed files with 150 additions and 249 deletions

View file

@ -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 {

View file

@ -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
}

View file

@ -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 {

View file

@ -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})

View file

@ -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})

View file

@ -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()

View file

@ -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)

View file

@ -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,
}