github.com/status-im/status-go@v1.1.0/protocol/pushnotificationclient/client_test.go (about) 1 package pushnotificationclient 2 3 import ( 4 "bytes" 5 "crypto/ecdsa" 6 "math/rand" 7 "testing" 8 9 "github.com/google/uuid" 10 "github.com/stretchr/testify/suite" 11 12 "github.com/status-im/status-go/appdatabase" 13 "github.com/status-im/status-go/eth-node/crypto" 14 "github.com/status-im/status-go/eth-node/crypto/ecies" 15 "github.com/status-im/status-go/eth-node/types" 16 "github.com/status-im/status-go/protocol/common" 17 "github.com/status-im/status-go/protocol/protobuf" 18 "github.com/status-im/status-go/protocol/sqlite" 19 "github.com/status-im/status-go/protocol/tt" 20 "github.com/status-im/status-go/t/helpers" 21 ) 22 23 const testDeviceToken = "test-token" 24 25 type ClientSuite struct { 26 suite.Suite 27 persistence *Persistence 28 identity *ecdsa.PrivateKey 29 installationID string 30 client *Client 31 } 32 33 func TestClientSuite(t *testing.T) { 34 s := new(ClientSuite) 35 s.installationID = "c6ae4fde-bb65-11ea-b3de-0242ac130004" 36 37 suite.Run(t, s) 38 } 39 40 func (s *ClientSuite) SetupTest() { 41 db, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) 42 s.Require().NoError(err) 43 err = sqlite.Migrate(db) 44 s.Require().NoError(err) 45 46 s.persistence = NewPersistence(db) 47 48 identity, err := crypto.GenerateKey() 49 s.Require().NoError(err) 50 s.identity = identity 51 52 config := &Config{ 53 Identity: identity, 54 Logger: tt.MustCreateTestLogger(), 55 RemoteNotificationsEnabled: true, 56 InstallationID: s.installationID, 57 } 58 59 s.client = New(s.persistence, config, nil, nil) 60 } 61 62 func (s *ClientSuite) TestBuildPushNotificationRegisterMessage() { 63 mutedChatList := []string{"a", "b"} 64 blockedChatList := []string{"c", "d"} 65 66 // build chat lish hashes 67 var mutedChatListHashes [][]byte 68 for _, chatID := range mutedChatList { 69 mutedChatListHashes = append(mutedChatListHashes, common.Shake256([]byte(chatID))) 70 } 71 // Build Blocked chat list hashes 72 var blockedChatListHashes [][]byte 73 for _, chatID := range blockedChatList { 74 blockedChatListHashes = append(blockedChatListHashes, common.Shake256([]byte(chatID))) 75 } 76 77 contactKey, err := crypto.GenerateKey() 78 s.Require().NoError(err) 79 contactIDs := []*ecdsa.PublicKey{&contactKey.PublicKey} 80 81 options := &RegistrationOptions{ 82 ContactIDs: contactIDs, 83 MutedChatIDs: mutedChatList, 84 BlockedChatIDs: blockedChatList, 85 } 86 87 // Set random generator for uuid 88 var seed int64 = 1 89 uuid.SetRand(rand.New(rand.NewSource(seed))) // nolint: gosec 90 91 // Get token 92 expectedUUID := uuid.New().String() 93 94 // Reset random generator 95 uuid.SetRand(rand.New(rand.NewSource(seed))) // nolint: gosec 96 97 s.client.deviceToken = testDeviceToken 98 // Set reader 99 s.client.reader = bytes.NewReader([]byte(expectedUUID)) 100 101 registration := &protobuf.PushNotificationRegistration{ 102 Version: 1, 103 AccessToken: expectedUUID, 104 DeviceToken: testDeviceToken, 105 InstallationId: s.installationID, 106 Enabled: true, 107 MutedChatList: mutedChatListHashes, 108 BlockedChatList: blockedChatListHashes, 109 } 110 111 actualMessage, err := s.client.buildPushNotificationRegistrationMessage(options) 112 s.Require().NoError(err) 113 114 s.Require().Equal(registration, actualMessage) 115 } 116 117 func (s *ClientSuite) TestBuildPushNotificationRegisterMessageAllowFromContactsOnly() { 118 mutedChatList := []string{"a", "b"} 119 publicChatList := []string{"c", "d"} 120 blockedChatList := []string{"e", "f"} 121 122 // build muted chat lish hashes 123 var mutedChatListHashes [][]byte 124 for _, chatID := range mutedChatList { 125 mutedChatListHashes = append(mutedChatListHashes, common.Shake256([]byte(chatID))) 126 } 127 128 // build blocked chat lish hashes 129 var blockedChatListHashes [][]byte 130 for _, chatID := range blockedChatList { 131 blockedChatListHashes = append(blockedChatListHashes, common.Shake256([]byte(chatID))) 132 } 133 134 // build public chat lish hashes 135 var publicChatListHashes [][]byte 136 for _, chatID := range publicChatList { 137 publicChatListHashes = append(publicChatListHashes, common.Shake256([]byte(chatID))) 138 } 139 140 contactKey, err := crypto.GenerateKey() 141 s.Require().NoError(err) 142 contactIDs := []*ecdsa.PublicKey{&contactKey.PublicKey} 143 options := &RegistrationOptions{ 144 ContactIDs: contactIDs, 145 MutedChatIDs: mutedChatList, 146 BlockedChatIDs: blockedChatList, 147 PublicChatIDs: publicChatList, 148 } 149 150 // Set random generator for uuid 151 var seed int64 = 1 152 uuid.SetRand(rand.New(rand.NewSource(seed))) // nolint: gosec 153 154 // Get token 155 expectedUUID := uuid.New().String() 156 157 // set up reader 158 reader := bytes.NewReader([]byte(expectedUUID)) 159 160 sharedKey, err := ecies.ImportECDSA(s.identity).GenerateShared( 161 ecies.ImportECDSAPublic(&contactKey.PublicKey), 162 accessTokenKeyLength, 163 accessTokenKeyLength, 164 ) 165 s.Require().NoError(err) 166 // build encrypted token 167 encryptedToken, err := encryptAccessToken([]byte(expectedUUID), sharedKey, reader) 168 s.Require().NoError(err) 169 170 // Reset random generator 171 uuid.SetRand(rand.New(rand.NewSource(seed))) // nolint: gosec 172 173 s.client.config.AllowFromContactsOnly = true 174 s.client.deviceToken = testDeviceToken 175 // Set reader 176 s.client.reader = bytes.NewReader([]byte(expectedUUID)) 177 178 registration := &protobuf.PushNotificationRegistration{ 179 Version: 1, 180 AccessToken: expectedUUID, 181 DeviceToken: testDeviceToken, 182 InstallationId: s.installationID, 183 AllowFromContactsOnly: true, 184 Enabled: true, 185 BlockedChatList: blockedChatListHashes, 186 MutedChatList: mutedChatListHashes, 187 AllowedKeyList: [][]byte{encryptedToken}, 188 AllowedMentionsChatList: publicChatListHashes, 189 } 190 191 actualMessage, err := s.client.buildPushNotificationRegistrationMessage(options) 192 s.Require().NoError(err) 193 194 s.Require().Equal(registration, actualMessage) 195 } 196 197 func (s *ClientSuite) TestHandleMessageScheduled() { 198 messageID := []byte("message-id") 199 chatID := "chat-id" 200 installationID1 := "1" 201 installationID2 := "2" 202 rawMessage := &common.RawMessage{ 203 ID: types.EncodeHex(messageID), 204 SendPushNotification: true, 205 LocalChatID: chatID, 206 } 207 208 event := &common.MessageEvent{ 209 RawMessage: rawMessage, 210 } 211 212 s.Require().NoError(s.client.handleMessageScheduled(event)) 213 214 key1, err := crypto.GenerateKey() 215 s.Require().NoError(err) 216 217 // First time, should notify 218 response, err := s.client.shouldNotifyOn(&key1.PublicKey, installationID1, messageID) 219 s.Require().NoError(err) 220 s.Require().True(response) 221 222 // Save notification 223 s.Require().NoError(s.client.notifiedOn(&key1.PublicKey, installationID1, messageID, chatID, protobuf.PushNotification_MESSAGE)) 224 225 // Second time, should not notify 226 response, err = s.client.shouldNotifyOn(&key1.PublicKey, installationID1, messageID) 227 s.Require().NoError(err) 228 s.Require().False(response) 229 230 // Different installationID 231 response, err = s.client.shouldNotifyOn(&key1.PublicKey, installationID2, messageID) 232 s.Require().NoError(err) 233 s.Require().True(response) 234 235 key2, err := crypto.GenerateKey() 236 s.Require().NoError(err) 237 // different key, should notify 238 response, err = s.client.shouldNotifyOn(&key2.PublicKey, installationID1, messageID) 239 s.Require().NoError(err) 240 s.Require().True(response) 241 242 // non tracked message id 243 response, err = s.client.shouldNotifyOn(&key1.PublicKey, installationID1, []byte("not-existing")) 244 s.Require().NoError(err) 245 s.Require().False(response) 246 } 247 248 func (s *ClientSuite) TestShouldRefreshToken() { 249 key1, err := crypto.GenerateKey() 250 s.Require().NoError(err) 251 key2, err := crypto.GenerateKey() 252 s.Require().NoError(err) 253 key3, err := crypto.GenerateKey() 254 s.Require().NoError(err) 255 key4, err := crypto.GenerateKey() 256 s.Require().NoError(err) 257 258 // Contacts are added 259 s.Require().False(s.client.shouldRefreshToken([]*ecdsa.PublicKey{&key1.PublicKey, &key2.PublicKey}, []*ecdsa.PublicKey{&key1.PublicKey, &key2.PublicKey, &key3.PublicKey, &key4.PublicKey}, true, true)) 260 261 // everything the same 262 s.Require().False(s.client.shouldRefreshToken([]*ecdsa.PublicKey{&key1.PublicKey, &key2.PublicKey}, []*ecdsa.PublicKey{&key2.PublicKey, &key1.PublicKey}, true, true)) 263 264 // A contact is removed 265 s.Require().True(s.client.shouldRefreshToken([]*ecdsa.PublicKey{&key1.PublicKey, &key2.PublicKey}, []*ecdsa.PublicKey{&key2.PublicKey}, true, true)) 266 267 // allow from contacts only is disabled 268 s.Require().False(s.client.shouldRefreshToken([]*ecdsa.PublicKey{&key1.PublicKey, &key2.PublicKey}, []*ecdsa.PublicKey{&key2.PublicKey, &key1.PublicKey}, true, false)) 269 270 // allow from contacts only is enabled 271 s.Require().True(s.client.shouldRefreshToken([]*ecdsa.PublicKey{&key1.PublicKey, &key2.PublicKey}, []*ecdsa.PublicKey{&key2.PublicKey, &key1.PublicKey}, false, true)) 272 } 273 274 func (s *ClientSuite) TestHandleMessageScheduledFromPairedDevice() { 275 messageID := []byte("message-id") 276 installationID1 := "1" 277 278 // Should return nil 279 response, err := s.client.shouldNotifyOn(&s.identity.PublicKey, installationID1, messageID) 280 s.Require().NoError(err) 281 s.Require().False(response) 282 }