2019-06-03 14:29:14 +00:00
|
|
|
package publisher
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/ecdsa"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
|
|
"github.com/ethereum/go-ethereum/crypto/ecies"
|
2019-06-26 18:17:41 +00:00
|
|
|
"github.com/status-im/status-go/messaging/filter"
|
2019-06-03 14:29:14 +00:00
|
|
|
"github.com/status-im/status-go/services/shhext/dedup"
|
|
|
|
"github.com/status-im/status-go/services/shhext/whisperutils"
|
|
|
|
whisper "github.com/status-im/whisper/whisperv6"
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestServiceTestSuite(t *testing.T) {
|
|
|
|
suite.Run(t, new(ServiceTestSuite))
|
|
|
|
}
|
|
|
|
|
|
|
|
type TestKey struct {
|
|
|
|
privateKey *ecdsa.PrivateKey
|
|
|
|
keyID string
|
|
|
|
publicKeyBytes hexutil.Bytes
|
|
|
|
}
|
|
|
|
|
|
|
|
type ServiceTestSuite struct {
|
|
|
|
suite.Suite
|
|
|
|
alice *Service
|
|
|
|
bob *Service
|
|
|
|
aliceKey *TestKey
|
|
|
|
bobKey *TestKey
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ServiceTestSuite) SetupTest() {
|
|
|
|
|
|
|
|
dir1, err := ioutil.TempDir("", "publisher-test")
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
config1 := &Config{
|
|
|
|
PfsEnabled: true,
|
|
|
|
DataDir: dir1,
|
|
|
|
InstallationID: "1",
|
|
|
|
}
|
|
|
|
|
|
|
|
whisper1 := whisper.New(nil)
|
|
|
|
err = whisper1.SetMinimumPoW(0)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
service1 := New(config1, whisper1)
|
|
|
|
|
|
|
|
pk1, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
keyID1, err := whisper1.AddKeyPair(pk1)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
key1 := &TestKey{
|
|
|
|
privateKey: pk1,
|
|
|
|
keyID: keyID1,
|
|
|
|
publicKeyBytes: crypto.FromECDSAPub(&pk1.PublicKey),
|
|
|
|
}
|
|
|
|
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
err = service1.Start(func() bool { return true }, false)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
err = service1.InitProtocolWithPassword("1", "")
|
|
|
|
s.Require().NoError(err)
|
|
|
|
_, err = service1.LoadFilters([]*filter.Chat{})
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
dir2, err := ioutil.TempDir("", "publisher-test")
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
config2 := &Config{
|
|
|
|
PfsEnabled: true,
|
|
|
|
DataDir: dir2,
|
|
|
|
InstallationID: "2",
|
|
|
|
}
|
|
|
|
|
|
|
|
whisper2 := whisper.New(nil)
|
|
|
|
err = whisper2.SetMinimumPoW(0)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
service2 := New(config2, whisper2)
|
|
|
|
|
|
|
|
pk2, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
keyID2, err := whisper2.AddKeyPair(pk2)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
key2 := &TestKey{
|
|
|
|
privateKey: pk2,
|
|
|
|
keyID: keyID2,
|
|
|
|
publicKeyBytes: crypto.FromECDSAPub(&pk2.PublicKey),
|
|
|
|
}
|
|
|
|
|
|
|
|
err = service2.Start(func() bool { return true }, false)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
err = service2.InitProtocolWithPassword("1", "")
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
_, err = service2.LoadFilters([]*filter.Chat{})
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
s.alice = service1
|
|
|
|
s.aliceKey = key1
|
|
|
|
s.bob = service2
|
|
|
|
s.bobKey = key2
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ServiceTestSuite) TestCreateDirectMessage() {
|
|
|
|
newMessage, err := s.alice.CreateDirectMessage(s.aliceKey.keyID, s.bobKey.publicKeyBytes, false, []byte("hello"))
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
message := &whisper.Message{
|
|
|
|
Sig: s.aliceKey.publicKeyBytes,
|
|
|
|
Topic: newMessage.Topic,
|
|
|
|
Payload: newMessage.Payload,
|
|
|
|
Dst: newMessage.PublicKey,
|
|
|
|
}
|
|
|
|
dedupMessage := dedup.DeduplicateMessage{
|
|
|
|
DedupID: []byte("1"),
|
|
|
|
Message: message,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = s.bob.ProcessMessage(dedupMessage)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
s.Require().Equal([]byte("hello"), message.Payload)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ServiceTestSuite) TestTopic() {
|
|
|
|
// We build an initial message
|
|
|
|
newMessage1, err := s.alice.CreateDirectMessage(s.aliceKey.keyID, s.bobKey.publicKeyBytes, false, []byte("hello"))
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
message1 := &whisper.Message{
|
|
|
|
Sig: s.aliceKey.publicKeyBytes,
|
|
|
|
Topic: newMessage1.Topic,
|
|
|
|
Payload: newMessage1.Payload,
|
|
|
|
Dst: newMessage1.PublicKey,
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have no information, it should use the discovery topic
|
|
|
|
s.Require().Equal(whisperutils.DiscoveryTopicBytes, message1.Topic)
|
|
|
|
|
|
|
|
// We build a contact code from user 2
|
|
|
|
newMessage2, err := s.bob.sendContactCode()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().NotNil(newMessage2)
|
|
|
|
|
|
|
|
message2 := &whisper.Message{
|
|
|
|
Sig: s.bobKey.publicKeyBytes,
|
|
|
|
Topic: newMessage2.Topic,
|
|
|
|
Payload: newMessage2.Payload,
|
|
|
|
Dst: newMessage2.PublicKey,
|
|
|
|
}
|
|
|
|
|
|
|
|
// We receive the contact code
|
|
|
|
dedupMessage2 := dedup.DeduplicateMessage{
|
|
|
|
DedupID: []byte("1"),
|
|
|
|
Message: message2,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = s.alice.ProcessMessage(dedupMessage2)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// We build another message, this time it should use the partitioned topic
|
|
|
|
newMessage3, err := s.alice.CreateDirectMessage(s.aliceKey.keyID, s.bobKey.publicKeyBytes, false, []byte("hello"))
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
message3 := &whisper.Message{
|
|
|
|
Sig: s.aliceKey.publicKeyBytes,
|
|
|
|
Topic: newMessage3.Topic,
|
|
|
|
Payload: newMessage3.Payload,
|
|
|
|
Dst: newMessage3.PublicKey,
|
|
|
|
}
|
|
|
|
expectedTopic3 := whisper.BytesToTopic(filter.PublicKeyToPartitionedTopicBytes(&s.bobKey.privateKey.PublicKey))
|
|
|
|
|
|
|
|
s.Require().Equal(expectedTopic3, message3.Topic)
|
|
|
|
|
|
|
|
// We receive the message
|
|
|
|
dedupMessage3 := dedup.DeduplicateMessage{
|
|
|
|
DedupID: []byte("1"),
|
|
|
|
Message: message3,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = s.bob.ProcessMessage(dedupMessage3)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// We build another message, this time it should use the negotiated topic
|
|
|
|
newMessage4, err := s.bob.CreateDirectMessage(s.bobKey.keyID, s.aliceKey.publicKeyBytes, false, []byte("hello"))
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
message4 := &whisper.Message{
|
|
|
|
Sig: s.bobKey.publicKeyBytes,
|
|
|
|
Topic: newMessage4.Topic,
|
|
|
|
Payload: newMessage4.Payload,
|
|
|
|
Dst: newMessage4.PublicKey,
|
|
|
|
}
|
|
|
|
sharedSecret, err := ecies.ImportECDSA(s.bobKey.privateKey).GenerateShared(
|
|
|
|
ecies.ImportECDSAPublic(&s.aliceKey.privateKey.PublicKey),
|
|
|
|
16,
|
|
|
|
16)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
keyString := fmt.Sprintf("%x", sharedSecret)
|
|
|
|
|
|
|
|
negotiatedTopic := whisper.BytesToTopic(filter.ToTopic(keyString))
|
|
|
|
|
|
|
|
s.Require().Equal(negotiatedTopic, message4.Topic)
|
|
|
|
|
|
|
|
// We receive the message
|
|
|
|
dedupMessage4 := dedup.DeduplicateMessage{
|
|
|
|
DedupID: []byte("1"),
|
|
|
|
Message: message4,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = s.alice.ProcessMessage(dedupMessage4)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Alice sends another message to Bob, this time it should use the negotiated topic
|
|
|
|
newMessage5, err := s.alice.CreateDirectMessage(s.aliceKey.keyID, s.bobKey.publicKeyBytes, false, []byte("hello"))
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
message5 := &whisper.Message{
|
|
|
|
Sig: s.aliceKey.publicKeyBytes,
|
|
|
|
Topic: newMessage5.Topic,
|
|
|
|
Payload: newMessage5.Payload,
|
|
|
|
Dst: newMessage5.PublicKey,
|
|
|
|
}
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Equal(negotiatedTopic, message5.Topic)
|
|
|
|
|
|
|
|
}
|