send push notification info with contact code
This commit is contained in:
parent
541756c777
commit
5544e710ab
|
@ -305,10 +305,29 @@ func (m *Messenger) Start() error {
|
|||
// handleSendContactCode sends a public message wrapped in the encryption
|
||||
// layer, which will propagate our bundle
|
||||
func (m *Messenger) handleSendContactCode() error {
|
||||
var payload []byte
|
||||
if m.pushNotificationClient != nil && m.pushNotificationClient.Enabled() {
|
||||
info, err := m.pushNotificationClient.MyPushNotificationQueryInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(info) != 0 {
|
||||
contactCode := &protobuf.ContactCodeAdvertisement{
|
||||
PushNotificationInfo: info,
|
||||
}
|
||||
|
||||
payload, err = proto.Marshal(contactCode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
contactCodeTopic := transport.ContactCodeTopic(&m.identity.PublicKey)
|
||||
rawMessage := common.RawMessage{
|
||||
LocalChatID: contactCodeTopic,
|
||||
Payload: nil,
|
||||
Payload: payload,
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
@ -2027,6 +2046,18 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
|
|||
}
|
||||
// We continue in any case, no changes to messenger
|
||||
continue
|
||||
case protobuf.ContactCodeAdvertisement:
|
||||
logger.Debug("Received ContactCodeAdvertisement")
|
||||
if m.pushNotificationClient == nil {
|
||||
continue
|
||||
}
|
||||
logger.Debug("Handling PushNotificationRegistrationResponse")
|
||||
if err := m.pushNotificationClient.HandleContactCodeAdvertisement(publicKey, msg.ParsedMessage.Interface().(protobuf.ContactCodeAdvertisement)); err != nil {
|
||||
logger.Warn("failed to handle ContactCodeAdvertisement", zap.Error(err))
|
||||
}
|
||||
// We continue in any case, no changes to messenger
|
||||
continue
|
||||
|
||||
case protobuf.PushNotificationResponse:
|
||||
logger.Debug("Received PushNotificationResponse")
|
||||
if m.pushNotificationClient == nil {
|
||||
|
|
|
@ -318,6 +318,53 @@ func (c *Client) HandlePushNotificationRegistrationResponse(publicKey *ecdsa.Pub
|
|||
return c.persistence.UpsertServer(server)
|
||||
}
|
||||
|
||||
// processQueryInfo takes info about push notifications and validates them
|
||||
func (c *Client) processQueryInfo(clientPublicKey *ecdsa.PublicKey, serverPublicKey *ecdsa.PublicKey, info *protobuf.PushNotificationQueryInfo) error {
|
||||
// make sure the public key matches
|
||||
if !bytes.Equal(info.PublicKey, common.HashPublicKey(clientPublicKey)) {
|
||||
c.config.Logger.Warn("reply for different key, ignoring")
|
||||
return errors.New("reply for a different key, ignoreing")
|
||||
}
|
||||
|
||||
accessToken := info.AccessToken
|
||||
|
||||
// the user wants notification from contacts only, try to decrypt the access token to see if we are in their contacts
|
||||
if len(accessToken) == 0 && len(info.AllowedKeyList) != 0 {
|
||||
accessToken = c.handleAllowedKeyList(clientPublicKey, info.AllowedKeyList)
|
||||
|
||||
}
|
||||
|
||||
// no luck
|
||||
if len(accessToken) == 0 {
|
||||
c.config.Logger.Debug("not in the allowed key list")
|
||||
return nil
|
||||
}
|
||||
|
||||
// We check the user has allowed this server to store this particular
|
||||
// access token, otherwise anyone could reply with a fake token
|
||||
// and receive notifications for a user
|
||||
if err := c.handleGrant(clientPublicKey, serverPublicKey, info.Grant, accessToken); err != nil {
|
||||
c.config.Logger.Warn("grant verification failed, ignoring", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
pushNotificationInfo := &PushNotificationInfo{
|
||||
PublicKey: clientPublicKey,
|
||||
ServerPublicKey: serverPublicKey,
|
||||
AccessToken: accessToken,
|
||||
InstallationID: info.InstallationId,
|
||||
Version: info.Version,
|
||||
RetrievedAt: time.Now().Unix(),
|
||||
}
|
||||
|
||||
err := c.persistence.SavePushNotificationInfo([]*PushNotificationInfo{pushNotificationInfo})
|
||||
if err != nil {
|
||||
c.config.Logger.Error("failed to save push notifications", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HandlePushNotificationQueryResponse should update the data in the database for a given user
|
||||
func (c *Client) HandlePushNotificationQueryResponse(serverPublicKey *ecdsa.PublicKey, response protobuf.PushNotificationQueryResponse) error {
|
||||
c.config.Logger.Debug("received push notification query response", zap.Any("response", response))
|
||||
|
@ -326,61 +373,42 @@ func (c *Client) HandlePushNotificationQueryResponse(serverPublicKey *ecdsa.Publ
|
|||
}
|
||||
|
||||
// get the public key associated with this query
|
||||
publicKey, err := c.persistence.GetQueryPublicKey(response.MessageId)
|
||||
clientPublicKey, err := c.persistence.GetQueryPublicKey(response.MessageId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if publicKey == nil {
|
||||
if clientPublicKey == nil {
|
||||
c.config.Logger.Debug("query not found")
|
||||
return nil
|
||||
}
|
||||
|
||||
var pushNotificationInfo []*PushNotificationInfo
|
||||
// process query, make sure to validate grant as coming from the server
|
||||
for _, info := range response.Info {
|
||||
// make sure the public key matches
|
||||
if !bytes.Equal(info.PublicKey, common.HashPublicKey(publicKey)) {
|
||||
c.config.Logger.Warn("reply for different key, ignoring")
|
||||
continue
|
||||
}
|
||||
|
||||
accessToken := info.AccessToken
|
||||
|
||||
// the user wants notification from contacts only, try to decrypt the access token to see if we are in their contacts
|
||||
if len(accessToken) == 0 && len(info.AllowedKeyList) != 0 {
|
||||
accessToken = c.handleAllowedKeyList(publicKey, info.AllowedKeyList)
|
||||
|
||||
}
|
||||
|
||||
// no luck
|
||||
if len(accessToken) == 0 {
|
||||
c.config.Logger.Debug("not in the allowed key list")
|
||||
continue
|
||||
}
|
||||
|
||||
// We check the user has allowed this server to store this particular
|
||||
// access token, otherwise anyone could reply with a fake token
|
||||
// and receive notifications for a user
|
||||
if err := c.handleGrant(publicKey, serverPublicKey, info.Grant, accessToken); err != nil {
|
||||
c.config.Logger.Warn("grant verification failed, ignoring", zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
pushNotificationInfo = append(pushNotificationInfo, &PushNotificationInfo{
|
||||
PublicKey: publicKey,
|
||||
ServerPublicKey: serverPublicKey,
|
||||
AccessToken: accessToken,
|
||||
InstallationID: info.InstallationId,
|
||||
Version: info.Version,
|
||||
RetrievedAt: time.Now().Unix(),
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
err = c.persistence.SavePushNotificationInfo(pushNotificationInfo)
|
||||
err := c.processQueryInfo(clientPublicKey, serverPublicKey, info)
|
||||
if err != nil {
|
||||
|
||||
c.config.Logger.Warn("failed to process info", zap.Any("info", info), zap.Error(err))
|
||||
continue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// HandleContactCodeAdvertisement checks if there are any info and process them
|
||||
func (c *Client) HandleContactCodeAdvertisement(clientPublicKey *ecdsa.PublicKey, message protobuf.ContactCodeAdvertisement) error {
|
||||
c.config.Logger.Debug("received contact code advertisement", zap.Any("advertisement", message))
|
||||
for _, info := range message.PushNotificationInfo {
|
||||
c.config.Logger.Debug("handling push notification query info")
|
||||
serverPublicKey, err := crypto.UnmarshalPubkey(info.ServerPublicKey)
|
||||
if err != nil {
|
||||
c.config.Logger.Error("failed to save push notifications", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
err = c.processQueryInfo(clientPublicKey, serverPublicKey, info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -443,6 +471,10 @@ func (c *Client) GetPushNotificationInfo(publicKey *ecdsa.PublicKey, installatio
|
|||
return c.persistence.GetPushNotificationInfo(publicKey, installationIDs)
|
||||
}
|
||||
|
||||
func (c *Client) Enabled() bool {
|
||||
return c.config.RemoteNotificationsEnabled
|
||||
}
|
||||
|
||||
func (c *Client) EnableSending() {
|
||||
c.config.SendEnabled = true
|
||||
}
|
||||
|
@ -1275,6 +1307,48 @@ func (c *Client) handleAllowedKeyList(publicKey *ecdsa.PublicKey, allowedKeyList
|
|||
return ""
|
||||
}
|
||||
|
||||
func (c *Client) MyPushNotificationQueryInfo() ([]*protobuf.PushNotificationQueryInfo, error) {
|
||||
|
||||
// Nothing to do
|
||||
if c.lastPushNotificationRegistration == nil || c.lastPushNotificationRegistration.Unregister {
|
||||
return nil, nil
|
||||
|
||||
}
|
||||
var response []*protobuf.PushNotificationQueryInfo
|
||||
servers, err := c.persistence.GetServers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, server := range servers {
|
||||
// ignore non-registered servers
|
||||
if !server.Registered {
|
||||
continue
|
||||
}
|
||||
// build grant for this specific server
|
||||
grant, err := c.buildGrantSignature(server.PublicKey, c.lastPushNotificationRegistration.AccessToken)
|
||||
if err != nil {
|
||||
c.config.Logger.Error("failed to build grant", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
queryInfo := &protobuf.PushNotificationQueryInfo{
|
||||
InstallationId: c.config.InstallationID,
|
||||
// is this the right key?
|
||||
PublicKey: common.HashPublicKey(&c.config.Identity.PublicKey),
|
||||
Version: c.lastPushNotificationRegistration.Version,
|
||||
Grant: grant,
|
||||
ServerPublicKey: crypto.CompressPubkey(server.PublicKey),
|
||||
}
|
||||
if c.lastPushNotificationRegistration.AllowFromContactsOnly {
|
||||
queryInfo.AllowedKeyList = c.lastPushNotificationRegistration.AllowedKeyList
|
||||
} else {
|
||||
queryInfo.AccessToken = c.lastPushNotificationRegistration.AccessToken
|
||||
}
|
||||
response = append(response, queryInfo)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// queryPushNotificationInfo sends a message to any server who has the given user registered.
|
||||
// it uses an ephemeral key so the identity of the client querying is not disclosed
|
||||
func (c *Client) queryPushNotificationInfo(publicKey *ecdsa.PublicKey) error {
|
||||
|
|
|
@ -226,7 +226,6 @@ func (m *StatusMessage) HandleApplication() error {
|
|||
|
||||
case protobuf.ApplicationMetadataMessage_PAIR_INSTALLATION:
|
||||
return m.unmarshalProtobufData(new(protobuf.PairInstallation))
|
||||
|
||||
case protobuf.ApplicationMetadataMessage_CONTACT_CODE_ADVERTISEMENT:
|
||||
return m.unmarshalProtobufData(new(protobuf.ContactCodeAdvertisement))
|
||||
case protobuf.ApplicationMetadataMessage_PUSH_NOTIFICATION_REQUEST:
|
||||
|
|
Loading…
Reference in New Issue