Handle mentions on server

This commit is contained in:
Andrea Maria Piana 2020-09-03 08:53:26 +02:00
parent 8ee3c75510
commit 18877cae6f
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
2 changed files with 120 additions and 22 deletions

View File

@ -152,10 +152,16 @@ func (s *Server) HandlePushNotificationRequest(publicKey *ecdsa.PublicKey,
return nil
}
response := s.buildPushNotificationRequestResponseAndSendNotification(&request)
response, requestsAndRegistrations := s.buildPushNotificationRequestResponse(&request)
//AndSendNotification(&request)
if response == nil {
return nil
}
err = s.sendPushNotification(requestsAndRegistrations)
if err != nil {
s.config.Logger.Error("failed to send go rush notification", zap.Error(err))
return err
}
encodedMessage, err := proto.Marshal(response)
if err != nil {
return err
@ -334,23 +340,22 @@ func (s *Server) buildPushNotificationQueryResponse(query *protobuf.PushNotifica
return response
}
func (s *Server) blockedChatID(blockedChatIDs [][]byte, chatID []byte) bool {
for _, blockedChatID := range blockedChatIDs {
if bytes.Equal(blockedChatID, chatID) {
func (s *Server) contains(list [][]byte, chatID []byte) bool {
for _, list := range list {
if bytes.Equal(list, chatID) {
return true
}
}
return false
}
// buildPushNotificationRequestResponseAndSendNotification will build a response
// and fire-and-forget send a query to the gorush instance
func (s *Server) buildPushNotificationRequestResponseAndSendNotification(request *protobuf.PushNotificationRequest) *protobuf.PushNotificationResponse {
// buildPushNotificationRequestResponse will build a response
func (s *Server) buildPushNotificationRequestResponse(request *protobuf.PushNotificationRequest) (*protobuf.PushNotificationResponse, []*RequestAndRegistration) {
response := &protobuf.PushNotificationResponse{}
// We don't even send a response in this case
if request == nil || len(request.MessageId) == 0 {
s.config.Logger.Warn("empty message id")
return nil
return nil, nil
}
response.MessageId = request.MessageId
@ -378,10 +383,10 @@ func (s *Server) buildPushNotificationRequestResponseAndSendNotification(request
report.Error = protobuf.PushNotificationReport_NOT_REGISTERED
} else if registration.AccessToken != pn.AccessToken {
report.Error = protobuf.PushNotificationReport_WRONG_TOKEN
} else if s.blockedChatID(registration.BlockedChatList, pn.ChatId) {
} else if s.contains(registration.BlockedChatList, pn.ChatId) {
// We report as successful but don't send the notification
report.Success = true
} else {
} else if s.isMessageNotification(pn) || s.isValidMentionNotification(pn, registration) {
// For now we just assume that the notification will be successful
requestAndRegistrations = append(requestAndRegistrations, &RequestAndRegistration{
Request: pn,
@ -389,27 +394,24 @@ func (s *Server) buildPushNotificationRequestResponseAndSendNotification(request
})
report.Success = true
}
response.Reports = append(response.Reports, report)
}
s.config.Logger.Info("built pn request")
if len(requestAndRegistrations) == 0 {
s.config.Logger.Warn("no request and registration")
return response
return response, nil
}
// This can be done asynchronously
return response, requestAndRegistrations
}
func (s *Server) sendPushNotification(requestAndRegistrations []*RequestAndRegistration) error {
if len(requestAndRegistrations) == 0 {
return nil
}
goRushRequest := PushNotificationRegistrationToGoRushRequest(requestAndRegistrations)
err := sendGoRushNotification(goRushRequest, s.config.GorushURL, s.config.Logger)
if err != nil {
s.config.Logger.Error("failed to send go rush notification", zap.Error(err))
// TODO: handle this error?
// GoRush will not let us know that the sending of the push notification has failed,
// so this likely mean that the actual HTTP request has failed, or there was some unexpected error
}
return response
return sendGoRushNotification(goRushRequest, s.config.GorushURL, s.config.Logger)
}
// listenToPublicKeyQueryTopic listen to a topic derived from the hashed public key
@ -468,3 +470,11 @@ func (s *Server) buildPushNotificationRegistrationResponse(publicKey *ecdsa.Publ
return response
}
func (s *Server) isMessageNotification(pn *protobuf.PushNotification) bool {
return pn.Type == protobuf.PushNotification_MESSAGE
}
func (s *Server) isValidMentionNotification(pn *protobuf.PushNotification, registration *protobuf.PushNotificationRegistration) bool {
return !registration.BlockMentions && pn.Type == protobuf.PushNotification_MENTION && s.contains(registration.AllowedMentionsChatList, pn.ChatId)
}

View File

@ -582,3 +582,91 @@ func (s *ServerSuite) TestbuildPushNotificationQueryResponseWithFiltering() {
s.Require().Equal(s.installationID, queryResponse.Info[0].InstallationId)
s.Require().Equal(allowedKeyList, queryResponse.Info[0].AllowedKeyList)
}
func (s *ServerSuite) TestPushNotificationMentions() {
existingChatID := []byte("existing-chat-id")
nonExistingChatID := []byte("non-existing-chat-id")
registration := &protobuf.PushNotificationRegistration{
DeviceToken: "abc",
AccessToken: s.accessToken,
Grant: s.grant,
TokenType: protobuf.PushNotificationRegistration_APN_TOKEN,
InstallationId: s.installationID,
AllowedMentionsChatList: [][]byte{existingChatID},
Version: 1,
}
payload, err := proto.Marshal(registration)
s.Require().NoError(err)
cyphertext, err := common.Encrypt(payload, s.sharedKey, rand.Reader)
s.Require().NoError(err)
response := s.server.buildPushNotificationRegistrationResponse(&s.key.PublicKey, cyphertext)
s.Require().NotNil(response)
s.Require().True(response.Success)
pushNotificationRequest := &protobuf.PushNotificationRequest{
MessageId: []byte("message-id"),
Requests: []*protobuf.PushNotification{
{
AccessToken: s.accessToken,
PublicKey: common.HashPublicKey(&s.key.PublicKey),
ChatId: existingChatID,
InstallationId: s.installationID,
Type: protobuf.PushNotification_MENTION,
},
{
AccessToken: s.accessToken,
PublicKey: common.HashPublicKey(&s.key.PublicKey),
ChatId: nonExistingChatID,
InstallationId: s.installationID,
Type: protobuf.PushNotification_MENTION,
},
},
}
pushNotificationResponse, requestAndRegistrations := s.server.buildPushNotificationRequestResponse(pushNotificationRequest)
s.Require().NotNil(pushNotificationResponse)
s.Require().NotNil(requestAndRegistrations)
// only one should succeed
s.Require().Len(requestAndRegistrations, 1)
}
func (s *ServerSuite) TestPushNotificationDisabledMentions() {
existingChatID := []byte("existing-chat-id")
registration := &protobuf.PushNotificationRegistration{
DeviceToken: "abc",
AccessToken: s.accessToken,
Grant: s.grant,
TokenType: protobuf.PushNotificationRegistration_APN_TOKEN,
BlockMentions: true,
InstallationId: s.installationID,
AllowedMentionsChatList: [][]byte{existingChatID},
Version: 1,
}
payload, err := proto.Marshal(registration)
s.Require().NoError(err)
cyphertext, err := common.Encrypt(payload, s.sharedKey, rand.Reader)
s.Require().NoError(err)
response := s.server.buildPushNotificationRegistrationResponse(&s.key.PublicKey, cyphertext)
s.Require().NotNil(response)
s.Require().True(response.Success)
pushNotificationRequest := &protobuf.PushNotificationRequest{
MessageId: []byte("message-id"),
Requests: []*protobuf.PushNotification{
{
AccessToken: s.accessToken,
PublicKey: common.HashPublicKey(&s.key.PublicKey),
ChatId: existingChatID,
InstallationId: s.installationID,
Type: protobuf.PushNotification_MENTION,
},
},
}
pushNotificationResponse, requestAndRegistrations := s.server.buildPushNotificationRequestResponse(pushNotificationRequest)
s.Require().NotNil(pushNotificationResponse)
s.Require().Nil(requestAndRegistrations)
}