-
Notifications
You must be signed in to change notification settings - Fork 12
/
public_key_topic.go
188 lines (162 loc) Β· 6.86 KB
/
public_key_topic.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package pubsub
import (
"encoding/hex"
"encoding/json"
"errors"
pubsub "github.com/libp2p/go-libp2p-pubsub"
libp2pCrypto "github.com/libp2p/go-libp2p/core/crypto"
"github.com/masa-finance/masa-oracle/pkg/consensus"
"github.com/sirupsen/logrus"
)
// topicPublicKeyMap maps topics to their associated public keys.
var topicPublicKeyMap = make(map[string]string)
// PublicKeySubscriptionHandler handles incoming messages on public key topics.
type PublicKeySubscriptionHandler struct {
PublicKeys []PublicKeyMessage
PubKeyTopic *pubsub.Topic
}
type PublicKeyPublisher struct {
pubSubManager *Manager
pubKey libp2pCrypto.PubKey
publishedMessages []PublicKeyMessage
}
// PublicKeyMessage represents the structure of the public key messages.
type PublicKeyMessage struct {
PublicKey string `json:"publicKey"`
Signature string `json:"signature"`
Data string `json:"data"`
}
// NewPublicKeyPublisher creates a new instance of PublicKeyPublisher.
func NewPublicKeyPublisher(manager *Manager, pubKey libp2pCrypto.PubKey) *PublicKeyPublisher {
logrus.Info("Creating new PublicKeyPublisher")
return &PublicKeyPublisher{
pubSubManager: manager,
pubKey: pubKey,
}
}
// PublishNodePublicKey publishes the node's public key to the designated topic.
func (p *PublicKeyPublisher) PublishNodePublicKey(publicKey string, data, signature []byte) error {
topicName := "bootNodePublicKey"
logrus.Infof("[PublicKeyPublisher] Publishing node's public key to topic: %s", topicName)
// Ensure the topic exists or create it
_, err := p.ensureTopic(topicName)
if err != nil {
logrus.WithError(err).Errorf("[PublicKeyPublisher] Failed to ensure topic '%s' exists", topicName)
return err
}
// Check if a public key has already been published to the topic
existingPubKey, exists := topicPublicKeyMap[topicName]
if exists {
logrus.Infof("[PublicKeyPublisher] Public key already published for topic: %s. Verifying signature.", topicName)
// If a public key exists, verify the signature against the existing public key
pubKeyBytes, err := hex.DecodeString(existingPubKey)
if err != nil {
logrus.WithError(err).Error("[PublicKeyPublisher] Failed to decode existing public key for verification")
return err
}
pubKey, err := libp2pCrypto.UnmarshalPublicKey(pubKeyBytes)
if err != nil {
logrus.WithError(err).Error("[PublicKeyPublisher] Failed to unmarshal existing public key for verification")
return err
}
isValid, err := pubKey.Verify(data, signature)
if err != nil || !isValid {
logrus.WithError(err).Error("[PublicKeyPublisher] Unauthorized: Failed signature verification or signature is invalid")
return errors.New("unauthorized: only the owner of the public key can publish changes")
}
logrus.Info("[PublicKeyPublisher] Signature verified successfully for topic: ", topicName)
} else {
logrus.Infof("[PublicKeyPublisher] No existing public key for topic: %s. Proceeding with initial publication.", topicName)
// If no public key is associated with the topic, this is the initial publication
topicPublicKeyMap[topicName] = publicKey
}
// Serialize the public key message
msg := PublicKeyMessage{
PublicKey: publicKey,
Signature: hex.EncodeToString(signature),
Data: string(data),
}
msgBytes, err := json.Marshal(msg)
if err != nil {
logrus.WithError(err).Error("[PublicKeyPublisher] Failed to marshal public key message")
return errors.New("failed to marshal message")
}
// Use the existing Manager to publish the message
logrus.Infof("[PublicKeyPublisher] Publishing serialized message to topic: %s", topicName)
if err := p.pubSubManager.Publish(topicName, msgBytes); err != nil {
return err
}
// Store the published message in the slice
p.publishedMessages = append(p.publishedMessages, msg)
logrus.Infof("[PublicKeyPublisher] Stored published message for topic: %s", topicName)
// Print the published data in the console
logrus.Infof("[PublicKeyPublisher] Published data: PublicKey: %s, Signature: %s, Data: %s", msg.PublicKey, msg.Signature, msg.Data)
return nil
}
// ensureTopic checks if a topic exists and creates it if not.
func (p *PublicKeyPublisher) ensureTopic(topicName string) (*pubsub.Topic, error) {
// Check if the topic already exists
if topic, exists := p.pubSubManager.topics[topicName]; exists {
return topic, nil
}
// If the topic does not exist, attempt to create it
topic, err := p.pubSubManager.createTopic(topicName)
if err != nil {
return nil, err
}
return topic, nil
}
// HandleMessage handles incoming public key messages, with verification and update logic.
func (handler *PublicKeySubscriptionHandler) HandleMessage(m *pubsub.Message) {
logrus.Info("Handling incoming public key message")
var incomingMsg PublicKeyMessage
if err := json.Unmarshal(m.Data, &incomingMsg); err != nil {
logrus.WithError(err).Error("Failed to unmarshal public key message")
return
}
logrus.Infof("Received public key message: %s", incomingMsg.PublicKey)
// Proceed with verification and update logic as before
for i, existingMsg := range handler.PublicKeys {
if existingMsg.PublicKey == incomingMsg.PublicKey {
logrus.Infof("Verifying signature for public key: %s", incomingMsg.PublicKey)
// Decode the public key from hexadecimal to bytes
pubKeyBytes, err := hex.DecodeString(existingMsg.PublicKey)
if err != nil {
logrus.WithError(err).Error("Failed to decode public key for verification")
return
}
// Unmarshal the public key bytes into a libp2pCrypto.PubKey
pubKey, err := libp2pCrypto.UnmarshalPublicKey(pubKeyBytes)
if err != nil {
logrus.WithError(err).Error("Failed to unmarshal public key for verification")
return
}
// Use the VerifySignature function from the consensus package
isValid, err := consensus.VerifySignature(pubKey, []byte(incomingMsg.Data), incomingMsg.Signature)
if err != nil || !isValid {
logrus.WithError(err).Error("Failed signature verification or signature is invalid")
return // Do not update or add if the signature is invalid
}
// Signature is valid, update the existing message's data
handler.PublicKeys[i].Data = incomingMsg.Data
logrus.Infof("Updated public key message: %s", incomingMsg.PublicKey)
logrus.Info("Data stored in the slice successfully.")
return
}
}
// If no public key is stored yet, add the new message
if len(handler.PublicKeys) == 0 {
handler.PublicKeys = append(handler.PublicKeys, incomingMsg)
logrus.Infof("Added new public key message: %s", incomingMsg.PublicKey)
logrus.Info("Data stored in the slice successfully.")
}
}
// GetPublicKeys returns the list of PublicKeyMessages.
func (handler *PublicKeySubscriptionHandler) GetPublicKeys() []PublicKeyMessage {
logrus.Info("Retrieving stored public keys")
return handler.PublicKeys
}
// Optionally, add a method to retrieve the stored messages
func (p *PublicKeyPublisher) GetPublishedMessages() []PublicKeyMessage {
return p.publishedMessages
}