Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix_: community sync #5880

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 2 additions & 39 deletions protocol/communities/community_events_processing.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package communities

import (
"crypto/ecdsa"
"errors"
"sort"

"github.com/golang/protobuf/proto"
"go.uber.org/zap"

utils "github.com/status-im/status-go/common"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/protobuf"
)
Expand Down Expand Up @@ -53,7 +51,7 @@ func (e *eventsProcessor) exec() error {
}

func (e *eventsProcessor) validateDescription() error {
description, err := validateAndGetEventsMessageCommunityDescription(e.message.EventsBaseCommunityDescription, e.community.ControlNode())
description, err := unmarshalCommunityDescriptionMessage(e.message.EventsBaseCommunityDescription, e.community.ControlNode())
if err != nil {
return err
}
Expand Down Expand Up @@ -285,7 +283,7 @@ func (o *Community) addNewCommunityEvent(event *CommunityEvent) error {
// If there were no events before, extract CommunityDescription from CommunityDescriptionProtocolMessage
// and check the signature
if o.config.EventsData == nil || len(o.config.EventsData.EventsBaseCommunityDescription) == 0 {
_, err := validateAndGetEventsMessageCommunityDescription(o.config.CommunityDescriptionProtocolMessage, o.ControlNode())
_, err := unmarshalCommunityDescriptionMessage(o.config.CommunityDescriptionProtocolMessage, o.ControlNode())
if err != nil {
return err
}
Expand Down Expand Up @@ -313,38 +311,3 @@ func (o *Community) toCommunityEventsMessage() *CommunityEventsMessage {
Events: o.config.EventsData.Events,
}
}

func validateAndGetEventsMessageCommunityDescription(signedDescription []byte, signerPubkey *ecdsa.PublicKey) (*protobuf.CommunityDescription, error) {
metadata := &protobuf.ApplicationMetadataMessage{}

err := proto.Unmarshal(signedDescription, metadata)
if err != nil {
return nil, err
}

if metadata.Type != protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION {
return nil, ErrInvalidMessage
}

signer, err := utils.RecoverKey(metadata)
if err != nil {
return nil, err
}

if signer == nil {
return nil, errors.New("CommunityDescription does not contain the control node signature")
}

if !signer.Equal(signerPubkey) {
return nil, errors.New("CommunityDescription was not signed by an owner")
}

description := &protobuf.CommunityDescription{}

err = proto.Unmarshal(metadata.Payload, description)
if err != nil {
return nil, err
}

return description, nil
}
95 changes: 47 additions & 48 deletions protocol/communities/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -3491,6 +3491,17 @@
}

func (m *Manager) HandleCommunityRequestToJoinResponse(signer *ecdsa.PublicKey, request *protobuf.CommunityRequestToJoinResponse) (*RequestToJoin, error) {
if len(request.CommunityDescriptionMessage) > 0 {
description, err := unmarshalCommunityDescriptionMessage(request.CommunityDescriptionMessage, signer)
if err != nil {
return nil, err

Check warning on line 3497 in protocol/communities/manager.go

View check run for this annotation

Codecov / codecov/patch

protocol/communities/manager.go#L3497

Added line #L3497 was not covered by tests
}
_, err = m.HandleCommunityDescriptionMessage(signer, description, request.CommunityDescriptionMessage, nil, nil)
if err != nil {
return nil, err

Check warning on line 3501 in protocol/communities/manager.go

View check run for this annotation

Codecov / codecov/patch

protocol/communities/manager.go#L3501

Added line #L3501 was not covered by tests
}
}

m.communityLock.Lock(request.CommunityId)
defer m.communityLock.Unlock(request.CommunityId)

Expand All @@ -3501,66 +3512,19 @@
return nil, err
}

communityDescriptionBytes, err := proto.Marshal(request.Community)
if err != nil {
return nil, err
}

// We need to wrap `request.Community` in an `ApplicationMetadataMessage`
// of type `CommunityDescription` because `UpdateCommunityDescription` expects this.
//
// This is merely for marsheling/unmarsheling, hence we attaching a `Signature`
// is not needed.
metadataMessage := &protobuf.ApplicationMetadataMessage{
Payload: communityDescriptionBytes,
Type: protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION,
}

appMetadataMsg, err := proto.Marshal(metadataMessage)
if err != nil {
return nil, err
}

isControlNodeSigner := common.IsPubKeyEqual(community.ControlNode(), signer)
if !isControlNodeSigner {
m.logger.Debug("signer is not control node", zap.String("signer", common.PubkeyToHex(signer)), zap.String("controlNode", common.PubkeyToHex(community.ControlNode())))
return nil, ErrNotAuthorized
}

_, processedDescription, err := m.preprocessDescription(community.ID(), request.Community)
if err != nil {
return nil, err
}

_, err = community.UpdateCommunityDescription(processedDescription, appMetadataMsg, nil)
if err != nil {
return nil, err
}

if err = m.handleCommunityTokensMetadata(community); err != nil {
return nil, err
}

Comment on lines -3504 to -3543
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, don't we want to keep this around for 3 versions, until users upgrade?
(only process it if CommunityDescriptionMessage is missing)

if community.Encrypted() && len(request.Grant) > 0 {
_, err = m.HandleCommunityGrant(community, request.Grant, request.Clock)
if err != nil && err != ErrGrantOlder && err != ErrGrantExpired {
m.logger.Error("Error handling a community grant", zap.Error(err))
}
}

err = m.persistence.SaveCommunity(community)

if err != nil {
return nil, err
}

if request.Accepted {
err = m.markRequestToJoinAsAccepted(&m.identity.PublicKey, community)
if err != nil {
return nil, err
}
} else {

err = m.persistence.SetRequestToJoinState(pkString, community.ID(), RequestToJoinStateDeclined)
if err != nil {
return nil, err
Expand Down Expand Up @@ -3924,7 +3888,7 @@
community.config.CommunityDescription = description

if community.config.EventsData != nil {
eventsDescription, err := validateAndGetEventsMessageCommunityDescription(community.config.EventsData.EventsBaseCommunityDescription, community.ControlNode())
eventsDescription, err := unmarshalCommunityDescriptionMessage(community.config.EventsData.EventsBaseCommunityDescription, community.ControlNode())
if err != nil {
m.logger.Error("invalid EventsBaseCommunityDescription", zap.Error(err))
}
Expand Down Expand Up @@ -5259,3 +5223,38 @@
func (m *Manager) UpdateEncryptionKeysRequests(communityID types.HexBytes, channelIDs []string) error {
return m.updateEncryptionKeysRequests(communityID, channelIDs, time.Now().UnixMilli())
}

func unmarshalCommunityDescriptionMessage(signedDescription []byte, signerPubkey *ecdsa.PublicKey) (*protobuf.CommunityDescription, error) {
metadata := &protobuf.ApplicationMetadataMessage{}

err := proto.Unmarshal(signedDescription, metadata)
if err != nil {
return nil, err

Check warning on line 5232 in protocol/communities/manager.go

View check run for this annotation

Codecov / codecov/patch

protocol/communities/manager.go#L5232

Added line #L5232 was not covered by tests
}

if metadata.Type != protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION {
return nil, ErrInvalidMessage

Check warning on line 5236 in protocol/communities/manager.go

View check run for this annotation

Codecov / codecov/patch

protocol/communities/manager.go#L5236

Added line #L5236 was not covered by tests
}

signer, err := utils.RecoverKey(metadata)
if err != nil {
return nil, err

Check warning on line 5241 in protocol/communities/manager.go

View check run for this annotation

Codecov / codecov/patch

protocol/communities/manager.go#L5241

Added line #L5241 was not covered by tests
}

if signer == nil {
return nil, errors.New("CommunityDescription does not contain the control node signature")

Check warning on line 5245 in protocol/communities/manager.go

View check run for this annotation

Codecov / codecov/patch

protocol/communities/manager.go#L5245

Added line #L5245 was not covered by tests
}

if !signer.Equal(signerPubkey) {
return nil, errors.New("CommunityDescription was not signed by an owner")

Check warning on line 5249 in protocol/communities/manager.go

View check run for this annotation

Codecov / codecov/patch

protocol/communities/manager.go#L5249

Added line #L5249 was not covered by tests
}

description := &protobuf.CommunityDescription{}

err = proto.Unmarshal(metadata.Payload, description)
if err != nil {
return nil, err

Check warning on line 5256 in protocol/communities/manager.go

View check run for this annotation

Codecov / codecov/patch

protocol/communities/manager.go#L5256

Added line #L5256 was not covered by tests
}

return description, nil
}
16 changes: 8 additions & 8 deletions protocol/communities_messenger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4661,17 +4661,17 @@ func (s *MessengerCommunitiesSuite) TestAliceDidNotProcessOutdatedCommunityReque
s.Require().NoError(err)
}

encryptedDescription, err := community.EncryptedDescription()
descriptionMessage, err := community.ToProtocolMessageBytes()
s.Require().NoError(err)

requestToJoinResponse := &protobuf.CommunityRequestToJoinResponse{
Clock: community.Clock(),
Accepted: true,
CommunityId: community.ID(),
Community: encryptedDescription,
Grant: grant,
ProtectedTopicPrivateKey: crypto.FromECDSA(key),
Shard: community.Shard().Protobuffer(),
Clock: community.Clock(),
Accepted: true,
CommunityId: community.ID(),
Grant: grant,
ProtectedTopicPrivateKey: crypto.FromECDSA(key),
Shard: community.Shard().Protobuffer(),
CommunityDescriptionMessage: descriptionMessage,
}

// alice handle duplicated request to join response
Expand Down
2 changes: 1 addition & 1 deletion protocol/messenger.go
Original file line number Diff line number Diff line change
Expand Up @@ -3634,7 +3634,7 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
err := m.dispatchToHandler(messageState, msg.ApplicationLayer.Payload, msg, filter, fromArchive)
if err != nil {
allMessagesProcessed = false
logger.Warn("failed to process protobuf", zap.Error(err))
logger.Warn("failed to process protobuf", zap.String("type", msg.ApplicationLayer.Type.String()), zap.Error(err))
if m.unhandledMessagesTracker != nil {
m.unhandledMessagesTracker(msg, err)
}
Expand Down
20 changes: 13 additions & 7 deletions protocol/messenger_communities.go
Original file line number Diff line number Diff line change
Expand Up @@ -1989,14 +1989,20 @@
return nil, err
}

descriptionMessage, err := community.ToProtocolMessageBytes()
if err != nil {
return nil, err

Check warning on line 1994 in protocol/messenger_communities.go

View check run for this annotation

Codecov / codecov/patch

protocol/messenger_communities.go#L1994

Added line #L1994 was not covered by tests
}

requestToJoinResponseProto := &protobuf.CommunityRequestToJoinResponse{
Clock: community.Clock(),
Accepted: true,
CommunityId: community.ID(),
Community: encryptedDescription,
Grant: grant,
ProtectedTopicPrivateKey: crypto.FromECDSA(key),
Shard: community.Shard().Protobuffer(),
Clock: community.Clock(),
Accepted: true,
CommunityId: community.ID(),
Community: encryptedDescription, // Deprecated but kept for backward compatibility, to be removed in future
Grant: grant,
ProtectedTopicPrivateKey: crypto.FromECDSA(key),
Shard: community.Shard().Protobuffer(),
CommunityDescriptionMessage: descriptionMessage,
}

// The purpose of this torrent code is to get the 'magnetlink' to populate 'requestToJoinResponseProto.MagnetUri'
Expand Down
5 changes: 1 addition & 4 deletions protocol/messenger_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -1700,7 +1700,7 @@ func (m *Messenger) HandleCommunityRequestToJoinResponse(state *ReceivedMessageS
communityShardKey := &protobuf.CommunityShardKey{
CommunityId: requestToJoinResponseProto.CommunityId,
PrivateKey: requestToJoinResponseProto.ProtectedTopicPrivateKey,
Clock: requestToJoinResponseProto.Community.Clock,
Clock: community.Clock(),
Shard: requestToJoinResponseProto.Shard,
}

Expand Down Expand Up @@ -1765,9 +1765,6 @@ func (m *Messenger) HandleCommunityRequestToJoinResponse(state *ReceivedMessageS

m.downloadAndImportHistoryArchives(community.ID(), magnetlink, task.CancelChan)
}(currentTask)

clock := requestToJoinResponseProto.Community.ArchiveMagnetlinkClock
return m.communitiesManager.UpdateMagnetlinkMessageClock(community.ID(), clock)
}
}

Expand Down
4 changes: 3 additions & 1 deletion protocol/protobuf/communities.proto
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,15 @@ message CommunityUserKicked {

message CommunityRequestToJoinResponse {
uint64 clock = 1;
CommunityDescription community = 2;
CommunityDescription community = 2 [deprecated = true];
bool accepted = 3;
bytes grant = 4;
bytes community_id = 5;
string magnet_uri = 6;
bytes protected_topic_private_key = 7;
Shard shard = 8;
// CommunityDescription with owner signature
bytes community_description_message = 9;
}

message CommunityRequestToLeave {
Expand Down