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 }