fix: tokenMaster does not have members revealed addresses (#4425)

This commit is contained in:
Mykhailo Prakhov 2023-12-07 17:27:14 +01:00 committed by GitHub
parent e0bbb7e2ec
commit fe604b2806
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 242 additions and 92 deletions

View File

@ -4,6 +4,7 @@ import (
"crypto/ecdsa"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/protobuf"
)
@ -33,22 +34,6 @@ func (m *Manager) HandleRequestToJoinPrivilegedUserSyncMessage(message *protobuf
}
requestToJoin.CalculateID()
_, err := m.saveOrUpdateRequestToJoin(communityID, requestToJoin)
if err != nil {
return nil, err
}
requestsToJoin = append(requestsToJoin, requestToJoin)
}
return requestsToJoin, nil
}
func (m *Manager) HandleSyncAllRequestToJoinForNewPrivilegedMember(message *protobuf.CommunityPrivilegedUserSyncMessage, communityID types.HexBytes) ([]*RequestToJoin, error) {
requestsToJoin := []*RequestToJoin{}
for _, syncRequestToJoin := range message.SyncRequestsToJoin {
requestToJoin := new(RequestToJoin)
requestToJoin.InitFromSyncProtobuf(syncRequestToJoin)
if _, err := m.saveOrUpdateRequestToJoin(communityID, requestToJoin); err != nil {
return nil, err
}
@ -62,7 +47,41 @@ func (m *Manager) HandleSyncAllRequestToJoinForNewPrivilegedMember(message *prot
return nil, err
}
}
requestsToJoin = append(requestsToJoin, requestToJoin)
}
return requestsToJoin, nil
}
func (m *Manager) HandleSyncAllRequestToJoinForNewPrivilegedMember(message *protobuf.CommunityPrivilegedUserSyncMessage, communityID types.HexBytes) ([]*RequestToJoin, error) {
nonAcceptedRequestsToJoin := []*RequestToJoin{}
myPk := common.PubkeyToHex(&m.identity.PublicKey)
// We received all requests to join from the control node. Remove all requests to join except our own
err := m.persistence.RemoveAllCommunityRequestsToJoinWithRevealedAddressesExceptPublicKey(myPk, communityID)
if err != nil {
return nil, err
}
for _, syncRequestToJoin := range message.SyncRequestsToJoin {
requestToJoin := new(RequestToJoin)
requestToJoin.InitFromSyncProtobuf(syncRequestToJoin)
if _, err := m.saveOrUpdateRequestToJoin(communityID, requestToJoin); err != nil {
return nil, err
}
if requestToJoin.RevealedAccounts != nil && len(requestToJoin.RevealedAccounts) > 0 {
if err := m.persistence.SaveRequestToJoinRevealedAddresses(requestToJoin.ID, requestToJoin.RevealedAccounts); err != nil {
return nil, err
}
}
if requestToJoin.State != RequestToJoinStateAccepted {
nonAcceptedRequestsToJoin = append(nonAcceptedRequestsToJoin, requestToJoin)
}
}
return nonAcceptedRequestsToJoin, nil
}

View File

@ -1580,9 +1580,8 @@ func (m *Manager) HandleCommunityDescriptionMessage(signer *ecdsa.PublicKey, des
}
}
if hasTokenOwnership {
if hasTokenOwnership && verifiedOwner != nil {
// Override verified owner
if verifiedOwner != nil {
m.logger.Info("updating verified owner", zap.String("communityID", community.IDString()), zap.String("owner", common.PubkeyToHex(verifiedOwner)))
// If we are not the verified owner anymore, drop the private key
@ -1597,9 +1596,6 @@ func (m *Manager) HandleCommunityDescriptionMessage(signer *ecdsa.PublicKey, des
} else if !common.IsPubKeyEqual(community.ControlNode(), signer) {
return nil, ErrNotAuthorized
}
} else if !common.IsPubKeyEqual(community.PublicKey(), signer) {
return nil, ErrNotAuthorized
}
return m.handleCommunityDescriptionMessageCommon(community, description, payload, verifiedOwner)
}
@ -2227,6 +2223,7 @@ func (m *Manager) AcceptRequestToJoin(dbRequest *RequestToJoin) (*Community, err
return nil, err
}
dbRequest.RevealedAccounts = revealedAccounts
if err = m.shareAcceptedRequestToJoinWithPrivilegedMembers(community, dbRequest); err != nil {
return nil, err
}
@ -4925,7 +4922,7 @@ func (m *Manager) shareRequestsToJoinWithNewPrivilegedMembers(community *Communi
case protobuf.CommunityMember_ROLE_ADMIN:
subscriptionMsg.CommunityPrivilegedUserSyncMessage = syncMsgWithoutRevealedAccounts
case protobuf.CommunityMember_ROLE_OWNER:
fallthrough
continue
case protobuf.CommunityMember_ROLE_TOKEN_MASTER:
subscriptionMsg.CommunityPrivilegedUserSyncMessage = syncMsgWitRevealedAccounts
}

View File

@ -1669,3 +1669,12 @@ func (p *Persistence) AllNonApprovedCommunitiesRequestsToJoin() ([]*RequestToJoi
}
return nonApprovedRequestsToJoin, nil
}
func (p *Persistence) RemoveAllCommunityRequestsToJoinWithRevealedAddressesExceptPublicKey(pk string, communityID []byte) error {
_, err := p.db.Exec(`
DELETE FROM communities_requests_to_join_revealed_addresses
WHERE request_id IN (SELECT id FROM communities_requests_to_join WHERE community_id = ? AND public_key != ?);
DELETE FROM communities_requests_to_join
WHERE community_id = ? AND public_key != ?;`, communityID, pk, communityID, pk)
return err
}

