diff --git a/protocol/communities_messenger_test.go b/protocol/communities_messenger_test.go index d2336e9b3..8e4222a60 100644 --- a/protocol/communities_messenger_test.go +++ b/protocol/communities_messenger_test.go @@ -3453,111 +3453,111 @@ func (s *MessengerCommunitiesSuite) TestStartCommunityRekeyLoop() { } } -// func (s *MessengerCommunitiesSuite) TestCommunityRekeyAfterBan() { -// s.owner.communitiesManager.RekeyInterval = 500 * time.Minute +func (s *MessengerCommunitiesSuite) TestCommunityRekeyAfterBan() { + s.owner.communitiesManager.RekeyInterval = 500 * time.Minute -// _, err := s.owner.Start() -// s.Require().NoError(err) + _, err := s.owner.Start() + s.Require().NoError(err) -// // Create a new community -// response, err := s.owner.CreateCommunity( -// &requests.CreateCommunity{ -// Membership: protobuf.CommunityPermissions_AUTO_ACCEPT, -// Name: "status", -// Color: "#57a7e5", -// Description: "status community description", -// }, -// true, -// ) -// s.Require().NoError(err) -// s.Require().NotNil(response) -// s.Require().Len(response.Communities(), 1) -// s.Require().Len(response.Communities()[0].Members(), 1) + // Create a new community + response, err := s.owner.CreateCommunity( + &requests.CreateCommunity{ + Membership: protobuf.CommunityPermissions_AUTO_ACCEPT, + Name: "status", + Color: "#57a7e5", + Description: "status community description", + }, + true, + ) + s.Require().NoError(err) + s.Require().NotNil(response) + s.Require().Len(response.Communities(), 1) + s.Require().Len(response.Communities()[0].Members(), 1) -// // Check community is present in the DB and has default values we care about -// c, err := s.owner.GetCommunityByID(response.Communities()[0].ID()) -// s.Require().NoError(err) -// s.Require().False(c.Encrypted()) -// // TODO some check that there are no keys for the community. Alt for s.Require().Zero(c.RekeyedAt().Unix()) + // Check community is present in the DB and has default values we care about + c, err := s.owner.GetCommunityByID(response.Communities()[0].ID()) + s.Require().NoError(err) + s.Require().False(c.Encrypted()) + // TODO some check that there are no keys for the community. Alt for s.Require().Zero(c.RekeyedAt().Unix()) -// _, err = s.owner.CreateCommunityTokenPermission(&requests.CreateCommunityTokenPermission{ -// CommunityID: c.ID(), -// Type: protobuf.CommunityTokenPermission_BECOME_MEMBER, -// TokenCriteria: []*protobuf.TokenCriteria{{ -// ContractAddresses: map[uint64]string{3: "0x933"}, -// Type: protobuf.CommunityTokenType_ERC20, -// Symbol: "STT", -// Name: "Status Test Token", -// Amount: "10", -// Decimals: 18, -// }}, -// }) -// s.Require().NoError(err) + _, err = s.owner.CreateCommunityTokenPermission(&requests.CreateCommunityTokenPermission{ + CommunityID: c.ID(), + Type: protobuf.CommunityTokenPermission_BECOME_MEMBER, + TokenCriteria: []*protobuf.TokenCriteria{{ + ContractAddresses: map[uint64]string{3: "0x933"}, + Type: protobuf.CommunityTokenType_ERC20, + Symbol: "STT", + Name: "Status Test Token", + Amount: "10", + Decimals: 18, + }}, + }) + s.Require().NoError(err) -// c, err = s.owner.GetCommunityByID(c.ID()) -// s.Require().NoError(err) -// s.Require().True(c.Encrypted()) + c, err = s.owner.GetCommunityByID(c.ID()) + s.Require().NoError(err) + s.Require().True(c.Encrypted()) -// s.advertiseCommunityTo(c, s.owner, s.bob) -// s.advertiseCommunityTo(c, s.owner, s.alice) + s.advertiseCommunityTo(c, s.owner, s.bob) + s.advertiseCommunityTo(c, s.owner, s.alice) -// s.owner.communitiesManager.PermissionChecker = &testPermissionChecker{} + s.owner.communitiesManager.PermissionChecker = &testPermissionChecker{} -// s.joinCommunity(c, s.owner, s.bob) -// s.joinCommunity(c, s.owner, s.alice) + s.joinCommunity(c, s.owner, s.bob) + s.joinCommunity(c, s.owner, s.alice) -// // Check the Alice and Bob are members of the community -// c, err = s.owner.GetCommunityByID(c.ID()) -// s.Require().NoError(err) -// s.Require().True(c.HasMember(&s.alice.identity.PublicKey)) -// s.Require().True(c.HasMember(&s.bob.identity.PublicKey)) + // Check the Alice and Bob are members of the community + c, err = s.owner.GetCommunityByID(c.ID()) + s.Require().NoError(err) + s.Require().True(c.HasMember(&s.alice.identity.PublicKey)) + s.Require().True(c.HasMember(&s.bob.identity.PublicKey)) -// // Make sure at least one key makes it to alice -// response, err = WaitOnMessengerResponse(s.alice, -// func(r *MessengerResponse) bool { -// keys, err := s.alice.encryptor.GetKeysForGroup(response.Communities()[0].ID()) -// if err != nil || len(keys) != 1 { -// return false -// } -// return true + // Make sure at least one key makes it to alice + response, err = WaitOnMessengerResponse(s.alice, + func(r *MessengerResponse) bool { + keys, err := s.alice.encryptor.GetKeysForGroup(response.Communities()[0].ID()) + if err != nil || len(keys) != 1 { + return false + } + return true -// }, -// "alice does not have enough keys", -// ) -// s.Require().NoError(err) + }, + "alice does not have enough keys", + ) + s.Require().NoError(err) -// response, err = s.owner.BanUserFromCommunity(context.Background(), &requests.BanUserFromCommunity{ -// CommunityID: c.ID(), -// User: common.PubkeyToHexBytes(&s.bob.identity.PublicKey), -// }) -// s.Require().NoError(err) -// s.Require().Len(response.Communities(), 1) + response, err = s.owner.BanUserFromCommunity(context.Background(), &requests.BanUserFromCommunity{ + CommunityID: c.ID(), + User: common.PubkeyToHexBytes(&s.bob.identity.PublicKey), + }) + s.Require().NoError(err) + s.Require().Len(response.Communities(), 1) -// s.Require().False(response.Communities()[0].HasMember(&s.bob.identity.PublicKey)) + s.Require().False(response.Communities()[0].HasMember(&s.bob.identity.PublicKey)) -// // Check bob has been banned -// response, err = WaitOnMessengerResponse(s.alice, -// func(r *MessengerResponse) bool { -// return len(r.Communities()) == 1 && !r.Communities()[0].HasMember(&s.bob.identity.PublicKey) + // Check bob has been banned + response, err = WaitOnMessengerResponse(s.alice, + func(r *MessengerResponse) bool { + return len(r.Communities()) == 1 && !r.Communities()[0].HasMember(&s.bob.identity.PublicKey) -// }, -// "alice didn't receive updated description", -// ) -// s.Require().NoError(err) + }, + "alice didn't receive updated description", + ) + s.Require().NoError(err) -// response, err = WaitOnMessengerResponse(s.alice, -// func(r *MessengerResponse) bool { -// keys, err := s.alice.encryptor.GetKeysForGroup(response.Communities()[0].ID()) -// if err != nil || len(keys) < 2 { -// return false -// } -// return true + response, err = WaitOnMessengerResponse(s.alice, + func(r *MessengerResponse) bool { + keys, err := s.alice.encryptor.GetKeysForGroup(response.Communities()[0].ID()) + if err != nil || len(keys) < 2 { + return false + } + return true -// }, -// "alice hasn't received updated key", -// ) -// s.Require().NoError(err) -// } + }, + "alice hasn't received updated key", + ) + s.Require().NoError(err) +} func (s *MessengerCommunitiesSuite) TestCommunityRekeyAfterBanDisableCompatibility() { common.RekeyCompatibility = false diff --git a/protocol/communities_messenger_token_permissions_test.go b/protocol/communities_messenger_token_permissions_test.go index 78dedd9df..ca29e8545 100644 --- a/protocol/communities_messenger_token_permissions_test.go +++ b/protocol/communities_messenger_token_permissions_test.go @@ -239,123 +239,123 @@ func (s *MessengerCommunitiesTokenPermissionsSuite) waitOnKeyDistribution(condit return testCommunitiesKeyDistributor.waitOnKeyDistribution(condition) } -// func (s *MessengerCommunitiesTokenPermissionsSuite) TestCreateTokenPermission() { -// community, _ := s.createCommunity() +func (s *MessengerCommunitiesTokenPermissionsSuite) TestCreateTokenPermission() { + community, _ := s.createCommunity() -// createTokenPermission := &requests.CreateCommunityTokenPermission{ -// CommunityID: community.ID(), -// Type: protobuf.CommunityTokenPermission_BECOME_MEMBER, -// TokenCriteria: []*protobuf.TokenCriteria{ -// &protobuf.TokenCriteria{ -// Type: protobuf.CommunityTokenType_ERC20, -// ContractAddresses: map[uint64]string{uint64(testChainID1): "0x123"}, -// Symbol: "TEST", -// Amount: "100", -// Decimals: uint64(18), -// }, -// }, -// } + createTokenPermission := &requests.CreateCommunityTokenPermission{ + CommunityID: community.ID(), + Type: protobuf.CommunityTokenPermission_BECOME_MEMBER, + TokenCriteria: []*protobuf.TokenCriteria{ + &protobuf.TokenCriteria{ + Type: protobuf.CommunityTokenType_ERC20, + ContractAddresses: map[uint64]string{uint64(testChainID1): "0x123"}, + Symbol: "TEST", + Amount: "100", + Decimals: uint64(18), + }, + }, + } -// response, err := s.owner.CreateCommunityTokenPermission(createTokenPermission) -// s.Require().NoError(err) -// s.Require().NotNil(response) -// s.Require().Len(response.Communities(), 1) + response, err := s.owner.CreateCommunityTokenPermission(createTokenPermission) + s.Require().NoError(err) + s.Require().NotNil(response) + s.Require().Len(response.Communities(), 1) -// tokenPermissions := response.Communities()[0].TokenPermissions() -// for _, tokenPermission := range tokenPermissions { -// for _, tc := range tokenPermission.TokenCriteria { -// s.Require().Equal(tc.Type, protobuf.CommunityTokenType_ERC20) -// s.Require().Equal(tc.Symbol, "TEST") -// s.Require().Equal(tc.Amount, "100") -// s.Require().Equal(tc.Decimals, uint64(18)) -// } -// } -// } + tokenPermissions := response.Communities()[0].TokenPermissions() + for _, tokenPermission := range tokenPermissions { + for _, tc := range tokenPermission.TokenCriteria { + s.Require().Equal(tc.Type, protobuf.CommunityTokenType_ERC20) + s.Require().Equal(tc.Symbol, "TEST") + s.Require().Equal(tc.Amount, "100") + s.Require().Equal(tc.Decimals, uint64(18)) + } + } +} -// func (s *MessengerCommunitiesTokenPermissionsSuite) TestEditTokenPermission() { -// community, _ := s.createCommunity() +func (s *MessengerCommunitiesTokenPermissionsSuite) TestEditTokenPermission() { + community, _ := s.createCommunity() -// tokenPermission := &requests.CreateCommunityTokenPermission{ -// CommunityID: community.ID(), -// Type: protobuf.CommunityTokenPermission_BECOME_MEMBER, -// TokenCriteria: []*protobuf.TokenCriteria{ -// &protobuf.TokenCriteria{ -// Type: protobuf.CommunityTokenType_ERC20, -// ContractAddresses: map[uint64]string{testChainID1: "0x123"}, -// Symbol: "TEST", -// Amount: "100", -// Decimals: uint64(18), -// }, -// }, -// } + tokenPermission := &requests.CreateCommunityTokenPermission{ + CommunityID: community.ID(), + Type: protobuf.CommunityTokenPermission_BECOME_MEMBER, + TokenCriteria: []*protobuf.TokenCriteria{ + &protobuf.TokenCriteria{ + Type: protobuf.CommunityTokenType_ERC20, + ContractAddresses: map[uint64]string{testChainID1: "0x123"}, + Symbol: "TEST", + Amount: "100", + Decimals: uint64(18), + }, + }, + } -// response, err := s.owner.CreateCommunityTokenPermission(tokenPermission) -// s.Require().NoError(err) -// s.Require().NotNil(response) -// s.Require().Len(response.Communities(), 1) + response, err := s.owner.CreateCommunityTokenPermission(tokenPermission) + s.Require().NoError(err) + s.Require().NotNil(response) + s.Require().Len(response.Communities(), 1) -// tokenPermissions := response.Communities()[0].TokenPermissions() + tokenPermissions := response.Communities()[0].TokenPermissions() -// var tokenPermissionID string -// for id := range tokenPermissions { -// tokenPermissionID = id -// } + var tokenPermissionID string + for id := range tokenPermissions { + tokenPermissionID = id + } -// tokenPermission.TokenCriteria[0].Symbol = "TESTUpdated" -// tokenPermission.TokenCriteria[0].Amount = "200" -// tokenPermission.TokenCriteria[0].Decimals = uint64(20) + tokenPermission.TokenCriteria[0].Symbol = "TESTUpdated" + tokenPermission.TokenCriteria[0].Amount = "200" + tokenPermission.TokenCriteria[0].Decimals = uint64(20) -// editTokenPermission := &requests.EditCommunityTokenPermission{ -// PermissionID: tokenPermissionID, -// CreateCommunityTokenPermission: *tokenPermission, -// } + editTokenPermission := &requests.EditCommunityTokenPermission{ + PermissionID: tokenPermissionID, + CreateCommunityTokenPermission: *tokenPermission, + } -// response2, err := s.owner.EditCommunityTokenPermission(editTokenPermission) -// s.Require().NoError(err) -// // wait for `checkMemberPermissions` to finish -// time.Sleep(1 * time.Second) -// s.Require().NotNil(response2) -// s.Require().Len(response2.Communities(), 1) + response2, err := s.owner.EditCommunityTokenPermission(editTokenPermission) + s.Require().NoError(err) + // wait for `checkMemberPermissions` to finish + time.Sleep(1 * time.Second) + s.Require().NotNil(response2) + s.Require().Len(response2.Communities(), 1) -// tokenPermissions = response2.Communities()[0].TokenPermissions() -// for _, tokenPermission := range tokenPermissions { -// for _, tc := range tokenPermission.TokenCriteria { -// s.Require().Equal(tc.Type, protobuf.CommunityTokenType_ERC20) -// s.Require().Equal(tc.Symbol, "TESTUpdated") -// s.Require().Equal(tc.Amount, "200") -// s.Require().Equal(tc.Decimals, uint64(20)) -// } -// } -// } + tokenPermissions = response2.Communities()[0].TokenPermissions() + for _, tokenPermission := range tokenPermissions { + for _, tc := range tokenPermission.TokenCriteria { + s.Require().Equal(tc.Type, protobuf.CommunityTokenType_ERC20) + s.Require().Equal(tc.Symbol, "TESTUpdated") + s.Require().Equal(tc.Amount, "200") + s.Require().Equal(tc.Decimals, uint64(20)) + } + } +} -// func (s *MessengerCommunitiesTokenPermissionsSuite) TestCommunityTokensMetadata() { -// community, _ := s.createCommunity() +func (s *MessengerCommunitiesTokenPermissionsSuite) TestCommunityTokensMetadata() { + community, _ := s.createCommunity() -// tokensMetadata := community.CommunityTokensMetadata() -// s.Require().Len(tokensMetadata, 0) + tokensMetadata := community.CommunityTokensMetadata() + s.Require().Len(tokensMetadata, 0) -// newToken := &protobuf.CommunityTokenMetadata{ -// ContractAddresses: map[uint64]string{testChainID1: "0xasd"}, -// Description: "desc1", -// Image: "IMG1", -// TokenType: protobuf.CommunityTokenType_ERC721, -// Symbol: "SMB", -// Decimals: 3, -// } + newToken := &protobuf.CommunityTokenMetadata{ + ContractAddresses: map[uint64]string{testChainID1: "0xasd"}, + Description: "desc1", + Image: "IMG1", + TokenType: protobuf.CommunityTokenType_ERC721, + Symbol: "SMB", + Decimals: 3, + } -// _, err := community.AddCommunityTokensMetadata(newToken) -// s.Require().NoError(err) -// tokensMetadata = community.CommunityTokensMetadata() -// s.Require().Len(tokensMetadata, 1) + _, err := community.AddCommunityTokensMetadata(newToken) + s.Require().NoError(err) + tokensMetadata = community.CommunityTokensMetadata() + s.Require().Len(tokensMetadata, 1) -// s.Require().Equal(tokensMetadata[0].ContractAddresses, newToken.ContractAddresses) -// s.Require().Equal(tokensMetadata[0].Description, newToken.Description) -// s.Require().Equal(tokensMetadata[0].Image, newToken.Image) -// s.Require().Equal(tokensMetadata[0].TokenType, newToken.TokenType) -// s.Require().Equal(tokensMetadata[0].Symbol, newToken.Symbol) -// s.Require().Equal(tokensMetadata[0].Name, newToken.Name) -// s.Require().Equal(tokensMetadata[0].Decimals, newToken.Decimals) -// } + s.Require().Equal(tokensMetadata[0].ContractAddresses, newToken.ContractAddresses) + s.Require().Equal(tokensMetadata[0].Description, newToken.Description) + s.Require().Equal(tokensMetadata[0].Image, newToken.Image) + s.Require().Equal(tokensMetadata[0].TokenType, newToken.TokenType) + s.Require().Equal(tokensMetadata[0].Symbol, newToken.Symbol) + s.Require().Equal(tokensMetadata[0].Name, newToken.Name) + s.Require().Equal(tokensMetadata[0].Decimals, newToken.Decimals) +} func (s *MessengerCommunitiesTokenPermissionsSuite) TestRequestAccessWithENSTokenPermission() { community, _ := s.createCommunity() @@ -420,205 +420,205 @@ func (s *MessengerCommunitiesTokenPermissionsSuite) TestRequestAccessWithENSToke } } -// func (s *MessengerCommunitiesTokenPermissionsSuite) TestJoinedCommunityMembersSharedAddress() { -// community, _ := s.createCommunity() -// s.advertiseCommunityTo(community, s.alice) -// s.advertiseCommunityTo(community, s.bob) +func (s *MessengerCommunitiesTokenPermissionsSuite) TestJoinedCommunityMembersSharedAddress() { + community, _ := s.createCommunity() + s.advertiseCommunityTo(community, s.alice) + s.advertiseCommunityTo(community, s.bob) -// s.joinCommunity(community, s.alice, alicePassword, []string{}) -// s.joinCommunity(community, s.bob, bobPassword, []string{}) + s.joinCommunity(community, s.alice, alicePassword, []string{}) + s.joinCommunity(community, s.bob, bobPassword, []string{}) -// community, err := s.owner.GetCommunityByID(community.ID()) -// s.Require().NoError(err) + community, err := s.owner.GetCommunityByID(community.ID()) + s.Require().NoError(err) -// s.Require().Equal(3, community.MembersCount()) + s.Require().Equal(3, community.MembersCount()) -// // Check owner's DB for revealed accounts -// for pubKey := range community.Members() { -// if pubKey != common.PubkeyToHex(&s.owner.identity.PublicKey) { -// revealedAccounts, err := s.owner.communitiesManager.GetRevealedAddresses(community.ID(), pubKey) -// s.Require().NoError(err) -// switch pubKey { -// case common.PubkeyToHex(&s.alice.identity.PublicKey): -// s.Require().Len(revealedAccounts, 2) -// s.Require().Equal(revealedAccounts[0].Address, aliceAddress1) -// s.Require().Equal(revealedAccounts[1].Address, aliceAddress2) -// s.Require().Equal(true, revealedAccounts[0].IsAirdropAddress) -// case common.PubkeyToHex(&s.bob.identity.PublicKey): -// s.Require().Len(revealedAccounts, 1) -// s.Require().Equal(revealedAccounts[0].Address, bobAddress) -// s.Require().Equal(true, revealedAccounts[0].IsAirdropAddress) -// default: -// s.Require().Fail("pubKey does not match expected keys") -// } -// } -// } + // Check owner's DB for revealed accounts + for pubKey := range community.Members() { + if pubKey != common.PubkeyToHex(&s.owner.identity.PublicKey) { + revealedAccounts, err := s.owner.communitiesManager.GetRevealedAddresses(community.ID(), pubKey) + s.Require().NoError(err) + switch pubKey { + case common.PubkeyToHex(&s.alice.identity.PublicKey): + s.Require().Len(revealedAccounts, 2) + s.Require().Equal(revealedAccounts[0].Address, aliceAddress1) + s.Require().Equal(revealedAccounts[1].Address, aliceAddress2) + s.Require().Equal(true, revealedAccounts[0].IsAirdropAddress) + case common.PubkeyToHex(&s.bob.identity.PublicKey): + s.Require().Len(revealedAccounts, 1) + s.Require().Equal(revealedAccounts[0].Address, bobAddress) + s.Require().Equal(true, revealedAccounts[0].IsAirdropAddress) + default: + s.Require().Fail("pubKey does not match expected keys") + } + } + } -// // Check Bob's DB for revealed accounts -// revealedAccountsInBobsDB, err := s.bob.communitiesManager.GetRevealedAddresses(community.ID(), common.PubkeyToHex(&s.bob.identity.PublicKey)) -// s.Require().NoError(err) -// s.Require().Len(revealedAccountsInBobsDB, 1) -// s.Require().Equal(revealedAccountsInBobsDB[0].Address, bobAddress) -// s.Require().Equal(true, revealedAccountsInBobsDB[0].IsAirdropAddress) + // Check Bob's DB for revealed accounts + revealedAccountsInBobsDB, err := s.bob.communitiesManager.GetRevealedAddresses(community.ID(), common.PubkeyToHex(&s.bob.identity.PublicKey)) + s.Require().NoError(err) + s.Require().Len(revealedAccountsInBobsDB, 1) + s.Require().Equal(revealedAccountsInBobsDB[0].Address, bobAddress) + s.Require().Equal(true, revealedAccountsInBobsDB[0].IsAirdropAddress) -// // Check Alices's DB for revealed accounts -// revealedAccountsInAlicesDB, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), common.PubkeyToHex(&s.alice.identity.PublicKey)) -// s.Require().NoError(err) -// s.Require().Len(revealedAccountsInAlicesDB, 2) -// s.Require().Equal(revealedAccountsInAlicesDB[0].Address, aliceAddress1) -// s.Require().Equal(revealedAccountsInAlicesDB[1].Address, aliceAddress2) -// s.Require().Equal(true, revealedAccountsInAlicesDB[0].IsAirdropAddress) -// } + // Check Alices's DB for revealed accounts + revealedAccountsInAlicesDB, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), common.PubkeyToHex(&s.alice.identity.PublicKey)) + s.Require().NoError(err) + s.Require().Len(revealedAccountsInAlicesDB, 2) + s.Require().Equal(revealedAccountsInAlicesDB[0].Address, aliceAddress1) + s.Require().Equal(revealedAccountsInAlicesDB[1].Address, aliceAddress2) + s.Require().Equal(true, revealedAccountsInAlicesDB[0].IsAirdropAddress) +} -// func (s *MessengerCommunitiesTokenPermissionsSuite) TestJoinedCommunityMembersSelectedSharedAddress() { -// community, _ := s.createCommunity() -// s.advertiseCommunityTo(community, s.alice) +func (s *MessengerCommunitiesTokenPermissionsSuite) TestJoinedCommunityMembersSelectedSharedAddress() { + community, _ := s.createCommunity() + s.advertiseCommunityTo(community, s.alice) -// s.joinCommunity(community, s.alice, alicePassword, []string{aliceAddress2}) + s.joinCommunity(community, s.alice, alicePassword, []string{aliceAddress2}) -// community, err := s.owner.GetCommunityByID(community.ID()) -// s.Require().NoError(err) + community, err := s.owner.GetCommunityByID(community.ID()) + s.Require().NoError(err) -// s.Require().Equal(2, community.MembersCount()) + s.Require().Equal(2, community.MembersCount()) -// alicePubkey := common.PubkeyToHex(&s.alice.identity.PublicKey) + alicePubkey := common.PubkeyToHex(&s.alice.identity.PublicKey) -// // Check owner's DB for revealed accounts -// revealedAccounts, err := s.owner.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) -// s.Require().NoError(err) -// s.Require().Len(revealedAccounts, 1) -// s.Require().Equal(revealedAccounts[0].Address, aliceAddress2) -// s.Require().Equal(true, revealedAccounts[0].IsAirdropAddress) + // Check owner's DB for revealed accounts + revealedAccounts, err := s.owner.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) + s.Require().NoError(err) + s.Require().Len(revealedAccounts, 1) + s.Require().Equal(revealedAccounts[0].Address, aliceAddress2) + s.Require().Equal(true, revealedAccounts[0].IsAirdropAddress) -// // Check Alice's DB for revealed accounts -// revealedAccountsInAlicesDB, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) -// s.Require().NoError(err) -// s.Require().Len(revealedAccountsInAlicesDB, 1) -// s.Require().Equal(revealedAccountsInAlicesDB[0].Address, aliceAddress2) -// s.Require().Equal(true, revealedAccountsInAlicesDB[0].IsAirdropAddress) -// } + // Check Alice's DB for revealed accounts + revealedAccountsInAlicesDB, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) + s.Require().NoError(err) + s.Require().Len(revealedAccountsInAlicesDB, 1) + s.Require().Equal(revealedAccountsInAlicesDB[0].Address, aliceAddress2) + s.Require().Equal(true, revealedAccountsInAlicesDB[0].IsAirdropAddress) +} -// func (s *MessengerCommunitiesTokenPermissionsSuite) TestJoinedCommunityMembersMultipleSelectedSharedAddresses() { -// community, _ := s.createCommunity() -// s.advertiseCommunityTo(community, s.alice) +func (s *MessengerCommunitiesTokenPermissionsSuite) TestJoinedCommunityMembersMultipleSelectedSharedAddresses() { + community, _ := s.createCommunity() + s.advertiseCommunityTo(community, s.alice) -// s.joinCommunityWithAirdropAddress(community, s.alice, alicePassword, []string{aliceAddress1, aliceAddress2}, aliceAddress2) + s.joinCommunityWithAirdropAddress(community, s.alice, alicePassword, []string{aliceAddress1, aliceAddress2}, aliceAddress2) -// community, err := s.owner.GetCommunityByID(community.ID()) -// s.Require().NoError(err) + community, err := s.owner.GetCommunityByID(community.ID()) + s.Require().NoError(err) -// s.Require().Equal(2, community.MembersCount()) + s.Require().Equal(2, community.MembersCount()) -// alicePubkey := common.PubkeyToHex(&s.alice.identity.PublicKey) + alicePubkey := common.PubkeyToHex(&s.alice.identity.PublicKey) -// // Check owner's DB for revealed accounts -// revealedAccounts, err := s.owner.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) -// s.Require().NoError(err) -// s.Require().Len(revealedAccounts, 2) -// s.Require().Equal(revealedAccounts[0].Address, aliceAddress1) -// s.Require().Equal(revealedAccounts[1].Address, aliceAddress2) -// s.Require().Equal(true, revealedAccounts[1].IsAirdropAddress) + // Check owner's DB for revealed accounts + revealedAccounts, err := s.owner.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) + s.Require().NoError(err) + s.Require().Len(revealedAccounts, 2) + s.Require().Equal(revealedAccounts[0].Address, aliceAddress1) + s.Require().Equal(revealedAccounts[1].Address, aliceAddress2) + s.Require().Equal(true, revealedAccounts[1].IsAirdropAddress) -// // Check Alice's DB for revealed accounts -// revealedAccountsInAlicesDB, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) -// s.Require().NoError(err) -// s.Require().Len(revealedAccountsInAlicesDB, 2) -// s.Require().Equal(revealedAccountsInAlicesDB[0].Address, aliceAddress1) -// s.Require().Equal(revealedAccountsInAlicesDB[1].Address, aliceAddress2) -// s.Require().Equal(true, revealedAccountsInAlicesDB[1].IsAirdropAddress) -// } + // Check Alice's DB for revealed accounts + revealedAccountsInAlicesDB, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) + s.Require().NoError(err) + s.Require().Len(revealedAccountsInAlicesDB, 2) + s.Require().Equal(revealedAccountsInAlicesDB[0].Address, aliceAddress1) + s.Require().Equal(revealedAccountsInAlicesDB[1].Address, aliceAddress2) + s.Require().Equal(true, revealedAccountsInAlicesDB[1].IsAirdropAddress) +} -// func (s *MessengerCommunitiesTokenPermissionsSuite) TestEditSharedAddresses() { -// community, _ := s.createCommunity() -// s.advertiseCommunityTo(community, s.alice) +func (s *MessengerCommunitiesTokenPermissionsSuite) TestEditSharedAddresses() { + community, _ := s.createCommunity() + s.advertiseCommunityTo(community, s.alice) -// s.joinCommunity(community, s.alice, alicePassword, []string{aliceAddress2}) + s.joinCommunity(community, s.alice, alicePassword, []string{aliceAddress2}) -// community, err := s.owner.GetCommunityByID(community.ID()) -// s.Require().NoError(err) -// s.Require().Equal(2, community.MembersCount()) + community, err := s.owner.GetCommunityByID(community.ID()) + s.Require().NoError(err) + s.Require().Equal(2, community.MembersCount()) -// alicePubkey := common.PubkeyToHex(&s.alice.identity.PublicKey) + alicePubkey := common.PubkeyToHex(&s.alice.identity.PublicKey) -// revealedAccounts, err := s.owner.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) -// s.Require().NoError(err) + revealedAccounts, err := s.owner.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) + s.Require().NoError(err) -// s.Require().Len(revealedAccounts, 1) -// s.Require().Equal(revealedAccounts[0].Address, aliceAddress2) -// s.Require().Equal(true, revealedAccounts[0].IsAirdropAddress) + s.Require().Len(revealedAccounts, 1) + s.Require().Equal(revealedAccounts[0].Address, aliceAddress2) + s.Require().Equal(true, revealedAccounts[0].IsAirdropAddress) -// alicesRevealedAccounts, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) -// s.Require().NoError(err) -// s.Require().Len(alicesRevealedAccounts, 1) -// s.Require().Equal(alicesRevealedAccounts[0].Address, aliceAddress2) -// s.Require().Equal(true, alicesRevealedAccounts[0].IsAirdropAddress) + alicesRevealedAccounts, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) + s.Require().NoError(err) + s.Require().Len(alicesRevealedAccounts, 1) + s.Require().Equal(alicesRevealedAccounts[0].Address, aliceAddress2) + s.Require().Equal(true, alicesRevealedAccounts[0].IsAirdropAddress) -// request := &requests.EditSharedAddresses{CommunityID: community.ID(), AddressesToReveal: []string{aliceAddress1}, AirdropAddress: aliceAddress1} + request := &requests.EditSharedAddresses{CommunityID: community.ID(), AddressesToReveal: []string{aliceAddress1}, AirdropAddress: aliceAddress1} -// signingParams, err := s.alice.GenerateJoiningCommunityRequestsForSigning(common.PubkeyToHex(&s.alice.identity.PublicKey), community.ID(), request.AddressesToReveal) -// s.Require().NoError(err) + signingParams, err := s.alice.GenerateJoiningCommunityRequestsForSigning(common.PubkeyToHex(&s.alice.identity.PublicKey), community.ID(), request.AddressesToReveal) + s.Require().NoError(err) -// passwdHash := types.EncodeHex(crypto.Keccak256([]byte(alicePassword))) -// for i := range signingParams { -// signingParams[i].Password = passwdHash -// } -// signatures, err := s.alice.SignData(signingParams) -// s.Require().NoError(err) + passwdHash := types.EncodeHex(crypto.Keccak256([]byte(alicePassword))) + for i := range signingParams { + signingParams[i].Password = passwdHash + } + signatures, err := s.alice.SignData(signingParams) + s.Require().NoError(err) -// updateAddresses := len(request.AddressesToReveal) == 0 -// if updateAddresses { -// request.AddressesToReveal = make([]string, len(signingParams)) -// } -// for i := range signingParams { -// request.AddressesToReveal[i] = signingParams[i].Address -// request.Signatures = append(request.Signatures, types.FromHex(signatures[i])) -// } -// if updateAddresses { -// request.AirdropAddress = request.AddressesToReveal[0] -// } + updateAddresses := len(request.AddressesToReveal) == 0 + if updateAddresses { + request.AddressesToReveal = make([]string, len(signingParams)) + } + for i := range signingParams { + request.AddressesToReveal[i] = signingParams[i].Address + request.Signatures = append(request.Signatures, types.FromHex(signatures[i])) + } + if updateAddresses { + request.AirdropAddress = request.AddressesToReveal[0] + } -// response, err := s.alice.EditSharedAddressesForCommunity(request) -// s.Require().NoError(err) -// s.Require().NotNil(response) + response, err := s.alice.EditSharedAddressesForCommunity(request) + s.Require().NoError(err) + s.Require().NotNil(response) -// // Retrieve address change -// err = tt.RetryWithBackOff(func() error { -// response, err := s.owner.RetrieveAll() -// if err != nil { -// return err -// } -// if len(response.Communities()) == 0 { -// return errors.New("no communities in response (address change reception)") -// } -// return nil -// }) -// s.Require().NoError(err) -// revealedAccounts, err = s.owner.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) -// s.Require().NoError(err) + // Retrieve address change + err = tt.RetryWithBackOff(func() error { + response, err := s.owner.RetrieveAll() + if err != nil { + return err + } + if len(response.Communities()) == 0 { + return errors.New("no communities in response (address change reception)") + } + return nil + }) + s.Require().NoError(err) + revealedAccounts, err = s.owner.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) + s.Require().NoError(err) -// s.Require().Len(revealedAccounts, 1) -// s.Require().Equal(revealedAccounts[0].Address, aliceAddress1) -// s.Require().Equal(true, revealedAccounts[0].IsAirdropAddress) + s.Require().Len(revealedAccounts, 1) + s.Require().Equal(revealedAccounts[0].Address, aliceAddress1) + s.Require().Equal(true, revealedAccounts[0].IsAirdropAddress) -// // Retrieve community description change -// err = tt.RetryWithBackOff(func() error { -// response, err := s.alice.RetrieveAll() -// if err != nil { -// return err -// } -// if len(response.Communities()) == 0 { -// return errors.New("no communities in response (address change reception)") -// } -// return nil -// }) -// s.Require().NoError(err) + // Retrieve community description change + err = tt.RetryWithBackOff(func() error { + response, err := s.alice.RetrieveAll() + if err != nil { + return err + } + if len(response.Communities()) == 0 { + return errors.New("no communities in response (address change reception)") + } + return nil + }) + s.Require().NoError(err) -// alicesRevealedAccounts, err = s.alice.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) -// s.Require().NoError(err) -// s.Require().Len(alicesRevealedAccounts, 1) -// s.Require().Equal(alicesRevealedAccounts[0].Address, aliceAddress1) -// s.Require().Equal(true, alicesRevealedAccounts[0].IsAirdropAddress) -// } + alicesRevealedAccounts, err = s.alice.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) + s.Require().NoError(err) + s.Require().Len(alicesRevealedAccounts, 1) + s.Require().Equal(alicesRevealedAccounts[0].Address, aliceAddress1) + s.Require().Equal(true, alicesRevealedAccounts[0].IsAirdropAddress) +} // NOTE(cammellos): Disabling for now as flaky, for some reason does not pass on CI, but passes locally /* @@ -819,183 +819,183 @@ func (s *MessengerCommunitiesTokenPermissionsSuite) TestBecomeMemberPermissions( s.Require().NoError(err) }*/ -// func (s *MessengerCommunitiesTokenPermissionsSuite) TestJoinCommunityWithAdminPermission() { -// community, _ := s.createCommunity() +func (s *MessengerCommunitiesTokenPermissionsSuite) TestJoinCommunityWithAdminPermission() { + community, _ := s.createCommunity() -// // setup become admin permission -// permissionRequest := requests.CreateCommunityTokenPermission{ -// CommunityID: community.ID(), -// Type: protobuf.CommunityTokenPermission_BECOME_ADMIN, -// TokenCriteria: []*protobuf.TokenCriteria{ -// &protobuf.TokenCriteria{ -// Type: protobuf.CommunityTokenType_ERC20, -// ContractAddresses: map[uint64]string{testChainID1: "0x123"}, -// Symbol: "TEST", -// Amount: "100", -// Decimals: uint64(18), -// }, -// }, -// } + // setup become admin permission + permissionRequest := requests.CreateCommunityTokenPermission{ + CommunityID: community.ID(), + Type: protobuf.CommunityTokenPermission_BECOME_ADMIN, + TokenCriteria: []*protobuf.TokenCriteria{ + &protobuf.TokenCriteria{ + Type: protobuf.CommunityTokenType_ERC20, + ContractAddresses: map[uint64]string{testChainID1: "0x123"}, + Symbol: "TEST", + Amount: "100", + Decimals: uint64(18), + }, + }, + } -// response, err := s.owner.CreateCommunityTokenPermission(&permissionRequest) -// s.Require().NoError(err) -// s.Require().Len(response.Communities(), 1) + response, err := s.owner.CreateCommunityTokenPermission(&permissionRequest) + s.Require().NoError(err) + s.Require().Len(response.Communities(), 1) -// s.advertiseCommunityTo(community, s.bob) + s.advertiseCommunityTo(community, s.bob) -// // Bob should still be able to join even if there is a permission to be an admin -// s.joinCommunity(community, s.bob, bobPassword, []string{}) + // Bob should still be able to join even if there is a permission to be an admin + s.joinCommunity(community, s.bob, bobPassword, []string{}) -// // Verify that we have Bob's revealed account -// revealedAccounts, err := s.owner.GetRevealedAccounts(community.ID(), common.PubkeyToHex(&s.bob.identity.PublicKey)) -// s.Require().NoError(err) -// s.Require().Len(revealedAccounts, 1) -// s.Require().Equal(bobAddress, revealedAccounts[0].Address) -// } + // Verify that we have Bob's revealed account + revealedAccounts, err := s.owner.GetRevealedAccounts(community.ID(), common.PubkeyToHex(&s.bob.identity.PublicKey)) + s.Require().NoError(err) + s.Require().Len(revealedAccounts, 1) + s.Require().Equal(bobAddress, revealedAccounts[0].Address) +} -// func (s *MessengerCommunitiesTokenPermissionsSuite) TestJoinCommunityAsMemberWithMemberAndAdminPermission() { -// community, _ := s.createCommunity() +func (s *MessengerCommunitiesTokenPermissionsSuite) TestJoinCommunityAsMemberWithMemberAndAdminPermission() { + community, _ := s.createCommunity() -// waitOnCommunityPermissionCreated := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool { -// return sub.Community.HasTokenPermissions() -// }) + waitOnCommunityPermissionCreated := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool { + return sub.Community.HasTokenPermissions() + }) -// // setup become member permission -// permissionRequestMember := requests.CreateCommunityTokenPermission{ -// CommunityID: community.ID(), -// Type: protobuf.CommunityTokenPermission_BECOME_MEMBER, -// TokenCriteria: []*protobuf.TokenCriteria{ -// &protobuf.TokenCriteria{ -// Type: protobuf.CommunityTokenType_ERC20, -// ContractAddresses: map[uint64]string{testChainID1: "0x123"}, -// Symbol: "TEST", -// Amount: "100", -// Decimals: uint64(18), -// }, -// }, -// } -// response, err := s.owner.CreateCommunityTokenPermission(&permissionRequestMember) -// s.Require().NoError(err) -// s.Require().Len(response.Communities(), 1) + // setup become member permission + permissionRequestMember := requests.CreateCommunityTokenPermission{ + CommunityID: community.ID(), + Type: protobuf.CommunityTokenPermission_BECOME_MEMBER, + TokenCriteria: []*protobuf.TokenCriteria{ + &protobuf.TokenCriteria{ + Type: protobuf.CommunityTokenType_ERC20, + ContractAddresses: map[uint64]string{testChainID1: "0x123"}, + Symbol: "TEST", + Amount: "100", + Decimals: uint64(18), + }, + }, + } + response, err := s.owner.CreateCommunityTokenPermission(&permissionRequestMember) + s.Require().NoError(err) + s.Require().Len(response.Communities(), 1) -// err = <-waitOnCommunityPermissionCreated -// s.Require().NoError(err) + err = <-waitOnCommunityPermissionCreated + s.Require().NoError(err) -// // setup become admin permission -// permissionRequestAdmin := requests.CreateCommunityTokenPermission{ -// CommunityID: community.ID(), -// Type: protobuf.CommunityTokenPermission_BECOME_ADMIN, -// TokenCriteria: []*protobuf.TokenCriteria{ -// &protobuf.TokenCriteria{ -// Type: protobuf.CommunityTokenType_ERC20, -// ContractAddresses: map[uint64]string{testChainID1: "0x124"}, -// Symbol: "TESTADMIN", -// Amount: "100", -// Decimals: uint64(18), -// }, -// }, -// } -// response, err = s.owner.CreateCommunityTokenPermission(&permissionRequestAdmin) -// s.Require().NoError(err) -// s.Require().Len(response.Communities(), 1) + // setup become admin permission + permissionRequestAdmin := requests.CreateCommunityTokenPermission{ + CommunityID: community.ID(), + Type: protobuf.CommunityTokenPermission_BECOME_ADMIN, + TokenCriteria: []*protobuf.TokenCriteria{ + &protobuf.TokenCriteria{ + Type: protobuf.CommunityTokenType_ERC20, + ContractAddresses: map[uint64]string{testChainID1: "0x124"}, + Symbol: "TESTADMIN", + Amount: "100", + Decimals: uint64(18), + }, + }, + } + response, err = s.owner.CreateCommunityTokenPermission(&permissionRequestAdmin) + s.Require().NoError(err) + s.Require().Len(response.Communities(), 1) -// waitOnCommunityPermissionCreated = waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool { -// return len(sub.Community.TokenPermissions()) == 2 -// }) + waitOnCommunityPermissionCreated = waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool { + return len(sub.Community.TokenPermissions()) == 2 + }) -// err = <-waitOnCommunityPermissionCreated -// s.Require().NoError(err) + err = <-waitOnCommunityPermissionCreated + s.Require().NoError(err) -// // make bob satisfy the member criteria -// s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, permissionRequestMember.TokenCriteria[0]) + // make bob satisfy the member criteria + s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, permissionRequestMember.TokenCriteria[0]) -// s.advertiseCommunityTo(response.Communities()[0], s.bob) + s.advertiseCommunityTo(response.Communities()[0], s.bob) -// // Bob should still be able to join even though he doesn't satisfy the admin requirement -// // because he satisfies the member one -// s.joinCommunity(community, s.bob, bobPassword, []string{}) + // Bob should still be able to join even though he doesn't satisfy the admin requirement + // because he satisfies the member one + s.joinCommunity(community, s.bob, bobPassword, []string{}) -// // Verify that we have Bob's revealed account -// revealedAccounts, err := s.owner.GetRevealedAccounts(community.ID(), common.PubkeyToHex(&s.bob.identity.PublicKey)) -// s.Require().NoError(err) -// s.Require().Len(revealedAccounts, 1) -// s.Require().Equal(bobAddress, revealedAccounts[0].Address) -// } + // Verify that we have Bob's revealed account + revealedAccounts, err := s.owner.GetRevealedAccounts(community.ID(), common.PubkeyToHex(&s.bob.identity.PublicKey)) + s.Require().NoError(err) + s.Require().Len(revealedAccounts, 1) + s.Require().Equal(bobAddress, revealedAccounts[0].Address) +} -// func (s *MessengerCommunitiesTokenPermissionsSuite) TestJoinCommunityAsAdminWithMemberAndAdminPermission() { -// community, _ := s.createCommunity() +func (s *MessengerCommunitiesTokenPermissionsSuite) TestJoinCommunityAsAdminWithMemberAndAdminPermission() { + community, _ := s.createCommunity() -// // setup become member permission -// permissionRequestMember := requests.CreateCommunityTokenPermission{ -// CommunityID: community.ID(), -// Type: protobuf.CommunityTokenPermission_BECOME_MEMBER, -// TokenCriteria: []*protobuf.TokenCriteria{ -// &protobuf.TokenCriteria{ -// Type: protobuf.CommunityTokenType_ERC20, -// ContractAddresses: map[uint64]string{testChainID1: "0x123"}, -// Symbol: "TEST", -// Amount: "100", -// Decimals: uint64(18), -// }, -// }, -// } -// response, err := s.owner.CreateCommunityTokenPermission(&permissionRequestMember) -// s.Require().NoError(err) -// s.Require().Len(response.Communities(), 1) + // setup become member permission + permissionRequestMember := requests.CreateCommunityTokenPermission{ + CommunityID: community.ID(), + Type: protobuf.CommunityTokenPermission_BECOME_MEMBER, + TokenCriteria: []*protobuf.TokenCriteria{ + &protobuf.TokenCriteria{ + Type: protobuf.CommunityTokenType_ERC20, + ContractAddresses: map[uint64]string{testChainID1: "0x123"}, + Symbol: "TEST", + Amount: "100", + Decimals: uint64(18), + }, + }, + } + response, err := s.owner.CreateCommunityTokenPermission(&permissionRequestMember) + s.Require().NoError(err) + s.Require().Len(response.Communities(), 1) -// waitOnCommunityPermissionCreated := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool { -// return sub.Community.HasTokenPermissions() -// }) + waitOnCommunityPermissionCreated := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool { + return sub.Community.HasTokenPermissions() + }) -// err = <-waitOnCommunityPermissionCreated -// s.Require().NoError(err) + err = <-waitOnCommunityPermissionCreated + s.Require().NoError(err) -// // setup become admin permission -// permissionRequestAdmin := requests.CreateCommunityTokenPermission{ -// CommunityID: community.ID(), -// Type: protobuf.CommunityTokenPermission_BECOME_ADMIN, -// TokenCriteria: []*protobuf.TokenCriteria{ -// &protobuf.TokenCriteria{ -// Type: protobuf.CommunityTokenType_ERC20, -// ContractAddresses: map[uint64]string{testChainID1: "0x124"}, -// Symbol: "TESTADMIN", -// Amount: "100", -// Decimals: uint64(18), -// }, -// }, -// } -// response, err = s.owner.CreateCommunityTokenPermission(&permissionRequestAdmin) -// s.Require().NoError(err) -// s.Require().Len(response.Communities(), 1) -// s.Require().Len(response.Communities()[0].TokenPermissionsByType(protobuf.CommunityTokenPermission_BECOME_ADMIN), 1) -// s.Require().Len(response.Communities()[0].TokenPermissions(), 2) + // setup become admin permission + permissionRequestAdmin := requests.CreateCommunityTokenPermission{ + CommunityID: community.ID(), + Type: protobuf.CommunityTokenPermission_BECOME_ADMIN, + TokenCriteria: []*protobuf.TokenCriteria{ + &protobuf.TokenCriteria{ + Type: protobuf.CommunityTokenType_ERC20, + ContractAddresses: map[uint64]string{testChainID1: "0x124"}, + Symbol: "TESTADMIN", + Amount: "100", + Decimals: uint64(18), + }, + }, + } + response, err = s.owner.CreateCommunityTokenPermission(&permissionRequestAdmin) + s.Require().NoError(err) + s.Require().Len(response.Communities(), 1) + s.Require().Len(response.Communities()[0].TokenPermissionsByType(protobuf.CommunityTokenPermission_BECOME_ADMIN), 1) + s.Require().Len(response.Communities()[0].TokenPermissions(), 2) -// waitOnCommunityPermissionCreated = waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool { -// return len(sub.Community.TokenPermissions()) == 2 -// }) + waitOnCommunityPermissionCreated = waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool { + return len(sub.Community.TokenPermissions()) == 2 + }) -// err = <-waitOnCommunityPermissionCreated -// s.Require().NoError(err) + err = <-waitOnCommunityPermissionCreated + s.Require().NoError(err) -// community, err = s.owner.communitiesManager.GetByID(community.ID()) -// s.Require().NoError(err) -// s.Require().Len(community.TokenPermissions(), 2) + community, err = s.owner.communitiesManager.GetByID(community.ID()) + s.Require().NoError(err) + s.Require().Len(community.TokenPermissions(), 2) -// s.advertiseCommunityTo(community, s.bob) + s.advertiseCommunityTo(community, s.bob) -// // make bob satisfy the admin criteria -// s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, permissionRequestAdmin.TokenCriteria[0]) + // make bob satisfy the admin criteria + s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, permissionRequestAdmin.TokenCriteria[0]) -// // Bob should still be able to join even though he doesn't satisfy the member requirement -// // because he satisfies the admin one -// s.joinCommunity(community, s.bob, bobPassword, []string{}) + // Bob should still be able to join even though he doesn't satisfy the member requirement + // because he satisfies the admin one + s.joinCommunity(community, s.bob, bobPassword, []string{}) -// // Verify that we have Bob's revealed account -// revealedAccounts, err := s.owner.GetRevealedAccounts(community.ID(), common.PubkeyToHex(&s.bob.identity.PublicKey)) -// s.Require().NoError(err) -// s.Require().Len(revealedAccounts, 1) -// s.Require().Equal(bobAddress, revealedAccounts[0].Address) -// } + // Verify that we have Bob's revealed account + revealedAccounts, err := s.owner.GetRevealedAccounts(community.ID(), common.PubkeyToHex(&s.bob.identity.PublicKey)) + s.Require().NoError(err) + s.Require().Len(revealedAccounts, 1) + s.Require().Equal(bobAddress, revealedAccounts[0].Address) +} func (s *MessengerCommunitiesTokenPermissionsSuite) TestViewChannelPermissions() { community, chat := s.createCommunity() @@ -1228,7 +1228,6 @@ func (s *MessengerCommunitiesTokenPermissionsSuite) TestReevaluateMemberTokenMas s.testReevaluateMemberPrivilegedRoleInOpenCommunity(protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER) } -/* func (s *MessengerCommunitiesTokenPermissionsSuite) testReevaluateMemberPrivilegedRoleInClosedCommunity(permissionType protobuf.CommunityTokenPermission_Type) { community, _ := s.createCommunity() @@ -1361,12 +1360,11 @@ func (s *MessengerCommunitiesTokenPermissionsSuite) testReevaluateMemberPrivileg s.Require().False(checkRoleBasedOnThePermissionType(permissionType, &s.alice.identity.PublicKey, community)) } -*/ -/* + func (s *MessengerCommunitiesTokenPermissionsSuite) TestReevaluateMemberAdminRoleInClosedCommunity() { s.testReevaluateMemberPrivilegedRoleInClosedCommunity(protobuf.CommunityTokenPermission_BECOME_ADMIN) } -*/ + /* func (s *MessengerCommunitiesTokenPermissionsSuite) TestReevaluateMemberTokenMasterRoleInClosedCommunity() { s.testReevaluateMemberPrivilegedRoleInClosedCommunity(protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER) diff --git a/protocol/messenger_communities_sharding_test.go b/protocol/messenger_communities_sharding_test.go index 53bb12771..3e43c532b 100644 --- a/protocol/messenger_communities_sharding_test.go +++ b/protocol/messenger_communities_sharding_test.go @@ -2,17 +2,16 @@ package protocol import ( "context" - // "crypto/ecdsa" + "crypto/ecdsa" "testing" - // "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/proto" "github.com/stretchr/testify/suite" "go.uber.org/zap" gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" "github.com/status-im/status-go/eth-node/types" - - // "github.com/status-im/status-go/protocol/common" + "github.com/status-im/status-go/protocol/common" "github.com/status-im/status-go/protocol/common/shard" "github.com/status-im/status-go/protocol/communities" "github.com/status-im/status-go/protocol/protobuf" @@ -147,7 +146,6 @@ func (s *MessengerCommunitiesShardingSuite) TestPostToCommunityChat() { } } -/* func (s *MessengerCommunitiesShardingSuite) TestIgnoreOutdatedShardKey() { community, _ := createCommunity(&s.Suite, s.owner) @@ -222,4 +220,3 @@ func (s *MessengerCommunitiesShardingSuite) TestIgnoreOutdatedShardKey() { s.Require().NoError(err) } } -*/ diff --git a/protocol/messenger_contact_requests_test.go b/protocol/messenger_contact_requests_test.go index 8893f1b04..804ec5b04 100644 --- a/protocol/messenger_contact_requests_test.go +++ b/protocol/messenger_contact_requests_test.go @@ -1,1632 +1,1634 @@ package protocol import ( - // "context" - // "fmt" + "context" + "fmt" "testing" - // "github.com/stretchr/testify/suite" - // "go.uber.org/zap" - // "github.com/status-im/status-go/deprecation" - // "github.com/status-im/status-go/eth-node/crypto" - // "github.com/status-im/status-go/eth-node/types" - // "github.com/status-im/status-go/multiaccounts/settings" - // "github.com/status-im/status-go/protocol/common" - // "github.com/status-im/status-go/protocol/protobuf" - // "github.com/status-im/status-go/protocol/requests" - // v1protocol "github.com/status-im/status-go/protocol/v1" + + "github.com/stretchr/testify/suite" + "go.uber.org/zap" + + "github.com/status-im/status-go/deprecation" + "github.com/status-im/status-go/eth-node/crypto" + "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/multiaccounts/settings" + "github.com/status-im/status-go/protocol/common" + "github.com/status-im/status-go/protocol/protobuf" + "github.com/status-im/status-go/protocol/requests" + v1protocol "github.com/status-im/status-go/protocol/v1" ) func TestMessengerContactRequestSuite(t *testing.T) { - //suite.Run(t, new(MessengerContactRequestSuite)) + suite.Run(t, new(MessengerContactRequestSuite)) } -// type MessengerContactRequestSuite struct { -// MessengerBaseTestSuite -// } - -// func (s *MessengerContactRequestSuite) findFirstByContentType(messages []*common.Message, contentType protobuf.ChatMessage_ContentType) *common.Message { -// return FindFirstByContentType(messages, contentType) -// } - -// func (s *MessengerContactRequestSuite) sendContactRequest(request *requests.SendContactRequest, messenger *Messenger) { -// s.logger.Info("sendContactRequest", zap.String("sender", messenger.IdentityPublicKeyString()), zap.String("receiver", request.ID)) - -// // Send contact request -// resp, err := messenger.SendContactRequest(context.Background(), request) -// s.Require().NoError(err) -// s.Require().NotNil(resp) - -// // Check CR and mutual state update messages -// s.Require().Len(resp.Messages(), 2) - -// mutualStateUpdate := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_SENT) -// s.Require().NotNil(mutualStateUpdate) - -// s.Require().NotNil(mutualStateUpdate.ID) -// s.Require().Equal(mutualStateUpdate.From, messenger.myHexIdentity()) -// s.Require().Equal(mutualStateUpdate.ChatId, request.ID) -// s.Require().Equal(mutualStateUpdate.Text, fmt.Sprintf(outgoingMutualStateEventSentDefaultText, request.ID)) - -// contactRequest := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) -// s.Require().NotNil(contactRequest) - -// s.Require().Equal(common.ContactRequestStatePending, contactRequest.ContactRequestState) -// s.Require().Equal(request.Message, contactRequest.Text) - -// // Check pending notification -// s.Require().Len(resp.ActivityCenterNotifications(), 1) -// s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) -// s.Require().Equal(contactRequest.ID, resp.ActivityCenterNotifications()[0].Message.ID) -// s.Require().Equal(contactRequest.ContactRequestState, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, true) - -// // Check contacts -// s.Require().Len(resp.Contacts, 1) -// contact := resp.Contacts[0] -// s.Require().False(contact.mutual()) - -// // Make sure it's not returned as coming from us -// contactRequests, _, err := messenger.PendingContactRequests("", 10) -// s.Require().NoError(err) -// s.Require().Len(contactRequests, 0) - -// // Make sure contact is added on the sender side -// contacts := messenger.AddedContacts() -// s.Require().Len(contacts, 1) -// s.Require().Equal(ContactRequestStateSent, contacts[0].ContactRequestLocalState) -// s.Require().NotNil(contacts[0].DisplayName) - -// // Check contact's primary name matches notification's name -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Name, contacts[0].PrimaryName()) -// } - -// func (s *MessengerContactRequestSuite) receiveContactRequest(messageText string, theirMessenger *Messenger) *common.Message { -// s.logger.Info("receiveContactRequest", zap.String("receiver", theirMessenger.IdentityPublicKeyString())) - -// // Wait for the message to reach its destination -// resp, err := WaitOnMessengerResponse( -// theirMessenger, -// func(r *MessengerResponse) bool { -// return len(r.Contacts) == 1 && len(r.Messages()) >= 2 && len(r.ActivityCenterNotifications()) == 1 -// }, -// "no messages", -// ) - -// // Check contact request has been received -// s.Require().NoError(err) -// s.Require().NotNil(resp) - -// // Check CR and mutual state update messages -// s.Require().Len(resp.Messages(), 2) - -// contactRequest := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) -// s.Require().NotNil(contactRequest) - -// s.Require().Equal(common.ContactRequestStatePending, contactRequest.ContactRequestState) -// s.Require().Equal(messageText, contactRequest.Text) - -// mutualStateUpdate := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_SENT) -// s.Require().NotNil(mutualStateUpdate) - -// s.Require().Equal(mutualStateUpdate.From, contactRequest.From) -// s.Require().Equal(mutualStateUpdate.ChatId, contactRequest.From) -// s.Require().Equal(mutualStateUpdate.Text, fmt.Sprintf(incomingMutualStateEventSentDefaultText, contactRequest.From)) - -// // Check activity center notification is of the right type -// s.Require().Len(resp.ActivityCenterNotifications(), 1) -// s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) -// s.Require().Equal(contactRequest.ID, resp.ActivityCenterNotifications()[0].Message.ID) -// s.Require().Equal(contactRequest.ContactRequestState, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, false) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Accepted, false) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Dismissed, false) - -// notifications, err := theirMessenger.ActivityCenterNotifications(ActivityCenterNotificationsRequest{ -// Cursor: "", -// Limit: 10, -// ActivityTypes: []ActivityCenterType{ActivityCenterNotificationTypeContactRequest}, -// ReadType: ActivityCenterQueryParamsReadUnread, -// }, -// ) -// s.Require().NoError(err) -// s.Require().Len(notifications.Notifications, 1) -// s.Require().Equal(contactRequest.ID, notifications.Notifications[0].Message.ID) -// s.Require().Equal(contactRequest.ContactRequestState, notifications.Notifications[0].Message.ContactRequestState) - -// // Check the contact state is correctly set -// s.Require().Len(resp.Contacts, 1) -// contact := resp.Contacts[0] -// s.Require().Equal(ContactRequestStateReceived, contact.ContactRequestRemoteState) - -// // Check contact's primary name matches notification's name -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Name, contact.PrimaryName()) - -// // Make sure it's the latest pending contact requests -// contactRequests, _, err := theirMessenger.PendingContactRequests("", 10) -// s.Require().NoError(err) -// s.Require().Greater(len(contactRequests), 0) -// s.Require().Equal(contactRequests[0].ID, contactRequest.ID) - -// return contactRequest -// } - -// // This function partially logs given MessengerResponse with description. -// // This is helpful for testing response content during long tests. -// // Logged contents: Messages, Contacts, ActivityCenterNotifications -// func (s *MessengerContactRequestSuite) logResponse(response *MessengerResponse, description string) { -// s.logger.Debug("MessengerResponse", zap.String("description", description)) - -// for i, message := range response.Messages() { -// s.logger.Debug("message", -// zap.Int("index", i), -// zap.String("Text", message.Text), -// zap.Any("ContentType", message.ContentType), -// ) -// } - -// for i, contact := range response.Contacts { -// s.logger.Debug("contact", -// zap.Int("index", i), -// zap.Bool("Blocked", contact.Blocked), -// zap.Bool("Removed", contact.Removed), -// zap.Any("crRemoteState", contact.ContactRequestLocalState), -// zap.Any("crLocalState", contact.ContactRequestRemoteState), -// ) -// } - -// for i, notification := range response.ActivityCenterNotifications() { -// messageText := "" -// if notification.Message != nil { -// messageText = notification.Message.Text -// } -// s.logger.Debug("acNotification", -// zap.Int("index", i), -// zap.Any("id", notification.ID), -// zap.Any("Type", notification.Type), -// zap.String("Message", messageText), -// zap.String("Name", notification.Name), -// zap.String("Author", notification.Author), -// ) -// } -// } - -// func (s *MessengerContactRequestSuite) acceptContactRequest( -// contactRequest *common.Message, sender *Messenger, receiver *Messenger) { -// s.logger.Info("acceptContactRequest", -// zap.String("sender", sender.IdentityPublicKeyString()), -// zap.String("receiver", receiver.IdentityPublicKeyString())) - -// // Accept contact request, receiver side -// resp, err := receiver.AcceptContactRequest(context.Background(), &requests.AcceptContactRequest{ID: types.Hex2Bytes(contactRequest.ID)}) -// s.Require().NoError(err) - -// // Chack updated contact request message and mutual state update -// s.Require().NotNil(resp) -// s.Require().Len(resp.Messages(), 2) - -// contactRequestMsg := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) -// s.Require().NotNil(contactRequestMsg) - -// mutualStateUpdate := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED) -// s.Require().NotNil(mutualStateUpdate) - -// s.Require().Equal(contactRequestMsg.ID, contactRequest.ID) -// s.Require().Equal(common.ContactRequestStateAccepted, contactRequestMsg.ContactRequestState) - -// s.Require().Equal(mutualStateUpdate.ChatId, contactRequestMsg.From) -// s.Require().Equal(mutualStateUpdate.From, contactRequestMsg.ChatId) -// s.Require().Equal(mutualStateUpdate.Text, fmt.Sprintf(outgoingMutualStateEventAcceptedDefaultText, contactRequestMsg.From)) - -// s.Require().Len(resp.ActivityCenterNotifications(), 1) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequest.ID) -// s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) -// s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - -// // Check the contact state is correctly set -// s.Require().Len(resp.Contacts, 1) -// s.Require().True(resp.Contacts[0].mutual()) - -// // Check contact's primary name matches notification's name -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Name, resp.Contacts[0].PrimaryName()) - -// // Check we have active chat in the response -// s.Require().Len(resp.Chats(), 1) -// s.Require().True(resp.Chats()[0].Active) - -// // Make sure the sender is added to our contacts -// contacts := receiver.AddedContacts() -// s.Require().Len(contacts, 1) - -// // Make sure we consider them a mutual contact, receiver side -// mutualContacts := receiver.MutualContacts() -// s.Require().Len(mutualContacts, 1) - -// // Wait for the message to reach its destination -// resp, err = WaitOnMessengerResponse(sender, -// func(r *MessengerResponse) bool { -// return len(r.Contacts) == 1 && len(r.Messages()) == 2 -// }, -// "contact request acceptance not received", -// ) -// s.logResponse(resp, "acceptContactRequest") -// s.Require().NoError(err) -// s.Require().NotNil(resp) - -// // Check activity center notification is of the right type -// s.Require().Len(resp.ActivityCenterNotifications(), 1) -// s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) -// s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, true) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Accepted, true) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Dismissed, false) -// s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - -// // Make sure the message is updated, sender side -// s.Require().Len(resp.Messages(), 2) - -// contactRequestMsg = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) -// s.Require().NotNil(contactRequestMsg) - -// mutualStateUpdate = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED) -// s.Require().NotNil(mutualStateUpdate) - -// s.Require().Equal(contactRequest.ID, contactRequestMsg.ID) -// s.Require().Equal(contactRequest.Text, contactRequestMsg.Text) -// s.Require().Equal(common.ContactRequestStateAccepted, contactRequestMsg.ContactRequestState) - -// s.Require().Equal(mutualStateUpdate.From, contactRequestMsg.ChatId) -// s.Require().Equal(mutualStateUpdate.ChatId, contactRequestMsg.ChatId) -// s.Require().Equal(mutualStateUpdate.Text, fmt.Sprintf(incomingMutualStateEventAcceptedDefaultText, contactRequestMsg.ChatId)) - -// // Make sure we consider them a mutual contact, sender side -// mutualContacts = s.m.MutualContacts() -// s.Require().Len(mutualContacts, 1) - -// // Check the contact state is correctly set -// s.Require().Len(resp.Contacts, 1) -// contact := resp.Contacts[0] -// s.Require().True(contact.mutual()) - -// // Check contact's primary name matches notification's name -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Name, contact.PrimaryName()) - -// // Sender's side chat should be active after the accepting the CR -// chat, ok := s.m.allChats.Load(contact.ID) -// s.Require().True(ok) -// s.Require().NotNil(chat) -// s.Require().True(chat.Active) - -// // Receiver's side chat should be also active after the accepting the CR -// myID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) -// chat, ok = receiver.allChats.Load(myID) -// s.Require().True(ok) -// s.Require().NotNil(chat) -// s.Require().True(chat.Active) -// } - -// func (s *MessengerContactRequestSuite) checkMutualContact(messenger *Messenger, contactPublicKey string) { -// contacts := messenger.AddedContacts() -// s.Require().Len(contacts, 1) -// contact := contacts[0] -// s.Require().Equal(contactPublicKey, contact.ID) -// s.Require().True(contact.mutual()) -// } - -// func (s *MessengerContactRequestSuite) createContactRequest(contactPublicKey string, messageText string) *requests.SendContactRequest { -// return &requests.SendContactRequest{ -// ID: contactPublicKey, -// Message: messageText, -// } -// } - -// func (s *MessengerContactRequestSuite) declineContactRequest(contactRequest *common.Message, theirMessenger *Messenger) { -// // Dismiss contact request, receiver side -// resp, err := theirMessenger.DeclineContactRequest(context.Background(), &requests.DeclineContactRequest{ID: types.Hex2Bytes(contactRequest.ID)}) -// s.Require().NoError(err) - -// // Check the contact state is correctly set -// s.Require().Len(resp.Contacts, 1) -// s.Require().Equal(ContactRequestStateDismissed, resp.Contacts[0].ContactRequestLocalState) - -// // Make sure the message is updated -// s.Require().NotNil(resp) -// s.Require().Len(resp.Messages(), 1) -// s.Require().Equal(resp.Messages()[0].ID, contactRequest.ID) -// s.Require().Equal(common.ContactRequestStateDismissed, resp.Messages()[0].ContactRequestState) - -// s.Require().Len(resp.ActivityCenterNotifications(), 1) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequest.ID) -// s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, true) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Accepted, false) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Dismissed, true) -// s.Require().Equal(common.ContactRequestStateDismissed, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - -// // Check contact's primary name matches notification's name -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Name, resp.Contacts[0].PrimaryName()) - -// // Make sure the sender is not added to our contacts -// contacts := theirMessenger.AddedContacts() -// s.Require().Len(contacts, 0) -// } - -// func (s *MessengerContactRequestSuite) retractContactRequest(contactID string, theirMessenger *Messenger) { -// resp, err := s.m.RetractContactRequest(&requests.RetractContactRequest{ID: types.Hex2Bytes(contactID)}) -// s.Require().NoError(err) -// s.Require().NotNil(resp) -// s.Require().Len(resp.Contacts, 1) -// s.Require().False(resp.Contacts[0].hasAddedUs()) -// s.Require().False(resp.Contacts[0].added()) - -// // Check the contact state is correctly set -// s.Require().Len(resp.Contacts, 1) -// s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestLocalState) -// s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestRemoteState) - -// // Check outgoing mutual state message -// s.Require().Len(resp.Messages(), 1) -// mutualStateUpdate := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_REMOVED) -// s.Require().NotNil(mutualStateUpdate) - -// myID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) -// s.Require().Equal(mutualStateUpdate.From, myID) -// s.Require().Equal(mutualStateUpdate.ChatId, contactID) -// s.Require().Equal(mutualStateUpdate.Text, fmt.Sprintf(outgoingMutualStateEventRemovedDefaultText, contactID)) - -// // Wait for the message to reach its destination -// resp, err = WaitOnMessengerResponse( -// theirMessenger, -// func(r *MessengerResponse) bool { -// return len(r.Contacts) > 0 && len(r.ActivityCenterNotifications()) == 1 -// }, -// "no messages", -// ) -// s.Require().NoError(err) -// s.Require().NotNil(resp) -// s.Require().Len(resp.Contacts, 1) - -// s.Require().Equal(myID, resp.Contacts[0].ID) - -// s.Require().False(resp.Contacts[0].added()) -// s.Require().False(resp.Contacts[0].hasAddedUs()) -// s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestLocalState) -// s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestRemoteState) - -// // Check pending notification -// s.Require().Len(resp.ActivityCenterNotifications(), 1) -// s.Require().Equal(ActivityCenterNotificationTypeContactRemoved, resp.ActivityCenterNotifications()[0].Type) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, false) - -// // Check incoming mutual state message -// s.Require().Len(resp.Messages(), 1) -// mutualStateUpdate = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_REMOVED) -// s.Require().NotNil(mutualStateUpdate) - -// s.Require().Equal(mutualStateUpdate.From, myID) -// s.Require().Equal(mutualStateUpdate.ChatId, myID) -// s.Require().Equal(mutualStateUpdate.Text, fmt.Sprintf(incomingMutualStateEventRemovedDefaultText, myID)) -// } - -// func (s *MessengerContactRequestSuite) syncInstallationContactV2FromContact(contact *Contact) protobuf.SyncInstallationContactV2 { -// return protobuf.SyncInstallationContactV2{ -// LastUpdatedLocally: contact.LastUpdatedLocally, -// LastUpdated: contact.LastUpdated, -// Id: contact.ID, -// DisplayName: contact.DisplayName, -// EnsName: contact.EnsName, -// LocalNickname: contact.LocalNickname, -// Added: contact.added(), -// Blocked: contact.Blocked, -// Muted: false, -// HasAddedUs: contact.hasAddedUs(), -// Removed: contact.Removed, -// ContactRequestLocalState: int64(contact.ContactRequestLocalState), -// ContactRequestRemoteState: int64(contact.ContactRequestRemoteState), -// ContactRequestRemoteClock: int64(contact.ContactRequestRemoteClock), -// ContactRequestLocalClock: int64(contact.ContactRequestLocalClock), -// VerificationStatus: int64(contact.VerificationStatus), -// TrustStatus: int64(contact.TrustStatus), -// } -// } - -// func (s *MessengerContactRequestSuite) TestReceiveAndAcceptContactRequest() { //nolint: unused -// messageText := "hello!" - -// theirMessenger := s.newMessenger() -// _, err := theirMessenger.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, theirMessenger) - -// contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) -// request := &requests.SendContactRequest{ -// ID: contactID, -// Message: messageText, -// } -// s.sendContactRequest(request, s.m) -// contactRequest := s.receiveContactRequest(messageText, theirMessenger) -// s.acceptContactRequest(contactRequest, s.m, theirMessenger) -// } - -// func (s *MessengerContactRequestSuite) TestReceiveAndDismissContactRequest() { -// messageText := "hello!" - -// theirMessenger := s.newMessenger() -// _, err := theirMessenger.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, theirMessenger) - -// contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) -// request := &requests.SendContactRequest{ -// ID: contactID, -// Message: messageText, -// } -// s.sendContactRequest(request, s.m) -// contactRequest := s.receiveContactRequest(messageText, theirMessenger) -// s.declineContactRequest(contactRequest, theirMessenger) -// } - -// func (s *MessengerContactRequestSuite) TestReceiveAcceptAndRetractContactRequest() { //nolint: unused -// messageText := "hello!" - -// theirMessenger := s.newMessenger() -// _, err := theirMessenger.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, theirMessenger) - -// s.Require().NoError(theirMessenger.settings.SaveSettingField(settings.MutualContactEnabled, true)) - -// contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) -// request := &requests.SendContactRequest{ -// ID: contactID, -// Message: messageText, -// } -// s.sendContactRequest(request, s.m) -// contactRequest := s.receiveContactRequest(messageText, theirMessenger) -// s.acceptContactRequest(contactRequest, s.m, theirMessenger) -// s.retractContactRequest(contactID, theirMessenger) -// } - -// // The scenario tested is as follow: -// // 1. Repeat 5 times: -// // 2.1) Alice sends a contact request to Bob -// // 2.2) Bob accepts the contact request -// // 2.3) Alice removes bob from contacts -// func (s *MessengerContactRequestSuite) TestAcceptCRRemoveAndRepeat() { -// theirMessenger := s.newMessenger() -// _, err := theirMessenger.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, theirMessenger) - -// contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) - -// for i := 0; i < 5; i++ { -// messageText := fmt.Sprintf("hello %d", i) -// request := &requests.SendContactRequest{ -// ID: contactID, -// Message: messageText, -// } -// s.sendContactRequest(request, s.m) -// contactRequest := s.receiveContactRequest(messageText, theirMessenger) -// s.acceptContactRequest(contactRequest, s.m, theirMessenger) -// s.retractContactRequest(contactID, theirMessenger) -// } -// } - -// // The scenario tested is as follow: -// // 1) Alice sends a contact request to Bob -// // 2) Bob declines the contact request -// // 3) Alice fails to send a new contact request to Bob -// func (s *MessengerContactRequestSuite) TestAliceTriesToSpamBobWithContactRequests() { -// messageTextAlice := "You wanna play with fire, Bobby?!" -// alice := s.m - -// bob := s.newMessenger() -// _, err := bob.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, bob) - -// bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) - -// // Alice sends a contact request to Bob -// request := &requests.SendContactRequest{ -// ID: bobID, -// Message: messageTextAlice, -// } -// s.sendContactRequest(request, alice) - -// contactRequest := s.receiveContactRequest(messageTextAlice, bob) -// s.Require().NotNil(contactRequest) - -// // Bob declines the contact request -// s.declineContactRequest(contactRequest, bob) - -// // Alice sends a new contact request -// resp, err := alice.SendContactRequest(context.Background(), request) -// s.Require().NoError(err) -// s.Require().NotNil(resp) - -// // Check CR and mutual state update messages -// s.Require().Len(resp.Messages(), 2) - -// contactRequest = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) -// s.Require().NotNil(contactRequest) - -// s.Require().Equal(common.ContactRequestStatePending, contactRequest.ContactRequestState) -// s.Require().Equal(request.Message, contactRequest.Text) - -// // We should not receive a CR from a rejected contact -// _, err = WaitOnMessengerResponse( -// bob, -// func(r *MessengerResponse) bool { -// return len(r.Messages()) > 0 && -// s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) != nil -// }, -// "no messages", -// ) -// s.Require().Error(err) -// s.Require().ErrorContains(err, "no messages") -// } - -// // The scenario tested is as follow: -// // 1) Alice sends a contact request to Bob -// // 2) Bob accepts the contact -// // 3) Bob accepts the contact request (again!) -// // 4) No extra mesages on Alice's side -// func (s *MessengerContactRequestSuite) TestAliceSeesOnlyOneAcceptFromBob() { -// messageTextAlice := "You wanna play with fire, Bobby?!" -// alice := s.m - -// bob := s.newMessenger() -// _, err := bob.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, bob) - -// bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) - -// // Alice sends a contact request to Bob -// request := &requests.SendContactRequest{ -// ID: bobID, -// Message: messageTextAlice, -// } -// s.sendContactRequest(request, alice) - -// contactRequest := s.receiveContactRequest(messageTextAlice, bob) -// s.Require().NotNil(contactRequest) - -// // Bob accepts the contact request -// s.acceptContactRequest(contactRequest, alice, bob) - -// // Accept contact request again -// _, err = bob.AcceptContactRequest(context.Background(), &requests.AcceptContactRequest{ID: types.Hex2Bytes(contactRequest.ID)}) -// s.Require().NoError(err) - -// // Check we don't have extra messages on Alice's side -// resp, err := WaitOnMessengerResponse(alice, -// func(r *MessengerResponse) bool { -// return len(r.ActivityCenterNotifications()) == 1 && len(r.Messages()) == 1 -// }, -// "contact request acceptance not received", -// ) -// s.Require().NoError(err) -// s.Require().NotNil(resp) - -// // Check activity center notification is of the right type -// s.Require().Len(resp.ActivityCenterNotifications(), 1) -// s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) -// s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, true) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Accepted, true) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Dismissed, false) -// s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) - -// // Make sure the message is updated, sender side -// s.Require().Len(resp.Messages(), 1) - -// contactRequest = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) -// s.Require().NotNil(contactRequest) - -// s.Require().Equal(common.ContactRequestStateAccepted, contactRequest.ContactRequestState) -// s.Require().Equal(request.Message, contactRequest.Text) -// } - -// func (s *MessengerContactRequestSuite) TestReceiveAndAcceptContactRequestTwice() { //nolint: unused -// messageText := "hello!" - -// theirMessenger := s.newMessenger() -// _, err := theirMessenger.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, theirMessenger) - -// contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) -// request := &requests.SendContactRequest{ -// ID: contactID, -// Message: messageText, -// } -// s.sendContactRequest(request, s.m) -// contactRequest := s.receiveContactRequest(messageText, theirMessenger) -// s.acceptContactRequest(contactRequest, s.m, theirMessenger) - -// // Resend contact request with higher clock value -// resp, err := s.m.SendContactRequest(context.Background(), request) -// s.Require().NoError(err) -// s.Require().NotNil(resp) - -// // Check CR and mutual state update messages -// s.Require().Len(resp.Messages(), 2) - -// contactRequest = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) -// s.Require().NotNil(contactRequest) - -// s.Require().Equal(common.ContactRequestStateAccepted, contactRequest.ContactRequestState) -// s.Require().Equal(request.Message, contactRequest.Text) - -// // We should not receive a CR from a mutual contact -// _, err = WaitOnMessengerResponse( -// theirMessenger, -// func(r *MessengerResponse) bool { -// return len(r.Messages()) > 0 && -// s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) != nil -// }, -// "no messages", -// ) -// s.Require().Error(err) -// s.Require().ErrorContains(err, "no messages") -// } - -// func (s *MessengerContactRequestSuite) TestAcceptLatestContactRequestForContact() { -// messageText := "hello!" - -// theirMessenger := s.newMessenger() -// _, err := theirMessenger.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, theirMessenger) - -// contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) -// request := &requests.SendContactRequest{ -// ID: contactID, -// Message: messageText, -// } -// s.sendContactRequest(request, s.m) -// contactRequest := s.receiveContactRequest(messageText, theirMessenger) - -// // Accept latest contact request, receiver side -// myID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) -// resp, err := theirMessenger.AcceptLatestContactRequestForContact(context.Background(), &requests.AcceptLatestContactRequestForContact{ID: types.Hex2Bytes(myID)}) -// s.Require().NoError(err) - -// // Make sure the message is updated -// s.Require().NotNil(resp) -// s.Require().Len(resp.Messages(), 2) - -// contactRequestMsg := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) -// s.Require().NotNil(contactRequestMsg) - -// mutualStateUpdate := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED) -// s.Require().NotNil(mutualStateUpdate) - -// s.Require().Equal(contactRequestMsg.ID, contactRequest.ID) -// s.Require().Equal(common.ContactRequestStateAccepted, contactRequestMsg.ContactRequestState) - -// s.Require().Equal(mutualStateUpdate.From, contactRequest.ChatId) -// s.Require().Equal(mutualStateUpdate.ChatId, contactRequest.From) - -// s.Require().Len(resp.ActivityCenterNotifications(), 1) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequest.ID) -// s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) -// s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - -// // Check the contact state is correctly set -// s.Require().Len(resp.Contacts, 1) -// s.Require().True(resp.Contacts[0].mutual()) - -// // Make sure the sender is added to our contacts -// contacts := theirMessenger.AddedContacts() -// s.Require().Len(contacts, 1) - -// // Make sure we consider them a mutual contact, receiver side -// mutualContacts := theirMessenger.MutualContacts() -// s.Require().Len(mutualContacts, 1) - -// // Wait for the message to reach its destination -// resp, err = WaitOnMessengerResponse( -// s.m, -// func(r *MessengerResponse) bool { -// return len(r.Contacts) == 1 && len(r.Messages()) == 2 && len(r.ActivityCenterNotifications()) == 1 -// }, -// "no messages", -// ) -// s.Require().NoError(err) - -// // Make sure the message is updated, sender side -// s.Require().NotNil(resp) - -// s.Require().Len(resp.Messages(), 2) - -// contactRequestMsg = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) -// s.Require().NotNil(contactRequestMsg) - -// mutualStateUpdate = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED) -// s.Require().NotNil(mutualStateUpdate) - -// s.Require().Equal(common.ContactRequestStateAccepted, contactRequestMsg.ContactRequestState) - -// s.Require().Equal(mutualStateUpdate.From, contactRequest.ChatId) -// s.Require().Equal(mutualStateUpdate.ChatId, contactRequest.ChatId) - -// // Check activity center notification is of the right type -// s.Require().Len(resp.ActivityCenterNotifications(), 1) -// s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) -// s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) -// s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - -// // Make sure we consider them a mutual contact, sender side -// mutualContacts = s.m.MutualContacts() -// s.Require().Len(mutualContacts, 1) - -// // Check the contact state is correctly set -// s.Require().Len(resp.Contacts, 1) -// s.Require().True(resp.Contacts[0].mutual()) -// } - -// func (s *MessengerContactRequestSuite) TestDismissLatestContactRequestForContact() { -// messageText := "hello!" - -// theirMessenger := s.newMessenger() -// _, err := theirMessenger.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, theirMessenger) - -// contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) -// request := &requests.SendContactRequest{ -// ID: contactID, -// Message: messageText, -// } -// s.sendContactRequest(request, s.m) -// contactRequest := s.receiveContactRequest(messageText, theirMessenger) - -// // Dismiss latest contact request, receiver side -// myID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) -// resp, err := theirMessenger.DismissLatestContactRequestForContact(context.Background(), &requests.DismissLatestContactRequestForContact{ID: types.Hex2Bytes(myID)}) -// s.Require().NoError(err) - -// // Make sure the message is updated -// s.Require().NotNil(resp) -// s.Require().Len(resp.Messages(), 1) -// s.Require().Equal(resp.Messages()[0].ID, contactRequest.ID) -// s.Require().Equal(common.ContactRequestStateDismissed, resp.Messages()[0].ContactRequestState) - -// s.Require().Len(resp.ActivityCenterNotifications(), 1) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequest.ID) -// s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) -// s.Require().Equal(common.ContactRequestStateDismissed, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) -// } - -// func (s *MessengerContactRequestSuite) TestPairedDevicesRemoveContact() { -// messageText := "hello!" - -// alice1 := s.m -// alice2, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, nil) -// s.Require().NoError(err) - -// _, err = alice2.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, alice2) - -// prepAliceMessengersForPairing(&s.Suite, alice1, alice2) - -// PairDevices(&s.Suite, alice1, alice2) -// PairDevices(&s.Suite, alice2, alice1) - -// bob := s.newMessenger() -// _, err = bob.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, bob) - -// // Alice sends a contact request to bob -// contactID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) -// request := &requests.SendContactRequest{ -// ID: contactID, -// Message: messageText, -// } -// s.sendContactRequest(request, alice1) -// contactRequest := s.receiveContactRequest(messageText, bob) -// s.acceptContactRequest(contactRequest, alice1, bob) - -// // Wait for the message to reach its destination -// resp, err := WaitOnMessengerResponse( -// alice2, -// func(r *MessengerResponse) bool { -// return len(r.Contacts) > 0 -// }, -// "no messages", -// ) -// s.Require().NoError(err) - -// // Make sure we consider them a mutual contact, sender side -// mutualContacts := alice2.MutualContacts() -// s.Require().Len(mutualContacts, 1) - -// // Check the contact state is correctly set -// s.Require().Len(resp.Contacts, 1) -// s.Require().True(resp.Contacts[0].mutual()) - -// s.retractContactRequest(contactID, bob) - -// // Check on alice2 side -// resp, err = WaitOnMessengerResponse( -// alice2, -// func(r *MessengerResponse) bool { -// return len(r.Contacts) > 0 -// }, -// "no messages", -// ) -// s.Require().NoError(err) -// s.Require().NotNil(resp) -// s.Require().Len(resp.Contacts, 1) - -// // Check the contact state is correctly set -// s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestLocalState) -// s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestRemoteState) -// } - -// // The scenario tested is as follow: -// // 1) Alice sends a contact request to Bob -// // 2) Bob accepts the contact request -// // 3) Alice restores state on a different device -// // 4) Alice sends a contact request to bob -// // Bob will need to help Alice recover her state, since as far as he can see -// // that's an already accepted contact request -// func (s *MessengerContactRequestSuite) TestAliceRecoverStateSendContactRequest() { -// messageText := "hello!" - -// alice1 := s.m - -// bob := s.newMessenger() -// _, err := bob.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, bob) - -// bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) - -// // Alice sends a contact request to bob -// request := &requests.SendContactRequest{ -// ID: bobID, -// Message: messageText, -// } -// s.sendContactRequest(request, alice1) - -// contactRequest := s.receiveContactRequest(messageText, bob) -// s.Require().NotNil(contactRequest) - -// // Bob accepts the contact request -// s.acceptContactRequest(contactRequest, alice1, bob) - -// // Alice resets her device -// alice2, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, nil) -// s.Require().NoError(err) - -// _, err = alice2.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, alice2) - -// // adds bob again to her device -// s.sendContactRequest(request, alice2) - -// // Wait for the message to reach its destination -// _, err = WaitOnMessengerResponse( -// bob, -// func(r *MessengerResponse) bool { -// return len(r.Contacts) > 0 -// }, -// "no messages", -// ) -// s.Require().NoError(err) - -// // Bob should be a mutual contact with alice, nothing has changed -// s.Require().Len(bob.MutualContacts(), 1) - -// // Alice retrieves her messages, she should have been notified by -// // dear bobby that they were contacts -// resp, err := WaitOnMessengerResponse( -// alice2, -// func(r *MessengerResponse) bool { -// return len(r.Contacts) > 0 -// }, -// "no messages", -// ) -// s.Require().NoError(err) -// s.Require().NotNil(resp) -// s.Require().Len(resp.Contacts, 1) - -// // Check the contact state is correctly set -// s.Require().True(resp.Contacts[0].mutual()) -// } - -// // The scenario tested is as follow: -// // 1) Alice sends a contact request to Bob -// // 2) Bob accepts the contact request -// // 3) Alice restores state on a different device -// // 4) Bob sends a message to alice -// // Alice will show a contact request from bob -// func (s *MessengerContactRequestSuite) TestAliceRecoverStateReceiveContactRequest() { -// messageText := "hello!" - -// alice1 := s.m - -// bob := s.newMessenger() -// _, err := bob.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, bob) - -// bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) - -// // Alice sends a contact request to bob -// request := &requests.SendContactRequest{ -// ID: bobID, -// Message: messageText, -// } -// s.sendContactRequest(request, alice1) - -// contactRequest := s.receiveContactRequest(messageText, bob) -// s.Require().NotNil(contactRequest) - -// // Bob accepts the contact request -// s.acceptContactRequest(contactRequest, alice1, bob) - -// // Alice resets her device -// alice2, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, nil) -// s.Require().NoError(err) - -// _, err = alice2.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, alice2) - -// // We want to facilitate the discovery of the x3dh bundl here, since bob does not know about alice device - -// alice2Bundle, err := alice2.encryptor.GetBundle(alice2.identity) -// s.Require().NoError(err) - -// _, err = bob.encryptor.ProcessPublicBundle(bob.identity, alice2Bundle) -// s.Require().NoError(err) - -// // Bob sends a chat message to alice - -// var chat Chat -// chats := bob.Chats() -// for i, c := range chats { -// if c.ID == alice1.myHexIdentity() && c.OneToOne() { -// chat = *chats[i] -// } -// } -// s.Require().NotNil(chat) - -// inputMessage := buildTestMessage(chat) -// _, err = bob.SendChatMessage(context.Background(), inputMessage) -// s.NoError(err) - -// // Alice retrieves the chat message, it should be -// resp, err := WaitOnMessengerResponse( -// alice2, -// func(r *MessengerResponse) bool { -// return len(r.ActivityCenterNotifications()) == 1 -// }, -// "no messages", -// ) -// s.Require().NoError(err) -// s.Require().NotNil(resp) -// s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) -// s.Require().Len(resp.Contacts, 1) - -// // Check the contact state is correctly set -// s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestLocalState) -// s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) -// } - -// // The scenario tested is as follow: -// // 1) Alice sends a contact request to Bob -// // 2) Bob accepts the contact request -// // 3) Bob goes offline -// // 4) Alice retracts the contact request -// // 5) Alice adds bob back to her contacts -// // 6) Bob goes online, they receive 4 and 5 in the correct order -// func (s *MessengerContactRequestSuite) TestAliceOfflineRetractsAndAddsCorrectOrder() { -// messageText := "hello!" - -// alice1 := s.m - -// bob := s.newMessenger() -// _, err := bob.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, bob) - -// bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) - -// // Alice sends a contact request to bob -// request := &requests.SendContactRequest{ -// ID: bobID, -// Message: messageText, -// } -// s.sendContactRequest(request, alice1) - -// contactRequest := s.receiveContactRequest(messageText, bob) -// s.Require().NotNil(contactRequest) - -// // Bob accepts the contact request -// s.acceptContactRequest(contactRequest, alice1, bob) - -// // Alice removes Bob from contacts -// _, err = alice1.RetractContactRequest(&requests.RetractContactRequest{ID: types.Hex2Bytes(bob.myHexIdentity())}) -// s.Require().NoError(err) - -// // Adds bob again to her device -// s.sendContactRequest(request, alice1) - -// // Wait for the message to reach its destination -// _, err = WaitOnMessengerResponse( -// bob, -// func(r *MessengerResponse) bool { -// return len(r.ActivityCenterNotifications()) > 0 -// }, -// "no messages", -// ) -// s.Require().NoError(err) -// } - -// // The scenario tested is as follow: -// // 1) Alice sends a contact request to Bob -// // 2) Bob accepts the contact request -// // 3) Bob goes offline -// // 4) Alice retracts the contact request -// // 5) Alice adds bob back to her contacts -// // 6) Bob goes online, they receive 4 and 5 in the wrong order -// func (s *MessengerContactRequestSuite) TestAliceOfflineRetractsAndAddsWrongOrder() { -// messageText := "hello!" - -// alice1 := s.m - -// bob := s.newMessenger() -// _, err := bob.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, bob) - -// bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) - -// // Alice sends a contact request to bob -// request := &requests.SendContactRequest{ -// ID: bobID, -// Message: messageText, -// } -// s.sendContactRequest(request, alice1) - -// contactRequest := s.receiveContactRequest(messageText, bob) -// s.Require().NotNil(contactRequest) - -// // Bob accepts the contact request -// s.acceptContactRequest(contactRequest, alice1, bob) - -// // Alice removes Bob from contacts -// _, err = alice1.RetractContactRequest(&requests.RetractContactRequest{ID: types.Hex2Bytes(bob.myHexIdentity())}) -// s.Require().NoError(err) - -// // Adds bob again to her device -// s.sendContactRequest(request, alice1) - -// // Get alice perspective of bob -// bobFromAlice := alice1.AddedContacts()[0] - -// // Get bob perspective of alice -// aliceFromBob := bob.MutualContacts()[0] - -// s.Require().NotNil(bobFromAlice) -// s.Require().NotNil(aliceFromBob) - -// // We can't simulate out-of-order messages easily, so we need to do -// // things manually here -// result := aliceFromBob.ContactRequestPropagatedStateReceived(bobFromAlice.ContactRequestPropagatedState()) -// s.Require().True(result.newContactRequestReceived) -// } - -// // The scenario tested is as follow: -// // 1) Alice sends a contact request to Bob -// // 2) Bob accepts the contact request -// // 3) Alice removes Bob from contacts -// // 4) Make sure Alice and Bob are not mutual contacts -// // 5) Alice sends new contact request -// // 6) Bob accepts new contact request -// func (s *MessengerContactRequestSuite) TestAliceResendsContactRequestAfterRemovingBobFromContacts() { -// messageTextFirst := "hello 1!" - -// theirMessenger := s.newMessenger() -// _, err := theirMessenger.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, theirMessenger) - -// contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) - -// // Alice sends a contact request to Bob -// request := &requests.SendContactRequest{ -// ID: contactID, -// Message: messageTextFirst, -// } -// s.sendContactRequest(request, s.m) - -// // Bob accepts the contact request -// contactRequest := s.receiveContactRequest(messageTextFirst, theirMessenger) -// s.Require().NotNil(contactRequest) -// s.acceptContactRequest(contactRequest, s.m, theirMessenger) - -// // Alice removes Bob from contacts -// s.retractContactRequest(contactID, theirMessenger) - -// // Send new contact request -// messageTextSecond := "hello 2!" - -// // Alice sends new contact request -// request = &requests.SendContactRequest{ -// ID: contactID, -// Message: messageTextSecond, -// } -// s.sendContactRequest(request, s.m) - -// // Make sure bob and alice are not mutual after sending CR -// s.Require().Len(s.m.MutualContacts(), 0) -// s.Require().Len(theirMessenger.MutualContacts(), 0) - -// // Bob accepts new contact request -// contactRequest = s.receiveContactRequest(messageTextSecond, theirMessenger) -// s.Require().NotNil(contactRequest) -// s.acceptContactRequest(contactRequest, s.m, theirMessenger) - -// // Make sure bob and alice are not mutual after sending CR -// s.Require().Len(s.m.MutualContacts(), 1) -// s.Require().Len(theirMessenger.MutualContacts(), 1) -// } - -// // The scenario tested is as follow: -// // 1) Alice sends a contact request to Bob -// // 2) Bob declines the contact request from Alice -// // 3) Bob sends a contact request to Alice -// // 4) Alice and Bob are mutual contacts (because Alice's CR is "pending" on her side), Both CRs are accepted -// func (s *MessengerContactRequestSuite) TestBobSendsContactRequestAfterDecliningOneFromAlice() { -// messageTextAlice := "hello, Bobby!" - -// alice := s.m - -// bob := s.newMessenger() -// _, err := bob.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, bob) - -// bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) - -// // Alice sends a contact request to bob -// requestFromAlice := &requests.SendContactRequest{ -// ID: bobID, -// Message: messageTextAlice, -// } -// s.sendContactRequest(requestFromAlice, alice) - -// contactRequest := s.receiveContactRequest(messageTextAlice, bob) -// s.Require().NotNil(contactRequest) - -// // Bob declines the contact request -// s.declineContactRequest(contactRequest, bob) - -// messageTextBob := "hello, Alice!" - -// aliceID := types.EncodeHex(crypto.FromECDSAPub(&alice.identity.PublicKey)) - -// // Bob sends a contact request to Alice -// requestFromBob := &requests.SendContactRequest{ -// ID: aliceID, -// Message: messageTextBob, -// } - -// // Send contact request -// resp, err := bob.SendContactRequest(context.Background(), requestFromBob) -// s.Require().NoError(err) -// s.Require().NotNil(resp) - -// // Check CR message, it should be accepted -// s.Require().Len(resp.Messages(), 2) - -// contactRequest = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) -// s.Require().NotNil(contactRequest) - -// s.Require().Equal(common.ContactRequestStateAccepted, contactRequest.ContactRequestState) -// s.Require().Equal(requestFromBob.Message, contactRequest.Text) - -// // Check pending notification -// s.Require().Len(resp.ActivityCenterNotifications(), 1) -// s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) -// s.Require().Equal(contactRequest.ID, resp.ActivityCenterNotifications()[0].Message.ID) -// s.Require().Equal(contactRequest.ContactRequestState, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, true) - -// // Check contacts Bob's side -// s.Require().Len(resp.Contacts, 1) -// contact := resp.Contacts[0] -// s.Require().True(contact.mutual()) -// } - -// func (s *MessengerContactRequestSuite) TestBuildContact() { -// contactKey, err := crypto.GenerateKey() -// s.Require().NoError(err) -// contactID := types.EncodeHex(crypto.FromECDSAPub(&contactKey.PublicKey)) - -// contact, err := s.m.BuildContact(&requests.BuildContact{PublicKey: contactID}) -// s.Require().NoError(err) - -// s.Require().Equal(contact.EnsName, "") -// s.Require().False(contact.ENSVerified) - -// contact, err = s.m.BuildContact(&requests.BuildContact{PublicKey: contactID, ENSName: "foobar"}) -// s.Require().NoError(err) - -// s.Require().Equal(contact.EnsName, "foobar") -// s.Require().True(contact.ENSVerified) -// } - -// func (s *MessengerContactRequestSuite) TestReceiveAcceptAndRetractContactRequestOutOfOrder() { -// message := protobuf.ChatMessage{ -// Clock: 4, -// Timestamp: 1, -// Text: "some text", -// ChatId: common.PubkeyToHex(&s.m.identity.PublicKey), -// MessageType: protobuf.MessageType_ONE_TO_ONE, -// ContentType: protobuf.ChatMessage_CONTACT_REQUEST, -// } - -// contactKey, err := crypto.GenerateKey() -// s.Require().NoError(err) - -// contact, err := BuildContactFromPublicKey(&contactKey.PublicKey) -// s.Require().NoError(err) - -// state := s.m.buildMessageState() - -// state.CurrentMessageState = &CurrentMessageState{ -// PublicKey: &contactKey.PublicKey, -// MessageID: "0xa", -// StatusMessage: &v1protocol.StatusMessage{TransportLayer: v1protocol.TransportLayer{Message: &types.Message{Timestamp: 1}}, ApplicationLayer: v1protocol.ApplicationLayer{ID: []byte("test-id")}}, -// Contact: contact, -// WhisperTimestamp: 1, -// } - -// response := state.Response -// err = s.m.HandleChatMessage(state, &message, nil, false) -// s.Require().NoError(err) -// s.Require().Len(response.ActivityCenterNotifications(), 1) -// contacts := s.m.Contacts() -// s.Require().Len(contacts, 1) -// s.Require().Equal(ContactRequestStateReceived, contacts[0].ContactRequestRemoteState) - -// retract := protobuf.RetractContactRequest{ -// Clock: 2, -// } -// err = s.m.HandleRetractContactRequest(state, &retract, nil) -// s.Require().NoError(err) - -// // Nothing should have changed -// contacts = s.m.Contacts() -// s.Require().Len(contacts, 1) -// s.Require().Equal(ContactRequestStateReceived, contacts[0].ContactRequestRemoteState) -// } - -// // The scenario tested is as follow: -// // 1) Alice sends a contact request to Bob -// // 2) Bob receives CR from Alice -// // 3) Bob resets his device -// // 4) Bob restores Alice's contact from backup, CR is created -// // 5) Bob succesefully accepts restored contact request -// // 6) Alice get notified properly -// func (s *MessengerContactRequestSuite) TestBobRestoresIncomingContactRequestFromSyncInstallationContactV2() { -// messageText := "hello, Bobby!" - -// alice := s.m - -// bob1 := s.newMessenger() -// _, err := bob1.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, bob1) - -// aliceID := types.EncodeHex(crypto.FromECDSAPub(&alice.identity.PublicKey)) -// bobID := types.EncodeHex(crypto.FromECDSAPub(&bob1.identity.PublicKey)) - -// // Alice sends a contact request to bob -// requestFromAlice := &requests.SendContactRequest{ -// ID: bobID, -// Message: messageText, -// } -// s.sendContactRequest(requestFromAlice, alice) - -// // Bob receives CR from Alice -// contactRequest := s.receiveContactRequest(messageText, bob1) -// s.Require().NotNil(contactRequest) - -// // Bob resets his device -// bob2, err := newMessengerWithKey(s.shh, bob1.identity, s.logger, nil) -// s.Require().NoError(err) - -// _, err = bob2.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, bob2) - -// // Get bob perspective of alice for backup -// aliceFromBob := bob1.Contacts()[0] -// state := bob2.buildMessageState() - -// // Restore alice's contact from backup -// sync := s.syncInstallationContactV2FromContact(aliceFromBob) -// err = bob2.HandleSyncInstallationContactV2(state, &sync, nil) -// s.Require().NoError(err) - -// // Accept latest CR for a contact -// resp, err := bob2.AcceptLatestContactRequestForContact(context.Background(), &requests.AcceptLatestContactRequestForContact{ID: types.Hex2Bytes(aliceID)}) -// s.Require().NoError(err) - -// // Make sure the message is updated -// s.Require().NotNil(resp) -// s.Require().Len(resp.Messages(), 2) - -// contactRequestMsg := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) -// s.Require().NotNil(contactRequestMsg) - -// // NOTE: We don't restore CR message -// // s.Require().Equal(resp.Messages()[0].ID, contactRequest.ID) -// s.Require().Equal(common.ContactRequestStateAccepted, contactRequestMsg.ContactRequestState) - -// s.Require().Len(resp.ActivityCenterNotifications(), 1) -// s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) -// s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - -// // Check the contact state is correctly set -// s.Require().Len(resp.Contacts, 1) -// s.Require().True(resp.Contacts[0].mutual()) - -// // Make sure the sender is added to our contacts -// contacts := bob2.AddedContacts() -// s.Require().Len(contacts, 1) - -// // Make sure we consider them a mutual contact, receiver side -// mutualContacts := bob2.MutualContacts() -// s.Require().Len(mutualContacts, 1) -// } - -// // The scenario tested is as follow: -// // 1) Alice sends a contact request to Bob -// // 2) Bob receives CR from Alice -// // 3) Alice resets her device -// // 4) Alice restores Bob's contact from backup, CR is created -// // 5) Bob accepts contact request -// // 6) Alice get notified properly -// func (s *MessengerContactRequestSuite) TestAliceRestoresOutgoingContactRequestFromSyncInstallationContactV2() { -// messageText := "hello, Bobby!" - -// alice1 := s.m - -// bob := s.newMessenger() -// _, err := bob.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, bob) - -// aliceID := types.EncodeHex(crypto.FromECDSAPub(&alice1.identity.PublicKey)) -// bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) - -// // Alice sends a contact request to bob -// requestFromAlice := &requests.SendContactRequest{ -// ID: bobID, -// Message: messageText, -// } -// s.sendContactRequest(requestFromAlice, alice1) - -// // Bob receives CR from Alice -// contactRequest := s.receiveContactRequest(messageText, bob) -// s.Require().NotNil(contactRequest) - -// // Bob resets his device -// alice2, err := newMessengerWithKey(s.shh, alice1.identity, s.logger, nil) -// s.Require().NoError(err) - -// _, err = alice2.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, alice2) - -// // Get bob perspective of alice for backup -// bobFromAlice := alice1.Contacts()[0] -// state := alice2.buildMessageState() - -// // Restore alice's contact from backup -// sync := s.syncInstallationContactV2FromContact(bobFromAlice) -// err = alice2.HandleSyncInstallationContactV2(state, &sync, nil) -// s.Require().NoError(err) - -// // Accept latest CR for a contact -// resp, err := bob.AcceptLatestContactRequestForContact(context.Background(), &requests.AcceptLatestContactRequestForContact{ID: types.Hex2Bytes(aliceID)}) -// s.Require().NoError(err) - -// // Make sure the message is updated -// s.Require().NotNil(resp) -// s.Require().Len(resp.Messages(), 2) - -// contactRequestMsg := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) -// s.Require().NotNil(contactRequestMsg) - -// // NOTE: We don't restore CR message -// // s.Require().Equal(resp.Messages()[0].ID, contactRequest.ID) -// s.Require().Equal(common.ContactRequestStateAccepted, contactRequestMsg.ContactRequestState) - -// s.Require().Len(resp.ActivityCenterNotifications(), 1) -// s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) -// s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) - -// // Check the contact state is correctly set -// s.Require().Len(resp.Contacts, 1) -// s.Require().True(resp.Contacts[0].mutual()) - -// // Make sure the sender is added to our contacts -// contacts := bob.AddedContacts() -// s.Require().Len(contacts, 1) - -// // Make sure we consider them a mutual contact, receiver side -// mutualContacts := bob.MutualContacts() -// s.Require().Len(mutualContacts, 1) -// } - -// /* -// Makes Alice and Bob mutual contacts. -// Verifies that Alice device-2 receives mutual contact information. -// Contact request is sent from Alice device 1. -// */ -// func (s *MessengerContactRequestSuite) makeMutualContactsAndSync(alice1 *Messenger, alice2 *Messenger, bob *Messenger, messageText string) { -// bobPublicKey := bob.IdentityPublicKeyString() - -// cr := s.createContactRequest(bobPublicKey, messageText) -// s.sendContactRequest(cr, alice1) -// receivedCR := s.receiveContactRequest(cr.Message, bob) -// s.acceptContactRequest(receivedCR, alice1, bob) -// s.checkMutualContact(alice1, bobPublicKey) - -// // Wait for Alice-2 to sync new contact -// resp, _ := WaitOnMessengerResponse(alice2, func(r *MessengerResponse) bool { -// // FIXME: https://github.com/status-im/status-go/issues/3803 -// // No condition here. There are randomly received 1-3 messages. -// return false // len(r.Contacts) == 1 && len(r.Messages()) == 3 -// }, "alice-2 didn't receive bob contact") -// s.logResponse(resp, "Wait for Alice-2 to sync new contact") -// s.Require().NotNil(resp) -// //s.Require().NoError(err) // WARNING: Uncomment when bug fixed. https://github.com/status-im/status-go/issues/3803 - -// // Check that Alice-2 has Bob as a contact -// s.Require().Len(alice2.Contacts(), 1) -// s.Require().Equal(bobPublicKey, alice2.Contacts()[0].ID) - -// // TODO: https://github.com/status-im/status-go/issues/3803 -// // Check response messages and AC notifications when -// } - -// func (s *MessengerContactRequestSuite) blockContactAndSync(alice1 *Messenger, alice2 *Messenger, bob *Messenger) { -// bobPublicKey := bob.IdentityPublicKeyString() -// bobDisplayName, err := bob.settings.DisplayName() -// s.Require().NoError(err) - -// // Alice-1 blocks Bob -// _, err = alice1.BlockContact(context.Background(), bobPublicKey, false) -// s.Require().NoError(err) -// s.Require().Len(alice1.BlockedContacts(), 1) -// s.Require().Equal(bobPublicKey, alice1.BlockedContacts()[0].ID) - -// // Wait for Bob to receive message that he was removed as contact -// resp, err := WaitOnMessengerResponse(bob, func(r *MessengerResponse) bool { -// return len(r.Contacts) == 1 && len(r.Messages()) == 1 -// }, "Bob didn't receive a message that he was removed as contact") - -// s.Require().NoError(err) -// s.Require().NotNil(resp) -// s.logResponse(resp, "Wait for Bob to receive message that he was removed as contact") - -// // Check response contacts -// s.Require().Len(resp.Contacts, 1) -// respContact := resp.Contacts[0] -// s.Require().Equal(respContact.ID, alice1.IdentityPublicKeyString()) -// s.Require().Equal(ContactRequestStateNone, respContact.ContactRequestLocalState) -// s.Require().Equal(ContactRequestStateNone, respContact.ContactRequestRemoteState) - -// // Check response messages -// s.Require().Len(resp.Messages(), 1) -// s.Require().Equal(resp.Messages()[0].Text, fmt.Sprintf(incomingMutualStateEventRemovedDefaultText, alice1.IdentityPublicKeyString())) - -// // Check response AC notifications -// s.Require().Len(resp.ActivityCenterNotifications(), 1) -// s.Require().Equal(resp.ActivityCenterNotifications()[0].Type, ActivityCenterNotificationTypeContactRemoved) - -// alice2.logger.Info("STARTING") -// // Wait for Alice-2 to sync Bob blocked state -// resp, err = WaitOnMessengerResponse(alice2, func(r *MessengerResponse) bool { -// return len(r.Contacts) == 1 -// }, "Alice-2 didn't receive blocking bob") -// s.logResponse(resp, "Wait for Alice-2 to sync Bob blocked state") -// s.Require().NoError(err) -// s.Require().NotNil(resp) - -// // Check that Bob contact is synced with correct display name and blocked -// s.Require().Len(alice2.Contacts(), 1) -// respContact = alice2.Contacts()[0] -// s.Require().True(respContact.Blocked) -// s.Require().True(respContact.Removed) -// s.Require().Equal(bobPublicKey, respContact.ID) -// s.Require().Equal(bobDisplayName, respContact.DisplayName) -// s.Require().Equal(ContactRequestStateDismissed, respContact.ContactRequestLocalState) -// s.Require().Equal(ContactRequestStateReceived, respContact.ContactRequestRemoteState) - -// // Check chats list -// s.Require().Len(alice2.Chats(), deprecation.AddChatsCount(2)) -// } - -// func (s *MessengerContactRequestSuite) unblockContactAndSync(alice1 *Messenger, alice2 *Messenger, bob *Messenger) { -// bobPublicKey := bob.IdentityPublicKeyString() - -// _, err := alice1.UnblockContact(bobPublicKey) -// s.Require().NoError(err) -// s.Require().Len(alice1.BlockedContacts(), 0) - -// // Bob doesn't receive any message on blocking. -// // No response wait here. - -// // Wait for Alice-2 to receive Bob unblocked state -// resp, err := WaitOnMessengerResponse(alice2, func(r *MessengerResponse) bool { -// return len(r.Contacts) == 1 -// }, "Alice-2 didn't receive Bob unblocked state") -// s.logResponse(resp, "Wait for Alice-2 to receive Bob unblocked state") -// s.Require().NoError(err) -// s.Require().NotNil(resp) - -// // Check that Alice-2 has Bob unblocked and removed -// s.Require().Len(alice2.Contacts(), 1) -// respContact := alice2.Contacts()[0] -// s.Require().Equal(bobPublicKey, respContact.ID) -// s.Require().False(respContact.Blocked) -// s.Require().True(respContact.Removed) -// s.Require().Equal(respContact.ContactRequestLocalState, ContactRequestStateNone) -// s.Require().Equal(respContact.ContactRequestRemoteState, ContactRequestStateNone) - -// // Check chats list -// s.Require().Len(alice2.Chats(), deprecation.AddChatsCount(2)) -// } - -// func (s *MessengerContactRequestSuite) TestBlockedContactSyncing() { -// // Setup Bob -// bob := s.newMessenger() -// _, err := bob.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, bob) -// _ = bob.SetDisplayName("bob-1") -// s.logger.Info("Bob account set up", zap.String("publicKey", bob.IdentityPublicKeyString())) - -// // Setup Alice-1 -// alice1 := s.m -// s.logger.Info("Alice account set up", zap.String("publicKey", alice1.IdentityPublicKeyString())) - -// // Setup Alice-2 -// alice2, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, nil) -// s.Require().NoError(err) -// _, err = alice2.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, alice2) - -// // Pair alice-1 <-> alice-2 -// // NOTE: This doesn't include initial data sync. Local pairing could be used. -// s.logger.Info("pairing Alice-1 and Alice-2") -// prepAliceMessengersForPairing(&s.Suite, alice1, alice2) -// PairDevices(&s.Suite, alice1, alice2) -// PairDevices(&s.Suite, alice2, alice1) -// s.logger.Info("pairing Alice-1 and Alice-2 finished") - -// // Loop cr-block-unblock. Some bugs happen at second iteration. -// for i := 0; i < 2; i++ { -// crText := fmt.Sprintf("hello-%d", i) -// s.makeMutualContactsAndSync(alice1, alice2, bob, crText) -// s.blockContactAndSync(alice1, alice2, bob) -// s.unblockContactAndSync(alice1, alice2, bob) -// } -// } +type MessengerContactRequestSuite struct { + MessengerBaseTestSuite +} + +func (s *MessengerContactRequestSuite) findFirstByContentType(messages []*common.Message, contentType protobuf.ChatMessage_ContentType) *common.Message { + return FindFirstByContentType(messages, contentType) +} + +func (s *MessengerContactRequestSuite) sendContactRequest(request *requests.SendContactRequest, messenger *Messenger) { + s.logger.Info("sendContactRequest", zap.String("sender", messenger.IdentityPublicKeyString()), zap.String("receiver", request.ID)) + + // Send contact request + resp, err := messenger.SendContactRequest(context.Background(), request) + s.Require().NoError(err) + s.Require().NotNil(resp) + + // Check CR and mutual state update messages + s.Require().Len(resp.Messages(), 2) + + mutualStateUpdate := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_SENT) + s.Require().NotNil(mutualStateUpdate) + + s.Require().NotNil(mutualStateUpdate.ID) + s.Require().Equal(mutualStateUpdate.From, messenger.myHexIdentity()) + s.Require().Equal(mutualStateUpdate.ChatId, request.ID) + s.Require().Equal(mutualStateUpdate.Text, fmt.Sprintf(outgoingMutualStateEventSentDefaultText, request.ID)) + + contactRequest := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) + s.Require().NotNil(contactRequest) + + s.Require().Equal(common.ContactRequestStatePending, contactRequest.ContactRequestState) + s.Require().Equal(request.Message, contactRequest.Text) + + // Check pending notification + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) + s.Require().Equal(contactRequest.ID, resp.ActivityCenterNotifications()[0].Message.ID) + s.Require().Equal(contactRequest.ContactRequestState, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, true) + + // Check contacts + s.Require().Len(resp.Contacts, 1) + contact := resp.Contacts[0] + s.Require().False(contact.mutual()) + + // Make sure it's not returned as coming from us + contactRequests, _, err := messenger.PendingContactRequests("", 10) + s.Require().NoError(err) + s.Require().Len(contactRequests, 0) + + // Make sure contact is added on the sender side + contacts := messenger.AddedContacts() + s.Require().Len(contacts, 1) + s.Require().Equal(ContactRequestStateSent, contacts[0].ContactRequestLocalState) + s.Require().NotNil(contacts[0].DisplayName) + + // Check contact's primary name matches notification's name + s.Require().Equal(resp.ActivityCenterNotifications()[0].Name, contacts[0].PrimaryName()) +} + +func (s *MessengerContactRequestSuite) receiveContactRequest(messageText string, theirMessenger *Messenger) *common.Message { + s.logger.Info("receiveContactRequest", zap.String("receiver", theirMessenger.IdentityPublicKeyString())) + + // Wait for the message to reach its destination + resp, err := WaitOnMessengerResponse( + theirMessenger, + func(r *MessengerResponse) bool { + return len(r.Contacts) == 1 && len(r.Messages()) >= 2 && len(r.ActivityCenterNotifications()) == 1 + }, + "no messages", + ) + + // Check contact request has been received + s.Require().NoError(err) + s.Require().NotNil(resp) + + // Check CR and mutual state update messages + s.Require().Len(resp.Messages(), 2) + + contactRequest := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) + s.Require().NotNil(contactRequest) + + s.Require().Equal(common.ContactRequestStatePending, contactRequest.ContactRequestState) + s.Require().Equal(messageText, contactRequest.Text) + + mutualStateUpdate := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_SENT) + s.Require().NotNil(mutualStateUpdate) + + s.Require().Equal(mutualStateUpdate.From, contactRequest.From) + s.Require().Equal(mutualStateUpdate.ChatId, contactRequest.From) + s.Require().Equal(mutualStateUpdate.Text, fmt.Sprintf(incomingMutualStateEventSentDefaultText, contactRequest.From)) + + // Check activity center notification is of the right type + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) + s.Require().Equal(contactRequest.ID, resp.ActivityCenterNotifications()[0].Message.ID) + s.Require().Equal(contactRequest.ContactRequestState, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, false) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Accepted, false) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Dismissed, false) + + notifications, err := theirMessenger.ActivityCenterNotifications(ActivityCenterNotificationsRequest{ + Cursor: "", + Limit: 10, + ActivityTypes: []ActivityCenterType{ActivityCenterNotificationTypeContactRequest}, + ReadType: ActivityCenterQueryParamsReadUnread, + }, + ) + s.Require().NoError(err) + s.Require().Len(notifications.Notifications, 1) + s.Require().Equal(contactRequest.ID, notifications.Notifications[0].Message.ID) + s.Require().Equal(contactRequest.ContactRequestState, notifications.Notifications[0].Message.ContactRequestState) + + // Check the contact state is correctly set + s.Require().Len(resp.Contacts, 1) + contact := resp.Contacts[0] + s.Require().Equal(ContactRequestStateReceived, contact.ContactRequestRemoteState) + + // Check contact's primary name matches notification's name + s.Require().Equal(resp.ActivityCenterNotifications()[0].Name, contact.PrimaryName()) + + // Make sure it's the latest pending contact requests + contactRequests, _, err := theirMessenger.PendingContactRequests("", 10) + s.Require().NoError(err) + s.Require().Greater(len(contactRequests), 0) + s.Require().Equal(contactRequests[0].ID, contactRequest.ID) + + return contactRequest +} + +// This function partially logs given MessengerResponse with description. +// This is helpful for testing response content during long tests. +// Logged contents: Messages, Contacts, ActivityCenterNotifications +func (s *MessengerContactRequestSuite) logResponse(response *MessengerResponse, description string) { + s.logger.Debug("MessengerResponse", zap.String("description", description)) + + for i, message := range response.Messages() { + s.logger.Debug("message", + zap.Int("index", i), + zap.String("Text", message.Text), + zap.Any("ContentType", message.ContentType), + ) + } + + for i, contact := range response.Contacts { + s.logger.Debug("contact", + zap.Int("index", i), + zap.Bool("Blocked", contact.Blocked), + zap.Bool("Removed", contact.Removed), + zap.Any("crRemoteState", contact.ContactRequestLocalState), + zap.Any("crLocalState", contact.ContactRequestRemoteState), + ) + } + + for i, notification := range response.ActivityCenterNotifications() { + messageText := "" + if notification.Message != nil { + messageText = notification.Message.Text + } + s.logger.Debug("acNotification", + zap.Int("index", i), + zap.Any("id", notification.ID), + zap.Any("Type", notification.Type), + zap.String("Message", messageText), + zap.String("Name", notification.Name), + zap.String("Author", notification.Author), + ) + } +} + +func (s *MessengerContactRequestSuite) acceptContactRequest( + contactRequest *common.Message, sender *Messenger, receiver *Messenger) { + s.logger.Info("acceptContactRequest", + zap.String("sender", sender.IdentityPublicKeyString()), + zap.String("receiver", receiver.IdentityPublicKeyString())) + + // Accept contact request, receiver side + resp, err := receiver.AcceptContactRequest(context.Background(), &requests.AcceptContactRequest{ID: types.Hex2Bytes(contactRequest.ID)}) + s.Require().NoError(err) + + // Chack updated contact request message and mutual state update + s.Require().NotNil(resp) + s.Require().Len(resp.Messages(), 2) + + contactRequestMsg := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) + s.Require().NotNil(contactRequestMsg) + + mutualStateUpdate := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED) + s.Require().NotNil(mutualStateUpdate) + + s.Require().Equal(contactRequestMsg.ID, contactRequest.ID) + s.Require().Equal(common.ContactRequestStateAccepted, contactRequestMsg.ContactRequestState) + + s.Require().Equal(mutualStateUpdate.ChatId, contactRequestMsg.From) + s.Require().Equal(mutualStateUpdate.From, contactRequestMsg.ChatId) + s.Require().Equal(mutualStateUpdate.Text, fmt.Sprintf(outgoingMutualStateEventAcceptedDefaultText, contactRequestMsg.From)) + + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequest.ID) + s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) + s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) + + // Check the contact state is correctly set + s.Require().Len(resp.Contacts, 1) + s.Require().True(resp.Contacts[0].mutual()) + + // Check contact's primary name matches notification's name + s.Require().Equal(resp.ActivityCenterNotifications()[0].Name, resp.Contacts[0].PrimaryName()) + + // Check we have active chat in the response + s.Require().Len(resp.Chats(), 1) + s.Require().True(resp.Chats()[0].Active) + + // Make sure the sender is added to our contacts + contacts := receiver.AddedContacts() + s.Require().Len(contacts, 1) + + // Make sure we consider them a mutual contact, receiver side + mutualContacts := receiver.MutualContacts() + s.Require().Len(mutualContacts, 1) + + // Wait for the message to reach its destination + resp, err = WaitOnMessengerResponse(sender, + func(r *MessengerResponse) bool { + return len(r.Contacts) == 1 && len(r.Messages()) == 2 + }, + "contact request acceptance not received", + ) + s.logResponse(resp, "acceptContactRequest") + s.Require().NoError(err) + s.Require().NotNil(resp) + + // Check activity center notification is of the right type + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) + s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, true) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Accepted, true) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Dismissed, false) + s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) + + // Make sure the message is updated, sender side + s.Require().Len(resp.Messages(), 2) + + contactRequestMsg = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) + s.Require().NotNil(contactRequestMsg) + + mutualStateUpdate = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED) + s.Require().NotNil(mutualStateUpdate) + + s.Require().Equal(contactRequest.ID, contactRequestMsg.ID) + s.Require().Equal(contactRequest.Text, contactRequestMsg.Text) + s.Require().Equal(common.ContactRequestStateAccepted, contactRequestMsg.ContactRequestState) + + s.Require().Equal(mutualStateUpdate.From, contactRequestMsg.ChatId) + s.Require().Equal(mutualStateUpdate.ChatId, contactRequestMsg.ChatId) + s.Require().Equal(mutualStateUpdate.Text, fmt.Sprintf(incomingMutualStateEventAcceptedDefaultText, contactRequestMsg.ChatId)) + + // Make sure we consider them a mutual contact, sender side + mutualContacts = s.m.MutualContacts() + s.Require().Len(mutualContacts, 1) + + // Check the contact state is correctly set + s.Require().Len(resp.Contacts, 1) + contact := resp.Contacts[0] + s.Require().True(contact.mutual()) + + // Check contact's primary name matches notification's name + s.Require().Equal(resp.ActivityCenterNotifications()[0].Name, contact.PrimaryName()) + + // Sender's side chat should be active after the accepting the CR + chat, ok := s.m.allChats.Load(contact.ID) + s.Require().True(ok) + s.Require().NotNil(chat) + s.Require().True(chat.Active) + + // Receiver's side chat should be also active after the accepting the CR + myID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) + chat, ok = receiver.allChats.Load(myID) + s.Require().True(ok) + s.Require().NotNil(chat) + s.Require().True(chat.Active) +} + +func (s *MessengerContactRequestSuite) checkMutualContact(messenger *Messenger, contactPublicKey string) { + contacts := messenger.AddedContacts() + s.Require().Len(contacts, 1) + contact := contacts[0] + s.Require().Equal(contactPublicKey, contact.ID) + s.Require().True(contact.mutual()) +} + +func (s *MessengerContactRequestSuite) createContactRequest(contactPublicKey string, messageText string) *requests.SendContactRequest { + return &requests.SendContactRequest{ + ID: contactPublicKey, + Message: messageText, + } +} + +func (s *MessengerContactRequestSuite) declineContactRequest(contactRequest *common.Message, theirMessenger *Messenger) { + // Dismiss contact request, receiver side + resp, err := theirMessenger.DeclineContactRequest(context.Background(), &requests.DeclineContactRequest{ID: types.Hex2Bytes(contactRequest.ID)}) + s.Require().NoError(err) + + // Check the contact state is correctly set + s.Require().Len(resp.Contacts, 1) + s.Require().Equal(ContactRequestStateDismissed, resp.Contacts[0].ContactRequestLocalState) + + // Make sure the message is updated + s.Require().NotNil(resp) + s.Require().Len(resp.Messages(), 1) + s.Require().Equal(resp.Messages()[0].ID, contactRequest.ID) + s.Require().Equal(common.ContactRequestStateDismissed, resp.Messages()[0].ContactRequestState) + + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequest.ID) + s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, true) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Accepted, false) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Dismissed, true) + s.Require().Equal(common.ContactRequestStateDismissed, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) + + // Check contact's primary name matches notification's name + s.Require().Equal(resp.ActivityCenterNotifications()[0].Name, resp.Contacts[0].PrimaryName()) + + // Make sure the sender is not added to our contacts + contacts := theirMessenger.AddedContacts() + s.Require().Len(contacts, 0) +} + +func (s *MessengerContactRequestSuite) retractContactRequest(contactID string, theirMessenger *Messenger) { + resp, err := s.m.RetractContactRequest(&requests.RetractContactRequest{ID: types.Hex2Bytes(contactID)}) + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Contacts, 1) + s.Require().False(resp.Contacts[0].hasAddedUs()) + s.Require().False(resp.Contacts[0].added()) + + // Check the contact state is correctly set + s.Require().Len(resp.Contacts, 1) + s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestLocalState) + s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestRemoteState) + + // Check outgoing mutual state message + s.Require().Len(resp.Messages(), 1) + mutualStateUpdate := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_REMOVED) + s.Require().NotNil(mutualStateUpdate) + + myID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) + s.Require().Equal(mutualStateUpdate.From, myID) + s.Require().Equal(mutualStateUpdate.ChatId, contactID) + s.Require().Equal(mutualStateUpdate.Text, fmt.Sprintf(outgoingMutualStateEventRemovedDefaultText, contactID)) + + // Wait for the message to reach its destination + resp, err = WaitOnMessengerResponse( + theirMessenger, + func(r *MessengerResponse) bool { + return len(r.Contacts) > 0 && len(r.ActivityCenterNotifications()) == 1 + }, + "no messages", + ) + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Contacts, 1) + + s.Require().Equal(myID, resp.Contacts[0].ID) + + s.Require().False(resp.Contacts[0].added()) + s.Require().False(resp.Contacts[0].hasAddedUs()) + s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestLocalState) + s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestRemoteState) + + // Check pending notification + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().Equal(ActivityCenterNotificationTypeContactRemoved, resp.ActivityCenterNotifications()[0].Type) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, false) + + // Check incoming mutual state message + s.Require().Len(resp.Messages(), 1) + mutualStateUpdate = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_REMOVED) + s.Require().NotNil(mutualStateUpdate) + + s.Require().Equal(mutualStateUpdate.From, myID) + s.Require().Equal(mutualStateUpdate.ChatId, myID) + s.Require().Equal(mutualStateUpdate.Text, fmt.Sprintf(incomingMutualStateEventRemovedDefaultText, myID)) +} + +func (s *MessengerContactRequestSuite) syncInstallationContactV2FromContact(contact *Contact) protobuf.SyncInstallationContactV2 { + return protobuf.SyncInstallationContactV2{ + LastUpdatedLocally: contact.LastUpdatedLocally, + LastUpdated: contact.LastUpdated, + Id: contact.ID, + DisplayName: contact.DisplayName, + EnsName: contact.EnsName, + LocalNickname: contact.LocalNickname, + Added: contact.added(), + Blocked: contact.Blocked, + Muted: false, + HasAddedUs: contact.hasAddedUs(), + Removed: contact.Removed, + ContactRequestLocalState: int64(contact.ContactRequestLocalState), + ContactRequestRemoteState: int64(contact.ContactRequestRemoteState), + ContactRequestRemoteClock: int64(contact.ContactRequestRemoteClock), + ContactRequestLocalClock: int64(contact.ContactRequestLocalClock), + VerificationStatus: int64(contact.VerificationStatus), + TrustStatus: int64(contact.TrustStatus), + } +} + +func (s *MessengerContactRequestSuite) TestReceiveAndAcceptContactRequest() { //nolint: unused + messageText := "hello!" + + theirMessenger := s.newMessenger() + _, err := theirMessenger.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, theirMessenger) + + contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageText, + } + s.sendContactRequest(request, s.m) + contactRequest := s.receiveContactRequest(messageText, theirMessenger) + s.acceptContactRequest(contactRequest, s.m, theirMessenger) +} + +func (s *MessengerContactRequestSuite) TestReceiveAndDismissContactRequest() { + messageText := "hello!" + + theirMessenger := s.newMessenger() + _, err := theirMessenger.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, theirMessenger) + + contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageText, + } + s.sendContactRequest(request, s.m) + contactRequest := s.receiveContactRequest(messageText, theirMessenger) + s.declineContactRequest(contactRequest, theirMessenger) +} + +func (s *MessengerContactRequestSuite) TestReceiveAcceptAndRetractContactRequest() { //nolint: unused + messageText := "hello!" + + theirMessenger := s.newMessenger() + _, err := theirMessenger.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, theirMessenger) + + s.Require().NoError(theirMessenger.settings.SaveSettingField(settings.MutualContactEnabled, true)) + + contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageText, + } + s.sendContactRequest(request, s.m) + contactRequest := s.receiveContactRequest(messageText, theirMessenger) + s.acceptContactRequest(contactRequest, s.m, theirMessenger) + s.retractContactRequest(contactID, theirMessenger) +} + +// The scenario tested is as follow: +// 1. Repeat 5 times: +// 2.1) Alice sends a contact request to Bob +// 2.2) Bob accepts the contact request +// 2.3) Alice removes bob from contacts +func (s *MessengerContactRequestSuite) TestAcceptCRRemoveAndRepeat() { + theirMessenger := s.newMessenger() + _, err := theirMessenger.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, theirMessenger) + + contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) + + for i := 0; i < 5; i++ { + messageText := fmt.Sprintf("hello %d", i) + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageText, + } + s.sendContactRequest(request, s.m) + contactRequest := s.receiveContactRequest(messageText, theirMessenger) + s.acceptContactRequest(contactRequest, s.m, theirMessenger) + s.retractContactRequest(contactID, theirMessenger) + } +} + +// The scenario tested is as follow: +// 1) Alice sends a contact request to Bob +// 2) Bob declines the contact request +// 3) Alice fails to send a new contact request to Bob +func (s *MessengerContactRequestSuite) TestAliceTriesToSpamBobWithContactRequests() { + messageTextAlice := "You wanna play with fire, Bobby?!" + alice := s.m + + bob := s.newMessenger() + _, err := bob.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, bob) + + bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) + + // Alice sends a contact request to Bob + request := &requests.SendContactRequest{ + ID: bobID, + Message: messageTextAlice, + } + s.sendContactRequest(request, alice) + + contactRequest := s.receiveContactRequest(messageTextAlice, bob) + s.Require().NotNil(contactRequest) + + // Bob declines the contact request + s.declineContactRequest(contactRequest, bob) + + // Alice sends a new contact request + resp, err := alice.SendContactRequest(context.Background(), request) + s.Require().NoError(err) + s.Require().NotNil(resp) + + // Check CR and mutual state update messages + s.Require().Len(resp.Messages(), 2) + + contactRequest = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) + s.Require().NotNil(contactRequest) + + s.Require().Equal(common.ContactRequestStatePending, contactRequest.ContactRequestState) + s.Require().Equal(request.Message, contactRequest.Text) + + // We should not receive a CR from a rejected contact + _, err = WaitOnMessengerResponse( + bob, + func(r *MessengerResponse) bool { + return len(r.Messages()) > 0 && + s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) != nil + }, + "no messages", + ) + s.Require().Error(err) + s.Require().ErrorContains(err, "no messages") +} + +// The scenario tested is as follow: +// 1) Alice sends a contact request to Bob +// 2) Bob accepts the contact +// 3) Bob accepts the contact request (again!) +// 4) No extra mesages on Alice's side +func (s *MessengerContactRequestSuite) TestAliceSeesOnlyOneAcceptFromBob() { + messageTextAlice := "You wanna play with fire, Bobby?!" + alice := s.m + + bob := s.newMessenger() + _, err := bob.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, bob) + + bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) + + // Alice sends a contact request to Bob + request := &requests.SendContactRequest{ + ID: bobID, + Message: messageTextAlice, + } + s.sendContactRequest(request, alice) + + contactRequest := s.receiveContactRequest(messageTextAlice, bob) + s.Require().NotNil(contactRequest) + + // Bob accepts the contact request + s.acceptContactRequest(contactRequest, alice, bob) + + // Accept contact request again + _, err = bob.AcceptContactRequest(context.Background(), &requests.AcceptContactRequest{ID: types.Hex2Bytes(contactRequest.ID)}) + s.Require().NoError(err) + + // Check we don't have extra messages on Alice's side + resp, err := WaitOnMessengerResponse(alice, + func(r *MessengerResponse) bool { + return len(r.ActivityCenterNotifications()) == 1 && len(r.Messages()) == 1 + }, + "contact request acceptance not received", + ) + s.Require().NoError(err) + s.Require().NotNil(resp) + + // Check activity center notification is of the right type + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) + s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, true) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Accepted, true) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Dismissed, false) + s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) + + // Make sure the message is updated, sender side + s.Require().Len(resp.Messages(), 1) + + contactRequest = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) + s.Require().NotNil(contactRequest) + + s.Require().Equal(common.ContactRequestStateAccepted, contactRequest.ContactRequestState) + s.Require().Equal(request.Message, contactRequest.Text) +} + +func (s *MessengerContactRequestSuite) TestReceiveAndAcceptContactRequestTwice() { //nolint: unused + messageText := "hello!" + + theirMessenger := s.newMessenger() + _, err := theirMessenger.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, theirMessenger) + + contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageText, + } + s.sendContactRequest(request, s.m) + contactRequest := s.receiveContactRequest(messageText, theirMessenger) + s.acceptContactRequest(contactRequest, s.m, theirMessenger) + + // Resend contact request with higher clock value + resp, err := s.m.SendContactRequest(context.Background(), request) + s.Require().NoError(err) + s.Require().NotNil(resp) + + // Check CR and mutual state update messages + s.Require().Len(resp.Messages(), 2) + + contactRequest = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) + s.Require().NotNil(contactRequest) + + s.Require().Equal(common.ContactRequestStateAccepted, contactRequest.ContactRequestState) + s.Require().Equal(request.Message, contactRequest.Text) + + // We should not receive a CR from a mutual contact + _, err = WaitOnMessengerResponse( + theirMessenger, + func(r *MessengerResponse) bool { + return len(r.Messages()) > 0 && + s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) != nil + }, + "no messages", + ) + s.Require().Error(err) + s.Require().ErrorContains(err, "no messages") +} + +func (s *MessengerContactRequestSuite) TestAcceptLatestContactRequestForContact() { + messageText := "hello!" + + theirMessenger := s.newMessenger() + _, err := theirMessenger.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, theirMessenger) + + contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageText, + } + s.sendContactRequest(request, s.m) + contactRequest := s.receiveContactRequest(messageText, theirMessenger) + + // Accept latest contact request, receiver side + myID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) + resp, err := theirMessenger.AcceptLatestContactRequestForContact(context.Background(), &requests.AcceptLatestContactRequestForContact{ID: types.Hex2Bytes(myID)}) + s.Require().NoError(err) + + // Make sure the message is updated + s.Require().NotNil(resp) + s.Require().Len(resp.Messages(), 2) + + contactRequestMsg := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) + s.Require().NotNil(contactRequestMsg) + + mutualStateUpdate := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED) + s.Require().NotNil(mutualStateUpdate) + + s.Require().Equal(contactRequestMsg.ID, contactRequest.ID) + s.Require().Equal(common.ContactRequestStateAccepted, contactRequestMsg.ContactRequestState) + + s.Require().Equal(mutualStateUpdate.From, contactRequest.ChatId) + s.Require().Equal(mutualStateUpdate.ChatId, contactRequest.From) + + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequest.ID) + s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) + s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) + + // Check the contact state is correctly set + s.Require().Len(resp.Contacts, 1) + s.Require().True(resp.Contacts[0].mutual()) + + // Make sure the sender is added to our contacts + contacts := theirMessenger.AddedContacts() + s.Require().Len(contacts, 1) + + // Make sure we consider them a mutual contact, receiver side + mutualContacts := theirMessenger.MutualContacts() + s.Require().Len(mutualContacts, 1) + + // Wait for the message to reach its destination + resp, err = WaitOnMessengerResponse( + s.m, + func(r *MessengerResponse) bool { + return len(r.Contacts) == 1 && len(r.Messages()) == 2 && len(r.ActivityCenterNotifications()) == 1 + }, + "no messages", + ) + s.Require().NoError(err) + + // Make sure the message is updated, sender side + s.Require().NotNil(resp) + + s.Require().Len(resp.Messages(), 2) + + contactRequestMsg = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) + s.Require().NotNil(contactRequestMsg) + + mutualStateUpdate = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED) + s.Require().NotNil(mutualStateUpdate) + + s.Require().Equal(common.ContactRequestStateAccepted, contactRequestMsg.ContactRequestState) + + s.Require().Equal(mutualStateUpdate.From, contactRequest.ChatId) + s.Require().Equal(mutualStateUpdate.ChatId, contactRequest.ChatId) + + // Check activity center notification is of the right type + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) + s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) + s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) + + // Make sure we consider them a mutual contact, sender side + mutualContacts = s.m.MutualContacts() + s.Require().Len(mutualContacts, 1) + + // Check the contact state is correctly set + s.Require().Len(resp.Contacts, 1) + s.Require().True(resp.Contacts[0].mutual()) +} + +func (s *MessengerContactRequestSuite) TestDismissLatestContactRequestForContact() { + messageText := "hello!" + + theirMessenger := s.newMessenger() + _, err := theirMessenger.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, theirMessenger) + + contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageText, + } + s.sendContactRequest(request, s.m) + contactRequest := s.receiveContactRequest(messageText, theirMessenger) + + // Dismiss latest contact request, receiver side + myID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) + resp, err := theirMessenger.DismissLatestContactRequestForContact(context.Background(), &requests.DismissLatestContactRequestForContact{ID: types.Hex2Bytes(myID)}) + s.Require().NoError(err) + + // Make sure the message is updated + s.Require().NotNil(resp) + s.Require().Len(resp.Messages(), 1) + s.Require().Equal(resp.Messages()[0].ID, contactRequest.ID) + s.Require().Equal(common.ContactRequestStateDismissed, resp.Messages()[0].ContactRequestState) + + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().Equal(resp.ActivityCenterNotifications()[0].ID.String(), contactRequest.ID) + s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) + s.Require().Equal(common.ContactRequestStateDismissed, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) +} + +func (s *MessengerContactRequestSuite) TestPairedDevicesRemoveContact() { + messageText := "hello!" + + alice1 := s.m + alice2, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, nil) + s.Require().NoError(err) + + _, err = alice2.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, alice2) + + prepAliceMessengersForPairing(&s.Suite, alice1, alice2) + + PairDevices(&s.Suite, alice1, alice2) + PairDevices(&s.Suite, alice2, alice1) + + bob := s.newMessenger() + _, err = bob.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, bob) + + // Alice sends a contact request to bob + contactID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageText, + } + s.sendContactRequest(request, alice1) + contactRequest := s.receiveContactRequest(messageText, bob) + s.acceptContactRequest(contactRequest, alice1, bob) + + // Wait for the message to reach its destination + resp, err := WaitOnMessengerResponse( + alice2, + func(r *MessengerResponse) bool { + return len(r.Contacts) > 0 + }, + "no messages", + ) + s.Require().NoError(err) + + // Make sure we consider them a mutual contact, sender side + mutualContacts := alice2.MutualContacts() + s.Require().Len(mutualContacts, 1) + + // Check the contact state is correctly set + s.Require().Len(resp.Contacts, 1) + s.Require().True(resp.Contacts[0].mutual()) + + s.retractContactRequest(contactID, bob) + + // Check on alice2 side + resp, err = WaitOnMessengerResponse( + alice2, + func(r *MessengerResponse) bool { + return len(r.Contacts) > 0 + }, + "no messages", + ) + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Contacts, 1) + + // Check the contact state is correctly set + s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestLocalState) + s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestRemoteState) +} + +// The scenario tested is as follow: +// 1) Alice sends a contact request to Bob +// 2) Bob accepts the contact request +// 3) Alice restores state on a different device +// 4) Alice sends a contact request to bob +// Bob will need to help Alice recover her state, since as far as he can see +// that's an already accepted contact request +func (s *MessengerContactRequestSuite) TestAliceRecoverStateSendContactRequest() { + messageText := "hello!" + + alice1 := s.m + + bob := s.newMessenger() + _, err := bob.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, bob) + + bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) + + // Alice sends a contact request to bob + request := &requests.SendContactRequest{ + ID: bobID, + Message: messageText, + } + s.sendContactRequest(request, alice1) + + contactRequest := s.receiveContactRequest(messageText, bob) + s.Require().NotNil(contactRequest) + + // Bob accepts the contact request + s.acceptContactRequest(contactRequest, alice1, bob) + + // Alice resets her device + alice2, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, nil) + s.Require().NoError(err) + + _, err = alice2.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, alice2) + + // adds bob again to her device + s.sendContactRequest(request, alice2) + + // Wait for the message to reach its destination + _, err = WaitOnMessengerResponse( + bob, + func(r *MessengerResponse) bool { + return len(r.Contacts) > 0 + }, + "no messages", + ) + s.Require().NoError(err) + + // Bob should be a mutual contact with alice, nothing has changed + s.Require().Len(bob.MutualContacts(), 1) + + // Alice retrieves her messages, she should have been notified by + // dear bobby that they were contacts + resp, err := WaitOnMessengerResponse( + alice2, + func(r *MessengerResponse) bool { + return len(r.Contacts) > 0 + }, + "no messages", + ) + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Contacts, 1) + + // Check the contact state is correctly set + s.Require().True(resp.Contacts[0].mutual()) +} + +// The scenario tested is as follow: +// 1) Alice sends a contact request to Bob +// 2) Bob accepts the contact request +// 3) Alice restores state on a different device +// 4) Bob sends a message to alice +// Alice will show a contact request from bob +func (s *MessengerContactRequestSuite) TestAliceRecoverStateReceiveContactRequest() { + messageText := "hello!" + + alice1 := s.m + + bob := s.newMessenger() + _, err := bob.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, bob) + + bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) + + // Alice sends a contact request to bob + request := &requests.SendContactRequest{ + ID: bobID, + Message: messageText, + } + s.sendContactRequest(request, alice1) + + contactRequest := s.receiveContactRequest(messageText, bob) + s.Require().NotNil(contactRequest) + + // Bob accepts the contact request + s.acceptContactRequest(contactRequest, alice1, bob) + + // Alice resets her device + alice2, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, nil) + s.Require().NoError(err) + + _, err = alice2.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, alice2) + + // We want to facilitate the discovery of the x3dh bundl here, since bob does not know about alice device + + alice2Bundle, err := alice2.encryptor.GetBundle(alice2.identity) + s.Require().NoError(err) + + _, err = bob.encryptor.ProcessPublicBundle(bob.identity, alice2Bundle) + s.Require().NoError(err) + + // Bob sends a chat message to alice + + var chat Chat + chats := bob.Chats() + for i, c := range chats { + if c.ID == alice1.myHexIdentity() && c.OneToOne() { + chat = *chats[i] + } + } + s.Require().NotNil(chat) + + inputMessage := buildTestMessage(chat) + _, err = bob.SendChatMessage(context.Background(), inputMessage) + s.NoError(err) + + // Alice retrieves the chat message, it should be + resp, err := WaitOnMessengerResponse( + alice2, + func(r *MessengerResponse) bool { + return len(r.ActivityCenterNotifications()) == 1 + }, + "no messages", + ) + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) + s.Require().Len(resp.Contacts, 1) + + // Check the contact state is correctly set + s.Require().Equal(ContactRequestStateNone, resp.Contacts[0].ContactRequestLocalState) + s.Require().Equal(ContactRequestStateReceived, resp.Contacts[0].ContactRequestRemoteState) +} + +// The scenario tested is as follow: +// 1) Alice sends a contact request to Bob +// 2) Bob accepts the contact request +// 3) Bob goes offline +// 4) Alice retracts the contact request +// 5) Alice adds bob back to her contacts +// 6) Bob goes online, they receive 4 and 5 in the correct order +func (s *MessengerContactRequestSuite) TestAliceOfflineRetractsAndAddsCorrectOrder() { + messageText := "hello!" + + alice1 := s.m + + bob := s.newMessenger() + _, err := bob.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, bob) + + bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) + + // Alice sends a contact request to bob + request := &requests.SendContactRequest{ + ID: bobID, + Message: messageText, + } + s.sendContactRequest(request, alice1) + + contactRequest := s.receiveContactRequest(messageText, bob) + s.Require().NotNil(contactRequest) + + // Bob accepts the contact request + s.acceptContactRequest(contactRequest, alice1, bob) + + // Alice removes Bob from contacts + _, err = alice1.RetractContactRequest(&requests.RetractContactRequest{ID: types.Hex2Bytes(bob.myHexIdentity())}) + s.Require().NoError(err) + + // Adds bob again to her device + s.sendContactRequest(request, alice1) + + // Wait for the message to reach its destination + _, err = WaitOnMessengerResponse( + bob, + func(r *MessengerResponse) bool { + return len(r.ActivityCenterNotifications()) > 0 + }, + "no messages", + ) + s.Require().NoError(err) +} + +// The scenario tested is as follow: +// 1) Alice sends a contact request to Bob +// 2) Bob accepts the contact request +// 3) Bob goes offline +// 4) Alice retracts the contact request +// 5) Alice adds bob back to her contacts +// 6) Bob goes online, they receive 4 and 5 in the wrong order +func (s *MessengerContactRequestSuite) TestAliceOfflineRetractsAndAddsWrongOrder() { + messageText := "hello!" + + alice1 := s.m + + bob := s.newMessenger() + _, err := bob.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, bob) + + bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) + + // Alice sends a contact request to bob + request := &requests.SendContactRequest{ + ID: bobID, + Message: messageText, + } + s.sendContactRequest(request, alice1) + + contactRequest := s.receiveContactRequest(messageText, bob) + s.Require().NotNil(contactRequest) + + // Bob accepts the contact request + s.acceptContactRequest(contactRequest, alice1, bob) + + // Alice removes Bob from contacts + _, err = alice1.RetractContactRequest(&requests.RetractContactRequest{ID: types.Hex2Bytes(bob.myHexIdentity())}) + s.Require().NoError(err) + + // Adds bob again to her device + s.sendContactRequest(request, alice1) + + // Get alice perspective of bob + bobFromAlice := alice1.AddedContacts()[0] + + // Get bob perspective of alice + aliceFromBob := bob.MutualContacts()[0] + + s.Require().NotNil(bobFromAlice) + s.Require().NotNil(aliceFromBob) + + // We can't simulate out-of-order messages easily, so we need to do + // things manually here + result := aliceFromBob.ContactRequestPropagatedStateReceived(bobFromAlice.ContactRequestPropagatedState()) + s.Require().True(result.newContactRequestReceived) +} + +// The scenario tested is as follow: +// 1) Alice sends a contact request to Bob +// 2) Bob accepts the contact request +// 3) Alice removes Bob from contacts +// 4) Make sure Alice and Bob are not mutual contacts +// 5) Alice sends new contact request +// 6) Bob accepts new contact request +func (s *MessengerContactRequestSuite) TestAliceResendsContactRequestAfterRemovingBobFromContacts() { + messageTextFirst := "hello 1!" + + theirMessenger := s.newMessenger() + _, err := theirMessenger.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, theirMessenger) + + contactID := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) + + // Alice sends a contact request to Bob + request := &requests.SendContactRequest{ + ID: contactID, + Message: messageTextFirst, + } + s.sendContactRequest(request, s.m) + + // Bob accepts the contact request + contactRequest := s.receiveContactRequest(messageTextFirst, theirMessenger) + s.Require().NotNil(contactRequest) + s.acceptContactRequest(contactRequest, s.m, theirMessenger) + + // Alice removes Bob from contacts + s.retractContactRequest(contactID, theirMessenger) + + // Send new contact request + messageTextSecond := "hello 2!" + + // Alice sends new contact request + request = &requests.SendContactRequest{ + ID: contactID, + Message: messageTextSecond, + } + s.sendContactRequest(request, s.m) + + // Make sure bob and alice are not mutual after sending CR + s.Require().Len(s.m.MutualContacts(), 0) + s.Require().Len(theirMessenger.MutualContacts(), 0) + + // Bob accepts new contact request + contactRequest = s.receiveContactRequest(messageTextSecond, theirMessenger) + s.Require().NotNil(contactRequest) + s.acceptContactRequest(contactRequest, s.m, theirMessenger) + + // Make sure bob and alice are not mutual after sending CR + s.Require().Len(s.m.MutualContacts(), 1) + s.Require().Len(theirMessenger.MutualContacts(), 1) +} + +// The scenario tested is as follow: +// 1) Alice sends a contact request to Bob +// 2) Bob declines the contact request from Alice +// 3) Bob sends a contact request to Alice +// 4) Alice and Bob are mutual contacts (because Alice's CR is "pending" on her side), Both CRs are accepted +func (s *MessengerContactRequestSuite) TestBobSendsContactRequestAfterDecliningOneFromAlice() { + messageTextAlice := "hello, Bobby!" + + alice := s.m + + bob := s.newMessenger() + _, err := bob.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, bob) + + bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) + + // Alice sends a contact request to bob + requestFromAlice := &requests.SendContactRequest{ + ID: bobID, + Message: messageTextAlice, + } + s.sendContactRequest(requestFromAlice, alice) + + contactRequest := s.receiveContactRequest(messageTextAlice, bob) + s.Require().NotNil(contactRequest) + + // Bob declines the contact request + s.declineContactRequest(contactRequest, bob) + + messageTextBob := "hello, Alice!" + + aliceID := types.EncodeHex(crypto.FromECDSAPub(&alice.identity.PublicKey)) + + // Bob sends a contact request to Alice + requestFromBob := &requests.SendContactRequest{ + ID: aliceID, + Message: messageTextBob, + } + + // Send contact request + resp, err := bob.SendContactRequest(context.Background(), requestFromBob) + s.Require().NoError(err) + s.Require().NotNil(resp) + + // Check CR message, it should be accepted + s.Require().Len(resp.Messages(), 2) + + contactRequest = s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) + s.Require().NotNil(contactRequest) + + s.Require().Equal(common.ContactRequestStateAccepted, contactRequest.ContactRequestState) + s.Require().Equal(requestFromBob.Message, contactRequest.Text) + + // Check pending notification + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().Equal(ActivityCenterNotificationTypeContactRequest, resp.ActivityCenterNotifications()[0].Type) + s.Require().Equal(contactRequest.ID, resp.ActivityCenterNotifications()[0].Message.ID) + s.Require().Equal(contactRequest.ContactRequestState, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Read, true) + + // Check contacts Bob's side + s.Require().Len(resp.Contacts, 1) + contact := resp.Contacts[0] + s.Require().True(contact.mutual()) +} + +func (s *MessengerContactRequestSuite) TestBuildContact() { + contactKey, err := crypto.GenerateKey() + s.Require().NoError(err) + contactID := types.EncodeHex(crypto.FromECDSAPub(&contactKey.PublicKey)) + + contact, err := s.m.BuildContact(&requests.BuildContact{PublicKey: contactID}) + s.Require().NoError(err) + + s.Require().Equal(contact.EnsName, "") + s.Require().False(contact.ENSVerified) + + contact, err = s.m.BuildContact(&requests.BuildContact{PublicKey: contactID, ENSName: "foobar"}) + s.Require().NoError(err) + + s.Require().Equal(contact.EnsName, "foobar") + s.Require().True(contact.ENSVerified) +} + +func (s *MessengerContactRequestSuite) TestReceiveAcceptAndRetractContactRequestOutOfOrder() { + message := protobuf.ChatMessage{ + Clock: 4, + Timestamp: 1, + Text: "some text", + ChatId: common.PubkeyToHex(&s.m.identity.PublicKey), + MessageType: protobuf.MessageType_ONE_TO_ONE, + ContentType: protobuf.ChatMessage_CONTACT_REQUEST, + } + + contactKey, err := crypto.GenerateKey() + s.Require().NoError(err) + + contact, err := BuildContactFromPublicKey(&contactKey.PublicKey) + s.Require().NoError(err) + + state := s.m.buildMessageState() + + state.CurrentMessageState = &CurrentMessageState{ + PublicKey: &contactKey.PublicKey, + MessageID: "0xa", + StatusMessage: &v1protocol.StatusMessage{TransportLayer: v1protocol.TransportLayer{Message: &types.Message{Timestamp: 1}}, ApplicationLayer: v1protocol.ApplicationLayer{ID: []byte("test-id")}}, + Contact: contact, + WhisperTimestamp: 1, + } + + response := state.Response + err = s.m.HandleChatMessage(state, &message, nil, false) + s.Require().NoError(err) + s.Require().Len(response.ActivityCenterNotifications(), 1) + contacts := s.m.Contacts() + s.Require().Len(contacts, 1) + s.Require().Equal(ContactRequestStateReceived, contacts[0].ContactRequestRemoteState) + + retract := protobuf.RetractContactRequest{ + Clock: 2, + } + err = s.m.HandleRetractContactRequest(state, &retract, nil) + s.Require().NoError(err) + + // Nothing should have changed + contacts = s.m.Contacts() + s.Require().Len(contacts, 1) + s.Require().Equal(ContactRequestStateReceived, contacts[0].ContactRequestRemoteState) +} + +// The scenario tested is as follow: +// 1) Alice sends a contact request to Bob +// 2) Bob receives CR from Alice +// 3) Bob resets his device +// 4) Bob restores Alice's contact from backup, CR is created +// 5) Bob succesefully accepts restored contact request +// 6) Alice get notified properly +func (s *MessengerContactRequestSuite) TestBobRestoresIncomingContactRequestFromSyncInstallationContactV2() { + messageText := "hello, Bobby!" + + alice := s.m + + bob1 := s.newMessenger() + _, err := bob1.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, bob1) + + aliceID := types.EncodeHex(crypto.FromECDSAPub(&alice.identity.PublicKey)) + bobID := types.EncodeHex(crypto.FromECDSAPub(&bob1.identity.PublicKey)) + + // Alice sends a contact request to bob + requestFromAlice := &requests.SendContactRequest{ + ID: bobID, + Message: messageText, + } + s.sendContactRequest(requestFromAlice, alice) + + // Bob receives CR from Alice + contactRequest := s.receiveContactRequest(messageText, bob1) + s.Require().NotNil(contactRequest) + + // Bob resets his device + bob2, err := newMessengerWithKey(s.shh, bob1.identity, s.logger, nil) + s.Require().NoError(err) + + _, err = bob2.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, bob2) + + // Get bob perspective of alice for backup + aliceFromBob := bob1.Contacts()[0] + state := bob2.buildMessageState() + + // Restore alice's contact from backup + sync := s.syncInstallationContactV2FromContact(aliceFromBob) + err = bob2.HandleSyncInstallationContactV2(state, &sync, nil) + s.Require().NoError(err) + + // Accept latest CR for a contact + resp, err := bob2.AcceptLatestContactRequestForContact(context.Background(), &requests.AcceptLatestContactRequestForContact{ID: types.Hex2Bytes(aliceID)}) + s.Require().NoError(err) + + // Make sure the message is updated + s.Require().NotNil(resp) + s.Require().Len(resp.Messages(), 2) + + contactRequestMsg := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) + s.Require().NotNil(contactRequestMsg) + + // NOTE: We don't restore CR message + // s.Require().Equal(resp.Messages()[0].ID, contactRequest.ID) + s.Require().Equal(common.ContactRequestStateAccepted, contactRequestMsg.ContactRequestState) + + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) + s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) + + // Check the contact state is correctly set + s.Require().Len(resp.Contacts, 1) + s.Require().True(resp.Contacts[0].mutual()) + + // Make sure the sender is added to our contacts + contacts := bob2.AddedContacts() + s.Require().Len(contacts, 1) + + // Make sure we consider them a mutual contact, receiver side + mutualContacts := bob2.MutualContacts() + s.Require().Len(mutualContacts, 1) +} + +// The scenario tested is as follow: +// 1) Alice sends a contact request to Bob +// 2) Bob receives CR from Alice +// 3) Alice resets her device +// 4) Alice restores Bob's contact from backup, CR is created +// 5) Bob accepts contact request +// 6) Alice get notified properly +func (s *MessengerContactRequestSuite) TestAliceRestoresOutgoingContactRequestFromSyncInstallationContactV2() { + messageText := "hello, Bobby!" + + alice1 := s.m + + bob := s.newMessenger() + _, err := bob.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, bob) + + aliceID := types.EncodeHex(crypto.FromECDSAPub(&alice1.identity.PublicKey)) + bobID := types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) + + // Alice sends a contact request to bob + requestFromAlice := &requests.SendContactRequest{ + ID: bobID, + Message: messageText, + } + s.sendContactRequest(requestFromAlice, alice1) + + // Bob receives CR from Alice + contactRequest := s.receiveContactRequest(messageText, bob) + s.Require().NotNil(contactRequest) + + // Bob resets his device + alice2, err := newMessengerWithKey(s.shh, alice1.identity, s.logger, nil) + s.Require().NoError(err) + + _, err = alice2.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, alice2) + + // Get bob perspective of alice for backup + bobFromAlice := alice1.Contacts()[0] + state := alice2.buildMessageState() + + // Restore alice's contact from backup + sync := s.syncInstallationContactV2FromContact(bobFromAlice) + err = alice2.HandleSyncInstallationContactV2(state, &sync, nil) + s.Require().NoError(err) + + // Accept latest CR for a contact + resp, err := bob.AcceptLatestContactRequestForContact(context.Background(), &requests.AcceptLatestContactRequestForContact{ID: types.Hex2Bytes(aliceID)}) + s.Require().NoError(err) + + // Make sure the message is updated + s.Require().NotNil(resp) + s.Require().Len(resp.Messages(), 2) + + contactRequestMsg := s.findFirstByContentType(resp.Messages(), protobuf.ChatMessage_CONTACT_REQUEST) + s.Require().NotNil(contactRequestMsg) + + // NOTE: We don't restore CR message + // s.Require().Equal(resp.Messages()[0].ID, contactRequest.ID) + s.Require().Equal(common.ContactRequestStateAccepted, contactRequestMsg.ContactRequestState) + + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().NotNil(resp.ActivityCenterNotifications()[0].Message) + s.Require().Equal(common.ContactRequestStateAccepted, resp.ActivityCenterNotifications()[0].Message.ContactRequestState) + + // Check the contact state is correctly set + s.Require().Len(resp.Contacts, 1) + s.Require().True(resp.Contacts[0].mutual()) + + // Make sure the sender is added to our contacts + contacts := bob.AddedContacts() + s.Require().Len(contacts, 1) + + // Make sure we consider them a mutual contact, receiver side + mutualContacts := bob.MutualContacts() + s.Require().Len(mutualContacts, 1) +} + +/* +Makes Alice and Bob mutual contacts. +Verifies that Alice device-2 receives mutual contact information. +Contact request is sent from Alice device 1. +*/ +func (s *MessengerContactRequestSuite) makeMutualContactsAndSync(alice1 *Messenger, alice2 *Messenger, bob *Messenger, messageText string) { + bobPublicKey := bob.IdentityPublicKeyString() + + cr := s.createContactRequest(bobPublicKey, messageText) + s.sendContactRequest(cr, alice1) + receivedCR := s.receiveContactRequest(cr.Message, bob) + s.acceptContactRequest(receivedCR, alice1, bob) + s.checkMutualContact(alice1, bobPublicKey) + + // Wait for Alice-2 to sync new contact + resp, _ := WaitOnMessengerResponse(alice2, func(r *MessengerResponse) bool { + // FIXME: https://github.com/status-im/status-go/issues/3803 + // No condition here. There are randomly received 1-3 messages. + return false // len(r.Contacts) == 1 && len(r.Messages()) == 3 + }, "alice-2 didn't receive bob contact") + s.logResponse(resp, "Wait for Alice-2 to sync new contact") + s.Require().NotNil(resp) + //s.Require().NoError(err) // WARNING: Uncomment when bug fixed. https://github.com/status-im/status-go/issues/3803 + + // Check that Alice-2 has Bob as a contact + s.Require().Len(alice2.Contacts(), 1) + s.Require().Equal(bobPublicKey, alice2.Contacts()[0].ID) + + // TODO: https://github.com/status-im/status-go/issues/3803 + // Check response messages and AC notifications when +} + +func (s *MessengerContactRequestSuite) blockContactAndSync(alice1 *Messenger, alice2 *Messenger, bob *Messenger) { + bobPublicKey := bob.IdentityPublicKeyString() + bobDisplayName, err := bob.settings.DisplayName() + s.Require().NoError(err) + + // Alice-1 blocks Bob + _, err = alice1.BlockContact(context.Background(), bobPublicKey, false) + s.Require().NoError(err) + s.Require().Len(alice1.BlockedContacts(), 1) + s.Require().Equal(bobPublicKey, alice1.BlockedContacts()[0].ID) + + // Wait for Bob to receive message that he was removed as contact + resp, err := WaitOnMessengerResponse(bob, func(r *MessengerResponse) bool { + return len(r.Contacts) == 1 && len(r.Messages()) == 1 + }, "Bob didn't receive a message that he was removed as contact") + + s.Require().NoError(err) + s.Require().NotNil(resp) + s.logResponse(resp, "Wait for Bob to receive message that he was removed as contact") + + // Check response contacts + s.Require().Len(resp.Contacts, 1) + respContact := resp.Contacts[0] + s.Require().Equal(respContact.ID, alice1.IdentityPublicKeyString()) + s.Require().Equal(ContactRequestStateNone, respContact.ContactRequestLocalState) + s.Require().Equal(ContactRequestStateNone, respContact.ContactRequestRemoteState) + + // Check response messages + s.Require().Len(resp.Messages(), 1) + s.Require().Equal(resp.Messages()[0].Text, fmt.Sprintf(incomingMutualStateEventRemovedDefaultText, alice1.IdentityPublicKeyString())) + + // Check response AC notifications + s.Require().Len(resp.ActivityCenterNotifications(), 1) + s.Require().Equal(resp.ActivityCenterNotifications()[0].Type, ActivityCenterNotificationTypeContactRemoved) + + alice2.logger.Info("STARTING") + // Wait for Alice-2 to sync Bob blocked state + resp, err = WaitOnMessengerResponse(alice2, func(r *MessengerResponse) bool { + return len(r.Contacts) == 1 + }, "Alice-2 didn't receive blocking bob") + s.logResponse(resp, "Wait for Alice-2 to sync Bob blocked state") + s.Require().NoError(err) + s.Require().NotNil(resp) + + // Check that Bob contact is synced with correct display name and blocked + s.Require().Len(alice2.Contacts(), 1) + respContact = alice2.Contacts()[0] + s.Require().True(respContact.Blocked) + s.Require().True(respContact.Removed) + s.Require().Equal(bobPublicKey, respContact.ID) + s.Require().Equal(bobDisplayName, respContact.DisplayName) + s.Require().Equal(ContactRequestStateDismissed, respContact.ContactRequestLocalState) + s.Require().Equal(ContactRequestStateReceived, respContact.ContactRequestRemoteState) + + // Check chats list + s.Require().Len(alice2.Chats(), deprecation.AddChatsCount(2)) +} + +func (s *MessengerContactRequestSuite) unblockContactAndSync(alice1 *Messenger, alice2 *Messenger, bob *Messenger) { + bobPublicKey := bob.IdentityPublicKeyString() + + _, err := alice1.UnblockContact(bobPublicKey) + s.Require().NoError(err) + s.Require().Len(alice1.BlockedContacts(), 0) + + // Bob doesn't receive any message on blocking. + // No response wait here. + + // Wait for Alice-2 to receive Bob unblocked state + resp, err := WaitOnMessengerResponse(alice2, func(r *MessengerResponse) bool { + return len(r.Contacts) == 1 + }, "Alice-2 didn't receive Bob unblocked state") + s.logResponse(resp, "Wait for Alice-2 to receive Bob unblocked state") + s.Require().NoError(err) + s.Require().NotNil(resp) + + // Check that Alice-2 has Bob unblocked and removed + s.Require().Len(alice2.Contacts(), 1) + respContact := alice2.Contacts()[0] + s.Require().Equal(bobPublicKey, respContact.ID) + s.Require().False(respContact.Blocked) + s.Require().True(respContact.Removed) + s.Require().Equal(respContact.ContactRequestLocalState, ContactRequestStateNone) + s.Require().Equal(respContact.ContactRequestRemoteState, ContactRequestStateNone) + + // Check chats list + s.Require().Len(alice2.Chats(), deprecation.AddChatsCount(2)) +} + +func (s *MessengerContactRequestSuite) TestBlockedContactSyncing() { + // Setup Bob + bob := s.newMessenger() + _, err := bob.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, bob) + _ = bob.SetDisplayName("bob-1") + s.logger.Info("Bob account set up", zap.String("publicKey", bob.IdentityPublicKeyString())) + + // Setup Alice-1 + alice1 := s.m + s.logger.Info("Alice account set up", zap.String("publicKey", alice1.IdentityPublicKeyString())) + + // Setup Alice-2 + alice2, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, nil) + s.Require().NoError(err) + _, err = alice2.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, alice2) + + // Pair alice-1 <-> alice-2 + // NOTE: This doesn't include initial data sync. Local pairing could be used. + s.logger.Info("pairing Alice-1 and Alice-2") + prepAliceMessengersForPairing(&s.Suite, alice1, alice2) + PairDevices(&s.Suite, alice1, alice2) + PairDevices(&s.Suite, alice2, alice1) + s.logger.Info("pairing Alice-1 and Alice-2 finished") + + // Loop cr-block-unblock. Some bugs happen at second iteration. + for i := 0; i < 2; i++ { + crText := fmt.Sprintf("hello-%d", i) + s.makeMutualContactsAndSync(alice1, alice2, bob, crText) + s.blockContactAndSync(alice1, alice2, bob) + s.unblockContactAndSync(alice1, alice2, bob) + } +} diff --git a/protocol/messenger_offline_test.go b/protocol/messenger_offline_test.go index 3688b0853..d2e4fd74e 100644 --- a/protocol/messenger_offline_test.go +++ b/protocol/messenger_offline_test.go @@ -1,9 +1,8 @@ package protocol import ( - //"context" - //"errors" - + "context" + "errors" "testing" "time" @@ -12,12 +11,10 @@ import ( gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" "github.com/status-im/status-go/eth-node/types" - - //"github.com/status-im/status-go/protocol/common" - //"github.com/status-im/status-go/protocol/communities" - // "github.com/status-im/status-go/protocol/protobuf" - //"github.com/status-im/status-go/protocol/requests" - + "github.com/status-im/status-go/protocol/common" + "github.com/status-im/status-go/protocol/communities" + "github.com/status-im/status-go/protocol/protobuf" + "github.com/status-im/status-go/protocol/requests" "github.com/status-im/status-go/protocol/tt" ) @@ -100,95 +97,95 @@ func (s *MessengerOfflineSuite) newMessenger(waku types.Waku, logger *zap.Logger }) } -// func (s *MessengerOfflineSuite) advertiseCommunityTo(community *communities.Community, owner *Messenger, user *Messenger) { -// advertiseCommunityTo(&s.Suite, community, owner, user) -// } +func (s *MessengerOfflineSuite) advertiseCommunityTo(community *communities.Community, owner *Messenger, user *Messenger) { + advertiseCommunityTo(&s.Suite, community, owner, user) +} -// func (s *MessengerOfflineSuite) joinCommunity(community *communities.Community, owner *Messenger, user *Messenger) { -// request := &requests.RequestToJoinCommunity{CommunityID: community.ID()} -// joinCommunity(&s.Suite, community, owner, user, request, "") -// } +func (s *MessengerOfflineSuite) joinCommunity(community *communities.Community, owner *Messenger, user *Messenger) { + request := &requests.RequestToJoinCommunity{CommunityID: community.ID()} + joinCommunity(&s.Suite, community, owner, user, request, "") +} -// func (s *MessengerOfflineSuite) TestCommunityOfflineEdit() { -// community, chat := createCommunity(&s.Suite, s.owner) +func (s *MessengerOfflineSuite) TestCommunityOfflineEdit() { + community, chat := createCommunity(&s.Suite, s.owner) -// chatID := chat.ID -// inputMessage := common.NewMessage() -// inputMessage.ChatId = chatID -// inputMessage.ContentType = protobuf.ChatMessage_TEXT_PLAIN -// inputMessage.Text = "some text" + chatID := chat.ID + inputMessage := common.NewMessage() + inputMessage.ChatId = chatID + inputMessage.ContentType = protobuf.ChatMessage_TEXT_PLAIN + inputMessage.Text = "some text" -// ctx := context.Background() + ctx := context.Background() -// s.advertiseCommunityTo(community, s.owner, s.alice) -// s.joinCommunity(community, s.owner, s.alice) + s.advertiseCommunityTo(community, s.owner, s.alice) + s.joinCommunity(community, s.owner, s.alice) -// _, err := s.alice.SendChatMessage(ctx, inputMessage) -// s.Require().NoError(err) -// s.checkMessageDelivery(ctx, inputMessage) + _, err := s.alice.SendChatMessage(ctx, inputMessage) + s.Require().NoError(err) + s.checkMessageDelivery(ctx, inputMessage) -// // Simulate going offline -// wakuv2 := gethbridge.GetGethWakuV2From(s.aliceWaku) -// wakuv2.SkipPublishToTopic(true) + // Simulate going offline + wakuv2 := gethbridge.GetGethWakuV2From(s.aliceWaku) + wakuv2.SkipPublishToTopic(true) -// resp, err := s.alice.SendChatMessage(ctx, inputMessage) -// messageID := types.Hex2Bytes(resp.Messages()[0].ID) -// s.Require().NoError(err) + resp, err := s.alice.SendChatMessage(ctx, inputMessage) + messageID := types.Hex2Bytes(resp.Messages()[0].ID) + s.Require().NoError(err) -// // Check that message is re-sent once back online -// wakuv2.SkipPublishToTopic(false) -// time.Sleep(5 * time.Second) + // Check that message is re-sent once back online + wakuv2.SkipPublishToTopic(false) + time.Sleep(5 * time.Second) -// s.checkMessageDelivery(ctx, inputMessage) + s.checkMessageDelivery(ctx, inputMessage) -// editedText := "some text edited" -// editedMessage := &requests.EditMessage{ -// ID: messageID, -// Text: editedText, -// } + editedText := "some text edited" + editedMessage := &requests.EditMessage{ + ID: messageID, + Text: editedText, + } -// wakuv2.SkipPublishToTopic(true) -// sendResponse, err := s.alice.EditMessage(ctx, editedMessage) -// s.Require().NotNil(sendResponse) -// s.Require().NoError(err) + wakuv2.SkipPublishToTopic(true) + sendResponse, err := s.alice.EditMessage(ctx, editedMessage) + s.Require().NotNil(sendResponse) + s.Require().NoError(err) -// // Check that message is re-sent once back online -// wakuv2.SkipPublishToTopic(false) -// time.Sleep(5 * time.Second) -// inputMessage.Text = editedText + // Check that message is re-sent once back online + wakuv2.SkipPublishToTopic(false) + time.Sleep(5 * time.Second) + inputMessage.Text = editedText -// s.checkMessageDelivery(ctx, inputMessage) -// } + s.checkMessageDelivery(ctx, inputMessage) +} -// func (s *MessengerOfflineSuite) checkMessageDelivery(ctx context.Context, inputMessage *common.Message) { -// var response *MessengerResponse -// // Pull message and make sure org is received -// err := tt.RetryWithBackOff(func() error { -// var err error -// response, err = s.owner.RetrieveAll() -// if err != nil { -// return err -// } -// if len(response.messages) == 0 { -// return errors.New("message not received") -// } -// return nil -// }) +func (s *MessengerOfflineSuite) checkMessageDelivery(ctx context.Context, inputMessage *common.Message) { + var response *MessengerResponse + // Pull message and make sure org is received + err := tt.RetryWithBackOff(func() error { + var err error + response, err = s.owner.RetrieveAll() + if err != nil { + return err + } + if len(response.messages) == 0 { + return errors.New("message not received") + } + return nil + }) -// s.Require().NoError(err) -// s.Require().Len(response.Messages(), 1) -// s.Require().Equal(inputMessage.Text, response.Messages()[0].Text) + s.Require().NoError(err) + s.Require().Len(response.Messages(), 1) + s.Require().Equal(inputMessage.Text, response.Messages()[0].Text) -// // check if response contains the chat we're interested in -// // we use this instead of checking just the length of the chat because -// // a CommunityDescription message might be received in the meantime due to syncing -// // hence response.Chats() might contain the general chat, and the new chat; -// // or only the new chat if the CommunityDescription message has not arrived -// found := false -// for _, chat := range response.Chats() { -// if chat.ID == inputMessage.ChatId { -// found = true -// } -// } -// s.Require().True(found) -// } + // check if response contains the chat we're interested in + // we use this instead of checking just the length of the chat because + // a CommunityDescription message might be received in the meantime due to syncing + // hence response.Chats() might contain the general chat, and the new chat; + // or only the new chat if the CommunityDescription message has not arrived + found := false + for _, chat := range response.Chats() { + if chat.ID == inputMessage.ChatId { + found = true + } + } + s.Require().True(found) +} diff --git a/protocol/messenger_profile_showcase_test.go b/protocol/messenger_profile_showcase_test.go index cdf9413c2..ff1b59ee0 100644 --- a/protocol/messenger_profile_showcase_test.go +++ b/protocol/messenger_profile_showcase_test.go @@ -71,46 +71,46 @@ func (s *TestMessengerProfileShowcase) mutualContact(theirMessenger *Messenger) s.Require().True(resp.Contacts[0].mutual()) } -// func (s *TestMessengerProfileShowcase) verifiedContact(theirMessenger *Messenger) { -// theirPk := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) -// challenge := "Want to see what I'm hiding in my profile showcase?" +func (s *TestMessengerProfileShowcase) verifiedContact(theirMessenger *Messenger) { + theirPk := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey)) + challenge := "Want to see what I'm hiding in my profile showcase?" -// _, err := s.m.SendContactVerificationRequest(context.Background(), theirPk, challenge) -// s.Require().NoError(err) + _, err := s.m.SendContactVerificationRequest(context.Background(), theirPk, challenge) + s.Require().NoError(err) -// // Wait for the message to reach its destination -// resp, err := WaitOnMessengerResponse( -// theirMessenger, -// func(r *MessengerResponse) bool { -// return len(r.VerificationRequests()) == 1 && len(r.ActivityCenterNotifications()) == 1 -// }, -// "no messages", -// ) -// s.Require().NoError(err) -// s.Require().Len(resp.VerificationRequests(), 1) -// verificationRequestID := resp.VerificationRequests()[0].ID + // Wait for the message to reach its destination + resp, err := WaitOnMessengerResponse( + theirMessenger, + func(r *MessengerResponse) bool { + return len(r.VerificationRequests()) == 1 && len(r.ActivityCenterNotifications()) == 1 + }, + "no messages", + ) + s.Require().NoError(err) + s.Require().Len(resp.VerificationRequests(), 1) + verificationRequestID := resp.VerificationRequests()[0].ID -// _, err = theirMessenger.AcceptContactVerificationRequest(context.Background(), verificationRequestID, "For sure!") -// s.Require().NoError(err) + _, err = theirMessenger.AcceptContactVerificationRequest(context.Background(), verificationRequestID, "For sure!") + s.Require().NoError(err) -// s.Require().NoError(err) + s.Require().NoError(err) -// // Wait for the message to reach its destination -// _, err = WaitOnMessengerResponse( -// s.m, -// func(r *MessengerResponse) bool { -// return len(r.VerificationRequests()) == 1 -// }, -// "no messages", -// ) -// s.Require().NoError(err) + // Wait for the message to reach its destination + _, err = WaitOnMessengerResponse( + s.m, + func(r *MessengerResponse) bool { + return len(r.VerificationRequests()) == 1 + }, + "no messages", + ) + s.Require().NoError(err) -// resp, err = s.m.VerifiedTrusted(context.Background(), &requests.VerifiedTrusted{ID: types.FromHex(verificationRequestID)}) -// s.Require().NoError(err) + resp, err = s.m.VerifiedTrusted(context.Background(), &requests.VerifiedTrusted{ID: types.FromHex(verificationRequestID)}) + s.Require().NoError(err) -// s.Require().Len(resp.Messages(), 1) -// s.Require().Equal(common.ContactVerificationStateTrusted, resp.Messages()[0].ContactVerificationState) -// } + s.Require().Len(resp.Messages(), 1) + s.Require().Equal(common.ContactVerificationStateTrusted, resp.Messages()[0].ContactVerificationState) +} func (s *TestMessengerProfileShowcase) TestSaveAndGetProfileShowcasePreferences() { request := DummyProfileShowcasePreferences() @@ -287,134 +287,134 @@ func (s *TestMessengerProfileShowcase) TestEncryptAndDecryptProfileShowcaseEntri } } -// func (s *TestMessengerProfileShowcase) TestShareShowcasePreferences() { -// // Set Display name to pass shouldPublishChatIdentity check -// profileKp := accounts.GetProfileKeypairForTest(true, false, false) -// profileKp.KeyUID = s.m.account.KeyUID -// profileKp.Accounts[0].KeyUID = s.m.account.KeyUID +func (s *TestMessengerProfileShowcase) TestShareShowcasePreferences() { + // Set Display name to pass shouldPublishChatIdentity check + profileKp := accounts.GetProfileKeypairForTest(true, false, false) + profileKp.KeyUID = s.m.account.KeyUID + profileKp.Accounts[0].KeyUID = s.m.account.KeyUID -// err := s.m.settings.SaveOrUpdateKeypair(profileKp) -// s.Require().NoError(err) + err := s.m.settings.SaveOrUpdateKeypair(profileKp) + s.Require().NoError(err) -// err = s.m.SetDisplayName("bobby") -// s.Require().NoError(err) + err = s.m.SetDisplayName("bobby") + s.Require().NoError(err) -// // Add mutual contact -// mutualContact := s.newMessenger() -// _, err = mutualContact.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, mutualContact) + // Add mutual contact + mutualContact := s.newMessenger() + _, err = mutualContact.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, mutualContact) -// s.mutualContact(mutualContact) + s.mutualContact(mutualContact) -// // Add identity verified contact -// verifiedContact := s.newMessenger() -// _, err = verifiedContact.Start() -// s.Require().NoError(err) -// defer TearDownMessenger(&s.Suite, verifiedContact) + // Add identity verified contact + verifiedContact := s.newMessenger() + _, err = verifiedContact.Start() + s.Require().NoError(err) + defer TearDownMessenger(&s.Suite, verifiedContact) -// s.mutualContact(verifiedContact) -// s.verifiedContact(verifiedContact) + s.mutualContact(verifiedContact) + s.verifiedContact(verifiedContact) -// // Save preferences to dispatch changes -// request := DummyProfileShowcasePreferences() -// err = s.m.SetProfileShowcasePreferences(request, false) -// s.Require().NoError(err) + // Save preferences to dispatch changes + request := DummyProfileShowcasePreferences() + err = s.m.SetProfileShowcasePreferences(request, false) + s.Require().NoError(err) -// contactID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) -// // Get summarised profile data for mutual contact -// resp, err := WaitOnMessengerResponse( -// mutualContact, -// func(r *MessengerResponse) bool { -// return len(r.updatedProfileShowcases) > 0 && r.updatedProfileShowcases[contactID] != nil -// }, -// "no messages", -// ) -// s.Require().NoError(err) -// s.Require().Len(resp.updatedProfileShowcases, 1) + contactID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey)) + // Get summarised profile data for mutual contact + resp, err := WaitOnMessengerResponse( + mutualContact, + func(r *MessengerResponse) bool { + return len(r.updatedProfileShowcases) > 0 && r.updatedProfileShowcases[contactID] != nil + }, + "no messages", + ) + s.Require().NoError(err) + s.Require().Len(resp.updatedProfileShowcases, 1) -// profileShowcase := resp.updatedProfileShowcases[contactID] + profileShowcase := resp.updatedProfileShowcases[contactID] -// s.Require().Len(profileShowcase.Accounts, 2) -// s.Require().Equal(profileShowcase.Accounts[0].Address, request.Accounts[0].Address) -// s.Require().Equal(profileShowcase.Accounts[0].Name, request.Accounts[0].Name) -// s.Require().Equal(profileShowcase.Accounts[0].ColorID, request.Accounts[0].ColorID) -// s.Require().Equal(profileShowcase.Accounts[0].Emoji, request.Accounts[0].Emoji) -// s.Require().Equal(profileShowcase.Accounts[0].Order, request.Accounts[0].Order) -// s.Require().Equal(profileShowcase.Accounts[1].Address, request.Accounts[1].Address) -// s.Require().Equal(profileShowcase.Accounts[1].Name, request.Accounts[1].Name) -// s.Require().Equal(profileShowcase.Accounts[1].ColorID, request.Accounts[1].ColorID) -// s.Require().Equal(profileShowcase.Accounts[1].Emoji, request.Accounts[1].Emoji) -// s.Require().Equal(profileShowcase.Accounts[1].Order, request.Accounts[1].Order) + s.Require().Len(profileShowcase.Accounts, 2) + s.Require().Equal(profileShowcase.Accounts[0].Address, request.Accounts[0].Address) + s.Require().Equal(profileShowcase.Accounts[0].Name, request.Accounts[0].Name) + s.Require().Equal(profileShowcase.Accounts[0].ColorID, request.Accounts[0].ColorID) + s.Require().Equal(profileShowcase.Accounts[0].Emoji, request.Accounts[0].Emoji) + s.Require().Equal(profileShowcase.Accounts[0].Order, request.Accounts[0].Order) + s.Require().Equal(profileShowcase.Accounts[1].Address, request.Accounts[1].Address) + s.Require().Equal(profileShowcase.Accounts[1].Name, request.Accounts[1].Name) + s.Require().Equal(profileShowcase.Accounts[1].ColorID, request.Accounts[1].ColorID) + s.Require().Equal(profileShowcase.Accounts[1].Emoji, request.Accounts[1].Emoji) + s.Require().Equal(profileShowcase.Accounts[1].Order, request.Accounts[1].Order) -// s.Require().Len(profileShowcase.Collectibles, 1) -// s.Require().Equal(profileShowcase.Collectibles[0].TokenID, request.Collectibles[0].TokenID) -// s.Require().Equal(profileShowcase.Collectibles[0].ChainID, request.Collectibles[0].ChainID) -// s.Require().Equal(profileShowcase.Collectibles[0].ContractAddress, request.Collectibles[0].ContractAddress) -// s.Require().Equal(profileShowcase.Collectibles[0].AccountAddress, request.Collectibles[0].AccountAddress) -// s.Require().Equal(profileShowcase.Collectibles[0].CommunityID, request.Collectibles[0].CommunityID) -// s.Require().Equal(profileShowcase.Collectibles[0].Order, request.Collectibles[0].Order) + s.Require().Len(profileShowcase.Collectibles, 1) + s.Require().Equal(profileShowcase.Collectibles[0].TokenID, request.Collectibles[0].TokenID) + s.Require().Equal(profileShowcase.Collectibles[0].ChainID, request.Collectibles[0].ChainID) + s.Require().Equal(profileShowcase.Collectibles[0].ContractAddress, request.Collectibles[0].ContractAddress) + s.Require().Equal(profileShowcase.Collectibles[0].AccountAddress, request.Collectibles[0].AccountAddress) + s.Require().Equal(profileShowcase.Collectibles[0].CommunityID, request.Collectibles[0].CommunityID) + s.Require().Equal(profileShowcase.Collectibles[0].Order, request.Collectibles[0].Order) -// s.Require().Len(profileShowcase.VerifiedTokens, 1) -// s.Require().Equal(profileShowcase.VerifiedTokens[0].Symbol, request.VerifiedTokens[0].Symbol) -// s.Require().Equal(profileShowcase.VerifiedTokens[0].Order, request.VerifiedTokens[0].Order) + s.Require().Len(profileShowcase.VerifiedTokens, 1) + s.Require().Equal(profileShowcase.VerifiedTokens[0].Symbol, request.VerifiedTokens[0].Symbol) + s.Require().Equal(profileShowcase.VerifiedTokens[0].Order, request.VerifiedTokens[0].Order) -// s.Require().Len(profileShowcase.UnverifiedTokens, 2) -// s.Require().Equal(profileShowcase.UnverifiedTokens[0].ContractAddress, request.UnverifiedTokens[0].ContractAddress) -// s.Require().Equal(profileShowcase.UnverifiedTokens[0].ChainID, request.UnverifiedTokens[0].ChainID) -// s.Require().Equal(profileShowcase.UnverifiedTokens[0].Order, request.UnverifiedTokens[0].Order) -// s.Require().Equal(profileShowcase.UnverifiedTokens[1].ContractAddress, request.UnverifiedTokens[1].ContractAddress) -// s.Require().Equal(profileShowcase.UnverifiedTokens[1].ChainID, request.UnverifiedTokens[1].ChainID) -// s.Require().Equal(profileShowcase.UnverifiedTokens[1].Order, request.UnverifiedTokens[1].Order) + s.Require().Len(profileShowcase.UnverifiedTokens, 2) + s.Require().Equal(profileShowcase.UnverifiedTokens[0].ContractAddress, request.UnverifiedTokens[0].ContractAddress) + s.Require().Equal(profileShowcase.UnverifiedTokens[0].ChainID, request.UnverifiedTokens[0].ChainID) + s.Require().Equal(profileShowcase.UnverifiedTokens[0].Order, request.UnverifiedTokens[0].Order) + s.Require().Equal(profileShowcase.UnverifiedTokens[1].ContractAddress, request.UnverifiedTokens[1].ContractAddress) + s.Require().Equal(profileShowcase.UnverifiedTokens[1].ChainID, request.UnverifiedTokens[1].ChainID) + s.Require().Equal(profileShowcase.UnverifiedTokens[1].Order, request.UnverifiedTokens[1].Order) -// // Get summarised profile data for verified contact -// resp, err = WaitOnMessengerResponse( -// verifiedContact, -// func(r *MessengerResponse) bool { -// return len(r.updatedProfileShowcases) > 0 -// }, -// "no messages", -// ) -// s.Require().NoError(err) -// s.Require().Len(resp.updatedProfileShowcases, 1) + // Get summarised profile data for verified contact + resp, err = WaitOnMessengerResponse( + verifiedContact, + func(r *MessengerResponse) bool { + return len(r.updatedProfileShowcases) > 0 + }, + "no messages", + ) + s.Require().NoError(err) + s.Require().Len(resp.updatedProfileShowcases, 1) -// // Here let's try synchronous -// profileShowcase, err = verifiedContact.GetProfileShowcaseForContact(contactID) -// s.Require().NoError(err) + // Here let's try synchronous + profileShowcase, err = verifiedContact.GetProfileShowcaseForContact(contactID) + s.Require().NoError(err) -// s.Require().Len(profileShowcase.Accounts, 2) -// s.Require().Equal(profileShowcase.Accounts[0].Address, request.Accounts[0].Address) -// s.Require().Equal(profileShowcase.Accounts[0].Name, request.Accounts[0].Name) -// s.Require().Equal(profileShowcase.Accounts[0].ColorID, request.Accounts[0].ColorID) -// s.Require().Equal(profileShowcase.Accounts[0].Emoji, request.Accounts[0].Emoji) -// s.Require().Equal(profileShowcase.Accounts[0].Order, request.Accounts[0].Order) -// s.Require().Equal(profileShowcase.Accounts[1].Address, request.Accounts[1].Address) -// s.Require().Equal(profileShowcase.Accounts[1].Name, request.Accounts[1].Name) -// s.Require().Equal(profileShowcase.Accounts[1].ColorID, request.Accounts[1].ColorID) -// s.Require().Equal(profileShowcase.Accounts[1].Emoji, request.Accounts[1].Emoji) -// s.Require().Equal(profileShowcase.Accounts[1].Order, request.Accounts[1].Order) + s.Require().Len(profileShowcase.Accounts, 2) + s.Require().Equal(profileShowcase.Accounts[0].Address, request.Accounts[0].Address) + s.Require().Equal(profileShowcase.Accounts[0].Name, request.Accounts[0].Name) + s.Require().Equal(profileShowcase.Accounts[0].ColorID, request.Accounts[0].ColorID) + s.Require().Equal(profileShowcase.Accounts[0].Emoji, request.Accounts[0].Emoji) + s.Require().Equal(profileShowcase.Accounts[0].Order, request.Accounts[0].Order) + s.Require().Equal(profileShowcase.Accounts[1].Address, request.Accounts[1].Address) + s.Require().Equal(profileShowcase.Accounts[1].Name, request.Accounts[1].Name) + s.Require().Equal(profileShowcase.Accounts[1].ColorID, request.Accounts[1].ColorID) + s.Require().Equal(profileShowcase.Accounts[1].Emoji, request.Accounts[1].Emoji) + s.Require().Equal(profileShowcase.Accounts[1].Order, request.Accounts[1].Order) -// s.Require().Len(profileShowcase.Collectibles, 1) -// s.Require().Equal(profileShowcase.Collectibles[0].ContractAddress, request.Collectibles[0].ContractAddress) -// s.Require().Equal(profileShowcase.Collectibles[0].ChainID, request.Collectibles[0].ChainID) -// s.Require().Equal(profileShowcase.Collectibles[0].TokenID, request.Collectibles[0].TokenID) -// s.Require().Equal(profileShowcase.Collectibles[0].CommunityID, request.Collectibles[0].CommunityID) -// s.Require().Equal(profileShowcase.Collectibles[0].Order, request.Collectibles[0].Order) + s.Require().Len(profileShowcase.Collectibles, 1) + s.Require().Equal(profileShowcase.Collectibles[0].ContractAddress, request.Collectibles[0].ContractAddress) + s.Require().Equal(profileShowcase.Collectibles[0].ChainID, request.Collectibles[0].ChainID) + s.Require().Equal(profileShowcase.Collectibles[0].TokenID, request.Collectibles[0].TokenID) + s.Require().Equal(profileShowcase.Collectibles[0].CommunityID, request.Collectibles[0].CommunityID) + s.Require().Equal(profileShowcase.Collectibles[0].Order, request.Collectibles[0].Order) -// s.Require().Len(profileShowcase.VerifiedTokens, 2) -// s.Require().Equal(profileShowcase.VerifiedTokens[0].Symbol, request.VerifiedTokens[0].Symbol) -// s.Require().Equal(profileShowcase.VerifiedTokens[0].Order, request.VerifiedTokens[0].Order) -// s.Require().Equal(profileShowcase.VerifiedTokens[1].Symbol, request.VerifiedTokens[1].Symbol) -// s.Require().Equal(profileShowcase.VerifiedTokens[1].Order, request.VerifiedTokens[1].Order) + s.Require().Len(profileShowcase.VerifiedTokens, 2) + s.Require().Equal(profileShowcase.VerifiedTokens[0].Symbol, request.VerifiedTokens[0].Symbol) + s.Require().Equal(profileShowcase.VerifiedTokens[0].Order, request.VerifiedTokens[0].Order) + s.Require().Equal(profileShowcase.VerifiedTokens[1].Symbol, request.VerifiedTokens[1].Symbol) + s.Require().Equal(profileShowcase.VerifiedTokens[1].Order, request.VerifiedTokens[1].Order) -// s.Require().Len(profileShowcase.UnverifiedTokens, 2) -// s.Require().Equal(profileShowcase.UnverifiedTokens[0].ContractAddress, request.UnverifiedTokens[0].ContractAddress) -// s.Require().Equal(profileShowcase.UnverifiedTokens[0].ChainID, request.UnverifiedTokens[0].ChainID) -// s.Require().Equal(profileShowcase.UnverifiedTokens[0].Order, request.UnverifiedTokens[0].Order) -// s.Require().Equal(profileShowcase.UnverifiedTokens[1].ContractAddress, request.UnverifiedTokens[1].ContractAddress) -// s.Require().Equal(profileShowcase.UnverifiedTokens[1].ChainID, request.UnverifiedTokens[1].ChainID) -// s.Require().Equal(profileShowcase.UnverifiedTokens[1].Order, request.UnverifiedTokens[1].Order) -// } + s.Require().Len(profileShowcase.UnverifiedTokens, 2) + s.Require().Equal(profileShowcase.UnverifiedTokens[0].ContractAddress, request.UnverifiedTokens[0].ContractAddress) + s.Require().Equal(profileShowcase.UnverifiedTokens[0].ChainID, request.UnverifiedTokens[0].ChainID) + s.Require().Equal(profileShowcase.UnverifiedTokens[0].Order, request.UnverifiedTokens[0].Order) + s.Require().Equal(profileShowcase.UnverifiedTokens[1].ContractAddress, request.UnverifiedTokens[1].ContractAddress) + s.Require().Equal(profileShowcase.UnverifiedTokens[1].ChainID, request.UnverifiedTokens[1].ChainID) + s.Require().Equal(profileShowcase.UnverifiedTokens[1].Order, request.UnverifiedTokens[1].Order) +} func (s *TestMessengerProfileShowcase) TestProfileShowcaseProofOfMembershipUnencryptedCommunities() { alice := s.m diff --git a/server/pairing/sync_device_test.go b/server/pairing/sync_device_test.go index 218339888..d734d7da0 100644 --- a/server/pairing/sync_device_test.go +++ b/server/pairing/sync_device_test.go @@ -3,9 +3,7 @@ package pairing import ( "context" "encoding/json" - - //"errors" - + "errors" "fmt" "os" "path/filepath" @@ -19,9 +17,7 @@ import ( "github.com/status-im/status-go/common/dbsetup" "github.com/status-im/status-go/eth-node/crypto" "github.com/status-im/status-go/protocol" - - //"github.com/status-im/status-go/protocol/encryption/multidevice" - + "github.com/status-im/status-go/protocol/encryption/multidevice" "github.com/status-im/status-go/protocol/tt" "github.com/google/uuid" @@ -45,22 +41,22 @@ import ( ) const ( - pathWalletRoot = "m/44'/60'/0'/0" - pathEIP1581 = "m/43'/60'/1581'" - pathDefaultChat = pathEIP1581 + "/0'/0" - pathDefaultWallet = pathWalletRoot + "/0" - currentNetwork = "mainnet_rpc" - socialLinkURL = "https://github.com/status-im" - ensUsername = "bob.stateofus.eth" - ensChainID = 1 - publicChatID = "localpairtest" - profileKeypairMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon" - seedKeypairMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" - //profileKeypairMnemonic1 = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about about" - //seedKeypairMnemonic1 = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about abandon" - path0 = "m/44'/60'/0'/0/0" - path1 = "m/44'/60'/0'/0/1" - expectedKDFIterations = 1024 + pathWalletRoot = "m/44'/60'/0'/0" + pathEIP1581 = "m/43'/60'/1581'" + pathDefaultChat = pathEIP1581 + "/0'/0" + pathDefaultWallet = pathWalletRoot + "/0" + currentNetwork = "mainnet_rpc" + socialLinkURL = "https://github.com/status-im" + ensUsername = "bob.stateofus.eth" + ensChainID = 1 + publicChatID = "localpairtest" + profileKeypairMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon" + seedKeypairMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" + profileKeypairMnemonic1 = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about about" + seedKeypairMnemonic1 = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about abandon" + path0 = "m/44'/60'/0'/0/0" + path1 = "m/44'/60'/0'/0/1" + expectedKDFIterations = 1024 ) var paths = []string{pathWalletRoot, pathEIP1581, pathDefaultChat, pathDefaultWallet} @@ -883,304 +879,303 @@ func (s *SyncDeviceSuite) TestTransferringKeystoreFiles() { } } -/* - func (s *SyncDeviceSuite) TestTransferringKeystoreFilesAfterStopUisngKeycard() { - ctx := context.TODO() +func (s *SyncDeviceSuite) TestTransferringKeystoreFilesAfterStopUisngKeycard() { + ctx := context.TODO() - // Prepare server - serverTmpDir := filepath.Join(s.clientAsReceiverTmpdir, "server") - serverBackend := s.prepareBackendWithAccount(profileKeypairMnemonic1, serverTmpDir) - serverMessenger := serverBackend.Messenger() - serverAccountsAPI := serverBackend.StatusNode().AccountService().APIs()[1].Service.(*accservice.API) + // Prepare server + serverTmpDir := filepath.Join(s.clientAsReceiverTmpdir, "server") + serverBackend := s.prepareBackendWithAccount(profileKeypairMnemonic1, serverTmpDir) + serverMessenger := serverBackend.Messenger() + serverAccountsAPI := serverBackend.StatusNode().AccountService().APIs()[1].Service.(*accservice.API) - // Prepare client - clientTmpDir := filepath.Join(s.clientAsReceiverTmpdir, "client") - clientBackend := s.prepareBackendWithAccount(profileKeypairMnemonic1, clientTmpDir) - clientMessenger := clientBackend.Messenger() - clientAccountsAPI := clientBackend.StatusNode().AccountService().APIs()[1].Service.(*accservice.API) + // Prepare client + clientTmpDir := filepath.Join(s.clientAsReceiverTmpdir, "client") + clientBackend := s.prepareBackendWithAccount(profileKeypairMnemonic1, clientTmpDir) + clientMessenger := clientBackend.Messenger() + clientAccountsAPI := clientBackend.StatusNode().AccountService().APIs()[1].Service.(*accservice.API) - defer func() { - require.NoError(s.T(), clientBackend.Logout()) - require.NoError(s.T(), serverBackend.Logout()) - }() + defer func() { + require.NoError(s.T(), clientBackend.Logout()) + require.NoError(s.T(), serverBackend.Logout()) + }() - // Pair server and client - im1 := &multidevice.InstallationMetadata{ - Name: "client-device", - DeviceType: "client-device-type", - } - settings, err := clientBackend.GetSettings() - s.Require().NoError(err) - err = clientMessenger.SetInstallationMetadata(settings.InstallationID, im1) - s.Require().NoError(err) - response, err := clientMessenger.SendPairInstallation(context.Background(), nil) - s.Require().NoError(err) - s.Require().NotNil(response) - s.Require().Len(response.Chats(), 1) - s.Require().False(response.Chats()[0].Active) + // Pair server and client + im1 := &multidevice.InstallationMetadata{ + Name: "client-device", + DeviceType: "client-device-type", + } + settings, err := clientBackend.GetSettings() + s.Require().NoError(err) + err = clientMessenger.SetInstallationMetadata(settings.InstallationID, im1) + s.Require().NoError(err) + response, err := clientMessenger.SendPairInstallation(context.Background(), nil) + s.Require().NoError(err) + s.Require().NotNil(response) + s.Require().Len(response.Chats(), 1) + s.Require().False(response.Chats()[0].Active) - response, err = protocol.WaitOnMessengerResponse( - serverMessenger, - func(r *protocol.MessengerResponse) bool { - for _, i := range r.Installations { - if i.ID == settings.InstallationID { - return true - } - } - return false - }, - "installation not received", - ) - - s.Require().NoError(err) - - found := false - for _, i := range response.Installations { - found = i.ID == settings.InstallationID && - i.InstallationMetadata != nil && - i.InstallationMetadata.Name == im1.Name && - i.InstallationMetadata.DeviceType == im1.DeviceType - if found { - break - } - } - s.Require().True(found) - - err = serverMessenger.EnableInstallation(settings.InstallationID) - s.Require().NoError(err) - - // Check if the logged in account is the same on server and client - serverActiveAccount, err := serverBackend.GetActiveAccount() - require.NoError(s.T(), err) - clientActiveAccount, err := clientBackend.GetActiveAccount() - require.NoError(s.T(), err) - require.True(s.T(), serverActiveAccount.KeyUID == clientActiveAccount.KeyUID) - - ////////////////////////////////////////////////////////////////////////////// - // From this point this test is trying to simulate the following scenario: - // - add a new seed phrase keypair on server - // - sync it to client - // - convert it to a keycard keypair on server - // - sync it to client - // - stop using keycard on server - // - sync it to client - // - try to transfer keystore files from server to client - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - // Add new seed phrase keypair to server and sync it to client - ////////////////////////////////////////////////////////////////////////////// - serverSeedPhraseKp := s.getSeedPhraseKeypairForTest(serverBackend, seedKeypairMnemonic1, true) - err = serverAccountsAPI.ImportMnemonic(ctx, seedKeypairMnemonic1, s.password) - require.NoError(s.T(), err, "importing mnemonic for new keypair on server") - err = serverAccountsAPI.AddKeypair(ctx, s.password, serverSeedPhraseKp) - require.NoError(s.T(), err, "saving seed phrase keypair on server with keystore files created") - - // Wait for sync messages to be received on client - err = tt.RetryWithBackOff(func() error { - response, err := clientMessenger.RetrieveAll() - if err != nil { - return err - } - - for _, kp := range response.Keypairs { - if kp.KeyUID == serverSeedPhraseKp.KeyUID { - return nil + response, err = protocol.WaitOnMessengerResponse( + serverMessenger, + func(r *protocol.MessengerResponse) bool { + for _, i := range r.Installations { + if i.ID == settings.InstallationID { + return true } } + return false + }, + "installation not received", + ) - return errors.New("no sync keypair received") - }) - s.Require().NoError(err) + s.Require().NoError(err) - // Check if the keypair saved on client is the same as the one on server - serverKp, err := serverAccountsAPI.GetKeypairByKeyUID(ctx, serverSeedPhraseKp.KeyUID) - s.Require().NoError(err) - clientKp, err := clientAccountsAPI.GetKeypairByKeyUID(ctx, serverSeedPhraseKp.KeyUID) - s.Require().NoError(err) - - s.Require().True(serverKp.KeyUID == clientKp.KeyUID && - serverKp.Name == clientKp.Name && - serverKp.Type == clientKp.Type && - serverKp.DerivedFrom == clientKp.DerivedFrom && - serverKp.LastUsedDerivationIndex == clientKp.LastUsedDerivationIndex && - serverKp.Clock == clientKp.Clock && - len(serverKp.Accounts) == len(clientKp.Accounts) && - len(serverKp.Keycards) == len(clientKp.Keycards)) - - // Check server - server should contain keystore files for imported seed phrase - serverKeystorePath := filepath.Join(serverTmpDir, keystoreDir, serverActiveAccount.KeyUID) - require.True(s.T(), containsKeystoreFile(serverKeystorePath, serverKp.DerivedFrom[2:])) - for _, acc := range serverKp.Accounts { - require.True(s.T(), containsKeystoreFile(serverKeystorePath, acc.Address.String()[2:])) - } - - // Check client - client should not contain keystore files for imported seed phrase - clientKeystorePath := filepath.Join(clientTmpDir, keystoreDir, clientActiveAccount.KeyUID) - require.False(s.T(), containsKeystoreFile(clientKeystorePath, clientKp.DerivedFrom[2:])) - for _, acc := range clientKp.Accounts { - require.False(s.T(), containsKeystoreFile(clientKeystorePath, acc.Address.String()[2:])) - } - - ////////////////////////////////////////////////////////////////////////////// - // Convert it to a keycard keypair on server and sync it to client - ////////////////////////////////////////////////////////////////////////////// - err = serverAccountsAPI.SaveOrUpdateKeycard(ctx, &accounts.Keycard{ - KeycardUID: "1234", - KeycardName: "new-keycard", - KeyUID: serverKp.KeyUID, - AccountsAddresses: []types.Address{serverKp.Accounts[0].Address, serverKp.Accounts[1].Address}, - }, false) - s.Require().NoError(err) - - // Wait for sync messages to be received on client - err = tt.RetryWithBackOff(func() error { - response, err := clientMessenger.RetrieveAll() - if err != nil { - return err - } - - for _, kp := range response.Keypairs { - if kp.KeyUID == serverKp.KeyUID { - return nil - } - } - return errors.New("no sync keypair received") - }) - s.Require().NoError(err) - - // Check if the keypair saved on client is the same as the one on server - serverKp, err = serverAccountsAPI.GetKeypairByKeyUID(ctx, serverSeedPhraseKp.KeyUID) - s.Require().NoError(err) - clientKp, err = clientAccountsAPI.GetKeypairByKeyUID(ctx, serverSeedPhraseKp.KeyUID) - s.Require().NoError(err) - - s.Require().True(serverKp.KeyUID == clientKp.KeyUID && - serverKp.Name == clientKp.Name && - serverKp.Type == clientKp.Type && - serverKp.DerivedFrom == clientKp.DerivedFrom && - serverKp.LastUsedDerivationIndex == clientKp.LastUsedDerivationIndex && - serverKp.Clock == clientKp.Clock && - len(serverKp.Accounts) == len(clientKp.Accounts) && - len(serverKp.Keycards) == len(clientKp.Keycards) && - len(serverKp.Keycards) == 1) - - // Check server - server should not contain keystore files for imported seed phrase - require.False(s.T(), containsKeystoreFile(serverKeystorePath, serverKp.DerivedFrom[2:])) - for _, acc := range serverKp.Accounts { - require.False(s.T(), containsKeystoreFile(serverKeystorePath, acc.Address.String()[2:])) - } - - // Check client - client should not contain keystore files for imported seed phrase - require.False(s.T(), containsKeystoreFile(clientKeystorePath, clientKp.DerivedFrom[2:])) - for _, acc := range clientKp.Accounts { - require.False(s.T(), containsKeystoreFile(clientKeystorePath, acc.Address.String()[2:])) - } - - ////////////////////////////////////////////////////////////////////////////// - // Stop using keycard on server and sync it to client - ////////////////////////////////////////////////////////////////////////////// - err = serverAccountsAPI.MigrateNonProfileKeycardKeypairToApp(ctx, seedKeypairMnemonic1, s.password) - s.Require().NoError(err) - - // Wait for sync messages to be received on client - err = tt.RetryWithBackOff(func() error { - response, err := clientMessenger.RetrieveAll() - if err != nil { - return err - } - - for _, kp := range response.Keypairs { - if kp.KeyUID == serverKp.KeyUID { - return nil - } - } - return errors.New("no sync keypair received") - }) - s.Require().NoError(err) - - // Check if the keypair saved on client is the same as the one on server - serverKp, err = serverAccountsAPI.GetKeypairByKeyUID(ctx, serverSeedPhraseKp.KeyUID) - s.Require().NoError(err) - clientKp, err = clientAccountsAPI.GetKeypairByKeyUID(ctx, serverSeedPhraseKp.KeyUID) - s.Require().NoError(err) - - s.Require().True(serverKp.KeyUID == clientKp.KeyUID && - serverKp.Name == clientKp.Name && - serverKp.Type == clientKp.Type && - serverKp.DerivedFrom == clientKp.DerivedFrom && - serverKp.LastUsedDerivationIndex == clientKp.LastUsedDerivationIndex && - serverKp.Clock == clientKp.Clock && - len(serverKp.Accounts) == len(clientKp.Accounts) && - len(serverKp.Keycards) == len(clientKp.Keycards) && - len(serverKp.Keycards) == 0) - - // Check server - server should contain keystore files for imported seed phrase - require.True(s.T(), containsKeystoreFile(serverKeystorePath, serverKp.DerivedFrom[2:])) - for _, acc := range serverKp.Accounts { - require.True(s.T(), containsKeystoreFile(serverKeystorePath, acc.Address.String()[2:])) - } - - // Check client - client should not contain keystore files for imported seed phrase - require.False(s.T(), containsKeystoreFile(clientKeystorePath, clientKp.DerivedFrom[2:])) - for _, acc := range clientKp.Accounts { - require.False(s.T(), containsKeystoreFile(clientKeystorePath, acc.Address.String()[2:])) - } - - ////////////////////////////////////////////////////////////////////////////// - // Try to transfer keystore files from server to client - ////////////////////////////////////////////////////////////////////////////// - - serverMessenger.SetLocalPairing(true) - clientMessenger.SetLocalPairing(true) - - // prepare sender - var config = KeystoreFilesSenderServerConfig{ - SenderConfig: &KeystoreFilesSenderConfig{ - KeystoreFilesConfig: KeystoreFilesConfig{ - KeystorePath: serverKeystorePath, - LoggedInKeyUID: serverActiveAccount.KeyUID, - Password: s.password, - }, - KeypairsToExport: []string{serverKp.KeyUID}, - }, - ServerConfig: new(ServerConfig), - } - configBytes, err := json.Marshal(config) - require.NoError(s.T(), err) - cs, err := StartUpKeystoreFilesSenderServer(serverBackend, string(configBytes)) - require.NoError(s.T(), err) - - // prepare receiver - clientPayloadSourceConfig := KeystoreFilesReceiverClientConfig{ - ReceiverConfig: &KeystoreFilesReceiverConfig{ - KeystoreFilesConfig: KeystoreFilesConfig{ - KeystorePath: clientKeystorePath, - LoggedInKeyUID: clientActiveAccount.KeyUID, - Password: s.password, - }, - KeypairsToImport: []string{clientKp.KeyUID}, - }, - ClientConfig: new(ClientConfig), - } - clientConfigBytes, err := json.Marshal(clientPayloadSourceConfig) - require.NoError(s.T(), err) - err = StartUpKeystoreFilesReceivingClient(clientBackend, cs, string(clientConfigBytes)) - require.NoError(s.T(), err) - - // Check server - server should contain keystore files for imported seed phrase - require.True(s.T(), containsKeystoreFile(serverKeystorePath, serverKp.DerivedFrom[2:])) - for _, acc := range serverKp.Accounts { - require.True(s.T(), containsKeystoreFile(serverKeystorePath, acc.Address.String()[2:])) - } - - // Check client - client should contain keystore files for imported seed phrase - require.True(s.T(), containsKeystoreFile(clientKeystorePath, clientKp.DerivedFrom[2:])) - for _, acc := range clientKp.Accounts { - require.True(s.T(), containsKeystoreFile(clientKeystorePath, acc.Address.String()[2:])) + found := false + for _, i := range response.Installations { + found = i.ID == settings.InstallationID && + i.InstallationMetadata != nil && + i.InstallationMetadata.Name == im1.Name && + i.InstallationMetadata.DeviceType == im1.DeviceType + if found { + break } } -*/ + s.Require().True(found) + + err = serverMessenger.EnableInstallation(settings.InstallationID) + s.Require().NoError(err) + + // Check if the logged in account is the same on server and client + serverActiveAccount, err := serverBackend.GetActiveAccount() + require.NoError(s.T(), err) + clientActiveAccount, err := clientBackend.GetActiveAccount() + require.NoError(s.T(), err) + require.True(s.T(), serverActiveAccount.KeyUID == clientActiveAccount.KeyUID) + + ////////////////////////////////////////////////////////////////////////////// + // From this point this test is trying to simulate the following scenario: + // - add a new seed phrase keypair on server + // - sync it to client + // - convert it to a keycard keypair on server + // - sync it to client + // - stop using keycard on server + // - sync it to client + // - try to transfer keystore files from server to client + ////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// + // Add new seed phrase keypair to server and sync it to client + ////////////////////////////////////////////////////////////////////////////// + serverSeedPhraseKp := s.getSeedPhraseKeypairForTest(serverBackend, seedKeypairMnemonic1, true) + err = serverAccountsAPI.ImportMnemonic(ctx, seedKeypairMnemonic1, s.password) + require.NoError(s.T(), err, "importing mnemonic for new keypair on server") + err = serverAccountsAPI.AddKeypair(ctx, s.password, serverSeedPhraseKp) + require.NoError(s.T(), err, "saving seed phrase keypair on server with keystore files created") + + // Wait for sync messages to be received on client + err = tt.RetryWithBackOff(func() error { + response, err := clientMessenger.RetrieveAll() + if err != nil { + return err + } + + for _, kp := range response.Keypairs { + if kp.KeyUID == serverSeedPhraseKp.KeyUID { + return nil + } + } + + return errors.New("no sync keypair received") + }) + s.Require().NoError(err) + + // Check if the keypair saved on client is the same as the one on server + serverKp, err := serverAccountsAPI.GetKeypairByKeyUID(ctx, serverSeedPhraseKp.KeyUID) + s.Require().NoError(err) + clientKp, err := clientAccountsAPI.GetKeypairByKeyUID(ctx, serverSeedPhraseKp.KeyUID) + s.Require().NoError(err) + + s.Require().True(serverKp.KeyUID == clientKp.KeyUID && + serverKp.Name == clientKp.Name && + serverKp.Type == clientKp.Type && + serverKp.DerivedFrom == clientKp.DerivedFrom && + serverKp.LastUsedDerivationIndex == clientKp.LastUsedDerivationIndex && + serverKp.Clock == clientKp.Clock && + len(serverKp.Accounts) == len(clientKp.Accounts) && + len(serverKp.Keycards) == len(clientKp.Keycards)) + + // Check server - server should contain keystore files for imported seed phrase + serverKeystorePath := filepath.Join(serverTmpDir, keystoreDir, serverActiveAccount.KeyUID) + require.True(s.T(), containsKeystoreFile(serverKeystorePath, serverKp.DerivedFrom[2:])) + for _, acc := range serverKp.Accounts { + require.True(s.T(), containsKeystoreFile(serverKeystorePath, acc.Address.String()[2:])) + } + + // Check client - client should not contain keystore files for imported seed phrase + clientKeystorePath := filepath.Join(clientTmpDir, keystoreDir, clientActiveAccount.KeyUID) + require.False(s.T(), containsKeystoreFile(clientKeystorePath, clientKp.DerivedFrom[2:])) + for _, acc := range clientKp.Accounts { + require.False(s.T(), containsKeystoreFile(clientKeystorePath, acc.Address.String()[2:])) + } + + ////////////////////////////////////////////////////////////////////////////// + // Convert it to a keycard keypair on server and sync it to client + ////////////////////////////////////////////////////////////////////////////// + err = serverAccountsAPI.SaveOrUpdateKeycard(ctx, &accounts.Keycard{ + KeycardUID: "1234", + KeycardName: "new-keycard", + KeyUID: serverKp.KeyUID, + AccountsAddresses: []types.Address{serverKp.Accounts[0].Address, serverKp.Accounts[1].Address}, + }, false) + s.Require().NoError(err) + + // Wait for sync messages to be received on client + err = tt.RetryWithBackOff(func() error { + response, err := clientMessenger.RetrieveAll() + if err != nil { + return err + } + + for _, kp := range response.Keypairs { + if kp.KeyUID == serverKp.KeyUID { + return nil + } + } + return errors.New("no sync keypair received") + }) + s.Require().NoError(err) + + // Check if the keypair saved on client is the same as the one on server + serverKp, err = serverAccountsAPI.GetKeypairByKeyUID(ctx, serverSeedPhraseKp.KeyUID) + s.Require().NoError(err) + clientKp, err = clientAccountsAPI.GetKeypairByKeyUID(ctx, serverSeedPhraseKp.KeyUID) + s.Require().NoError(err) + + s.Require().True(serverKp.KeyUID == clientKp.KeyUID && + serverKp.Name == clientKp.Name && + serverKp.Type == clientKp.Type && + serverKp.DerivedFrom == clientKp.DerivedFrom && + serverKp.LastUsedDerivationIndex == clientKp.LastUsedDerivationIndex && + serverKp.Clock == clientKp.Clock && + len(serverKp.Accounts) == len(clientKp.Accounts) && + len(serverKp.Keycards) == len(clientKp.Keycards) && + len(serverKp.Keycards) == 1) + + // Check server - server should not contain keystore files for imported seed phrase + require.False(s.T(), containsKeystoreFile(serverKeystorePath, serverKp.DerivedFrom[2:])) + for _, acc := range serverKp.Accounts { + require.False(s.T(), containsKeystoreFile(serverKeystorePath, acc.Address.String()[2:])) + } + + // Check client - client should not contain keystore files for imported seed phrase + require.False(s.T(), containsKeystoreFile(clientKeystorePath, clientKp.DerivedFrom[2:])) + for _, acc := range clientKp.Accounts { + require.False(s.T(), containsKeystoreFile(clientKeystorePath, acc.Address.String()[2:])) + } + + ////////////////////////////////////////////////////////////////////////////// + // Stop using keycard on server and sync it to client + ////////////////////////////////////////////////////////////////////////////// + err = serverAccountsAPI.MigrateNonProfileKeycardKeypairToApp(ctx, seedKeypairMnemonic1, s.password) + s.Require().NoError(err) + + // Wait for sync messages to be received on client + err = tt.RetryWithBackOff(func() error { + response, err := clientMessenger.RetrieveAll() + if err != nil { + return err + } + + for _, kp := range response.Keypairs { + if kp.KeyUID == serverKp.KeyUID { + return nil + } + } + return errors.New("no sync keypair received") + }) + s.Require().NoError(err) + + // Check if the keypair saved on client is the same as the one on server + serverKp, err = serverAccountsAPI.GetKeypairByKeyUID(ctx, serverSeedPhraseKp.KeyUID) + s.Require().NoError(err) + clientKp, err = clientAccountsAPI.GetKeypairByKeyUID(ctx, serverSeedPhraseKp.KeyUID) + s.Require().NoError(err) + + s.Require().True(serverKp.KeyUID == clientKp.KeyUID && + serverKp.Name == clientKp.Name && + serverKp.Type == clientKp.Type && + serverKp.DerivedFrom == clientKp.DerivedFrom && + serverKp.LastUsedDerivationIndex == clientKp.LastUsedDerivationIndex && + serverKp.Clock == clientKp.Clock && + len(serverKp.Accounts) == len(clientKp.Accounts) && + len(serverKp.Keycards) == len(clientKp.Keycards) && + len(serverKp.Keycards) == 0) + + // Check server - server should contain keystore files for imported seed phrase + require.True(s.T(), containsKeystoreFile(serverKeystorePath, serverKp.DerivedFrom[2:])) + for _, acc := range serverKp.Accounts { + require.True(s.T(), containsKeystoreFile(serverKeystorePath, acc.Address.String()[2:])) + } + + // Check client - client should not contain keystore files for imported seed phrase + require.False(s.T(), containsKeystoreFile(clientKeystorePath, clientKp.DerivedFrom[2:])) + for _, acc := range clientKp.Accounts { + require.False(s.T(), containsKeystoreFile(clientKeystorePath, acc.Address.String()[2:])) + } + + ////////////////////////////////////////////////////////////////////////////// + // Try to transfer keystore files from server to client + ////////////////////////////////////////////////////////////////////////////// + + serverMessenger.SetLocalPairing(true) + clientMessenger.SetLocalPairing(true) + + // prepare sender + var config = KeystoreFilesSenderServerConfig{ + SenderConfig: &KeystoreFilesSenderConfig{ + KeystoreFilesConfig: KeystoreFilesConfig{ + KeystorePath: serverKeystorePath, + LoggedInKeyUID: serverActiveAccount.KeyUID, + Password: s.password, + }, + KeypairsToExport: []string{serverKp.KeyUID}, + }, + ServerConfig: new(ServerConfig), + } + configBytes, err := json.Marshal(config) + require.NoError(s.T(), err) + cs, err := StartUpKeystoreFilesSenderServer(serverBackend, string(configBytes)) + require.NoError(s.T(), err) + + // prepare receiver + clientPayloadSourceConfig := KeystoreFilesReceiverClientConfig{ + ReceiverConfig: &KeystoreFilesReceiverConfig{ + KeystoreFilesConfig: KeystoreFilesConfig{ + KeystorePath: clientKeystorePath, + LoggedInKeyUID: clientActiveAccount.KeyUID, + Password: s.password, + }, + KeypairsToImport: []string{clientKp.KeyUID}, + }, + ClientConfig: new(ClientConfig), + } + clientConfigBytes, err := json.Marshal(clientPayloadSourceConfig) + require.NoError(s.T(), err) + err = StartUpKeystoreFilesReceivingClient(clientBackend, cs, string(clientConfigBytes)) + require.NoError(s.T(), err) + + // Check server - server should contain keystore files for imported seed phrase + require.True(s.T(), containsKeystoreFile(serverKeystorePath, serverKp.DerivedFrom[2:])) + for _, acc := range serverKp.Accounts { + require.True(s.T(), containsKeystoreFile(serverKeystorePath, acc.Address.String()[2:])) + } + + // Check client - client should contain keystore files for imported seed phrase + require.True(s.T(), containsKeystoreFile(clientKeystorePath, clientKp.DerivedFrom[2:])) + for _, acc := range clientKp.Accounts { + require.True(s.T(), containsKeystoreFile(clientKeystorePath, acc.Address.String()[2:])) + } +} + func (s *SyncDeviceSuite) TestPreventLoggedInAccountLocalPairingClientAsReceiver() { clientTmpDir := filepath.Join(s.clientAsSenderTmpdir, "client") clientBackend := s.prepareBackendWithAccount("", clientTmpDir)