From ebadfb3e7b5bd3638cb891717facab9ecc0d65be Mon Sep 17 00:00:00 2001 From: Mykhailo Prakhov <117639195+mprakhov@users.noreply.github.com> Date: Tue, 8 Aug 2023 17:02:56 +0200 Subject: [PATCH] feat: allow owner without community private key to manage privileged community permissions (#3861) feat: allow owner without community private key to manage privileged permissions --- protocol/communities/community.go | 28 ++- ...events_owner_without_community_key_test.go | 150 +++----------- .../communities_events_token_master_test.go | 87 ++++---- protocol/communities_events_utils_test.go | 196 +++++++++++------- protocol/communities_messenger_admin_test.go | 87 ++++---- .../communities_messenger_helpers_test.go | 89 ++++++++ ...nities_messenger_token_permissions_test.go | 82 +------- 7 files changed, 359 insertions(+), 360 deletions(-) diff --git a/protocol/communities/community.go b/protocol/communities/community.go index 86b03ee60..63a81f244 100644 --- a/protocol/communities/community.go +++ b/protocol/communities/community.go @@ -1096,6 +1096,10 @@ func (o *Community) IsTokenMaster() bool { return o.IsMemberTokenMaster(o.config.MemberIdentity) } +func (o *Community) IsAdmin() bool { + return o.IsMemberAdmin(o.config.MemberIdentity) +} + func (o *Community) GetPrivilegedMembers() []*ecdsa.PublicKey { privilegedMembers := make([]*ecdsa.PublicKey, 0) members := o.GetMemberPubkeys() @@ -1437,9 +1441,11 @@ func (o *Community) AddTokenPermission(permission *protobuf.CommunityTokenPermis defer o.mutex.Unlock() isControlNode := o.IsControlNode() - allowedToSendEvents := o.HasPermissionToSendCommunityEvents() + allowedToManageMemberPermissions := o.IsTokenMaster() || o.IsAdmin() + allowedToManageAllPermissions := o.IsOwnerWithoutCommunityKey() - if !isControlNode && !allowedToSendEvents || (allowedToSendEvents && permission.Type == protobuf.CommunityTokenPermission_BECOME_ADMIN) { + if (!isControlNode && !allowedToManageMemberPermissions && !allowedToManageAllPermissions) || + (allowedToManageMemberPermissions && permission.Type != protobuf.CommunityTokenPermission_BECOME_MEMBER) { return nil, ErrNotEnoughPermissions } @@ -1448,7 +1454,7 @@ func (o *Community) AddTokenPermission(permission *protobuf.CommunityTokenPermis return nil, err } - if allowedToSendEvents { + if allowedToManageMemberPermissions || allowedToManageAllPermissions { err := o.addNewCommunityEvent(o.ToCommunityTokenPermissionChangeCommunityEvent(permission)) if err != nil { return nil, err @@ -1468,9 +1474,11 @@ func (o *Community) UpdateTokenPermission(permissionID string, tokenPermission * defer o.mutex.Unlock() isControlNode := o.IsControlNode() - allowedToSendEvents := o.HasPermissionToSendCommunityEvents() + allowedToManageMemberPermissions := o.IsTokenMaster() || o.IsAdmin() + allowedToManageAllPermissions := o.IsOwnerWithoutCommunityKey() - if !isControlNode && !allowedToSendEvents || (allowedToSendEvents && tokenPermission.Type == protobuf.CommunityTokenPermission_BECOME_ADMIN) { + if (!isControlNode && !allowedToManageMemberPermissions && !allowedToManageAllPermissions) || + (allowedToManageMemberPermissions && tokenPermission.Type != protobuf.CommunityTokenPermission_BECOME_MEMBER) { return nil, ErrNotEnoughPermissions } @@ -1479,7 +1487,7 @@ func (o *Community) UpdateTokenPermission(permissionID string, tokenPermission * return nil, err } - if allowedToSendEvents { + if allowedToManageMemberPermissions || allowedToManageAllPermissions { err := o.addNewCommunityEvent(o.ToCommunityTokenPermissionChangeCommunityEvent(tokenPermission)) if err != nil { return nil, err @@ -1505,9 +1513,11 @@ func (o *Community) DeleteTokenPermission(permissionID string) (*CommunityChange } isControlNode := o.IsControlNode() - allowedToSendEvents := o.HasPermissionToSendCommunityEvents() + allowedToManageMemberPermissions := o.IsTokenMaster() || o.IsAdmin() + allowedToManageAllPermissions := o.IsOwnerWithoutCommunityKey() - if !isControlNode && !allowedToSendEvents || (allowedToSendEvents && permission.Type == protobuf.CommunityTokenPermission_BECOME_ADMIN) { + if (!isControlNode && !allowedToManageMemberPermissions && !allowedToManageAllPermissions) || + (allowedToManageMemberPermissions && permission.Type != protobuf.CommunityTokenPermission_BECOME_MEMBER) { return nil, ErrNotEnoughPermissions } @@ -1516,7 +1526,7 @@ func (o *Community) DeleteTokenPermission(permissionID string) (*CommunityChange return nil, err } - if allowedToSendEvents { + if allowedToManageMemberPermissions || allowedToManageAllPermissions { err := o.addNewCommunityEvent(o.ToCommunityTokenPermissionDeleteCommunityEvent(permission)) if err != nil { return nil, err diff --git a/protocol/communities_events_owner_without_community_key_test.go b/protocol/communities_events_owner_without_community_key_test.go index 4401d642c..af6d16d61 100644 --- a/protocol/communities_events_owner_without_community_key_test.go +++ b/protocol/communities_events_owner_without_community_key_test.go @@ -1,18 +1,18 @@ package protocol import ( - "crypto/ecdsa" "testing" "github.com/stretchr/testify/suite" "go.uber.org/zap" + gethcommon "github.com/ethereum/go-ethereum/common" + hexutil "github.com/ethereum/go-ethereum/common/hexutil" + gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" - "github.com/status-im/status-go/eth-node/crypto" "github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/protocol/common" "github.com/status-im/status-go/protocol/protobuf" - "github.com/status-im/status-go/protocol/requests" "github.com/status-im/status-go/protocol/tt" "github.com/status-im/status-go/waku" ) @@ -28,8 +28,9 @@ type OwnerWithoutCommunityKeyCommunityEventsSuite struct { alice *Messenger // If one wants to send messages between different instances of Messenger, // a single Waku service should be shared. - shh types.Waku - logger *zap.Logger + shh types.Waku + logger *zap.Logger + mockedBalances map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big // chainID, account, token, balance } func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) GetControlNode() *Messenger { @@ -57,15 +58,17 @@ func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) SetupTest() { s.shh = gethbridge.NewGethWakuWrapper(shh) s.Require().NoError(shh.Start()) - s.controlNode = s.newMessenger() - s.ownerWithoutCommunityKey = s.newMessenger() - s.alice = s.newMessenger() + s.controlNode = s.newMessenger("", []string{}) + s.ownerWithoutCommunityKey = s.newMessenger("qwerty", []string{commmunitiesEventsEventSenderAddress}) + s.alice = s.newMessenger("", []string{}) _, err := s.controlNode.Start() s.Require().NoError(err) _, err = s.ownerWithoutCommunityKey.Start() s.Require().NoError(err) _, err = s.alice.Start() s.Require().NoError(err) + + s.mockedBalances = createMockedWalletBalance(&s.Suite) } func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TearDownTest() { @@ -75,18 +78,8 @@ func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TearDownTest() { _ = s.logger.Sync() } -func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) newMessengerWithKey(shh types.Waku, privateKey *ecdsa.PrivateKey) *Messenger { - messenger, err := newCommunitiesTestMessenger(shh, privateKey, s.logger, nil, nil) - s.Require().NoError(err) - - return messenger -} - -func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) newMessenger() *Messenger { - privateKey, err := crypto.GenerateKey() - s.Require().NoError(err) - - return s.newMessengerWithKey(s.shh, privateKey) +func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) newMessenger(password string, walletAddresses []string) *Messenger { + return newMessenger(&s.Suite, s.shh, s.logger, password, walletAddresses, &s.mockedBalances) } func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerEditCommunityDescription() { @@ -102,114 +95,31 @@ func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerCreateEditDelete func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerCreateEditDeleteBecomeMemberPermission() { community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER) - testCreateEditDeleteBecomeMemberPermission(s, community) + testCreateEditDeleteBecomeMemberPermission(s, community, protobuf.CommunityTokenPermission_BECOME_MEMBER) } -func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerCannotCreateBecomeAdminPermission() { +func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerCreateEditDeleteBecomeAdminPermission() { community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER) - - permissionRequest := createTestPermissionRequest(community) - permissionRequest.Type = protobuf.CommunityTokenPermission_BECOME_ADMIN - - response, err := s.ownerWithoutCommunityKey.CreateCommunityTokenPermission(permissionRequest) - s.Require().Nil(response) - s.Require().Error(err) + testCreateEditDeleteBecomeMemberPermission(s, community, protobuf.CommunityTokenPermission_BECOME_ADMIN) } -func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerCannotEditBecomeAdminPermission() { +func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerCreateEditDeleteBecomeTokenMasterPermission() { community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER) - permissionRequest := createTestPermissionRequest(community) - permissionRequest.Type = protobuf.CommunityTokenPermission_BECOME_ADMIN - - // control node creates BECOME_ADMIN permission - response, err := s.controlNode.CreateCommunityTokenPermission(permissionRequest) - s.Require().NoError(err) - - var tokenPermissionID string - for id := range response.CommunityChanges[0].TokenPermissionsAdded { - tokenPermissionID = id - } - s.Require().NotEqual(tokenPermissionID, "") - - ownerCommunity, err := s.controlNode.communitiesManager.GetByID(community.ID()) - s.Require().NoError(err) - assertCheckTokenPermissionCreated(&s.Suite, ownerCommunity) - - // then, ensure event sender receives updated community - _, err = WaitOnMessengerResponse( - s.ownerWithoutCommunityKey, - func(r *MessengerResponse) bool { return len(r.Communities()) > 0 }, - "event sender did not receive updated community", - ) - s.Require().NoError(err) - eventSenderCommunity, err := s.ownerWithoutCommunityKey.communitiesManager.GetByID(community.ID()) - s.Require().NoError(err) - assertCheckTokenPermissionCreated(&s.Suite, eventSenderCommunity) - - permissionRequest.TokenCriteria[0].Symbol = "UPDATED" - permissionRequest.TokenCriteria[0].Amount = "200" - - permissionEditRequest := &requests.EditCommunityTokenPermission{ - PermissionID: tokenPermissionID, - CreateCommunityTokenPermission: *permissionRequest, - } - - // then, event sender tries to edit permission - response, err = s.ownerWithoutCommunityKey.EditCommunityTokenPermission(permissionEditRequest) - s.Require().Error(err) - s.Require().Nil(response) -} - -func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerCannotDeleteBecomeAdminPermission() { - - community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER) - permissionRequest := createTestPermissionRequest(community) - permissionRequest.Type = protobuf.CommunityTokenPermission_BECOME_ADMIN - - // control node creates BECOME_ADMIN permission - response, err := s.controlNode.CreateCommunityTokenPermission(permissionRequest) - s.Require().NoError(err) - - var tokenPermissionID string - for id := range response.CommunityChanges[0].TokenPermissionsAdded { - tokenPermissionID = id - } - s.Require().NotEqual(tokenPermissionID, "") - - // then, ensure event sender receives updated community - _, err = WaitOnMessengerResponse( - s.ownerWithoutCommunityKey, - func(r *MessengerResponse) bool { return len(r.Communities()) > 0 }, - "event sender did not receive updated community", - ) - s.Require().NoError(err) - eventSenderCommunity, err := s.ownerWithoutCommunityKey.communitiesManager.GetByID(community.ID()) - s.Require().NoError(err) - assertCheckTokenPermissionCreated(&s.Suite, eventSenderCommunity) - - deleteTokenPermission := &requests.DeleteCommunityTokenPermission{ - CommunityID: community.ID(), - PermissionID: tokenPermissionID, - } - - // then event sender tries to delete BECOME_ADMIN permission which should fail - response, err = s.ownerWithoutCommunityKey.DeleteCommunityTokenPermission(deleteTokenPermission) - s.Require().Error(err) - s.Require().Nil(response) + testCreateEditDeleteBecomeMemberPermission(s, community, protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER) } func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders() { - additionalOwner := s.newMessenger() + 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() + user := s.newMessenger("", []string{}) testAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders(s, community, user, additionalOwner) } func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerAcceptMemberRequestToJoinNotConfirmedByControlNode() { community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER, []*Messenger{}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testAcceptMemberRequestToJoinNotConfirmedByControlNode(s, community, user) } @@ -217,22 +127,22 @@ func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerAcceptMemberRequ community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER, []*Messenger{}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testAcceptMemberRequestToJoin(s, community, user) } func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerRejectMemberRequestToJoinResponseSharedWithOtherEventSenders() { - additionalOwner := s.newMessenger() + 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() + user := s.newMessenger("", []string{}) testAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders(s, community, user, additionalOwner) } func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerRejectMemberRequestToJoinNotConfirmedByControlNode() { community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER, []*Messenger{}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testRejectMemberRequestToJoinNotConfirmedByControlNode(s, community, user) } @@ -240,25 +150,25 @@ func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerRejectMemberRequ community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER, []*Messenger{}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testRejectMemberRequestToJoin(s, community, user) } func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerRequestToJoinStateCannotBeOverridden() { - additionalOwner := s.newMessenger() + 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() + user := s.newMessenger("", []string{}) testEventSenderCannotOverrideRequestToJoinState(s, community, user, additionalOwner) } func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerControlNodeHandlesMultipleEventSenderRequestToJoinDecisions() { - additionalOwner := s.newMessenger() + 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() + user := s.newMessenger("", []string{}) testControlNodeHandlesMultipleEventSenderRequestToJoinDecisions(s, community, user, additionalOwner) } diff --git a/protocol/communities_events_token_master_test.go b/protocol/communities_events_token_master_test.go index 37a090abb..8a3f4e8c9 100644 --- a/protocol/communities_events_token_master_test.go +++ b/protocol/communities_events_token_master_test.go @@ -1,14 +1,15 @@ package protocol import ( - "crypto/ecdsa" "testing" "github.com/stretchr/testify/suite" "go.uber.org/zap" + gethcommon "github.com/ethereum/go-ethereum/common" + hexutil "github.com/ethereum/go-ethereum/common/hexutil" + gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" - "github.com/status-im/status-go/eth-node/crypto" "github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/protocol/common" "github.com/status-im/status-go/protocol/protobuf" @@ -27,8 +28,9 @@ type TokenMasterCommunityEventsSuite struct { alice *Messenger // If one wants to send messages between different instances of Messenger, // a single Waku service should be shared. - shh types.Waku - logger *zap.Logger + shh types.Waku + logger *zap.Logger + mockedBalances map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big // chainID, account, token, balance } func (s *TokenMasterCommunityEventsSuite) GetControlNode() *Messenger { @@ -56,15 +58,17 @@ func (s *TokenMasterCommunityEventsSuite) SetupTest() { s.shh = gethbridge.NewGethWakuWrapper(shh) s.Require().NoError(shh.Start()) - s.controlNode = s.newMessenger() - s.tokenMaster = s.newMessenger() - s.alice = s.newMessenger() + s.controlNode = s.newMessenger("", []string{}) + s.tokenMaster = s.newMessenger("qwerty", []string{commmunitiesEventsEventSenderAddress}) + s.alice = s.newMessenger("", []string{}) _, err := s.controlNode.Start() s.Require().NoError(err) _, err = s.tokenMaster.Start() s.Require().NoError(err) _, err = s.alice.Start() s.Require().NoError(err) + + s.mockedBalances = createMockedWalletBalance(&s.Suite) } func (s *TokenMasterCommunityEventsSuite) TearDownTest() { @@ -74,18 +78,8 @@ func (s *TokenMasterCommunityEventsSuite) TearDownTest() { _ = s.logger.Sync() } -func (s *TokenMasterCommunityEventsSuite) newMessengerWithKey(shh types.Waku, privateKey *ecdsa.PrivateKey) *Messenger { - messenger, err := newCommunitiesTestMessenger(shh, privateKey, s.logger, nil, nil) - s.Require().NoError(err) - - return messenger -} - -func (s *TokenMasterCommunityEventsSuite) newMessenger() *Messenger { - privateKey, err := crypto.GenerateKey() - s.Require().NoError(err) - - return s.newMessengerWithKey(s.shh, privateKey) +func (s *TokenMasterCommunityEventsSuite) newMessenger(password string, walletAddresses []string) *Messenger { + return newMessenger(&s.Suite, s.shh, s.logger, password, walletAddresses, &s.mockedBalances) } func (s *TokenMasterCommunityEventsSuite) TestTokenMasterEditCommunityDescription() { @@ -100,89 +94,102 @@ func (s *TokenMasterCommunityEventsSuite) TestTokenMasterCreateEditDeleteChannel func (s *TokenMasterCommunityEventsSuite) TestTokenMasterCreateEditDeleteBecomeMemberPermission() { community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER) - testCreateEditDeleteBecomeMemberPermission(s, community) + testCreateEditDeleteBecomeMemberPermission(s, community, protobuf.CommunityTokenPermission_BECOME_MEMBER) } func (s *TokenMasterCommunityEventsSuite) TestTokenMasterCannotCreateBecomeAdminPermission() { community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER) + testEventSenderCannotCreatePrivilegedCommunityPermission(s, community, protobuf.CommunityTokenPermission_BECOME_ADMIN) +} - permissionRequest := createTestPermissionRequest(community) - permissionRequest.Type = protobuf.CommunityTokenPermission_BECOME_ADMIN - - response, err := s.tokenMaster.CreateCommunityTokenPermission(permissionRequest) - s.Require().Nil(response) - s.Require().Error(err) +func (s *TokenMasterCommunityEventsSuite) TestTokenMasterCannotCreateBecomeTokenMasterPermission() { + community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER) + testEventSenderCannotCreatePrivilegedCommunityPermission(s, community, protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER) } func (s *TokenMasterCommunityEventsSuite) TestTokenMasterCannotEditBecomeAdminPermission() { community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER) - testEventSenderCannotEditBecomeAdminPermission(s, community) + testEventSenderCannotEditPrivilegedCommunityPermission( + s, community, protobuf.CommunityTokenPermission_BECOME_ADMIN, protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER) +} + +func (s *TokenMasterCommunityEventsSuite) TestTokenMasterCannotEditBecomeTokenMasterPermission() { + community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER) + testEventSenderCannotEditPrivilegedCommunityPermission( + s, community, protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER) } func (s *TokenMasterCommunityEventsSuite) TestTokenMasterCannotDeleteBecomeAdminPermission() { community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER) - testEventSenderCannotDeleteBecomeAdminPermission(s, community) + testEventSenderCannotDeletePrivilegedCommunityPermission( + s, community, protobuf.CommunityTokenPermission_BECOME_ADMIN, protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER) +} + +func (s *TokenMasterCommunityEventsSuite) TestTokenMasterCannotDeleteBecomeTokenMasterPermission() { + community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER) + testEventSenderCannotDeletePrivilegedCommunityPermission( + s, community, protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER) } func (s *TokenMasterCommunityEventsSuite) TestTokenMasterAcceptMemberRequestToJoinNotConfirmedByControlNode() { community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testAcceptMemberRequestToJoinNotConfirmedByControlNode(s, community, user) } func (s *TokenMasterCommunityEventsSuite) TestTokenMasterAcceptMemberRequestToJoin() { community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testAcceptMemberRequestToJoin(s, community, user) } func (s *TokenMasterCommunityEventsSuite) TestTokenMasterAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders() { - additionalTokenMaster := s.newMessenger() + additionalTokenMaster := s.newMessenger("qwerty", []string{commmunitiesEventsEventSenderAddress}) community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{additionalTokenMaster}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders(s, community, user, additionalTokenMaster) } func (s *TokenMasterCommunityEventsSuite) TestTokenMasterRejectMemberRequestToJoinResponseSharedWithOtherEventSenders() { - additionalTokenMaster := s.newMessenger() + additionalTokenMaster := s.newMessenger("qwerty", []string{commmunitiesEventsEventSenderAddress}) community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{additionalTokenMaster}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testRejectMemberRequestToJoinResponseSharedWithOtherEventSenders(s, community, user, additionalTokenMaster) } func (s *TokenMasterCommunityEventsSuite) TestTokenMasterRejectMemberRequestToJoinNotConfirmedByControlNode() { community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testRejectMemberRequestToJoinNotConfirmedByControlNode(s, community, user) } func (s *TokenMasterCommunityEventsSuite) TestTokenMasterRejectMemberRequestToJoin() { community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testRejectMemberRequestToJoin(s, community, user) } func (s *TokenMasterCommunityEventsSuite) TestTokenMasterRequestToJoinStateCannotBeOverridden() { - additionalTokenMaster := s.newMessenger() + 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() + user := s.newMessenger("", []string{}) testEventSenderCannotOverrideRequestToJoinState(s, community, user, additionalTokenMaster) } func (s *TokenMasterCommunityEventsSuite) TestTokenMasterControlNodeHandlesMultipleEventSenderRequestToJoinDecisions() { - additionalTokenMaster := s.newMessenger() + additionalTokenMaster := s.newMessenger("qwerty", []string{commmunitiesEventsEventSenderAddress}) community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{additionalTokenMaster}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testControlNodeHandlesMultipleEventSenderRequestToJoinDecisions(s, community, user, additionalTokenMaster) } diff --git a/protocol/communities_events_utils_test.go b/protocol/communities_events_utils_test.go index d36c83aee..f39d1687b 100644 --- a/protocol/communities_events_utils_test.go +++ b/protocol/communities_events_utils_test.go @@ -7,6 +7,9 @@ import ( "github.com/stretchr/testify/suite" + gethcommon "github.com/ethereum/go-ethereum/common" + hexutil "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/protocol/common" "github.com/status-im/status-go/protocol/communities" @@ -22,6 +25,10 @@ type CommunityEventsTestsInterface interface { GetSuite() *suite.Suite } +const commmunitiesEventsTestTokenAddress = "0x0400000000000000000000000000000000000000" +const commmunitiesEventsTestChainID = 1 +const commmunitiesEventsEventSenderAddress = "0x0200000000000000000000000000000000000000" + type MessageResponseValidator func(*MessengerResponse) error type WaitResponseValidator func(*MessengerResponse) bool @@ -77,6 +84,24 @@ func refreshMessengerResponses(base CommunityEventsTestsInterface) { base.GetSuite().Require().NoError(err) } +func createMockedWalletBalance(s *suite.Suite) map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big { + eventSenderAddress := gethcommon.HexToAddress(commmunitiesEventsEventSenderAddress) + + mockedBalances := make(map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big) + mockedBalances[testChainID1] = make(map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big) + mockedBalances[testChainID1][eventSenderAddress] = make(map[gethcommon.Address]*hexutil.Big) + + // event sender will have token with `commmunitiesEventsTestTokenAddress`` + contractAddress := gethcommon.HexToAddress(commmunitiesEventsTestTokenAddress) + balance, ok := new(big.Int).SetString("200", 10) + s.Require().True(ok) + decimalsFactor := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(18)), nil) + balance.Mul(balance, decimalsFactor) + + mockedBalances[commmunitiesEventsTestChainID][eventSenderAddress][contractAddress] = (*hexutil.Big)(balance) + return mockedBalances +} + func setUpCommunityAndRoles(base CommunityEventsTestsInterface, role protobuf.CommunityMember_Roles) *communities.Community { tcs2, err := base.GetControlNode().communitiesManager.All() suite := base.GetSuite() @@ -91,9 +116,21 @@ func setUpCommunityAndRoles(base CommunityEventsTestsInterface, role protobuf.Co advertiseCommunityTo(suite, community, base.GetControlNode(), base.GetEventSender()) advertiseCommunityTo(suite, community, base.GetControlNode(), base.GetMember()) - request := &requests.RequestToJoinCommunity{CommunityID: community.ID()} + request := &requests.RequestToJoinCommunity{ + CommunityID: community.ID(), + AddressesToReveal: []string{commmunitiesEventsEventSenderAddress}, + Password: "qwerty1", + AirdropAddress: commmunitiesEventsEventSenderAddress, + } joinCommunity(suite, community, base.GetControlNode(), base.GetEventSender(), request) refreshMessengerResponses(base) + + request = &requests.RequestToJoinCommunity{ + CommunityID: community.ID(), + AddressesToReveal: []string{"0x0300000000000000000000000000000000000000"}, + Password: "qwerty2", + AirdropAddress: "0x0300000000000000000000000000000000000000", + } joinCommunity(suite, community, base.GetControlNode(), base.GetMember(), request) refreshMessengerResponses(base) @@ -220,14 +257,14 @@ func deleteCommunityChannel(base CommunityEventsTestsInterface, community *commu checkClientsReceivedAdminEvent(base, WaitCommunityCondition, checkChannelDeleted) } -func createTestPermissionRequest(community *communities.Community) *requests.CreateCommunityTokenPermission { +func createTestPermissionRequest(community *communities.Community, pType protobuf.CommunityTokenPermission_Type) *requests.CreateCommunityTokenPermission { return &requests.CreateCommunityTokenPermission{ CommunityID: community.ID(), - Type: protobuf.CommunityTokenPermission_BECOME_MEMBER, + Type: pType, TokenCriteria: []*protobuf.TokenCriteria{ { Type: protobuf.CommunityTokenType_ERC20, - ContractAddresses: map[uint64]string{uint64(1): "0x123"}, + ContractAddresses: map[uint64]string{uint64(commmunitiesEventsTestChainID): commmunitiesEventsTestTokenAddress}, Symbol: "TEST", Amount: "100", Decimals: uint64(18), @@ -243,7 +280,7 @@ func createTokenPermission(base CommunityEventsTestsInterface, community *commun return err } - if !modifiedCommmunity.HasTokenPermissions() { + if len(modifiedCommmunity.TokenPermissionsByType(request.Type)) == 0 { return errors.New("new token permission was not found") } @@ -267,8 +304,8 @@ func createTokenPermission(base CommunityEventsTestsInterface, community *commun return tokenPermissionID, request } -func createTestTokenPermission(base CommunityEventsTestsInterface, community *communities.Community) (string, *requests.CreateCommunityTokenPermission) { - createTokenPermissionRequest := createTestPermissionRequest(community) +func createTestTokenPermission(base CommunityEventsTestsInterface, community *communities.Community, pType protobuf.CommunityTokenPermission_Type) (string, *requests.CreateCommunityTokenPermission) { + createTokenPermissionRequest := createTestPermissionRequest(community, pType) return createTokenPermission(base, community, createTokenPermissionRequest) } @@ -280,7 +317,7 @@ func editTokenPermission(base CommunityEventsTestsInterface, community *communit return err } - assertCheckTokenPermissionEdited(s, modifiedCommmunity) + assertCheckTokenPermissionEdited(s, modifiedCommmunity, request.CreateCommunityTokenPermission.Type) return nil } @@ -292,8 +329,8 @@ func editTokenPermission(base CommunityEventsTestsInterface, community *communit checkClientsReceivedAdminEvent(base, WaitCommunityCondition, checkTokenPermissionEdit) } -func assertCheckTokenPermissionEdited(s *suite.Suite, community *communities.Community) { - permissions := community.TokenPermissionsByType(protobuf.CommunityTokenPermission_BECOME_MEMBER) +func assertCheckTokenPermissionEdited(s *suite.Suite, community *communities.Community, pType protobuf.CommunityTokenPermission_Type) { + permissions := community.TokenPermissionsByType(pType) s.Require().Len(permissions, 1) s.Require().Len(permissions[0].TokenCriteria, 1) s.Require().Equal(permissions[0].TokenCriteria[0].Type, protobuf.CommunityTokenType_ERC20) @@ -324,12 +361,8 @@ func deleteTokenPermission(base CommunityEventsTestsInterface, community *commun checkClientsReceivedAdminEvent(base, WaitCommunityCondition, checkTokenPermissionDeleted) } -func assertCheckTokenPermissionCreated(s *suite.Suite, community *communities.Community) { - permissions := make([]*protobuf.CommunityTokenPermission, 0) - tokenPermissions := community.TokenPermissions() - for _, p := range tokenPermissions { - permissions = append(permissions, p) - } +func assertCheckTokenPermissionCreated(s *suite.Suite, community *communities.Community, pType protobuf.CommunityTokenPermission_Type) { + permissions := community.TokenPermissionsByType(pType) s.Require().Len(permissions, 1) s.Require().Len(permissions[0].TokenCriteria, 1) s.Require().Equal(permissions[0].TokenCriteria[0].Type, protobuf.CommunityTokenType_ERC20) @@ -712,6 +745,40 @@ func editCommunityDescription(base CommunityEventsTestsInterface, community *com checkClientsReceivedAdminEvent(base, WaitCommunityCondition, checkCommunityEdit) } +func controlNodeCreatesCommunityPermission(base CommunityEventsTestsInterface, community *communities.Community, permissionRequest *requests.CreateCommunityTokenPermission) string { + // control node creates permission + response, err := base.GetControlNode().CreateCommunityTokenPermission(permissionRequest) + s := base.GetSuite() + s.Require().NoError(err) + + var tokenPermissionID string + for id := range response.CommunityChanges[0].TokenPermissionsAdded { + tokenPermissionID = id + } + s.Require().NotEqual(tokenPermissionID, "") + + ownerCommunity, err := base.GetControlNode().communitiesManager.GetByID(community.ID()) + s.Require().NoError(err) + assertCheckTokenPermissionCreated(s, ownerCommunity, permissionRequest.Type) + + // then, ensure event sender receives updated community + _, err = WaitOnMessengerResponse( + base.GetEventSender(), + func(r *MessengerResponse) bool { + return len(r.Communities()) > 0 && + len(r.Communities()[0].TokenPermissionsByType(permissionRequest.Type)) > 0 + }, + "event sender did not receive community token permission", + ) + s.Require().NoError(err) + eventSenderCommunity, err := base.GetEventSender().communitiesManager.GetByID(community.ID()) + s.Require().NoError(err) + assertCheckTokenPermissionCreated(s, eventSenderCommunity, permissionRequest.Type) + s.Require().True(eventSenderCommunity.HasPermissionToSendCommunityEvents()) + + return tokenPermissionID +} + func testCreateEditDeleteChannels(base CommunityEventsTestsInterface, community *communities.Community) { newChat := &protobuf.CommunityChat{ Permissions: &protobuf.CommunityPermissions{ @@ -731,9 +798,9 @@ func testCreateEditDeleteChannels(base CommunityEventsTestsInterface, community deleteCommunityChannel(base, community, newChatID) } -func testCreateEditDeleteBecomeMemberPermission(base CommunityEventsTestsInterface, community *communities.Community) { +func testCreateEditDeleteBecomeMemberPermission(base CommunityEventsTestsInterface, community *communities.Community, pType protobuf.CommunityTokenPermission_Type) { // first, create token permission - tokenPermissionID, createTokenPermission := createTestTokenPermission(base, community) + tokenPermissionID, createTokenPermission := createTestTokenPermission(base, community, pType) createTokenPermission.TokenCriteria[0].Symbol = "UPDATED" createTokenPermission.TokenCriteria[0].Amount = "200" @@ -784,6 +851,15 @@ func testAcceptMemberRequestToJoin(base CommunityEventsTestsInterface, community s.Require().NoError(err) s.Require().Len(response.RequestsToJoinCommunity, 1) + // control node receives request to join + response, err = WaitOnMessengerResponse( + base.GetControlNode(), + 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) + // event sender has not accepted request yet eventSenderCommunity, err := base.GetEventSender().GetCommunityByID(community.ID()) s.Require().NoError(err) @@ -1560,72 +1636,42 @@ func testMemberReceiveEventsWhenControlNodeOffline(base CommunityEventsTestsInte waitOnMessengerResponse(s, WaitCommunityCondition, checkChannelDeleted, eventSender) } -func testEventSenderCannotDeleteBecomeAdminPermission(base CommunityEventsTestsInterface, community *communities.Community) { - permissionRequest := createTestPermissionRequest(community) - permissionRequest.Type = protobuf.CommunityTokenPermission_BECOME_ADMIN - - // control node creates BECOME_ADMIN permission - response, err := base.GetControlNode().CreateCommunityTokenPermission(permissionRequest) - s := base.GetSuite() - s.Require().NoError(err) - - var tokenPermissionID string - for id := range response.CommunityChanges[0].TokenPermissionsAdded { - tokenPermissionID = id +func testEventSenderCannotDeletePrivilegedCommunityPermission(base CommunityEventsTestsInterface, community *communities.Community, + testPermissionType protobuf.CommunityTokenPermission_Type, rolePermissionType protobuf.CommunityTokenPermission_Type) { + // Community should have eventSenderRole permission or eventSender will loose his role + // after control node create a new community permission + if testPermissionType != rolePermissionType { + rolePermission := createTestPermissionRequest(community, rolePermissionType) + controlNodeCreatesCommunityPermission(base, community, rolePermission) } - s.Require().NotEqual(tokenPermissionID, "") - // then, ensure event sender receives updated community - _, err = WaitOnMessengerResponse( - base.GetEventSender(), - func(r *MessengerResponse) bool { return len(r.Communities()) > 0 }, - "event sender did not receive updated community", - ) - s.Require().NoError(err) - eventSenderCommunity, err := base.GetEventSender().communitiesManager.GetByID(community.ID()) - s.Require().NoError(err) - assertCheckTokenPermissionCreated(s, eventSenderCommunity) + permissionRequest := createTestPermissionRequest(community, testPermissionType) + tokenPermissionID := controlNodeCreatesCommunityPermission(base, community, permissionRequest) deleteTokenPermission := &requests.DeleteCommunityTokenPermission{ CommunityID: community.ID(), PermissionID: tokenPermissionID, } - // then event sender tries to delete BECOME_ADMIN permission which should fail - response, err = base.GetEventSender().DeleteCommunityTokenPermission(deleteTokenPermission) + // then event sender tries to delete permission which should fail + response, err := base.GetEventSender().DeleteCommunityTokenPermission(deleteTokenPermission) + s := base.GetSuite() s.Require().Error(err) s.Require().Nil(response) } -func testEventSenderCannotEditBecomeAdminPermission(base CommunityEventsTestsInterface, community *communities.Community) { - permissionRequest := createTestPermissionRequest(community) - permissionRequest.Type = protobuf.CommunityTokenPermission_BECOME_ADMIN +func testEventSenderCannotEditPrivilegedCommunityPermission(base CommunityEventsTestsInterface, community *communities.Community, + testPermissionType protobuf.CommunityTokenPermission_Type, rolePermissionType protobuf.CommunityTokenPermission_Type) { - // control node creates BECOME_ADMIN permission - response, err := base.GetControlNode().CreateCommunityTokenPermission(permissionRequest) - s := base.GetSuite() - s.Require().NoError(err) - - var tokenPermissionID string - for id := range response.CommunityChanges[0].TokenPermissionsAdded { - tokenPermissionID = id + // Community should have eventSenderRole permission or eventSender will loose his role + // after control node create a new community permission + if testPermissionType != rolePermissionType { + rolePermission := createTestPermissionRequest(community, rolePermissionType) + controlNodeCreatesCommunityPermission(base, community, rolePermission) } - s.Require().NotEqual(tokenPermissionID, "") - ownerCommunity, err := base.GetControlNode().communitiesManager.GetByID(community.ID()) - s.Require().NoError(err) - assertCheckTokenPermissionCreated(s, ownerCommunity) - - // then, ensure event sender receives updated community - _, err = WaitOnMessengerResponse( - base.GetEventSender(), - func(r *MessengerResponse) bool { return len(r.Communities()) > 0 }, - "event sender did not receive updated community", - ) - s.Require().NoError(err) - eventSenderCommunity, err := base.GetEventSender().communitiesManager.GetByID(community.ID()) - s.Require().NoError(err) - assertCheckTokenPermissionCreated(s, eventSenderCommunity) + permissionRequest := createTestPermissionRequest(community, testPermissionType) + tokenPermissionID := controlNodeCreatesCommunityPermission(base, community, permissionRequest) permissionRequest.TokenCriteria[0].Symbol = "UPDATED" permissionRequest.TokenCriteria[0].Amount = "200" @@ -1636,7 +1682,8 @@ func testEventSenderCannotEditBecomeAdminPermission(base CommunityEventsTestsInt } // then, event sender tries to edit permission - response, err = base.GetEventSender().EditCommunityTokenPermission(permissionEditRequest) + response, err := base.GetEventSender().EditCommunityTokenPermission(permissionEditRequest) + s := base.GetSuite() s.Require().Error(err) s.Require().Nil(response) } @@ -1683,3 +1730,12 @@ func testEventSenderAddedCommunityToken(base CommunityEventsTestsInterface, comm checkClientsReceivedAdminEvent(base, WaitCommunityCondition, checkTokenAdded) } + +func testEventSenderCannotCreatePrivilegedCommunityPermission(base CommunityEventsTestsInterface, community *communities.Community, pType protobuf.CommunityTokenPermission_Type) { + permissionRequest := createTestPermissionRequest(community, pType) + + response, err := base.GetEventSender().CreateCommunityTokenPermission(permissionRequest) + s := base.GetSuite() + s.Require().Nil(response) + s.Require().Error(err) +} diff --git a/protocol/communities_messenger_admin_test.go b/protocol/communities_messenger_admin_test.go index aeb7fcd4d..781a177a9 100644 --- a/protocol/communities_messenger_admin_test.go +++ b/protocol/communities_messenger_admin_test.go @@ -1,15 +1,16 @@ package protocol import ( - "crypto/ecdsa" "math/big" "testing" "github.com/stretchr/testify/suite" "go.uber.org/zap" + gethcommon "github.com/ethereum/go-ethereum/common" + hexutil "github.com/ethereum/go-ethereum/common/hexutil" + gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" - "github.com/status-im/status-go/eth-node/crypto" "github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/protocol/common" "github.com/status-im/status-go/protocol/communities" @@ -30,8 +31,9 @@ type AdminCommunityEventsSuite struct { alice *Messenger // If one wants to send messages between different instances of Messenger, // a single Waku service should be shared. - shh types.Waku - logger *zap.Logger + shh types.Waku + logger *zap.Logger + mockedBalances map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big // chainID, account, token, balance } func (s *AdminCommunityEventsSuite) GetControlNode() *Messenger { @@ -59,15 +61,17 @@ func (s *AdminCommunityEventsSuite) SetupTest() { s.shh = gethbridge.NewGethWakuWrapper(shh) s.Require().NoError(shh.Start()) - s.owner = s.newMessenger() - s.admin = s.newMessenger() - s.alice = s.newMessenger() + s.owner = s.newMessenger("", []string{}) + s.admin = s.newMessenger("qwerty", []string{commmunitiesEventsEventSenderAddress}) + s.alice = s.newMessenger("", []string{}) _, err := s.owner.Start() s.Require().NoError(err) _, err = s.admin.Start() s.Require().NoError(err) _, err = s.alice.Start() s.Require().NoError(err) + + s.mockedBalances = createMockedWalletBalance(&s.Suite) } func (s *AdminCommunityEventsSuite) TearDownTest() { @@ -77,18 +81,8 @@ func (s *AdminCommunityEventsSuite) TearDownTest() { _ = s.logger.Sync() } -func (s *AdminCommunityEventsSuite) newMessengerWithKey(shh types.Waku, privateKey *ecdsa.PrivateKey) *Messenger { - messenger, err := newCommunitiesTestMessenger(shh, privateKey, s.logger, nil, nil) - s.Require().NoError(err) - - return messenger -} - -func (s *AdminCommunityEventsSuite) newMessenger() *Messenger { - privateKey, err := crypto.GenerateKey() - s.Require().NoError(err) - - return s.newMessengerWithKey(s.shh, privateKey) +func (s *AdminCommunityEventsSuite) newMessenger(password string, walletAddresses []string) *Messenger { + return newMessenger(&s.Suite, s.shh, s.logger, password, walletAddresses, &s.mockedBalances) } func (s *AdminCommunityEventsSuite) TestAdminEditCommunityDescription() { @@ -104,42 +98,55 @@ func (s *AdminCommunityEventsSuite) TestAdminCreateEditDeleteChannels() { func (s *AdminCommunityEventsSuite) TestAdminCreateEditDeleteBecomeMemberPermission() { community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN) - testCreateEditDeleteBecomeMemberPermission(s, community) + testCreateEditDeleteBecomeMemberPermission(s, community, protobuf.CommunityTokenPermission_BECOME_MEMBER) } func (s *AdminCommunityEventsSuite) TestAdminCannotCreateBecomeAdminPermission() { community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN) + testEventSenderCannotCreatePrivilegedCommunityPermission(s, community, protobuf.CommunityTokenPermission_BECOME_ADMIN) +} - permissionRequest := createTestPermissionRequest(community) - permissionRequest.Type = protobuf.CommunityTokenPermission_BECOME_ADMIN - - response, err := s.admin.CreateCommunityTokenPermission(permissionRequest) - s.Require().Nil(response) - s.Require().Error(err) +func (s *AdminCommunityEventsSuite) TestAdminCannotCreateBecomeTokenMasterPermission() { + community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN) + testEventSenderCannotCreatePrivilegedCommunityPermission(s, community, protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER) } func (s *AdminCommunityEventsSuite) TestAdminCannotEditBecomeAdminPermission() { community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN) - testEventSenderCannotEditBecomeAdminPermission(s, community) + testEventSenderCannotEditPrivilegedCommunityPermission( + s, community, protobuf.CommunityTokenPermission_BECOME_ADMIN, protobuf.CommunityTokenPermission_BECOME_ADMIN) +} + +func (s *AdminCommunityEventsSuite) TestAdminCannotEditBecomeTokenMasterPermission() { + community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN) + testEventSenderCannotEditPrivilegedCommunityPermission( + s, community, protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, protobuf.CommunityTokenPermission_BECOME_ADMIN) } func (s *AdminCommunityEventsSuite) TestAdminCannotDeleteBecomeAdminPermission() { community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN) - testEventSenderCannotDeleteBecomeAdminPermission(s, community) + testEventSenderCannotDeletePrivilegedCommunityPermission( + s, community, protobuf.CommunityTokenPermission_BECOME_ADMIN, protobuf.CommunityTokenPermission_BECOME_ADMIN) +} + +func (s *AdminCommunityEventsSuite) TestAdminCannotDeleteBecomeTokenMasterPermission() { + community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN) + testEventSenderCannotDeletePrivilegedCommunityPermission( + s, community, protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, protobuf.CommunityTokenPermission_BECOME_ADMIN) } func (s *AdminCommunityEventsSuite) TestAdminAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders() { - additionalAdmin := s.newMessenger() + additionalAdmin := s.newMessenger("qwerty", []string{commmunitiesEventsEventSenderAddress}) community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{additionalAdmin}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders(s, community, user, additionalAdmin) } func (s *AdminCommunityEventsSuite) TestAdminAcceptMemberRequestToJoinNotConfirmedByControlNode() { community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testAcceptMemberRequestToJoinNotConfirmedByControlNode(s, community, user) } @@ -147,15 +154,15 @@ func (s *AdminCommunityEventsSuite) TestAdminAcceptMemberRequestToJoin() { community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testAcceptMemberRequestToJoin(s, community, user) } func (s *AdminCommunityEventsSuite) TestAdminRejectMemberRequestToJoinResponseSharedWithOtherEventSenders() { - additionalAdmin := s.newMessenger() + additionalAdmin := s.newMessenger("qwerty", []string{commmunitiesEventsEventSenderAddress}) community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{additionalAdmin}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testRejectMemberRequestToJoinResponseSharedWithOtherEventSenders(s, community, user, additionalAdmin) } @@ -163,7 +170,7 @@ func (s *AdminCommunityEventsSuite) TestAdminRejectMemberRequestToJoinNotConfirm community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testRejectMemberRequestToJoinNotConfirmedByControlNode(s, community, user) } @@ -171,25 +178,25 @@ func (s *AdminCommunityEventsSuite) TestAdminRejectMemberRequestToJoin() { community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testRejectMemberRequestToJoin(s, community, user) } func (s *AdminCommunityEventsSuite) TestAdminRequestToJoinStateCannotBeOverridden() { - additionalAdmin := s.newMessenger() + additionalAdmin := s.newMessenger("qwerty", []string{commmunitiesEventsEventSenderAddress}) community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{additionalAdmin}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testEventSenderCannotOverrideRequestToJoinState(s, community, user, additionalAdmin) } func (s *AdminCommunityEventsSuite) TestAdminControlNodeHandlesMultipleEventSenderRequestToJoinDecisions() { - additionalAdmin := s.newMessenger() + additionalAdmin := s.newMessenger("qwerty", []string{commmunitiesEventsEventSenderAddress}) community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{additionalAdmin}) // set up additional user that will send request to join - user := s.newMessenger() + user := s.newMessenger("", []string{}) testControlNodeHandlesMultipleEventSenderRequestToJoinDecisions(s, community, user, additionalAdmin) } diff --git a/protocol/communities_messenger_helpers_test.go b/protocol/communities_messenger_helpers_test.go index 75be1c7d0..4167e76af 100644 --- a/protocol/communities_messenger_helpers_test.go +++ b/protocol/communities_messenger_helpers_test.go @@ -6,15 +6,22 @@ import ( "encoding/json" "errors" "io/ioutil" + "sync" + "time" "github.com/google/uuid" "github.com/stretchr/testify/suite" "go.uber.org/zap" + gethcommon "github.com/ethereum/go-ethereum/common" + hexutil "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/status-im/status-go/account" "github.com/status-im/status-go/account/generator" + "github.com/status-im/status-go/eth-node/crypto" "github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/multiaccounts" + "github.com/status-im/status-go/multiaccounts/accounts" "github.com/status-im/status-go/multiaccounts/settings" "github.com/status-im/status-go/params" "github.com/status-im/status-go/protocol/common" @@ -25,6 +32,88 @@ import ( "github.com/status-im/status-go/protocol/tt" ) +type AccountManagerMock struct { + AccountsMap map[string]string +} + +func (m *AccountManagerMock) GetVerifiedWalletAccount(db *accounts.Database, address, password string) (*account.SelectedExtKey, error) { + return &account.SelectedExtKey{ + Address: types.HexToAddress(address), + }, nil +} + +func (m *AccountManagerMock) CanRecover(rpcParams account.RecoverParams, revealedAddress types.Address) (bool, error) { + return true, nil +} + +func (m *AccountManagerMock) Sign(rpcParams account.SignParams, verifiedAccount *account.SelectedExtKey) (result types.HexBytes, err error) { + return types.HexBytes{}, nil +} + +func (m *AccountManagerMock) DeleteAccount(address types.Address) error { + return nil +} + +type TokenManagerMock struct { + Balances *map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big +} + +func (m *TokenManagerMock) GetAllChainIDs() ([]uint64, error) { + chainIDs := make([]uint64, 0, len(*m.Balances)) + for key := range *m.Balances { + chainIDs = append(chainIDs, key) + } + return chainIDs, nil +} + +func (m *TokenManagerMock) GetBalancesByChain(ctx context.Context, accounts, tokenAddresses []gethcommon.Address, chainIDs []uint64) (map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big, error) { + time.Sleep(100 * time.Millisecond) // simulate response time + return *m.Balances, nil +} + +func newMessenger(s *suite.Suite, shh types.Waku, logger *zap.Logger, password string, walletAddresses []string, + mockedBalances *map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big) *Messenger { + accountsManagerMock := &AccountManagerMock{} + accountsManagerMock.AccountsMap = make(map[string]string) + for _, walletAddress := range walletAddresses { + accountsManagerMock.AccountsMap[walletAddress] = types.EncodeHex(crypto.Keccak256([]byte(password))) + } + + tokenManagerMock := &TokenManagerMock{ + Balances: mockedBalances, + } + + privateKey, err := crypto.GenerateKey() + s.Require().NoError(err) + + messenger, err := newCommunitiesTestMessenger(shh, privateKey, logger, accountsManagerMock, tokenManagerMock) + s.Require().NoError(err) + + currentDistributorObj, ok := messenger.communitiesKeyDistributor.(*CommunitiesKeyDistributorImpl) + s.Require().True(ok) + messenger.communitiesKeyDistributor = &TestCommunitiesKeyDistributor{ + CommunitiesKeyDistributorImpl: *currentDistributorObj, + subscriptions: map[chan *CommunityAndKeyActions]bool{}, + mutex: sync.RWMutex{}, + } + + // add wallet account with keypair + for _, walletAddress := range walletAddresses { + kp := accounts.GetProfileKeypairForTest(false, true, false) + kp.Accounts[0].Address = types.HexToAddress(walletAddress) + err := messenger.settings.SaveOrUpdateKeypair(kp) + s.Require().NoError(err) + } + + walletAccounts, err := messenger.settings.GetActiveAccounts() + s.Require().NoError(err) + s.Require().Len(walletAccounts, len(walletAddresses)) + for i := range walletAddresses { + s.Require().Equal(walletAccounts[i].Type, accounts.AccountTypeGenerated) + } + return messenger +} + func newCommunitiesTestMessenger(shh types.Waku, privateKey *ecdsa.PrivateKey, logger *zap.Logger, accountsManager account.Manager, tokenManager communities.TokenManager) (*Messenger, error) { tmpfile, err := ioutil.TempFile("", "accounts-tests-") if err != nil { diff --git a/protocol/communities_messenger_token_permissions_test.go b/protocol/communities_messenger_token_permissions_test.go index 896a51718..3bc5eb0b5 100644 --- a/protocol/communities_messenger_token_permissions_test.go +++ b/protocol/communities_messenger_token_permissions_test.go @@ -2,7 +2,6 @@ package protocol import ( "bytes" - "context" "crypto/ecdsa" "errors" "math/big" @@ -15,11 +14,9 @@ import ( gethcommon "github.com/ethereum/go-ethereum/common" hexutil "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/status-im/status-go/account" gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" "github.com/status-im/status-go/eth-node/crypto" "github.com/status-im/status-go/eth-node/types" - "github.com/status-im/status-go/multiaccounts/accounts" "github.com/status-im/status-go/protocol/common" "github.com/status-im/status-go/protocol/communities" "github.com/status-im/status-go/protocol/protobuf" @@ -39,45 +36,6 @@ const aliceAddress1 = "0x0200000000000000000000000000000000000000" const aliceAddress2 = "0x0210000000000000000000000000000000000000" const bobAddress = "0x0300000000000000000000000000000000000000" -type AccountManagerMock struct { - AccountsMap map[string]string -} - -func (m *AccountManagerMock) GetVerifiedWalletAccount(db *accounts.Database, address, password string) (*account.SelectedExtKey, error) { - return &account.SelectedExtKey{ - Address: types.HexToAddress(address), - }, nil -} - -func (m *AccountManagerMock) CanRecover(rpcParams account.RecoverParams, revealedAddress types.Address) (bool, error) { - return true, nil -} - -func (m *AccountManagerMock) Sign(rpcParams account.SignParams, verifiedAccount *account.SelectedExtKey) (result types.HexBytes, err error) { - return types.HexBytes{}, nil -} - -func (m *AccountManagerMock) DeleteAccount(address types.Address) error { - return nil -} - -type TokenManagerMock struct { - Balances *map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big -} - -func (m *TokenManagerMock) GetAllChainIDs() ([]uint64, error) { - chainIDs := make([]uint64, 0, len(*m.Balances)) - for key := range *m.Balances { - chainIDs = append(chainIDs, key) - } - return chainIDs, nil -} - -func (m *TokenManagerMock) GetBalancesByChain(ctx context.Context, accounts, tokenAddresses []gethcommon.Address, chainIDs []uint64) (map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big, error) { - time.Sleep(100 * time.Millisecond) // simulate response time - return *m.Balances, nil -} - type CommunityAndKeyActions struct { community *communities.Community keyActions *communities.EncryptionKeyActions @@ -200,45 +158,7 @@ func (s *MessengerCommunitiesTokenPermissionsSuite) TearDownTest() { } func (s *MessengerCommunitiesTokenPermissionsSuite) newMessenger(password string, walletAddresses []string) *Messenger { - accountsManagerMock := &AccountManagerMock{} - accountsManagerMock.AccountsMap = make(map[string]string) - for _, walletAddress := range walletAddresses { - accountsManagerMock.AccountsMap[walletAddress] = types.EncodeHex(crypto.Keccak256([]byte(password))) - } - - tokenManagerMock := &TokenManagerMock{ - Balances: &s.mockedBalances, - } - - privateKey, err := crypto.GenerateKey() - s.Require().NoError(err) - - messenger, err := newCommunitiesTestMessenger(s.shh, privateKey, s.logger, accountsManagerMock, tokenManagerMock) - s.Require().NoError(err) - - currentDistributorObj, ok := messenger.communitiesKeyDistributor.(*CommunitiesKeyDistributorImpl) - s.Require().True(ok) - messenger.communitiesKeyDistributor = &TestCommunitiesKeyDistributor{ - CommunitiesKeyDistributorImpl: *currentDistributorObj, - subscriptions: map[chan *CommunityAndKeyActions]bool{}, - mutex: sync.RWMutex{}, - } - - // add wallet account with keypair - for _, walletAddress := range walletAddresses { - kp := accounts.GetProfileKeypairForTest(false, true, false) - kp.Accounts[0].Address = types.HexToAddress(walletAddress) - err := messenger.settings.SaveOrUpdateKeypair(kp) - s.Require().NoError(err) - } - - walletAccounts, err := messenger.settings.GetActiveAccounts() - s.Require().NoError(err) - s.Require().Len(walletAccounts, len(walletAddresses)) - for i := range walletAddresses { - s.Require().Equal(walletAccounts[i].Type, accounts.AccountTypeGenerated) - } - return messenger + return newMessenger(&s.Suite, s.shh, s.logger, password, walletAddresses, &s.mockedBalances) } func (s *MessengerCommunitiesTokenPermissionsSuite) joinCommunity(community *communities.Community, user *Messenger, password string, addresses []string) {