github.com/status-im/status-go@v1.1.0/protocol/push_notification_test.go (about) 1 package protocol 2 3 import ( 4 "context" 5 "crypto/ecdsa" 6 "encoding/hex" 7 "errors" 8 "testing" 9 10 "github.com/stretchr/testify/suite" 11 "go.uber.org/zap" 12 13 gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" 14 "github.com/status-im/status-go/eth-node/crypto" 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/communities" 18 "github.com/status-im/status-go/protocol/protobuf" 19 "github.com/status-im/status-go/protocol/pushnotificationclient" 20 "github.com/status-im/status-go/protocol/pushnotificationserver" 21 "github.com/status-im/status-go/protocol/requests" 22 "github.com/status-im/status-go/protocol/tt" 23 "github.com/status-im/status-go/waku" 24 ) 25 26 const ( 27 bob1DeviceToken = "token-1" 28 bob2DeviceToken = "token-2" 29 testAPNTopic = "topic" 30 ) 31 32 func TestMessengerPushNotificationSuite(t *testing.T) { 33 suite.Run(t, new(MessengerPushNotificationSuite)) 34 } 35 36 type MessengerPushNotificationSuite struct { 37 suite.Suite 38 m *Messenger // main instance of Messenger 39 privateKey *ecdsa.PrivateKey // private key for the main instance of Messenger 40 // If one wants to send messages between different instances of Messenger, 41 // a single Waku service should be shared. 42 shh types.Waku 43 logger *zap.Logger 44 } 45 46 func (s *MessengerPushNotificationSuite) SetupTest() { 47 s.logger = tt.MustCreateTestLogger() 48 49 config := waku.DefaultConfig 50 config.MinimumAcceptedPoW = 0 51 shh := waku.New(&config, s.logger) 52 s.shh = gethbridge.NewGethWakuWrapper(shh) 53 s.Require().NoError(shh.Start()) 54 55 s.m = s.newMessenger(s.shh) 56 s.privateKey = s.m.identity 57 } 58 59 func (s *MessengerPushNotificationSuite) TearDownTest() { 60 TearDownMessenger(&s.Suite, s.m) 61 _ = s.logger.Sync() 62 } 63 64 func (s *MessengerPushNotificationSuite) newMessenger(shh types.Waku) *Messenger { 65 privateKey, err := crypto.GenerateKey() 66 s.Require().NoError(err) 67 68 messenger, err := newMessengerWithKey(s.shh, privateKey, s.logger, []Option{WithPushNotifications()}) 69 s.Require().NoError(err) 70 return messenger 71 } 72 73 func (s *MessengerPushNotificationSuite) newPushNotificationServer(shh types.Waku, privateKey *ecdsa.PrivateKey) *Messenger { 74 75 serverConfig := &pushnotificationserver.Config{ 76 Enabled: true, 77 Logger: s.logger, 78 Identity: privateKey, 79 } 80 81 options := []Option{ 82 WithPushNotificationServerConfig(serverConfig), 83 } 84 messenger, err := newMessengerWithKey(shh, privateKey, s.logger, options) 85 s.Require().NoError(err) 86 return messenger 87 } 88 89 func (s *MessengerPushNotificationSuite) TestReceivePushNotification() { 90 91 bob1 := s.m 92 bob2, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, []Option{WithPushNotifications()}) 93 s.Require().NoError(err) 94 defer TearDownMessenger(&s.Suite, bob2) 95 96 serverKey, err := crypto.GenerateKey() 97 s.Require().NoError(err) 98 server := s.newPushNotificationServer(s.shh, serverKey) 99 defer TearDownMessenger(&s.Suite, server) 100 101 alice := s.newMessenger(s.shh) 102 defer TearDownMessenger(&s.Suite, alice) 103 s.Require().NoError(alice.EnableSendingPushNotifications()) 104 bobInstallationIDs := []string{bob1.installationID, bob2.installationID} 105 106 // Register bob1 107 err = bob1.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom) 108 s.Require().NoError(err) 109 110 err = bob1.RegisterForPushNotifications(context.Background(), bob1DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN) 111 112 // Pull servers and check we registered 113 err = tt.RetryWithBackOff(func() error { 114 _, err = server.RetrieveAll() 115 if err != nil { 116 return err 117 } 118 _, err = bob1.RetrieveAll() 119 if err != nil { 120 return err 121 } 122 registered, err := bob1.RegisteredForPushNotifications() 123 if err != nil { 124 return err 125 } 126 if !registered { 127 return errors.New("not registered") 128 } 129 bobServers, err := bob1.GetPushNotificationsServers() 130 if err != nil { 131 return err 132 } 133 134 if len(bobServers) == 0 { 135 return errors.New("not registered") 136 } 137 138 return nil 139 }) 140 // Make sure we receive it 141 s.Require().NoError(err) 142 bob1Servers, err := bob1.GetPushNotificationsServers() 143 s.Require().NoError(err) 144 145 // Register bob2 146 err = bob2.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom) 147 s.Require().NoError(err) 148 149 err = bob2.RegisterForPushNotifications(context.Background(), bob2DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN) 150 s.Require().NoError(err) 151 152 err = tt.RetryWithBackOff(func() error { 153 _, err = server.RetrieveAll() 154 if err != nil { 155 return err 156 } 157 _, err = bob2.RetrieveAll() 158 if err != nil { 159 return err 160 } 161 162 registered, err := bob2.RegisteredForPushNotifications() 163 if err != nil { 164 return err 165 } 166 if !registered { 167 return errors.New("not registered") 168 } 169 bobServers, err := bob2.GetPushNotificationsServers() 170 if err != nil { 171 return err 172 } 173 174 if len(bobServers) == 0 { 175 return errors.New("not registered") 176 } 177 178 return nil 179 }) 180 // Make sure we receive it 181 s.Require().NoError(err) 182 bob2Servers, err := bob2.GetPushNotificationsServers() 183 s.Require().NoError(err) 184 185 // Create one to one chat & send message 186 pkString := hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey)) 187 chat := CreateOneToOneChat(pkString, &s.m.identity.PublicKey, alice.transport) 188 s.Require().NoError(alice.SaveChat(chat)) 189 inputMessage := buildTestMessage(*chat) 190 response, err := alice.SendChatMessage(context.Background(), inputMessage) 191 s.Require().NoError(err) 192 messageIDString := response.Messages()[0].ID 193 messageID, err := hex.DecodeString(messageIDString[2:]) 194 s.Require().NoError(err) 195 196 infoMap := make(map[string]*pushnotificationclient.PushNotificationInfo) 197 err = tt.RetryWithBackOff(func() error { 198 _, err = server.RetrieveAll() 199 if err != nil { 200 return err 201 } 202 _, err = alice.RetrieveAll() 203 if err != nil { 204 return err 205 } 206 207 info, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob1.identity.PublicKey, bobInstallationIDs) 208 if err != nil { 209 return err 210 } 211 for _, i := range info { 212 infoMap[i.AccessToken] = i 213 } 214 215 // Check we have replies for both bob1 and bob2 216 if len(infoMap) != 2 { 217 return errors.New("info not fetched") 218 } 219 return nil 220 221 }) 222 223 s.Require().Len(infoMap, 2) 224 225 // Check we have replies for both bob1 and bob2 226 var bob1Info, bob2Info *pushnotificationclient.PushNotificationInfo 227 228 bob1Info = infoMap[bob1Servers[0].AccessToken] 229 bob2Info = infoMap[bob2Servers[0].AccessToken] 230 231 s.Require().NotNil(bob1Info) 232 s.Require().Equal(bob1.installationID, bob1Info.InstallationID) 233 s.Require().Equal(bob1Servers[0].AccessToken, bob1Info.AccessToken) 234 s.Require().Equal(&bob1.identity.PublicKey, bob1Info.PublicKey) 235 236 s.Require().NotNil(bob2Info) 237 s.Require().Equal(bob2.installationID, bob2Info.InstallationID) 238 s.Require().Equal(bob2Servers[0].AccessToken, bob2Info.AccessToken) 239 s.Require().Equal(&bob2.identity.PublicKey, bob2Info.PublicKey) 240 241 retrievedNotificationInfo, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob1.identity.PublicKey, bobInstallationIDs) 242 243 s.Require().NoError(err) 244 s.Require().NotNil(retrievedNotificationInfo) 245 s.Require().Len(retrievedNotificationInfo, 2) 246 247 var sentNotification *pushnotificationclient.SentNotification 248 err = tt.RetryWithBackOff(func() error { 249 _, err = server.RetrieveAll() 250 if err != nil { 251 return err 252 } 253 _, err = alice.RetrieveAll() 254 if err != nil { 255 return err 256 } 257 sentNotification, err = alice.pushNotificationClient.GetSentNotification(common.HashPublicKey(&bob1.identity.PublicKey), bob1.installationID, messageID) 258 if err != nil { 259 return err 260 } 261 if sentNotification == nil { 262 return errors.New("sent notification not found") 263 } 264 if !sentNotification.Success { 265 return errors.New("sent notification not successul") 266 } 267 return nil 268 }) 269 s.Require().NoError(err) 270 } 271 272 func (s *MessengerPushNotificationSuite) TestReceivePushNotificationFromContactOnly() { 273 274 bob := s.m 275 276 serverKey, err := crypto.GenerateKey() 277 s.Require().NoError(err) 278 server := s.newPushNotificationServer(s.shh, serverKey) 279 defer TearDownMessenger(&s.Suite, server) 280 281 alice := s.newMessenger(s.shh) 282 defer TearDownMessenger(&s.Suite, alice) 283 s.Require().NoError(alice.EnableSendingPushNotifications()) 284 bobInstallationIDs := []string{bob.installationID} 285 286 // Register bob 287 err = bob.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom) 288 s.Require().NoError(err) 289 290 // Add alice has a contact 291 aliceContact := &Contact{ 292 ID: types.EncodeHex(crypto.FromECDSAPub(&alice.identity.PublicKey)), 293 EnsName: "Some Contact", 294 ContactRequestLocalState: ContactRequestStateSent, 295 } 296 297 _, err = bob.AddContact(context.Background(), &requests.AddContact{ID: aliceContact.ID}) 298 s.Require().NoError(err) 299 300 // Enable from contacts only 301 err = bob.EnablePushNotificationsFromContactsOnly() 302 s.Require().NoError(err) 303 304 err = bob.RegisterForPushNotifications(context.Background(), bob1DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN) 305 s.Require().NoError(err) 306 307 // Pull servers and check we registered 308 err = tt.RetryWithBackOff(func() error { 309 _, err = server.RetrieveAll() 310 if err != nil { 311 return err 312 } 313 _, err = bob.RetrieveAll() 314 if err != nil { 315 return err 316 } 317 registered, err := bob.RegisteredForPushNotifications() 318 if err != nil { 319 return err 320 } 321 if !registered { 322 return errors.New("not registered") 323 } 324 bobServers, err := bob.GetPushNotificationsServers() 325 if err != nil { 326 return err 327 } 328 329 if len(bobServers) == 0 { 330 return errors.New("not registered") 331 } 332 333 return nil 334 }) 335 // Make sure we receive it 336 s.Require().NoError(err) 337 bobServers, err := bob.GetPushNotificationsServers() 338 s.Require().NoError(err) 339 340 // Create one to one chat & send message 341 pkString := hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey)) 342 chat := CreateOneToOneChat(pkString, &s.m.identity.PublicKey, alice.transport) 343 s.Require().NoError(alice.SaveChat(chat)) 344 inputMessage := buildTestMessage(*chat) 345 response, err := alice.SendChatMessage(context.Background(), inputMessage) 346 s.Require().NoError(err) 347 messageIDString := response.Messages()[0].ID 348 messageID, err := hex.DecodeString(messageIDString[2:]) 349 s.Require().NoError(err) 350 351 var info []*pushnotificationclient.PushNotificationInfo 352 err = tt.RetryWithBackOff(func() error { 353 _, err = server.RetrieveAll() 354 if err != nil { 355 return err 356 } 357 _, err = alice.RetrieveAll() 358 if err != nil { 359 return err 360 } 361 362 info, err = alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs) 363 if err != nil { 364 return err 365 } 366 // Check we have replies for bob 367 if len(info) != 1 { 368 return errors.New("info not fetched") 369 } 370 return nil 371 372 }) 373 s.Require().NoError(err) 374 375 s.Require().NotNil(info) 376 s.Require().Equal(bob.installationID, info[0].InstallationID) 377 s.Require().Equal(bobServers[0].AccessToken, info[0].AccessToken) 378 s.Require().Equal(&bob.identity.PublicKey, info[0].PublicKey) 379 380 retrievedNotificationInfo, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs) 381 s.Require().NoError(err) 382 s.Require().NotNil(retrievedNotificationInfo) 383 s.Require().Len(retrievedNotificationInfo, 1) 384 385 var sentNotification *pushnotificationclient.SentNotification 386 err = tt.RetryWithBackOff(func() error { 387 _, err = server.RetrieveAll() 388 if err != nil { 389 return err 390 } 391 _, err = alice.RetrieveAll() 392 if err != nil { 393 return err 394 } 395 sentNotification, err = alice.pushNotificationClient.GetSentNotification(common.HashPublicKey(&bob.identity.PublicKey), bob.installationID, messageID) 396 if err != nil { 397 return err 398 } 399 if sentNotification == nil { 400 return errors.New("sent notification not found") 401 } 402 if !sentNotification.Success { 403 return errors.New("sent notification not successul") 404 } 405 return nil 406 }) 407 408 s.Require().NoError(err) 409 } 410 411 func (s *MessengerPushNotificationSuite) TestReceivePushNotificationRetries() { 412 413 bob := s.m 414 415 serverKey, err := crypto.GenerateKey() 416 s.Require().NoError(err) 417 server := s.newPushNotificationServer(s.shh, serverKey) 418 defer TearDownMessenger(&s.Suite, server) 419 420 alice := s.newMessenger(s.shh) 421 // another contact to invalidate the token 422 frank := s.newMessenger(s.shh) 423 defer TearDownMessenger(&s.Suite, frank) 424 defer TearDownMessenger(&s.Suite, alice) 425 426 s.Require().NoError(alice.EnableSendingPushNotifications()) 427 bobInstallationIDs := []string{bob.installationID} 428 429 // Register bob 430 err = bob.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom) 431 s.Require().NoError(err) 432 433 // Add alice has a contact 434 aliceContact := &Contact{ 435 ID: types.EncodeHex(crypto.FromECDSAPub(&alice.identity.PublicKey)), 436 EnsName: "Some Contact", 437 ContactRequestLocalState: ContactRequestStateSent, 438 } 439 440 _, err = bob.AddContact(context.Background(), &requests.AddContact{ID: aliceContact.ID}) 441 s.Require().NoError(err) 442 443 // Add frank has a contact 444 frankContact := &Contact{ 445 ID: types.EncodeHex(crypto.FromECDSAPub(&frank.identity.PublicKey)), 446 EnsName: "Some Contact", 447 ContactRequestLocalState: ContactRequestStateSent, 448 } 449 450 _, err = bob.AddContact(context.Background(), &requests.AddContact{ID: frankContact.ID}) 451 s.Require().NoError(err) 452 453 // Enable from contacts only 454 err = bob.EnablePushNotificationsFromContactsOnly() 455 s.Require().NoError(err) 456 457 err = bob.RegisterForPushNotifications(context.Background(), bob1DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN) 458 s.Require().NoError(err) 459 460 // Pull servers and check we registered 461 err = tt.RetryWithBackOff(func() error { 462 _, err = server.RetrieveAll() 463 if err != nil { 464 return err 465 } 466 _, err = bob.RetrieveAll() 467 if err != nil { 468 return err 469 } 470 registered, err := bob.RegisteredForPushNotifications() 471 if err != nil { 472 return err 473 } 474 if !registered { 475 return errors.New("not registered") 476 } 477 bobServers, err := bob.GetPushNotificationsServers() 478 if err != nil { 479 return err 480 } 481 482 if len(bobServers) == 0 { 483 return errors.New("not registered") 484 } 485 486 return nil 487 }) 488 // Make sure we receive it 489 s.Require().NoError(err) 490 bobServers, err := bob.GetPushNotificationsServers() 491 s.Require().NoError(err) 492 493 // Create one to one chat & send message 494 pkString := hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey)) 495 chat := CreateOneToOneChat(pkString, &s.m.identity.PublicKey, alice.transport) 496 s.Require().NoError(alice.SaveChat(chat)) 497 inputMessage := buildTestMessage(*chat) 498 _, err = alice.SendChatMessage(context.Background(), inputMessage) 499 s.Require().NoError(err) 500 501 // We check that alice retrieves the info from the server 502 var info []*pushnotificationclient.PushNotificationInfo 503 err = tt.RetryWithBackOff(func() error { 504 _, err = server.RetrieveAll() 505 if err != nil { 506 return err 507 } 508 _, err = alice.RetrieveAll() 509 if err != nil { 510 return err 511 } 512 513 info, err = alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs) 514 if err != nil { 515 return err 516 } 517 // Check we have replies for bob 518 if len(info) != 1 { 519 return errors.New("info not fetched") 520 } 521 return nil 522 523 }) 524 s.Require().NoError(err) 525 526 s.Require().NotNil(info) 527 s.Require().Equal(bob.installationID, info[0].InstallationID) 528 s.Require().Equal(bobServers[0].AccessToken, info[0].AccessToken) 529 s.Require().Equal(&bob.identity.PublicKey, info[0].PublicKey) 530 531 // The message has been sent, but not received, now we remove a contact so that the token is invalidated 532 frankContact = &Contact{ 533 ID: types.EncodeHex(crypto.FromECDSAPub(&frank.identity.PublicKey)), 534 EnsName: "Some Contact", 535 } 536 _, err = bob.RemoveContact(context.Background(), frankContact.ID) 537 s.Require().NoError(err) 538 539 // Re-registration should be triggered, pull from server and bob to check we are correctly registered 540 // Pull servers and check we registered 541 err = tt.RetryWithBackOff(func() error { 542 _, err = server.RetrieveAll() 543 if err != nil { 544 return err 545 } 546 _, err = bob.RetrieveAll() 547 if err != nil { 548 return err 549 } 550 registered, err := bob.RegisteredForPushNotifications() 551 if err != nil { 552 return err 553 } 554 if !registered { 555 return errors.New("not registered") 556 } 557 return nil 558 }) 559 560 newBobServers, err := bob.GetPushNotificationsServers() 561 s.Require().NoError(err) 562 // Make sure access token is not the same 563 s.Require().NotEqual(newBobServers[0].AccessToken, bobServers[0].AccessToken) 564 565 // Send another message, here the token will not be valid 566 inputMessage = buildTestMessage(*chat) 567 response, err := alice.SendChatMessage(context.Background(), inputMessage) 568 s.Require().NoError(err) 569 messageIDString := response.Messages()[0].ID 570 messageID, err := hex.DecodeString(messageIDString[2:]) 571 s.Require().NoError(err) 572 573 err = tt.RetryWithBackOff(func() error { 574 _, err = server.RetrieveAll() 575 if err != nil { 576 return err 577 } 578 _, err = alice.RetrieveAll() 579 if err != nil { 580 return err 581 } 582 583 info, err = alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs) 584 if err != nil { 585 return err 586 } 587 // Check we have replies for bob 588 if len(info) != 1 { 589 return errors.New("info not fetched") 590 } 591 if newBobServers[0].AccessToken != info[0].AccessToken { 592 return errors.New("still using the old access token") 593 } 594 return nil 595 596 }) 597 s.Require().NoError(err) 598 599 s.Require().NotNil(info) 600 s.Require().Equal(bob.installationID, info[0].InstallationID) 601 s.Require().Equal(newBobServers[0].AccessToken, info[0].AccessToken) 602 s.Require().Equal(&bob.identity.PublicKey, info[0].PublicKey) 603 604 retrievedNotificationInfo, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs) 605 s.Require().NoError(err) 606 s.Require().NotNil(retrievedNotificationInfo) 607 s.Require().Len(retrievedNotificationInfo, 1) 608 609 var sentNotification *pushnotificationclient.SentNotification 610 err = tt.RetryWithBackOff(func() error { 611 _, err = server.RetrieveAll() 612 if err != nil { 613 return err 614 } 615 _, err = alice.RetrieveAll() 616 if err != nil { 617 return err 618 } 619 sentNotification, err = alice.pushNotificationClient.GetSentNotification(common.HashPublicKey(&bob.identity.PublicKey), bob.installationID, messageID) 620 if err != nil { 621 return err 622 } 623 if sentNotification == nil { 624 return errors.New("sent notification not found") 625 } 626 if !sentNotification.Success { 627 return errors.New("sent notification not successul") 628 } 629 return nil 630 }) 631 632 s.Require().NoError(err) 633 } 634 635 func (s *MessengerPushNotificationSuite) TestContactCode() { 636 637 bob1 := s.m 638 639 serverKey, err := crypto.GenerateKey() 640 s.Require().NoError(err) 641 server := s.newPushNotificationServer(s.shh, serverKey) 642 defer TearDownMessenger(&s.Suite, server) 643 644 alice := s.newMessenger(s.shh) 645 s.Require().NoError(err) 646 defer TearDownMessenger(&s.Suite, alice) 647 s.Require().NoError(alice.EnableSendingPushNotifications()) 648 649 // Register bob1 650 err = bob1.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom) 651 s.Require().NoError(err) 652 653 err = bob1.RegisterForPushNotifications(context.Background(), bob1DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN) 654 655 // Pull servers and check we registered 656 err = tt.RetryWithBackOff(func() error { 657 _, err = server.RetrieveAll() 658 if err != nil { 659 return err 660 } 661 _, err = bob1.RetrieveAll() 662 if err != nil { 663 return err 664 } 665 registered, err := bob1.RegisteredForPushNotifications() 666 if err != nil { 667 return err 668 } 669 if !registered { 670 return errors.New("not registered") 671 } 672 bobServers, err := bob1.GetPushNotificationsServers() 673 if err != nil { 674 return err 675 } 676 677 if len(bobServers) == 0 { 678 return errors.New("not registered") 679 } 680 681 return nil 682 }) 683 // Make sure we receive it 684 s.Require().NoError(err) 685 686 contactCodeAdvertisement, err := bob1.buildContactCodeAdvertisement() 687 s.Require().NoError(err) 688 s.Require().NotNil(contactCodeAdvertisement) 689 690 s.Require().NoError(alice.pushNotificationClient.HandleContactCodeAdvertisement(&bob1.identity.PublicKey, contactCodeAdvertisement)) 691 692 } 693 694 func (s *MessengerPushNotificationSuite) TestReceivePushNotificationMention() { 695 696 bob := s.m 697 698 serverKey, err := crypto.GenerateKey() 699 s.Require().NoError(err) 700 server := s.newPushNotificationServer(s.shh, serverKey) 701 defer TearDownMessenger(&s.Suite, server) 702 703 alice := s.newMessenger(s.shh) 704 s.Require().NoError(err) 705 defer TearDownMessenger(&s.Suite, alice) 706 s.Require().NoError(alice.EnableSendingPushNotifications()) 707 bobInstallationIDs := []string{bob.installationID} 708 709 // Create public chat and join for both alice and bob 710 chat := CreatePublicChat("status", s.m.transport) 711 err = bob.SaveChat(chat) 712 s.Require().NoError(err) 713 714 _, err = bob.Join(chat) 715 s.Require().NoError(err) 716 717 err = alice.SaveChat(chat) 718 s.Require().NoError(err) 719 720 _, err = alice.Join(chat) 721 s.Require().NoError(err) 722 723 // Register bob 724 err = bob.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom) 725 s.Require().NoError(err) 726 727 err = bob.RegisterForPushNotifications(context.Background(), bob1DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN) 728 729 // Pull servers and check we registered 730 err = tt.RetryWithBackOff(func() error { 731 _, err = server.RetrieveAll() 732 if err != nil { 733 return err 734 } 735 _, err = bob.RetrieveAll() 736 if err != nil { 737 return err 738 } 739 registered, err := bob.RegisteredForPushNotifications() 740 if err != nil { 741 return err 742 } 743 if !registered { 744 return errors.New("not registered") 745 } 746 747 bobServers, err := bob.GetPushNotificationsServers() 748 if err != nil { 749 return err 750 } 751 752 if len(bobServers) == 0 { 753 return errors.New("not registered") 754 } 755 756 return nil 757 }) 758 // Make sure we receive it 759 s.Require().NoError(err) 760 bobServers, err := bob.GetPushNotificationsServers() 761 s.Require().NoError(err) 762 763 inputMessage := buildTestMessage(*chat) 764 // message contains a mention 765 inputMessage.Text = "Hey @" + types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey)) 766 response, err := alice.SendChatMessage(context.Background(), inputMessage) 767 s.Require().NoError(err) 768 messageIDString := response.Messages()[0].ID 769 messageID, err := hex.DecodeString(messageIDString[2:]) 770 s.Require().NoError(err) 771 772 var bobInfo []*pushnotificationclient.PushNotificationInfo 773 err = tt.RetryWithBackOff(func() error { 774 _, err = server.RetrieveAll() 775 if err != nil { 776 return err 777 } 778 _, err = alice.RetrieveAll() 779 if err != nil { 780 return err 781 } 782 783 bobInfo, err = alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs) 784 if err != nil { 785 return err 786 } 787 // Check we have replies for bob 788 if len(bobInfo) != 1 { 789 return errors.New("info not fetched") 790 } 791 return nil 792 793 }) 794 795 s.Require().NoError(err) 796 797 s.Require().NotEmpty(bobInfo) 798 s.Require().Equal(bob.installationID, bobInfo[0].InstallationID) 799 s.Require().Equal(bobServers[0].AccessToken, bobInfo[0].AccessToken) 800 s.Require().Equal(&bob.identity.PublicKey, bobInfo[0].PublicKey) 801 802 retrievedNotificationInfo, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs) 803 804 s.Require().NoError(err) 805 s.Require().NotNil(retrievedNotificationInfo) 806 s.Require().Len(retrievedNotificationInfo, 1) 807 808 var sentNotification *pushnotificationclient.SentNotification 809 err = tt.RetryWithBackOff(func() error { 810 _, err = server.RetrieveAll() 811 if err != nil { 812 return err 813 } 814 _, err = alice.RetrieveAll() 815 if err != nil { 816 return err 817 } 818 sentNotification, err = alice.pushNotificationClient.GetSentNotification(common.HashPublicKey(&bob.identity.PublicKey), bob.installationID, messageID) 819 if err != nil { 820 return err 821 } 822 if sentNotification == nil { 823 return errors.New("sent notification not found") 824 } 825 if !sentNotification.Success { 826 return errors.New("sent notification not successul") 827 } 828 return nil 829 }) 830 s.Require().NoError(err) 831 } 832 833 func (s *MessengerPushNotificationSuite) TestReceivePushNotificationCommunityRequest() { 834 835 bob := s.m 836 837 serverKey, err := crypto.GenerateKey() 838 s.Require().NoError(err) 839 server := s.newPushNotificationServer(s.shh, serverKey) 840 defer TearDownMessenger(&s.Suite, server) 841 842 alice := s.newMessenger(s.shh) 843 s.Require().NoError(err) 844 defer TearDownMessenger(&s.Suite, alice) 845 s.Require().NoError(alice.EnableSendingPushNotifications()) 846 847 // Register bob 848 err = bob.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom) 849 s.Require().NoError(err) 850 851 err = bob.RegisterForPushNotifications(context.Background(), bob1DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN) 852 853 // Pull servers and check we registered 854 err = tt.RetryWithBackOff(func() error { 855 _, err = server.RetrieveAll() 856 if err != nil { 857 return err 858 } 859 _, err = bob.RetrieveAll() 860 if err != nil { 861 return err 862 } 863 registered, err := bob.RegisteredForPushNotifications() 864 if err != nil { 865 return err 866 } 867 if !registered { 868 return errors.New("not registered") 869 } 870 871 bobServers, err := bob.GetPushNotificationsServers() 872 if err != nil { 873 return err 874 } 875 876 if len(bobServers) == 0 { 877 return errors.New("not registered") 878 } 879 880 return nil 881 }) 882 // Make sure we receive it 883 s.Require().NoError(err) 884 _, err = bob.GetPushNotificationsServers() 885 s.Require().NoError(err) 886 887 description := &requests.CreateCommunity{ 888 Membership: protobuf.CommunityPermissions_MANUAL_ACCEPT, 889 Name: "status", 890 Color: "#ffffff", 891 Description: "status community description", 892 } 893 894 response, err := bob.CreateCommunity(description, true) 895 s.Require().NoError(err) 896 s.Require().NotNil(response) 897 s.Require().Len(response.Communities(), 1) 898 community := response.Communities()[0] 899 900 // Send a community message 901 chat := CreateOneToOneChat(common.PubkeyToHex(&alice.identity.PublicKey), &alice.identity.PublicKey, alice.transport) 902 903 inputMessage := common.NewMessage() 904 inputMessage.ChatId = chat.ID 905 inputMessage.Text = "some text" 906 inputMessage.CommunityID = community.IDString() 907 908 err = bob.SaveChat(chat) 909 s.NoError(err) 910 _, err = bob.SendChatMessage(context.Background(), inputMessage) 911 s.NoError(err) 912 913 // Pull message and make sure org is received 914 err = tt.RetryWithBackOff(func() error { 915 response, err = alice.RetrieveAll() 916 if err != nil { 917 return err 918 } 919 if len(response.Communities()) == 0 { 920 return errors.New("community not received") 921 } 922 return nil 923 }) 924 925 request := createRequestToJoinCommunity(&s.Suite, community.ID(), alice, alicePassword, []string{aliceAddress1}) 926 alice.communitiesManager.PermissionChecker = &testPermissionChecker{} 927 // We try to join the org 928 response, err = alice.RequestToJoinCommunity(request) 929 s.Require().NoError(err) 930 s.Require().NotNil(response) 931 s.Require().Len(response.RequestsToJoinCommunity(), 1) 932 933 requestToJoin1 := response.RequestsToJoinCommunity()[0] 934 s.Require().NotNil(requestToJoin1) 935 s.Require().Equal(community.ID(), requestToJoin1.CommunityID) 936 s.Require().True(requestToJoin1.Our) 937 s.Require().NotEmpty(requestToJoin1.ID) 938 s.Require().NotEmpty(requestToJoin1.Clock) 939 s.Require().Equal(requestToJoin1.PublicKey, common.PubkeyToHex(&alice.identity.PublicKey)) 940 s.Require().Equal(communities.RequestToJoinStatePending, requestToJoin1.State) 941 942 err = tt.RetryWithBackOff(func() error { 943 _, err = server.RetrieveAll() 944 if err != nil { 945 return err 946 } 947 _, err = alice.RetrieveAll() 948 if err != nil { 949 return err 950 } 951 952 if server.pushNotificationServer.SentRequests != 1 { 953 return errors.New("request not sent") 954 } 955 956 return nil 957 958 }) 959 960 s.Require().NoError(err) 961 962 } 963 964 func (s *MessengerPushNotificationSuite) TestReceivePushNotificationPairedDevices() { 965 966 bob1 := s.m 967 bob2, err := newMessengerWithKey(s.shh, s.m.identity, s.logger, []Option{WithPushNotifications()}) 968 s.Require().NoError(err) 969 defer TearDownMessenger(&s.Suite, bob2) 970 971 serverKey, err := crypto.GenerateKey() 972 s.Require().NoError(err) 973 server := s.newPushNotificationServer(s.shh, serverKey) 974 defer TearDownMessenger(&s.Suite, server) 975 976 alice := s.newMessenger(s.shh) 977 s.Require().NoError(err) 978 defer TearDownMessenger(&s.Suite, alice) 979 s.Require().NoError(alice.EnableSendingPushNotifications()) 980 bobInstallationIDs := []string{bob1.installationID, bob2.installationID} 981 982 // Register bob1 983 err = bob1.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom) 984 s.Require().NoError(err) 985 986 err = bob1.RegisterForPushNotifications(context.Background(), bob1DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN) 987 988 // Pull servers and check we registered 989 err = tt.RetryWithBackOff(func() error { 990 _, err = server.RetrieveAll() 991 if err != nil { 992 return err 993 } 994 _, err = bob1.RetrieveAll() 995 if err != nil { 996 return err 997 } 998 registered, err := bob1.RegisteredForPushNotifications() 999 if err != nil { 1000 return err 1001 } 1002 if !registered { 1003 return errors.New("not registered") 1004 } 1005 bobServers, err := bob1.GetPushNotificationsServers() 1006 if err != nil { 1007 return err 1008 } 1009 1010 if len(bobServers) == 0 { 1011 return errors.New("not registered") 1012 } 1013 1014 return nil 1015 }) 1016 // Make sure we receive it 1017 s.Require().NoError(err) 1018 bob1Servers, err := bob1.GetPushNotificationsServers() 1019 s.Require().NoError(err) 1020 1021 // Register bob2 1022 err = bob2.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom) 1023 s.Require().NoError(err) 1024 1025 err = bob2.RegisterForPushNotifications(context.Background(), bob2DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN) 1026 s.Require().NoError(err) 1027 1028 err = tt.RetryWithBackOff(func() error { 1029 _, err = server.RetrieveAll() 1030 if err != nil { 1031 return err 1032 } 1033 _, err = bob2.RetrieveAll() 1034 if err != nil { 1035 return err 1036 } 1037 1038 registered, err := bob2.RegisteredForPushNotifications() 1039 if err != nil { 1040 return err 1041 } 1042 if !registered { 1043 return errors.New("not registered") 1044 } 1045 bobServers, err := bob2.GetPushNotificationsServers() 1046 if err != nil { 1047 return err 1048 } 1049 1050 if len(bobServers) == 0 { 1051 return errors.New("not registered") 1052 } 1053 1054 return nil 1055 }) 1056 // Make sure we receive it 1057 s.Require().NoError(err) 1058 bob2Servers, err := bob2.GetPushNotificationsServers() 1059 s.Require().NoError(err) 1060 1061 // Create one to one chat & send message 1062 pkString := hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey)) 1063 chat := CreateOneToOneChat(pkString, &s.m.identity.PublicKey, alice.transport) 1064 s.Require().NoError(alice.SaveChat(chat)) 1065 inputMessage := buildTestMessage(*chat) 1066 response, err := alice.SendChatMessage(context.Background(), inputMessage) 1067 s.Require().NoError(err) 1068 messageIDString := response.Messages()[0].ID 1069 messageID, err := hex.DecodeString(messageIDString[2:]) 1070 s.Require().NoError(err) 1071 1072 infoMap := make(map[string]*pushnotificationclient.PushNotificationInfo) 1073 err = tt.RetryWithBackOff(func() error { 1074 _, err = server.RetrieveAll() 1075 if err != nil { 1076 return err 1077 } 1078 _, err = alice.RetrieveAll() 1079 if err != nil { 1080 return err 1081 } 1082 1083 info, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob1.identity.PublicKey, bobInstallationIDs) 1084 if err != nil { 1085 return err 1086 } 1087 for _, i := range info { 1088 infoMap[i.AccessToken] = i 1089 } 1090 1091 // Check we have replies for both bob1 and bob2 1092 if len(infoMap) != 2 { 1093 return errors.New("info not fetched") 1094 } 1095 return nil 1096 1097 }) 1098 1099 s.Require().Len(infoMap, 2) 1100 1101 // Check we have replies for both bob1 and bob2 1102 var bob1Info, bob2Info *pushnotificationclient.PushNotificationInfo 1103 1104 bob1Info = infoMap[bob1Servers[0].AccessToken] 1105 bob2Info = infoMap[bob2Servers[0].AccessToken] 1106 1107 s.Require().NotNil(bob1Info) 1108 s.Require().Equal(bob1.installationID, bob1Info.InstallationID) 1109 s.Require().Equal(bob1Servers[0].AccessToken, bob1Info.AccessToken) 1110 s.Require().Equal(&bob1.identity.PublicKey, bob1Info.PublicKey) 1111 1112 s.Require().NotNil(bob2Info) 1113 s.Require().Equal(bob2.installationID, bob2Info.InstallationID) 1114 s.Require().Equal(bob2Servers[0].AccessToken, bob2Info.AccessToken) 1115 s.Require().Equal(&bob2.identity.PublicKey, bob2Info.PublicKey) 1116 1117 retrievedNotificationInfo, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob1.identity.PublicKey, bobInstallationIDs) 1118 1119 s.Require().NoError(err) 1120 s.Require().NotNil(retrievedNotificationInfo) 1121 s.Require().Len(retrievedNotificationInfo, 2) 1122 1123 var sentNotification *pushnotificationclient.SentNotification 1124 err = tt.RetryWithBackOff(func() error { 1125 _, err = server.RetrieveAll() 1126 if err != nil { 1127 return err 1128 } 1129 _, err = alice.RetrieveAll() 1130 if err != nil { 1131 return err 1132 } 1133 sentNotification, err = alice.pushNotificationClient.GetSentNotification(common.HashPublicKey(&bob1.identity.PublicKey), bob1.installationID, messageID) 1134 if err != nil { 1135 return err 1136 } 1137 if sentNotification == nil { 1138 return errors.New("sent notification not found") 1139 } 1140 if !sentNotification.Success { 1141 return errors.New("sent notification not successul") 1142 } 1143 return nil 1144 }) 1145 s.Require().NoError(err) 1146 } 1147 1148 func (s *MessengerPushNotificationSuite) TestReceivePushNotificationReply() { 1149 1150 bob := s.m 1151 1152 serverKey, err := crypto.GenerateKey() 1153 s.Require().NoError(err) 1154 server := s.newPushNotificationServer(s.shh, serverKey) 1155 defer TearDownMessenger(&s.Suite, server) 1156 1157 alice := s.newMessenger(s.shh) 1158 s.Require().NoError(err) 1159 defer TearDownMessenger(&s.Suite, alice) 1160 s.Require().NoError(alice.EnableSendingPushNotifications()) 1161 bobInstallationIDs := []string{bob.installationID} 1162 1163 // Create public chat and join for both alice and bob 1164 chat := CreatePublicChat("status", s.m.transport) 1165 err = bob.SaveChat(chat) 1166 s.Require().NoError(err) 1167 1168 _, err = bob.Join(chat) 1169 s.Require().NoError(err) 1170 1171 err = alice.SaveChat(chat) 1172 s.Require().NoError(err) 1173 1174 _, err = alice.Join(chat) 1175 s.Require().NoError(err) 1176 1177 // Register bob 1178 err = bob.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom) 1179 s.Require().NoError(err) 1180 1181 err = bob.RegisterForPushNotifications(context.Background(), bob1DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN) 1182 1183 // Pull servers and check we registered 1184 err = tt.RetryWithBackOff(func() error { 1185 _, err = server.RetrieveAll() 1186 if err != nil { 1187 return err 1188 } 1189 _, err = bob.RetrieveAll() 1190 if err != nil { 1191 return err 1192 } 1193 registered, err := bob.RegisteredForPushNotifications() 1194 if err != nil { 1195 return err 1196 } 1197 if !registered { 1198 return errors.New("not registered") 1199 } 1200 1201 bobServers, err := bob.GetPushNotificationsServers() 1202 if err != nil { 1203 return err 1204 } 1205 1206 if len(bobServers) == 0 { 1207 return errors.New("not registered") 1208 } 1209 1210 return nil 1211 }) 1212 // Make sure we receive it 1213 s.Require().NoError(err) 1214 bobServers, err := bob.GetPushNotificationsServers() 1215 s.Require().NoError(err) 1216 1217 firstMessage := buildTestMessage(*chat) 1218 firstMessage.Text = "Hello!" 1219 response, err := bob.SendChatMessage(context.Background(), firstMessage) 1220 s.Require().NoError(err) 1221 messageIDString := response.Messages()[0].ID 1222 1223 _, err = WaitOnMessengerResponse( 1224 alice, 1225 func(r *MessengerResponse) bool { 1226 for _, message := range r.Messages() { 1227 if message.ID == messageIDString { 1228 return true 1229 } 1230 } 1231 return false 1232 1233 }, 1234 "no messages", 1235 ) 1236 1237 replyMessage := buildTestMessage(*chat) 1238 replyMessage.Text = "Hello reply" 1239 replyMessage.ResponseTo = messageIDString 1240 response, err = alice.SendChatMessage(context.Background(), replyMessage) 1241 s.Require().NoError(err) 1242 messageIDString = response.Messages()[0].ID 1243 messageID, err := hex.DecodeString(messageIDString[2:]) 1244 s.Require().NoError(err) 1245 1246 var bobInfo []*pushnotificationclient.PushNotificationInfo 1247 err = tt.RetryWithBackOff(func() error { 1248 _, err = server.RetrieveAll() 1249 if err != nil { 1250 return err 1251 } 1252 _, err = alice.RetrieveAll() 1253 if err != nil { 1254 return err 1255 } 1256 1257 bobInfo, err = alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs) 1258 if err != nil { 1259 return err 1260 } 1261 // Check we have replies for bob 1262 if len(bobInfo) != 1 { 1263 return errors.New("info not fetched") 1264 } 1265 return nil 1266 1267 }) 1268 1269 s.Require().NoError(err) 1270 1271 s.Require().NotEmpty(bobInfo) 1272 s.Require().Equal(bob.installationID, bobInfo[0].InstallationID) 1273 s.Require().Equal(bobServers[0].AccessToken, bobInfo[0].AccessToken) 1274 s.Require().Equal(&bob.identity.PublicKey, bobInfo[0].PublicKey) 1275 1276 retrievedNotificationInfo, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs) 1277 1278 s.Require().NoError(err) 1279 s.Require().NotNil(retrievedNotificationInfo) 1280 s.Require().Len(retrievedNotificationInfo, 1) 1281 1282 var sentNotification *pushnotificationclient.SentNotification 1283 err = tt.RetryWithBackOff(func() error { 1284 _, err = server.RetrieveAll() 1285 if err != nil { 1286 return err 1287 } 1288 _, err = alice.RetrieveAll() 1289 if err != nil { 1290 return err 1291 } 1292 sentNotification, err = alice.pushNotificationClient.GetSentNotification(common.HashPublicKey(&bob.identity.PublicKey), bob.installationID, messageID) 1293 if err != nil { 1294 return err 1295 } 1296 if sentNotification == nil { 1297 return errors.New("sent notification not found") 1298 } 1299 if !sentNotification.Success { 1300 return errors.New("sent notification not successul") 1301 } 1302 return nil 1303 }) 1304 s.Require().NoError(err) 1305 }