2020-07-07 09:00:04 +00:00
|
|
|
package protocol
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/ecdsa"
|
2020-07-20 12:46:15 +00:00
|
|
|
"encoding/hex"
|
2020-07-16 08:36:17 +00:00
|
|
|
"errors"
|
2020-11-30 11:03:44 +00:00
|
|
|
"io/ioutil"
|
2020-07-07 09:00:04 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
|
2020-12-15 16:22:56 +00:00
|
|
|
"github.com/status-im/status-go/account/generator"
|
2020-07-07 09:00:04 +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"
|
2020-11-30 11:03:44 +00:00
|
|
|
"github.com/status-im/status-go/multiaccounts"
|
2020-07-20 14:14:42 +00:00
|
|
|
"github.com/status-im/status-go/protocol/common"
|
2020-07-30 08:24:30 +00:00
|
|
|
"github.com/status-im/status-go/protocol/protobuf"
|
2020-07-22 07:41:40 +00:00
|
|
|
"github.com/status-im/status-go/protocol/pushnotificationclient"
|
|
|
|
"github.com/status-im/status-go/protocol/pushnotificationserver"
|
2020-10-08 14:05:49 +00:00
|
|
|
"github.com/status-im/status-go/protocol/sqlite"
|
2020-07-07 09:00:04 +00:00
|
|
|
"github.com/status-im/status-go/protocol/tt"
|
2020-07-21 15:41:10 +00:00
|
|
|
"github.com/status-im/status-go/waku"
|
2020-07-07 09:00:04 +00:00
|
|
|
)
|
|
|
|
|
2020-07-22 07:41:40 +00:00
|
|
|
const (
|
|
|
|
bob1DeviceToken = "token-1"
|
|
|
|
bob2DeviceToken = "token-2"
|
2020-07-30 08:24:30 +00:00
|
|
|
testAPNTopic = "topic"
|
2020-07-22 07:41:40 +00:00
|
|
|
)
|
|
|
|
|
2020-07-07 09:00:04 +00:00
|
|
|
func TestMessengerPushNotificationSuite(t *testing.T) {
|
|
|
|
suite.Run(t, new(MessengerPushNotificationSuite))
|
|
|
|
}
|
|
|
|
|
|
|
|
type MessengerPushNotificationSuite struct {
|
|
|
|
suite.Suite
|
|
|
|
m *Messenger // main instance of Messenger
|
|
|
|
privateKey *ecdsa.PrivateKey // private key for the main instance of Messenger
|
|
|
|
// If one wants to send messages between different instances of Messenger,
|
2020-07-21 15:41:10 +00:00
|
|
|
// a single Waku service should be shared.
|
2020-10-08 14:05:49 +00:00
|
|
|
shh types.Waku
|
|
|
|
logger *zap.Logger
|
2020-07-07 09:00:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MessengerPushNotificationSuite) SetupTest() {
|
|
|
|
s.logger = tt.MustCreateTestLogger()
|
|
|
|
|
2020-07-21 15:41:10 +00:00
|
|
|
config := waku.DefaultConfig
|
|
|
|
config.MinimumAcceptedPoW = 0
|
|
|
|
shh := waku.New(&config, s.logger)
|
|
|
|
s.shh = gethbridge.NewGethWakuWrapper(shh)
|
2020-07-07 09:00:04 +00:00
|
|
|
s.Require().NoError(shh.Start(nil))
|
|
|
|
|
|
|
|
s.m = s.newMessenger(s.shh)
|
|
|
|
s.privateKey = s.m.identity
|
2020-07-31 09:46:38 +00:00
|
|
|
s.Require().NoError(s.m.Start())
|
2020-07-07 09:00:04 +00:00
|
|
|
}
|
|
|
|
|
2020-07-21 15:41:10 +00:00
|
|
|
func (s *MessengerPushNotificationSuite) TearDownTest() {
|
|
|
|
s.Require().NoError(s.m.Shutdown())
|
|
|
|
_ = s.logger.Sync()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MessengerPushNotificationSuite) newMessengerWithOptions(shh types.Waku, privateKey *ecdsa.PrivateKey, options []Option) *Messenger {
|
2020-07-07 09:00:04 +00:00
|
|
|
m, err := NewMessenger(
|
|
|
|
privateKey,
|
|
|
|
&testNode{shh: shh},
|
|
|
|
uuid.New().String(),
|
|
|
|
options...,
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
err = m.Init()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
2020-07-21 15:41:10 +00:00
|
|
|
func (s *MessengerPushNotificationSuite) newMessengerWithKey(shh types.Waku, privateKey *ecdsa.PrivateKey) *Messenger {
|
2020-11-30 11:03:44 +00:00
|
|
|
tmpfile, err := ioutil.TempFile("", "accounts-tests-")
|
|
|
|
s.Require().NoError(err)
|
|
|
|
madb, err := multiaccounts.InitializeDB(tmpfile.Name())
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2020-12-15 16:22:56 +00:00
|
|
|
acc := generator.NewAccount(privateKey, nil)
|
|
|
|
iai := acc.ToIdentifiedAccountInfo("")
|
|
|
|
|
2020-07-07 13:55:24 +00:00
|
|
|
options := []Option{
|
|
|
|
WithCustomLogger(s.logger),
|
|
|
|
WithMessagesPersistenceEnabled(),
|
2020-10-08 14:05:49 +00:00
|
|
|
WithDatabaseConfig(sqlite.InMemoryPath, ""),
|
2020-07-07 13:55:24 +00:00
|
|
|
WithDatasync(),
|
2020-07-27 15:20:16 +00:00
|
|
|
WithPushNotifications(),
|
2020-11-30 11:03:44 +00:00
|
|
|
WithMultiAccounts(madb),
|
2020-12-15 16:22:56 +00:00
|
|
|
WithAccount(iai.ToMultiAccount()),
|
2020-07-07 13:55:24 +00:00
|
|
|
}
|
|
|
|
return s.newMessengerWithOptions(shh, privateKey, options)
|
|
|
|
}
|
|
|
|
|
2020-07-21 15:41:10 +00:00
|
|
|
func (s *MessengerPushNotificationSuite) newMessenger(shh types.Waku) *Messenger {
|
2020-07-07 09:00:04 +00:00
|
|
|
privateKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
return s.newMessengerWithKey(s.shh, privateKey)
|
|
|
|
}
|
|
|
|
|
2020-07-22 07:41:40 +00:00
|
|
|
func (s *MessengerPushNotificationSuite) newPushNotificationServer(shh types.Waku, privateKey *ecdsa.PrivateKey) *Messenger {
|
2020-07-07 13:55:24 +00:00
|
|
|
|
2020-07-22 07:41:40 +00:00
|
|
|
serverConfig := &pushnotificationserver.Config{
|
2020-08-20 07:26:00 +00:00
|
|
|
Enabled: true,
|
2020-07-07 13:55:24 +00:00
|
|
|
Logger: s.logger,
|
|
|
|
Identity: privateKey,
|
|
|
|
}
|
|
|
|
|
|
|
|
options := []Option{
|
|
|
|
WithCustomLogger(s.logger),
|
|
|
|
WithMessagesPersistenceEnabled(),
|
2020-10-08 14:05:49 +00:00
|
|
|
WithDatabaseConfig(sqlite.InMemoryPath, "some-key"),
|
2020-07-07 13:55:24 +00:00
|
|
|
WithPushNotificationServerConfig(serverConfig),
|
|
|
|
WithDatasync(),
|
|
|
|
}
|
|
|
|
return s.newMessengerWithOptions(shh, privateKey, options)
|
|
|
|
}
|
|
|
|
|
2020-07-07 09:00:04 +00:00
|
|
|
func (s *MessengerPushNotificationSuite) TestReceivePushNotification() {
|
2020-07-07 13:55:24 +00:00
|
|
|
|
2020-07-09 16:52:26 +00:00
|
|
|
bob1 := s.m
|
|
|
|
bob2 := s.newMessengerWithKey(s.shh, s.m.identity)
|
2020-07-31 09:46:38 +00:00
|
|
|
s.Require().NoError(bob2.Start())
|
2020-07-22 07:41:40 +00:00
|
|
|
|
|
|
|
serverKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
server := s.newPushNotificationServer(s.shh, serverKey)
|
|
|
|
|
2020-07-10 13:26:06 +00:00
|
|
|
alice := s.newMessenger(s.shh)
|
2020-07-20 12:46:15 +00:00
|
|
|
// start alice and enable sending push notifications
|
|
|
|
s.Require().NoError(alice.Start())
|
|
|
|
s.Require().NoError(alice.EnableSendingPushNotifications())
|
2020-07-10 13:26:06 +00:00
|
|
|
bobInstallationIDs := []string{bob1.installationID, bob2.installationID}
|
2020-07-07 09:00:04 +00:00
|
|
|
|
2020-07-09 16:52:26 +00:00
|
|
|
// Register bob1
|
2020-08-20 09:05:39 +00:00
|
|
|
err = bob1.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom)
|
2020-07-07 09:00:04 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2020-07-30 08:24:30 +00:00
|
|
|
err = bob1.RegisterForPushNotifications(context.Background(), bob1DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN)
|
2020-07-07 13:55:24 +00:00
|
|
|
|
2020-07-17 11:41:49 +00:00
|
|
|
// Pull servers and check we registered
|
|
|
|
err = tt.RetryWithBackOff(func() error {
|
2020-07-20 08:06:24 +00:00
|
|
|
_, err = server.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = bob1.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-07-17 11:41:49 +00:00
|
|
|
registered, err := bob1.RegisteredForPushNotifications()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !registered {
|
|
|
|
return errors.New("not registered")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
// Make sure we receive it
|
|
|
|
s.Require().NoError(err)
|
2020-08-20 09:05:39 +00:00
|
|
|
bob1Servers, err := bob1.GetPushNotificationsServers()
|
2020-07-17 11:41:49 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Register bob2
|
2020-08-20 09:05:39 +00:00
|
|
|
err = bob2.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom)
|
2020-07-17 11:41:49 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2020-07-30 08:24:30 +00:00
|
|
|
err = bob2.RegisterForPushNotifications(context.Background(), bob2DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN)
|
2020-07-17 11:41:49 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
err = tt.RetryWithBackOff(func() error {
|
2020-07-20 08:06:24 +00:00
|
|
|
_, err = server.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = bob2.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-07-17 11:41:49 +00:00
|
|
|
registered, err := bob2.RegisteredForPushNotifications()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !registered {
|
|
|
|
return errors.New("not registered")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
// Make sure we receive it
|
|
|
|
s.Require().NoError(err)
|
2020-08-20 09:05:39 +00:00
|
|
|
bob2Servers, err := bob2.GetPushNotificationsServers()
|
2020-07-17 11:41:49 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2020-07-20 12:46:15 +00:00
|
|
|
// Create one to one chat & send message
|
|
|
|
pkString := hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey))
|
|
|
|
chat := CreateOneToOneChat(pkString, &s.m.identity.PublicKey, alice.transport)
|
|
|
|
s.Require().NoError(alice.SaveChat(&chat))
|
|
|
|
inputMessage := buildTestMessage(chat)
|
2020-07-20 14:14:42 +00:00
|
|
|
response, err := alice.SendChatMessage(context.Background(), inputMessage)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
messageIDString := response.Messages[0].ID
|
|
|
|
messageID, err := hex.DecodeString(messageIDString[2:])
|
2020-07-17 11:41:49 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2020-07-22 07:41:40 +00:00
|
|
|
var info []*pushnotificationclient.PushNotificationInfo
|
2020-07-20 08:06:24 +00:00
|
|
|
err = tt.RetryWithBackOff(func() error {
|
|
|
|
_, err = server.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = alice.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-07-17 11:41:49 +00:00
|
|
|
|
2020-07-20 08:06:24 +00:00
|
|
|
info, err = alice.pushNotificationClient.GetPushNotificationInfo(&bob1.identity.PublicKey, bobInstallationIDs)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// Check we have replies for both bob1 and bob2
|
|
|
|
if len(info) != 2 {
|
|
|
|
return errors.New("info not fetched")
|
|
|
|
}
|
|
|
|
return nil
|
2020-07-17 11:41:49 +00:00
|
|
|
|
2020-07-20 08:06:24 +00:00
|
|
|
})
|
2020-07-17 11:41:49 +00:00
|
|
|
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Check we have replies for both bob1 and bob2
|
2020-07-22 07:41:40 +00:00
|
|
|
var bob1Info, bob2Info *pushnotificationclient.PushNotificationInfo
|
2020-07-17 11:41:49 +00:00
|
|
|
|
|
|
|
if info[0].AccessToken == bob1Servers[0].AccessToken {
|
|
|
|
bob1Info = info[0]
|
|
|
|
bob2Info = info[1]
|
|
|
|
} else {
|
|
|
|
bob2Info = info[0]
|
|
|
|
bob1Info = info[1]
|
|
|
|
}
|
|
|
|
|
|
|
|
s.Require().NotNil(bob1Info)
|
|
|
|
s.Require().Equal(bob1.installationID, bob1Info.InstallationID)
|
2020-07-20 08:32:00 +00:00
|
|
|
s.Require().Equal(bob1Servers[0].AccessToken, bob1Info.AccessToken)
|
2020-07-17 11:41:49 +00:00
|
|
|
s.Require().Equal(&bob1.identity.PublicKey, bob1Info.PublicKey)
|
|
|
|
|
|
|
|
s.Require().NotNil(bob2Info)
|
|
|
|
s.Require().Equal(bob2.installationID, bob2Info.InstallationID)
|
|
|
|
s.Require().Equal(bob2Servers[0].AccessToken, bob2Info.AccessToken)
|
|
|
|
s.Require().Equal(&bob2.identity.PublicKey, bob2Info.PublicKey)
|
|
|
|
|
|
|
|
retrievedNotificationInfo, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob1.identity.PublicKey, bobInstallationIDs)
|
2020-07-20 08:32:00 +00:00
|
|
|
|
2020-07-17 11:41:49 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().NotNil(retrievedNotificationInfo)
|
|
|
|
s.Require().Len(retrievedNotificationInfo, 2)
|
2020-07-20 14:14:42 +00:00
|
|
|
|
2020-07-22 07:41:40 +00:00
|
|
|
var sentNotification *pushnotificationclient.SentNotification
|
2020-07-20 14:14:42 +00:00
|
|
|
err = tt.RetryWithBackOff(func() error {
|
|
|
|
_, err = server.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = alice.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
sentNotification, err = alice.pushNotificationClient.GetSentNotification(common.HashPublicKey(&bob1.identity.PublicKey), bob1.installationID, messageID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if sentNotification == nil {
|
|
|
|
return errors.New("sent notification not found")
|
|
|
|
}
|
|
|
|
if !sentNotification.Success {
|
|
|
|
return errors.New("sent notification not successul")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
2020-07-20 14:52:55 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-21 15:41:10 +00:00
|
|
|
s.Require().NoError(bob2.Shutdown())
|
|
|
|
s.Require().NoError(alice.Shutdown())
|
|
|
|
s.Require().NoError(server.Shutdown())
|
2020-07-17 11:41:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MessengerPushNotificationSuite) TestReceivePushNotificationFromContactOnly() {
|
|
|
|
|
2020-07-20 08:32:00 +00:00
|
|
|
bob := s.m
|
2020-07-22 07:41:40 +00:00
|
|
|
|
|
|
|
serverKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
server := s.newPushNotificationServer(s.shh, serverKey)
|
|
|
|
|
2020-07-17 11:41:49 +00:00
|
|
|
alice := s.newMessenger(s.shh)
|
2020-07-20 12:46:15 +00:00
|
|
|
// start alice and enable push notifications
|
|
|
|
s.Require().NoError(alice.Start())
|
|
|
|
s.Require().NoError(alice.EnableSendingPushNotifications())
|
2020-07-20 13:58:54 +00:00
|
|
|
bobInstallationIDs := []string{bob.installationID}
|
2020-07-17 11:41:49 +00:00
|
|
|
|
2020-07-20 08:32:00 +00:00
|
|
|
// Register bob
|
2020-08-20 09:05:39 +00:00
|
|
|
err = bob.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom)
|
2020-07-17 11:41:49 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2020-07-20 08:32:00 +00:00
|
|
|
// Add alice has a contact
|
|
|
|
aliceContact := &Contact{
|
|
|
|
ID: types.EncodeHex(crypto.FromECDSAPub(&alice.identity.PublicKey)),
|
|
|
|
Name: "Some Contact",
|
|
|
|
SystemTags: []string{contactAdded},
|
|
|
|
}
|
2020-07-09 16:52:26 +00:00
|
|
|
|
2020-07-20 08:32:00 +00:00
|
|
|
err = bob.SaveContact(aliceContact)
|
2020-07-16 08:36:17 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-09 16:52:26 +00:00
|
|
|
|
2020-07-20 08:32:00 +00:00
|
|
|
// Enable from contacts only
|
|
|
|
err = bob.EnablePushNotificationsFromContactsOnly()
|
2020-07-09 16:52:26 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2020-07-30 08:24:30 +00:00
|
|
|
err = bob.RegisterForPushNotifications(context.Background(), bob1DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN)
|
2020-07-16 08:36:17 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-09 16:52:26 +00:00
|
|
|
|
2020-07-20 08:32:00 +00:00
|
|
|
// Pull servers and check we registered
|
2020-07-16 08:36:17 +00:00
|
|
|
err = tt.RetryWithBackOff(func() error {
|
2020-07-20 08:06:24 +00:00
|
|
|
_, err = server.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-07-20 08:32:00 +00:00
|
|
|
_, err = bob.RetrieveAll()
|
2020-07-20 08:06:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-07-20 08:32:00 +00:00
|
|
|
registered, err := bob.RegisteredForPushNotifications()
|
2020-07-16 08:36:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !registered {
|
|
|
|
return errors.New("not registered")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
2020-07-09 16:52:26 +00:00
|
|
|
// Make sure we receive it
|
|
|
|
s.Require().NoError(err)
|
2020-08-20 09:05:39 +00:00
|
|
|
bobServers, err := bob.GetPushNotificationsServers()
|
2020-07-16 08:36:17 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-09 16:52:26 +00:00
|
|
|
|
2020-07-20 12:46:15 +00:00
|
|
|
// Create one to one chat & send message
|
|
|
|
pkString := hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey))
|
|
|
|
chat := CreateOneToOneChat(pkString, &s.m.identity.PublicKey, alice.transport)
|
|
|
|
s.Require().NoError(alice.SaveChat(&chat))
|
|
|
|
inputMessage := buildTestMessage(chat)
|
2020-07-20 14:14:42 +00:00
|
|
|
response, err := alice.SendChatMessage(context.Background(), inputMessage)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
messageIDString := response.Messages[0].ID
|
|
|
|
messageID, err := hex.DecodeString(messageIDString[2:])
|
2020-07-10 13:26:06 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-09 16:52:26 +00:00
|
|
|
|
2020-07-22 07:41:40 +00:00
|
|
|
var info []*pushnotificationclient.PushNotificationInfo
|
2020-07-20 08:06:24 +00:00
|
|
|
err = tt.RetryWithBackOff(func() error {
|
|
|
|
_, err = server.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = alice.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-07-09 16:52:26 +00:00
|
|
|
|
2020-07-20 08:32:00 +00:00
|
|
|
info, err = alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs)
|
2020-07-20 08:06:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-07-20 08:32:00 +00:00
|
|
|
// Check we have replies for bob
|
|
|
|
if len(info) != 1 {
|
2020-07-20 08:06:24 +00:00
|
|
|
return errors.New("info not fetched")
|
|
|
|
}
|
|
|
|
return nil
|
2020-07-10 13:26:06 +00:00
|
|
|
|
2020-07-20 08:06:24 +00:00
|
|
|
})
|
2020-07-07 09:00:04 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-09 16:52:26 +00:00
|
|
|
|
2020-07-20 08:32:00 +00:00
|
|
|
s.Require().NotNil(info)
|
|
|
|
s.Require().Equal(bob.installationID, info[0].InstallationID)
|
|
|
|
s.Require().Equal(bobServers[0].AccessToken, info[0].AccessToken)
|
|
|
|
s.Require().Equal(&bob.identity.PublicKey, info[0].PublicKey)
|
2020-07-09 16:52:26 +00:00
|
|
|
|
2020-07-20 08:32:00 +00:00
|
|
|
retrievedNotificationInfo, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs)
|
2020-07-10 13:26:06 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().NotNil(retrievedNotificationInfo)
|
2020-07-20 08:32:00 +00:00
|
|
|
s.Require().Len(retrievedNotificationInfo, 1)
|
2020-07-20 14:14:42 +00:00
|
|
|
|
2020-07-22 07:41:40 +00:00
|
|
|
var sentNotification *pushnotificationclient.SentNotification
|
2020-07-20 14:14:42 +00:00
|
|
|
err = tt.RetryWithBackOff(func() error {
|
|
|
|
_, err = server.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = alice.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
sentNotification, err = alice.pushNotificationClient.GetSentNotification(common.HashPublicKey(&bob.identity.PublicKey), bob.installationID, messageID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if sentNotification == nil {
|
|
|
|
return errors.New("sent notification not found")
|
|
|
|
}
|
|
|
|
if !sentNotification.Success {
|
|
|
|
return errors.New("sent notification not successul")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
2020-07-20 14:52:55 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-21 15:41:10 +00:00
|
|
|
s.Require().NoError(alice.Shutdown())
|
|
|
|
s.Require().NoError(server.Shutdown())
|
2020-07-07 09:00:04 +00:00
|
|
|
}
|
2020-07-20 13:58:54 +00:00
|
|
|
|
|
|
|
func (s *MessengerPushNotificationSuite) TestReceivePushNotificationRetries() {
|
|
|
|
|
|
|
|
bob := s.m
|
2020-07-22 07:41:40 +00:00
|
|
|
|
|
|
|
serverKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
server := s.newPushNotificationServer(s.shh, serverKey)
|
|
|
|
|
2020-07-20 13:58:54 +00:00
|
|
|
alice := s.newMessenger(s.shh)
|
|
|
|
// another contact to invalidate the token
|
|
|
|
frank := s.newMessenger(s.shh)
|
2020-07-31 09:46:38 +00:00
|
|
|
s.Require().NoError(frank.Start())
|
2020-07-20 13:58:54 +00:00
|
|
|
// start alice and enable push notifications
|
|
|
|
s.Require().NoError(alice.Start())
|
|
|
|
s.Require().NoError(alice.EnableSendingPushNotifications())
|
|
|
|
bobInstallationIDs := []string{bob.installationID}
|
|
|
|
|
|
|
|
// Register bob
|
2020-08-20 09:05:39 +00:00
|
|
|
err = bob.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom)
|
2020-07-20 13:58:54 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Add alice has a contact
|
|
|
|
aliceContact := &Contact{
|
|
|
|
ID: types.EncodeHex(crypto.FromECDSAPub(&alice.identity.PublicKey)),
|
|
|
|
Name: "Some Contact",
|
|
|
|
SystemTags: []string{contactAdded},
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bob.SaveContact(aliceContact)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Add frank has a contact
|
|
|
|
frankContact := &Contact{
|
|
|
|
ID: types.EncodeHex(crypto.FromECDSAPub(&frank.identity.PublicKey)),
|
|
|
|
Name: "Some Contact",
|
|
|
|
SystemTags: []string{contactAdded},
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bob.SaveContact(frankContact)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Enable from contacts only
|
|
|
|
err = bob.EnablePushNotificationsFromContactsOnly()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2020-07-30 08:24:30 +00:00
|
|
|
err = bob.RegisterForPushNotifications(context.Background(), bob1DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN)
|
2020-07-20 13:58:54 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Pull servers and check we registered
|
|
|
|
err = tt.RetryWithBackOff(func() error {
|
|
|
|
_, err = server.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = bob.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
registered, err := bob.RegisteredForPushNotifications()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !registered {
|
|
|
|
return errors.New("not registered")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
// Make sure we receive it
|
|
|
|
s.Require().NoError(err)
|
2020-08-20 09:05:39 +00:00
|
|
|
bobServers, err := bob.GetPushNotificationsServers()
|
2020-07-20 13:58:54 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Create one to one chat & send message
|
|
|
|
pkString := hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey))
|
|
|
|
chat := CreateOneToOneChat(pkString, &s.m.identity.PublicKey, alice.transport)
|
|
|
|
s.Require().NoError(alice.SaveChat(&chat))
|
|
|
|
inputMessage := buildTestMessage(chat)
|
2020-07-20 14:52:55 +00:00
|
|
|
_, err = alice.SendChatMessage(context.Background(), inputMessage)
|
2020-07-20 14:14:42 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2020-07-20 14:52:55 +00:00
|
|
|
// We check that alice retrieves the info from the server
|
2020-07-22 07:41:40 +00:00
|
|
|
var info []*pushnotificationclient.PushNotificationInfo
|
2020-07-20 14:52:55 +00:00
|
|
|
err = tt.RetryWithBackOff(func() error {
|
|
|
|
_, err = server.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = alice.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
info, err = alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// Check we have replies for bob
|
|
|
|
if len(info) != 1 {
|
|
|
|
return errors.New("info not fetched")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
|
|
|
|
})
|
2020-07-20 13:58:54 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2020-07-20 14:52:55 +00:00
|
|
|
s.Require().NotNil(info)
|
|
|
|
s.Require().Equal(bob.installationID, info[0].InstallationID)
|
|
|
|
s.Require().Equal(bobServers[0].AccessToken, info[0].AccessToken)
|
|
|
|
s.Require().Equal(&bob.identity.PublicKey, info[0].PublicKey)
|
|
|
|
|
2020-07-20 13:58:54 +00:00
|
|
|
// The message has been sent, but not received, now we remove a contact so that the token is invalidated
|
|
|
|
frankContact = &Contact{
|
|
|
|
ID: types.EncodeHex(crypto.FromECDSAPub(&frank.identity.PublicKey)),
|
|
|
|
Name: "Some Contact",
|
|
|
|
SystemTags: []string{},
|
|
|
|
}
|
|
|
|
err = bob.SaveContact(frankContact)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Re-registration should be triggered, pull from server and bob to check we are correctly registered
|
|
|
|
// Pull servers and check we registered
|
|
|
|
err = tt.RetryWithBackOff(func() error {
|
|
|
|
_, err = server.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = bob.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
registered, err := bob.RegisteredForPushNotifications()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !registered {
|
|
|
|
return errors.New("not registered")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
2020-08-20 09:05:39 +00:00
|
|
|
newBobServers, err := bob.GetPushNotificationsServers()
|
2020-07-20 13:58:54 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
// Make sure access token is not the same
|
|
|
|
s.Require().NotEqual(newBobServers[0].AccessToken, bobServers[0].AccessToken)
|
|
|
|
|
2020-07-20 14:52:55 +00:00
|
|
|
// Send another message, here the token will not be valid
|
|
|
|
inputMessage = buildTestMessage(chat)
|
|
|
|
response, err := alice.SendChatMessage(context.Background(), inputMessage)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
messageIDString := response.Messages[0].ID
|
|
|
|
messageID, err := hex.DecodeString(messageIDString[2:])
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2020-07-20 13:58:54 +00:00
|
|
|
err = tt.RetryWithBackOff(func() error {
|
|
|
|
_, err = server.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = alice.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
info, err = alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// Check we have replies for bob
|
|
|
|
if len(info) != 1 {
|
|
|
|
return errors.New("info not fetched")
|
|
|
|
}
|
2020-07-20 14:52:55 +00:00
|
|
|
if newBobServers[0].AccessToken != info[0].AccessToken {
|
|
|
|
return errors.New("still using the old access token")
|
|
|
|
}
|
2020-07-20 13:58:54 +00:00
|
|
|
return nil
|
|
|
|
|
|
|
|
})
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
s.Require().NotNil(info)
|
|
|
|
s.Require().Equal(bob.installationID, info[0].InstallationID)
|
|
|
|
s.Require().Equal(newBobServers[0].AccessToken, info[0].AccessToken)
|
|
|
|
s.Require().Equal(&bob.identity.PublicKey, info[0].PublicKey)
|
|
|
|
|
|
|
|
retrievedNotificationInfo, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().NotNil(retrievedNotificationInfo)
|
|
|
|
s.Require().Len(retrievedNotificationInfo, 1)
|
2020-07-20 14:14:42 +00:00
|
|
|
|
2020-07-22 07:41:40 +00:00
|
|
|
var sentNotification *pushnotificationclient.SentNotification
|
2020-07-20 14:14:42 +00:00
|
|
|
err = tt.RetryWithBackOff(func() error {
|
|
|
|
_, err = server.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = alice.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
sentNotification, err = alice.pushNotificationClient.GetSentNotification(common.HashPublicKey(&bob.identity.PublicKey), bob.installationID, messageID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if sentNotification == nil {
|
|
|
|
return errors.New("sent notification not found")
|
|
|
|
}
|
|
|
|
if !sentNotification.Success {
|
|
|
|
return errors.New("sent notification not successul")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
2020-07-20 14:52:55 +00:00
|
|
|
|
|
|
|
s.Require().NoError(err)
|
2020-07-21 15:41:10 +00:00
|
|
|
s.Require().NoError(alice.Shutdown())
|
|
|
|
s.Require().NoError(server.Shutdown())
|
2020-07-20 13:58:54 +00:00
|
|
|
}
|
2020-07-22 07:41:40 +00:00
|
|
|
|
2020-08-18 15:07:48 +00:00
|
|
|
func (s *MessengerPushNotificationSuite) TestContactCode() {
|
|
|
|
|
|
|
|
bob1 := s.m
|
|
|
|
|
|
|
|
serverKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
server := s.newPushNotificationServer(s.shh, serverKey)
|
|
|
|
|
|
|
|
alice := s.newMessenger(s.shh)
|
|
|
|
// start alice and enable sending push notifications
|
|
|
|
s.Require().NoError(alice.Start())
|
|
|
|
s.Require().NoError(alice.EnableSendingPushNotifications())
|
|
|
|
|
|
|
|
// Register bob1
|
2020-08-20 09:05:39 +00:00
|
|
|
err = bob1.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom)
|
2020-08-18 15:07:48 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
err = bob1.RegisterForPushNotifications(context.Background(), bob1DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN)
|
|
|
|
|
|
|
|
// Pull servers and check we registered
|
|
|
|
err = tt.RetryWithBackOff(func() error {
|
|
|
|
_, err = server.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = bob1.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
registered, err := bob1.RegisteredForPushNotifications()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !registered {
|
|
|
|
return errors.New("not registered")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
// Make sure we receive it
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
contactCodeAdvertisement, err := bob1.buildContactCodeAdvertisement()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().NotNil(contactCodeAdvertisement)
|
|
|
|
|
|
|
|
s.Require().NoError(alice.pushNotificationClient.HandleContactCodeAdvertisement(&bob1.identity.PublicKey, *contactCodeAdvertisement))
|
|
|
|
|
|
|
|
s.Require().NoError(alice.Shutdown())
|
|
|
|
s.Require().NoError(server.Shutdown())
|
|
|
|
}
|
2020-09-02 14:11:16 +00:00
|
|
|
|
|
|
|
func (s *MessengerPushNotificationSuite) TestReceivePushNotificationMention() {
|
|
|
|
|
|
|
|
bob := s.m
|
|
|
|
|
|
|
|
serverKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
server := s.newPushNotificationServer(s.shh, serverKey)
|
|
|
|
|
|
|
|
alice := s.newMessenger(s.shh)
|
|
|
|
// start alice and enable sending push notifications
|
|
|
|
s.Require().NoError(alice.Start())
|
|
|
|
s.Require().NoError(alice.EnableSendingPushNotifications())
|
|
|
|
bobInstallationIDs := []string{bob.installationID}
|
|
|
|
|
|
|
|
// Create public chat and join for both alice and bob
|
|
|
|
chat := CreatePublicChat("status", s.m.transport)
|
|
|
|
err = bob.SaveChat(&chat)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
err = bob.Join(chat)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
err = alice.SaveChat(&chat)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
err = alice.Join(chat)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Register bob
|
|
|
|
err = bob.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
err = bob.RegisterForPushNotifications(context.Background(), bob1DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN)
|
|
|
|
|
|
|
|
// Pull servers and check we registered
|
|
|
|
err = tt.RetryWithBackOff(func() error {
|
|
|
|
_, err = server.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = bob.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
registered, err := bob.RegisteredForPushNotifications()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !registered {
|
|
|
|
return errors.New("not registered")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
// Make sure we receive it
|
|
|
|
s.Require().NoError(err)
|
|
|
|
bobServers, err := bob.GetPushNotificationsServers()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
inputMessage := buildTestMessage(chat)
|
|
|
|
// message contains a mention
|
|
|
|
inputMessage.Text = "Hey @" + types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey))
|
|
|
|
response, err := alice.SendChatMessage(context.Background(), inputMessage)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
messageIDString := response.Messages[0].ID
|
|
|
|
messageID, err := hex.DecodeString(messageIDString[2:])
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
var bobInfo []*pushnotificationclient.PushNotificationInfo
|
|
|
|
err = tt.RetryWithBackOff(func() error {
|
|
|
|
_, err = server.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = alice.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
bobInfo, err = alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// Check we have replies for bob
|
|
|
|
if len(bobInfo) != 1 {
|
|
|
|
return errors.New("info not fetched")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
s.Require().NotEmpty(bobInfo)
|
|
|
|
s.Require().Equal(bob.installationID, bobInfo[0].InstallationID)
|
|
|
|
s.Require().Equal(bobServers[0].AccessToken, bobInfo[0].AccessToken)
|
|
|
|
s.Require().Equal(&bob.identity.PublicKey, bobInfo[0].PublicKey)
|
|
|
|
|
|
|
|
retrievedNotificationInfo, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs)
|
|
|
|
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().NotNil(retrievedNotificationInfo)
|
|
|
|
s.Require().Len(retrievedNotificationInfo, 1)
|
|
|
|
|
|
|
|
var sentNotification *pushnotificationclient.SentNotification
|
|
|
|
err = tt.RetryWithBackOff(func() error {
|
|
|
|
_, err = server.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = alice.RetrieveAll()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
sentNotification, err = alice.pushNotificationClient.GetSentNotification(common.HashPublicKey(&bob.identity.PublicKey), bob.installationID, messageID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if sentNotification == nil {
|
|
|
|
return errors.New("sent notification not found")
|
|
|
|
}
|
|
|
|
if !sentNotification.Success {
|
|
|
|
return errors.New("sent notification not successul")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().NoError(alice.Shutdown())
|
|
|
|
s.Require().NoError(server.Shutdown())
|
|
|
|
}
|