mirror of https://github.com/status-im/go-waku.git
chore: add unit test for signed validator and --protected-topic-flag
This commit is contained in:
parent
f2d2e8127a
commit
837a0f2708
|
@ -206,6 +206,14 @@ var (
|
|||
Destination: &options.Relay.Topics,
|
||||
EnvVars: []string{"WAKUNODE2_TOPICS"},
|
||||
})
|
||||
ProtectedTopics = cliutils.NewGenericFlagMultiValue(&cli.GenericFlag{
|
||||
Name: "protected-topic",
|
||||
Usage: "Topics and its public key to be used for message validation, topic:pubkey. Argument may be repeated.",
|
||||
EnvVars: []string{"WAKUNODE2_PROTECTED_TOPIC"},
|
||||
Value: &cliutils.ProtectedTopicSlice{
|
||||
Values: &options.Relay.ProtectedTopics,
|
||||
},
|
||||
})
|
||||
RelayPeerExchange = altsrc.NewBoolFlag(&cli.BoolFlag{
|
||||
Name: "relay-peer-exchange",
|
||||
Value: false,
|
||||
|
|
|
@ -45,6 +45,7 @@ func main() {
|
|||
AgentString,
|
||||
Relay,
|
||||
Topics,
|
||||
ProtectedTopics,
|
||||
RelayPeerExchange,
|
||||
MinRelayPeersToPublish,
|
||||
StoreNodeFlag,
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
package cliutils
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
type ProtectedTopic struct {
|
||||
Topic string
|
||||
PublicKey *ecdsa.PublicKey
|
||||
}
|
||||
|
||||
func (p ProtectedTopic) String() string {
|
||||
pubKBytes := crypto.FromECDSAPub(p.PublicKey)
|
||||
return fmt.Sprintf("%s:%s", p.Topic, hex.EncodeToString(pubKBytes))
|
||||
}
|
||||
|
||||
type ProtectedTopicSlice struct {
|
||||
Values *[]ProtectedTopic
|
||||
}
|
||||
|
||||
func (k *ProtectedTopicSlice) Set(value string) error {
|
||||
protectedTopicParts := strings.Split(value, ":")
|
||||
if len(protectedTopicParts) != 2 {
|
||||
return errors.New("expected topic_name:hex_encoded_public_key")
|
||||
}
|
||||
|
||||
pubk, err := crypto.UnmarshalPubkey(common.FromHex(protectedTopicParts[1]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*k.Values = append(*k.Values, ProtectedTopic{
|
||||
Topic: protectedTopicParts[0],
|
||||
PublicKey: pubk,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *ProtectedTopicSlice) String() string {
|
||||
if v.Values == nil {
|
||||
return ""
|
||||
}
|
||||
var output []string
|
||||
for _, v := range *v.Values {
|
||||
output = append(output, v.String())
|
||||
}
|
||||
|
||||
return strings.Join(output, ", ")
|
||||
}
|
|
@ -300,6 +300,11 @@ func Execute(options Options) {
|
|||
failOnErr(err, "Error subscring to topic")
|
||||
wakuNode.Broadcaster().Unregister(&nodeTopic, sub.C)
|
||||
}
|
||||
|
||||
for _, protectedTopic := range options.Relay.ProtectedTopics {
|
||||
err := wakuNode.Relay().AddSignedTopicValidator(protectedTopic.Topic, protectedTopic.PublicKey)
|
||||
failOnErr(err, "Error adding signed topic validator")
|
||||
}
|
||||
}
|
||||
|
||||
for _, n := range options.StaticNodes {
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/waku-org/go-waku/waku/cliutils"
|
||||
)
|
||||
|
||||
// DiscV5Options are settings to enable a modified version of Ethereum’s Node
|
||||
|
@ -24,6 +25,7 @@ type DiscV5Options struct {
|
|||
type RelayOptions struct {
|
||||
Enable bool
|
||||
Topics cli.StringSlice
|
||||
ProtectedTopics []cliutils.ProtectedTopic
|
||||
PeerExchange bool
|
||||
MinRelayPeersToPublish int
|
||||
}
|
||||
|
|
|
@ -21,9 +21,10 @@ func MsgHash(pubSubTopic string, msg *pb.WakuMessage) []byte {
|
|||
return hash.SHA256([]byte(pubSubTopic), msg.Payload, []byte(msg.ContentTopic))
|
||||
}
|
||||
|
||||
func (w *WakuRelay) AddSignedTopicValidator(topic string, publicKey *ecdsa.PublicKey) error {
|
||||
w.log.Info("adding validator to signed topic", zap.String("topic", topic), zap.String("publicKey", hex.EncodeToString(elliptic.Marshal(publicKey.Curve, publicKey.X, publicKey.Y))))
|
||||
err := w.pubsub.RegisterTopicValidator(topic, func(ctx context.Context, peerID peer.ID, message *pubsub.Message) bool {
|
||||
type validatorFn = func(ctx context.Context, peerID peer.ID, message *pubsub.Message) bool
|
||||
|
||||
func validatorFnBuilder(topic string, publicKey *ecdsa.PublicKey) validatorFn {
|
||||
return func(ctx context.Context, peerID peer.ID, message *pubsub.Message) bool {
|
||||
msg := new(pb.WakuMessage)
|
||||
err := proto.Unmarshal(message.Data, msg)
|
||||
if err != nil {
|
||||
|
@ -34,11 +35,16 @@ func (w *WakuRelay) AddSignedTopicValidator(topic string, publicKey *ecdsa.Publi
|
|||
signature := msg.Meta
|
||||
|
||||
return ecdsa.VerifyASN1(publicKey, msgHash, signature)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (w *WakuRelay) AddSignedTopicValidator(topic string, publicKey *ecdsa.PublicKey) error {
|
||||
w.log.Info("adding validator to signed topic", zap.String("topic", topic), zap.String("publicKey", hex.EncodeToString(elliptic.Marshal(publicKey.Curve, publicKey.X, publicKey.Y))))
|
||||
err := w.pubsub.RegisterTopicValidator(topic, validatorFnBuilder(topic, publicKey))
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *WakuRelay) SignMessage(privKey *ecdsa.PrivateKey, topic string, msg *pb.WakuMessage) error {
|
||||
func SignMessage(privKey *ecdsa.PrivateKey, topic string, msg *pb.WakuMessage) error {
|
||||
msgHash := MsgHash(topic, msg)
|
||||
sign, err := ecdsa.SignASN1(rand.Reader, privKey, msgHash)
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package relay
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
pubsub_pb "github.com/libp2p/go-libp2p-pubsub/pb"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/pb"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestMsgHash(t *testing.T) {
|
||||
privKeyB, _ := hexutil.Decode("0x5526a8990317c9b7b58d07843d270f9cd1d9aaee129294c1c478abf7261dd9e6")
|
||||
prvKey, _ := crypto.ToECDSA(privKeyB)
|
||||
|
||||
payload, _ := hexutil.Decode("0x3af5c7a8d71498e82e1991089d8429448f3b78277fac141af9052e77fc003dfb")
|
||||
contentTopic := "my-content-topic"
|
||||
pubsubTopic := "some-spam-protected-topic"
|
||||
|
||||
msg := &pb.WakuMessage{
|
||||
Payload: payload,
|
||||
ContentTopic: contentTopic,
|
||||
}
|
||||
|
||||
err := SignMessage(prvKey, pubsubTopic, msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
msgData, _ := proto.Marshal(msg)
|
||||
|
||||
expectedMessageHash, _ := hexutil.Decode("0xd0e3231ec48f9c0cf9306b7100c30b4e85c78854b67b41e4ee388fb4610f543d")
|
||||
messageHash := MsgHash(pubsubTopic, msg)
|
||||
require.True(t, bytes.Equal(expectedMessageHash, messageHash))
|
||||
|
||||
myValidator := validatorFnBuilder(pubsubTopic, &prvKey.PublicKey)
|
||||
|
||||
result := myValidator(context.Background(), "", &pubsub.Message{
|
||||
Message: &pubsub_pb.Message{
|
||||
Data: msgData,
|
||||
},
|
||||
})
|
||||
require.True(t, result)
|
||||
}
|
Loading…
Reference in New Issue