status-go/protocol/pushnotificationclient/client_test.go

285 lines
8.7 KiB
Go
Raw Normal View History

2020-07-22 07:41:40 +00:00
package pushnotificationclient
2020-06-30 07:50:59 +00:00
import (
"bytes"
"crypto/ecdsa"
"io/ioutil"
2020-06-30 07:50:59 +00:00
"math/rand"
"os"
2020-06-30 07:50:59 +00:00
"testing"
"github.com/google/uuid"
2020-07-22 07:41:40 +00:00
"github.com/stretchr/testify/suite"
2020-06-30 07:50:59 +00:00
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/crypto/ecies"
2020-07-22 07:41:40 +00:00
"github.com/status-im/status-go/eth-node/types"
2020-07-10 07:45:40 +00:00
"github.com/status-im/status-go/protocol/common"
2020-06-30 07:50:59 +00:00
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/protocol/sqlite"
"github.com/status-im/status-go/protocol/tt"
2020-06-30 07:50:59 +00:00
)
2020-07-22 07:41:40 +00:00
const testDeviceToken = "test-token"
type ClientSuite struct {
suite.Suite
tmpFile *os.File
persistence *Persistence
identity *ecdsa.PrivateKey
installationID string
client *Client
}
func TestClientSuite(t *testing.T) {
s := new(ClientSuite)
s.installationID = "c6ae4fde-bb65-11ea-b3de-0242ac130004"
suite.Run(t, s)
}
func (s *ClientSuite) SetupTest() {
tmpFile, err := ioutil.TempFile("", "")
s.Require().NoError(err)
s.tmpFile = tmpFile
database, err := sqlite.Open(s.tmpFile.Name(), "", sqlite.ReducedKDFIterationsNumber)
s.Require().NoError(err)
s.persistence = NewPersistence(database)
identity, err := crypto.GenerateKey()
s.Require().NoError(err)
s.identity = identity
config := &Config{
Identity: identity,
Logger: tt.MustCreateTestLogger(),
RemoteNotificationsEnabled: true,
InstallationID: s.installationID,
}
s.client = New(s.persistence, config, nil, nil)
}
func (s *ClientSuite) TestBuildPushNotificationRegisterMessage() {
2020-06-30 07:50:59 +00:00
mutedChatList := []string{"a", "b"}
blockedChatList := []string{"c", "d"}
2020-06-30 07:50:59 +00:00
// build chat lish hashes
var mutedChatListHashes [][]byte
for _, chatID := range mutedChatList {
2020-07-10 07:45:40 +00:00
mutedChatListHashes = append(mutedChatListHashes, common.Shake256([]byte(chatID)))
2020-06-30 07:50:59 +00:00
}
// Build Blocked chat list hashes
var blockedChatListHashes [][]byte
for _, chatID := range blockedChatList {
blockedChatListHashes = append(blockedChatListHashes, common.Shake256([]byte(chatID)))
}
2020-06-30 07:50:59 +00:00
contactKey, err := crypto.GenerateKey()
s.Require().NoError(err)
2020-06-30 07:50:59 +00:00
contactIDs := []*ecdsa.PublicKey{&contactKey.PublicKey}
options := &RegistrationOptions{
ContactIDs: contactIDs,
MutedChatIDs: mutedChatList,
BlockedChatIDs: blockedChatList,
}
2020-06-30 07:50:59 +00:00
// Set random generator for uuid
var seed int64 = 1
2020-12-28 09:09:45 +00:00
uuid.SetRand(rand.New(rand.NewSource(seed))) // nolint: gosec
2020-06-30 07:50:59 +00:00
// Get token
expectedUUID := uuid.New().String()
2020-07-17 12:29:51 +00:00
// Reset random generator
2020-12-28 09:09:45 +00:00
uuid.SetRand(rand.New(rand.NewSource(seed))) // nolint: gosec
2020-07-17 12:29:51 +00:00
2020-07-22 07:41:40 +00:00
s.client.deviceToken = testDeviceToken
2020-07-17 12:29:51 +00:00
// Set reader
s.client.reader = bytes.NewReader([]byte(expectedUUID))
registration := &protobuf.PushNotificationRegistration{
2020-07-17 12:29:51 +00:00
Version: 1,
AccessToken: expectedUUID,
2020-07-22 07:41:40 +00:00
DeviceToken: testDeviceToken,
2020-07-17 12:29:51 +00:00
InstallationId: s.installationID,
Enabled: true,
MutedChatList: mutedChatListHashes,
BlockedChatList: blockedChatListHashes,
2020-07-17 12:29:51 +00:00
}
actualMessage, err := s.client.buildPushNotificationRegistrationMessage(options)
2020-07-17 12:29:51 +00:00
s.Require().NoError(err)
s.Require().Equal(registration, actualMessage)
2020-07-17 12:29:51 +00:00
}
func (s *ClientSuite) TestBuildPushNotificationRegisterMessageAllowFromContactsOnly() {
mutedChatList := []string{"a", "b"}
publicChatList := []string{"c", "d"}
blockedChatList := []string{"e", "f"}
2020-07-17 12:29:51 +00:00
// build muted chat lish hashes
2020-07-17 12:29:51 +00:00
var mutedChatListHashes [][]byte
for _, chatID := range mutedChatList {
mutedChatListHashes = append(mutedChatListHashes, common.Shake256([]byte(chatID)))
}
// build blocked chat lish hashes
var blockedChatListHashes [][]byte
for _, chatID := range blockedChatList {
blockedChatListHashes = append(blockedChatListHashes, common.Shake256([]byte(chatID)))
}
// build public chat lish hashes
var publicChatListHashes [][]byte
for _, chatID := range publicChatList {
publicChatListHashes = append(publicChatListHashes, common.Shake256([]byte(chatID)))
}
2020-07-17 12:29:51 +00:00
contactKey, err := crypto.GenerateKey()
s.Require().NoError(err)
contactIDs := []*ecdsa.PublicKey{&contactKey.PublicKey}
options := &RegistrationOptions{
ContactIDs: contactIDs,
MutedChatIDs: mutedChatList,
BlockedChatIDs: blockedChatList,
PublicChatIDs: publicChatList,
}
2020-07-17 12:29:51 +00:00
// Set random generator for uuid
var seed int64 = 1
2020-12-28 09:09:45 +00:00
uuid.SetRand(rand.New(rand.NewSource(seed))) // nolint: gosec
2020-07-17 12:29:51 +00:00
// Get token
expectedUUID := uuid.New().String()
2020-06-30 07:50:59 +00:00
// set up reader
reader := bytes.NewReader([]byte(expectedUUID))
sharedKey, err := ecies.ImportECDSA(s.identity).GenerateShared(
2020-06-30 07:50:59 +00:00
ecies.ImportECDSAPublic(&contactKey.PublicKey),
accessTokenKeyLength,
accessTokenKeyLength,
)
s.Require().NoError(err)
2020-06-30 07:50:59 +00:00
// build encrypted token
encryptedToken, err := encryptAccessToken([]byte(expectedUUID), sharedKey, reader)
s.Require().NoError(err)
2020-06-30 07:50:59 +00:00
// Reset random generator
2020-12-28 09:09:45 +00:00
uuid.SetRand(rand.New(rand.NewSource(seed))) // nolint: gosec
2020-06-30 07:50:59 +00:00
2020-07-22 07:41:40 +00:00
s.client.config.AllowFromContactsOnly = true
s.client.deviceToken = testDeviceToken
2020-06-30 07:50:59 +00:00
// Set reader
s.client.reader = bytes.NewReader([]byte(expectedUUID))
2020-06-30 07:50:59 +00:00
registration := &protobuf.PushNotificationRegistration{
Version: 1,
AccessToken: expectedUUID,
DeviceToken: testDeviceToken,
InstallationId: s.installationID,
AllowFromContactsOnly: true,
Enabled: true,
BlockedChatList: blockedChatListHashes,
MutedChatList: mutedChatListHashes,
AllowedKeyList: [][]byte{encryptedToken},
AllowedMentionsChatList: publicChatListHashes,
2020-06-30 07:50:59 +00:00
}
actualMessage, err := s.client.buildPushNotificationRegistrationMessage(options)
s.Require().NoError(err)
s.Require().Equal(registration, actualMessage)
}
2020-06-30 07:50:59 +00:00
2020-07-22 07:41:40 +00:00
func (s *ClientSuite) TestHandleMessageScheduled() {
messageID := []byte("message-id")
chatID := "chat-id"
installationID1 := "1"
installationID2 := "2"
2020-07-22 07:41:40 +00:00
rawMessage := &common.RawMessage{
ID: types.EncodeHex(messageID),
SendPushNotification: true,
LocalChatID: chatID,
}
event := &common.MessageEvent{
RawMessage: rawMessage,
}
s.Require().NoError(s.client.handleMessageScheduled(event))
key1, err := crypto.GenerateKey()
s.Require().NoError(err)
// First time, should notify
response, err := s.client.shouldNotifyOn(&key1.PublicKey, installationID1, messageID)
s.Require().NoError(err)
s.Require().True(response)
// Save notification
s.Require().NoError(s.client.notifiedOn(&key1.PublicKey, installationID1, messageID, chatID, protobuf.PushNotification_MESSAGE))
// Second time, should not notify
response, err = s.client.shouldNotifyOn(&key1.PublicKey, installationID1, messageID)
s.Require().NoError(err)
s.Require().False(response)
// Different installationID
response, err = s.client.shouldNotifyOn(&key1.PublicKey, installationID2, messageID)
s.Require().NoError(err)
s.Require().True(response)
key2, err := crypto.GenerateKey()
s.Require().NoError(err)
// different key, should notify
response, err = s.client.shouldNotifyOn(&key2.PublicKey, installationID1, messageID)
s.Require().NoError(err)
s.Require().True(response)
// non tracked message id
response, err = s.client.shouldNotifyOn(&key1.PublicKey, installationID1, []byte("not-existing"))
s.Require().NoError(err)
s.Require().False(response)
2020-06-30 07:50:59 +00:00
}
func (s *ClientSuite) TestShouldRefreshToken() {
key1, err := crypto.GenerateKey()
s.Require().NoError(err)
key2, err := crypto.GenerateKey()
s.Require().NoError(err)
key3, err := crypto.GenerateKey()
s.Require().NoError(err)
key4, err := crypto.GenerateKey()
s.Require().NoError(err)
// Contacts are added
s.Require().False(s.client.shouldRefreshToken([]*ecdsa.PublicKey{&key1.PublicKey, &key2.PublicKey}, []*ecdsa.PublicKey{&key1.PublicKey, &key2.PublicKey, &key3.PublicKey, &key4.PublicKey}, true, true))
// everything the same
s.Require().False(s.client.shouldRefreshToken([]*ecdsa.PublicKey{&key1.PublicKey, &key2.PublicKey}, []*ecdsa.PublicKey{&key2.PublicKey, &key1.PublicKey}, true, true))
// A contact is removed
s.Require().True(s.client.shouldRefreshToken([]*ecdsa.PublicKey{&key1.PublicKey, &key2.PublicKey}, []*ecdsa.PublicKey{&key2.PublicKey}, true, true))
// allow from contacts only is disabled
s.Require().False(s.client.shouldRefreshToken([]*ecdsa.PublicKey{&key1.PublicKey, &key2.PublicKey}, []*ecdsa.PublicKey{&key2.PublicKey, &key1.PublicKey}, true, false))
// allow from contacts only is enabled
s.Require().True(s.client.shouldRefreshToken([]*ecdsa.PublicKey{&key1.PublicKey, &key2.PublicKey}, []*ecdsa.PublicKey{&key2.PublicKey, &key1.PublicKey}, false, true))
}
func (s *ClientSuite) TestHandleMessageScheduledFromPairedDevice() {
messageID := []byte("message-id")
installationID1 := "1"
// Should return nil
response, err := s.client.shouldNotifyOn(&s.identity.PublicKey, installationID1, messageID)
s.Require().NoError(err)
s.Require().False(response)
}