View File

@ -757,3 +757,108 @@ func (s *PersistenceSuite) TestAllNonApprovedCommunitiesRequestsToJoin() {
s.Require().NoError(err)
s.Require().Len(result, 6) // all except RequestToJoinStateAccepted
}
func (s *PersistenceSuite) TestRemoveAllCommunityRequestsToJoinWithRevealedAddressesExceptPublicKey() {
myIdentity, err := crypto.GenerateKey()
s.Require().NoError(err, "crypto.GenerateKey shouldn't give any error")
myPk := common.PubkeyToHex(&myIdentity.PublicKey)
clock := uint64(time.Now().Unix())
// add a new community
community := s.makeNewCommunity(myIdentity)
err = s.db.SaveCommunity(community)
s.Require().NoError(err)
// check on empty db
err = s.db.RemoveAllCommunityRequestsToJoinWithRevealedAddressesExceptPublicKey(myPk, community.ID())
s.Require().NoError(err)
// add requests to join to the community
allStates := []RequestToJoinState{
RequestToJoinStatePending,
RequestToJoinStateDeclined,
RequestToJoinStateAccepted,
RequestToJoinStateCanceled,
RequestToJoinStateAcceptedPending,
RequestToJoinStateDeclinedPending,
RequestToJoinStateAwaitingAddresses,
}
allRequestsToJoinIDs := [][]byte{}
for i := range allStates {
identity, err := crypto.GenerateKey()
s.Require().NoError(err)
revealedAccounts := []*protobuf.RevealedAccount{}
for j := 0; j < i; j++ {
acc := &protobuf.RevealedAccount{
Address: "testAddr",
ChainIds: []uint64{123},
IsAirdropAddress: true,
Signature: []byte{},
}
revealedAccounts = append(revealedAccounts, acc)
}
rtj := &RequestToJoin{
ID: types.HexBytes{1, 2, 3, 4, 5, 6, 7, byte(i)},
PublicKey: common.PubkeyToHex(&identity.PublicKey),
Clock: clock,
CommunityID: community.ID(),
State: allStates[i],
RevealedAccounts: revealedAccounts,
}
allRequestsToJoinIDs = append(allRequestsToJoinIDs, rtj.ID)
err = s.db.SaveRequestToJoin(rtj)
s.Require().NoError(err, "SaveRequestToJoin shouldn't give any error")
err = s.db.SaveRequestToJoinRevealedAddresses(rtj.ID, rtj.RevealedAccounts)
s.Require().NoError(err)
}
err = s.db.RemoveAllCommunityRequestsToJoinWithRevealedAddressesExceptPublicKey(myPk, community.ID())
s.Require().NoError(err)
requests, err := s.db.GetCommunityRequestsToJoinWithRevealedAddresses(community.ID())
s.Require().NoError(err)
s.Require().Len(requests, 0)
for _, rtjID := range allRequestsToJoinIDs {
accounts, err := s.db.GetRequestToJoinRevealedAddresses(rtjID)
s.Require().NoError(err)
s.Require().Len(accounts, 0)
}
myRtj := &RequestToJoin{
ID: types.HexBytes{1, 2, 3, 4, 5, 6, 7, 8},
PublicKey: myPk,
Clock: clock,
CommunityID: community.ID(),
State: RequestToJoinStateAccepted,
RevealedAccounts: []*protobuf.RevealedAccount{
{
Address: "testAddr",
ChainIds: []uint64{123},
IsAirdropAddress: true,
Signature: []byte{},
},
},
}
err = s.db.SaveRequestToJoin(myRtj)
s.Require().NoError(err, "SaveRequestToJoin shouldn't give any error")
err = s.db.SaveRequestToJoinRevealedAddresses(myRtj.ID, myRtj.RevealedAccounts)
s.Require().NoError(err)
err = s.db.RemoveAllCommunityRequestsToJoinWithRevealedAddressesExceptPublicKey(myPk, community.ID())
s.Require().NoError(err)
requests, err = s.db.GetCommunityRequestsToJoinWithRevealedAddresses(community.ID())
s.Require().NoError(err)
s.Require().Len(requests, 1)
s.Require().Len(requests[0].RevealedAccounts, 1)
}

