2020-07-06 08:54:22 +00:00
|
|
|
package common
|
2019-11-21 16:19:22 +00:00
|
|
|
|
|
|
|
import (
|
2023-11-09 20:36:57 +00:00
|
|
|
"math"
|
2019-11-21 16:19:22 +00:00
|
|
|
"testing"
|
|
|
|
|
2021-04-22 13:36:18 +00:00
|
|
|
transport2 "github.com/status-im/status-go/protocol/transport"
|
2023-10-02 09:28:42 +00:00
|
|
|
"github.com/status-im/status-go/t/helpers"
|
2021-04-22 13:36:18 +00:00
|
|
|
|
|
|
|
"github.com/status-im/status-go/waku"
|
|
|
|
|
2019-11-21 16:19:22 +00:00
|
|
|
"github.com/golang/protobuf/proto"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
|
2023-12-15 16:16:18 +00:00
|
|
|
datasyncproto "github.com/status-im/mvds/protobuf"
|
2020-01-02 09:10:19 +00:00
|
|
|
|
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"
|
2023-12-15 16:16:18 +00:00
|
|
|
"github.com/status-im/status-go/protocol/datasync"
|
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"
|
|
|
|
v1protocol "github.com/status-im/status-go/protocol/v1"
|
2023-10-02 09:28:42 +00:00
|
|
|
|
|
|
|
"github.com/status-im/status-go/appdatabase"
|
2019-11-21 16:19:22 +00:00
|
|
|
)
|
|
|
|
|
2021-06-23 14:13:48 +00:00
|
|
|
func TestMessageSenderSuite(t *testing.T) {
|
|
|
|
suite.Run(t, new(MessageSenderSuite))
|
2019-11-21 16:19:22 +00:00
|
|
|
}
|
|
|
|
|
2021-06-23 14:13:48 +00:00
|
|
|
type MessageSenderSuite struct {
|
2019-11-21 16:19:22 +00:00
|
|
|
suite.Suite
|
|
|
|
|
2021-06-23 14:13:48 +00:00
|
|
|
sender *MessageSender
|
2020-07-22 07:41:40 +00:00
|
|
|
testMessage protobuf.ChatMessage
|
2019-11-21 16:19:22 +00:00
|
|
|
logger *zap.Logger
|
|
|
|
}
|
|
|
|
|
2021-06-23 14:13:48 +00:00
|
|
|
func (s *MessageSenderSuite) 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)
|
|
|
|
|
|
|
|
identity, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2023-10-02 09:28:42 +00:00
|
|
|
database, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{})
|
|
|
|
s.Require().NoError(err)
|
|
|
|
err = sqlite.Migrate(database)
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
encryptionProtocol := encryption.New(
|
|
|
|
database,
|
|
|
|
"installation-1",
|
|
|
|
s.logger,
|
|
|
|
)
|
|
|
|
|
2021-04-22 13:36:18 +00:00
|
|
|
wakuConfig := waku.DefaultConfig
|
|
|
|
wakuConfig.MinimumAcceptedPoW = 0
|
|
|
|
shh := waku.New(&wakuConfig, s.logger)
|
2021-07-09 13:19:33 +00:00
|
|
|
s.Require().NoError(shh.Start())
|
2019-11-21 16:19:22 +00:00
|
|
|
|
2021-04-22 13:36:18 +00:00
|
|
|
whisperTransport, err := transport2.NewTransport(
|
|
|
|
gethbridge.NewGethWakuWrapper(shh),
|
2019-11-21 16:19:22 +00:00
|
|
|
identity,
|
|
|
|
database,
|
2021-06-16 20:19:45 +00:00
|
|
|
"waku_keys",
|
2019-11-21 16:19:22 +00:00
|
|
|
nil,
|
|
|
|
nil,
|
|
|
|
s.logger,
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2021-06-23 14:13:48 +00:00
|
|
|
s.sender, err = NewMessageSender(
|
2019-11-21 16:19:22 +00:00
|
|
|
identity,
|
|
|
|
database,
|
|
|
|
encryptionProtocol,
|
|
|
|
whisperTransport,
|
|
|
|
s.logger,
|
2023-11-17 15:26:49 +00:00
|
|
|
FeatureFlags{
|
|
|
|
Datasync: true,
|
|
|
|
},
|
2019-11-21 16:19:22 +00:00
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
}
|
|
|
|
|
2021-06-23 14:13:48 +00:00
|
|
|
func (s *MessageSenderSuite) TearDownTest() {
|
2019-11-21 16:19:22 +00:00
|
|
|
_ = s.logger.Sync()
|
|
|
|
}
|
|
|
|
|
2021-06-23 14:13:48 +00:00
|
|
|
func (s *MessageSenderSuite) TestHandleDecodedMessagesWrapped() {
|
2019-11-21 16:19:22 +00:00
|
|
|
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
|
|
|
|
|
2023-12-15 11:50:47 +00:00
|
|
|
response, err := s.sender.HandleMessages(message)
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().NoError(err)
|
2023-12-15 11:50:47 +00:00
|
|
|
decodedMessages := response.StatusMessages
|
2019-11-21 16:19:22 +00:00
|
|
|
|
|
|
|
s.Require().Equal(1, len(decodedMessages))
|
|
|
|
s.Require().Equal(&authorKey.PublicKey, decodedMessages[0].SigPubKey())
|
2023-11-08 18:05:33 +00:00
|
|
|
s.Require().Equal(v1protocol.MessageID(&authorKey.PublicKey, wrappedPayload), decodedMessages[0].ApplicationLayer.ID)
|
|
|
|
s.Require().Equal(encodedPayload, decodedMessages[0].ApplicationLayer.Payload)
|
|
|
|
s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].ApplicationLayer.Type)
|
2019-11-21 16:19:22 +00:00
|
|
|
}
|
|
|
|
|
2021-06-23 14:13:48 +00:00
|
|
|
func (s *MessageSenderSuite) TestHandleDecodedMessagesDatasync() {
|
2019-11-21 16:19:22 +00:00
|
|
|
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)
|
|
|
|
|
2023-12-15 16:16:18 +00:00
|
|
|
ds := datasync.New(nil, nil, false, s.sender.logger)
|
|
|
|
s.sender.datasync = ds
|
|
|
|
|
2019-11-21 16:19:22 +00:00
|
|
|
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
|
|
|
|
|
2023-12-15 11:50:47 +00:00
|
|
|
response, err := s.sender.HandleMessages(message)
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().NoError(err)
|
2023-12-15 11:50:47 +00:00
|
|
|
decodedMessages := response.StatusMessages
|
2019-11-21 16:19:22 +00:00
|
|
|
|
|
|
|
// 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())
|
2023-11-08 18:05:33 +00:00
|
|
|
s.Require().Equal(v1protocol.MessageID(&authorKey.PublicKey, wrappedPayload), decodedMessages[0].ApplicationLayer.ID)
|
|
|
|
s.Require().Equal(encodedPayload, decodedMessages[0].ApplicationLayer.Payload)
|
|
|
|
s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].ApplicationLayer.Type)
|
2019-11-21 16:19:22 +00:00
|
|
|
}
|
|
|
|
|
2021-06-23 14:13:48 +00:00
|
|
|
func (s *MessageSenderSuite) CalculatePoWTest() {
|
2020-05-13 13:19:29 +00:00
|
|
|
largeSizePayload := make([]byte, largeSizeInBytes)
|
|
|
|
s.Require().Equal(whisperLargeSizePoW, calculatePoW(largeSizePayload))
|
|
|
|
normalSizePayload := make([]byte, largeSizeInBytes-1)
|
|
|
|
s.Require().Equal(whisperDefaultPoW, calculatePoW(normalSizePayload))
|
|
|
|
|
|
|
|
}
|
2021-06-23 14:13:48 +00:00
|
|
|
func (s *MessageSenderSuite) TestHandleDecodedMessagesDatasyncEncrypted() {
|
2019-11-21 16:19:22 +00:00
|
|
|
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.
|
2023-10-02 09:28:42 +00:00
|
|
|
senderDatabase, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{})
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().NoError(err)
|
2023-10-02 09:28:42 +00:00
|
|
|
err = sqlite.Migrate(senderDatabase)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2019-11-21 16:19:22 +00:00
|
|
|
senderEncryptionProtocol := encryption.New(
|
|
|
|
senderDatabase,
|
|
|
|
"installation-2",
|
|
|
|
s.logger,
|
|
|
|
)
|
|
|
|
|
2021-09-21 15:47:04 +00:00
|
|
|
messageSpec, err := senderEncryptionProtocol.BuildEncryptedMessage(
|
2019-11-21 16:19:22 +00:00
|
|
|
relayerKey,
|
2021-06-23 14:13:48 +00:00
|
|
|
&s.sender.identity.PublicKey,
|
2019-11-21 16:19:22 +00:00
|
|
|
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
|
|
|
|
|
2023-12-15 16:16:18 +00:00
|
|
|
ds := datasync.New(nil, nil, false, s.sender.logger)
|
|
|
|
s.sender.datasync = ds
|
|
|
|
|
2023-12-15 11:50:47 +00:00
|
|
|
response, err := s.sender.HandleMessages(message)
|
2019-11-21 16:19:22 +00:00
|
|
|
s.Require().NoError(err)
|
2023-12-15 11:50:47 +00:00
|
|
|
decodedMessages := response.StatusMessages
|
2019-11-21 16:19:22 +00:00
|
|
|
|
|
|
|
// 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())
|
2023-11-08 18:05:33 +00:00
|
|
|
s.Require().Equal(v1protocol.MessageID(&authorKey.PublicKey, wrappedPayload), decodedMessages[0].ApplicationLayer.ID)
|
|
|
|
s.Require().Equal(encodedPayload, decodedMessages[0].ApplicationLayer.Payload)
|
|
|
|
s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].ApplicationLayer.Type)
|
2019-11-21 16:19:22 +00:00
|
|
|
}
|
2023-10-30 11:53:37 +00:00
|
|
|
|
|
|
|
func (s *MessageSenderSuite) TestHandleOutOfOrderHashRatchet() {
|
|
|
|
groupID := []byte("group-id")
|
|
|
|
senderKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
encodedPayload, err := proto.Marshal(&s.testMessage)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Create sender encryption protocol.
|
|
|
|
senderDatabase, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{})
|
|
|
|
s.Require().NoError(err)
|
|
|
|
err = sqlite.Migrate(senderDatabase)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
senderEncryptionProtocol := encryption.New(
|
|
|
|
senderDatabase,
|
|
|
|
"installation-2",
|
|
|
|
s.logger,
|
|
|
|
)
|
|
|
|
|
|
|
|
ratchet, err := senderEncryptionProtocol.GenerateHashRatchetKey(groupID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
ratchets := []*encryption.HashRatchetKeyCompatibility{ratchet}
|
|
|
|
|
|
|
|
hashRatchetKeyExchangeMessage, err := senderEncryptionProtocol.BuildHashRatchetKeyExchangeMessage(senderKey, &s.sender.identity.PublicKey, groupID, ratchets)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
encryptedPayload1, err := proto.Marshal(hashRatchetKeyExchangeMessage.Message)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
wrappedPayload2, err := v1protocol.WrapMessageV1(encodedPayload, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, senderKey)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
messageSpec2, err := senderEncryptionProtocol.BuildHashRatchetMessage(
|
|
|
|
groupID,
|
|
|
|
wrappedPayload2,
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
encryptedPayload2, err := proto.Marshal(messageSpec2.Message)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
message := &types.Message{}
|
|
|
|
message.Sig = crypto.FromECDSAPub(&senderKey.PublicKey)
|
|
|
|
message.Hash = []byte{0x1}
|
|
|
|
message.Payload = encryptedPayload2
|
|
|
|
|
2023-12-15 11:50:47 +00:00
|
|
|
_, err = s.sender.HandleMessages(message)
|
2023-10-30 11:53:37 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
keyID, err := ratchet.GetKeyID()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
msgs, err := s.sender.persistence.GetHashRatchetMessages(keyID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
s.Require().Len(msgs, 1)
|
|
|
|
|
|
|
|
message = &types.Message{}
|
|
|
|
message.Sig = crypto.FromECDSAPub(&senderKey.PublicKey)
|
|
|
|
message.Hash = []byte{0x2}
|
|
|
|
message.Payload = encryptedPayload1
|
|
|
|
|
2023-12-15 11:50:47 +00:00
|
|
|
response, err := s.sender.HandleMessages(message)
|
2023-10-30 11:53:37 +00:00
|
|
|
s.Require().NoError(err)
|
2023-12-15 11:50:47 +00:00
|
|
|
decodedMessages2 := response.StatusMessages
|
2023-10-30 11:53:37 +00:00
|
|
|
s.Require().NotNil(decodedMessages2)
|
|
|
|
|
|
|
|
// It should have 2 messages, the key exchange and the one from the database
|
|
|
|
s.Require().Len(decodedMessages2, 2)
|
|
|
|
|
|
|
|
// it deletes the messages after being processed
|
|
|
|
msgs, err = s.sender.persistence.GetHashRatchetMessages(keyID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
s.Require().Len(msgs, 0)
|
|
|
|
|
|
|
|
}
|
2023-11-09 20:36:57 +00:00
|
|
|
|
|
|
|
func (s *MessageSenderSuite) TestHandleSegmentMessages() {
|
|
|
|
relayerKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
authorKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
encodedPayload, err := proto.Marshal(&s.testMessage)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
wrappedPayload, err := v1protocol.WrapMessageV1(encodedPayload, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, authorKey)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
segmentedMessages, err := segmentMessage(&types.NewMessage{Payload: wrappedPayload}, int(math.Ceil(float64(len(wrappedPayload))/2)))
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(segmentedMessages, 2)
|
|
|
|
|
|
|
|
message := &types.Message{}
|
|
|
|
message.Sig = crypto.FromECDSAPub(&relayerKey.PublicKey)
|
|
|
|
message.Payload = segmentedMessages[0].Payload
|
|
|
|
|
|
|
|
// First segment is received, no messages are decoded
|
2023-12-15 11:50:47 +00:00
|
|
|
response, err := s.sender.HandleMessages(message)
|
2023-11-09 20:36:57 +00:00
|
|
|
s.Require().NoError(err)
|
2023-12-15 11:50:47 +00:00
|
|
|
s.Require().Nil(response)
|
2023-11-09 20:36:57 +00:00
|
|
|
|
|
|
|
// Second (and final) segment is received, reassembled message is decoded
|
|
|
|
message.Payload = segmentedMessages[1].Payload
|
2023-12-15 11:50:47 +00:00
|
|
|
response, err = s.sender.HandleMessages(message)
|
2023-11-09 20:36:57 +00:00
|
|
|
s.Require().NoError(err)
|
2023-12-15 11:50:47 +00:00
|
|
|
|
|
|
|
decodedMessages := response.StatusMessages
|
2023-11-09 20:36:57 +00:00
|
|
|
s.Require().Len(decodedMessages, 1)
|
|
|
|
s.Require().Equal(&authorKey.PublicKey, decodedMessages[0].SigPubKey())
|
|
|
|
s.Require().Equal(v1protocol.MessageID(&authorKey.PublicKey, wrappedPayload), decodedMessages[0].ApplicationLayer.ID)
|
|
|
|
s.Require().Equal(encodedPayload, decodedMessages[0].ApplicationLayer.Payload)
|
|
|
|
s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].ApplicationLayer.Type)
|
|
|
|
|
|
|
|
// Receiving another segment after the message has been reassembled is considered an error
|
2023-12-15 11:50:47 +00:00
|
|
|
_, err = s.sender.HandleMessages(message)
|
2023-11-09 20:36:57 +00:00
|
|
|
s.Require().ErrorIs(err, ErrMessageSegmentsAlreadyCompleted)
|
|
|
|
}
|