github.com/status-im/status-go@v1.1.0/protocol/communities/manager_test.go (about) 1 package communities 2 3 import ( 4 "bytes" 5 "context" 6 "errors" 7 "image" 8 "image/png" 9 "math" 10 "math/big" 11 "os" 12 "testing" 13 "time" 14 15 gethcommon "github.com/ethereum/go-ethereum/common" 16 "github.com/ethereum/go-ethereum/common/hexutil" 17 "github.com/status-im/status-go/appdatabase" 18 "github.com/status-im/status-go/eth-node/crypto" 19 "github.com/status-im/status-go/eth-node/types" 20 userimages "github.com/status-im/status-go/images" 21 "github.com/status-im/status-go/params" 22 "github.com/status-im/status-go/protocol/common" 23 community_token "github.com/status-im/status-go/protocol/communities/token" 24 "github.com/status-im/status-go/protocol/protobuf" 25 "github.com/status-im/status-go/protocol/requests" 26 "github.com/status-im/status-go/protocol/sqlite" 27 "github.com/status-im/status-go/protocol/transport" 28 v1 "github.com/status-im/status-go/protocol/v1" 29 "github.com/status-im/status-go/services/wallet/bigint" 30 walletCommon "github.com/status-im/status-go/services/wallet/common" 31 "github.com/status-im/status-go/services/wallet/thirdparty" 32 "github.com/status-im/status-go/services/wallet/token" 33 "github.com/status-im/status-go/t/helpers" 34 35 "github.com/golang/protobuf/proto" 36 _ "github.com/mutecomm/go-sqlcipher/v4" // require go-sqlcipher that overrides default implementation 37 "github.com/stretchr/testify/suite" 38 "go.uber.org/zap" 39 ) 40 41 func TestManagerSuite(t *testing.T) { 42 suite.Run(t, new(ManagerSuite)) 43 } 44 45 type ManagerSuite struct { 46 suite.Suite 47 manager *Manager 48 archiveManager *ArchiveManager 49 } 50 51 func (s *ManagerSuite) buildManagers(ownerVerifier OwnerVerifier) (*Manager, *ArchiveManager) { 52 db, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) 53 s.Require().NoError(err, "creating sqlite db instance") 54 err = sqlite.Migrate(db) 55 s.Require().NoError(err, "protocol migrate") 56 57 key, err := crypto.GenerateKey() 58 s.Require().NoError(err) 59 60 logger, err := zap.NewDevelopment() 61 s.Require().NoError(err) 62 63 m, err := NewManager(key, "", db, nil, logger, nil, ownerVerifier, nil, &TimeSourceStub{}, nil, nil) 64 s.Require().NoError(err) 65 s.Require().NoError(m.Start()) 66 67 amc := &ArchiveManagerConfig{ 68 TorrentConfig: buildTorrentConfig(), 69 Logger: logger, 70 Persistence: m.GetPersistence(), 71 Transport: nil, 72 Identity: key, 73 Encryptor: nil, 74 Publisher: m, 75 } 76 t := NewArchiveManager(amc) 77 s.Require().NoError(err) 78 79 return m, t 80 } 81 82 func (s *ManagerSuite) SetupTest() { 83 m, t := s.buildManagers(nil) 84 SetValidateInterval(30 * time.Millisecond) 85 s.manager = m 86 s.archiveManager = t 87 } 88 89 func intToBig(n int64) *hexutil.Big { 90 return (*hexutil.Big)(big.NewInt(n)) 91 } 92 93 func uintToDecBig(n uint64) *bigint.BigInt { 94 return &bigint.BigInt{Int: big.NewInt(int64(n))} 95 } 96 97 func tokenBalance(tokenID uint64, balance uint64) thirdparty.TokenBalance { 98 return thirdparty.TokenBalance{ 99 TokenID: uintToDecBig(tokenID), 100 Balance: uintToDecBig(balance), 101 } 102 } 103 104 func (s *ManagerSuite) getHistoryTasksCount() int { 105 // sync.Map doesn't have a Len function, so we need to count manually 106 count := 0 107 s.archiveManager.historyArchiveTasks.Range(func(_, _ interface{}) bool { 108 count++ 109 return true 110 }) 111 return count 112 } 113 114 type testCollectiblesManager struct { 115 response map[uint64]map[gethcommon.Address]thirdparty.TokenBalancesPerContractAddress 116 } 117 118 func (m *testCollectiblesManager) setResponse(chainID uint64, walletAddress gethcommon.Address, contractAddress gethcommon.Address, balances []thirdparty.TokenBalance) { 119 if m.response == nil { 120 m.response = make(map[uint64]map[gethcommon.Address]thirdparty.TokenBalancesPerContractAddress) 121 } 122 if m.response[chainID] == nil { 123 m.response[chainID] = make(map[gethcommon.Address]thirdparty.TokenBalancesPerContractAddress) 124 } 125 if m.response[chainID][walletAddress] == nil { 126 m.response[chainID][walletAddress] = make(thirdparty.TokenBalancesPerContractAddress) 127 } 128 129 m.response[chainID][walletAddress][contractAddress] = balances 130 } 131 132 func (m *testCollectiblesManager) FetchBalancesByOwnerAndContractAddress(ctx context.Context, chainID walletCommon.ChainID, ownerAddress gethcommon.Address, contractAddresses []gethcommon.Address) (thirdparty.TokenBalancesPerContractAddress, error) { 133 return m.response[uint64(chainID)][ownerAddress], nil 134 } 135 136 func (m *testCollectiblesManager) GetCollectibleOwnership(id thirdparty.CollectibleUniqueID) ([]thirdparty.AccountBalance, error) { 137 return nil, errors.New("GetCollectibleOwnership is not implemented for testCollectiblesManager") 138 } 139 140 func (m *testCollectiblesManager) FetchCollectibleOwnersByContractAddress(ctx context.Context, chainID walletCommon.ChainID, contractAddress gethcommon.Address) (*thirdparty.CollectibleContractOwnership, error) { 141 ret := &thirdparty.CollectibleContractOwnership{ 142 ContractAddress: contractAddress, 143 Owners: []thirdparty.CollectibleOwner{}, 144 } 145 146 balancesPerOwner, ok := m.response[uint64(chainID)] 147 if !ok { 148 return ret, nil 149 } 150 151 for ownerAddress, collectibles := range balancesPerOwner { 152 for collectibleAddress, balances := range collectibles { 153 if collectibleAddress == contractAddress { 154 ret.Owners = append(ret.Owners, thirdparty.CollectibleOwner{ 155 OwnerAddress: ownerAddress, 156 TokenBalances: balances, 157 }) 158 break 159 } 160 } 161 } 162 163 return ret, nil 164 } 165 166 func (m *testCollectiblesManager) FetchCachedBalancesByOwnerAndContractAddress(ctx context.Context, chainID walletCommon.ChainID, ownerAddress gethcommon.Address, contractAddresses []gethcommon.Address) (thirdparty.TokenBalancesPerContractAddress, error) { 167 return m.response[uint64(chainID)][ownerAddress], nil 168 } 169 170 type testTokenManager struct { 171 response map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big 172 } 173 174 func (m *testTokenManager) setResponse(chainID uint64, walletAddress, tokenAddress gethcommon.Address, balance int64) { 175 176 if m.response == nil { 177 m.response = make(map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big) 178 } 179 180 if m.response[chainID] == nil { 181 m.response[chainID] = make(map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big) 182 } 183 184 if m.response[chainID][walletAddress] == nil { 185 m.response[chainID][walletAddress] = make(map[gethcommon.Address]*hexutil.Big) 186 } 187 188 m.response[chainID][walletAddress][tokenAddress] = intToBig(balance) 189 190 } 191 192 func (m *testTokenManager) GetAllChainIDs() ([]uint64, error) { 193 return []uint64{5}, nil 194 } 195 196 func (m *testTokenManager) GetBalancesByChain(ctx context.Context, accounts, tokenAddresses []gethcommon.Address, chainIDs []uint64) (map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big, error) { 197 return m.response, nil 198 } 199 200 func (m *testTokenManager) GetCachedBalancesByChain(ctx context.Context, accounts, tokenAddresses []gethcommon.Address, chainIDs []uint64) (BalancesByChain, error) { 201 return m.response, nil 202 } 203 204 func (m *testTokenManager) FindOrCreateTokenByAddress(ctx context.Context, chainID uint64, address gethcommon.Address) *token.Token { 205 return nil 206 } 207 208 func (s *ManagerSuite) setupManagerForTokenPermissions() (*Manager, *testCollectiblesManager, *testTokenManager) { 209 db, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) 210 s.NoError(err, "creating sqlite db instance") 211 err = sqlite.Migrate(db) 212 s.NoError(err, "protocol migrate") 213 214 key, err := crypto.GenerateKey() 215 s.Require().NoError(err) 216 s.Require().NoError(err) 217 218 cm := &testCollectiblesManager{} 219 tm := &testTokenManager{} 220 221 options := []ManagerOption{ 222 WithWalletConfig(¶ms.WalletConfig{ 223 OpenseaAPIKey: "some-key", 224 }), 225 WithCollectiblesManager(cm), 226 WithTokenManager(tm), 227 } 228 229 m, err := NewManager(key, "", db, nil, nil, nil, nil, nil, &TimeSourceStub{}, nil, nil, options...) 230 s.Require().NoError(err) 231 s.Require().NoError(m.Start()) 232 233 return m, cm, tm 234 } 235 236 func (s *ManagerSuite) TestRetrieveTokens() { 237 m, _, tm := s.setupManagerForTokenPermissions() 238 239 var chainID uint64 = 5 240 contractAddresses := make(map[uint64]string) 241 contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a" 242 var decimals uint64 = 18 243 244 var tokenCriteria = []*protobuf.TokenCriteria{ 245 &protobuf.TokenCriteria{ 246 ContractAddresses: contractAddresses, 247 Symbol: "STT", 248 Type: protobuf.CommunityTokenType_ERC20, 249 Name: "Status Test Token", 250 AmountInWei: "1000000000000000000", 251 Decimals: decimals, 252 }, 253 } 254 255 var permissions = []*CommunityTokenPermission{ 256 &CommunityTokenPermission{ 257 CommunityTokenPermission: &protobuf.CommunityTokenPermission{ 258 Id: "some-id", 259 Type: protobuf.CommunityTokenPermission_BECOME_MEMBER, 260 TokenCriteria: tokenCriteria, 261 }, 262 }, 263 } 264 265 preParsedPermissions := preParsedCommunityPermissionsData(permissions) 266 267 accountChainIDsCombination := []*AccountChainIDsCombination{ 268 &AccountChainIDsCombination{ 269 Address: gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"), 270 ChainIDs: []uint64{chainID}, 271 }, 272 } 273 // Set response to exactly the right one 274 tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals)))) 275 resp, err := m.PermissionChecker.CheckPermissions(preParsedPermissions, accountChainIDsCombination, false) 276 s.Require().NoError(err) 277 s.Require().NotNil(resp) 278 s.Require().True(resp.Satisfied) 279 280 // Set response to 0 281 tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0) 282 resp, err = m.PermissionChecker.CheckPermissions(preParsedPermissions, accountChainIDsCombination, false) 283 s.Require().NoError(err) 284 s.Require().NotNil(resp) 285 s.Require().False(resp.Satisfied) 286 } 287 288 func (s *ManagerSuite) TestRetrieveCollectibles() { 289 m, cm, _ := s.setupManagerForTokenPermissions() 290 291 var chainID uint64 = 5 292 contractAddresses := make(map[uint64]string) 293 contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a" 294 295 tokenID := uint64(10) 296 var tokenBalances []thirdparty.TokenBalance 297 298 var tokenCriteria = []*protobuf.TokenCriteria{ 299 { 300 ContractAddresses: contractAddresses, 301 TokenIds: []uint64{tokenID}, 302 Type: protobuf.CommunityTokenType_ERC721, 303 AmountInWei: "1", 304 }, 305 } 306 307 var permissions = []*CommunityTokenPermission{ 308 { 309 CommunityTokenPermission: &protobuf.CommunityTokenPermission{ 310 Id: "some-id", 311 Type: protobuf.CommunityTokenPermission_BECOME_MEMBER, 312 TokenCriteria: tokenCriteria, 313 }, 314 }, 315 } 316 317 preParsedPermissions := preParsedCommunityPermissionsData(permissions) 318 319 accountChainIDsCombination := []*AccountChainIDsCombination{ 320 { 321 Address: gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"), 322 ChainIDs: []uint64{chainID}, 323 }, 324 } 325 326 // Set response to exactly the right one 327 tokenBalances = []thirdparty.TokenBalance{tokenBalance(tokenID, 1)} 328 cm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), tokenBalances) 329 resp, err := m.PermissionChecker.CheckPermissions(preParsedPermissions, accountChainIDsCombination, false) 330 s.Require().NoError(err) 331 s.Require().NotNil(resp) 332 s.Require().True(resp.Satisfied) 333 334 // Set balances to 0 335 tokenBalances = []thirdparty.TokenBalance{} 336 cm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), tokenBalances) 337 resp, err = m.PermissionChecker.CheckPermissions(preParsedPermissions, accountChainIDsCombination, false) 338 s.Require().NoError(err) 339 s.Require().NotNil(resp) 340 s.Require().False(resp.Satisfied) 341 } 342 343 func (s *ManagerSuite) TestCreateCommunity() { 344 request := &requests.CreateCommunity{ 345 Name: "status", 346 Description: "token membership description", 347 Membership: protobuf.CommunityPermissions_AUTO_ACCEPT, 348 } 349 350 community, err := s.manager.CreateCommunity(request, true) 351 s.Require().NoError(err) 352 s.Require().NotNil(community) 353 354 communities, err := s.manager.All() 355 s.Require().NoError(err) 356 s.Require().Len(communities, 1) 357 358 actualCommunity := communities[0] 359 if bytes.Equal(community.ID(), communities[0].ID()) { 360 actualCommunity = communities[0] 361 } 362 363 s.Require().Equal(community.ID(), actualCommunity.ID()) 364 s.Require().Equal(community.PrivateKey(), actualCommunity.PrivateKey()) 365 s.Require().True(community.IsControlNode()) 366 s.Require().True(proto.Equal(community.config.CommunityDescription, actualCommunity.config.CommunityDescription)) 367 } 368 369 func (s *ManagerSuite) TestCreateCommunity_WithBanner() { 370 // Generate test image bigger than BannerDim 371 testImage := image.NewRGBA(image.Rect(0, 0, 20, 10)) 372 373 tmpTestFilePath := s.T().TempDir() + "/test.png" 374 file, err := os.Create(tmpTestFilePath) 375 s.NoError(err) 376 defer file.Close() 377 378 err = png.Encode(file, testImage) 379 s.Require().NoError(err) 380 381 request := &requests.CreateCommunity{ 382 Name: "with_banner", 383 Description: "community with banner ", 384 Membership: protobuf.CommunityPermissions_AUTO_ACCEPT, 385 Banner: userimages.CroppedImage{ 386 ImagePath: tmpTestFilePath, 387 X: 1, 388 Y: 1, 389 Width: 10, 390 Height: 5, 391 }, 392 } 393 394 community, err := s.manager.CreateCommunity(request, true) 395 s.Require().NoError(err) 396 s.Require().NotNil(community) 397 398 communities, err := s.manager.All() 399 s.Require().NoError(err) 400 s.Require().Len(communities, 1) 401 s.Require().Equal(len(community.config.CommunityDescription.Identity.Images), 1) 402 testIdentityImage, isMapContainsKey := community.config.CommunityDescription.Identity.Images[userimages.BannerIdentityName] 403 s.Require().True(isMapContainsKey) 404 s.Require().Positive(len(testIdentityImage.Payload)) 405 } 406 407 func (s *ManagerSuite) TestEditCommunity() { 408 //create community 409 createRequest := &requests.CreateCommunity{ 410 Name: "status", 411 Description: "status community description", 412 Membership: protobuf.CommunityPermissions_AUTO_ACCEPT, 413 } 414 415 community, err := s.manager.CreateCommunity(createRequest, true) 416 s.Require().NoError(err) 417 s.Require().NotNil(community) 418 419 update := &requests.EditCommunity{ 420 CommunityID: community.ID(), 421 CreateCommunity: requests.CreateCommunity{ 422 Name: "statusEdited", 423 Description: "status community description edited", 424 }, 425 } 426 427 updatedCommunity, err := s.manager.EditCommunity(update) 428 s.Require().NoError(err) 429 s.Require().NotNil(updatedCommunity) 430 431 //ensure updated community successfully stored 432 communities, err := s.manager.All() 433 s.Require().NoError(err) 434 s.Require().Len(communities, 1) 435 436 storedCommunity := communities[0] 437 if bytes.Equal(community.ID(), communities[0].ID()) { 438 storedCommunity = communities[0] 439 } 440 441 s.Require().Equal(storedCommunity.ID(), updatedCommunity.ID()) 442 s.Require().Equal(storedCommunity.PrivateKey(), updatedCommunity.PrivateKey()) 443 s.Require().Equal(storedCommunity.config.CommunityDescription.Identity.DisplayName, update.CreateCommunity.Name) 444 s.Require().Equal(storedCommunity.config.CommunityDescription.Identity.Description, update.CreateCommunity.Description) 445 } 446 447 func (s *ManagerSuite) TestGetControlledCommunitiesChatIDs() { 448 community, _, err := s.buildCommunityWithChat() 449 s.Require().NoError(err) 450 s.Require().NotNil(community) 451 452 controlledChatIDs, err := s.manager.GetOwnedCommunitiesChatIDs() 453 454 s.Require().NoError(err) 455 s.Require().Len(controlledChatIDs, 1) 456 } 457 458 func (s *ManagerSuite) TestStartAndStopTorrentClient() { 459 err := s.archiveManager.StartTorrentClient() 460 s.Require().NoError(err) 461 s.Require().NotNil(s.archiveManager.torrentClient) 462 defer s.archiveManager.Stop() //nolint: errcheck 463 464 _, err = os.Stat(s.archiveManager.torrentConfig.DataDir) 465 s.Require().NoError(err) 466 s.Require().Equal(s.archiveManager.torrentClientStarted(), true) 467 } 468 469 func (s *ManagerSuite) TestStartHistoryArchiveTasksInterval() { 470 err := s.archiveManager.StartTorrentClient() 471 s.Require().NoError(err) 472 defer s.archiveManager.Stop() //nolint: errcheck 473 474 community, _, err := s.buildCommunityWithChat() 475 s.Require().NoError(err) 476 477 interval := 10 * time.Second 478 go s.archiveManager.StartHistoryArchiveTasksInterval(community, interval) 479 // Due to async exec we need to wait a bit until we check 480 // the task count. 481 time.Sleep(5 * time.Second) 482 483 count := s.getHistoryTasksCount() 484 s.Require().Equal(count, 1) 485 486 // We wait another 5 seconds to ensure the first tick has kicked in 487 time.Sleep(5 * time.Second) 488 489 _, err = os.Stat(torrentFile(s.archiveManager.torrentConfig.TorrentDir, community.IDString())) 490 s.Require().Error(err) 491 492 s.archiveManager.StopHistoryArchiveTasksInterval(community.ID()) 493 s.archiveManager.historyArchiveTasksWaitGroup.Wait() 494 count = s.getHistoryTasksCount() 495 s.Require().Equal(count, 0) 496 } 497 498 func (s *ManagerSuite) TestStopHistoryArchiveTasksIntervals() { 499 err := s.archiveManager.StartTorrentClient() 500 s.Require().NoError(err) 501 defer s.archiveManager.Stop() //nolint: errcheck 502 503 community, _, err := s.buildCommunityWithChat() 504 s.Require().NoError(err) 505 506 interval := 10 * time.Second 507 go s.archiveManager.StartHistoryArchiveTasksInterval(community, interval) 508 509 time.Sleep(2 * time.Second) 510 511 count := s.getHistoryTasksCount() 512 s.Require().Equal(count, 1) 513 514 s.archiveManager.stopHistoryArchiveTasksIntervals() 515 516 count = s.getHistoryTasksCount() 517 s.Require().Equal(count, 0) 518 } 519 520 func (s *ManagerSuite) TestStopTorrentClient_ShouldStopHistoryArchiveTasks() { 521 err := s.archiveManager.StartTorrentClient() 522 s.Require().NoError(err) 523 defer s.archiveManager.Stop() //nolint: errcheck 524 525 community, _, err := s.buildCommunityWithChat() 526 s.Require().NoError(err) 527 528 interval := 10 * time.Second 529 go s.archiveManager.StartHistoryArchiveTasksInterval(community, interval) 530 // Due to async exec we need to wait a bit until we check 531 // the task count. 532 time.Sleep(2 * time.Second) 533 534 count := s.getHistoryTasksCount() 535 s.Require().Equal(count, 1) 536 537 err = s.archiveManager.Stop() 538 s.Require().NoError(err) 539 540 count = s.getHistoryTasksCount() 541 s.Require().Equal(count, 0) 542 } 543 544 func (s *ManagerSuite) TestStartTorrentClient_DelayedUntilOnline() { 545 s.Require().False(s.archiveManager.torrentClientStarted()) 546 547 s.archiveManager.SetOnline(true) 548 s.Require().True(s.archiveManager.torrentClientStarted()) 549 } 550 551 func (s *ManagerSuite) TestCreateHistoryArchiveTorrent_WithoutMessages() { 552 community, chatID, err := s.buildCommunityWithChat() 553 s.Require().NoError(err) 554 555 topic := types.BytesToTopic(transport.ToTopic(chatID)) 556 topics := []types.TopicType{topic} 557 558 // Time range of 7 days 559 startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC) 560 endDate := time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC) 561 // Partition of 7 days 562 partition := 7 * 24 * time.Hour 563 564 _, err = s.archiveManager.CreateHistoryArchiveTorrentFromDB(community.ID(), topics, startDate, endDate, partition, false) 565 s.Require().NoError(err) 566 567 // There are no waku messages in the database so we don't expect 568 // any archives to be created 569 _, err = os.Stat(s.archiveManager.archiveDataFile(community.IDString())) 570 s.Require().Error(err) 571 _, err = os.Stat(s.archiveManager.archiveIndexFile(community.IDString())) 572 s.Require().Error(err) 573 _, err = os.Stat(torrentFile(s.archiveManager.torrentConfig.TorrentDir, community.IDString())) 574 s.Require().Error(err) 575 } 576 577 func (s *ManagerSuite) TestCreateHistoryArchiveTorrent_ShouldCreateArchive() { 578 community, chatID, err := s.buildCommunityWithChat() 579 s.Require().NoError(err) 580 581 topic := types.BytesToTopic(transport.ToTopic(chatID)) 582 topics := []types.TopicType{topic} 583 584 // Time range of 7 days 585 startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC) 586 endDate := time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC) 587 // Partition of 7 days, this should create a single archive 588 partition := 7 * 24 * time.Hour 589 590 message1 := buildMessage(startDate.Add(1*time.Hour), topic, []byte{1}) 591 message2 := buildMessage(startDate.Add(2*time.Hour), topic, []byte{2}) 592 // This message is outside of the startDate-endDate range and should not 593 // be part of the archive 594 message3 := buildMessage(endDate.Add(2*time.Hour), topic, []byte{3}) 595 596 err = s.manager.StoreWakuMessage(&message1) 597 s.Require().NoError(err) 598 err = s.manager.StoreWakuMessage(&message2) 599 s.Require().NoError(err) 600 err = s.manager.StoreWakuMessage(&message3) 601 s.Require().NoError(err) 602 603 _, err = s.archiveManager.CreateHistoryArchiveTorrentFromDB(community.ID(), topics, startDate, endDate, partition, false) 604 s.Require().NoError(err) 605 606 _, err = os.Stat(s.archiveManager.archiveDataFile(community.IDString())) 607 s.Require().NoError(err) 608 _, err = os.Stat(s.archiveManager.archiveIndexFile(community.IDString())) 609 s.Require().NoError(err) 610 _, err = os.Stat(torrentFile(s.archiveManager.torrentConfig.TorrentDir, community.IDString())) 611 s.Require().NoError(err) 612 613 index, err := s.archiveManager.LoadHistoryArchiveIndexFromFile(s.manager.identity, community.ID()) 614 s.Require().NoError(err) 615 s.Require().Len(index.Archives, 1) 616 617 totalData, err := os.ReadFile(s.archiveManager.archiveDataFile(community.IDString())) 618 s.Require().NoError(err) 619 620 for _, metadata := range index.Archives { 621 archive := &protobuf.WakuMessageArchive{} 622 data := totalData[metadata.Offset : metadata.Offset+metadata.Size-metadata.Padding] 623 624 err = proto.Unmarshal(data, archive) 625 s.Require().NoError(err) 626 627 s.Require().Len(archive.Messages, 2) 628 } 629 } 630 631 func (s *ManagerSuite) TestCreateHistoryArchiveTorrent_ShouldCreateMultipleArchives() { 632 community, chatID, err := s.buildCommunityWithChat() 633 s.Require().NoError(err) 634 635 topic := types.BytesToTopic(transport.ToTopic(chatID)) 636 topics := []types.TopicType{topic} 637 638 // Time range of 3 weeks 639 startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC) 640 endDate := time.Date(2020, 1, 21, 00, 00, 00, 0, time.UTC) 641 // 7 days partition, this should create three archives 642 partition := 7 * 24 * time.Hour 643 644 message1 := buildMessage(startDate.Add(1*time.Hour), topic, []byte{1}) 645 message2 := buildMessage(startDate.Add(2*time.Hour), topic, []byte{2}) 646 // We expect 2 archives to be created for startDate - endDate of each 647 // 7 days of data. This message should end up in the second archive 648 message3 := buildMessage(startDate.Add(8*24*time.Hour), topic, []byte{3}) 649 // This one should end up in the third archive 650 message4 := buildMessage(startDate.Add(14*24*time.Hour), topic, []byte{4}) 651 652 err = s.manager.StoreWakuMessage(&message1) 653 s.Require().NoError(err) 654 err = s.manager.StoreWakuMessage(&message2) 655 s.Require().NoError(err) 656 err = s.manager.StoreWakuMessage(&message3) 657 s.Require().NoError(err) 658 err = s.manager.StoreWakuMessage(&message4) 659 s.Require().NoError(err) 660 661 _, err = s.archiveManager.CreateHistoryArchiveTorrentFromDB(community.ID(), topics, startDate, endDate, partition, false) 662 s.Require().NoError(err) 663 664 index, err := s.archiveManager.LoadHistoryArchiveIndexFromFile(s.manager.identity, community.ID()) 665 s.Require().NoError(err) 666 s.Require().Len(index.Archives, 3) 667 668 totalData, err := os.ReadFile(s.archiveManager.archiveDataFile(community.IDString())) 669 s.Require().NoError(err) 670 671 // First archive has 2 messages 672 // Second archive has 1 message 673 // Third archive has 1 message 674 fromMap := map[uint64]int{ 675 uint64(startDate.Unix()): 2, 676 uint64(startDate.Add(partition).Unix()): 1, 677 uint64(startDate.Add(partition * 2).Unix()): 1, 678 } 679 680 for _, metadata := range index.Archives { 681 archive := &protobuf.WakuMessageArchive{} 682 data := totalData[metadata.Offset : metadata.Offset+metadata.Size-metadata.Padding] 683 684 err = proto.Unmarshal(data, archive) 685 s.Require().NoError(err) 686 s.Require().Len(archive.Messages, fromMap[metadata.Metadata.From]) 687 } 688 } 689 690 func (s *ManagerSuite) TestCreateHistoryArchiveTorrent_ShouldAppendArchives() { 691 community, chatID, err := s.buildCommunityWithChat() 692 s.Require().NoError(err) 693 694 topic := types.BytesToTopic(transport.ToTopic(chatID)) 695 topics := []types.TopicType{topic} 696 697 // Time range of 1 week 698 startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC) 699 endDate := time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC) 700 // 7 days partition, this should create one archive 701 partition := 7 * 24 * time.Hour 702 703 message1 := buildMessage(startDate.Add(1*time.Hour), topic, []byte{1}) 704 err = s.manager.StoreWakuMessage(&message1) 705 s.Require().NoError(err) 706 707 _, err = s.archiveManager.CreateHistoryArchiveTorrentFromDB(community.ID(), topics, startDate, endDate, partition, false) 708 s.Require().NoError(err) 709 710 index, err := s.archiveManager.LoadHistoryArchiveIndexFromFile(s.manager.identity, community.ID()) 711 s.Require().NoError(err) 712 s.Require().Len(index.Archives, 1) 713 714 // Time range of next week 715 startDate = time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC) 716 endDate = time.Date(2020, 1, 14, 00, 00, 00, 0, time.UTC) 717 718 message2 := buildMessage(startDate.Add(2*time.Hour), topic, []byte{2}) 719 err = s.manager.StoreWakuMessage(&message2) 720 s.Require().NoError(err) 721 722 _, err = s.archiveManager.CreateHistoryArchiveTorrentFromDB(community.ID(), topics, startDate, endDate, partition, false) 723 s.Require().NoError(err) 724 725 index, err = s.archiveManager.LoadHistoryArchiveIndexFromFile(s.manager.identity, community.ID()) 726 s.Require().NoError(err) 727 s.Require().Len(index.Archives, 2) 728 } 729 730 func (s *ManagerSuite) TestCreateHistoryArchiveTorrentFromMessages() { 731 community, chatID, err := s.buildCommunityWithChat() 732 s.Require().NoError(err) 733 734 topic := types.BytesToTopic(transport.ToTopic(chatID)) 735 topics := []types.TopicType{topic} 736 737 // Time range of 7 days 738 startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC) 739 endDate := time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC) 740 // Partition of 7 days, this should create a single archive 741 partition := 7 * 24 * time.Hour 742 743 message1 := buildMessage(startDate.Add(1*time.Hour), topic, []byte{1}) 744 message2 := buildMessage(startDate.Add(2*time.Hour), topic, []byte{2}) 745 // This message is outside of the startDate-endDate range and should not 746 // be part of the archive 747 message3 := buildMessage(endDate.Add(2*time.Hour), topic, []byte{3}) 748 749 _, err = s.archiveManager.CreateHistoryArchiveTorrentFromMessages(community.ID(), []*types.Message{&message1, &message2, &message3}, topics, startDate, endDate, partition, false) 750 s.Require().NoError(err) 751 752 _, err = os.Stat(s.archiveManager.archiveDataFile(community.IDString())) 753 s.Require().NoError(err) 754 _, err = os.Stat(s.archiveManager.archiveIndexFile(community.IDString())) 755 s.Require().NoError(err) 756 _, err = os.Stat(torrentFile(s.archiveManager.torrentConfig.TorrentDir, community.IDString())) 757 s.Require().NoError(err) 758 759 index, err := s.archiveManager.LoadHistoryArchiveIndexFromFile(s.manager.identity, community.ID()) 760 s.Require().NoError(err) 761 s.Require().Len(index.Archives, 1) 762 763 totalData, err := os.ReadFile(s.archiveManager.archiveDataFile(community.IDString())) 764 s.Require().NoError(err) 765 766 for _, metadata := range index.Archives { 767 archive := &protobuf.WakuMessageArchive{} 768 data := totalData[metadata.Offset : metadata.Offset+metadata.Size-metadata.Padding] 769 770 err = proto.Unmarshal(data, archive) 771 s.Require().NoError(err) 772 773 s.Require().Len(archive.Messages, 2) 774 } 775 } 776 777 func (s *ManagerSuite) TestCreateHistoryArchiveTorrentFromMessages_ShouldCreateMultipleArchives() { 778 community, chatID, err := s.buildCommunityWithChat() 779 s.Require().NoError(err) 780 781 topic := types.BytesToTopic(transport.ToTopic(chatID)) 782 topics := []types.TopicType{topic} 783 784 // Time range of 3 weeks 785 startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC) 786 endDate := time.Date(2020, 1, 21, 00, 00, 00, 0, time.UTC) 787 // 7 days partition, this should create three archives 788 partition := 7 * 24 * time.Hour 789 790 message1 := buildMessage(startDate.Add(1*time.Hour), topic, []byte{1}) 791 message2 := buildMessage(startDate.Add(2*time.Hour), topic, []byte{2}) 792 // We expect 2 archives to be created for startDate - endDate of each 793 // 7 days of data. This message should end up in the second archive 794 message3 := buildMessage(startDate.Add(8*24*time.Hour), topic, []byte{3}) 795 // This one should end up in the third archive 796 message4 := buildMessage(startDate.Add(14*24*time.Hour), topic, []byte{4}) 797 798 _, err = s.archiveManager.CreateHistoryArchiveTorrentFromMessages(community.ID(), []*types.Message{&message1, &message2, &message3, &message4}, topics, startDate, endDate, partition, false) 799 s.Require().NoError(err) 800 801 index, err := s.archiveManager.LoadHistoryArchiveIndexFromFile(s.manager.identity, community.ID()) 802 s.Require().NoError(err) 803 s.Require().Len(index.Archives, 3) 804 805 totalData, err := os.ReadFile(s.archiveManager.archiveDataFile(community.IDString())) 806 s.Require().NoError(err) 807 808 // First archive has 2 messages 809 // Second archive has 1 message 810 // Third archive has 1 message 811 fromMap := map[uint64]int{ 812 uint64(startDate.Unix()): 2, 813 uint64(startDate.Add(partition).Unix()): 1, 814 uint64(startDate.Add(partition * 2).Unix()): 1, 815 } 816 817 for _, metadata := range index.Archives { 818 archive := &protobuf.WakuMessageArchive{} 819 data := totalData[metadata.Offset : metadata.Offset+metadata.Size-metadata.Padding] 820 821 err = proto.Unmarshal(data, archive) 822 s.Require().NoError(err) 823 s.Require().Len(archive.Messages, fromMap[metadata.Metadata.From]) 824 } 825 } 826 827 func (s *ManagerSuite) TestCreateHistoryArchiveTorrentFromMessages_ShouldAppendArchives() { 828 community, chatID, err := s.buildCommunityWithChat() 829 s.Require().NoError(err) 830 831 topic := types.BytesToTopic(transport.ToTopic(chatID)) 832 topics := []types.TopicType{topic} 833 834 // Time range of 1 week 835 startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC) 836 endDate := time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC) 837 // 7 days partition, this should create one archive 838 partition := 7 * 24 * time.Hour 839 840 message1 := buildMessage(startDate.Add(1*time.Hour), topic, []byte{1}) 841 842 _, err = s.archiveManager.CreateHistoryArchiveTorrentFromMessages(community.ID(), []*types.Message{&message1}, topics, startDate, endDate, partition, false) 843 s.Require().NoError(err) 844 845 index, err := s.archiveManager.LoadHistoryArchiveIndexFromFile(s.manager.identity, community.ID()) 846 s.Require().NoError(err) 847 s.Require().Len(index.Archives, 1) 848 849 // Time range of next week 850 startDate = time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC) 851 endDate = time.Date(2020, 1, 14, 00, 00, 00, 0, time.UTC) 852 853 message2 := buildMessage(startDate.Add(2*time.Hour), topic, []byte{2}) 854 855 _, err = s.archiveManager.CreateHistoryArchiveTorrentFromMessages(community.ID(), []*types.Message{&message2}, topics, startDate, endDate, partition, false) 856 s.Require().NoError(err) 857 858 index, err = s.archiveManager.LoadHistoryArchiveIndexFromFile(s.manager.identity, community.ID()) 859 s.Require().NoError(err) 860 s.Require().Len(index.Archives, 2) 861 } 862 863 func (s *ManagerSuite) TestSeedHistoryArchiveTorrent() { 864 err := s.archiveManager.StartTorrentClient() 865 s.Require().NoError(err) 866 defer s.archiveManager.Stop() //nolint: errcheck 867 868 community, chatID, err := s.buildCommunityWithChat() 869 s.Require().NoError(err) 870 871 topic := types.BytesToTopic(transport.ToTopic(chatID)) 872 topics := []types.TopicType{topic} 873 874 startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC) 875 endDate := time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC) 876 partition := 7 * 24 * time.Hour 877 878 message1 := buildMessage(startDate.Add(1*time.Hour), topic, []byte{1}) 879 err = s.manager.StoreWakuMessage(&message1) 880 s.Require().NoError(err) 881 882 _, err = s.archiveManager.CreateHistoryArchiveTorrentFromDB(community.ID(), topics, startDate, endDate, partition, false) 883 s.Require().NoError(err) 884 885 err = s.archiveManager.SeedHistoryArchiveTorrent(community.ID()) 886 s.Require().NoError(err) 887 s.Require().Len(s.archiveManager.torrentTasks, 1) 888 889 metaInfoHash := s.archiveManager.torrentTasks[community.IDString()] 890 torrent, ok := s.archiveManager.torrentClient.Torrent(metaInfoHash) 891 defer torrent.Drop() 892 893 s.Require().Equal(ok, true) 894 s.Require().Equal(torrent.Seeding(), true) 895 } 896 897 func (s *ManagerSuite) TestUnseedHistoryArchiveTorrent() { 898 err := s.archiveManager.StartTorrentClient() 899 s.Require().NoError(err) 900 defer s.archiveManager.Stop() //nolint: errcheck 901 902 community, chatID, err := s.buildCommunityWithChat() 903 s.Require().NoError(err) 904 905 topic := types.BytesToTopic(transport.ToTopic(chatID)) 906 topics := []types.TopicType{topic} 907 908 startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC) 909 endDate := time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC) 910 partition := 7 * 24 * time.Hour 911 912 message1 := buildMessage(startDate.Add(1*time.Hour), topic, []byte{1}) 913 err = s.manager.StoreWakuMessage(&message1) 914 s.Require().NoError(err) 915 916 _, err = s.archiveManager.CreateHistoryArchiveTorrentFromDB(community.ID(), topics, startDate, endDate, partition, false) 917 s.Require().NoError(err) 918 919 err = s.archiveManager.SeedHistoryArchiveTorrent(community.ID()) 920 s.Require().NoError(err) 921 s.Require().Len(s.archiveManager.torrentTasks, 1) 922 923 metaInfoHash := s.archiveManager.torrentTasks[community.IDString()] 924 925 s.archiveManager.UnseedHistoryArchiveTorrent(community.ID()) 926 _, ok := s.archiveManager.torrentClient.Torrent(metaInfoHash) 927 s.Require().Equal(ok, false) 928 } 929 930 func (s *ManagerSuite) TestCheckChannelPermissions_NoPermissions() { 931 932 m, _, tm := s.setupManagerForTokenPermissions() 933 934 var chainID uint64 = 5 935 contractAddresses := make(map[uint64]string) 936 contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a" 937 938 accountChainIDsCombination := []*AccountChainIDsCombination{ 939 &AccountChainIDsCombination{ 940 Address: gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"), 941 ChainIDs: []uint64{chainID}, 942 }, 943 } 944 945 var viewOnlyPermissions = make([]*CommunityTokenPermission, 0) 946 var viewAndPostPermissions = make([]*CommunityTokenPermission, 0) 947 viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions) 948 viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions) 949 950 tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0) 951 resp, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false) 952 s.Require().NoError(err) 953 s.Require().NotNil(resp) 954 955 // Both viewOnly and viewAndPost permissions are expected to be satisfied 956 // because we call `checkChannelPermissions()` with no permissions to check 957 s.Require().True(resp.ViewOnlyPermissions.Satisfied) 958 s.Require().True(resp.ViewAndPostPermissions.Satisfied) 959 } 960 961 func (s *ManagerSuite) TestCheckChannelPermissions_ViewOnlyPermissions() { 962 963 m, _, tm := s.setupManagerForTokenPermissions() 964 965 var chainID uint64 = 5 966 contractAddresses := make(map[uint64]string) 967 contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a" 968 var decimals uint64 = 18 969 970 accountChainIDsCombination := []*AccountChainIDsCombination{ 971 &AccountChainIDsCombination{ 972 Address: gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"), 973 ChainIDs: []uint64{chainID}, 974 }, 975 } 976 977 var tokenCriteria = []*protobuf.TokenCriteria{ 978 &protobuf.TokenCriteria{ 979 ContractAddresses: contractAddresses, 980 Symbol: "STT", 981 Type: protobuf.CommunityTokenType_ERC20, 982 Name: "Status Test Token", 983 AmountInWei: "1000000000000000000", 984 Decimals: decimals, 985 }, 986 } 987 988 var viewOnlyPermissions = []*CommunityTokenPermission{ 989 &CommunityTokenPermission{ 990 CommunityTokenPermission: &protobuf.CommunityTokenPermission{ 991 Id: "some-id", 992 Type: protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL, 993 TokenCriteria: tokenCriteria, 994 ChatIds: []string{"test-channel-id", "test-channel-id-2"}, 995 }, 996 }, 997 } 998 999 var viewAndPostPermissions = make([]*CommunityTokenPermission, 0) 1000 1001 viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions) 1002 viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions) 1003 1004 tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0) 1005 resp, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false) 1006 s.Require().NoError(err) 1007 s.Require().NotNil(resp) 1008 1009 s.Require().False(resp.ViewOnlyPermissions.Satisfied) 1010 // if viewOnly permissions are not satisfied then viewAndPost 1011 // permissions shouldn't be satisfied either 1012 s.Require().False(resp.ViewAndPostPermissions.Satisfied) 1013 1014 // Set response to exactly the right one 1015 tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals)))) 1016 resp, err = m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false) 1017 s.Require().NoError(err) 1018 s.Require().NotNil(resp) 1019 1020 s.Require().True(resp.ViewOnlyPermissions.Satisfied) 1021 s.Require().False(resp.ViewAndPostPermissions.Satisfied) 1022 } 1023 1024 func (s *ManagerSuite) TestCheckChannelPermissions_ViewAndPostPermissions() { 1025 1026 m, _, tm := s.setupManagerForTokenPermissions() 1027 1028 var chainID uint64 = 5 1029 contractAddresses := make(map[uint64]string) 1030 contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a" 1031 var decimals uint64 = 18 1032 1033 accountChainIDsCombination := []*AccountChainIDsCombination{ 1034 &AccountChainIDsCombination{ 1035 Address: gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"), 1036 ChainIDs: []uint64{chainID}, 1037 }, 1038 } 1039 1040 var tokenCriteria = []*protobuf.TokenCriteria{ 1041 &protobuf.TokenCriteria{ 1042 ContractAddresses: contractAddresses, 1043 Symbol: "STT", 1044 Type: protobuf.CommunityTokenType_ERC20, 1045 Name: "Status Test Token", 1046 AmountInWei: "1000000000000000000", 1047 Decimals: decimals, 1048 }, 1049 } 1050 1051 var viewAndPostPermissions = []*CommunityTokenPermission{ 1052 &CommunityTokenPermission{ 1053 CommunityTokenPermission: &protobuf.CommunityTokenPermission{ 1054 Id: "some-id", 1055 Type: protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL, 1056 TokenCriteria: tokenCriteria, 1057 ChatIds: []string{"test-channel-id", "test-channel-id-2"}, 1058 }, 1059 }, 1060 } 1061 1062 var viewOnlyPermissions = make([]*CommunityTokenPermission, 0) 1063 1064 viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions) 1065 viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions) 1066 1067 tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0) 1068 resp, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false) 1069 s.Require().NoError(err) 1070 s.Require().NotNil(resp) 1071 1072 s.Require().False(resp.ViewAndPostPermissions.Satisfied) 1073 // viewOnly permissions are flagged as not satisfied because we have no viewOnly 1074 // permissions on this channel and the viewAndPost permission is not satisfied either 1075 s.Require().False(resp.ViewOnlyPermissions.Satisfied) 1076 1077 // Set response to exactly the right one 1078 tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals)))) 1079 resp, err = m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false) 1080 s.Require().NoError(err) 1081 s.Require().NotNil(resp) 1082 1083 s.Require().True(resp.ViewAndPostPermissions.Satisfied) 1084 // if viewAndPost is satisfied then viewOnly should be automatically satisfied 1085 s.Require().True(resp.ViewOnlyPermissions.Satisfied) 1086 } 1087 1088 func (s *ManagerSuite) TestCheckChannelPermissions_ViewAndPostPermissionsCombination() { 1089 1090 m, _, tm := s.setupManagerForTokenPermissions() 1091 1092 var chainID uint64 = 5 1093 contractAddresses := make(map[uint64]string) 1094 contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a" 1095 var decimals uint64 = 18 1096 1097 accountChainIDsCombination := []*AccountChainIDsCombination{ 1098 &AccountChainIDsCombination{ 1099 Address: gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"), 1100 ChainIDs: []uint64{chainID}, 1101 }, 1102 } 1103 1104 var viewOnlyTokenCriteria = []*protobuf.TokenCriteria{ 1105 &protobuf.TokenCriteria{ 1106 ContractAddresses: contractAddresses, 1107 Symbol: "STT", 1108 Type: protobuf.CommunityTokenType_ERC20, 1109 Name: "Status Test Token", 1110 AmountInWei: "1000000000000000000", 1111 Decimals: decimals, 1112 }, 1113 } 1114 1115 var viewOnlyPermissions = []*CommunityTokenPermission{ 1116 &CommunityTokenPermission{ 1117 CommunityTokenPermission: &protobuf.CommunityTokenPermission{ 1118 Id: "some-id", 1119 Type: protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL, 1120 TokenCriteria: viewOnlyTokenCriteria, 1121 ChatIds: []string{"test-channel-id", "test-channel-id-2"}, 1122 }, 1123 }, 1124 } 1125 1126 testContractAddresses := make(map[uint64]string) 1127 testContractAddresses[chainID] = "0x123" 1128 1129 // Set up token criteria that won't be satisfied 1130 var viewAndPostTokenCriteria = []*protobuf.TokenCriteria{ 1131 &protobuf.TokenCriteria{ 1132 ContractAddresses: testContractAddresses, 1133 Symbol: "TEST", 1134 Type: protobuf.CommunityTokenType_ERC20, 1135 Name: "TEST token", 1136 AmountInWei: "1000000000000000000", 1137 Decimals: decimals, 1138 }, 1139 } 1140 1141 var viewAndPostPermissions = []*CommunityTokenPermission{ 1142 &CommunityTokenPermission{ 1143 CommunityTokenPermission: &protobuf.CommunityTokenPermission{ 1144 Id: "some-id", 1145 Type: protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL, 1146 TokenCriteria: viewAndPostTokenCriteria, 1147 ChatIds: []string{"test-channel-id", "test-channel-id-2"}, 1148 }, 1149 }, 1150 } 1151 1152 // Set response for viewOnly permissions 1153 tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals)))) 1154 // Set resopnse for viewAndPost permissions 1155 tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(testContractAddresses[chainID]), 0) 1156 1157 viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions) 1158 viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions) 1159 1160 resp, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false) 1161 s.Require().NoError(err) 1162 s.Require().NotNil(resp) 1163 1164 // viewOnly permission should be satisfied, even though viewAndPost is not satisfied 1165 s.Require().True(resp.ViewOnlyPermissions.Satisfied) 1166 s.Require().False(resp.ViewAndPostPermissions.Satisfied) 1167 } 1168 1169 // Same as the one above, but reversed where the View permission is not satisfied, but the view and post is 1170 func (s *ManagerSuite) TestCheckChannelPermissions_ViewAndPostPermissionsCombination2() { 1171 1172 m, _, tm := s.setupManagerForTokenPermissions() 1173 1174 var chainID uint64 = 5 1175 contractAddresses := make(map[uint64]string) 1176 contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a" 1177 var decimals uint64 = 18 1178 1179 accountChainIDsCombination := []*AccountChainIDsCombination{ 1180 &AccountChainIDsCombination{ 1181 Address: gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"), 1182 ChainIDs: []uint64{chainID}, 1183 }, 1184 } 1185 1186 var viewOnlyTokenCriteria = []*protobuf.TokenCriteria{ 1187 &protobuf.TokenCriteria{ 1188 ContractAddresses: contractAddresses, 1189 Symbol: "STT", 1190 Type: protobuf.CommunityTokenType_ERC20, 1191 Name: "Status Test Token", 1192 AmountInWei: "1000000000000000000", 1193 Decimals: decimals, 1194 }, 1195 } 1196 1197 var viewOnlyPermissions = []*CommunityTokenPermission{ 1198 &CommunityTokenPermission{ 1199 CommunityTokenPermission: &protobuf.CommunityTokenPermission{ 1200 Id: "some-id", 1201 Type: protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL, 1202 TokenCriteria: viewOnlyTokenCriteria, 1203 ChatIds: []string{"test-channel-id", "test-channel-id-2"}, 1204 }, 1205 }, 1206 } 1207 1208 testContractAddresses := make(map[uint64]string) 1209 testContractAddresses[chainID] = "0x123" 1210 1211 // Set up token criteria that won't be satisfied 1212 var viewAndPostTokenCriteria = []*protobuf.TokenCriteria{ 1213 &protobuf.TokenCriteria{ 1214 ContractAddresses: testContractAddresses, 1215 Symbol: "TEST", 1216 Type: protobuf.CommunityTokenType_ERC20, 1217 Name: "TEST token", 1218 AmountInWei: "1000000000000000000", 1219 Decimals: decimals, 1220 }, 1221 } 1222 1223 var viewAndPostPermissions = []*CommunityTokenPermission{ 1224 &CommunityTokenPermission{ 1225 CommunityTokenPermission: &protobuf.CommunityTokenPermission{ 1226 Id: "some-id", 1227 Type: protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL, 1228 TokenCriteria: viewAndPostTokenCriteria, 1229 ChatIds: []string{"test-channel-id", "test-channel-id-2"}, 1230 }, 1231 }, 1232 } 1233 1234 // Set response for viewOnly permissions 1235 tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0) 1236 // Set resopnse for viewAndPost permissions 1237 tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(testContractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals)))) 1238 1239 viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions) 1240 viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions) 1241 1242 resp, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false) 1243 s.Require().NoError(err) 1244 s.Require().NotNil(resp) 1245 1246 // Both permissions should be satisfied, even though view is not satisfied 1247 s.Require().True(resp.ViewOnlyPermissions.Satisfied) 1248 s.Require().True(resp.ViewAndPostPermissions.Satisfied) 1249 } 1250 1251 func (s *ManagerSuite) TestCheckAllChannelsPermissions_EmptyPermissions() { 1252 1253 m, _, _ := s.setupManagerForTokenPermissions() 1254 1255 createRequest := &requests.CreateCommunity{ 1256 Name: "channel permission community", 1257 Description: "some description", 1258 Membership: protobuf.CommunityPermissions_AUTO_ACCEPT, 1259 } 1260 community, err := m.CreateCommunity(createRequest, true) 1261 s.Require().NoError(err) 1262 1263 // create community chats 1264 chat := &protobuf.CommunityChat{ 1265 Identity: &protobuf.ChatIdentity{ 1266 DisplayName: "chat1", 1267 Description: "description", 1268 }, 1269 Permissions: &protobuf.CommunityPermissions{ 1270 Access: protobuf.CommunityPermissions_AUTO_ACCEPT, 1271 }, 1272 Members: make(map[string]*protobuf.CommunityMember), 1273 } 1274 1275 changes, err := m.CreateChat(community.ID(), chat, true, "") 1276 s.Require().NoError(err) 1277 1278 var chatID string 1279 for cid := range changes.ChatsAdded { 1280 chatID = community.IDString() + cid 1281 } 1282 1283 response, err := m.CheckAllChannelsPermissions(community.ID(), []gethcommon.Address{ 1284 gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"), 1285 }) 1286 s.Require().NoError(err) 1287 s.Require().NotNil(response) 1288 1289 s.Require().Len(response.Channels, 1) 1290 // we expect both, viewOnly and viewAndPost permissions to be satisfied 1291 // as there aren't any permissions on this channel 1292 s.Require().True(response.Channels[chatID].ViewOnlyPermissions.Satisfied) 1293 s.Require().True(response.Channels[chatID].ViewAndPostPermissions.Satisfied) 1294 s.Require().Len(response.Channels[chatID].ViewOnlyPermissions.Permissions, 0) 1295 s.Require().Len(response.Channels[chatID].ViewAndPostPermissions.Permissions, 0) 1296 } 1297 1298 func (s *ManagerSuite) TestCheckAllChannelsPermissions() { 1299 1300 m, _, tm := s.setupManagerForTokenPermissions() 1301 1302 var chatID1 string 1303 var chatID2 string 1304 1305 // create community 1306 createRequest := &requests.CreateCommunity{ 1307 Name: "channel permission community", 1308 Description: "some description", 1309 Membership: protobuf.CommunityPermissions_AUTO_ACCEPT, 1310 } 1311 community, err := m.CreateCommunity(createRequest, true) 1312 s.Require().NoError(err) 1313 1314 // create first community chat 1315 chat := &protobuf.CommunityChat{ 1316 Identity: &protobuf.ChatIdentity{ 1317 DisplayName: "chat1", 1318 Description: "description", 1319 }, 1320 Permissions: &protobuf.CommunityPermissions{ 1321 Access: protobuf.CommunityPermissions_AUTO_ACCEPT, 1322 }, 1323 Members: make(map[string]*protobuf.CommunityMember), 1324 } 1325 1326 changes, err := m.CreateChat(community.ID(), chat, true, "") 1327 s.Require().NoError(err) 1328 1329 for chatID := range changes.ChatsAdded { 1330 chatID1 = community.IDString() + chatID 1331 } 1332 1333 // create second community chat 1334 chat = &protobuf.CommunityChat{ 1335 Identity: &protobuf.ChatIdentity{ 1336 DisplayName: "chat2", 1337 Description: "description", 1338 }, 1339 Permissions: &protobuf.CommunityPermissions{ 1340 Access: protobuf.CommunityPermissions_AUTO_ACCEPT, 1341 }, 1342 Members: make(map[string]*protobuf.CommunityMember), 1343 } 1344 1345 changes, err = m.CreateChat(community.ID(), chat, true, "") 1346 s.Require().NoError(err) 1347 1348 for chatID := range changes.ChatsAdded { 1349 chatID2 = community.IDString() + chatID 1350 } 1351 1352 var chainID uint64 = 5 1353 contractAddresses := make(map[uint64]string) 1354 contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a" 1355 var decimals uint64 = 18 1356 1357 accountChainIDsCombination := []*AccountChainIDsCombination{ 1358 &AccountChainIDsCombination{ 1359 Address: gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"), 1360 ChainIDs: []uint64{chainID}, 1361 }, 1362 } 1363 1364 var tokenCriteria = []*protobuf.TokenCriteria{ 1365 &protobuf.TokenCriteria{ 1366 ContractAddresses: contractAddresses, 1367 Symbol: "STT", 1368 Type: protobuf.CommunityTokenType_ERC20, 1369 Name: "Status Test Token", 1370 AmountInWei: "1000000000000000000", 1371 Decimals: decimals, 1372 }, 1373 } 1374 1375 // create view only permission 1376 viewOnlyPermission := &requests.CreateCommunityTokenPermission{ 1377 CommunityID: community.ID(), 1378 Type: protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL, 1379 TokenCriteria: tokenCriteria, 1380 ChatIds: []string{chatID1, chatID2}, 1381 } 1382 1383 _, changes, err = m.CreateCommunityTokenPermission(viewOnlyPermission) 1384 s.Require().NoError(err) 1385 1386 var viewOnlyPermissionID string 1387 for permissionID := range changes.TokenPermissionsAdded { 1388 viewOnlyPermissionID = permissionID 1389 } 1390 1391 response, err := m.CheckAllChannelsPermissions(community.ID(), []gethcommon.Address{ 1392 gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"), 1393 }) 1394 s.Require().NoError(err) 1395 s.Require().NotNil(response) 1396 1397 // we've added to chats to the community, so there should be 2 items 1398 s.Require().Len(response.Channels, 2) 1399 1400 // viewOnly permissions should not be satisfied because the account doesn't 1401 // have the necessary funds 1402 1403 // channel1 1404 s.Require().False(response.Channels[chatID1].ViewOnlyPermissions.Satisfied) 1405 s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions, 1) 1406 s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria, 1) 1407 s.Require().False(response.Channels[chatID1].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria[0]) 1408 1409 // channel2 1410 s.Require().False(response.Channels[chatID2].ViewOnlyPermissions.Satisfied) 1411 s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions, 1) 1412 s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria, 1) 1413 s.Require().False(response.Channels[chatID2].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria[0]) 1414 1415 // viewAndPost permissions are flagged as not satisfied either because 1416 // viewOnly permission is not satisfied and there are no viewAndPost permissions 1417 1418 // channel1 1419 s.Require().False(response.Channels[chatID1].ViewAndPostPermissions.Satisfied) 1420 s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions, 0) 1421 1422 // channel2 1423 s.Require().False(response.Channels[chatID2].ViewAndPostPermissions.Satisfied) 1424 s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions, 0) 1425 1426 // now change balance such that viewOnly permission should be satisfied 1427 tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals)))) 1428 1429 response, err = m.CheckAllChannelsPermissions(community.ID(), []gethcommon.Address{ 1430 gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"), 1431 }) 1432 s.Require().NoError(err) 1433 s.Require().NotNil(response) 1434 s.Require().Len(response.Channels, 2) 1435 1436 // viewOnly permissions should be satisfied for both channels while 1437 // viewAndPost permissions should not be satisfied (as there aren't any) 1438 1439 // channel1 1440 s.Require().True(response.Channels[chatID1].ViewOnlyPermissions.Satisfied) 1441 s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions, 1) 1442 s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria, 1) 1443 s.Require().True(response.Channels[chatID1].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria[0]) 1444 1445 s.Require().False(response.Channels[chatID1].ViewAndPostPermissions.Satisfied) 1446 s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions, 0) 1447 1448 // channel2 1449 s.Require().True(response.Channels[chatID2].ViewOnlyPermissions.Satisfied) 1450 s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions, 1) 1451 s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria, 1) 1452 s.Require().True(response.Channels[chatID2].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria[0]) 1453 1454 s.Require().False(response.Channels[chatID2].ViewAndPostPermissions.Satisfied) 1455 s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions, 0) 1456 1457 // next, create viewAndPost permission 1458 // create view only permission 1459 viewAndPostPermission := &requests.CreateCommunityTokenPermission{ 1460 CommunityID: community.ID(), 1461 Type: protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL, 1462 TokenCriteria: tokenCriteria, 1463 ChatIds: []string{chatID1, chatID2}, 1464 } 1465 1466 _, changes, err = m.CreateCommunityTokenPermission(viewAndPostPermission) 1467 s.Require().NoError(err) 1468 1469 var viewAndPostPermissionID string 1470 for permissionID := range changes.TokenPermissionsAdded { 1471 viewAndPostPermissionID = permissionID 1472 } 1473 1474 // now change balance such that viewAndPost permission is not satisfied 1475 tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0) 1476 1477 response, err = m.CheckAllChannelsPermissions(community.ID(), []gethcommon.Address{ 1478 gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"), 1479 }) 1480 s.Require().NoError(err) 1481 s.Require().NotNil(response) 1482 s.Require().Len(response.Channels, 2) 1483 1484 // Both, viewOnly and viewAndPost permissions exist on channel1 and channel2 1485 // but shouldn't be satisfied 1486 1487 // channel1 1488 s.Require().False(response.Channels[chatID1].ViewOnlyPermissions.Satisfied) 1489 s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions, 1) 1490 s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria, 1) 1491 s.Require().False(response.Channels[chatID1].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria[0]) 1492 1493 s.Require().False(response.Channels[chatID1].ViewAndPostPermissions.Satisfied) 1494 s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions, 1) 1495 s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria, 1) 1496 s.Require().False(response.Channels[chatID1].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria[0]) 1497 1498 // channel2 1499 s.Require().False(response.Channels[chatID2].ViewOnlyPermissions.Satisfied) 1500 s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions, 1) 1501 s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria, 1) 1502 s.Require().False(response.Channels[chatID2].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria[0]) 1503 1504 s.Require().False(response.Channels[chatID2].ViewAndPostPermissions.Satisfied) 1505 s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions, 1) 1506 s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria, 1) 1507 s.Require().False(response.Channels[chatID2].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria[0]) 1508 1509 // now change balance such that both, viewOnly and viewAndPost permission, are satisfied 1510 tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals)))) 1511 1512 response, err = m.CheckAllChannelsPermissions(community.ID(), []gethcommon.Address{ 1513 gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"), 1514 }) 1515 s.Require().NoError(err) 1516 s.Require().NotNil(response) 1517 s.Require().Len(response.Channels, 2) 1518 1519 // Both, viewOnly and viewAndPost permissions exist on channel1 and channel2 1520 // and are satisfied 1521 1522 // channel1 1523 s.Require().True(response.Channels[chatID1].ViewOnlyPermissions.Satisfied) 1524 s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions, 1) 1525 s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria, 1) 1526 s.Require().True(response.Channels[chatID1].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria[0]) 1527 1528 s.Require().True(response.Channels[chatID1].ViewAndPostPermissions.Satisfied) 1529 s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions, 1) 1530 s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria, 1) 1531 s.Require().True(response.Channels[chatID1].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria[0]) 1532 1533 // channel2 1534 s.Require().True(response.Channels[chatID2].ViewOnlyPermissions.Satisfied) 1535 s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions, 1) 1536 s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria, 1) 1537 s.Require().True(response.Channels[chatID2].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria[0]) 1538 1539 s.Require().True(response.Channels[chatID2].ViewAndPostPermissions.Satisfied) 1540 s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions, 1) 1541 s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria, 1) 1542 s.Require().True(response.Channels[chatID2].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria[0]) 1543 1544 // next, delete viewOnly permission so we can check the viewAndPost permission-only case 1545 deleteViewOnlyPermission := &requests.DeleteCommunityTokenPermission{ 1546 CommunityID: community.ID(), 1547 PermissionID: viewOnlyPermissionID, 1548 } 1549 _, _, err = m.DeleteCommunityTokenPermission(deleteViewOnlyPermission) 1550 s.Require().NoError(err) 1551 1552 response, err = m.CheckAllChannelsPermissions(community.ID(), []gethcommon.Address{ 1553 gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"), 1554 }) 1555 s.Require().NoError(err) 1556 s.Require().NotNil(response) 1557 s.Require().Len(response.Channels, 2) 1558 1559 // Both, channel1 and channel2 now have viewAndPost only permissions that should 1560 // be satisfied, there's no viewOnly permission anymore the response should mark it 1561 // as satisfied as well 1562 1563 // channel1 1564 s.Require().True(response.Channels[chatID1].ViewAndPostPermissions.Satisfied) 1565 s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions, 1) 1566 s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria, 1) 1567 s.Require().True(response.Channels[chatID1].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria[0]) 1568 1569 s.Require().True(response.Channels[chatID1].ViewOnlyPermissions.Satisfied) 1570 s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions, 0) 1571 1572 // channel2 1573 s.Require().True(response.Channels[chatID2].ViewAndPostPermissions.Satisfied) 1574 s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions, 1) 1575 s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria, 1) 1576 s.Require().True(response.Channels[chatID2].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria[0]) 1577 1578 s.Require().True(response.Channels[chatID2].ViewOnlyPermissions.Satisfied) 1579 s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions, 0) 1580 1581 // now change balance such that viewAndPost permission is no longer satisfied 1582 tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0) 1583 1584 response, err = m.CheckAllChannelsPermissions(community.ID(), []gethcommon.Address{ 1585 gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"), 1586 }) 1587 s.Require().NoError(err) 1588 s.Require().NotNil(response) 1589 s.Require().Len(response.Channels, 2) 1590 1591 // because viewAndPost permission is not satisfied and there are no viewOnly permissions 1592 // on the channels, the response should mark the viewOnly permissions as not satisfied as well 1593 1594 // channel1 1595 s.Require().False(response.Channels[chatID1].ViewAndPostPermissions.Satisfied) 1596 s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions, 1) 1597 s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria, 1) 1598 s.Require().False(response.Channels[chatID1].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria[0]) 1599 1600 s.Require().False(response.Channels[chatID1].ViewOnlyPermissions.Satisfied) 1601 s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions, 0) 1602 1603 // channel2 1604 s.Require().False(response.Channels[chatID2].ViewAndPostPermissions.Satisfied) 1605 s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions, 1) 1606 s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria, 1) 1607 s.Require().False(response.Channels[chatID2].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria[0]) 1608 1609 s.Require().False(response.Channels[chatID2].ViewOnlyPermissions.Satisfied) 1610 s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions, 0) 1611 } 1612 1613 func buildTorrentConfig() *params.TorrentConfig { 1614 return ¶ms.TorrentConfig{ 1615 Enabled: true, 1616 DataDir: os.TempDir() + "/archivedata", 1617 TorrentDir: os.TempDir() + "/torrents", 1618 Port: 0, 1619 } 1620 } 1621 1622 func buildMessage(timestamp time.Time, topic types.TopicType, hash []byte) types.Message { 1623 message := types.Message{ 1624 Sig: []byte{1}, 1625 Timestamp: uint32(timestamp.Unix()), 1626 Topic: topic, 1627 Payload: []byte{1}, 1628 Padding: []byte{1}, 1629 Hash: hash, 1630 } 1631 return message 1632 } 1633 1634 func (s *ManagerSuite) buildCommunityWithChat() (*Community, string, error) { 1635 createRequest := &requests.CreateCommunity{ 1636 Name: "status", 1637 Description: "status community description", 1638 Membership: protobuf.CommunityPermissions_AUTO_ACCEPT, 1639 } 1640 community, err := s.manager.CreateCommunity(createRequest, true) 1641 if err != nil { 1642 return nil, "", err 1643 } 1644 chat := &protobuf.CommunityChat{ 1645 Identity: &protobuf.ChatIdentity{ 1646 DisplayName: "added-chat", 1647 Description: "description", 1648 }, 1649 Permissions: &protobuf.CommunityPermissions{ 1650 Access: protobuf.CommunityPermissions_AUTO_ACCEPT, 1651 }, 1652 Members: make(map[string]*protobuf.CommunityMember), 1653 } 1654 changes, err := s.manager.CreateChat(community.ID(), chat, true, "") 1655 if err != nil { 1656 return nil, "", err 1657 } 1658 1659 chatID := "" 1660 for cID := range changes.ChatsAdded { 1661 chatID = cID 1662 break 1663 } 1664 return community, chatID, nil 1665 } 1666 1667 type testOwnerVerifier struct { 1668 called int 1669 ownersMap map[string]string 1670 } 1671 1672 func (t *testOwnerVerifier) SafeGetSignerPubKey(ctx context.Context, chainID uint64, communityID string) (string, error) { 1673 t.called++ 1674 return t.ownersMap[communityID], nil 1675 } 1676 1677 func (s *ManagerSuite) TestCommunityQueue() { 1678 1679 owner, err := crypto.GenerateKey() 1680 s.Require().NoError(err) 1681 1682 verifier := &testOwnerVerifier{} 1683 m, _ := s.buildManagers(verifier) 1684 1685 createRequest := &requests.CreateCommunity{ 1686 Name: "status", 1687 Description: "status community description", 1688 Membership: protobuf.CommunityPermissions_AUTO_ACCEPT, 1689 } 1690 community, err := s.manager.CreateCommunity(createRequest, true) 1691 s.Require().NoError(err) 1692 1693 // set verifier public key 1694 verifier.ownersMap = make(map[string]string) 1695 verifier.ownersMap[community.IDString()] = common.PubkeyToHex(&owner.PublicKey) 1696 1697 description := community.config.CommunityDescription 1698 1699 // safety check 1700 s.Require().Equal(uint64(0), CommunityDescriptionTokenOwnerChainID(description)) 1701 1702 // set up permissions 1703 description.TokenPermissions = make(map[string]*protobuf.CommunityTokenPermission) 1704 description.TokenPermissions["some-id"] = &protobuf.CommunityTokenPermission{ 1705 Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER, 1706 Id: "some-token-id", 1707 TokenCriteria: []*protobuf.TokenCriteria{ 1708 &protobuf.TokenCriteria{ 1709 ContractAddresses: map[uint64]string{ 1710 2: "some-address", 1711 }, 1712 }, 1713 }} 1714 1715 // Should have now a token owner 1716 s.Require().Equal(uint64(2), CommunityDescriptionTokenOwnerChainID(description)) 1717 1718 payload, err := community.MarshaledDescription() 1719 s.Require().NoError(err) 1720 1721 payload, err = v1.WrapMessageV1(payload, protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION, owner) 1722 s.Require().NoError(err) 1723 1724 // Create a signer, that is not the owner 1725 notTheOwner, err := crypto.GenerateKey() 1726 s.Require().NoError(err) 1727 1728 subscription := m.Subscribe() 1729 1730 response, err := m.HandleCommunityDescriptionMessage(¬TheOwner.PublicKey, description, payload, nil, nil) 1731 s.Require().NoError(err) 1732 1733 // No response, as it should be queued 1734 s.Require().Nil(response) 1735 1736 published := false 1737 1738 for !published { 1739 select { 1740 case event := <-subscription: 1741 if event.TokenCommunityValidated == nil { 1742 continue 1743 } 1744 published = true 1745 case <-time.After(2 * time.Second): 1746 s.FailNow("no subscription") 1747 } 1748 } 1749 1750 // Check it's not called multiple times 1751 s.Require().Equal(1, verifier.called) 1752 // Cleans up the communities to validate 1753 communitiesToValidate, err := m.persistence.getCommunitiesToValidate() 1754 s.Require().NoError(err) 1755 s.Require().Empty(communitiesToValidate) 1756 } 1757 1758 // 1) We create a community 1759 // 2) We have 2 owners, but only new owner is returned by the contract 1760 // 3) We receive the old owner community first 1761 // 4) We receive the new owner community second 1762 // 5) We start the queue 1763 // 6) We should only process 4, and ignore anything else if that is successful, as that's the most recent 1764 1765 func (s *ManagerSuite) TestCommunityQueueMultipleDifferentSigners() { 1766 1767 newOwner, err := crypto.GenerateKey() 1768 s.Require().NoError(err) 1769 1770 oldOwner, err := crypto.GenerateKey() 1771 s.Require().NoError(err) 1772 1773 verifier := &testOwnerVerifier{} 1774 m, _ := s.buildManagers(verifier) 1775 1776 createRequest := &requests.CreateCommunity{ 1777 Name: "status", 1778 Description: "status community description", 1779 Membership: protobuf.CommunityPermissions_AUTO_ACCEPT, 1780 } 1781 community, err := s.manager.CreateCommunity(createRequest, true) 1782 s.Require().NoError(err) 1783 1784 // set verifier public key 1785 verifier.ownersMap = make(map[string]string) 1786 verifier.ownersMap[community.IDString()] = common.PubkeyToHex(&newOwner.PublicKey) 1787 1788 description := community.config.CommunityDescription 1789 1790 // safety check 1791 s.Require().Equal(uint64(0), CommunityDescriptionTokenOwnerChainID(description)) 1792 1793 // set up permissions 1794 description.TokenPermissions = make(map[string]*protobuf.CommunityTokenPermission) 1795 description.TokenPermissions["some-id"] = &protobuf.CommunityTokenPermission{ 1796 Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER, 1797 Id: "some-token-id", 1798 TokenCriteria: []*protobuf.TokenCriteria{ 1799 &protobuf.TokenCriteria{ 1800 ContractAddresses: map[uint64]string{ 1801 2: "some-address", 1802 }, 1803 }, 1804 }} 1805 1806 // Should have now a token owner 1807 s.Require().Equal(uint64(2), CommunityDescriptionTokenOwnerChainID(description)) 1808 1809 // We nil owner verifier so that messages won't be processed 1810 m.ownerVerifier = nil 1811 1812 // Send message from old owner first 1813 1814 payload, err := community.MarshaledDescription() 1815 s.Require().NoError(err) 1816 1817 payload, err = v1.WrapMessageV1(payload, protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION, oldOwner) 1818 s.Require().NoError(err) 1819 1820 subscription := m.Subscribe() 1821 1822 response, err := m.HandleCommunityDescriptionMessage(&oldOwner.PublicKey, description, payload, nil, nil) 1823 s.Require().NoError(err) 1824 1825 // No response, as it should be queued 1826 s.Require().Nil(response) 1827 1828 // Send message from new owner now 1829 1830 community.config.CommunityDescription.Clock++ 1831 1832 clock2 := community.config.CommunityDescription.Clock 1833 1834 payload, err = community.MarshaledDescription() 1835 s.Require().NoError(err) 1836 1837 payload, err = v1.WrapMessageV1(payload, protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION, newOwner) 1838 s.Require().NoError(err) 1839 1840 response, err = m.HandleCommunityDescriptionMessage(&newOwner.PublicKey, description, payload, nil, nil) 1841 s.Require().NoError(err) 1842 1843 // No response, as it should be queued 1844 s.Require().Nil(response) 1845 1846 count, err := m.persistence.getCommunitiesToValidateCount() 1847 s.Require().NoError(err) 1848 s.Require().Equal(2, count) 1849 1850 communitiesToValidate, err := m.persistence.getCommunitiesToValidate() 1851 s.Require().NoError(err) 1852 s.Require().NotNil(communitiesToValidate) 1853 s.Require().NotNil(communitiesToValidate[community.IDString()]) 1854 s.Require().Len(communitiesToValidate[community.IDString()], 2) 1855 1856 // We set owner verifier so that we start processing the queue 1857 m.ownerVerifier = verifier 1858 1859 published := false 1860 1861 for !published { 1862 select { 1863 case event := <-subscription: 1864 if event.TokenCommunityValidated == nil { 1865 continue 1866 } 1867 published = true 1868 case <-time.After(2 * time.Second): 1869 s.FailNow("no subscription") 1870 } 1871 } 1872 1873 // Check it's not called multiple times, since we should be checking newest first 1874 s.Require().Equal(1, verifier.called) 1875 // Cleans up the communities to validate 1876 communitiesToValidate, err = m.persistence.getCommunitiesToValidate() 1877 s.Require().NoError(err) 1878 s.Require().Empty(communitiesToValidate) 1879 1880 // Check clock of community is of the last community description 1881 fetchedCommunity, err := m.GetByID(community.ID()) 1882 s.Require().NoError(err) 1883 s.Require().Equal(clock2, fetchedCommunity.config.CommunityDescription.Clock) 1884 1885 } 1886 1887 // 1) We create a community 1888 // 2) We have 2 owners, but only old owner is returned by the contract 1889 // 3) We receive the old owner community first 1890 // 4) We receive the new owner community second (that could be a malicious user) 1891 // 5) We start the queue 1892 // 6) We should process both, but ignore the last community description 1893 1894 func (s *ManagerSuite) TestCommunityQueueMultipleDifferentSignersIgnoreIfNotReturned() { 1895 1896 newOwner, err := crypto.GenerateKey() 1897 s.Require().NoError(err) 1898 1899 oldOwner, err := crypto.GenerateKey() 1900 s.Require().NoError(err) 1901 1902 verifier := &testOwnerVerifier{} 1903 m, _ := s.buildManagers(verifier) 1904 1905 createRequest := &requests.CreateCommunity{ 1906 Name: "status", 1907 Description: "status community description", 1908 Membership: protobuf.CommunityPermissions_AUTO_ACCEPT, 1909 } 1910 community, err := s.manager.CreateCommunity(createRequest, true) 1911 s.Require().NoError(err) 1912 1913 // set verifier public key 1914 verifier.ownersMap = make(map[string]string) 1915 verifier.ownersMap[community.IDString()] = common.PubkeyToHex(&oldOwner.PublicKey) 1916 1917 description := community.config.CommunityDescription 1918 1919 // safety check 1920 s.Require().Equal(uint64(0), CommunityDescriptionTokenOwnerChainID(description)) 1921 1922 // set up permissions 1923 description.TokenPermissions = make(map[string]*protobuf.CommunityTokenPermission) 1924 description.TokenPermissions["some-id"] = &protobuf.CommunityTokenPermission{ 1925 Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER, 1926 Id: "some-token-id", 1927 TokenCriteria: []*protobuf.TokenCriteria{ 1928 &protobuf.TokenCriteria{ 1929 ContractAddresses: map[uint64]string{ 1930 2: "some-address", 1931 }, 1932 }, 1933 }} 1934 1935 // Should have now a token owner 1936 s.Require().Equal(uint64(2), CommunityDescriptionTokenOwnerChainID(description)) 1937 1938 // We nil owner verifier so that messages won't be processed 1939 m.ownerVerifier = nil 1940 1941 clock1 := community.config.CommunityDescription.Clock 1942 // Send message from old owner first 1943 1944 payload, err := community.MarshaledDescription() 1945 s.Require().NoError(err) 1946 1947 payload, err = v1.WrapMessageV1(payload, protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION, oldOwner) 1948 s.Require().NoError(err) 1949 1950 subscription := m.Subscribe() 1951 1952 response, err := m.HandleCommunityDescriptionMessage(&oldOwner.PublicKey, description, payload, nil, nil) 1953 s.Require().NoError(err) 1954 1955 // No response, as it should be queued 1956 s.Require().Nil(response) 1957 1958 // Send message from new owner now 1959 1960 community.config.CommunityDescription.Clock++ 1961 1962 payload, err = community.MarshaledDescription() 1963 s.Require().NoError(err) 1964 1965 payload, err = v1.WrapMessageV1(payload, protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION, newOwner) 1966 s.Require().NoError(err) 1967 1968 response, err = m.HandleCommunityDescriptionMessage(&newOwner.PublicKey, description, payload, nil, nil) 1969 s.Require().NoError(err) 1970 1971 // No response, as it should be queued 1972 s.Require().Nil(response) 1973 1974 count, err := m.persistence.getCommunitiesToValidateCount() 1975 s.Require().NoError(err) 1976 s.Require().Equal(2, count) 1977 1978 communitiesToValidate, err := m.persistence.getCommunitiesToValidate() 1979 s.Require().NoError(err) 1980 s.Require().NotNil(communitiesToValidate) 1981 s.Require().NotNil(communitiesToValidate[community.IDString()]) 1982 s.Require().Len(communitiesToValidate[community.IDString()], 2) 1983 1984 // We set owner verifier so that we start processing the queue 1985 m.ownerVerifier = verifier 1986 1987 published := false 1988 1989 for !published { 1990 select { 1991 case event := <-subscription: 1992 if event.TokenCommunityValidated == nil { 1993 continue 1994 } 1995 published = true 1996 case <-time.After(2 * time.Second): 1997 s.FailNow("no subscription") 1998 } 1999 } 2000 2001 // Check it's not called multiple times, since we should be checking newest first 2002 s.Require().Equal(2, verifier.called) 2003 // Cleans up the communities to validate 2004 communitiesToValidate, err = m.persistence.getCommunitiesToValidate() 2005 s.Require().NoError(err) 2006 s.Require().Empty(communitiesToValidate) 2007 2008 // Check clock of community is of the first community description 2009 fetchedCommunity, err := m.GetByID(community.ID()) 2010 s.Require().NoError(err) 2011 s.Require().Equal(clock1, fetchedCommunity.config.CommunityDescription.Clock) 2012 } 2013 2014 func (s *ManagerSuite) TestFillMissingCommunityTokens() { 2015 // Create community 2016 request := &requests.CreateCommunity{ 2017 Name: "status", 2018 Description: "token membership description", 2019 Membership: protobuf.CommunityPermissions_AUTO_ACCEPT, 2020 } 2021 2022 community, err := s.manager.CreateCommunity(request, true) 2023 s.Require().NoError(err) 2024 s.Require().NotNil(community) 2025 s.Require().Len(community.CommunityTokensMetadata(), 0) 2026 2027 // Create community token but without adding to the description 2028 token := community_token.CommunityToken{ 2029 TokenType: protobuf.CommunityTokenType_ERC721, 2030 CommunityID: community.IDString(), 2031 Address: "0x001", 2032 Name: "TestTok", 2033 Symbol: "TST", 2034 Description: "Desc", 2035 Supply: &bigint.BigInt{Int: big.NewInt(0)}, 2036 InfiniteSupply: true, 2037 Transferable: true, 2038 RemoteSelfDestruct: true, 2039 ChainID: 1, 2040 DeployState: community_token.Deployed, 2041 Base64Image: "", 2042 Decimals: 18, 2043 Deployer: "0x0002", 2044 PrivilegesLevel: community_token.CommunityLevel, 2045 } 2046 2047 err = s.manager.persistence.AddCommunityToken(&token) 2048 s.Require().NoError(err) 2049 2050 // Fill community with missing token 2051 err = s.manager.fillMissingCommunityTokens() 2052 s.Require().NoError(err) 2053 2054 community, err = s.manager.GetByID(community.ID()) 2055 s.Require().NoError(err) 2056 s.Require().Len(community.CommunityTokensMetadata(), 1) 2057 } 2058 2059 func (s *ManagerSuite) TestDetermineChannelsForHRKeysRequest() { 2060 request := &requests.CreateCommunity{ 2061 Name: "status", 2062 Description: "token membership description", 2063 Membership: protobuf.CommunityPermissions_AUTO_ACCEPT, 2064 } 2065 2066 community, err := s.manager.CreateCommunity(request, true) 2067 s.Require().NoError(err) 2068 s.Require().NotNil(community) 2069 2070 channel := &protobuf.CommunityChat{ 2071 Members: map[string]*protobuf.CommunityMember{ 2072 common.PubkeyToHex(&s.manager.identity.PublicKey): {}, 2073 }, 2074 } 2075 2076 description := community.config.CommunityDescription 2077 description.Chats = map[string]*protobuf.CommunityChat{} 2078 description.Chats["channel-id"] = channel 2079 2080 // Simulate channel encrypted 2081 _, err = community.UpsertTokenPermission(&protobuf.CommunityTokenPermission{ 2082 ChatIds: []string{ChatID(community.IDString(), "channel-id")}, 2083 }) 2084 s.Require().NoError(err) 2085 2086 err = generateBloomFiltersForChannels(description, s.manager.identity) 2087 s.Require().NoError(err) 2088 2089 now := int64(1) 2090 tenMinutes := int64(10 * 60 * 1000) 2091 2092 // Member does not have missing encryption keys 2093 channels, err := s.manager.determineChannelsForHRKeysRequest(community, now) 2094 s.Require().NoError(err) 2095 s.Require().Empty(channels) 2096 2097 // Simulate missing encryption key 2098 channel.Members = map[string]*protobuf.CommunityMember{} 2099 2100 // Channel without prior request should be returned 2101 channels, err = s.manager.determineChannelsForHRKeysRequest(community, now) 2102 s.Require().NoError(err) 2103 s.Require().Len(channels, 1) 2104 s.Require().Equal("channel-id", channels[0]) 2105 2106 // Simulate encryption keys request 2107 err = s.manager.updateEncryptionKeysRequests(community.ID(), []string{"channel-id"}, now) 2108 s.Require().NoError(err) 2109 2110 // Channel with prior request should not be returned before backoff interval 2111 channels, err = s.manager.determineChannelsForHRKeysRequest(community, now) 2112 s.Require().NoError(err) 2113 s.Require().Len(channels, 0) 2114 2115 // Channel with prior request should be returned only after backoff interval 2116 channels, err = s.manager.determineChannelsForHRKeysRequest(community, now+tenMinutes) 2117 s.Require().NoError(err) 2118 s.Require().Len(channels, 1) 2119 s.Require().Equal("channel-id", channels[0]) 2120 2121 // Simulate multiple encryption keys request 2122 err = s.manager.updateEncryptionKeysRequests(community.ID(), []string{"channel-id"}, now+tenMinutes) 2123 s.Require().NoError(err) 2124 err = s.manager.updateEncryptionKeysRequests(community.ID(), []string{"channel-id"}, now+2*tenMinutes) 2125 s.Require().NoError(err) 2126 2127 // Channel with prior request should not be returned before backoff interval 2128 channels, err = s.manager.determineChannelsForHRKeysRequest(community, now+2*tenMinutes) 2129 s.Require().NoError(err) 2130 s.Require().Len(channels, 0) 2131 2132 // Channel with prior request should be returned only after backoff interval 2133 channels, err = s.manager.determineChannelsForHRKeysRequest(community, now+6*tenMinutes) 2134 s.Require().NoError(err) 2135 s.Require().Len(channels, 1) 2136 s.Require().Equal("channel-id", channels[0]) 2137 2138 // Simulate encryption key being received (it will remove request for given channel) 2139 err = s.manager.updateEncryptionKeysRequests(community.ID(), []string{}, now) 2140 s.Require().NoError(err) 2141 2142 // Channel without prior request should be returned 2143 channels, err = s.manager.determineChannelsForHRKeysRequest(community, now) 2144 s.Require().NoError(err) 2145 s.Require().Len(channels, 1) 2146 s.Require().Equal("channel-id", channels[0]) 2147 }