2023-01-06 12:21:14 +00:00
package protocol
import (
"context"
2023-02-28 12:32:45 +00:00
"errors"
2023-01-06 12:21:14 +00:00
"github.com/golang/protobuf/proto"
"go.uber.org/zap"
"github.com/status-im/status-go/protocol/common"
2023-02-28 12:32:45 +00:00
"github.com/status-im/status-go/protocol/encryption/multidevice"
"github.com/status-im/status-go/protocol/protobuf"
2023-01-06 12:21:14 +00:00
localnotifications "github.com/status-im/status-go/services/local-notifications"
"github.com/status-im/status-go/signal"
)
type RawMessageHandler func ( ctx context . Context , rawMessage common . RawMessage ) ( common . RawMessage , error )
func ( m * Messenger ) HandleSyncRawMessages ( rawMessages [ ] * protobuf . RawMessage ) error {
state := m . buildMessageState ( )
for _ , rawMessage := range rawMessages {
switch rawMessage . GetMessageType ( ) {
case protobuf . ApplicationMetadataMessage_CONTACT_UPDATE :
var message protobuf . ContactUpdate
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
2023-03-28 03:45:54 +00:00
publicKey , err := common . HexToPubkey ( message . PublicKey )
if err != nil {
return err
}
var contact * Contact
if c , ok := state . AllContacts . Load ( message . PublicKey ) ; ok {
contact = c
} else {
c , err := buildContact ( message . PublicKey , publicKey )
if err != nil {
m . logger . Info ( "failed to build contact" , zap . Error ( err ) )
continue
}
contact = c
state . AllContacts . Store ( message . PublicKey , contact )
}
currentMessageState := & CurrentMessageState {
Message : protobuf . ChatMessage {
Clock : message . Clock ,
} ,
MessageID : " " , // make it not empty to bypass this validation: https://github.com/status-im/status-go/blob/7cd7430d3141b08f7c455d7918f4160ea8fd0559/protocol/messenger_handler.go#L325
WhisperTimestamp : message . Clock ,
PublicKey : publicKey ,
Contact : contact ,
}
state . CurrentMessageState = currentMessageState
2023-01-06 12:21:14 +00:00
err = m . HandleContactUpdate ( state , message )
if err != nil {
m . logger . Warn ( "failed to HandleContactUpdate when HandleSyncRawMessages" , zap . Error ( err ) )
continue
}
case protobuf . ApplicationMetadataMessage_SYNC_INSTALLATION_PUBLIC_CHAT :
var message protobuf . SyncInstallationPublicChat
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
addedChat := m . HandleSyncInstallationPublicChat ( state , message )
if addedChat != nil {
_ , err = m . createPublicChat ( addedChat . ID , state . Response )
if err != nil {
m . logger . Error ( "error createPublicChat when HandleSyncRawMessages" , zap . Error ( err ) )
continue
}
}
case protobuf . ApplicationMetadataMessage_SYNC_CHAT_REMOVED :
var message protobuf . SyncChatRemoved
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
err = m . HandleSyncChatRemoved ( state , message )
if err != nil {
m . logger . Error ( "failed to HandleSyncChatRemoved when HandleSyncRawMessages" , zap . Error ( err ) )
continue
}
case protobuf . ApplicationMetadataMessage_SYNC_CHAT_MESSAGES_READ :
var message protobuf . SyncChatMessagesRead
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
err = m . HandleSyncChatMessagesRead ( state , message )
if err != nil {
m . logger . Error ( "failed to HandleSyncChatMessagesRead when HandleSyncRawMessages" , zap . Error ( err ) )
continue
}
case protobuf . ApplicationMetadataMessage_SYNC_CLEAR_HISTORY :
var message protobuf . SyncClearHistory
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
err = m . handleSyncClearHistory ( state , message )
if err != nil {
m . logger . Error ( "failed to handleSyncClearHistory when HandleSyncRawMessages" , zap . Error ( err ) )
continue
}
case protobuf . ApplicationMetadataMessage_SYNC_INSTALLATION_CONTACT :
var message protobuf . SyncInstallationContactV2
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
err = m . HandleSyncInstallationContact ( state , message )
if err != nil {
m . logger . Error ( "failed to HandleSyncInstallationContact when HandleSyncRawMessages" , zap . Error ( err ) )
continue
}
case protobuf . ApplicationMetadataMessage_SYNC_INSTALLATION_COMMUNITY :
var message protobuf . SyncCommunity
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
err = m . handleSyncCommunity ( state , message )
if err != nil {
m . logger . Error ( "failed to handleSyncCommunity when HandleSyncRawMessages" , zap . Error ( err ) )
continue
}
case protobuf . ApplicationMetadataMessage_SYNC_BOOKMARK :
var message protobuf . SyncBookmark
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
err = m . handleSyncBookmark ( state , message )
if err != nil {
m . logger . Error ( "failed to handleSyncBookmark when HandleSyncRawMessages" , zap . Error ( err ) )
continue
}
case protobuf . ApplicationMetadataMessage_SYNC_TRUSTED_USER :
var message protobuf . SyncTrustedUser
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
err = m . handleSyncTrustedUser ( state , message )
if err != nil {
m . logger . Error ( "failed to handleSyncTrustedUser when HandleSyncRawMessages" , zap . Error ( err ) )
continue
}
case protobuf . ApplicationMetadataMessage_SYNC_VERIFICATION_REQUEST :
var message protobuf . SyncVerificationRequest
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
err = m . handleSyncVerificationRequest ( state , message )
if err != nil {
m . logger . Error ( "failed to handleSyncVerificationRequest when HandleSyncRawMessages" , zap . Error ( err ) )
continue
}
case protobuf . ApplicationMetadataMessage_SYNC_SETTING :
var message protobuf . SyncSetting
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
err = m . handleSyncSetting ( state , & message )
if err != nil {
m . logger . Error ( "failed to handleSyncSetting when HandleSyncRawMessages" , zap . Error ( err ) )
continue
}
case protobuf . ApplicationMetadataMessage_SYNC_PROFILE_PICTURE :
var message protobuf . SyncProfilePictures
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
err = m . HandleSyncProfilePictures ( state , message )
if err != nil {
m . logger . Error ( "failed to HandleSyncProfilePictures when HandleSyncRawMessages" , zap . Error ( err ) )
continue
}
case protobuf . ApplicationMetadataMessage_SYNC_CONTACT_REQUEST_DECISION :
var message protobuf . SyncContactRequestDecision
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
err = m . HandleSyncContactRequestDecision ( state , message )
if err != nil {
m . logger . Error ( "failed to HandleSyncContactRequestDecision when HandleSyncRawMessages" , zap . Error ( err ) )
continue
}
2023-05-16 10:48:00 +00:00
case protobuf . ApplicationMetadataMessage_SYNC_ACCOUNT :
var message protobuf . SyncAccount
2023-01-06 12:21:14 +00:00
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
2023-06-28 19:45:36 +00:00
err = m . HandleSyncWatchOnlyAccount ( state , message )
2023-01-06 12:21:14 +00:00
if err != nil {
2023-06-28 19:45:36 +00:00
m . logger . Error ( "failed to HandleSyncWatchOnlyAccount when HandleSyncRawMessages" , zap . Error ( err ) )
2023-01-06 12:21:14 +00:00
continue
}
2023-06-28 19:45:36 +00:00
case protobuf . ApplicationMetadataMessage_SYNC_KEYPAIR :
var message protobuf . SyncKeypair
2023-01-06 12:21:14 +00:00
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
2023-08-09 11:14:17 +00:00
err = m . HandleSyncKeypair ( state , message , true )
2023-01-06 12:21:14 +00:00
if err != nil {
2023-06-28 19:45:36 +00:00
m . logger . Error ( "failed to HandleSyncKeypair when HandleSyncRawMessages" , zap . Error ( err ) )
2023-01-06 12:21:14 +00:00
continue
}
2023-07-16 11:11:48 +00:00
case protobuf . ApplicationMetadataMessage_SYNC_ACCOUNTS_POSITIONS :
var message protobuf . SyncAccountsPositions
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
err = m . HandleSyncAccountsPositions ( state , message )
if err != nil {
m . logger . Error ( "failed to HandleSyncAccountsPositions when HandleSyncRawMessages" , zap . Error ( err ) )
continue
}
2023-05-16 10:48:00 +00:00
case protobuf . ApplicationMetadataMessage_SYNC_SAVED_ADDRESS :
var message protobuf . SyncSavedAddress
2023-02-21 12:35:26 +00:00
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
2023-05-16 10:48:00 +00:00
err = m . handleSyncSavedAddress ( state , message )
2023-02-21 12:35:26 +00:00
if err != nil {
2023-05-16 10:48:00 +00:00
m . logger . Error ( "failed to handleSyncSavedAddress when HandleSyncRawMessages" , zap . Error ( err ) )
2023-04-19 22:59:09 +00:00
continue
}
2023-06-05 11:10:26 +00:00
case protobuf . ApplicationMetadataMessage_SYNC_SOCIAL_LINKS :
var message protobuf . SyncSocialLinks
2023-04-19 22:59:09 +00:00
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
2023-06-05 11:10:26 +00:00
err = m . HandleSyncSocialLinks ( state , message )
2023-04-19 22:59:09 +00:00
if err != nil {
2023-06-05 11:10:26 +00:00
m . logger . Error ( "failed to HandleSyncSocialLinks when HandleSyncRawMessages" , zap . Error ( err ) )
2023-04-26 15:37:18 +00:00
continue
}
case protobuf . ApplicationMetadataMessage_SYNC_ENS_USERNAME_DETAIL :
var message protobuf . SyncEnsUsernameDetail
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
err = m . handleSyncEnsUsernameDetail ( state , message )
if err != nil {
m . logger . Error ( "failed to handleSyncEnsUsernameDetail when HandleSyncRawMessages" , zap . Error ( err ) )
2023-05-12 08:31:34 +00:00
continue
}
case protobuf . ApplicationMetadataMessage_SYNC_DELETE_FOR_ME_MESSAGE :
var message protobuf . DeleteForMeMessage
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
err = m . HandleDeleteForMeMessage ( state , message )
if err != nil {
m . logger . Error ( "failed to HandleDeleteForMeMessage when HandleSyncRawMessages" , zap . Error ( err ) )
2023-02-21 12:35:26 +00:00
continue
}
2023-02-28 12:32:45 +00:00
case protobuf . ApplicationMetadataMessage_PAIR_INSTALLATION :
var message protobuf . PairInstallation
err := proto . Unmarshal ( rawMessage . GetPayload ( ) , & message )
if err != nil {
return err
}
identity := m . myHexIdentity ( )
installations := [ ] * multidevice . Installation {
{
Identity : identity ,
ID : message . InstallationId ,
Version : message . Version ,
Enabled : true ,
Timestamp : int64 ( message . Clock ) ,
InstallationMetadata : & multidevice . InstallationMetadata {
DeviceType : message . DeviceType ,
Name : message . Name ,
} ,
} }
m . handleInstallations ( installations )
// set WhisperTimestamp to pass the validation in HandlePairInstallation
state . CurrentMessageState = & CurrentMessageState { WhisperTimestamp : message . Clock }
err = m . HandlePairInstallation ( state , message )
if err != nil {
return err
}
multidevice := m . encryptor . GetMultiDevice ( )
if multidevice == nil {
return errors . New ( "multidevice is nil" )
}
_ , err = multidevice . AddInstallations ( m . IdentityPublicKeyCompressed ( ) , int64 ( message . GetClock ( ) ) , installations , true )
if err != nil {
return err
}
// if receiver already logged in before local pairing, we need force enable the installation,
// AddInstallations won't make sure enable it, e.g. installation maybe already exist in db but not enabled yet
err = m . EnableInstallation ( message . InstallationId )
if err != nil {
return err
}
2023-01-06 12:21:14 +00:00
}
}
response , err := m . saveDataAndPrepareResponse ( state )
if err != nil {
return err
}
publishMessengerResponse ( response )
return nil
}
// this is a copy implementation of the one in ext/service.go, we should refactor this?
func publishMessengerResponse ( response * MessengerResponse ) {
if ! response . IsEmpty ( ) {
notifications := response . Notifications ( )
// Clear notifications as not used for now
response . ClearNotifications ( )
signal . SendNewMessages ( response )
localnotifications . PushMessages ( notifications )
}
}