github.com/status-im/status-go@v1.1.0/protocol/communities_messenger_token_permissions_test.go (about)

     1  package protocol
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"crypto/ecdsa"
     7  	"errors"
     8  	"fmt"
     9  	"os"
    10  	"strconv"
    11  	"strings"
    12  	"sync"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/google/uuid"
    17  	"github.com/stretchr/testify/suite"
    18  	"go.uber.org/zap"
    19  	"golang.org/x/exp/maps"
    20  
    21  	gethcommon "github.com/ethereum/go-ethereum/common"
    22  	hexutil "github.com/ethereum/go-ethereum/common/hexutil"
    23  	gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
    24  	"github.com/status-im/status-go/eth-node/crypto"
    25  	"github.com/status-im/status-go/eth-node/types"
    26  	"github.com/status-im/status-go/params"
    27  	"github.com/status-im/status-go/protocol/common"
    28  	"github.com/status-im/status-go/protocol/common/shard"
    29  	"github.com/status-im/status-go/protocol/communities"
    30  	"github.com/status-im/status-go/protocol/protobuf"
    31  	"github.com/status-im/status-go/protocol/requests"
    32  	"github.com/status-im/status-go/protocol/transport"
    33  	"github.com/status-im/status-go/protocol/tt"
    34  	"github.com/status-im/status-go/services/wallet/thirdparty"
    35  )
    36  
    37  const testChainID1 = 1
    38  
    39  const ownerPassword = "123456"
    40  const alicePassword = "qwerty"
    41  const bobPassword = "bob123"
    42  
    43  const ownerAddress = "0x0100000000000000000000000000000000000000"
    44  const aliceAddress1 = "0x0200000000000000000000000000000000000000"
    45  const aliceAddress2 = "0x0210000000000000000000000000000000000000"
    46  const bobAddress = "0x0300000000000000000000000000000000000000"
    47  
    48  type CommunityAndKeyActions struct {
    49  	community  *communities.Community
    50  	keyActions *communities.EncryptionKeyActions
    51  }
    52  
    53  type TestCommunitiesKeyDistributor struct {
    54  	CommunitiesKeyDistributorImpl
    55  
    56  	subscriptions map[chan *CommunityAndKeyActions]bool
    57  	mutex         sync.RWMutex
    58  }
    59  
    60  func (tckd *TestCommunitiesKeyDistributor) Generate(community *communities.Community, keyActions *communities.EncryptionKeyActions) error {
    61  	return tckd.CommunitiesKeyDistributorImpl.Generate(community, keyActions)
    62  }
    63  
    64  func (tckd *TestCommunitiesKeyDistributor) Distribute(community *communities.Community, keyActions *communities.EncryptionKeyActions) error {
    65  	err := tckd.CommunitiesKeyDistributorImpl.Distribute(community, keyActions)
    66  	if err != nil {
    67  		return err
    68  	}
    69  
    70  	// notify distribute finished
    71  	tckd.mutex.RLock()
    72  	for s := range tckd.subscriptions {
    73  		s <- &CommunityAndKeyActions{
    74  			community:  community,
    75  			keyActions: keyActions,
    76  		}
    77  	}
    78  	tckd.mutex.RUnlock()
    79  
    80  	return nil
    81  }
    82  
    83  func (tckd *TestCommunitiesKeyDistributor) subscribeToKeyDistribution() chan *CommunityAndKeyActions {
    84  	subscription := make(chan *CommunityAndKeyActions, 40)
    85  	tckd.mutex.Lock()
    86  	defer tckd.mutex.Unlock() // Ensure the mutex is always unlocked
    87  	tckd.subscriptions[subscription] = true
    88  	return subscription
    89  }
    90  
    91  func (tckd *TestCommunitiesKeyDistributor) unsubscribeFromKeyDistribution(subscription chan *CommunityAndKeyActions) {
    92  	tckd.mutex.Lock()
    93  	delete(tckd.subscriptions, subscription)
    94  	tckd.mutex.Unlock()
    95  	close(subscription)
    96  }
    97  
    98  func (tckd *TestCommunitiesKeyDistributor) waitOnKeyDistribution(condition func(*CommunityAndKeyActions) bool) <-chan error {
    99  	errCh := make(chan error, 1)
   100  
   101  	subscription := tckd.subscribeToKeyDistribution()
   102  
   103  	go func() {
   104  		defer func() {
   105  			close(errCh)
   106  
   107  			tckd.unsubscribeFromKeyDistribution(subscription)
   108  		}()
   109  
   110  		for {
   111  			select {
   112  			case s, more := <-subscription:
   113  				if !more {
   114  					errCh <- errors.New("channel closed when waiting for key distribution")
   115  					return
   116  				}
   117  
   118  				if condition(s) {
   119  					return
   120  				}
   121  
   122  			case <-time.After(5 * time.Second):
   123  				errCh <- errors.New("timed out when waiting for key distribution")
   124  				return
   125  			}
   126  		}
   127  	}()
   128  
   129  	return errCh
   130  }
   131  
   132  func TestMessengerCommunitiesTokenPermissionsSuite(t *testing.T) {
   133  	suite.Run(t, new(MessengerCommunitiesTokenPermissionsSuite))
   134  }
   135  
   136  type MessengerCommunitiesTokenPermissionsSuite struct {
   137  	suite.Suite
   138  	owner *Messenger
   139  	bob   *Messenger
   140  	alice *Messenger
   141  
   142  	ownerWaku types.Waku
   143  	bobWaku   types.Waku
   144  	aliceWaku types.Waku
   145  
   146  	logger *zap.Logger
   147  
   148  	mockedBalances          communities.BalancesByChain
   149  	mockedCollectibles      communities.CollectiblesByChain
   150  	collectiblesServiceMock *CollectiblesServiceMock
   151  	collectiblesManagerMock *CollectiblesManagerMock
   152  	accountsTestData        map[string][]string
   153  	accountsPasswords       map[string]string
   154  }
   155  
   156  func (s *MessengerCommunitiesTokenPermissionsSuite) SetupTest() {
   157  	// Initialize with nil to avoid panics in TearDownTest
   158  	s.owner = nil
   159  	s.bob = nil
   160  	s.alice = nil
   161  	s.ownerWaku = nil
   162  	s.bobWaku = nil
   163  	s.aliceWaku = nil
   164  
   165  	s.accountsTestData = make(map[string][]string)
   166  	s.accountsPasswords = make(map[string]string)
   167  
   168  	s.mockedCollectibles = make(communities.CollectiblesByChain)
   169  	s.collectiblesManagerMock = &CollectiblesManagerMock{
   170  		Collectibles: &s.mockedCollectibles,
   171  	}
   172  	s.resetMockedBalances()
   173  
   174  	s.logger = tt.MustCreateTestLogger()
   175  
   176  	wakuNodes := CreateWakuV2Network(&s.Suite, s.logger, []string{"owner", "bob", "alice"})
   177  
   178  	s.ownerWaku = wakuNodes[0]
   179  	s.owner = s.newMessenger(ownerPassword, []string{ownerAddress}, s.ownerWaku, "owner", []Option{})
   180  
   181  	s.bobWaku = wakuNodes[1]
   182  	s.bob = s.newMessenger(bobPassword, []string{bobAddress}, s.bobWaku, "bob", []Option{})
   183  	s.bob.EnableBackedupMessagesProcessing()
   184  
   185  	s.aliceWaku = wakuNodes[2]
   186  	s.alice = s.newMessenger(alicePassword, []string{aliceAddress1, aliceAddress2}, s.aliceWaku, "alice", []Option{})
   187  
   188  	_, err := s.owner.Start()
   189  	s.Require().NoError(err)
   190  	_, err = s.bob.Start()
   191  	s.Require().NoError(err)
   192  	_, err = s.alice.Start()
   193  	s.Require().NoError(err)
   194  }
   195  
   196  func (s *MessengerCommunitiesTokenPermissionsSuite) TearDownTest() {
   197  	TearDownMessenger(&s.Suite, s.owner)
   198  	TearDownMessenger(&s.Suite, s.bob)
   199  	TearDownMessenger(&s.Suite, s.alice)
   200  	if s.ownerWaku != nil {
   201  		s.Require().NoError(gethbridge.GetGethWakuV2From(s.ownerWaku).Stop())
   202  	}
   203  	if s.bobWaku != nil {
   204  		s.Require().NoError(gethbridge.GetGethWakuV2From(s.bobWaku).Stop())
   205  	}
   206  	if s.aliceWaku != nil {
   207  		s.Require().NoError(gethbridge.GetGethWakuV2From(s.aliceWaku).Stop())
   208  	}
   209  	_ = s.logger.Sync()
   210  }
   211  
   212  func (s *MessengerCommunitiesTokenPermissionsSuite) newMessenger(password string, walletAddresses []string, waku types.Waku, name string, extraOptions []Option) *Messenger {
   213  	communityManagerOptions := []communities.ManagerOption{
   214  		communities.WithAllowForcingCommunityMembersReevaluation(true),
   215  	}
   216  	extraOptions = append(extraOptions, WithCommunityManagerOptions(communityManagerOptions))
   217  
   218  	messenger := newTestCommunitiesMessenger(&s.Suite, waku, testCommunitiesMessengerConfig{
   219  		testMessengerConfig: testMessengerConfig{
   220  			logger:       s.logger.Named(name),
   221  			extraOptions: extraOptions,
   222  		},
   223  		password:            password,
   224  		walletAddresses:     walletAddresses,
   225  		mockedBalances:      &s.mockedBalances,
   226  		collectiblesService: s.collectiblesServiceMock,
   227  		collectiblesManager: s.collectiblesManagerMock,
   228  	})
   229  
   230  	publicKey := messenger.IdentityPublicKeyString()
   231  	s.accountsTestData[publicKey] = walletAddresses
   232  	s.accountsPasswords[publicKey] = password
   233  
   234  	return messenger
   235  }
   236  
   237  func (s *MessengerCommunitiesTokenPermissionsSuite) createRequestToJoinCommunity(communityID types.HexBytes, user *Messenger) *requests.RequestToJoinCommunity {
   238  	userPk := user.IdentityPublicKeyString()
   239  	addresses, exists := s.accountsTestData[userPk]
   240  	s.Require().True(exists)
   241  	password, exists := s.accountsPasswords[userPk]
   242  	s.Require().True(exists)
   243  	return createRequestToJoinCommunity(&s.Suite, communityID, user, password, addresses)
   244  }
   245  
   246  func (s *MessengerCommunitiesTokenPermissionsSuite) joinCommunity(community *communities.Community, user *Messenger) {
   247  	addresses, exists := s.accountsTestData[user.IdentityPublicKeyString()]
   248  	s.Require().True(exists)
   249  	password, exists := s.accountsPasswords[user.IdentityPublicKeyString()]
   250  	s.Require().True(exists)
   251  	joinCommunity(&s.Suite, community.ID(), s.owner, user, password, addresses)
   252  }
   253  
   254  func (s *MessengerCommunitiesTokenPermissionsSuite) advertiseCommunityTo(community *communities.Community, user *Messenger) {
   255  	advertiseCommunityTo(&s.Suite, community, s.owner, user)
   256  }
   257  
   258  func (s *MessengerCommunitiesTokenPermissionsSuite) createCommunity() (*communities.Community, *Chat) {
   259  	return createCommunity(&s.Suite, s.owner)
   260  }
   261  
   262  func (s *MessengerCommunitiesTokenPermissionsSuite) sendChatMessage(sender *Messenger, chatID string, text string) *common.Message {
   263  	return sendChatMessage(&s.Suite, sender, chatID, text)
   264  }
   265  
   266  func (s *MessengerCommunitiesTokenPermissionsSuite) makeAddressSatisfyTheCriteria(chainID uint64, address string, criteria *protobuf.TokenCriteria) {
   267  	makeAddressSatisfyTheCriteria(&s.Suite, s.mockedBalances, s.mockedCollectibles, chainID, address, criteria)
   268  }
   269  
   270  func (s *MessengerCommunitiesTokenPermissionsSuite) resetMockedBalances() {
   271  	s.mockedBalances = make(map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big)
   272  	s.mockedBalances[testChainID1] = make(map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big)
   273  	s.mockedBalances[testChainID1][gethcommon.HexToAddress(aliceAddress1)] = make(map[gethcommon.Address]*hexutil.Big)
   274  	s.mockedBalances[testChainID1][gethcommon.HexToAddress(aliceAddress2)] = make(map[gethcommon.Address]*hexutil.Big)
   275  	s.mockedBalances[testChainID1][gethcommon.HexToAddress(bobAddress)] = make(map[gethcommon.Address]*hexutil.Big)
   276  
   277  	s.mockedCollectibles = make(communities.CollectiblesByChain)
   278  	s.mockedCollectibles[testChainID1] = make(map[gethcommon.Address]thirdparty.TokenBalancesPerContractAddress)
   279  	s.mockedCollectibles[testChainID1][gethcommon.HexToAddress(aliceAddress1)] = make(thirdparty.TokenBalancesPerContractAddress)
   280  	s.mockedCollectibles[testChainID1][gethcommon.HexToAddress(aliceAddress2)] = make(thirdparty.TokenBalancesPerContractAddress)
   281  	s.mockedCollectibles[testChainID1][gethcommon.HexToAddress(bobAddress)] = make(thirdparty.TokenBalancesPerContractAddress)
   282  }
   283  
   284  func (s *MessengerCommunitiesTokenPermissionsSuite) waitOnKeyDistribution(condition func(*CommunityAndKeyActions) bool) <-chan error {
   285  	testCommunitiesKeyDistributor, ok := s.owner.communitiesKeyDistributor.(*TestCommunitiesKeyDistributor)
   286  	s.Require().True(ok)
   287  	return testCommunitiesKeyDistributor.waitOnKeyDistribution(condition)
   288  }
   289  
   290  func (s *MessengerCommunitiesTokenPermissionsSuite) TestCreateTokenPermission() {
   291  
   292  	community, _ := s.createCommunity()
   293  
   294  	createTokenPermission := &requests.CreateCommunityTokenPermission{
   295  		CommunityID: community.ID(),
   296  		Type:        protobuf.CommunityTokenPermission_BECOME_MEMBER,
   297  		TokenCriteria: []*protobuf.TokenCriteria{
   298  			&protobuf.TokenCriteria{
   299  				Type:              protobuf.CommunityTokenType_ERC20,
   300  				ContractAddresses: map[uint64]string{uint64(testChainID1): "0x123"},
   301  				Symbol:            "TEST",
   302  				AmountInWei:       "100000000000000000000",
   303  				Decimals:          uint64(18),
   304  			},
   305  		},
   306  	}
   307  
   308  	response, err := s.owner.CreateCommunityTokenPermission(createTokenPermission)
   309  	s.Require().NoError(err)
   310  	s.Require().NotNil(response)
   311  	s.Require().Len(response.Communities(), 1)
   312  
   313  	tokenPermissions := response.Communities()[0].TokenPermissions()
   314  	for _, tokenPermission := range tokenPermissions {
   315  		for _, tc := range tokenPermission.TokenCriteria {
   316  			s.Require().Equal(tc.Type, protobuf.CommunityTokenType_ERC20)
   317  			s.Require().Equal(tc.Symbol, "TEST")
   318  			s.Require().Equal(tc.AmountInWei, "100000000000000000000")
   319  			s.Require().Equal(tc.Amount, "100") // automatically upgraded deprecated amount
   320  			s.Require().Equal(tc.Decimals, uint64(18))
   321  		}
   322  	}
   323  }
   324  
   325  func (s *MessengerCommunitiesTokenPermissionsSuite) TestEditTokenPermission() {
   326  
   327  	community, _ := s.createCommunity()
   328  
   329  	tokenPermission := &requests.CreateCommunityTokenPermission{
   330  		CommunityID: community.ID(),
   331  		Type:        protobuf.CommunityTokenPermission_BECOME_MEMBER,
   332  		TokenCriteria: []*protobuf.TokenCriteria{
   333  			&protobuf.TokenCriteria{
   334  				Type:              protobuf.CommunityTokenType_ERC20,
   335  				ContractAddresses: map[uint64]string{testChainID1: "0x123"},
   336  				Symbol:            "TEST",
   337  				AmountInWei:       "100000000000000000000",
   338  				Decimals:          uint64(18),
   339  			},
   340  		},
   341  	}
   342  
   343  	response, err := s.owner.CreateCommunityTokenPermission(tokenPermission)
   344  	s.Require().NoError(err)
   345  	s.Require().NotNil(response)
   346  	s.Require().Len(response.Communities(), 1)
   347  
   348  	tokenPermissions := response.Communities()[0].TokenPermissions()
   349  
   350  	var tokenPermissionID string
   351  	for id := range tokenPermissions {
   352  		tokenPermissionID = id
   353  	}
   354  
   355  	tokenPermission.TokenCriteria[0].Symbol = "TESTUpdated"
   356  	tokenPermission.TokenCriteria[0].AmountInWei = "200000000000000000000"
   357  	tokenPermission.TokenCriteria[0].Decimals = uint64(20)
   358  
   359  	editTokenPermission := &requests.EditCommunityTokenPermission{
   360  		PermissionID:                   tokenPermissionID,
   361  		CreateCommunityTokenPermission: *tokenPermission,
   362  	}
   363  
   364  	response2, err := s.owner.EditCommunityTokenPermission(editTokenPermission)
   365  	s.Require().NoError(err)
   366  	// wait for `checkMemberPermissions` to finish
   367  	time.Sleep(1 * time.Second)
   368  	s.Require().NotNil(response2)
   369  	s.Require().Len(response2.Communities(), 1)
   370  
   371  	tokenPermissions = response2.Communities()[0].TokenPermissions()
   372  	for _, tokenPermission := range tokenPermissions {
   373  		for _, tc := range tokenPermission.TokenCriteria {
   374  			s.Require().Equal(tc.Type, protobuf.CommunityTokenType_ERC20)
   375  			s.Require().Equal(tc.Symbol, "TESTUpdated")
   376  			s.Require().Equal(tc.AmountInWei, "200000000000000000000")
   377  			s.Require().Equal(tc.Amount, "2") // automatically upgraded deprecated amount
   378  			s.Require().Equal(tc.Decimals, uint64(20))
   379  		}
   380  	}
   381  }
   382  
   383  func (s *MessengerCommunitiesTokenPermissionsSuite) TestCommunityTokensMetadata() {
   384  
   385  	community, _ := s.createCommunity()
   386  
   387  	tokensMetadata := community.CommunityTokensMetadata()
   388  	s.Require().Len(tokensMetadata, 0)
   389  
   390  	newToken := &protobuf.CommunityTokenMetadata{
   391  		ContractAddresses: map[uint64]string{testChainID1: "0xasd"},
   392  		Description:       "desc1",
   393  		Image:             "IMG1",
   394  		TokenType:         protobuf.CommunityTokenType_ERC721,
   395  		Symbol:            "SMB",
   396  		Decimals:          3,
   397  		Version:           "1.0.0",
   398  	}
   399  
   400  	_, err := community.AddCommunityTokensMetadata(newToken)
   401  	s.Require().NoError(err)
   402  	tokensMetadata = community.CommunityTokensMetadata()
   403  	s.Require().Len(tokensMetadata, 1)
   404  
   405  	s.Require().Equal(tokensMetadata[0].ContractAddresses, newToken.ContractAddresses)
   406  	s.Require().Equal(tokensMetadata[0].Description, newToken.Description)
   407  	s.Require().Equal(tokensMetadata[0].Image, newToken.Image)
   408  	s.Require().Equal(tokensMetadata[0].TokenType, newToken.TokenType)
   409  	s.Require().Equal(tokensMetadata[0].Symbol, newToken.Symbol)
   410  	s.Require().Equal(tokensMetadata[0].Name, newToken.Name)
   411  	s.Require().Equal(tokensMetadata[0].Decimals, newToken.Decimals)
   412  	s.Require().Equal(tokensMetadata[0].Version, newToken.Version)
   413  }
   414  
   415  // Note: (mprakhov) after providing revealed addresses this test must be fixed
   416  func (s *MessengerCommunitiesTokenPermissionsSuite) TestRequestAccessWithENSTokenPermission() {
   417  	s.T().Skip("flaky test")
   418  	community, _ := createCommunity(&s.Suite, s.owner)
   419  
   420  	createTokenPermission := &requests.CreateCommunityTokenPermission{
   421  		CommunityID: community.ID(),
   422  		Type:        protobuf.CommunityTokenPermission_BECOME_MEMBER,
   423  		TokenCriteria: []*protobuf.TokenCriteria{
   424  			&protobuf.TokenCriteria{
   425  				Type:       protobuf.CommunityTokenType_ENS,
   426  				EnsPattern: "test.stateofus.eth",
   427  			},
   428  		},
   429  	}
   430  
   431  	response, err := s.owner.CreateCommunityTokenPermission(createTokenPermission)
   432  	s.Require().NoError(err)
   433  	s.Require().NotNil(response)
   434  	s.Require().Len(response.Communities(), 1)
   435  
   436  	s.advertiseCommunityTo(community, s.alice)
   437  
   438  	// Make sure declined requests are 0
   439  	declinedRequests, err := s.owner.DeclinedRequestsToJoinForCommunity(community.ID())
   440  	s.Require().NoError(err)
   441  	s.Require().Len(declinedRequests, 0)
   442  
   443  	requestToJoin := s.createRequestToJoinCommunity(community.ID(), s.alice)
   444  	// We try to join the org
   445  	response, err = s.alice.RequestToJoinCommunity(requestToJoin)
   446  	s.Require().NoError(err)
   447  	s.Require().NotNil(response)
   448  	s.Require().Len(response.RequestsToJoinCommunity(), 1)
   449  
   450  	requestToJoin1 := response.RequestsToJoinCommunity()[0]
   451  	s.Require().Equal(communities.RequestToJoinStatePending, requestToJoin1.State)
   452  
   453  	// Retrieve request to join
   454  	err = tt.RetryWithBackOff(func() error {
   455  		_, err = s.owner.RetrieveAll()
   456  		if err != nil {
   457  			return err
   458  		}
   459  		declinedRequests, err := s.owner.DeclinedRequestsToJoinForCommunity(community.ID())
   460  		if err != nil {
   461  			return err
   462  		}
   463  		if len(declinedRequests) != 1 {
   464  			return errors.New("there should be one declined request")
   465  		}
   466  		if !bytes.Equal(requestToJoin1.ID, declinedRequests[0].ID) {
   467  			return errors.New("wrong declined request")
   468  		}
   469  		return nil
   470  	})
   471  	s.Require().NoError(err)
   472  
   473  	// Ensure alice is not a member of the community
   474  	allCommunities, err := s.owner.Communities()
   475  	if bytes.Equal(allCommunities[0].ID(), community.ID()) {
   476  		s.Require().False(allCommunities[0].HasMember(&s.alice.identity.PublicKey))
   477  	}
   478  }
   479  
   480  // NOTE(cammellos): Disabling for now as flaky, for some reason does not pass on CI, but passes locally
   481  func (s *MessengerCommunitiesTokenPermissionsSuite) TestBecomeMemberPermissions() {
   482  	s.T().Skip("flaky test")
   483  
   484  	// Create a store node
   485  	// This is needed to fetch the messages after rejoining the community
   486  	var err error
   487  
   488  	cfg := testWakuV2Config{
   489  		logger:      s.logger.Named("store-node-waku"),
   490  		enableStore: false,
   491  		clusterID:   shard.MainStatusShardCluster,
   492  	}
   493  	wakuStoreNode := NewTestWakuV2(&s.Suite, cfg)
   494  
   495  	storeNodeListenAddresses := wakuStoreNode.ListenAddresses()
   496  	s.Require().LessOrEqual(1, len(storeNodeListenAddresses))
   497  
   498  	storeNodeAddress := storeNodeListenAddresses[0]
   499  	s.logger.Info("store node ready", zap.Stringer("address", storeNodeAddress))
   500  
   501  	// Create messengers
   502  
   503  	wakuNodes := CreateWakuV2Network(&s.Suite, s.logger, []string{"owner", "bob"})
   504  	s.ownerWaku = wakuNodes[0]
   505  	s.bobWaku = wakuNodes[1]
   506  
   507  	options := []Option{
   508  		WithTestStoreNode(&s.Suite, localMailserverID, storeNodeAddress, localFleet, s.collectiblesServiceMock),
   509  	}
   510  
   511  	s.owner = s.newMessenger(ownerPassword, []string{ownerAddress}, s.ownerWaku, "owner", options)
   512  	s.Require().NoError(err)
   513  
   514  	_, err = s.owner.Start()
   515  	s.Require().NoError(err)
   516  
   517  	s.bob = s.newMessenger(bobPassword, []string{bobAddress}, s.bobWaku, "bob", options)
   518  	s.Require().NoError(err)
   519  
   520  	_, err = s.bob.Start()
   521  	s.Require().NoError(err)
   522  
   523  	// Force the owner to use the store node as relay peer
   524  
   525  	err = s.owner.DialPeer(storeNodeAddress)
   526  	s.Require().NoError(err)
   527  
   528  	// Create a community
   529  
   530  	community, chat := s.createCommunity()
   531  
   532  	// bob joins the community
   533  	s.advertiseCommunityTo(community, s.bob)
   534  	s.joinCommunity(community, s.bob)
   535  
   536  	messages := []string{
   537  		"1-message", // RandomLettersString(10), // successful message on open community
   538  		"2-message", // RandomLettersString(11), // failing message on encrypted community
   539  		"3-message", // RandomLettersString(12), // successful message on encrypted community
   540  	}
   541  
   542  	// send message to the channel
   543  	msg := s.sendChatMessage(s.owner, chat.ID, messages[0])
   544  	s.logger.Debug("owner sent a message",
   545  		zap.String("messageText", msg.Text),
   546  		zap.String("messageID", msg.ID),
   547  	)
   548  
   549  	// bob can read the message
   550  	response, err := WaitOnMessengerResponse(
   551  		s.bob,
   552  		func(r *MessengerResponse) bool {
   553  			for _, message := range r.messages {
   554  				if message.Text == msg.Text {
   555  					return true
   556  				}
   557  			}
   558  			return false
   559  		},
   560  		"first message not received",
   561  	)
   562  	s.Require().NoError(err)
   563  	s.Require().Len(response.Messages(), 1)
   564  	s.Require().Equal(msg.Text, response.Messages()[0].Text)
   565  
   566  	bobMessages, _, err := s.bob.MessageByChatID(msg.ChatId, "", 10)
   567  	s.Require().NoError(err)
   568  	s.Require().Len(bobMessages, 1)
   569  	s.Require().Equal(messages[0], bobMessages[0].Text)
   570  
   571  	// setup become member permission
   572  	permissionRequest := requests.CreateCommunityTokenPermission{
   573  		CommunityID: community.ID(),
   574  		Type:        protobuf.CommunityTokenPermission_BECOME_MEMBER,
   575  		TokenCriteria: []*protobuf.TokenCriteria{
   576  			&protobuf.TokenCriteria{
   577  				Type:              protobuf.CommunityTokenType_ERC20,
   578  				ContractAddresses: map[uint64]string{testChainID1: "0x123"},
   579  				Symbol:            "TEST",
   580  				Amount:            "100",
   581  				Decimals:          uint64(18),
   582  			},
   583  		},
   584  	}
   585  
   586  	waitOnBobToBeKicked := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
   587  		return len(sub.Community.Members()) == 1
   588  	})
   589  
   590  	response, err = s.owner.CreateCommunityTokenPermission(&permissionRequest)
   591  	s.Require().NoError(err)
   592  	s.Require().Len(response.Communities(), 1)
   593  
   594  	err = <-waitOnBobToBeKicked
   595  	s.Require().NoError(err)
   596  
   597  	// bob should be kicked from the community,
   598  	// because he doesn't meet the criteria
   599  	community, err = s.owner.communitiesManager.GetByID(community.ID())
   600  	s.Require().NoError(err)
   601  	s.Require().Len(community.Members(), 1)
   602  
   603  	// bob receives community changes
   604  	// chats and members should be empty,
   605  	// this info is available only to members
   606  	_, err = WaitOnMessengerResponse(
   607  		s.bob,
   608  		func(r *MessengerResponse) bool {
   609  			return len(r.Communities()) == 1 && len(community.TokenPermissions()) > 0 && r.Communities()[0].IDString() == community.IDString() && !r.Communities()[0].Joined()
   610  		},
   611  		"no community that satisfies criteria",
   612  	)
   613  	s.Require().NoError(err)
   614  
   615  	// We are not member of the community anymore, so we need to refetch
   616  	// the data, since we would not be pulling it anymore
   617  	_, err = WaitOnMessengerResponse(
   618  		s.bob,
   619  		func(r *MessengerResponse) bool {
   620  			_, err := s.bob.FetchCommunity(&FetchCommunityRequest{WaitForResponse: true, TryDatabase: false, CommunityKey: community.IDString()})
   621  			if err != nil {
   622  				return false
   623  			}
   624  			c, err := s.bob.communitiesManager.GetByID(community.ID())
   625  			return err == nil && c != nil && len(c.TokenPermissions()) > 0 && !c.Joined()
   626  		},
   627  		"no token permissions",
   628  	)
   629  
   630  	s.Require().NoError(err)
   631  
   632  	// bob tries to join, but he doesn't satisfy so the request isn't sent
   633  	request := s.createRequestToJoinCommunity(community.ID(), s.bob)
   634  	_, err = s.bob.RequestToJoinCommunity(request)
   635  	s.Require().ErrorIs(err, communities.ErrPermissionToJoinNotSatisfied)
   636  
   637  	// make sure bob does not have a pending request to join
   638  	pendingRequests, err := s.bob.MyPendingRequestsToJoin()
   639  	s.Require().NoError(err)
   640  	s.Require().Len(pendingRequests, 0)
   641  
   642  	// Send chat message while bob is not in the community
   643  	msg = s.sendChatMessage(s.owner, chat.ID, messages[1])
   644  
   645  	// make bob satisfy the criteria
   646  	s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, permissionRequest.TokenCriteria[0])
   647  
   648  	waitOnCommunityKeyToBeDistributedToBob := s.waitOnKeyDistribution(func(sub *CommunityAndKeyActions) bool {
   649  		return len(sub.community.Description().Members) == 2 &&
   650  			len(sub.keyActions.CommunityKeyAction.Members) == 1 &&
   651  			sub.keyActions.CommunityKeyAction.ActionType == communities.EncryptionKeySendToMembers
   652  	})
   653  
   654  	// bob re-joins the community
   655  	s.joinCommunity(community, s.bob)
   656  
   657  	err = <-waitOnCommunityKeyToBeDistributedToBob
   658  	s.Require().NoError(err)
   659  
   660  	// send message to channel
   661  	msg = s.sendChatMessage(s.owner, chat.ID, messages[2])
   662  	s.logger.Debug("owner sent a message",
   663  		zap.String("messageText", msg.Text),
   664  		zap.String("messageID", msg.ID),
   665  	)
   666  
   667  	// bob can read the message
   668  	_, err = WaitOnMessengerResponse(
   669  		s.bob,
   670  		func(r *MessengerResponse) bool {
   671  			// Bob should have all 3 messages
   672  			bobMessages, _, err = s.bob.MessageByChatID(msg.ChatId, "", 10)
   673  			return err == nil && len(bobMessages) == 3
   674  		},
   675  		"not all 3 messages received",
   676  	)
   677  	bobMessages, _, err = s.bob.MessageByChatID(msg.ChatId, "", 10)
   678  	for _, m := range bobMessages {
   679  		fmt.Printf("ID: %s\n", m.ID)
   680  	}
   681  	s.Require().NoError(err)
   682  }
   683  
   684  func (s *MessengerCommunitiesTokenPermissionsSuite) TestJoinCommunityWithAdminPermission() {
   685  
   686  	community, _ := s.createCommunity()
   687  
   688  	// setup become admin permission
   689  	permissionRequest := requests.CreateCommunityTokenPermission{
   690  		CommunityID: community.ID(),
   691  		Type:        protobuf.CommunityTokenPermission_BECOME_ADMIN,
   692  		TokenCriteria: []*protobuf.TokenCriteria{
   693  			&protobuf.TokenCriteria{
   694  				Type:              protobuf.CommunityTokenType_ERC20,
   695  				ContractAddresses: map[uint64]string{testChainID1: "0x123"},
   696  				Symbol:            "TEST",
   697  				AmountInWei:       "100000000000000000000",
   698  				Decimals:          uint64(18),
   699  			},
   700  		},
   701  	}
   702  
   703  	response, err := s.owner.CreateCommunityTokenPermission(&permissionRequest)
   704  	s.Require().NoError(err)
   705  	s.Require().Len(response.Communities(), 1)
   706  
   707  	s.advertiseCommunityTo(community, s.bob)
   708  
   709  	// Bob should still be able to join even if there is a permission to be an admin
   710  	s.joinCommunity(community, s.bob)
   711  
   712  	// Verify that we have Bob's revealed account
   713  	revealedAccounts, err := s.owner.GetRevealedAccounts(community.ID(), common.PubkeyToHex(&s.bob.identity.PublicKey))
   714  	s.Require().NoError(err)
   715  	s.Require().Len(revealedAccounts, 1)
   716  	s.Require().Equal(bobAddress, revealedAccounts[0].Address)
   717  }
   718  
   719  func (s *MessengerCommunitiesTokenPermissionsSuite) TestJoinCommunityAsMemberWithMemberAndAdminPermission() {
   720  	community, _ := s.createCommunity()
   721  
   722  	waitOnCommunityPermissionCreated := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
   723  		return sub.Community.HasTokenPermissions()
   724  	})
   725  
   726  	// setup become member permission
   727  	permissionRequestMember := requests.CreateCommunityTokenPermission{
   728  		CommunityID: community.ID(),
   729  		Type:        protobuf.CommunityTokenPermission_BECOME_MEMBER,
   730  		TokenCriteria: []*protobuf.TokenCriteria{
   731  			&protobuf.TokenCriteria{
   732  				Type:              protobuf.CommunityTokenType_ERC20,
   733  				ContractAddresses: map[uint64]string{testChainID1: "0x123"},
   734  				Symbol:            "TEST",
   735  				AmountInWei:       "100000000000000000000",
   736  				Decimals:          uint64(18),
   737  			},
   738  		},
   739  	}
   740  	response, err := s.owner.CreateCommunityTokenPermission(&permissionRequestMember)
   741  	s.Require().NoError(err)
   742  	s.Require().Len(response.Communities(), 1)
   743  
   744  	err = <-waitOnCommunityPermissionCreated
   745  	s.Require().NoError(err)
   746  
   747  	// setup become admin permission
   748  	permissionRequestAdmin := requests.CreateCommunityTokenPermission{
   749  		CommunityID: community.ID(),
   750  		Type:        protobuf.CommunityTokenPermission_BECOME_ADMIN,
   751  		TokenCriteria: []*protobuf.TokenCriteria{
   752  			&protobuf.TokenCriteria{
   753  				Type:              protobuf.CommunityTokenType_ERC20,
   754  				ContractAddresses: map[uint64]string{testChainID1: "0x124"},
   755  				Symbol:            "TESTADMIN",
   756  				AmountInWei:       "100000000000000000000",
   757  				Decimals:          uint64(18),
   758  			},
   759  		},
   760  	}
   761  
   762  	waitOnCommunityPermissionCreated = waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
   763  		return len(sub.Community.TokenPermissions()) == 2
   764  	})
   765  
   766  	response, err = s.owner.CreateCommunityTokenPermission(&permissionRequestAdmin)
   767  	s.Require().NoError(err)
   768  	s.Require().Len(response.Communities(), 1)
   769  
   770  	err = <-waitOnCommunityPermissionCreated
   771  	s.Require().NoError(err)
   772  
   773  	// make bob satisfy the member criteria
   774  	s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, permissionRequestMember.TokenCriteria[0])
   775  
   776  	s.advertiseCommunityTo(response.Communities()[0], s.bob)
   777  
   778  	// Bob should still be able to join even though he doesn't satisfy the admin requirement
   779  	// because he satisfies the member one
   780  	s.joinCommunity(community, s.bob)
   781  
   782  	// Verify that we have Bob's revealed account
   783  	revealedAccounts, err := s.owner.GetRevealedAccounts(community.ID(), common.PubkeyToHex(&s.bob.identity.PublicKey))
   784  	s.Require().NoError(err)
   785  	s.Require().Len(revealedAccounts, 1)
   786  	s.Require().Equal(bobAddress, revealedAccounts[0].Address)
   787  }
   788  
   789  func (s *MessengerCommunitiesTokenPermissionsSuite) TestJoinCommunityAsAdminWithMemberAndAdminPermission() {
   790  
   791  	community, _ := s.createCommunity()
   792  
   793  	// setup become member permission
   794  	permissionRequestMember := requests.CreateCommunityTokenPermission{
   795  		CommunityID: community.ID(),
   796  		Type:        protobuf.CommunityTokenPermission_BECOME_MEMBER,
   797  		TokenCriteria: []*protobuf.TokenCriteria{
   798  			&protobuf.TokenCriteria{
   799  				Type:              protobuf.CommunityTokenType_ERC20,
   800  				ContractAddresses: map[uint64]string{testChainID1: "0x123"},
   801  				Symbol:            "TEST",
   802  				AmountInWei:       "100000000000000000000",
   803  				Decimals:          uint64(18),
   804  			},
   805  		},
   806  	}
   807  
   808  	waitOnCommunityPermissionCreated := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
   809  		return sub.Community.HasTokenPermissions()
   810  	})
   811  
   812  	response, err := s.owner.CreateCommunityTokenPermission(&permissionRequestMember)
   813  	s.Require().NoError(err)
   814  	s.Require().Len(response.Communities(), 1)
   815  
   816  	err = <-waitOnCommunityPermissionCreated
   817  	s.Require().NoError(err)
   818  
   819  	// setup become admin permission
   820  	permissionRequestAdmin := requests.CreateCommunityTokenPermission{
   821  		CommunityID: community.ID(),
   822  		Type:        protobuf.CommunityTokenPermission_BECOME_ADMIN,
   823  		TokenCriteria: []*protobuf.TokenCriteria{
   824  			&protobuf.TokenCriteria{
   825  				Type:              protobuf.CommunityTokenType_ERC20,
   826  				ContractAddresses: map[uint64]string{testChainID1: "0x124"},
   827  				Symbol:            "TESTADMIN",
   828  				AmountInWei:       "100000000000000000000",
   829  				Decimals:          uint64(18),
   830  			},
   831  		},
   832  	}
   833  
   834  	waitOnCommunityPermissionCreated = waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
   835  		return len(sub.Community.TokenPermissions()) == 2
   836  	})
   837  
   838  	response, err = s.owner.CreateCommunityTokenPermission(&permissionRequestAdmin)
   839  	s.Require().NoError(err)
   840  	s.Require().Len(response.Communities(), 1)
   841  	s.Require().Len(response.Communities()[0].TokenPermissionsByType(protobuf.CommunityTokenPermission_BECOME_ADMIN), 1)
   842  	s.Require().Len(response.Communities()[0].TokenPermissions(), 2)
   843  
   844  	err = <-waitOnCommunityPermissionCreated
   845  	s.Require().NoError(err)
   846  
   847  	community, err = s.owner.communitiesManager.GetByID(community.ID())
   848  	s.Require().NoError(err)
   849  	s.Require().Len(community.TokenPermissions(), 2)
   850  
   851  	s.advertiseCommunityTo(community, s.bob)
   852  
   853  	// make bob satisfy the admin criteria
   854  	s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, permissionRequestAdmin.TokenCriteria[0])
   855  
   856  	// Bob should still be able to join even though he doesn't satisfy the member requirement
   857  	// because he satisfies the admin one
   858  	s.joinCommunity(community, s.bob)
   859  
   860  	// Verify that we have Bob's revealed account
   861  	revealedAccounts, err := s.owner.GetRevealedAccounts(community.ID(), common.PubkeyToHex(&s.bob.identity.PublicKey))
   862  	s.Require().NoError(err)
   863  	s.Require().Len(revealedAccounts, 1)
   864  	s.Require().Equal(bobAddress, revealedAccounts[0].Address)
   865  }
   866  
   867  func (s *MessengerCommunitiesTokenPermissionsSuite) testViewChannelPermissions(viewersCanAddReactions bool) {
   868  	community, chat := s.createCommunity()
   869  
   870  	// setup channel reactions permissions
   871  	editedChat := &protobuf.CommunityChat{
   872  		Identity: &protobuf.ChatIdentity{
   873  			DisplayName: chat.Name,
   874  			Description: chat.Description,
   875  			Emoji:       chat.Emoji,
   876  			Color:       chat.Color,
   877  		},
   878  		Permissions: &protobuf.CommunityPermissions{
   879  			Access: protobuf.CommunityPermissions_AUTO_ACCEPT,
   880  		},
   881  		ViewersCanPostReactions: viewersCanAddReactions,
   882  	}
   883  
   884  	_, err := s.owner.EditCommunityChat(community.ID(), chat.ID, editedChat)
   885  	s.Require().NoError(err)
   886  
   887  	// bob joins the community
   888  	s.advertiseCommunityTo(community, s.bob)
   889  	s.joinCommunity(community, s.bob)
   890  
   891  	// send message to the channel
   892  	msg := s.sendChatMessage(s.owner, chat.ID, "hello on open community")
   893  
   894  	// bob can read the message
   895  	response, err := WaitOnMessengerResponse(
   896  		s.bob,
   897  		func(r *MessengerResponse) bool {
   898  			_, ok := r.messages[msg.ID]
   899  			return ok
   900  		},
   901  		"no messages",
   902  	)
   903  	s.Require().NoError(err)
   904  	s.Require().Len(response.Messages(), 1)
   905  	s.Require().Equal(msg.Text, response.Messages()[0].Text)
   906  
   907  	waitOnBobToBeKickedFromChannel := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
   908  		channel, ok := sub.Community.Chats()[chat.CommunityChatID()]
   909  		return ok && len(channel.Members) == 1
   910  	})
   911  	waitOnChannelToBeRekeyedOnceBobIsKicked := s.waitOnKeyDistribution(func(sub *CommunityAndKeyActions) bool {
   912  		action, ok := sub.keyActions.ChannelKeysActions[chat.CommunityChatID()]
   913  		return ok && (action.ActionType == communities.EncryptionKeyRekey || action.ActionType == communities.EncryptionKeyAdd)
   914  	})
   915  
   916  	// setup view channel permission
   917  	channelPermissionRequest := requests.CreateCommunityTokenPermission{
   918  		CommunityID: community.ID(),
   919  		Type:        protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
   920  		TokenCriteria: []*protobuf.TokenCriteria{
   921  			&protobuf.TokenCriteria{
   922  				Type:              protobuf.CommunityTokenType_ERC20,
   923  				ContractAddresses: map[uint64]string{testChainID1: "0x123"},
   924  				Symbol:            "TEST",
   925  				AmountInWei:       "100000000000000000000",
   926  				Decimals:          uint64(18),
   927  			},
   928  		},
   929  		ChatIds: []string{chat.ID},
   930  	}
   931  
   932  	response, err = s.owner.CreateCommunityTokenPermission(&channelPermissionRequest)
   933  	s.Require().NoError(err)
   934  	s.Require().Len(response.Communities(), 1)
   935  	s.Require().True(s.owner.communitiesManager.IsChannelEncrypted(community.IDString(), chat.ID))
   936  
   937  	err = <-waitOnBobToBeKickedFromChannel
   938  	s.Require().NoError(err)
   939  
   940  	err = <-waitOnChannelToBeRekeyedOnceBobIsKicked
   941  	s.Require().NoError(err)
   942  
   943  	// bob receives community changes
   944  	// channel members should be empty,
   945  	// this info is available only to channel members
   946  	_, err = WaitOnMessengerResponse(
   947  		s.bob,
   948  		func(r *MessengerResponse) bool {
   949  			c, err := s.bob.GetCommunityByID(community.ID())
   950  			if err != nil {
   951  				return false
   952  			}
   953  			if c == nil {
   954  				return false
   955  			}
   956  			channel := c.Chats()[chat.CommunityChatID()]
   957  			return channel != nil && len(channel.Members) == 0
   958  		},
   959  		"no community that satisfies criteria",
   960  	)
   961  	s.Require().NoError(err)
   962  
   963  	// bob should not be in the bloom filter list
   964  	community, err = s.bob.communitiesManager.GetByID(community.ID())
   965  	s.Require().NoError(err)
   966  	s.Require().False(community.IsMemberLikelyInChat(chat.CommunityChatID()))
   967  
   968  	// make bob satisfy channel criteria
   969  	s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, channelPermissionRequest.TokenCriteria[0])
   970  	defer s.resetMockedBalances() // reset mocked balances, this test in run with different test cases
   971  
   972  	waitOnChannelKeyToBeDistributedToBob := s.waitOnKeyDistribution(func(sub *CommunityAndKeyActions) bool {
   973  		action, ok := sub.keyActions.ChannelKeysActions[chat.CommunityChatID()]
   974  		if !ok || action.ActionType != communities.EncryptionKeySendToMembers {
   975  			return false
   976  		}
   977  		_, ok = action.Members[common.PubkeyToHex(&s.bob.identity.PublicKey)]
   978  		return ok
   979  	})
   980  
   981  	// force owner to reevaluate channel members
   982  	// in production it will happen automatically, by periodic check
   983  	err = s.owner.communitiesManager.ForceMembersReevaluation(community.ID())
   984  	s.Require().NoError(err)
   985  
   986  	err = <-waitOnChannelKeyToBeDistributedToBob
   987  	s.Require().NoError(err)
   988  
   989  	// send message to the channel
   990  	msg = s.sendChatMessage(s.owner, chat.ID, "hello on closed channel")
   991  
   992  	// bob can read the message
   993  	response, err = WaitOnMessengerResponse(
   994  		s.bob,
   995  		func(r *MessengerResponse) bool {
   996  			_, ok := r.messages[msg.ID]
   997  			return ok
   998  		},
   999  		"no messages",
  1000  	)
  1001  	s.Require().NoError(err)
  1002  	s.Require().Len(response.Messages(), 1)
  1003  	s.Require().Equal(msg.Text, response.Messages()[0].Text)
  1004  
  1005  	// bob should be in the bloom filter list
  1006  	community, err = s.bob.communitiesManager.GetByID(community.ID())
  1007  	s.Require().NoError(err)
  1008  	s.Require().True(community.IsMemberLikelyInChat(chat.CommunityChatID()))
  1009  
  1010  	// bob can/can't post reactions
  1011  	response, err = s.bob.SendEmojiReaction(context.Background(), chat.ID, msg.ID, protobuf.EmojiReaction_THUMBS_UP)
  1012  	if !viewersCanAddReactions {
  1013  		s.Require().Error(err)
  1014  	} else {
  1015  		s.Require().NoError(err)
  1016  		s.Require().Len(response.emojiReactions, 1)
  1017  		reactionMessage := response.EmojiReactions()[0]
  1018  
  1019  		response, err = WaitOnMessengerResponse(
  1020  			s.owner,
  1021  			func(r *MessengerResponse) bool {
  1022  				_, ok := r.emojiReactions[reactionMessage.ID()]
  1023  				return ok
  1024  			},
  1025  			"no reactions received",
  1026  		)
  1027  
  1028  		if viewersCanAddReactions {
  1029  			s.Require().NoError(err)
  1030  			s.Require().Len(response.EmojiReactions(), 1)
  1031  			s.Require().Equal(response.EmojiReactions()[0].Type, protobuf.EmojiReaction_THUMBS_UP)
  1032  		} else {
  1033  			s.Require().Error(err)
  1034  			s.Require().Len(response.EmojiReactions(), 0)
  1035  		}
  1036  	}
  1037  }
  1038  
  1039  func (s *MessengerCommunitiesTokenPermissionsSuite) TestViewChannelPermissions() {
  1040  	testCases := []struct {
  1041  		name                    string
  1042  		viewersCanPostReactions bool
  1043  	}{
  1044  		{
  1045  			name:                    "viewers are allowed to post reactions",
  1046  			viewersCanPostReactions: true,
  1047  		},
  1048  		{
  1049  			name:                    "viewers are forbidden to post reactions",
  1050  			viewersCanPostReactions: false,
  1051  		},
  1052  	}
  1053  
  1054  	for _, tc := range testCases {
  1055  		s.T().Run(tc.name, func(*testing.T) {
  1056  			s.testViewChannelPermissions(tc.viewersCanPostReactions)
  1057  		})
  1058  	}
  1059  }
  1060  
  1061  func (s *MessengerCommunitiesTokenPermissionsSuite) TestAnnouncementsChannelPermissions() {
  1062  	community, chat := s.createCommunity()
  1063  
  1064  	// bob joins the community
  1065  	s.advertiseCommunityTo(community, s.bob)
  1066  	s.joinCommunity(community, s.bob)
  1067  
  1068  	// setup view channel permission
  1069  	channelPermissionRequest := requests.CreateCommunityTokenPermission{
  1070  		CommunityID: community.ID(),
  1071  		Type:        protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
  1072  		ChatIds:     []string{chat.ID},
  1073  	}
  1074  
  1075  	response, err := s.owner.CreateCommunityTokenPermission(&channelPermissionRequest)
  1076  	s.Require().NoError(err)
  1077  	s.Require().Len(response.Communities(), 1)
  1078  	s.Require().False(s.owner.communitiesManager.IsChannelEncrypted(community.IDString(), chat.ID))
  1079  
  1080  	// bob should be in the bloom filter list since everyone has access to readonly channels
  1081  	community, err = s.bob.communitiesManager.GetByID(community.ID())
  1082  	s.Require().NoError(err)
  1083  	s.Require().True(community.IsMemberLikelyInChat(chat.CommunityChatID()))
  1084  
  1085  	// force owner to reevaluate channel members
  1086  	// in production it will happen automatically, by periodic check
  1087  	err = s.owner.communitiesManager.ForceMembersReevaluation(community.ID())
  1088  	s.Require().NoError(err)
  1089  
  1090  	// bob receives community changes
  1091  	_, err = WaitOnMessengerResponse(
  1092  		s.bob,
  1093  		func(r *MessengerResponse) bool {
  1094  			c, err := s.bob.GetCommunityByID(community.ID())
  1095  			if err != nil {
  1096  				return false
  1097  			}
  1098  			if c == nil {
  1099  				return false
  1100  			}
  1101  			channel := c.Chats()[chat.CommunityChatID()]
  1102  
  1103  			if channel == nil || len(channel.Members) != 2 {
  1104  				return false
  1105  			}
  1106  			member := channel.Members[s.bob.IdentityPublicKeyString()]
  1107  			return member != nil && member.ChannelRole == protobuf.CommunityMember_CHANNEL_ROLE_VIEWER
  1108  		},
  1109  		"no community that satisfies criteria",
  1110  	)
  1111  	s.Require().NoError(err)
  1112  
  1113  	// bob should be in the bloom filter list
  1114  	community, err = s.bob.communitiesManager.GetByID(community.ID())
  1115  	s.Require().NoError(err)
  1116  	s.Require().True(community.IsMemberLikelyInChat(chat.CommunityChatID()))
  1117  
  1118  	// bob can't post
  1119  	msg := &common.Message{
  1120  		ChatMessage: &protobuf.ChatMessage{
  1121  			ChatId:      chat.ID,
  1122  			ContentType: protobuf.ChatMessage_TEXT_PLAIN,
  1123  			Text:        "I can't post on read-only channel",
  1124  		},
  1125  	}
  1126  
  1127  	_, err = s.bob.SendChatMessage(context.Background(), msg)
  1128  	s.Require().Error(err)
  1129  	s.Require().Contains(err.Error(), "can't post")
  1130  }
  1131  
  1132  func (s *MessengerCommunitiesTokenPermissionsSuite) TestSearchMessageinPermissionedChannel() {
  1133  	community, chat := s.createCommunity()
  1134  
  1135  	newChat := protobuf.CommunityChat{
  1136  		Permissions: &protobuf.CommunityPermissions{
  1137  			EnsOnly: false,
  1138  			Private: false,
  1139  			Access:  1,
  1140  		},
  1141  		Identity: &protobuf.ChatIdentity{
  1142  			DisplayName: "new-channel",
  1143  			Description: "description",
  1144  			Emoji:       "",
  1145  			Color:       "",
  1146  		},
  1147  		CategoryId:              "",
  1148  		ViewersCanPostReactions: true,
  1149  		HideIfPermissionsNotMet: false,
  1150  	}
  1151  
  1152  	response, err := s.owner.CreateCommunityChat(community.ID(), &newChat)
  1153  	s.Require().NoError(err)
  1154  	s.Require().NotNil(response)
  1155  	newChatID := response.Chats()[0].ID
  1156  
  1157  	// bob joins the community
  1158  	s.advertiseCommunityTo(community, s.bob)
  1159  	s.joinCommunity(community, s.bob)
  1160  
  1161  	// send message to the original channel
  1162  	msg := s.sendChatMessage(s.owner, chat.ID, "hello on open community")
  1163  
  1164  	// bob can read the message
  1165  	response, err = WaitOnMessengerResponse(
  1166  		s.bob,
  1167  		func(r *MessengerResponse) bool {
  1168  			_, ok := r.messages[msg.ID]
  1169  			return ok
  1170  		},
  1171  		"no messages",
  1172  	)
  1173  	s.Require().NoError(err)
  1174  	s.Require().Len(response.Messages(), 1)
  1175  	s.Require().Equal(msg.Text, response.Messages()[0].Text)
  1176  
  1177  	// send message to the new channel
  1178  	msgText := "hello on new chat"
  1179  	msg = s.sendChatMessage(s.owner, newChatID, msgText)
  1180  
  1181  	// bob can read the message
  1182  	response, err = WaitOnMessengerResponse(
  1183  		s.bob,
  1184  		func(r *MessengerResponse) bool {
  1185  			_, ok := r.messages[msg.ID]
  1186  			return ok
  1187  		},
  1188  		"no messages",
  1189  	)
  1190  	s.Require().NoError(err)
  1191  	s.Require().Len(response.Messages(), 1)
  1192  	s.Require().Equal(msg.Text, response.Messages()[0].Text)
  1193  
  1194  	waitOnBobToBeKickedFromChannel := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
  1195  		channel, ok := sub.Community.Chats()[chat.CommunityChatID()]
  1196  		return ok && len(channel.Members) == 1
  1197  	})
  1198  	waitOnChannelToBeRekeyedOnceBobIsKicked := s.waitOnKeyDistribution(func(sub *CommunityAndKeyActions) bool {
  1199  		action, ok := sub.keyActions.ChannelKeysActions[chat.CommunityChatID()]
  1200  		return ok && (action.ActionType == communities.EncryptionKeyRekey || action.ActionType == communities.EncryptionKeyAdd)
  1201  	})
  1202  
  1203  	// setup view channel permission
  1204  	channelPermissionRequest := requests.CreateCommunityTokenPermission{
  1205  		CommunityID: community.ID(),
  1206  		Type:        protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
  1207  		TokenCriteria: []*protobuf.TokenCriteria{
  1208  			&protobuf.TokenCriteria{
  1209  				Type:              protobuf.CommunityTokenType_ERC20,
  1210  				ContractAddresses: map[uint64]string{testChainID1: "0x123"},
  1211  				Symbol:            "TEST",
  1212  				AmountInWei:       "100000000000000000000",
  1213  				Decimals:          uint64(18),
  1214  			},
  1215  		},
  1216  		ChatIds: []string{chat.ID},
  1217  	}
  1218  
  1219  	response, err = s.owner.CreateCommunityTokenPermission(&channelPermissionRequest)
  1220  	s.Require().NoError(err)
  1221  	s.Require().Len(response.Communities(), 1)
  1222  	s.Require().True(s.owner.communitiesManager.IsChannelEncrypted(community.IDString(), chat.ID))
  1223  
  1224  	err = <-waitOnBobToBeKickedFromChannel
  1225  	s.Require().NoError(err)
  1226  
  1227  	err = <-waitOnChannelToBeRekeyedOnceBobIsKicked
  1228  	s.Require().NoError(err)
  1229  
  1230  	// bob receives community changes
  1231  	// channel members should be empty,
  1232  	// this info is available only to channel members
  1233  	_, err = WaitOnMessengerResponse(
  1234  		s.bob,
  1235  		func(r *MessengerResponse) bool {
  1236  			c, err := s.bob.GetCommunityByID(community.ID())
  1237  			if err != nil {
  1238  				return false
  1239  			}
  1240  			if c == nil {
  1241  				return false
  1242  			}
  1243  			channel := c.Chats()[chat.CommunityChatID()]
  1244  			return channel != nil && len(channel.Members) == 0
  1245  		},
  1246  		"no community that satisfies criteria",
  1247  	)
  1248  	s.Require().NoError(err)
  1249  
  1250  	// Bob searches for "hello" but only finds it in the new channel
  1251  	communities := make([]string, 1)
  1252  	communities[0] = community.IDString()
  1253  	messages, err := s.bob.AllMessagesFromChatsAndCommunitiesWhichMatchTerm(communities, make([]string, 0), "hello", false)
  1254  	s.Require().NoError(err)
  1255  	s.Require().Len(messages, 1)
  1256  	s.Require().Equal(msgText, messages[0].Text)
  1257  }
  1258  
  1259  func (s *MessengerCommunitiesTokenPermissionsSuite) TestMemberRoleGetUpdatedWhenChangingPermissions() {
  1260  	community, chat := s.createCommunity()
  1261  
  1262  	// bob joins the community
  1263  	s.advertiseCommunityTo(community, s.bob)
  1264  	s.joinCommunity(community, s.bob)
  1265  
  1266  	community, err := s.owner.communitiesManager.GetByID(community.ID())
  1267  	s.Require().NoError(err)
  1268  
  1269  	// send message to the channel
  1270  	msg := s.sendChatMessage(s.owner, chat.ID, "hello on open community")
  1271  
  1272  	// bob can read the message
  1273  	response, err := WaitOnMessengerResponse(
  1274  		s.bob,
  1275  		func(r *MessengerResponse) bool {
  1276  			_, ok := r.messages[msg.ID]
  1277  			return ok
  1278  		},
  1279  		"no messages",
  1280  	)
  1281  	s.Require().NoError(err)
  1282  	s.Require().Len(response.Messages(), 1)
  1283  	s.Require().Equal(msg.Text, response.Messages()[0].Text)
  1284  
  1285  	waitOnBobToBeKickedFromChannel := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
  1286  		channel, ok := sub.Community.Chats()[chat.CommunityChatID()]
  1287  		return ok && len(channel.Members) == 1
  1288  	})
  1289  	waitOnChannelToBeRekeyedOnceBobIsKicked := s.waitOnKeyDistribution(func(sub *CommunityAndKeyActions) bool {
  1290  		action, ok := sub.keyActions.ChannelKeysActions[chat.CommunityChatID()]
  1291  		return ok && (action.ActionType == communities.EncryptionKeyRekey || action.ActionType == communities.EncryptionKeyAdd)
  1292  	})
  1293  
  1294  	// setup view channel permission
  1295  	channelPermissionRequest := requests.CreateCommunityTokenPermission{
  1296  		CommunityID: community.ID(),
  1297  		Type:        protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
  1298  		TokenCriteria: []*protobuf.TokenCriteria{
  1299  			&protobuf.TokenCriteria{
  1300  				Type:              protobuf.CommunityTokenType_ERC20,
  1301  				ContractAddresses: map[uint64]string{testChainID1: "0x123"},
  1302  				Symbol:            "TEST",
  1303  				AmountInWei:       "100000000000000000000",
  1304  				Decimals:          uint64(18),
  1305  			},
  1306  		},
  1307  		ChatIds: []string{chat.ID},
  1308  	}
  1309  
  1310  	response, err = s.owner.CreateCommunityTokenPermission(&channelPermissionRequest)
  1311  	s.Require().NoError(err)
  1312  	s.Require().Len(response.Communities(), 1)
  1313  	s.Require().Len(response.CommunityChanges[0].TokenPermissionsAdded, 1)
  1314  	s.Require().True(s.owner.communitiesManager.IsChannelEncrypted(community.IDString(), chat.ID))
  1315  
  1316  	err = <-waitOnBobToBeKickedFromChannel
  1317  	s.Require().NoError(err)
  1318  
  1319  	err = <-waitOnChannelToBeRekeyedOnceBobIsKicked
  1320  	s.Require().NoError(err)
  1321  
  1322  	// bob receives community changes
  1323  	// channel members should be empty,
  1324  	// this info is available only to channel members
  1325  	_, err = WaitOnMessengerResponse(
  1326  		s.bob,
  1327  		func(r *MessengerResponse) bool {
  1328  			c, err := s.bob.GetCommunityByID(community.ID())
  1329  			if err != nil {
  1330  				return false
  1331  			}
  1332  			if c == nil {
  1333  				return false
  1334  			}
  1335  			channel := c.Chats()[chat.CommunityChatID()]
  1336  			return channel != nil && len(channel.Members) == 0
  1337  		},
  1338  		"no community that satisfies criteria",
  1339  	)
  1340  	s.Require().NoError(err)
  1341  
  1342  	// make bob satisfy channel criteria
  1343  	s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, channelPermissionRequest.TokenCriteria[0])
  1344  	defer s.resetMockedBalances() // reset mocked balances, this test in run with different test cases
  1345  
  1346  	waitOnChannelKeyToBeDistributedToBob := s.waitOnKeyDistribution(func(sub *CommunityAndKeyActions) bool {
  1347  		action, ok := sub.keyActions.ChannelKeysActions[chat.CommunityChatID()]
  1348  		if !ok || action.ActionType != communities.EncryptionKeySendToMembers {
  1349  			return false
  1350  		}
  1351  		_, ok = action.Members[common.PubkeyToHex(&s.bob.identity.PublicKey)]
  1352  		return ok
  1353  	})
  1354  
  1355  	// force owner to reevaluate channel members
  1356  	// in production it will happen automatically, by periodic check
  1357  	err = s.owner.communitiesManager.ForceMembersReevaluation(community.ID())
  1358  	s.Require().NoError(err)
  1359  
  1360  	err = <-waitOnChannelKeyToBeDistributedToBob
  1361  	s.Require().NoError(err)
  1362  
  1363  	community, err = s.owner.communitiesManager.GetByID(community.ID())
  1364  	s.Require().NoError(err)
  1365  	chatID := strings.TrimPrefix(chat.ID, community.IDString())
  1366  	members := community.Chats()[chatID].Members
  1367  	s.Require().Len(members, 2)
  1368  	// confirm that member is a viewer and not a poster
  1369  	s.Require().Equal(protobuf.CommunityMember_CHANNEL_ROLE_VIEWER, members[s.bob.IdentityPublicKeyString()].ChannelRole)
  1370  
  1371  	// send message to the channel
  1372  	msg = s.sendChatMessage(s.owner, chat.ID, "hello on closed channel")
  1373  
  1374  	// bob can read the message
  1375  	response, err = WaitOnMessengerResponse(
  1376  		s.bob,
  1377  		func(r *MessengerResponse) bool {
  1378  			_, ok := r.messages[msg.ID]
  1379  			return ok
  1380  		},
  1381  		"no messages",
  1382  	)
  1383  	s.Require().NoError(err)
  1384  	s.Require().Len(response.Messages(), 1)
  1385  	s.Require().Equal(msg.Text, response.Messages()[0].Text)
  1386  
  1387  	tokenPermissions := community.TokenPermissions()
  1388  
  1389  	var tokenPermissionID string
  1390  	for id := range tokenPermissions {
  1391  		tokenPermissionID = id
  1392  	}
  1393  
  1394  	// Edit permission so that Bob can now be a poster to show that member role can be edited
  1395  	channelPermissionRequest.Type = protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL
  1396  	editChannelPermissionRequest := requests.EditCommunityTokenPermission{
  1397  		PermissionID:                   tokenPermissionID,
  1398  		CreateCommunityTokenPermission: channelPermissionRequest,
  1399  	}
  1400  	response, err = s.owner.EditCommunityTokenPermission(&editChannelPermissionRequest)
  1401  	s.Require().NoError(err)
  1402  	s.Require().Len(response.Communities(), 1)
  1403  	s.Require().True(s.owner.communitiesManager.IsChannelEncrypted(community.IDString(), chat.ID))
  1404  	s.Require().Len(response.CommunityChanges[0].TokenPermissionsModified, 1)
  1405  
  1406  	waitOnBobAddedToChannelAsPoster := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
  1407  		channel, ok := sub.Community.Chats()[chat.CommunityChatID()]
  1408  		if !ok {
  1409  			return false
  1410  		}
  1411  		member, ok := channel.Members[s.bob.IdentityPublicKeyString()]
  1412  		if !ok {
  1413  			return false
  1414  		}
  1415  		return member.ChannelRole == protobuf.CommunityMember_CHANNEL_ROLE_POSTER
  1416  	})
  1417  
  1418  	// force owner to reevaluate channel members
  1419  	// in production it will happen automatically, by periodic check
  1420  	err = s.owner.communitiesManager.ForceMembersReevaluation(community.ID())
  1421  	s.Require().NoError(err)
  1422  
  1423  	err = <-waitOnBobAddedToChannelAsPoster
  1424  	s.Require().NoError(err)
  1425  
  1426  	community, err = s.owner.communitiesManager.GetByID(community.ID())
  1427  	s.Require().NoError(err)
  1428  
  1429  	members = community.Chats()[chatID].Members
  1430  	s.Require().Len(members, 2)
  1431  	// confirm that member is now a poster
  1432  	s.Require().Equal(protobuf.CommunityMember_CHANNEL_ROLE_POSTER, members[s.bob.IdentityPublicKeyString()].ChannelRole)
  1433  
  1434  	err = <-waitOnChannelKeyToBeDistributedToBob
  1435  	s.Require().NoError(err)
  1436  
  1437  	// wait until bob permissions are upgraded
  1438  	_, err = WaitOnMessengerResponse(
  1439  		s.bob,
  1440  		func(r *MessengerResponse) bool {
  1441  			community, err = s.bob.communitiesManager.GetByID(community.ID())
  1442  			s.Require().NoError(err)
  1443  			chats := community.Chats()
  1444  			if len(chats) == 0 {
  1445  				return false
  1446  			}
  1447  			if chats[chat.ID] == nil {
  1448  				return false
  1449  			}
  1450  			members = chats[chat.ID].Members
  1451  			return len(members) == 2 && members[s.bob.myHexIdentity()] != nil && members[s.bob.myHexIdentity()].ChannelRole == protobuf.CommunityMember_CHANNEL_ROLE_POSTER
  1452  		},
  1453  		"bob never got post permissions",
  1454  	)
  1455  
  1456  	msg = s.sendChatMessage(s.bob, chat.ID, "hello on closed channel from Bob")
  1457  
  1458  	// owner can read the message
  1459  	response, err = WaitOnMessengerResponse(
  1460  		s.owner,
  1461  		func(r *MessengerResponse) bool {
  1462  			_, ok := r.messages[msg.ID]
  1463  			return ok
  1464  		},
  1465  		"no messages",
  1466  	)
  1467  	s.Require().NoError(err)
  1468  	s.Require().Len(response.Messages(), 1)
  1469  	s.Require().Equal(msg.Text, response.Messages()[0].Text)
  1470  }
  1471  
  1472  func (s *MessengerCommunitiesTokenPermissionsSuite) testReevaluateMemberPrivilegedRoleInOpenCommunity(permissionType protobuf.CommunityTokenPermission_Type, tokenType protobuf.CommunityTokenType) {
  1473  	community, _ := s.createCommunity()
  1474  
  1475  	amountInWei := "100000000000000000000"
  1476  	decimals := uint64(18)
  1477  	if tokenType == protobuf.CommunityTokenType_ERC721 {
  1478  		amountInWei = "1"
  1479  		decimals = 0
  1480  	}
  1481  
  1482  	createTokenPermission := &requests.CreateCommunityTokenPermission{
  1483  		CommunityID: community.ID(),
  1484  		Type:        permissionType,
  1485  		TokenCriteria: []*protobuf.TokenCriteria{
  1486  			{
  1487  				Type:              tokenType,
  1488  				ContractAddresses: map[uint64]string{testChainID1: "0x123"},
  1489  				Symbol:            "TEST",
  1490  				AmountInWei:       amountInWei,
  1491  				Decimals:          decimals,
  1492  			},
  1493  		},
  1494  	}
  1495  
  1496  	waitOnCommunityPermissionCreated := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
  1497  		return sub.Community.HasTokenPermissions()
  1498  	})
  1499  
  1500  	response, err := s.owner.CreateCommunityTokenPermission(createTokenPermission)
  1501  	s.Require().NoError(err)
  1502  	s.Require().NotNil(response)
  1503  	s.Require().Len(response.Communities(), 1)
  1504  	s.Require().True(response.Communities()[0].HasTokenPermissions())
  1505  
  1506  	err = <-waitOnCommunityPermissionCreated
  1507  	s.Require().NoError(err)
  1508  
  1509  	community, err = s.owner.communitiesManager.GetByID(community.ID())
  1510  	s.Require().NoError(err)
  1511  	s.Require().True(community.HasTokenPermissions())
  1512  
  1513  	s.advertiseCommunityTo(community, s.alice)
  1514  
  1515  	var tokenPermission *communities.CommunityTokenPermission
  1516  	for _, tokenPermission = range community.TokenPermissions() {
  1517  		break
  1518  	}
  1519  
  1520  	s.makeAddressSatisfyTheCriteria(testChainID1, aliceAddress1, tokenPermission.TokenCriteria[0])
  1521  
  1522  	// join community as a privileged user
  1523  	s.joinCommunity(community, s.alice)
  1524  
  1525  	community, err = s.owner.communitiesManager.GetByID(community.ID())
  1526  	s.Require().NoError(err)
  1527  	s.Require().True(checkRoleBasedOnThePermissionType(permissionType, &s.alice.identity.PublicKey, community))
  1528  
  1529  	waitOnPermissionsReevaluated := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
  1530  		if sub.Community == nil {
  1531  			return false
  1532  		}
  1533  		return checkRoleBasedOnThePermissionType(permissionType, &s.alice.identity.PublicKey, sub.Community)
  1534  	})
  1535  
  1536  	// the control node re-evaluates the roles of the participants, checking that the privileged user has not lost his role
  1537  	err = s.owner.communitiesManager.ForceMembersReevaluation(community.ID())
  1538  	s.Require().NoError(err)
  1539  
  1540  	err = <-waitOnPermissionsReevaluated
  1541  	s.Require().NoError(err)
  1542  
  1543  	community, err = s.owner.communitiesManager.GetByID(community.ID())
  1544  	s.Require().NoError(err)
  1545  	s.Require().True(checkRoleBasedOnThePermissionType(permissionType, &s.alice.identity.PublicKey, community))
  1546  
  1547  	// remove privileged token permission and reevaluate member permissions
  1548  	deleteTokenPermission := &requests.DeleteCommunityTokenPermission{
  1549  		CommunityID:  community.ID(),
  1550  		PermissionID: tokenPermission.Id,
  1551  	}
  1552  
  1553  	waitOnPermissionsReevaluated = waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
  1554  		if sub.Community == nil {
  1555  			return false
  1556  		}
  1557  		return !checkRoleBasedOnThePermissionType(permissionType, &s.alice.identity.PublicKey, sub.Community)
  1558  	})
  1559  
  1560  	response, err = s.owner.DeleteCommunityTokenPermission(deleteTokenPermission)
  1561  	s.Require().NoError(err)
  1562  	s.Require().NotNil(response)
  1563  	s.Require().Len(response.Communities(), 1)
  1564  	s.Require().False(response.Communities()[0].HasTokenPermissions())
  1565  
  1566  	community, err = s.owner.communitiesManager.GetByID(community.ID())
  1567  	s.Require().NoError(err)
  1568  	s.Require().False(community.HasTokenPermissions())
  1569  
  1570  	err = s.owner.communitiesManager.ForceMembersReevaluation(community.ID())
  1571  	s.Require().NoError(err)
  1572  
  1573  	err = <-waitOnPermissionsReevaluated
  1574  	s.Require().NoError(err)
  1575  
  1576  	community, err = s.owner.communitiesManager.GetByID(community.ID())
  1577  	s.Require().NoError(err)
  1578  	s.Require().True(community.HasMember(&s.alice.identity.PublicKey))
  1579  	s.Require().False(checkRoleBasedOnThePermissionType(permissionType, &s.alice.identity.PublicKey, community))
  1580  }
  1581  
  1582  func (s *MessengerCommunitiesTokenPermissionsSuite) TestReevaluateMemberAdminRoleInOpenCommunity_ERC20() {
  1583  	s.testReevaluateMemberPrivilegedRoleInOpenCommunity(protobuf.CommunityTokenPermission_BECOME_ADMIN, protobuf.CommunityTokenType_ERC20)
  1584  }
  1585  
  1586  func (s *MessengerCommunitiesTokenPermissionsSuite) TestReevaluateMemberAdminRoleInOpenCommunity_ERC721() {
  1587  	s.testReevaluateMemberPrivilegedRoleInOpenCommunity(protobuf.CommunityTokenPermission_BECOME_ADMIN, protobuf.CommunityTokenType_ERC721)
  1588  }
  1589  
  1590  func (s *MessengerCommunitiesTokenPermissionsSuite) TestReevaluateMemberTokenMasterRoleInOpenCommunity_ERC20() {
  1591  	s.testReevaluateMemberPrivilegedRoleInOpenCommunity(protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, protobuf.CommunityTokenType_ERC20)
  1592  }
  1593  
  1594  func (s *MessengerCommunitiesTokenPermissionsSuite) TestReevaluateMemberTokenMasterRoleInOpenCommunity_ERC721() {
  1595  	s.testReevaluateMemberPrivilegedRoleInOpenCommunity(protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, protobuf.CommunityTokenType_ERC721)
  1596  }
  1597  
  1598  func (s *MessengerCommunitiesTokenPermissionsSuite) testReevaluateMemberPrivilegedRoleInClosedCommunity(permissionType protobuf.CommunityTokenPermission_Type, tokenType protobuf.CommunityTokenType) {
  1599  	community, _ := s.createCommunity()
  1600  
  1601  	amountInWei := "100000000000000000000"
  1602  	decimals := uint64(18)
  1603  	if tokenType == protobuf.CommunityTokenType_ERC721 {
  1604  		amountInWei = "1"
  1605  		decimals = 0
  1606  	}
  1607  
  1608  	createTokenPermission := &requests.CreateCommunityTokenPermission{
  1609  		CommunityID: community.ID(),
  1610  		Type:        permissionType,
  1611  		TokenCriteria: []*protobuf.TokenCriteria{
  1612  			{
  1613  				Type:              tokenType,
  1614  				ContractAddresses: map[uint64]string{testChainID1: "0x123"},
  1615  				Symbol:            "TEST",
  1616  				AmountInWei:       amountInWei,
  1617  				Decimals:          decimals,
  1618  			},
  1619  		},
  1620  	}
  1621  
  1622  	response, err := s.owner.CreateCommunityTokenPermission(createTokenPermission)
  1623  	s.Require().NoError(err)
  1624  	s.Require().NotNil(response)
  1625  	s.Require().Len(response.Communities(), 1)
  1626  	s.Require().True(response.Communities()[0].HasTokenPermissions())
  1627  
  1628  	createTokenMemberPermission := &requests.CreateCommunityTokenPermission{
  1629  		CommunityID: community.ID(),
  1630  		Type:        protobuf.CommunityTokenPermission_BECOME_MEMBER,
  1631  		TokenCriteria: []*protobuf.TokenCriteria{
  1632  			{
  1633  				Type:              tokenType,
  1634  				ContractAddresses: map[uint64]string{testChainID1: "0x124"},
  1635  				Symbol:            "TEST2",
  1636  				AmountInWei:       amountInWei,
  1637  				Decimals:          decimals,
  1638  			},
  1639  		},
  1640  	}
  1641  
  1642  	waitOnCommunityPermissionCreated := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
  1643  		return len(sub.Community.TokenPermissions()) == 2
  1644  	})
  1645  
  1646  	response, err = s.owner.CreateCommunityTokenPermission(createTokenMemberPermission)
  1647  	s.Require().NoError(err)
  1648  	s.Require().NotNil(response)
  1649  	s.Require().Len(response.Communities(), 1)
  1650  
  1651  	community = response.Communities()[0]
  1652  	s.Require().True(community.HasTokenPermissions())
  1653  	s.Require().Len(community.TokenPermissions(), 2)
  1654  
  1655  	err = <-waitOnCommunityPermissionCreated
  1656  	s.Require().NoError(err)
  1657  
  1658  	s.advertiseCommunityTo(community, s.alice)
  1659  
  1660  	var tokenPermission *communities.CommunityTokenPermission
  1661  	var tokenMemberPermission *communities.CommunityTokenPermission
  1662  	for _, permission := range community.TokenPermissions() {
  1663  		if permission.Type == protobuf.CommunityTokenPermission_BECOME_MEMBER {
  1664  			tokenMemberPermission = permission
  1665  		} else {
  1666  			tokenPermission = permission
  1667  		}
  1668  	}
  1669  
  1670  	s.makeAddressSatisfyTheCriteria(testChainID1, aliceAddress1, tokenPermission.TokenCriteria[0])
  1671  	s.makeAddressSatisfyTheCriteria(testChainID1, aliceAddress1, tokenMemberPermission.TokenCriteria[0])
  1672  
  1673  	waitOnAliceAddedToCommunity := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
  1674  		if sub.Community == nil {
  1675  			return false
  1676  		}
  1677  		return checkRoleBasedOnThePermissionType(permissionType, &s.alice.identity.PublicKey, sub.Community)
  1678  	})
  1679  
  1680  	// join community as a privileged user
  1681  	s.joinCommunity(community, s.alice)
  1682  
  1683  	community, err = s.owner.communitiesManager.GetByID(community.ID())
  1684  	s.Require().NoError(err)
  1685  	s.Require().True(checkRoleBasedOnThePermissionType(permissionType, &s.alice.identity.PublicKey, community))
  1686  
  1687  	// the control node reevaluates the roles of the participants, checking that the privileged user has not lost his role
  1688  	err = s.owner.communitiesManager.ForceMembersReevaluation(community.ID())
  1689  	s.Require().NoError(err)
  1690  
  1691  	err = <-waitOnAliceAddedToCommunity
  1692  	s.Require().NoError(err)
  1693  
  1694  	community, err = s.owner.communitiesManager.GetByID(community.ID())
  1695  	s.Require().NoError(err)
  1696  	s.Require().True(checkRoleBasedOnThePermissionType(permissionType, &s.alice.identity.PublicKey, community))
  1697  
  1698  	deleteTokenPermission := &requests.DeleteCommunityTokenPermission{
  1699  		CommunityID:  community.ID(),
  1700  		PermissionID: tokenPermission.Id,
  1701  	}
  1702  
  1703  	// remove privileged token permission and reevaluate member permissions
  1704  	response, err = s.owner.DeleteCommunityTokenPermission(deleteTokenPermission)
  1705  	s.Require().NoError(err)
  1706  	s.Require().NotNil(response)
  1707  	s.Require().Len(response.Communities(), 1)
  1708  	s.Require().Len(response.Communities()[0].TokenPermissions(), 1)
  1709  
  1710  	community, err = s.owner.communitiesManager.GetByID(community.ID())
  1711  	s.Require().NoError(err)
  1712  	s.Require().Len(response.Communities()[0].TokenPermissions(), 1)
  1713  
  1714  	waitOnAliceLostPermission := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
  1715  		if sub.Community == nil {
  1716  			return false
  1717  		}
  1718  		return !checkRoleBasedOnThePermissionType(permissionType, &s.alice.identity.PublicKey, sub.Community)
  1719  	})
  1720  
  1721  	err = s.owner.communitiesManager.ForceMembersReevaluation(community.ID())
  1722  	s.Require().NoError(err)
  1723  
  1724  	err = <-waitOnAliceLostPermission
  1725  	s.Require().NoError(err)
  1726  
  1727  	community, err = s.owner.communitiesManager.GetByID(community.ID())
  1728  	s.Require().NoError(err)
  1729  	s.Require().True(community.HasMember(&s.alice.identity.PublicKey))
  1730  	s.Require().False(checkRoleBasedOnThePermissionType(permissionType, &s.alice.identity.PublicKey, community))
  1731  
  1732  	// delete member permissions and reevaluate user permissions
  1733  	deleteMemberTokenPermission := &requests.DeleteCommunityTokenPermission{
  1734  		CommunityID:  community.ID(),
  1735  		PermissionID: tokenMemberPermission.Id,
  1736  	}
  1737  
  1738  	waitOnReevaluation := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
  1739  		if sub.Community == nil {
  1740  			return false
  1741  		}
  1742  		return !checkRoleBasedOnThePermissionType(permissionType, &s.alice.identity.PublicKey, sub.Community)
  1743  	})
  1744  
  1745  	response, err = s.owner.DeleteCommunityTokenPermission(deleteMemberTokenPermission)
  1746  	s.Require().NoError(err)
  1747  	s.Require().NotNil(response)
  1748  	s.Require().Len(response.Communities(), 1)
  1749  	s.Require().Len(response.Communities()[0].TokenPermissions(), 0)
  1750  
  1751  	community, err = s.owner.communitiesManager.GetByID(community.ID())
  1752  	s.Require().NoError(err)
  1753  	s.Require().Len(response.Communities()[0].TokenPermissions(), 0)
  1754  
  1755  	err = s.owner.communitiesManager.ForceMembersReevaluation(community.ID())
  1756  	s.Require().NoError(err)
  1757  
  1758  	err = <-waitOnReevaluation
  1759  	s.Require().NoError(err)
  1760  
  1761  	community, err = s.owner.communitiesManager.GetByID(community.ID())
  1762  	s.Require().NoError(err)
  1763  	s.Require().True(community.HasMember(&s.alice.identity.PublicKey))
  1764  
  1765  	s.Require().False(checkRoleBasedOnThePermissionType(permissionType, &s.alice.identity.PublicKey, community))
  1766  }
  1767  
  1768  func (s *MessengerCommunitiesTokenPermissionsSuite) TestReevaluateMemberAdminRoleInClosedCommunity_ERC20() {
  1769  	s.testReevaluateMemberPrivilegedRoleInClosedCommunity(protobuf.CommunityTokenPermission_BECOME_ADMIN, protobuf.CommunityTokenType_ERC20)
  1770  }
  1771  
  1772  func (s *MessengerCommunitiesTokenPermissionsSuite) TestReevaluateMemberAdminRoleInClosedCommunity_ERC721() {
  1773  	s.testReevaluateMemberPrivilegedRoleInClosedCommunity(protobuf.CommunityTokenPermission_BECOME_ADMIN, protobuf.CommunityTokenType_ERC721)
  1774  }
  1775  
  1776  func (s *MessengerCommunitiesTokenPermissionsSuite) TestReevaluateMemberTokenMasterRoleInClosedCommunity_ERC20() {
  1777  	s.testReevaluateMemberPrivilegedRoleInClosedCommunity(protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, protobuf.CommunityTokenType_ERC20)
  1778  }
  1779  
  1780  func (s *MessengerCommunitiesTokenPermissionsSuite) TestReevaluateMemberTokenMasterRoleInClosedCommunity_ERC721() {
  1781  	s.testReevaluateMemberPrivilegedRoleInClosedCommunity(protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, protobuf.CommunityTokenType_ERC721)
  1782  }
  1783  
  1784  func checkRoleBasedOnThePermissionType(permissionType protobuf.CommunityTokenPermission_Type, member *ecdsa.PublicKey, community *communities.Community) bool {
  1785  	switch permissionType {
  1786  	case protobuf.CommunityTokenPermission_BECOME_ADMIN:
  1787  		return community.IsMemberAdmin(member)
  1788  	case protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER:
  1789  		return community.IsMemberTokenMaster(member)
  1790  	default:
  1791  		panic("Unknown permission, please, update the test")
  1792  	}
  1793  }
  1794  
  1795  func (s *MessengerCommunitiesTokenPermissionsSuite) TestResendEncryptionKeyOnBackupRestore() {
  1796  	community, chat := s.createCommunity()
  1797  
  1798  	// bob joins the community
  1799  	s.advertiseCommunityTo(community, s.bob)
  1800  	s.joinCommunity(community, s.bob)
  1801  
  1802  	// setup view channel permission
  1803  	channelPermissionRequest := requests.CreateCommunityTokenPermission{
  1804  		CommunityID: community.ID(),
  1805  		Type:        protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
  1806  		TokenCriteria: []*protobuf.TokenCriteria{
  1807  			&protobuf.TokenCriteria{
  1808  				Type:              protobuf.CommunityTokenType_ERC20,
  1809  				ContractAddresses: map[uint64]string{testChainID1: "0x123"},
  1810  				Symbol:            "TEST",
  1811  				AmountInWei:       "100000000000000000000",
  1812  				Decimals:          uint64(18),
  1813  			},
  1814  		},
  1815  		ChatIds: []string{chat.ID},
  1816  	}
  1817  
  1818  	// make bob satisfy channel criteria
  1819  	s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, channelPermissionRequest.TokenCriteria[0])
  1820  	defer s.resetMockedBalances() // reset mocked balances, this test in run with different test cases
  1821  
  1822  	response, err := s.owner.CreateCommunityTokenPermission(&channelPermissionRequest)
  1823  	s.Require().NoError(err)
  1824  	s.Require().Len(response.Communities(), 1)
  1825  	s.Require().True(s.owner.communitiesManager.IsChannelEncrypted(community.IDString(), chat.ID))
  1826  
  1827  	// reevalate community member permissions in order get encryption keys
  1828  	community, err = s.owner.communitiesManager.GetByID(community.ID())
  1829  	s.Require().NoError(err)
  1830  
  1831  	waitOnChannelKeyToBeDistributedToBob := s.waitOnKeyDistribution(func(sub *CommunityAndKeyActions) bool {
  1832  		action, ok := sub.keyActions.ChannelKeysActions[chat.CommunityChatID()]
  1833  		if !ok || action.ActionType != communities.EncryptionKeyAdd {
  1834  			return false
  1835  		}
  1836  
  1837  		_, ok = action.Members[common.PubkeyToHex(&s.bob.identity.PublicKey)]
  1838  		return ok
  1839  	})
  1840  
  1841  	err = <-waitOnChannelKeyToBeDistributedToBob
  1842  	s.Require().NoError(err)
  1843  
  1844  	// bob receives community changes
  1845  	// channel members should not be empty,
  1846  	// this info is available only to channel members with encryption key
  1847  	_, err = WaitOnMessengerResponse(
  1848  		s.bob,
  1849  		func(r *MessengerResponse) bool {
  1850  			c, err := s.bob.GetCommunityByID(community.ID())
  1851  			if err != nil {
  1852  				return false
  1853  			}
  1854  			if c == nil {
  1855  				return false
  1856  			}
  1857  			channel := c.Chats()[chat.CommunityChatID()]
  1858  			if channel != nil && len(channel.Members) < 2 {
  1859  				return false
  1860  			}
  1861  
  1862  			return channel.Permissions != nil
  1863  		},
  1864  		"no community that satisfies criteria",
  1865  	)
  1866  	s.Require().NoError(err)
  1867  
  1868  	// owner send message to the channel
  1869  	msg := s.sendChatMessage(s.owner, chat.ID, "hello to encrypted channel")
  1870  
  1871  	// bob can read the message
  1872  	response, err = WaitOnMessengerResponse(
  1873  		s.bob,
  1874  		func(r *MessengerResponse) bool {
  1875  			_, ok := r.messages[msg.ID]
  1876  			return ok
  1877  		},
  1878  		"no messages",
  1879  	)
  1880  	s.Require().NoError(err)
  1881  	s.Require().Len(response.Messages(), 1)
  1882  	s.Require().Equal(msg.Text, response.Messages()[0].Text)
  1883  
  1884  	// Simulate backup creation and handling backup message
  1885  	// As a result, bob sends request to resend encryption keys to the owner
  1886  	clock, _ := s.bob.getLastClockWithRelatedChat()
  1887  
  1888  	community, err = s.owner.communitiesManager.GetByID(community.ID())
  1889  	s.Require().NoError(err)
  1890  
  1891  	backupMessage, err := s.bob.backupCommunity(community, clock)
  1892  	s.Require().NoError(err)
  1893  
  1894  	err = s.bob.HandleBackup(s.bob.buildMessageState(), backupMessage, nil)
  1895  	s.Require().NoError(err)
  1896  
  1897  	// regenerate key for the channel in order to check that owner will send keys
  1898  	// on bob request from `HandleBackup`
  1899  	_, err = s.owner.encryptor.GenerateHashRatchetKey([]byte(community.IDString() + chat.CommunityChatID()))
  1900  	s.Require().NoError(err)
  1901  
  1902  	testCommunitiesKeyDistributor, ok := s.owner.communitiesKeyDistributor.(*TestCommunitiesKeyDistributor)
  1903  	s.Require().True(ok)
  1904  	s.Require().NotNil(testCommunitiesKeyDistributor)
  1905  	subscription := testCommunitiesKeyDistributor.subscribeToKeyDistribution()
  1906  
  1907  	// `HandleCommunityEncryptionKeysRequest` does not return any response
  1908  	// To make sure that `HandleCommunityEncryptionKeysRequest` was called and new keys sent
  1909  	// we will subscribe to key distribution
  1910  	checkKeyWasSent := func() bool {
  1911  		var sub *CommunityAndKeyActions
  1912  		select {
  1913  		case sub = <-subscription:
  1914  		default:
  1915  			return false // No data available, return false
  1916  		}
  1917  		action, ok := sub.keyActions.ChannelKeysActions[chat.CommunityChatID()]
  1918  		if !ok || action.ActionType != communities.EncryptionKeySendToMembers {
  1919  			return false
  1920  		}
  1921  
  1922  		_, ok = action.Members[common.PubkeyToHex(&s.bob.identity.PublicKey)]
  1923  		return ok
  1924  	}
  1925  
  1926  	_, err = WaitOnMessengerResponse(
  1927  		s.owner,
  1928  		func(r *MessengerResponse) bool {
  1929  			return checkKeyWasSent()
  1930  		},
  1931  		"no community that satisfies criteria",
  1932  	)
  1933  
  1934  	testCommunitiesKeyDistributor.unsubscribeFromKeyDistribution(subscription)
  1935  
  1936  	s.Require().NoError(err)
  1937  
  1938  	// msg will be encrypted using new keys
  1939  	msg = s.sendChatMessage(s.owner, chat.ID, "hello to closed channel with the new key")
  1940  
  1941  	// bob received new keys and can read the message
  1942  	response, err = WaitOnMessengerResponse(
  1943  		s.bob,
  1944  		func(r *MessengerResponse) bool {
  1945  			_, ok := r.messages[msg.ID]
  1946  			return ok
  1947  		},
  1948  		"no messages",
  1949  	)
  1950  	s.Require().NoError(err)
  1951  	s.Require().Len(response.Messages(), 1)
  1952  }
  1953  
  1954  func (s *MessengerCommunitiesTokenPermissionsSuite) TestReevaluateMemberPermissionsPerformance() {
  1955  	// This test is created for a performance degradation tracking for reevaluateMember permissions
  1956  	// current scenario mostly track channels permissions reevaluating, but feel free to expand it to
  1957  	// other scenarios or test you performance improvements
  1958  
  1959  	// in average, it took nearly 100-105 ms to check one permission for a current scenario:
  1960  	// - 10 members
  1961  	// - 10 channels
  1962  	// - one permission (channel permission for all 10 channels is set up)
  1963  
  1964  	// currently, adding any new permission to test must twice the current test average time
  1965  
  1966  	community, chat := s.createCommunity()
  1967  
  1968  	community, err := s.owner.communitiesManager.GetByID(community.ID())
  1969  	s.Require().NoError(err)
  1970  	s.Require().Len(community.Chats(), 1)
  1971  
  1972  	requestToJoin := &communities.RequestToJoin{
  1973  		Clock:       uint64(time.Now().Unix()),
  1974  		CommunityID: community.ID(),
  1975  		State:       communities.RequestToJoinStateAccepted,
  1976  		RevealedAccounts: []*protobuf.RevealedAccount{
  1977  			{
  1978  				Address:          bobAddress,
  1979  				ChainIds:         []uint64{testChainID1},
  1980  				IsAirdropAddress: true,
  1981  				Signature:        []byte("test"),
  1982  			},
  1983  		},
  1984  	}
  1985  	communityRole := []protobuf.CommunityMember_Roles{}
  1986  
  1987  	keysCount := 10
  1988  
  1989  	for i := 0; i < keysCount; i++ {
  1990  		privateKey, err := crypto.GenerateKey()
  1991  		s.Require().NoError(err)
  1992  
  1993  		memberPubKeyStr := common.PubkeyToHex(&privateKey.PublicKey)
  1994  		requestId := communities.CalculateRequestID(memberPubKeyStr, community.ID())
  1995  		requestToJoin.ID = requestId
  1996  		requestToJoin.PublicKey = memberPubKeyStr
  1997  
  1998  		err = s.owner.communitiesManager.SaveRequestToJoin(requestToJoin)
  1999  		s.Require().NoError(err)
  2000  		err = s.owner.communitiesManager.SaveRequestToJoinRevealedAddresses(requestId, requestToJoin.RevealedAccounts)
  2001  		s.Require().NoError(err)
  2002  		_, err = community.AddMember(&privateKey.PublicKey, communityRole, requestToJoin.Clock)
  2003  		s.Require().NoError(err)
  2004  		_, err = community.AddMemberToChat(chat.CommunityChatID(), &privateKey.PublicKey, communityRole, protobuf.CommunityMember_CHANNEL_ROLE_POSTER)
  2005  		s.Require().NoError(err)
  2006  	}
  2007  
  2008  	s.Require().Equal(community.MembersCount(), keysCount+1) // 1 is owner
  2009  
  2010  	chatsCount := 9 // in total will be 10, 1 channel were created during creating the community
  2011  
  2012  	for i := 0; i < chatsCount; i++ {
  2013  		newChat := &protobuf.CommunityChat{
  2014  			Permissions: &protobuf.CommunityPermissions{
  2015  				Access: protobuf.CommunityPermissions_AUTO_ACCEPT,
  2016  			},
  2017  			Identity: &protobuf.ChatIdentity{
  2018  				DisplayName: "name-" + strconv.Itoa(i),
  2019  				Description: "",
  2020  			},
  2021  		}
  2022  
  2023  		chatID := uuid.New().String()
  2024  		_, err = community.CreateChat(chatID, newChat)
  2025  		s.Require().NoError(err)
  2026  	}
  2027  
  2028  	s.Require().Len(community.Chats(), chatsCount+1) // 1 chat were created during community creation
  2029  
  2030  	err = s.owner.communitiesManager.SaveCommunity(community)
  2031  	s.Require().NoError(err)
  2032  
  2033  	// setup view channel permission
  2034  	channelPermissionRequest := requests.CreateCommunityTokenPermission{
  2035  		CommunityID: community.ID(),
  2036  		Type:        protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
  2037  		TokenCriteria: []*protobuf.TokenCriteria{
  2038  			&protobuf.TokenCriteria{
  2039  				Type:              protobuf.CommunityTokenType_ERC20,
  2040  				ContractAddresses: map[uint64]string{testChainID1: "0x123"},
  2041  				Symbol:            "TEST",
  2042  				AmountInWei:       "100000000000000000000",
  2043  				Decimals:          uint64(18),
  2044  			},
  2045  		},
  2046  		ChatIds: community.ChatIDs(),
  2047  	}
  2048  
  2049  	s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, channelPermissionRequest.TokenCriteria[0])
  2050  	defer s.resetMockedBalances() // reset mocked balances, this test in run with different test cases
  2051  
  2052  	// create permission using communitiesManager in order not to launch blocking reevaluation loop
  2053  	community, _, err = s.owner.communitiesManager.CreateCommunityTokenPermission(&channelPermissionRequest)
  2054  	s.Require().NoError(err)
  2055  	s.Require().Len(community.TokenPermissions(), 1)
  2056  
  2057  	for _, ids := range community.ChatIDs() {
  2058  		s.Require().True(s.owner.communitiesManager.IsChannelEncrypted(community.IDString(), ids))
  2059  	}
  2060  
  2061  	// force owner to reevaluate channel members
  2062  	// in production it will happen automatically, by periodic check
  2063  	start := time.Now()
  2064  	_, _, err = s.owner.communitiesManager.ReevaluateMembers(community.ID())
  2065  	s.Require().NoError(err)
  2066  
  2067  	elapsed := time.Since(start)
  2068  
  2069  	fmt.Println("ReevaluateMembers Time: ", elapsed)
  2070  	s.Require().Less(elapsed.Seconds(), 2.0)
  2071  }
  2072  
  2073  func (s *MessengerCommunitiesTokenPermissionsSuite) TestImportDecryptedArchiveMessages() {
  2074  	// 1.1. Create community
  2075  	community, chat := s.createCommunity()
  2076  
  2077  	// 1.2. Setup permissions
  2078  	communityPermission := &requests.CreateCommunityTokenPermission{
  2079  		CommunityID: community.ID(),
  2080  		Type:        protobuf.CommunityTokenPermission_BECOME_MEMBER,
  2081  		TokenCriteria: []*protobuf.TokenCriteria{
  2082  			{
  2083  				Type:              protobuf.CommunityTokenType_ERC20,
  2084  				ContractAddresses: map[uint64]string{testChainID1: "0x124"},
  2085  				Symbol:            "TEST2",
  2086  				AmountInWei:       "100000000000000000000",
  2087  				Decimals:          uint64(18),
  2088  			},
  2089  		},
  2090  	}
  2091  
  2092  	channelPermission := &requests.CreateCommunityTokenPermission{
  2093  		CommunityID: community.ID(),
  2094  		Type:        protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL,
  2095  		ChatIds:     []string{chat.ID},
  2096  		TokenCriteria: []*protobuf.TokenCriteria{
  2097  			{
  2098  				Type:              protobuf.CommunityTokenType_ERC20,
  2099  				ContractAddresses: map[uint64]string{testChainID1: "0x124"},
  2100  				Symbol:            "TEST2",
  2101  				AmountInWei:       "200000000000000000000",
  2102  				Decimals:          uint64(18),
  2103  			},
  2104  		},
  2105  	}
  2106  
  2107  	waitOnChannelKeyAdded := s.waitOnKeyDistribution(func(sub *CommunityAndKeyActions) bool {
  2108  		action, ok := sub.keyActions.ChannelKeysActions[chat.CommunityChatID()]
  2109  		if !ok || action.ActionType != communities.EncryptionKeyAdd {
  2110  			return false
  2111  		}
  2112  		_, ok = action.Members[common.PubkeyToHex(&s.owner.identity.PublicKey)]
  2113  		return ok
  2114  	})
  2115  
  2116  	waitOnCommunityPermissionCreated := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
  2117  		return len(sub.Community.TokenPermissions()) == 2
  2118  	})
  2119  
  2120  	response, err := s.owner.CreateCommunityTokenPermission(communityPermission)
  2121  	s.Require().NoError(err)
  2122  	s.Require().NotNil(response)
  2123  	s.Require().Len(response.Communities(), 1)
  2124  
  2125  	response, err = s.owner.CreateCommunityTokenPermission(channelPermission)
  2126  	s.Require().NoError(err)
  2127  	s.Require().NotNil(response)
  2128  	s.Require().Len(response.Communities(), 1)
  2129  
  2130  	community = response.Communities()[0]
  2131  	s.Require().True(community.HasTokenPermissions())
  2132  	s.Require().Len(community.TokenPermissions(), 2)
  2133  
  2134  	err = <-waitOnCommunityPermissionCreated
  2135  	s.Require().NoError(err)
  2136  	s.Require().True(community.Encrypted())
  2137  
  2138  	err = <-waitOnChannelKeyAdded
  2139  	s.Require().NoError(err)
  2140  
  2141  	// 2. Owner: Send a message A
  2142  	messageText1 := RandomLettersString(10)
  2143  	message1 := s.sendChatMessage(s.owner, chat.ID, messageText1)
  2144  
  2145  	// 2.2. Retrieve own message (to make it stored in the archive later)
  2146  	_, err = s.owner.RetrieveAll()
  2147  	s.Require().NoError(err)
  2148  
  2149  	// 3. Owner: Create community archive
  2150  	const partition = 2 * time.Minute
  2151  	messageDate := time.UnixMilli(int64(message1.Timestamp))
  2152  	startDate := messageDate.Add(-time.Minute)
  2153  	endDate := messageDate.Add(time.Minute)
  2154  	topic := types.BytesToTopic(transport.ToTopic(chat.ID))
  2155  	topics := []types.TopicType{topic}
  2156  
  2157  	torrentConfig := params.TorrentConfig{
  2158  		Enabled:    true,
  2159  		DataDir:    os.TempDir() + "/archivedata",
  2160  		TorrentDir: os.TempDir() + "/torrents",
  2161  		Port:       0,
  2162  	}
  2163  
  2164  	// Share archive directory between all users
  2165  	s.owner.archiveManager.SetTorrentConfig(&torrentConfig)
  2166  	s.bob.archiveManager.SetTorrentConfig(&torrentConfig)
  2167  	s.owner.config.messengerSignalsHandler = &MessengerSignalsHandlerMock{}
  2168  	s.bob.config.messengerSignalsHandler = &MessengerSignalsHandlerMock{}
  2169  
  2170  	archiveIDs, err := s.owner.archiveManager.CreateHistoryArchiveTorrentFromDB(community.ID(), topics, startDate, endDate, partition, community.Encrypted())
  2171  	s.Require().NoError(err)
  2172  	s.Require().Len(archiveIDs, 1)
  2173  
  2174  	community, err = s.owner.GetCommunityByID(community.ID())
  2175  	s.Require().NoError(err)
  2176  
  2177  	// 4. Bob: join community (satisfying membership, but not channel permissions)
  2178  	s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, communityPermission.TokenCriteria[0])
  2179  	s.advertiseCommunityTo(community, s.bob)
  2180  
  2181  	waitForKeysDistributedToBob := s.waitOnKeyDistribution(func(sub *CommunityAndKeyActions) bool {
  2182  		action := sub.keyActions.CommunityKeyAction
  2183  		if action.ActionType != communities.EncryptionKeySendToMembers {
  2184  			return false
  2185  		}
  2186  		_, ok := action.Members[s.bob.IdentityPublicKeyString()]
  2187  		return ok
  2188  	})
  2189  
  2190  	s.joinCommunity(community, s.bob)
  2191  
  2192  	err = <-waitForKeysDistributedToBob
  2193  	s.Require().NoError(err)
  2194  
  2195  	// 5. Bob: Import community archive
  2196  	// The archive is successfully decrypted, but the message inside is not.
  2197  	// https://github.com/status-im/status-desktop/issues/13105 can be reproduced at this stage
  2198  	// by forcing `encryption.ErrHashRatchetGroupIDNotFound` in `ExtractMessagesFromHistoryArchive` after decryption here:
  2199  	// https://github.com/status-im/status-go/blob/6c82a6c2be7ebed93bcae3b9cf5053da3820de50/protocol/communities/manager.go#L4403
  2200  
  2201  	// Ensure owner has archive
  2202  	archiveIndex, err := s.owner.archiveManager.LoadHistoryArchiveIndexFromFile(s.owner.identity, community.ID())
  2203  	s.Require().NoError(err)
  2204  	s.Require().Len(archiveIndex.Archives, 1)
  2205  
  2206  	// Ensure bob has archive (because they share same local directory)
  2207  	archiveIndex, err = s.bob.archiveManager.LoadHistoryArchiveIndexFromFile(s.bob.identity, community.ID())
  2208  	s.Require().NoError(err)
  2209  	s.Require().Len(archiveIndex.Archives, 1)
  2210  
  2211  	archiveHash := maps.Keys(archiveIndex.Archives)[0]
  2212  
  2213  	// Save message archive ID as in
  2214  	// https://github.com/status-im/status-go/blob/6c82a6c2be7ebed93bcae3b9cf5053da3820de50/protocol/communities/manager.go#L4325-L4336
  2215  	err = s.bob.archiveManager.SaveMessageArchiveID(community.ID(), archiveHash)
  2216  	s.Require().NoError(err)
  2217  
  2218  	// Import archive
  2219  	s.bob.importDelayer.once.Do(func() {
  2220  		close(s.bob.importDelayer.wait)
  2221  	})
  2222  	cancel := make(chan struct{})
  2223  	err = s.bob.importHistoryArchives(community.ID(), cancel)
  2224  	s.Require().NoError(err)
  2225  
  2226  	// Ensure message1 wasn't imported, as it's encrypted, and we don't have access to the channel
  2227  	receivedMessage1, err := s.bob.MessageByID(message1.ID)
  2228  	s.Require().Nil(receivedMessage1)
  2229  	s.Require().Error(err)
  2230  
  2231  	chatID := []byte(chat.ID)
  2232  	hashRatchetMessagesCount, err := s.bob.persistence.GetHashRatchetMessagesCountForGroup(chatID)
  2233  	s.Require().NoError(err)
  2234  	s.Require().Equal(1, hashRatchetMessagesCount)
  2235  
  2236  	// Make bob satisfy channel criteria
  2237  	waitOnChannelKeyToBeDistributedToBob := s.waitOnKeyDistribution(func(sub *CommunityAndKeyActions) bool {
  2238  		action, ok := sub.keyActions.ChannelKeysActions[chat.CommunityChatID()]
  2239  		if !ok || action.ActionType != communities.EncryptionKeySendToMembers {
  2240  			return false
  2241  		}
  2242  		_, ok = action.Members[common.PubkeyToHex(&s.bob.identity.PublicKey)]
  2243  		return ok
  2244  	})
  2245  
  2246  	s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, channelPermission.TokenCriteria[0])
  2247  
  2248  	// force owner to reevaluate channel members
  2249  	// in production it will happen automatically, by periodic check
  2250  	err = s.owner.communitiesManager.ForceMembersReevaluation(community.ID())
  2251  	s.Require().NoError(err)
  2252  
  2253  	err = <-waitOnChannelKeyToBeDistributedToBob
  2254  	s.Require().NoError(err)
  2255  
  2256  	// Finally ensure that the message from archive was retrieved and decrypted
  2257  
  2258  	// NOTE: In theory a single RetrieveAll call should be enough,
  2259  	// 		 because we immediately process all hash ratchet messages
  2260  	response, err = s.bob.RetrieveAll()
  2261  	s.Require().NoError(err)
  2262  	s.Require().Len(response.Messages(), 1)
  2263  
  2264  	receivedMessage1, ok := response.messages[message1.ID]
  2265  	s.Require().True(ok)
  2266  	s.Require().Equal(messageText1, receivedMessage1.Text)
  2267  }
  2268  
  2269  func (s *MessengerCommunitiesTokenPermissionsSuite) TestDeleteChannelWithTokenPermission() {
  2270  	// Setup community with two permitted channels
  2271  	community, firstChat := s.createCommunity()
  2272  
  2273  	response, err := s.owner.CreateCommunityChat(community.ID(), &protobuf.CommunityChat{
  2274  		Permissions: &protobuf.CommunityPermissions{
  2275  			Access: protobuf.CommunityPermissions_AUTO_ACCEPT,
  2276  		},
  2277  		Identity: &protobuf.ChatIdentity{
  2278  			DisplayName: "new channel",
  2279  			Emoji:       "",
  2280  			Description: "chat created after joining the community",
  2281  		},
  2282  	})
  2283  	s.Require().NoError(err)
  2284  	s.Require().Len(response.Chats(), 1)
  2285  	secondChat := response.Chats()[0]
  2286  
  2287  	channelPermission := &requests.CreateCommunityTokenPermission{
  2288  		CommunityID: community.ID(),
  2289  		Type:        protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL,
  2290  		ChatIds:     []string{firstChat.ID, secondChat.ID},
  2291  		TokenCriteria: []*protobuf.TokenCriteria{
  2292  			{
  2293  				Type:              protobuf.CommunityTokenType_ERC20,
  2294  				ContractAddresses: map[uint64]string{testChainID1: "0x124"},
  2295  				Symbol:            "TEST2",
  2296  				AmountInWei:       "200000000000000000000",
  2297  				Decimals:          uint64(18),
  2298  			},
  2299  		},
  2300  	}
  2301  
  2302  	response, err = s.owner.CreateCommunityTokenPermission(channelPermission)
  2303  	s.Require().NoError(err)
  2304  	s.Require().NotNil(response)
  2305  	s.Require().Len(response.Communities(), 1)
  2306  
  2307  	// Make sure both channels are covered with permission
  2308  	community, err = s.owner.GetCommunityByID(community.ID())
  2309  	s.Require().NoError(err)
  2310  	s.Require().Len(community.Chats(), 2)
  2311  	s.Require().Len(community.TokenPermissions(), 1)
  2312  	for _, permission := range community.TokenPermissions() {
  2313  		s.Require().Len(permission.ChatIds, 2)
  2314  		s.Require().True(permission.HasChat(firstChat.ID))
  2315  		s.Require().True(permission.HasChat(secondChat.ID))
  2316  	}
  2317  
  2318  	// Delete first community channel
  2319  	response, err = s.owner.DeleteCommunityChat(community.ID(), firstChat.ID)
  2320  	s.Require().NoError(err)
  2321  	s.Require().Len(response.Communities(), 1)
  2322  	community = response.Communities()[0]
  2323  	s.Require().Len(community.Chats(), 1)
  2324  	for _, permission := range community.TokenPermissions() {
  2325  		s.Require().Len(permission.ChatIds, 1)
  2326  		s.Require().False(permission.HasChat(firstChat.ID))
  2327  		s.Require().True(permission.HasChat(secondChat.ID))
  2328  	}
  2329  
  2330  	// Delete second community channel
  2331  	response, err = s.owner.DeleteCommunityChat(community.ID(), secondChat.ID)
  2332  	s.Require().NoError(err)
  2333  	s.Require().Len(response.Communities(), 1)
  2334  	community = response.Communities()[0]
  2335  	s.Require().Len(community.Chats(), 0)
  2336  	s.Require().Len(community.TokenPermissions(), 0)
  2337  }