2020-07-06 08:54:22 +00:00
|
|
|
package common
|
2019-11-21 16:19:22 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
|
2020-01-02 09:10:19 +00:00
|
|
|
datasyncproto "github.com/vacp2p/mvds/protobuf"
|
|
|
|
|
2019-11-23 17:57:05 +00:00
|
|
|
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
|
|
|
|
"github.com/status-im/status-go/eth-node/crypto"
|
|
|
|
"github.com/status-im/status-go/eth-node/types"
|
2019-11-21 16:19:22 +00:00
|
|
|
"github.com/status-im/status-go/protocol/encryption"
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
"github.com/status-im/status-go/protocol/protobuf"
|
2019-11-21 16:19:22 +00:00
|
|
|
"github.com/status-im/status-go/protocol/sqlite"
|
|
|
|
transport "github.com/status-im/status-go/protocol/transport/whisper"
|
|
|
|
v1protocol "github.com/status-im/status-go/protocol/v1"
|
2019-12-09 10:36:14 +00:00
|
|
|
"github.com/status-im/status-go/whisper/v6"
|
2019-11-21 16:19:22 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestMessageProcessorSuite(t *testing.T) {
|
|
|
|
suite.Run(t, new(MessageProcessorSuite))
|
|
|
|
}
|
|
|
|
|
|
|
|
type MessageProcessorSuite struct {
|
|
|
|
suite.Suite
|
|
|
|
|
2020-07-22 07:41:40 +00:00
|
|
|
processor *MessageProcessor
|
2019-11-21 16:19:22 +00:00
|
|
|
tmpDir string
|
2020-07-22 07:41:40 +00:00
|
|
|
testMessage protobuf.ChatMessage
|
2019-11-21 16:19:22 +00:00
|
|
|
logger *zap.Logger
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MessageProcessorSuite) SetupTest() {
|
2020-07-22 07:41:40 +00:00
|
|
|
s.testMessage = protobuf.ChatMessage{
|
|
|
|
Text: "abc123",
|
|
|
|
ChatId: "testing-adamb",
|
|
|
|
ContentType: protobuf.ChatMessage_TEXT_PLAIN,
|
2020-07-25 11:46:43 +00:00
|
|
|
MessageType: protobuf.MessageType_PUBLIC_GROUP,
|
2020-07-22 07:41:40 +00:00
|
|
|
Clock: 154593077368201,
|
|
|
|
Timestamp: 1545930773682,
|
2019-11-21 16:19:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
s.logger, err = zap.NewDevelopment()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
s.tmpDir, err = ioutil.TempDir("", "")
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
identity, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
database, err := sqlite.Open(filepath.Join(s.tmpDir, "processor-test.sql"), "some-key")
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
encryptionProtocol := encryption.New(
|
|
|
|
database,
|
|
|
|
"installation-1",
|
|
|
|
s.logger,
|
|
|
|
)
|
|
|
|
|
|
|
|
whisperConfig := whisper.DefaultConfig
|
|
|
|
whisperConfig.MinimumAcceptedPOW = 0
|
|
|
|
shh := whisper.New(&whisperConfig)
|
|
|
|
s.Require().NoError(shh.Start(nil))
|
|
|
|
|
2020-02-10 11:22:37 +00:00
|
|
|
whisperTransport, err := transport.NewTransport(
|
2019-11-21 16:19:22 +00:00
|
|
|
gethbridge.NewGethWhisperWrapper(shh),
|
|
|
|
identity,
|
|
|
|
database,
|
|
|
|
nil,
|
|
|
|
nil,
|
|
|
|
s.logger,
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2020-07-22 07:41:40 +00:00
|
|
|
s.processor, err = NewMessageProcessor(
|
2019-11-21 16:19:22 +00:00
|
|
|
identity,
|
|
|
|
database,
|
|
|
|
encryptionProtocol,
|
|
|
|
whisperTransport,
|
|
|
|
s.logger,
|
2020-07-22 07:41:40 +00:00
|
|
|
FeatureFlags{},
|
2019-11-21 16:19:22 +00:00
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MessageProcessorSuite) TearDownTest() {
|
|
|
|
os.Remove(s.tmpDir)
|
|
|
|
_ = s.logger.Sync()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MessageProcessorSuite) TestHandleDecodedMessagesWrapped() {
|
|
|
|
relayerKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
authorKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
encodedPayload, err := proto.Marshal(&s.testMessage)
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2019-12-02 15:34:05 +00:00
|
|
|
wrappedPayload, err := v1protocol.WrapMessageV1(encodedPayload, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, authorKey)
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2019-11-23 17:57:05 +00:00
|
|
|
message := &types.Message{}
|
2019-11-21 16:19:22 +00:00
|
|
|
message.Sig = crypto.FromECDSAPub(&relayerKey.PublicKey)
|
|
|
|
message.Payload = wrappedPayload
|
|
|
|
|
2020-07-22 07:41:40 +00:00
|
|
|
decodedMessages, err := s.processor.HandleMessages(message, true)
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
s.Require().Equal(1, len(decodedMessages))
|
|
|
|
s.Require().Equal(&authorKey.PublicKey, decodedMessages[0].SigPubKey())
|
|
|
|
s.Require().Equal(v1protocol.MessageID(&authorKey.PublicKey, wrappedPayload), decodedMessages[0].ID)
|
2020-07-28 07:53:32 +00:00
|
|
|
parsedMessage := decodedMessages[0].ParsedMessage.Interface().(protobuf.ChatMessage)
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().Equal(encodedPayload, decodedMessages[0].DecryptedPayload)
|
2020-07-22 07:41:40 +00:00
|
|
|
s.Require().True(proto.Equal(&s.testMessage, &parsedMessage))
|
2019-12-02 15:34:05 +00:00
|
|
|
s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].Type)
|
2019-11-21 16:19:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MessageProcessorSuite) TestHandleDecodedMessagesDatasync() {
|
|
|
|
relayerKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
authorKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
encodedPayload, err := proto.Marshal(&s.testMessage)
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2019-12-02 15:34:05 +00:00
|
|
|
wrappedPayload, err := v1protocol.WrapMessageV1(encodedPayload, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, authorKey)
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
dataSyncMessage := datasyncproto.Payload{
|
|
|
|
Messages: []*datasyncproto.Message{
|
|
|
|
{Body: wrappedPayload},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
marshalledDataSyncMessage, err := proto.Marshal(&dataSyncMessage)
|
|
|
|
s.Require().NoError(err)
|
2019-11-23 17:57:05 +00:00
|
|
|
message := &types.Message{}
|
2019-11-21 16:19:22 +00:00
|
|
|
message.Sig = crypto.FromECDSAPub(&relayerKey.PublicKey)
|
|
|
|
message.Payload = marshalledDataSyncMessage
|
|
|
|
|
2020-07-22 07:41:40 +00:00
|
|
|
decodedMessages, err := s.processor.HandleMessages(message, true)
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// We send two messages, the unwrapped one will be attributed to the relayer, while the wrapped one will be attributed to the author
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
s.Require().Equal(1, len(decodedMessages))
|
|
|
|
s.Require().Equal(&authorKey.PublicKey, decodedMessages[0].SigPubKey())
|
|
|
|
s.Require().Equal(v1protocol.MessageID(&authorKey.PublicKey, wrappedPayload), decodedMessages[0].ID)
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().Equal(encodedPayload, decodedMessages[0].DecryptedPayload)
|
2020-07-28 07:53:32 +00:00
|
|
|
parsedMessage := decodedMessages[0].ParsedMessage.Interface().(protobuf.ChatMessage)
|
2020-07-22 07:41:40 +00:00
|
|
|
s.Require().True(proto.Equal(&s.testMessage, &parsedMessage))
|
2019-12-02 15:34:05 +00:00
|
|
|
s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].Type)
|
2019-11-21 16:19:22 +00:00
|
|
|
}
|
|
|
|
|
2020-05-13 13:19:29 +00:00
|
|
|
func (s *MessageProcessorSuite) CalculatePoWTest() {
|
|
|
|
largeSizePayload := make([]byte, largeSizeInBytes)
|
|
|
|
s.Require().Equal(whisperLargeSizePoW, calculatePoW(largeSizePayload))
|
|
|
|
normalSizePayload := make([]byte, largeSizeInBytes-1)
|
|
|
|
s.Require().Equal(whisperDefaultPoW, calculatePoW(normalSizePayload))
|
|
|
|
|
|
|
|
}
|
2019-11-21 16:19:22 +00:00
|
|
|
func (s *MessageProcessorSuite) TestHandleDecodedMessagesDatasyncEncrypted() {
|
|
|
|
relayerKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
authorKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
encodedPayload, err := proto.Marshal(&s.testMessage)
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2019-12-02 15:34:05 +00:00
|
|
|
wrappedPayload, err := v1protocol.WrapMessageV1(encodedPayload, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, authorKey)
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
dataSyncMessage := datasyncproto.Payload{
|
|
|
|
Messages: []*datasyncproto.Message{
|
2019-12-19 15:40:44 +00:00
|
|
|
{Body: wrappedPayload},
|
2019-11-21 16:19:22 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
marshalledDataSyncMessage, err := proto.Marshal(&dataSyncMessage)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Create sender encryption protocol.
|
|
|
|
senderDatabase, err := sqlite.Open(filepath.Join(s.tmpDir, "sender.db.sql"), "")
|
|
|
|
s.Require().NoError(err)
|
|
|
|
senderEncryptionProtocol := encryption.New(
|
|
|
|
senderDatabase,
|
|
|
|
"installation-2",
|
|
|
|
s.logger,
|
|
|
|
)
|
|
|
|
|
|
|
|
messageSpec, err := senderEncryptionProtocol.BuildDirectMessage(
|
|
|
|
relayerKey,
|
|
|
|
&s.processor.identity.PublicKey,
|
|
|
|
marshalledDataSyncMessage,
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
encryptedPayload, err := proto.Marshal(messageSpec.Message)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2019-11-23 17:57:05 +00:00
|
|
|
message := &types.Message{}
|
2019-11-21 16:19:22 +00:00
|
|
|
message.Sig = crypto.FromECDSAPub(&relayerKey.PublicKey)
|
|
|
|
message.Payload = encryptedPayload
|
|
|
|
|
2020-07-22 07:41:40 +00:00
|
|
|
decodedMessages, err := s.processor.HandleMessages(message, true)
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// We send two messages, the unwrapped one will be attributed to the relayer,
|
|
|
|
// while the wrapped one will be attributed to the author.
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
s.Require().Equal(1, len(decodedMessages))
|
|
|
|
s.Require().Equal(&authorKey.PublicKey, decodedMessages[0].SigPubKey())
|
|
|
|
s.Require().Equal(v1protocol.MessageID(&authorKey.PublicKey, wrappedPayload), decodedMessages[0].ID)
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().Equal(encodedPayload, decodedMessages[0].DecryptedPayload)
|
2020-07-28 07:53:32 +00:00
|
|
|
parsedMessage := decodedMessages[0].ParsedMessage.Interface().(protobuf.ChatMessage)
|
2020-07-22 07:41:40 +00:00
|
|
|
s.Require().True(proto.Equal(&s.testMessage, &parsedMessage))
|
2019-12-02 15:34:05 +00:00
|
|
|
s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].Type)
|
2019-11-21 16:19:22 +00:00
|
|
|
}
|