-
Notifications
You must be signed in to change notification settings - Fork 242
/
messenger_community_shard.go
120 lines (102 loc) · 3.49 KB
/
messenger_community_shard.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package protocol
import (
"context"
"errors"
"github.com/golang/protobuf/proto"
"go.uber.org/zap"
"github.com/status-im/status-go/eth-node/crypto"
"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/shard"
"github.com/status-im/status-go/protocol/communities"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/protocol/transport"
v1protocol "github.com/status-im/status-go/protocol/v1"
)
func (m *Messenger) sendPublicCommunityShardInfo(community *communities.Community) error {
if !community.IsControlNode() {
return communities.ErrNotControlNode
}
publicShardInfo := &protobuf.PublicShardInfo{
Clock: community.Clock(),
CommunityId: community.ID(),
Shard: community.Shard().Protobuffer(),
ChainId: communities.CommunityDescriptionTokenOwnerChainID(community.Description()),
}
payload, err := proto.Marshal(publicShardInfo)
if err != nil {
return err
}
signature, err := crypto.Sign(crypto.Keccak256(payload), community.PrivateKey())
if err != nil {
return err
}
signedShardInfo := &protobuf.CommunityPublicShardInfo{
Signature: signature,
Payload: payload,
}
payload, err = proto.Marshal(signedShardInfo)
if err != nil {
return err
}
rawMessage := common.RawMessage{
Payload: payload,
Sender: community.PrivateKey(),
// we don't want to wrap in an encryption layer message
SkipEncryptionLayer: true,
MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_PUBLIC_SHARD_INFO,
PubsubTopic: shard.DefaultNonProtectedPubsubTopic(), // it must be sent always to default shard pubsub topic
}
chatName := transport.CommunityShardInfoTopic(community.IDString())
_, err = m.sender.SendPublic(context.Background(), chatName, rawMessage)
return err
}
func (m *Messenger) HandleCommunityPublicShardInfo(state *ReceivedMessageState, a *protobuf.CommunityPublicShardInfo, statusMessage *v1protocol.StatusMessage) error {
publicShardInfo := &protobuf.PublicShardInfo{}
err := proto.Unmarshal(a.Payload, publicShardInfo)
if err != nil {
return err
}
logError := func(err error) {
m.logger.Error("HandleCommunityPublicShardInfo failed: ", zap.Error(err), zap.String("communityID", types.EncodeHex(publicShardInfo.CommunityId)))
}
err = m.verifyCommunitySignature(a.Payload, a.Signature, publicShardInfo.CommunityId, publicShardInfo.ChainId)
if err != nil {
logError(err)
return err
}
err = m.communitiesManager.SaveCommunityShard(publicShardInfo.CommunityId, shard.FromProtobuff(publicShardInfo.Shard), publicShardInfo.Clock)
if err != nil && err != communities.ErrOldShardInfo {
logError(err)
return err
}
return nil
}
func (m *Messenger) verifyCommunitySignature(payload, signature, communityID []byte, chainID uint64) error {
if len(signature) == 0 {
return errors.New("missing signature")
}
pubKey, err := crypto.SigToPub(crypto.Keccak256(payload), signature)
if err != nil {
return err
}
pubKeyStr := common.PubkeyToHex(pubKey)
var ownerPublicKey string
if chainID > 0 {
owner, err := m.communitiesManager.SafeGetSignerPubKey(chainID, types.EncodeHex(communityID))
if err != nil {
return err
}
ownerPublicKey = owner
} else {
communityPubkey, err := crypto.DecompressPubkey(communityID)
if err != nil {
return err
}
ownerPublicKey = common.PubkeyToHex(communityPubkey)
}
if pubKeyStr != ownerPublicKey {
return errors.New("signed not by a community owner")
}
return nil
}