Dont sent messages to user who have not joined
This commit is contained in:
parent
2d525f9503
commit
28e06daf6d
|
@ -115,6 +115,16 @@ func (c *Chat) MembersAsPublicKeys() ([]*ecdsa.PublicKey, error) {
|
||||||
return stringSliceToPublicKeys(publicKeys, true)
|
return stringSliceToPublicKeys(publicKeys, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Chat) JoinedMembersAsPublicKeys() ([]*ecdsa.PublicKey, error) {
|
||||||
|
var publicKeys []string
|
||||||
|
for _, item := range c.Members {
|
||||||
|
if item.Joined {
|
||||||
|
publicKeys = append(publicKeys, item.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stringSliceToPublicKeys(publicKeys, true)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Chat) HasMember(memberID string) bool {
|
func (c *Chat) HasMember(memberID string) bool {
|
||||||
for _, member := range c.Members {
|
for _, member := range c.Members {
|
||||||
if memberID == member.ID {
|
if memberID == member.ID {
|
||||||
|
|
|
@ -1663,9 +1663,18 @@ func (m *Messenger) dispatchMessage(ctx context.Context, spec common.RawMessage)
|
||||||
case ChatTypePrivateGroupChat:
|
case ChatTypePrivateGroupChat:
|
||||||
logger.Debug("sending group message", zap.String("chatName", chat.Name))
|
logger.Debug("sending group message", zap.String("chatName", chat.Name))
|
||||||
if spec.Recipients == nil {
|
if spec.Recipients == nil {
|
||||||
spec.Recipients, err = chat.MembersAsPublicKeys()
|
// Chat messages are only dispatched to users who joined
|
||||||
if err != nil {
|
if spec.MessageType == protobuf.ApplicationMetadataMessage_CHAT_MESSAGE {
|
||||||
return nil, err
|
spec.Recipients, err = chat.JoinedMembersAsPublicKeys()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
spec.Recipients, err = chat.MembersAsPublicKeys()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hasPairedDevices := m.hasPairedDevices()
|
hasPairedDevices := m.hasPairedDevices()
|
||||||
|
@ -3519,7 +3528,7 @@ func (m *Messenger) pushNotificationOptions() *pushnotificationclient.Registrati
|
||||||
var publicChatIDs []string
|
var publicChatIDs []string
|
||||||
|
|
||||||
for _, contact := range m.allContacts {
|
for _, contact := range m.allContacts {
|
||||||
if contact.IsAdded() {
|
if contact.IsAdded() && !contact.IsBlocked() {
|
||||||
pk, err := contact.PublicKey()
|
pk, err := contact.PublicKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.logger.Warn("could not parse contact public key")
|
m.logger.Warn("could not parse contact public key")
|
||||||
|
|
|
@ -641,168 +641,6 @@ func (s *MessengerPushNotificationSuite) TestReceivePushNotificationRetries() {
|
||||||
s.Require().NoError(server.Shutdown())
|
s.Require().NoError(server.Shutdown())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here bob acts as his own server
|
|
||||||
func (s *MessengerPushNotificationSuite) TestActAsYourOwnPushNotificationServer() {
|
|
||||||
bob1 := s.m
|
|
||||||
server := s.newPushNotificationServer(s.shh, s.m.identity)
|
|
||||||
bob2 := server
|
|
||||||
alice := s.newMessenger(s.shh)
|
|
||||||
// start alice and enable sending push notifications
|
|
||||||
s.Require().NoError(alice.Start())
|
|
||||||
s.Require().NoError(alice.EnableSendingPushNotifications())
|
|
||||||
bobInstallationIDs := []string{bob1.installationID, bob2.installationID}
|
|
||||||
|
|
||||||
// Register bob1
|
|
||||||
err := bob1.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom)
|
|
||||||
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)
|
|
||||||
bob1Servers, err := bob1.GetPushNotificationsServers()
|
|
||||||
s.Require().NoError(err)
|
|
||||||
|
|
||||||
// Register bob2
|
|
||||||
err = bob2.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom)
|
|
||||||
s.Require().NoError(err)
|
|
||||||
|
|
||||||
err = bob2.RegisterForPushNotifications(context.Background(), bob2DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN)
|
|
||||||
s.Require().NoError(err)
|
|
||||||
|
|
||||||
err = tt.RetryWithBackOff(func() error {
|
|
||||||
_, err = server.RetrieveAll()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = bob2.RetrieveAll()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
bob2Servers, err := bob2.GetPushNotificationsServers()
|
|
||||||
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)
|
|
||||||
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 info []*pushnotificationclient.PushNotificationInfo
|
|
||||||
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(&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
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
s.Require().NoError(err)
|
|
||||||
|
|
||||||
// Check we have replies for both bob1 and bob2
|
|
||||||
var bob1Info, bob2Info *pushnotificationclient.PushNotificationInfo
|
|
||||||
|
|
||||||
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)
|
|
||||||
s.Require().Equal(bob1Servers[0].AccessToken, bob1Info.AccessToken)
|
|
||||||
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)
|
|
||||||
|
|
||||||
s.Require().NoError(err)
|
|
||||||
s.Require().NotNil(retrievedNotificationInfo)
|
|
||||||
s.Require().Len(retrievedNotificationInfo, 2)
|
|
||||||
|
|
||||||
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(&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
|
|
||||||
})
|
|
||||||
s.Require().NoError(err)
|
|
||||||
s.Require().NoError(bob2.Shutdown())
|
|
||||||
s.Require().NoError(alice.Shutdown())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *MessengerPushNotificationSuite) TestContactCode() {
|
func (s *MessengerPushNotificationSuite) TestContactCode() {
|
||||||
|
|
||||||
bob1 := s.m
|
bob1 := s.m
|
||||||
|
|
|
@ -363,12 +363,14 @@ func (s *Server) buildPushNotificationRequestResponse(request *protobuf.PushNoti
|
||||||
// collect successful requests & registrations
|
// collect successful requests & registrations
|
||||||
var requestAndRegistrations []*RequestAndRegistration
|
var requestAndRegistrations []*RequestAndRegistration
|
||||||
|
|
||||||
|
// TODO: this logic needs to be extracted and tested
|
||||||
for _, pn := range request.Requests {
|
for _, pn := range request.Requests {
|
||||||
registration, err := s.persistence.GetPushNotificationRegistrationByPublicKeyAndInstallationID(pn.PublicKey, pn.InstallationId)
|
registration, err := s.persistence.GetPushNotificationRegistrationByPublicKeyAndInstallationID(pn.PublicKey, pn.InstallationId)
|
||||||
report := &protobuf.PushNotificationReport{
|
report := &protobuf.PushNotificationReport{
|
||||||
PublicKey: pn.PublicKey,
|
PublicKey: pn.PublicKey,
|
||||||
InstallationId: pn.InstallationId,
|
InstallationId: pn.InstallationId,
|
||||||
}
|
}
|
||||||
|
s.config.Logger.Info("registration and request", zap.Any("registration", registration), zap.Any("request", pn))
|
||||||
|
|
||||||
if pn.Type == protobuf.PushNotification_UNKNOWN_PUSH_NOTIFICATION_TYPE {
|
if pn.Type == protobuf.PushNotification_UNKNOWN_PUSH_NOTIFICATION_TYPE {
|
||||||
s.config.Logger.Warn("unhandled type")
|
s.config.Logger.Warn("unhandled type")
|
||||||
|
@ -382,14 +384,17 @@ func (s *Server) buildPushNotificationRequestResponse(request *protobuf.PushNoti
|
||||||
s.config.Logger.Warn("empty registration")
|
s.config.Logger.Warn("empty registration")
|
||||||
report.Error = protobuf.PushNotificationReport_NOT_REGISTERED
|
report.Error = protobuf.PushNotificationReport_NOT_REGISTERED
|
||||||
} else if registration.AccessToken != pn.AccessToken {
|
} else if registration.AccessToken != pn.AccessToken {
|
||||||
|
s.config.Logger.Debug("invalid token")
|
||||||
report.Error = protobuf.PushNotificationReport_WRONG_TOKEN
|
report.Error = protobuf.PushNotificationReport_WRONG_TOKEN
|
||||||
} else if s.contains(registration.BlockedChatList, pn.ChatId) || !s.isValidMentionNotification(pn, registration) {
|
} else if s.contains(registration.BlockedChatList, pn.ChatId) || (s.isMentionNotification(pn) && !s.isValidMentionNotification(pn, registration)) {
|
||||||
// We report as successful but don't send the notification
|
// We report as successful but don't send the notification
|
||||||
// for privacy reasons, as otherwise we would disclose that
|
// for privacy reasons, as otherwise we would disclose that
|
||||||
// the sending client has been blocked or that the registering
|
// the sending client has been blocked or that the registering
|
||||||
// client has not joined a given public chat
|
// client has not joined a given public chat
|
||||||
report.Success = true
|
report.Success = true
|
||||||
|
s.config.Logger.Debug("invalid token", zap.Bool("blocked", s.contains(registration.BlockedChatList, pn.ChatId)), zap.Bool("mention", (s.isMentionNotification(pn) && !s.isValidMentionNotification(pn, registration))))
|
||||||
} else {
|
} else {
|
||||||
|
s.config.Logger.Debug("sending push notification")
|
||||||
// For now we just assume that the notification will be successful
|
// For now we just assume that the notification will be successful
|
||||||
requestAndRegistrations = append(requestAndRegistrations, &RequestAndRegistration{
|
requestAndRegistrations = append(requestAndRegistrations, &RequestAndRegistration{
|
||||||
Request: pn,
|
Request: pn,
|
||||||
|
@ -474,6 +479,10 @@ func (s *Server) buildPushNotificationRegistrationResponse(publicKey *ecdsa.Publ
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) isValidMentionNotification(pn *protobuf.PushNotification, registration *protobuf.PushNotificationRegistration) bool {
|
func (s *Server) isMentionNotification(pn *protobuf.PushNotification) bool {
|
||||||
return !registration.BlockMentions && pn.Type == protobuf.PushNotification_MENTION && s.contains(registration.AllowedMentionsChatList, pn.ChatId)
|
return pn.Type == protobuf.PushNotification_MENTION
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) isValidMentionNotification(pn *protobuf.PushNotification, registration *protobuf.PushNotificationRegistration) bool {
|
||||||
|
return s.isMentionNotification(pn) && !registration.BlockMentions && s.contains(registration.AllowedMentionsChatList, pn.ChatId)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue