2020-07-22 07:41:40 +00:00
package pushnotificationserver
2020-06-30 08:30:58 +00:00
import (
2020-08-25 09:46:01 +00:00
"bytes"
2020-07-07 09:00:04 +00:00
"context"
2020-06-30 13:14:25 +00:00
"crypto/ecdsa"
2020-07-09 16:52:26 +00:00
"encoding/hex"
2020-06-30 13:14:25 +00:00
2020-06-30 14:55:24 +00:00
"github.com/golang/protobuf/proto"
2020-07-01 08:37:54 +00:00
"github.com/google/uuid"
2020-08-20 07:26:00 +00:00
"github.com/pkg/errors"
2020-07-22 07:41:40 +00:00
"go.uber.org/zap"
2020-06-30 14:55:24 +00:00
2020-07-13 08:53:13 +00:00
"github.com/status-im/status-go/eth-node/crypto"
2020-06-30 13:14:25 +00:00
"github.com/status-im/status-go/eth-node/crypto/ecies"
2020-07-14 14:07:19 +00:00
"github.com/status-im/status-go/eth-node/types"
2020-07-06 08:54:22 +00:00
"github.com/status-im/status-go/protocol/common"
2020-06-30 08:30:58 +00:00
"github.com/status-im/status-go/protocol/protobuf"
)
2020-06-30 13:14:25 +00:00
const encryptedPayloadKeyLength = 16
2020-07-13 10:39:33 +00:00
const defaultGorushURL = "https://gorush.status.im"
2020-06-30 13:14:25 +00:00
2020-09-07 08:25:57 +00:00
var errUnhandledPushNotificationType = errors . New ( "unhandled push notification type" )
2020-06-30 08:30:58 +00:00
type Config struct {
2020-08-20 07:26:00 +00:00
Enabled bool
2020-06-30 08:30:58 +00:00
// Identity is our identity key
Identity * ecdsa . PrivateKey
// GorushUrl is the url for the gorush service
GorushURL string
2020-07-03 10:08:47 +00:00
Logger * zap . Logger
2020-06-30 08:30:58 +00:00
}
type Server struct {
2020-07-06 08:54:22 +00:00
persistence Persistence
config * Config
messageProcessor * common . MessageProcessor
2021-03-31 16:23:45 +00:00
// SentRequests keeps track of the requests sent to gorush, for testing only
SentRequests int64
2020-06-30 08:30:58 +00:00
}
2020-07-06 08:54:22 +00:00
func New ( config * Config , persistence Persistence , messageProcessor * common . MessageProcessor ) * Server {
2020-07-13 10:39:33 +00:00
if len ( config . GorushURL ) == 0 {
config . GorushURL = defaultGorushURL
}
2020-07-06 08:54:22 +00:00
return & Server { persistence : persistence , config : config , messageProcessor : messageProcessor }
2020-06-30 08:30:58 +00:00
}
2020-07-22 07:41:40 +00:00
func ( s * Server ) Start ( ) error {
2020-08-20 07:26:00 +00:00
if s . config . Logger == nil {
logger , err := zap . NewDevelopment ( )
if err != nil {
return errors . Wrap ( err , "failed to create a logger" )
}
s . config . Logger = logger
}
2020-07-22 07:41:40 +00:00
s . config . Logger . Info ( "starting push notification server" )
if s . config . Identity == nil {
2020-09-07 08:25:57 +00:00
s . config . Logger . Debug ( "Identity nil" )
2020-07-22 07:41:40 +00:00
// Pull identity from database
identity , err := s . persistence . GetIdentity ( )
if err != nil {
return err
}
if identity == nil {
identity , err = crypto . GenerateKey ( )
if err != nil {
return err
}
if err := s . persistence . SaveIdentity ( identity ) ; err != nil {
return err
}
}
s . config . Identity = identity
}
pks , err := s . persistence . GetPushNotificationRegistrationPublicKeys ( )
if err != nil {
return err
}
// listen to all topics for users registered
for _ , pk := range pks {
if err := s . listenToPublicKeyQueryTopic ( pk ) ; err != nil {
return err
}
}
s . config . Logger . Info ( "started push notification server" , zap . String ( "identity" , types . EncodeHex ( crypto . FromECDSAPub ( & s . config . Identity . PublicKey ) ) ) )
return nil
}
// HandlePushNotificationRegistration builds a response for the registration and sends it back to the user
func ( s * Server ) HandlePushNotificationRegistration ( publicKey * ecdsa . PublicKey , payload [ ] byte ) error {
response := s . buildPushNotificationRegistrationResponse ( publicKey , payload )
if response == nil {
return nil
}
encodedMessage , err := proto . Marshal ( response )
if err != nil {
return err
}
2020-07-28 13:22:22 +00:00
rawMessage := common . RawMessage {
2020-07-22 07:41:40 +00:00
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_PUSH_NOTIFICATION_REGISTRATION_RESPONSE ,
// we skip encryption as might be sent from an ephemeral key
SkipEncryption : true ,
}
2021-02-23 15:47:45 +00:00
_ , err = s . messageProcessor . SendPrivate ( context . Background ( ) , publicKey , & rawMessage )
2020-07-22 07:41:40 +00:00
return err
}
// HandlePushNotificationQuery builds a response for the query and sends it back to the user
func ( s * Server ) HandlePushNotificationQuery ( publicKey * ecdsa . PublicKey , messageID [ ] byte , query protobuf . PushNotificationQuery ) error {
response := s . buildPushNotificationQueryResponse ( & query )
if response == nil {
return nil
}
response . MessageId = messageID
encodedMessage , err := proto . Marshal ( response )
if err != nil {
return err
}
2020-07-28 13:22:22 +00:00
rawMessage := common . RawMessage {
2020-07-22 07:41:40 +00:00
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_PUSH_NOTIFICATION_QUERY_RESPONSE ,
// we skip encryption as sent from an ephemeral key
SkipEncryption : true ,
}
2021-02-23 15:47:45 +00:00
_ , err = s . messageProcessor . SendPrivate ( context . Background ( ) , publicKey , & rawMessage )
2020-07-22 07:41:40 +00:00
return err
}
// HandlePushNotificationRequest will send a gorush notification and send a response back to the user
func ( s * Server ) HandlePushNotificationRequest ( publicKey * ecdsa . PublicKey ,
2020-08-26 05:54:00 +00:00
messageID [ ] byte ,
2020-07-22 07:41:40 +00:00
request protobuf . PushNotificationRequest ) error {
2020-09-07 08:25:57 +00:00
s . config . Logger . Debug ( "handling pn request" , zap . Binary ( "message-id" , messageID ) )
2020-08-26 05:54:00 +00:00
// This is at-most-once semantic for now
exists , err := s . persistence . PushNotificationExists ( messageID )
if err != nil {
return err
}
if exists {
2020-09-07 08:25:57 +00:00
s . config . Logger . Debug ( "already handled" )
2020-08-26 05:54:00 +00:00
return nil
}
2020-09-03 06:53:26 +00:00
response , requestsAndRegistrations := s . buildPushNotificationRequestResponse ( & request )
//AndSendNotification(&request)
2020-07-22 07:41:40 +00:00
if response == nil {
return nil
}
2020-09-03 06:53:26 +00:00
err = s . sendPushNotification ( requestsAndRegistrations )
if err != nil {
s . config . Logger . Error ( "failed to send go rush notification" , zap . Error ( err ) )
return err
}
2020-07-22 07:41:40 +00:00
encodedMessage , err := proto . Marshal ( response )
if err != nil {
return err
}
2020-07-28 13:22:22 +00:00
rawMessage := common . RawMessage {
2020-07-22 07:41:40 +00:00
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_PUSH_NOTIFICATION_RESPONSE ,
// We skip encryption here as the message has been sent from an ephemeral key
SkipEncryption : true ,
}
2021-02-23 15:47:45 +00:00
_ , err = s . messageProcessor . SendPrivate ( context . Background ( ) , publicKey , & rawMessage )
2020-07-22 07:41:40 +00:00
return err
}
// buildGrantSignatureMaterial builds a grant for a specific server.
// We use 3 components:
// 1) The client public key. Not sure this applies to our signature scheme, but best to be conservative. https://crypto.stackexchange.com/questions/15538/given-a-message-and-signature-find-a-public-key-that-makes-the-signature-valid
// 2) The server public key
// 3) The access token
// By verifying this signature, a client can trust the server was instructed to store this access token.
func ( s * Server ) buildGrantSignatureMaterial ( clientPublicKey * ecdsa . PublicKey , serverPublicKey * ecdsa . PublicKey , accessToken string ) [ ] byte {
var signatureMaterial [ ] byte
signatureMaterial = append ( signatureMaterial , crypto . CompressPubkey ( clientPublicKey ) ... )
signatureMaterial = append ( signatureMaterial , crypto . CompressPubkey ( serverPublicKey ) ... )
signatureMaterial = append ( signatureMaterial , [ ] byte ( accessToken ) ... )
a := crypto . Keccak256 ( signatureMaterial )
return a
}
func ( s * Server ) verifyGrantSignature ( clientPublicKey * ecdsa . PublicKey , accessToken string , grant [ ] byte ) error {
signatureMaterial := s . buildGrantSignatureMaterial ( clientPublicKey , & s . config . Identity . PublicKey , accessToken )
recoveredPublicKey , err := crypto . SigToPub ( signatureMaterial , grant )
if err != nil {
return err
}
if ! common . IsPubKeyEqual ( recoveredPublicKey , clientPublicKey ) {
return errors . New ( "pubkey mismatch" )
}
return nil
}
func ( s * Server ) generateSharedKey ( publicKey * ecdsa . PublicKey ) ( [ ] byte , error ) {
return ecies . ImportECDSA ( s . config . Identity ) . GenerateShared (
2020-06-30 14:55:24 +00:00
ecies . ImportECDSAPublic ( publicKey ) ,
encryptedPayloadKeyLength ,
encryptedPayloadKeyLength ,
)
}
2020-07-22 07:41:40 +00:00
func ( s * Server ) validateUUID ( u string ) error {
2020-07-01 08:37:54 +00:00
if len ( u ) == 0 {
return errors . New ( "empty uuid" )
}
_ , err := uuid . Parse ( u )
return err
}
2020-07-22 07:41:40 +00:00
func ( s * Server ) decryptRegistration ( publicKey * ecdsa . PublicKey , payload [ ] byte ) ( [ ] byte , error ) {
sharedKey , err := s . generateSharedKey ( publicKey )
2020-07-01 10:09:40 +00:00
if err != nil {
return nil , err
}
2020-07-07 09:00:04 +00:00
return common . Decrypt ( payload , sharedKey )
2020-07-01 10:09:40 +00:00
}
2020-07-22 07:41:40 +00:00
// validateRegistration validates a new message against the last one received for a given installationID and and public key
2020-07-01 08:53:05 +00:00
// and return the decrypted message
2020-07-22 07:41:40 +00:00
func ( s * Server ) validateRegistration ( publicKey * ecdsa . PublicKey , payload [ ] byte ) ( * protobuf . PushNotificationRegistration , error ) {
2020-06-30 13:14:25 +00:00
if payload == nil {
2020-07-02 08:08:19 +00:00
return nil , ErrEmptyPushNotificationRegistrationPayload
2020-06-30 13:14:25 +00:00
}
if publicKey == nil {
2020-07-02 08:08:19 +00:00
return nil , ErrEmptyPushNotificationRegistrationPublicKey
2020-06-30 13:14:25 +00:00
}
2020-07-13 08:53:13 +00:00
decryptedPayload , err := s . decryptRegistration ( publicKey , payload )
2020-06-30 13:14:25 +00:00
if err != nil {
2020-07-01 08:53:05 +00:00
return nil , err
2020-06-30 08:30:58 +00:00
}
2020-06-30 13:14:25 +00:00
2020-07-02 08:08:19 +00:00
registration := & protobuf . PushNotificationRegistration { }
2020-06-30 14:55:24 +00:00
2020-07-02 08:08:19 +00:00
if err := proto . Unmarshal ( decryptedPayload , registration ) ; err != nil {
return nil , ErrCouldNotUnmarshalPushNotificationRegistration
2020-06-30 14:55:24 +00:00
}
2020-07-02 08:08:19 +00:00
if registration . Version < 1 {
return nil , ErrInvalidPushNotificationRegistrationVersion
2020-07-01 08:37:54 +00:00
}
2020-07-13 08:53:13 +00:00
if err := s . validateUUID ( registration . InstallationId ) ; err != nil {
2020-07-02 08:08:19 +00:00
return nil , ErrMalformedPushNotificationRegistrationInstallationID
2020-07-01 08:37:54 +00:00
}
2020-07-30 14:47:24 +00:00
previousVersion , err := s . persistence . GetPushNotificationRegistrationVersion ( common . HashPublicKey ( publicKey ) , registration . InstallationId )
2020-07-01 10:09:40 +00:00
if err != nil {
return nil , err
}
2020-07-30 14:47:24 +00:00
if registration . Version <= previousVersion {
2020-07-02 08:08:19 +00:00
return nil , ErrInvalidPushNotificationRegistrationVersion
2020-07-01 10:09:40 +00:00
}
2020-07-22 07:41:40 +00:00
// unregistering message
2020-07-02 08:08:19 +00:00
if registration . Unregister {
return registration , nil
2020-07-01 08:37:54 +00:00
}
2020-07-13 08:53:13 +00:00
if err := s . validateUUID ( registration . AccessToken ) ; err != nil {
2020-07-02 08:08:19 +00:00
return nil , ErrMalformedPushNotificationRegistrationAccessToken
2020-07-01 08:37:54 +00:00
}
2020-07-13 08:53:13 +00:00
if len ( registration . Grant ) == 0 {
return nil , ErrMalformedPushNotificationRegistrationGrant
}
if err := s . verifyGrantSignature ( publicKey , registration . AccessToken , registration . Grant ) ; err != nil {
s . config . Logger . Error ( "failed to verify grant" , zap . Error ( err ) )
return nil , ErrMalformedPushNotificationRegistrationGrant
}
2020-07-22 07:41:40 +00:00
if len ( registration . DeviceToken ) == 0 {
2020-07-02 08:08:19 +00:00
return nil , ErrMalformedPushNotificationRegistrationDeviceToken
2020-06-30 14:55:24 +00:00
}
2020-06-30 13:14:25 +00:00
2020-07-02 14:19:21 +00:00
if registration . TokenType == protobuf . PushNotificationRegistration_UNKNOWN_TOKEN_TYPE {
return nil , ErrUnknownPushNotificationRegistrationTokenType
}
2020-07-02 08:08:19 +00:00
return registration , nil
2020-06-30 08:30:58 +00:00
}
2020-06-30 13:14:25 +00:00
2020-07-22 07:41:40 +00:00
// buildPushNotificationQueryResponse check if we have the client information and send them back
func ( s * Server ) buildPushNotificationQueryResponse ( query * protobuf . PushNotificationQuery ) * protobuf . PushNotificationQueryResponse {
2020-07-09 16:52:26 +00:00
2020-09-07 08:25:57 +00:00
s . config . Logger . Debug ( "handling push notification query" )
2020-07-02 13:57:50 +00:00
response := & protobuf . PushNotificationQueryResponse { }
if query == nil || len ( query . PublicKeys ) == 0 {
return response
}
2020-07-14 14:07:19 +00:00
registrations , err := s . persistence . GetPushNotificationRegistrationByPublicKeys ( query . PublicKeys )
2020-07-02 13:57:50 +00:00
if err != nil {
2020-07-14 14:07:19 +00:00
s . config . Logger . Error ( "failed to retrieve registration" , zap . Error ( err ) )
2020-07-02 13:57:50 +00:00
return response
}
for _ , idAndResponse := range registrations {
registration := idAndResponse . Registration
2020-07-30 14:47:24 +00:00
2020-07-02 13:57:50 +00:00
info := & protobuf . PushNotificationQueryInfo {
PublicKey : idAndResponse . ID ,
2020-07-13 08:53:13 +00:00
Grant : registration . Grant ,
2020-07-17 11:41:49 +00:00
Version : registration . Version ,
2020-07-02 13:57:50 +00:00
InstallationId : registration . InstallationId ,
}
2020-07-22 07:41:40 +00:00
// if instructed to only allow from contacts, send back a list
2020-07-20 08:32:00 +00:00
if registration . AllowFromContactsOnly {
2020-07-22 07:41:40 +00:00
info . AllowedKeyList = registration . AllowedKeyList
2020-07-02 13:57:50 +00:00
} else {
info . AccessToken = registration . AccessToken
}
response . Info = append ( response . Info , info )
}
response . Success = true
return response
}
2020-09-03 06:53:26 +00:00
func ( s * Server ) contains ( list [ ] [ ] byte , chatID [ ] byte ) bool {
for _ , list := range list {
if bytes . Equal ( list , chatID ) {
2020-08-25 09:46:01 +00:00
return true
}
}
return false
}
2020-09-07 08:25:57 +00:00
type reportResult struct {
sendNotification bool
report * protobuf . PushNotificationReport
}
// buildPushNotificationReport checks the request against the registration and
// returns whether we should send the notification and what the response should be
func ( s * Server ) buildPushNotificationReport ( pn * protobuf . PushNotification , registration * protobuf . PushNotificationRegistration ) ( * reportResult , error ) {
response := & reportResult { }
report := & protobuf . PushNotificationReport {
PublicKey : pn . PublicKey ,
InstallationId : pn . InstallationId ,
}
if pn . Type == protobuf . PushNotification_UNKNOWN_PUSH_NOTIFICATION_TYPE {
s . config . Logger . Warn ( "unhandled type" )
return nil , errUnhandledPushNotificationType
}
if registration == nil {
s . config . Logger . Warn ( "empty registration" )
report . Error = protobuf . PushNotificationReport_NOT_REGISTERED
} else if registration . AccessToken != pn . AccessToken {
s . config . Logger . Debug ( "invalid token" )
report . Error = protobuf . PushNotificationReport_WRONG_TOKEN
2021-03-31 16:23:45 +00:00
} else if ( s . isMessageNotification ( pn ) && ! s . isValidMessageNotification ( pn , registration ) ) || ( s . isMentionNotification ( pn ) && ! s . isValidMentionNotification ( pn , registration ) ) || ( s . isRequestToJoinCommunityNotification ( pn ) && ! s . isValidRequestToJoinCommunityNotification ( pn , registration ) ) {
2020-09-07 08:25:57 +00:00
s . config . Logger . Debug ( "filtered notification" )
// We report as successful but don't send the notification
// for privacy reasons, as otherwise we would disclose that
// the sending client has been blocked or that the registering
// client has not joined a given public chat
report . Success = true
} else {
response . sendNotification = true
s . config . Logger . Debug ( "sending push notification" )
report . Success = true
}
response . report = report
return response , nil
}
2020-09-03 06:53:26 +00:00
// buildPushNotificationRequestResponse will build a response
func ( s * Server ) buildPushNotificationRequestResponse ( request * protobuf . PushNotificationRequest ) ( * protobuf . PushNotificationResponse , [ ] * RequestAndRegistration ) {
2020-07-03 08:02:28 +00:00
response := & protobuf . PushNotificationResponse { }
// We don't even send a response in this case
if request == nil || len ( request . MessageId ) == 0 {
2020-07-14 14:07:19 +00:00
s . config . Logger . Warn ( "empty message id" )
2020-09-03 06:53:26 +00:00
return nil , nil
2020-07-03 08:02:28 +00:00
}
response . MessageId = request . MessageId
2020-07-22 07:41:40 +00:00
// collect successful requests & registrations
2020-07-03 08:02:28 +00:00
var requestAndRegistrations [ ] * RequestAndRegistration
for _ , pn := range request . Requests {
2020-07-14 14:07:19 +00:00
registration , err := s . persistence . GetPushNotificationRegistrationByPublicKeyAndInstallationID ( pn . PublicKey , pn . InstallationId )
2020-09-07 08:25:57 +00:00
var report * protobuf . PushNotificationReport
2020-07-03 08:02:28 +00:00
if err != nil {
2020-09-07 08:25:57 +00:00
report = & protobuf . PushNotificationReport {
PublicKey : pn . PublicKey ,
Error : protobuf . PushNotificationReport_UNKNOWN_ERROR_TYPE ,
InstallationId : pn . InstallationId ,
}
2020-09-03 07:19:46 +00:00
} else {
2020-09-07 08:25:57 +00:00
response , err := s . buildPushNotificationReport ( pn , registration )
if err != nil {
s . config . Logger . Warn ( "unhandled type" )
continue
}
if response . sendNotification {
requestAndRegistrations = append ( requestAndRegistrations , & RequestAndRegistration {
Request : pn ,
Registration : registration ,
} )
}
report = response . report
2020-07-03 08:02:28 +00:00
}
2020-09-07 08:25:57 +00:00
2020-07-03 08:02:28 +00:00
response . Reports = append ( response . Reports , report )
}
2020-09-07 08:25:57 +00:00
s . config . Logger . Debug ( "built pn request" )
2020-07-03 08:02:28 +00:00
if len ( requestAndRegistrations ) == 0 {
2020-07-14 14:07:19 +00:00
s . config . Logger . Warn ( "no request and registration" )
2020-09-03 06:53:26 +00:00
return response , nil
2020-07-03 08:02:28 +00:00
}
2020-09-03 06:53:26 +00:00
return response , requestAndRegistrations
}
2020-07-03 08:02:28 +00:00
2020-09-03 06:53:26 +00:00
func ( s * Server ) sendPushNotification ( requestAndRegistrations [ ] * RequestAndRegistration ) error {
if len ( requestAndRegistrations ) == 0 {
return nil
}
2021-03-31 16:23:45 +00:00
s . SentRequests ++
2020-09-03 06:53:26 +00:00
goRushRequest := PushNotificationRegistrationToGoRushRequest ( requestAndRegistrations )
return sendGoRushNotification ( goRushRequest , s . config . GorushURL , s . config . Logger )
2020-07-03 08:02:28 +00:00
}
2020-07-22 07:41:40 +00:00
// listenToPublicKeyQueryTopic listen to a topic derived from the hashed public key
func ( s * Server ) listenToPublicKeyQueryTopic ( hashedPublicKey [ ] byte ) error {
if s . messageProcessor == nil {
return nil
}
encodedPublicKey := hex . EncodeToString ( hashedPublicKey )
2021-01-11 10:32:51 +00:00
_ , err := s . messageProcessor . JoinPublic ( encodedPublicKey )
return err
2020-07-22 07:41:40 +00:00
}
// buildPushNotificationRegistrationResponse will check the registration is valid, save it, and listen to the topic for the queries
func ( s * Server ) buildPushNotificationRegistrationResponse ( publicKey * ecdsa . PublicKey , payload [ ] byte ) * protobuf . PushNotificationRegistrationResponse {
2020-07-07 13:55:24 +00:00
2020-09-07 08:25:57 +00:00
s . config . Logger . Debug ( "handling push notification registration" )
2020-07-02 08:08:19 +00:00
response := & protobuf . PushNotificationRegistrationResponse {
2020-07-07 09:00:04 +00:00
RequestId : common . Shake256 ( payload ) ,
2020-07-02 08:08:19 +00:00
}
2020-07-22 07:41:40 +00:00
registration , err := s . validateRegistration ( publicKey , payload )
2020-07-01 10:09:40 +00:00
if err != nil {
2020-07-02 08:08:19 +00:00
if err == ErrInvalidPushNotificationRegistrationVersion {
response . Error = protobuf . PushNotificationRegistrationResponse_VERSION_MISMATCH
} else {
response . Error = protobuf . PushNotificationRegistrationResponse_MALFORMED_MESSAGE
}
2020-07-07 13:55:24 +00:00
s . config . Logger . Warn ( "registration did not validate" , zap . Error ( err ) )
2020-07-02 08:08:19 +00:00
return response
2020-07-01 10:09:40 +00:00
}
2020-07-02 08:08:19 +00:00
if registration . Unregister {
2020-09-07 08:25:57 +00:00
s . config . Logger . Debug ( "unregistering client" )
2020-07-02 08:08:19 +00:00
// We save an empty registration, only keeping version and installation-id
2020-07-30 14:47:24 +00:00
if err := s . persistence . UnregisterPushNotificationRegistration ( common . HashPublicKey ( publicKey ) , registration . InstallationId , registration . Version ) ; err != nil {
2020-07-02 08:08:19 +00:00
response . Error = protobuf . PushNotificationRegistrationResponse_INTERNAL_ERROR
2020-07-07 13:55:24 +00:00
s . config . Logger . Error ( "failed to unregister " , zap . Error ( err ) )
2020-07-02 08:08:19 +00:00
return response
}
2020-07-07 13:55:24 +00:00
} else if err := s . persistence . SavePushNotificationRegistration ( common . HashPublicKey ( publicKey ) , registration ) ; err != nil {
2020-07-02 08:08:19 +00:00
response . Error = protobuf . PushNotificationRegistrationResponse_INTERNAL_ERROR
2020-07-07 13:55:24 +00:00
s . config . Logger . Error ( "failed to save registration" , zap . Error ( err ) )
2020-07-02 08:08:19 +00:00
return response
}
2020-07-09 16:52:26 +00:00
if err := s . listenToPublicKeyQueryTopic ( common . HashPublicKey ( publicKey ) ) ; err != nil {
response . Error = protobuf . PushNotificationRegistrationResponse_INTERNAL_ERROR
s . config . Logger . Error ( "failed to listen to topic" , zap . Error ( err ) )
return response
}
2020-07-02 08:08:19 +00:00
response . Success = true
2020-09-07 08:25:57 +00:00
s . config . Logger . Debug ( "handled push notification registration successfully" )
2020-07-07 13:55:24 +00:00
2020-07-02 08:08:19 +00:00
return response
2020-07-01 10:09:40 +00:00
}
2020-09-03 06:53:26 +00:00
2020-09-03 09:54:05 +00:00
func ( s * Server ) isMentionNotification ( pn * protobuf . PushNotification ) bool {
return pn . Type == protobuf . PushNotification_MENTION
}
2020-09-07 08:25:57 +00:00
// isValidMentionNotification checks:
// this is a mention
// mentions are enabled
// the user joined the public chat
// the author is not blocked
2020-09-03 06:53:26 +00:00
func ( s * Server ) isValidMentionNotification ( pn * protobuf . PushNotification , registration * protobuf . PushNotificationRegistration ) bool {
2020-09-07 08:25:57 +00:00
return s . isMentionNotification ( pn ) && ! registration . BlockMentions && s . contains ( registration . AllowedMentionsChatList , pn . ChatId ) && ! s . contains ( registration . BlockedChatList , pn . Author )
}
func ( s * Server ) isMessageNotification ( pn * protobuf . PushNotification ) bool {
return pn . Type == protobuf . PushNotification_MESSAGE
}
2021-03-31 16:23:45 +00:00
// isValidMessageNotification checks:
2020-09-07 08:25:57 +00:00
// this is a message
// the chat is not muted
// the author is not blocked
func ( s * Server ) isValidMessageNotification ( pn * protobuf . PushNotification , registration * protobuf . PushNotificationRegistration ) bool {
return s . isMessageNotification ( pn ) && ! s . contains ( registration . BlockedChatList , pn . ChatId ) && ! s . contains ( registration . BlockedChatList , pn . Author )
2020-09-03 06:53:26 +00:00
}
2021-03-31 16:23:45 +00:00
func ( s * Server ) isRequestToJoinCommunityNotification ( pn * protobuf . PushNotification ) bool {
return pn . Type == protobuf . PushNotification_REQUEST_TO_JOIN_COMMUNITY
}
// isValidRequestToJoinCommunityNotification checks:
// this is a request to join a community
// the author is not blocked
func ( s * Server ) isValidRequestToJoinCommunityNotification ( pn * protobuf . PushNotification , registration * protobuf . PushNotificationRegistration ) bool {
return s . isRequestToJoinCommunityNotification ( pn ) && ! s . contains ( registration . BlockedChatList , pn . Author )
}