2018-09-24 18:07:34 +00:00
|
|
|
package chat
|
|
|
|
|
|
|
|
import (
|
|
|
|
"os"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestProtocolServiceTestSuite(t *testing.T) {
|
|
|
|
suite.Run(t, new(ProtocolServiceTestSuite))
|
|
|
|
}
|
|
|
|
|
|
|
|
type ProtocolServiceTestSuite struct {
|
|
|
|
suite.Suite
|
|
|
|
alice *ProtocolService
|
|
|
|
bob *ProtocolService
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ProtocolServiceTestSuite) SetupTest() {
|
|
|
|
aliceDBPath := "/tmp/alice.db"
|
|
|
|
aliceDBKey := "alice"
|
|
|
|
bobDBPath := "/tmp/bob.db"
|
|
|
|
bobDBKey := "bob"
|
|
|
|
|
|
|
|
os.Remove(aliceDBPath)
|
|
|
|
os.Remove(bobDBPath)
|
|
|
|
|
|
|
|
alicePersistence, err := NewSQLLitePersistence(aliceDBPath, aliceDBKey)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
bobPersistence, err := NewSQLLitePersistence(bobDBPath, bobDBKey)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
s.alice = NewProtocolService(NewEncryptionService(alicePersistence, "1"))
|
|
|
|
s.bob = NewProtocolService(NewEncryptionService(bobPersistence, "2"))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ProtocolServiceTestSuite) TestBuildDirectMessage() {
|
|
|
|
bobKey, err := crypto.GenerateKey()
|
|
|
|
s.NoError(err)
|
|
|
|
aliceKey, err := crypto.GenerateKey()
|
|
|
|
s.NoError(err)
|
|
|
|
|
|
|
|
payload, err := proto.Marshal(&ChatMessagePayload{
|
|
|
|
Content: "Test content",
|
|
|
|
ClockValue: 1,
|
|
|
|
ContentType: "a",
|
|
|
|
MessageType: "some type",
|
|
|
|
})
|
|
|
|
s.NoError(err)
|
|
|
|
|
Change handling of skipped/deleted keys & add version (#1261)
- Skipped keys
The purpose of limiting the number of skipped keys generated is to avoid a dos
attack whereby an attacker would send a large N, forcing the device to
compute all the keys between currentN..N .
Previously the logic for handling skipped keys was:
- If in the current receiving chain there are more than maxSkip keys,
throw an error
This is problematic as in long-lived session dropped/unreceived messages starts
piling up, eventually reaching the threshold (1000 dropped/unreceived
messages).
This logic has been changed to be more inline with signals spec, and now
it is:
- If N is > currentN + maxSkip, throw an error
The purpose of limiting the number of skipped keys stored is to avoid a dos
attack whereby an attacker would force us to store a large number of
keys, filling up our storage.
Previously the logic for handling old keys was:
- Once you have maxKeep ratchet steps, delete any key from
currentRatchet - maxKeep.
This, in combination with the maxSkip implementation, capped the number of stored keys to
maxSkip * maxKeep.
The logic has been changed to:
- Keep a maximum of MaxMessageKeysPerSession
and additionally we delete any key that has a sequence number <
currentSeqNum - maxKeep
- Version
We check now the version of the bundle so that when we get a bundle from
the same installationID with a higher version, we mark the previous
bundle as expired and use the new bundle the next time a message is sent
2018-11-05 19:00:04 +00:00
|
|
|
marshaledMsg, err := s.alice.BuildDirectMessage(aliceKey, payload, &bobKey.PublicKey, &aliceKey.PublicKey)
|
2018-09-24 18:07:34 +00:00
|
|
|
|
|
|
|
s.NoError(err)
|
|
|
|
s.NotNil(marshaledMsg, "It creates a message")
|
|
|
|
s.NotNil(marshaledMsg[&aliceKey.PublicKey], "It creates a single message")
|
|
|
|
|
|
|
|
unmarshaledMsg := &ProtocolMessage{}
|
|
|
|
err = proto.Unmarshal(marshaledMsg[&bobKey.PublicKey], unmarshaledMsg)
|
|
|
|
|
|
|
|
s.NoError(err)
|
|
|
|
|
|
|
|
s.NotNilf(unmarshaledMsg.GetBundle(), "It adds a bundle to the message")
|
|
|
|
|
|
|
|
directMessage := unmarshaledMsg.GetDirectMessage()
|
|
|
|
|
|
|
|
s.NotNilf(directMessage, "It sets the direct message")
|
|
|
|
|
|
|
|
encryptedPayload := directMessage["none"].GetPayload()
|
|
|
|
|
|
|
|
s.NotNilf(encryptedPayload, "It sets the payload of the message")
|
|
|
|
|
|
|
|
s.NotEqualf(payload, encryptedPayload, "It encrypts the payload")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ProtocolServiceTestSuite) TestBuildAndReadDirectMessage() {
|
|
|
|
bobKey, err := crypto.GenerateKey()
|
|
|
|
s.NoError(err)
|
|
|
|
aliceKey, err := crypto.GenerateKey()
|
|
|
|
s.NoError(err)
|
|
|
|
|
|
|
|
payload := ChatMessagePayload{
|
|
|
|
Content: "Test content",
|
|
|
|
ClockValue: 1,
|
|
|
|
ContentType: "a",
|
|
|
|
MessageType: "some type",
|
|
|
|
}
|
|
|
|
|
|
|
|
marshaledPayload, err := proto.Marshal(&payload)
|
|
|
|
s.NoError(err)
|
|
|
|
|
|
|
|
// Message is sent with DH
|
2018-10-16 15:22:28 +00:00
|
|
|
marshaledMsg, err := s.alice.BuildDirectMessage(aliceKey, marshaledPayload, &bobKey.PublicKey)
|
2018-09-24 18:07:34 +00:00
|
|
|
|
|
|
|
s.NoError(err)
|
|
|
|
|
|
|
|
// Bob is able to decrypt the message
|
2018-10-16 10:31:05 +00:00
|
|
|
response, err := s.bob.HandleMessage(bobKey, &aliceKey.PublicKey, marshaledMsg[&bobKey.PublicKey])
|
2018-09-24 18:07:34 +00:00
|
|
|
s.NoError(err)
|
2018-10-16 10:31:05 +00:00
|
|
|
unmarshaledMsg := response.Message
|
2018-09-24 18:07:34 +00:00
|
|
|
|
|
|
|
s.NotNil(unmarshaledMsg)
|
|
|
|
|
|
|
|
recoveredPayload := ChatMessagePayload{}
|
|
|
|
err = proto.Unmarshal(unmarshaledMsg, &recoveredPayload)
|
|
|
|
|
|
|
|
s.NoError(err)
|
|
|
|
s.Equalf(proto.Equal(&payload, &recoveredPayload), true, "It successfully unmarshal the decrypted message")
|
|
|
|
}
|