View File

@ -1459,7 +1459,7 @@ func testControlNodeHandlesMultipleEventSenderRequestToJoinDecisions(base Commun
// control node receives event sender 1's and 2's decision
_, err = WaitOnMessengerResponse(
base.GetControlNode(),
func(r *MessengerResponse) bool { return len(r.Communities()) > 0 },
func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity) > 0 },
"control node did not receive event senders decision",
)
s.Require().NoError(err)
@ -2032,15 +2032,6 @@ func testJoinedPrivilegedMemberReceiveRequestsToJoin(base CommunityEventsTestsIn
advertiseCommunityTo(s, community, base.GetControlNode(), bob)
advertiseCommunityTo(s, community, base.GetControlNode(), newPrivilegedUser)
requestMember := &requests.RequestToJoinCommunity{
CommunityID: community.ID(),
AddressesToReveal: []string{bobAccountAddress},
ENSName: "bob",
AirdropAddress: bobAccountAddress,
}
requestToJoinCommunity(s, base.GetControlNode(), bob, requestMember)
requestNewPrivilegedUser := &requests.RequestToJoinCommunity{
CommunityID: community.ID(),
AddressesToReveal: []string{eventsSenderAccountAddress},
@ -2060,38 +2051,39 @@ func testJoinedPrivilegedMemberReceiveRequestsToJoin(base CommunityEventsTestsIn
s.Require().NotNil(updatedCommunity)
s.Require().True(updatedCommunity.HasMember(&newPrivilegedUser.identity.PublicKey))
// privileged user should receive request to join from user and its shared addresses from control node
_, err = WaitOnMessengerResponse(
newPrivilegedUser,
base.GetEventSender(),
func(r *MessengerResponse) bool {
requestsToJoin, err := newPrivilegedUser.communitiesManager.GetCommunityRequestsToJoinWithRevealedAddresses(community.ID())
if err != nil {
return false
}
if len(requestsToJoin) != 4 {
s.T().Log("invalid requests to join count:", len(requestsToJoin))
return false
}
for _, request := range requestsToJoin {
if tokenPermissionType == protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER {
if len(request.RevealedAccounts) != 1 {
s.T().Log("no accounts revealed")
return false
}
} else {
if len(request.RevealedAccounts) != 0 {
s.T().Log("unexpected accounts revealed")
return false
}
}
}
return true
return len(r.Communities()) > 0 &&
len(r.Communities()[0].TokenPermissionsByType(tokenPermissionType)) > 0 &&
r.Communities()[0].HasPermissionToSendCommunityEvents()
},
"newPrivilegedUser did not receive all requests to join from the control node",
"newPrivilegedUser did not receive privileged role",
)
s.Require().NoError(err)
expectedLength := 3
// newPrivilegedUser user should receive all requests to join with shared addresses from the control node
waitAndCheckRequestsToJoin(s, newPrivilegedUser, expectedLength, community.ID(), tokenPermissionType == protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER)
// bob joins the community
requestMember := &requests.RequestToJoinCommunity{
CommunityID: community.ID(),
AddressesToReveal: []string{bobAccountAddress},
ENSName: "bob",
AirdropAddress: bobAccountAddress,
}
bobRequestToJoinID := requestToJoinCommunity(s, base.GetControlNode(), bob, requestMember)
// accept join request
acceptRequestToJoin = &requests.AcceptRequestToJoinCommunity{ID: bobRequestToJoinID}
_, err = base.GetControlNode().AcceptRequestToJoinCommunity(acceptRequestToJoin)
s.Require().NoError(err)
expectedLength = 4
waitAndCheckRequestsToJoin(s, newPrivilegedUser, expectedLength, community.ID(), tokenPermissionType == protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER)
}
func testMemberReceiveRequestsToJoinAfterGettingNewRole(base CommunityEventsTestsInterface, bob *Messenger, tokenPermissionType protobuf.CommunityTokenPermission_Type) {
@ -2102,7 +2094,6 @@ func testMemberReceiveRequestsToJoinAfterGettingNewRole(base CommunityEventsTest
// control node creates a community and chat
community := createTestCommunity(base, protobuf.CommunityPermissions_MANUAL_ACCEPT)
refreshMessengerResponses(base)
advertiseCommunityTo(s, community, base.GetControlNode(), base.GetEventSender())
advertiseCommunityTo(s, community, base.GetControlNode(), base.GetMember())
@ -2152,27 +2143,56 @@ func testMemberReceiveRequestsToJoinAfterGettingNewRole(base CommunityEventsTest
s.Require().NoError(err)
assertCheckTokenPermissionCreated(s, ownerCommunity, rolePermission.Type)
// receive request to join msg
_, err = WaitOnMessengerResponse(
base.GetEventSender(),
func(r *MessengerResponse) bool {
return len(r.RequestsToJoinCommunity) > 2
return len(r.Communities()) > 0 &&
len(r.Communities()[0].TokenPermissionsByType(tokenPermissionType)) > 0 &&
r.Communities()[0].HasPermissionToSendCommunityEvents()
},
"Event sender did not receive all requests to join from the control node",
"event sender did not receive privileged role",
)
s.Require().NoError(err)
expectedLength := 3
waitAndCheckRequestsToJoin(s, base.GetEventSender(), expectedLength, community.ID(), tokenPermissionType == protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER)
}
func waitAndCheckRequestsToJoin(s *suite.Suite, user *Messenger, expectedLength int, communityID types.HexBytes, checkRevealedAddresses bool) {
_, err := WaitOnMessengerResponse(
user,
func(r *MessengerResponse) bool {
requestsToJoin, err := user.communitiesManager.GetCommunityRequestsToJoinWithRevealedAddresses(communityID)
if err != nil {
return false
}
if len(requestsToJoin) != expectedLength {
s.T().Log("invalid requests to join count:", len(requestsToJoin))
return false
}
for _, request := range requestsToJoin {
if request.PublicKey == common.PubkeyToHex(&user.identity.PublicKey) {
if len(request.RevealedAccounts) != 1 {
s.T().Log("our own requests to join must always have accounts revealed")
return false
}
} else if checkRevealedAddresses {
if len(request.RevealedAccounts) != 1 {
s.T().Log("no accounts revealed")
return false
}
} else {
if len(request.RevealedAccounts) != 0 {
s.T().Log("unexpected accounts revealed")
return false
}
}
}
return true
},
"user did not receive all requests to join from the control node",
)
s.Require().NoError(err)
requestsToJoin, err := base.GetEventSender().communitiesManager.GetCommunityRequestsToJoinWithRevealedAddresses(community.ID())
s.Require().NoError(err)
// event sender, bob and alice requests
s.Require().Len(requestsToJoin, 3)
// check if revealed addresses are present based on the role
for _, request := range requestsToJoin {
if tokenPermissionType == protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER {
s.Require().Len(request.RevealedAccounts, 1)
} else {
s.Require().Len(request.RevealedAccounts, 0)
}
}
}

View File

@ -3026,18 +3026,18 @@ func (m *Messenger) handleCommunityPrivilegedUserSyncMessage(state *ReceivedMess
return err
}
if community == nil {
return communities.ErrOrgNotFound
}
// Currently this type of msg coming from the control node.
// If it will change in the future, check that events types starting from
// CONTROL_NODE were sent by a control node
isControlNodeMsg := common.IsPubKeyEqual(community.PublicKey(), signer)
isControlNodeMsg := common.IsPubKeyEqual(community.ControlNode(), signer)
if !isControlNodeMsg {
return errors.New("accepted/requested to join sync messages can be send only by the control node")
}
if community == nil {
return errors.New("community not found")
}
err = m.communitiesManager.ValidateCommunityPrivilegedUserSyncMessage(message)
if err != nil {
return err
@ -3054,11 +3054,11 @@ func (m *Messenger) handleCommunityPrivilegedUserSyncMessage(state *ReceivedMess
state.Response.AddRequestsToJoinCommunity(requestsToJoin)
case protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ALL_SYNC_REQUESTS_TO_JOIN:
requestsToJoin, err := m.communitiesManager.HandleSyncAllRequestToJoinForNewPrivilegedMember(message, community.ID())
nonAcceptedRequestsToJoin, err := m.communitiesManager.HandleSyncAllRequestToJoinForNewPrivilegedMember(message, community.ID())
if err != nil {
return nil
}
state.Response.AddRequestsToJoinCommunity(requestsToJoin)
state.Response.AddRequestsToJoinCommunity(nonAcceptedRequestsToJoin)
}
return nil