github.com/status-im/status-go@v1.1.0/protocol/messenger_handler.go (about)

     1  package protocol
     2  
     3  import (
     4  	"context"
     5  	"crypto/ecdsa"
     6  	"database/sql"
     7  	"encoding/hex"
     8  	"fmt"
     9  	"sync"
    10  	"time"
    11  
    12  	gethcommon "github.com/ethereum/go-ethereum/common"
    13  
    14  	"github.com/status-im/status-go/services/accounts/accountsevent"
    15  	"github.com/status-im/status-go/services/browsers"
    16  	"github.com/status-im/status-go/signal"
    17  
    18  	"github.com/pkg/errors"
    19  	"go.uber.org/zap"
    20  
    21  	"github.com/google/uuid"
    22  
    23  	utils "github.com/status-im/status-go/common"
    24  	"github.com/status-im/status-go/eth-node/crypto"
    25  	"github.com/status-im/status-go/eth-node/types"
    26  	"github.com/status-im/status-go/images"
    27  	"github.com/status-im/status-go/multiaccounts/accounts"
    28  	multiaccountscommon "github.com/status-im/status-go/multiaccounts/common"
    29  	"github.com/status-im/status-go/multiaccounts/settings"
    30  	walletsettings "github.com/status-im/status-go/multiaccounts/settings_wallet"
    31  	"github.com/status-im/status-go/protocol/common"
    32  	"github.com/status-im/status-go/protocol/communities"
    33  	"github.com/status-im/status-go/protocol/encryption/multidevice"
    34  	"github.com/status-im/status-go/protocol/peersyncing"
    35  	"github.com/status-im/status-go/protocol/protobuf"
    36  	"github.com/status-im/status-go/protocol/requests"
    37  	"github.com/status-im/status-go/protocol/transport"
    38  	v1protocol "github.com/status-im/status-go/protocol/v1"
    39  	"github.com/status-im/status-go/protocol/verification"
    40  )
    41  
    42  const (
    43  	transactionRequestDeclinedMessage           = "Transaction request declined"
    44  	requestAddressForTransactionAcceptedMessage = "Request address for transaction accepted"
    45  	requestAddressForTransactionDeclinedMessage = "Request address for transaction declined"
    46  )
    47  
    48  var (
    49  	ErrMessageNotAllowed                      = errors.New("message from a non-contact")
    50  	ErrMessageForWrongChatType                = errors.New("message for the wrong chat type")
    51  	ErrNotWatchOnlyAccount                    = errors.New("an account is not a watch only account")
    52  	ErrWalletAccountNotSupportedForMobileApp  = errors.New("handling account is not supported for mobile app")
    53  	ErrTryingToApplyOldWalletAccountsOrder    = errors.New("trying to apply old wallet accounts order")
    54  	ErrTryingToStoreOldWalletAccount          = errors.New("trying to store an old wallet account")
    55  	ErrTryingToStoreOldKeypair                = errors.New("trying to store an old keypair")
    56  	ErrSomeFieldsMissingForWalletAccount      = errors.New("some fields are missing for wallet account")
    57  	ErrUnknownKeypairForWalletAccount         = errors.New("keypair is not known for the wallet account")
    58  	ErrInvalidCommunityID                     = errors.New("invalid community id")
    59  	ErrTryingToApplyOldTokenPreferences       = errors.New("trying to apply old token preferences")
    60  	ErrTryingToApplyOldCollectiblePreferences = errors.New("trying to apply old collectible preferences")
    61  	ErrOutdatedCommunityRequestToJoin         = errors.New("outdated community request to join response")
    62  )
    63  
    64  // HandleMembershipUpdate updates a Chat instance according to the membership updates.
    65  // It retrieves chat, if exists, and merges membership updates from the message.
    66  // Finally, the Chat is updated with the new group events.
    67  func (m *Messenger) HandleMembershipUpdateMessage(messageState *ReceivedMessageState, rawMembershipUpdate *protobuf.MembershipUpdateMessage, statusMessage *v1protocol.StatusMessage) error {
    68  	chat, _ := messageState.AllChats.Load(rawMembershipUpdate.ChatId)
    69  
    70  	return m.HandleMembershipUpdate(messageState, chat, rawMembershipUpdate, m.systemMessagesTranslations)
    71  }
    72  
    73  func (m *Messenger) HandleMembershipUpdate(messageState *ReceivedMessageState, chat *Chat, rawMembershipUpdate *protobuf.MembershipUpdateMessage, translations *systemMessageTranslationsMap) error {
    74  
    75  	var group *v1protocol.Group
    76  	var err error
    77  
    78  	if rawMembershipUpdate == nil {
    79  		return nil
    80  	}
    81  
    82  	logger := m.logger.With(zap.String("site", "HandleMembershipUpdate"))
    83  
    84  	message, err := v1protocol.MembershipUpdateMessageFromProtobuf(rawMembershipUpdate)
    85  	if err != nil {
    86  		return err
    87  
    88  	}
    89  
    90  	if err := ValidateMembershipUpdateMessage(message, messageState.Timesource.GetCurrentTime()); err != nil {
    91  		logger.Warn("failed to validate message", zap.Error(err))
    92  		return err
    93  	}
    94  
    95  	senderID := messageState.CurrentMessageState.Contact.ID
    96  	allowed, err := m.isMessageAllowedFrom(senderID, chat)
    97  	if err != nil {
    98  		return err
    99  	}
   100  
   101  	if !allowed {
   102  		return ErrMessageNotAllowed
   103  	}
   104  
   105  	//if chat.InvitationAdmin exists means we are waiting for invitation request approvement, and in that case
   106  	//we need to create a new chat instance like we don't have a chat and just use a regular invitation flow
   107  	waitingForApproval := chat != nil && len(chat.InvitationAdmin) > 0
   108  	ourKey := contactIDFromPublicKey(&m.identity.PublicKey)
   109  	isActive := messageState.CurrentMessageState.Contact.added() || messageState.CurrentMessageState.Contact.ID == ourKey || waitingForApproval
   110  	showPushNotification := isActive && messageState.CurrentMessageState.Contact.ID != ourKey
   111  
   112  	// wasUserAdded indicates whether the user has been added to the group with this update
   113  	wasUserAdded := false
   114  	if chat == nil || waitingForApproval {
   115  		if len(message.Events) == 0 {
   116  			return errors.New("can't create new group chat without events")
   117  		}
   118  
   119  		//approve invitations
   120  		if waitingForApproval {
   121  
   122  			groupChatInvitation := &GroupChatInvitation{
   123  				GroupChatInvitation: &protobuf.GroupChatInvitation{
   124  					ChatId: message.ChatID,
   125  				},
   126  				From: types.EncodeHex(crypto.FromECDSAPub(&m.identity.PublicKey)),
   127  			}
   128  
   129  			groupChatInvitation, err = m.persistence.InvitationByID(groupChatInvitation.ID())
   130  			if err != nil && err != common.ErrRecordNotFound {
   131  				return err
   132  			}
   133  			if groupChatInvitation != nil {
   134  				groupChatInvitation.State = protobuf.GroupChatInvitation_APPROVED
   135  
   136  				err := m.persistence.SaveInvitation(groupChatInvitation)
   137  				if err != nil {
   138  					return err
   139  				}
   140  				messageState.GroupChatInvitations[groupChatInvitation.ID()] = groupChatInvitation
   141  			}
   142  		}
   143  
   144  		group, err = v1protocol.NewGroupWithEvents(message.ChatID, message.Events)
   145  		if err != nil {
   146  			return err
   147  		}
   148  
   149  		// A new chat must have contained us at some point
   150  		wasEverMember, err := group.WasEverMember(ourKey)
   151  		if err != nil {
   152  			return err
   153  		}
   154  
   155  		if !wasEverMember {
   156  			return errors.New("can't create a new group chat without us being a member")
   157  		}
   158  
   159  		wasUserAdded = group.IsMember(ourKey)
   160  		newChat := CreateGroupChat(messageState.Timesource)
   161  		// We set group chat inactive and create a notification instead
   162  		// unless is coming from us or a contact or were waiting for approval.
   163  		// Also, as message MEMBER_JOINED may come from member(not creator, not our contact)
   164  		// reach earlier than CHAT_CREATED from creator, we need check if creator is our contact
   165  		newChat.Active = isActive || m.checkIfCreatorIsOurContact(group)
   166  		newChat.ReceivedInvitationAdmin = senderID
   167  		chat = &newChat
   168  
   169  		chat.updateChatFromGroupMembershipChanges(group)
   170  
   171  		if err != nil {
   172  			return errors.Wrap(err, "failed to get group creator")
   173  		}
   174  
   175  		publicKeys, err := group.MemberPublicKeys()
   176  		if err != nil {
   177  			return errors.Wrap(err, "failed to get group members")
   178  		}
   179  		filters, err := m.transport.JoinGroup(publicKeys)
   180  		if err != nil {
   181  			return errors.Wrap(err, "failed to join group")
   182  		}
   183  		ok, err := m.scheduleSyncFilters(filters)
   184  		if err != nil {
   185  			return errors.Wrap(err, "failed to schedule sync filter")
   186  		}
   187  		m.logger.Debug("result of schedule sync filter", zap.Bool("ok", ok))
   188  	} else {
   189  		existingGroup, err := newProtocolGroupFromChat(chat)
   190  		if err != nil {
   191  			return errors.Wrap(err, "failed to create a Group from Chat")
   192  		}
   193  		updateGroup, err := v1protocol.NewGroupWithEvents(message.ChatID, message.Events)
   194  		if err != nil {
   195  			return errors.Wrap(err, "invalid membership update")
   196  		}
   197  		merged := v1protocol.MergeMembershipUpdateEvents(existingGroup.Events(), updateGroup.Events())
   198  		group, err = v1protocol.NewGroupWithEvents(chat.ID, merged)
   199  		if err != nil {
   200  			return errors.Wrap(err, "failed to create a group with new membership updates")
   201  		}
   202  		chat.updateChatFromGroupMembershipChanges(group)
   203  
   204  		// Reactivate deleted group chat on re-invite from contact
   205  		chat.Active = chat.Active || (isActive && group.IsMember(ourKey))
   206  
   207  		wasUserAdded = !existingGroup.IsMember(ourKey) && group.IsMember(ourKey)
   208  
   209  		// Show push notifications when our key is added to members list and chat is Active
   210  		showPushNotification = showPushNotification && wasUserAdded
   211  	}
   212  	maxClockVal := uint64(0)
   213  	for _, event := range group.Events() {
   214  		if event.ClockValue > maxClockVal {
   215  			maxClockVal = event.ClockValue
   216  		}
   217  	}
   218  
   219  	if chat.LastClockValue < maxClockVal {
   220  		chat.LastClockValue = maxClockVal
   221  	}
   222  
   223  	// Only create a message notification when the user is added, not when removed
   224  	if !chat.Active && wasUserAdded {
   225  		chat.Highlight = true
   226  		m.createMessageNotification(chat, messageState, chat.LastMessage)
   227  	}
   228  
   229  	profilePicturesVisibility, err := m.settings.GetProfilePicturesVisibility()
   230  	if err != nil {
   231  		return errors.Wrap(err, "failed to get profilePicturesVisibility setting")
   232  	}
   233  
   234  	if showPushNotification {
   235  		// chat is highlighted for new group invites or group re-invites
   236  		chat.Highlight = true
   237  		messageState.Response.AddNotification(NewPrivateGroupInviteNotification(chat.ID, chat, messageState.CurrentMessageState.Contact, profilePicturesVisibility))
   238  	}
   239  
   240  	systemMessages := buildSystemMessages(message.Events, translations)
   241  
   242  	for _, message := range systemMessages {
   243  		messageID := message.ID
   244  		exists, err := m.messageExists(messageID, messageState.ExistingMessagesMap)
   245  		if err != nil {
   246  			m.logger.Warn("failed to check message exists", zap.Error(err))
   247  		}
   248  		if exists {
   249  			continue
   250  		}
   251  		messageState.Response.AddMessage(message)
   252  	}
   253  
   254  	messageState.Response.AddChat(chat)
   255  	// Store in chats map as it might be a new one
   256  	messageState.AllChats.Store(chat.ID, chat)
   257  
   258  	// explicit join has been removed, mimic auto-join for backward compatibility
   259  	// no all cases are covered, e.g. if added to a group by non-contact
   260  	autoJoin := chat.Active && wasUserAdded
   261  	if autoJoin || waitingForApproval {
   262  		_, err = m.ConfirmJoiningGroup(context.Background(), chat.ID)
   263  		if err != nil {
   264  			return err
   265  		}
   266  	}
   267  
   268  	if message.Message != nil {
   269  		return m.HandleChatMessage(messageState, message.Message, nil, false)
   270  	} else if message.EmojiReaction != nil {
   271  		return m.HandleEmojiReaction(messageState, message.EmojiReaction, nil)
   272  	}
   273  
   274  	return nil
   275  }
   276  
   277  func (m *Messenger) checkIfCreatorIsOurContact(group *v1protocol.Group) bool {
   278  	creator, err := group.Creator()
   279  	if err == nil {
   280  		contact, _ := m.allContacts.Load(creator)
   281  		return contact != nil && contact.mutual()
   282  	}
   283  	m.logger.Warn("failed to get creator from group", zap.String("group name", group.Name()), zap.String("group chat id", group.ChatID()), zap.Error(err))
   284  	return false
   285  }
   286  
   287  func (m *Messenger) createMessageNotification(chat *Chat, messageState *ReceivedMessageState, message *common.Message) {
   288  
   289  	var notificationType ActivityCenterType
   290  	if chat.OneToOne() {
   291  		notificationType = ActivityCenterNotificationTypeNewOneToOne
   292  	} else {
   293  		notificationType = ActivityCenterNotificationTypeNewPrivateGroupChat
   294  	}
   295  	notification := &ActivityCenterNotification{
   296  		ID:          types.FromHex(chat.ID),
   297  		Name:        chat.Name,
   298  		Message:     message,
   299  		Type:        notificationType,
   300  		Author:      messageState.CurrentMessageState.Contact.ID,
   301  		Timestamp:   messageState.CurrentMessageState.WhisperTimestamp,
   302  		ChatID:      chat.ID,
   303  		CommunityID: chat.CommunityID,
   304  		UpdatedAt:   m.GetCurrentTimeInMillis(),
   305  	}
   306  
   307  	err := m.addActivityCenterNotification(messageState.Response, notification, nil)
   308  	if err != nil {
   309  		m.logger.Warn("failed to create activity center notification", zap.Error(err))
   310  	}
   311  }
   312  
   313  func (m *Messenger) PendingNotificationContactRequest(contactID string) (*ActivityCenterNotification, error) {
   314  	return m.persistence.ActiveContactRequestNotification(contactID)
   315  }
   316  
   317  func (m *Messenger) createContactRequestForContactUpdate(contact *Contact, messageState *ReceivedMessageState) (*common.Message, error) {
   318  
   319  	contactRequest, err := m.generateContactRequest(
   320  		contact.ContactRequestRemoteClock,
   321  		messageState.CurrentMessageState.WhisperTimestamp,
   322  		contact,
   323  		defaultContactRequestText(),
   324  		false,
   325  	)
   326  	if err != nil {
   327  		return nil, err
   328  	}
   329  
   330  	contactRequest.ID = defaultContactRequestID(contact.ID)
   331  
   332  	// save this message
   333  	messageState.Response.AddMessage(contactRequest)
   334  	err = m.persistence.SaveMessages([]*common.Message{contactRequest})
   335  
   336  	if err != nil {
   337  		return nil, err
   338  	}
   339  
   340  	return contactRequest, nil
   341  }
   342  
   343  func (m *Messenger) createIncomingContactRequestNotification(contact *Contact, messageState *ReceivedMessageState, contactRequest *common.Message, createNewNotification bool) error {
   344  	if contactRequest.ContactRequestState == common.ContactRequestStateAccepted {
   345  		// Pull one from the db if there
   346  		notification, err := m.persistence.GetActivityCenterNotificationByID(types.FromHex(contactRequest.ID))
   347  		if err != nil {
   348  			return err
   349  		}
   350  
   351  		if notification != nil {
   352  			notification.Name = contact.PrimaryName()
   353  			notification.Message = contactRequest
   354  			notification.Read = true
   355  			notification.Accepted = true
   356  			notification.Dismissed = false
   357  			notification.UpdatedAt = m.GetCurrentTimeInMillis()
   358  			_, err = m.persistence.SaveActivityCenterNotification(notification, true)
   359  			if err != nil {
   360  				return err
   361  			}
   362  			messageState.Response.AddMessage(contactRequest)
   363  			messageState.Response.AddActivityCenterNotification(notification)
   364  		}
   365  		return nil
   366  	}
   367  
   368  	if !createNewNotification {
   369  		return nil
   370  	}
   371  
   372  	notification := &ActivityCenterNotification{
   373  		ID:        types.FromHex(contactRequest.ID),
   374  		Name:      contact.PrimaryName(),
   375  		Message:   contactRequest,
   376  		Type:      ActivityCenterNotificationTypeContactRequest,
   377  		Author:    contactRequest.From,
   378  		Timestamp: contactRequest.WhisperTimestamp,
   379  		ChatID:    contact.ID,
   380  		Read:      contactRequest.ContactRequestState == common.ContactRequestStateAccepted || contactRequest.ContactRequestState == common.ContactRequestStateDismissed,
   381  		Accepted:  contactRequest.ContactRequestState == common.ContactRequestStateAccepted,
   382  		Dismissed: contactRequest.ContactRequestState == common.ContactRequestStateDismissed,
   383  		UpdatedAt: m.GetCurrentTimeInMillis(),
   384  	}
   385  
   386  	return m.addActivityCenterNotification(messageState.Response, notification, nil)
   387  }
   388  
   389  func (m *Messenger) handleCommandMessage(state *ReceivedMessageState, message *common.Message) error {
   390  	message.ID = state.CurrentMessageState.MessageID
   391  	message.From = state.CurrentMessageState.Contact.ID
   392  	message.Alias = state.CurrentMessageState.Contact.Alias
   393  	message.SigPubKey = state.CurrentMessageState.PublicKey
   394  	message.Identicon = state.CurrentMessageState.Contact.Identicon
   395  	message.WhisperTimestamp = state.CurrentMessageState.WhisperTimestamp
   396  
   397  	if err := message.PrepareContent(common.PubkeyToHex(&m.identity.PublicKey)); err != nil {
   398  		return fmt.Errorf("failed to prepare content: %v", err)
   399  	}
   400  
   401  	// Get Application layer messageType from commandState
   402  	// Currently this is not really used in `matchChatEntity`, but I did want to pass UNKNOWN there.
   403  	var messageType protobuf.ApplicationMetadataMessage_Type
   404  	switch message.CommandParameters.CommandState {
   405  	case common.CommandStateRequestAddressForTransaction:
   406  		messageType = protobuf.ApplicationMetadataMessage_REQUEST_ADDRESS_FOR_TRANSACTION
   407  	case common.CommandStateRequestAddressForTransactionAccepted:
   408  		messageType = protobuf.ApplicationMetadataMessage_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION
   409  	case common.CommandStateRequestAddressForTransactionDeclined:
   410  		messageType = protobuf.ApplicationMetadataMessage_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION
   411  	case common.CommandStateRequestTransaction:
   412  		messageType = protobuf.ApplicationMetadataMessage_REQUEST_TRANSACTION
   413  	case common.CommandStateRequestTransactionDeclined:
   414  		messageType = protobuf.ApplicationMetadataMessage_DECLINE_REQUEST_TRANSACTION
   415  	default:
   416  		messageType = protobuf.ApplicationMetadataMessage_UNKNOWN
   417  	}
   418  
   419  	chat, err := m.matchChatEntity(message, messageType)
   420  	if err != nil {
   421  		return err
   422  	}
   423  
   424  	allowed, err := m.isMessageAllowedFrom(state.CurrentMessageState.Contact.ID, chat)
   425  	if err != nil {
   426  		return err
   427  	}
   428  
   429  	if !allowed {
   430  		return ErrMessageNotAllowed
   431  	}
   432  
   433  	// If deleted-at is greater, ignore message
   434  	if chat.DeletedAtClockValue >= message.Clock {
   435  		return nil
   436  	}
   437  
   438  	// Set the LocalChatID for the message
   439  	message.LocalChatID = chat.ID
   440  
   441  	if c, ok := state.AllChats.Load(chat.ID); ok {
   442  		chat = c
   443  	}
   444  
   445  	// Set the LocalChatID for the message
   446  	message.LocalChatID = chat.ID
   447  
   448  	// Increase unviewed count
   449  	if !common.IsPubKeyEqual(message.SigPubKey, &m.identity.PublicKey) {
   450  		m.updateUnviewedCounts(chat, message)
   451  		message.OutgoingStatus = ""
   452  	} else {
   453  		// Our own message, mark as sent
   454  		message.OutgoingStatus = common.OutgoingStatusSent
   455  	}
   456  
   457  	err = chat.UpdateFromMessage(message, state.Timesource)
   458  	if err != nil {
   459  		return err
   460  	}
   461  
   462  	if !chat.Active {
   463  		m.createMessageNotification(chat, state, chat.LastMessage)
   464  	}
   465  
   466  	// Add to response
   467  	state.Response.AddChat(chat)
   468  	if message != nil {
   469  		message.New = true
   470  		state.Response.AddMessage(message)
   471  	}
   472  
   473  	// Set in the modified maps chat
   474  	state.AllChats.Store(chat.ID, chat)
   475  
   476  	return nil
   477  }
   478  
   479  func (m *Messenger) syncContactRequestForInstallationContact(contact *Contact, state *ReceivedMessageState, chat *Chat, outgoing bool) error {
   480  
   481  	if chat == nil {
   482  		return fmt.Errorf("no chat restored during the contact synchronisation, contact.ID = %s", contact.ID)
   483  	}
   484  
   485  	contactRequestID, err := m.persistence.LatestPendingContactRequestIDForContact(contact.ID)
   486  	if err != nil {
   487  		return err
   488  	}
   489  
   490  	if contactRequestID != "" {
   491  		m.logger.Warn("syncContactRequestForInstallationContact: skipping as contact request found", zap.String("contactRequestID", contactRequestID))
   492  		return nil
   493  	}
   494  
   495  	clock, timestamp := chat.NextClockAndTimestamp(m.transport)
   496  	contactRequest, err := m.generateContactRequest(clock, timestamp, contact, defaultContactRequestText(), outgoing)
   497  	if err != nil {
   498  		return err
   499  	}
   500  
   501  	contactRequest.ID = defaultContactRequestID(contact.ID)
   502  
   503  	state.Response.AddMessage(contactRequest)
   504  	err = m.persistence.SaveMessages([]*common.Message{contactRequest})
   505  	if err != nil {
   506  		return err
   507  	}
   508  
   509  	if outgoing {
   510  		notification := m.generateOutgoingContactRequestNotification(contact, contactRequest)
   511  		err = m.addActivityCenterNotification(state.Response, notification, nil)
   512  		if err != nil {
   513  			return err
   514  		}
   515  	} else {
   516  		err = m.createIncomingContactRequestNotification(contact, state, contactRequest, true)
   517  		if err != nil {
   518  			return err
   519  		}
   520  	}
   521  
   522  	return nil
   523  }
   524  
   525  func (m *Messenger) HandleSyncInstallationAccount(state *ReceivedMessageState, message *protobuf.SyncInstallationAccount, statusMessage *v1protocol.StatusMessage) error {
   526  	// Noop
   527  	return nil
   528  }
   529  
   530  func (m *Messenger) handleSyncChats(messageState *ReceivedMessageState, chats []*protobuf.SyncChat) error {
   531  	for _, syncChat := range chats {
   532  		oldChat, ok := m.allChats.Load(syncChat.Id)
   533  		clock := int64(syncChat.Clock)
   534  		if ok && oldChat.Timestamp > clock {
   535  			// We already know this chat and its timestamp is newer than the syncChat
   536  			continue
   537  		}
   538  		chat := &Chat{
   539  			ID:                       syncChat.Id,
   540  			Name:                     syncChat.Name,
   541  			Timestamp:                clock,
   542  			ReadMessagesAtClockValue: 0,
   543  			Active:                   syncChat.Active,
   544  			Muted:                    syncChat.Muted,
   545  			Joined:                   clock,
   546  			ChatType:                 ChatType(syncChat.ChatType),
   547  			Highlight:                false,
   548  		}
   549  		if chat.PrivateGroupChat() {
   550  			chat.MembershipUpdates = make([]v1protocol.MembershipUpdateEvent, len(syncChat.MembershipUpdateEvents))
   551  			for i, membershipUpdate := range syncChat.MembershipUpdateEvents {
   552  				chat.MembershipUpdates[i] = v1protocol.MembershipUpdateEvent{
   553  					ClockValue: membershipUpdate.Clock,
   554  					Type:       protobuf.MembershipUpdateEvent_EventType(membershipUpdate.Type),
   555  					Members:    membershipUpdate.Members,
   556  					Name:       membershipUpdate.Name,
   557  					Signature:  membershipUpdate.Signature,
   558  					ChatID:     membershipUpdate.ChatId,
   559  					From:       membershipUpdate.From,
   560  					RawPayload: membershipUpdate.RawPayload,
   561  					Color:      membershipUpdate.Color,
   562  					Image:      membershipUpdate.Image,
   563  				}
   564  			}
   565  			group, err := newProtocolGroupFromChat(chat)
   566  			if err != nil {
   567  				return err
   568  			}
   569  			chat.updateChatFromGroupMembershipChanges(group)
   570  		}
   571  
   572  		err := m.saveChat(chat)
   573  		if err != nil {
   574  			return err
   575  		}
   576  		messageState.Response.AddChat(chat)
   577  	}
   578  
   579  	return nil
   580  }
   581  
   582  func (m *Messenger) HandleSyncInstallationContactV2(state *ReceivedMessageState, message *protobuf.SyncInstallationContactV2, statusMessage *v1protocol.StatusMessage) error {
   583  	// Ignore own contact installation
   584  
   585  	if message.Id == m.myHexIdentity() {
   586  		m.logger.Warn("HandleSyncInstallationContactV2: skipping own contact")
   587  		return nil
   588  	}
   589  
   590  	removed := message.Removed && !message.Blocked
   591  	chat, ok := state.AllChats.Load(message.Id)
   592  	if !ok && (message.Added || message.HasAddedUs || message.Muted) && !removed {
   593  		pubKey, err := common.HexToPubkey(message.Id)
   594  		if err != nil {
   595  			return err
   596  		}
   597  
   598  		chat = OneToOneFromPublicKey(pubKey, state.Timesource)
   599  		// We don't want to show the chat to the user
   600  		chat.Active = false
   601  	}
   602  
   603  	contact, contactFound := state.AllContacts.Load(message.Id)
   604  	if !contactFound {
   605  		if message.Removed && !message.Blocked {
   606  			// Nothing to do in case if contact doesn't exist
   607  			return nil
   608  		}
   609  
   610  		var err error
   611  		contact, err = buildContactFromPkString(message.Id)
   612  		if err != nil {
   613  			return err
   614  		}
   615  	}
   616  
   617  	if message.ContactRequestRemoteClock != 0 || message.ContactRequestLocalClock != 0 {
   618  		// Some local action about contact requests were performed,
   619  		// process them
   620  		contact.ProcessSyncContactRequestState(
   621  			ContactRequestState(message.ContactRequestRemoteState),
   622  			uint64(message.ContactRequestRemoteClock),
   623  			ContactRequestState(message.ContactRequestLocalState),
   624  			uint64(message.ContactRequestLocalClock))
   625  		state.ModifiedContacts.Store(contact.ID, true)
   626  		state.AllContacts.Store(contact.ID, contact)
   627  
   628  		err := m.syncContactRequestForInstallationContact(contact, state, chat, contact.ContactRequestLocalState == ContactRequestStateSent)
   629  		if err != nil {
   630  			return err
   631  		}
   632  	} else if message.Added || message.HasAddedUs {
   633  		// NOTE(cammellos): this is for handling backward compatibility, old clients
   634  		// won't propagate ContactRequestRemoteClock or ContactRequestLocalClock
   635  
   636  		if message.Added && contact.LastUpdatedLocally < message.LastUpdatedLocally {
   637  			contact.ContactRequestSent(message.LastUpdatedLocally)
   638  
   639  			err := m.syncContactRequestForInstallationContact(contact, state, chat, true)
   640  			if err != nil {
   641  				return err
   642  			}
   643  		}
   644  
   645  		if message.HasAddedUs && contact.LastUpdated < message.LastUpdated {
   646  			contact.ContactRequestReceived(message.LastUpdated)
   647  
   648  			err := m.syncContactRequestForInstallationContact(contact, state, chat, false)
   649  			if err != nil {
   650  				return err
   651  			}
   652  		}
   653  
   654  		if message.Removed && contact.LastUpdatedLocally < message.LastUpdatedLocally {
   655  			err := m.removeContact(context.Background(), state.Response, contact.ID, false)
   656  			if err != nil {
   657  				return err
   658  			}
   659  		}
   660  	}
   661  
   662  	// Sync last updated field
   663  	// We don't set `LastUpdated`, since that would cause some issues
   664  	// as `LastUpdated` tracks both display name & picture.
   665  	// The case where it would break is as follow:
   666  	// 1) User A pairs A1 with device A2.
   667  	// 2) User B publishes display name and picture with LastUpdated = 3.
   668  	// 3) Device A1 receives message from step 2.
   669  	// 4) Device A1 syncs with A2 (which has not received message from step 3).
   670  	// 5) Device A2 saves Display name and sets LastUpdated = 3,
   671  	//    note that picture has not been set as it's not synced.
   672  	// 6) Device A2 receives the message from 2. because LastUpdated is 3
   673  	//    it will be discarded, A2 will not have B's picture.
   674  	// The correct solution is to either sync profile image (expensive)
   675  	// or split the clock for image/display name, so they can be synced
   676  	// independently.
   677  	if !contactFound || (contact.LastUpdated < message.LastUpdated) {
   678  		if message.DisplayName != "" {
   679  			contact.DisplayName = message.DisplayName
   680  		}
   681  		contact.CustomizationColor = multiaccountscommon.IDToColorFallbackToBlue(message.CustomizationColor)
   682  		state.ModifiedContacts.Store(contact.ID, true)
   683  		state.AllContacts.Store(contact.ID, contact)
   684  	}
   685  
   686  	if contact.LastUpdatedLocally < message.LastUpdatedLocally {
   687  		// NOTE(cammellos): probably is cleaner to pass a flag
   688  		// to method to tell them not to sync, or factor out in different
   689  		// methods
   690  		contact.IsSyncing = true
   691  		defer func() {
   692  			contact.IsSyncing = false
   693  		}()
   694  
   695  		if message.EnsName != "" && contact.EnsName != message.EnsName {
   696  			contact.EnsName = message.EnsName
   697  			publicKey, err := contact.PublicKey()
   698  			if err != nil {
   699  				return err
   700  			}
   701  
   702  			err = m.ENSVerified(common.PubkeyToHex(publicKey), message.EnsName)
   703  			if err != nil {
   704  				contact.ENSVerified = false
   705  			}
   706  			contact.ENSVerified = true
   707  		}
   708  		contact.CustomizationColor = multiaccountscommon.IDToColorFallbackToBlue(message.CustomizationColor)
   709  		contact.LastUpdatedLocally = message.LastUpdatedLocally
   710  		contact.LocalNickname = message.LocalNickname
   711  		contact.TrustStatus = verification.TrustStatus(message.TrustStatus)
   712  		contact.VerificationStatus = VerificationStatus(message.VerificationStatus)
   713  
   714  		_, err := m.verificationDatabase.UpsertTrustStatus(contact.ID, contact.TrustStatus, message.LastUpdatedLocally)
   715  		if err != nil {
   716  			return err
   717  		}
   718  
   719  		if message.Blocked != contact.Blocked {
   720  			if message.Blocked {
   721  				state.AllContacts.Store(contact.ID, contact)
   722  				response, err := m.BlockContact(context.TODO(), contact.ID, true)
   723  				if err != nil {
   724  					return err
   725  				}
   726  				err = state.Response.Merge(response)
   727  				if err != nil {
   728  					return err
   729  				}
   730  			} else {
   731  				contact.Unblock(message.LastUpdatedLocally)
   732  			}
   733  		}
   734  		if chat != nil && message.Muted != chat.Muted {
   735  			if message.Muted {
   736  				_, err := m.muteChat(chat, contact, time.Time{})
   737  				if err != nil {
   738  					return err
   739  				}
   740  			} else {
   741  				err := m.unmuteChat(chat, contact)
   742  				if err != nil {
   743  					return err
   744  				}
   745  			}
   746  
   747  			state.Response.AddChat(chat)
   748  		}
   749  
   750  		state.ModifiedContacts.Store(contact.ID, true)
   751  		state.AllContacts.Store(contact.ID, contact)
   752  	}
   753  
   754  	if chat != nil {
   755  		state.AllChats.Store(chat.ID, chat)
   756  	}
   757  
   758  	return nil
   759  }
   760  
   761  func (m *Messenger) HandleSyncProfilePictures(state *ReceivedMessageState, message *protobuf.SyncProfilePictures, statusMessage *v1protocol.StatusMessage) error {
   762  	dbImages, err := m.multiAccounts.GetIdentityImages(message.KeyUid)
   763  	if err != nil {
   764  		return err
   765  	}
   766  	dbImageMap := make(map[string]*images.IdentityImage)
   767  	for _, img := range dbImages {
   768  		dbImageMap[img.Name] = img
   769  	}
   770  	idImages := make([]images.IdentityImage, len(message.Pictures))
   771  	i := 0
   772  	for _, message := range message.Pictures {
   773  		dbImg := dbImageMap[message.Name]
   774  		if dbImg != nil && message.Clock <= dbImg.Clock {
   775  			continue
   776  		}
   777  		image := images.IdentityImage{
   778  			Name:         message.Name,
   779  			Payload:      message.Payload,
   780  			Width:        int(message.Width),
   781  			Height:       int(message.Height),
   782  			FileSize:     int(message.FileSize),
   783  			ResizeTarget: int(message.ResizeTarget),
   784  			Clock:        message.Clock,
   785  		}
   786  		idImages[i] = image
   787  		i++
   788  	}
   789  
   790  	if i == 0 {
   791  		return nil
   792  	}
   793  
   794  	err = m.multiAccounts.StoreIdentityImages(message.KeyUid, idImages[:i], false)
   795  	if err == nil {
   796  		state.Response.IdentityImages = idImages[:i]
   797  	}
   798  	return err
   799  }
   800  
   801  func (m *Messenger) HandleSyncChat(state *ReceivedMessageState, message *protobuf.SyncChat, statusMessage *v1protocol.StatusMessage) error {
   802  	chatID := message.Id
   803  	existingChat, ok := state.AllChats.Load(chatID)
   804  	if ok && (existingChat.Active || uint32(message.GetClock()/1000) < existingChat.SyncedTo) {
   805  		return nil
   806  	}
   807  
   808  	chat := existingChat
   809  	if !ok {
   810  		chats := make([]*protobuf.SyncChat, 1)
   811  		chats[0] = message
   812  		return m.handleSyncChats(state, chats)
   813  	}
   814  	existingChat.Joined = int64(message.Clock)
   815  	state.AllChats.Store(chat.ID, chat)
   816  
   817  	state.Response.AddChat(chat)
   818  
   819  	return nil
   820  }
   821  
   822  func (m *Messenger) HandleSyncChatRemoved(state *ReceivedMessageState, message *protobuf.SyncChatRemoved, statusMessage *v1protocol.StatusMessage) error {
   823  	chat, ok := m.allChats.Load(message.Id)
   824  	if !ok {
   825  		return ErrChatNotFound
   826  	}
   827  
   828  	if chat.Joined > int64(message.Clock) {
   829  		return nil
   830  	}
   831  
   832  	if chat.DeletedAtClockValue > message.Clock {
   833  		return nil
   834  	}
   835  
   836  	if chat.PrivateGroupChat() {
   837  		_, err := m.leaveGroupChat(context.Background(), state.Response, message.Id, true, false)
   838  		if err != nil {
   839  			return err
   840  		}
   841  	}
   842  
   843  	response, err := m.deactivateChat(message.Id, message.Clock, false, true)
   844  	if err != nil {
   845  		return err
   846  	}
   847  
   848  	return state.Response.Merge(response)
   849  }
   850  
   851  func (m *Messenger) HandleSyncChatMessagesRead(state *ReceivedMessageState, message *protobuf.SyncChatMessagesRead, statusMessage *v1protocol.StatusMessage) error {
   852  	chat, ok := m.allChats.Load(message.Id)
   853  	if !ok {
   854  		return ErrChatNotFound
   855  	}
   856  
   857  	if chat.ReadMessagesAtClockValue > message.Clock {
   858  		return nil
   859  	}
   860  
   861  	err := m.markAllRead(message.Id, message.Clock, false)
   862  	if err != nil {
   863  		return err
   864  	}
   865  
   866  	state.Response.AddChat(chat)
   867  	return nil
   868  }
   869  
   870  func (m *Messenger) handlePinMessage(pinner *Contact, whisperTimestamp uint64, response *MessengerResponse, message *protobuf.PinMessage, forceSeen bool) error {
   871  	logger := m.logger.With(zap.String("site", "HandlePinMessage"))
   872  
   873  	logger.Info("Handling pin message")
   874  
   875  	publicKey, err := pinner.PublicKey()
   876  	if err != nil {
   877  		return err
   878  	}
   879  
   880  	pinMessage := &common.PinMessage{
   881  		PinMessage: message,
   882  		// MessageID:        message.MessageId,
   883  		WhisperTimestamp: whisperTimestamp,
   884  		From:             pinner.ID,
   885  		SigPubKey:        publicKey,
   886  		Identicon:        pinner.Identicon,
   887  		Alias:            pinner.Alias,
   888  	}
   889  
   890  	chat, err := m.matchChatEntity(pinMessage, protobuf.ApplicationMetadataMessage_PIN_MESSAGE)
   891  	if err != nil {
   892  		return err // matchChatEntity returns a descriptive error message
   893  	}
   894  
   895  	pinMessage.ID, err = generatePinMessageID(&m.identity.PublicKey, pinMessage, chat)
   896  	if err != nil {
   897  		return err
   898  	}
   899  
   900  	// If deleted-at is greater, ignore message
   901  	if chat.DeletedAtClockValue >= pinMessage.Clock {
   902  		return nil
   903  	}
   904  
   905  	if c, ok := m.allChats.Load(chat.ID); ok {
   906  		chat = c
   907  	}
   908  
   909  	// Set the LocalChatID for the message
   910  	pinMessage.LocalChatID = chat.ID
   911  
   912  	inserted, err := m.persistence.SavePinMessage(pinMessage)
   913  	if err != nil {
   914  		return err
   915  	}
   916  
   917  	// Nothing to do, returning
   918  	if !inserted {
   919  		m.logger.Info("pin message already processed")
   920  		return nil
   921  	}
   922  
   923  	if message.Pinned {
   924  		id, err := generatePinMessageNotificationID(&m.identity.PublicKey, pinMessage, chat)
   925  		if err != nil {
   926  			return err
   927  		}
   928  		systemMessage := &common.Message{
   929  			ChatMessage: &protobuf.ChatMessage{
   930  				Clock:       message.Clock,
   931  				Timestamp:   whisperTimestamp,
   932  				ChatId:      chat.ID,
   933  				MessageType: message.MessageType,
   934  				ResponseTo:  message.MessageId,
   935  				ContentType: protobuf.ChatMessage_SYSTEM_MESSAGE_PINNED_MESSAGE,
   936  			},
   937  			WhisperTimestamp: whisperTimestamp,
   938  			ID:               id,
   939  			LocalChatID:      chat.ID,
   940  			From:             pinner.ID,
   941  		}
   942  
   943  		if forceSeen {
   944  			systemMessage.Seen = true
   945  		}
   946  
   947  		response.AddMessage(systemMessage)
   948  		chat.UnviewedMessagesCount++
   949  	}
   950  
   951  	if chat.LastClockValue < message.Clock {
   952  		chat.LastClockValue = message.Clock
   953  	}
   954  
   955  	response.AddPinMessage(pinMessage)
   956  
   957  	// Set in the modified maps chat
   958  	response.AddChat(chat)
   959  	m.allChats.Store(chat.ID, chat)
   960  	return nil
   961  }
   962  
   963  func (m *Messenger) HandlePinMessage(state *ReceivedMessageState, message *protobuf.PinMessage, statusMessage *v1protocol.StatusMessage, fromArchive bool) error {
   964  	return m.handlePinMessage(state.CurrentMessageState.Contact, state.CurrentMessageState.WhisperTimestamp, state.Response, message, fromArchive)
   965  }
   966  
   967  func (m *Messenger) handleAcceptContactRequest(
   968  	response *MessengerResponse,
   969  	contact *Contact,
   970  	originalRequest *common.Message,
   971  	clock uint64) (ContactRequestProcessingResponse, error) {
   972  
   973  	m.logger.Debug("received contact request", zap.Uint64("clock-sent", clock), zap.Uint64("current-clock", contact.ContactRequestRemoteClock), zap.Uint64("current-state", uint64(contact.ContactRequestRemoteState)))
   974  	if contact.ContactRequestRemoteClock > clock {
   975  		m.logger.Debug("not handling accept since clock lower")
   976  		return ContactRequestProcessingResponse{}, nil
   977  	}
   978  
   979  	// The contact request accepted wasn't found, a reason for this might
   980  	// be that we sent a legacy contact request/contact-update, or another
   981  	// device has sent it, and we haven't synchronized it
   982  	if originalRequest == nil {
   983  		return contact.ContactRequestAccepted(clock), nil
   984  	}
   985  
   986  	if originalRequest.LocalChatID != contact.ID {
   987  		return ContactRequestProcessingResponse{}, errors.New("can't accept contact request not sent to user")
   988  	}
   989  
   990  	contact.ContactRequestAccepted(clock)
   991  
   992  	originalRequest.ContactRequestState = common.ContactRequestStateAccepted
   993  
   994  	err := m.persistence.SetContactRequestState(originalRequest.ID, originalRequest.ContactRequestState)
   995  	if err != nil {
   996  		return ContactRequestProcessingResponse{}, err
   997  	}
   998  
   999  	response.AddMessage(originalRequest)
  1000  	return ContactRequestProcessingResponse{}, nil
  1001  }
  1002  
  1003  func (m *Messenger) handleAcceptContactRequestMessage(state *ReceivedMessageState, clock uint64, contactRequestID string, isOutgoing bool) error {
  1004  	request, err := m.persistence.MessageByID(contactRequestID)
  1005  	if err != nil && err != common.ErrRecordNotFound {
  1006  		return err
  1007  	}
  1008  
  1009  	// We still want to handle acceptance of the CR even it was already accepted
  1010  	previouslyAccepted := request != nil && request.ContactRequestState == common.ContactRequestStateAccepted
  1011  
  1012  	contact := state.CurrentMessageState.Contact
  1013  
  1014  	// The request message will be added to the response here
  1015  	processingResponse, err := m.handleAcceptContactRequest(state.Response, contact, request, clock)
  1016  	if err != nil {
  1017  		return err
  1018  	}
  1019  
  1020  	// If the state has changed from non-mutual contact, to mutual contact
  1021  	// we want to notify the user
  1022  	if contact.mutual() {
  1023  		// We set the chat as active, this is currently the expected behavior
  1024  		// for mobile, it might change as we implement further the activity
  1025  		// center
  1026  		chat, _, err := m.getOneToOneAndNextClock(contact)
  1027  		if err != nil {
  1028  			return err
  1029  		}
  1030  
  1031  		if chat.LastClockValue < clock {
  1032  			chat.LastClockValue = clock
  1033  		}
  1034  
  1035  		// NOTE(cammellos): This will re-enable the chat if it was deleted, and only
  1036  		// after we became contact, currently seems safe, but that needs
  1037  		// discussing with UX.
  1038  		if chat.DeletedAtClockValue < clock {
  1039  			chat.Active = true
  1040  		}
  1041  
  1042  		// Add mutual state update message for incoming contact request
  1043  		if !previouslyAccepted {
  1044  			clock, timestamp := chat.NextClockAndTimestamp(m.transport)
  1045  
  1046  			updateMessage, err := m.prepareMutualStateUpdateMessage(contact.ID, MutualStateUpdateTypeAdded, clock, timestamp, false)
  1047  			if err != nil {
  1048  				return err
  1049  			}
  1050  
  1051  			err = m.prepareMessage(updateMessage, m.httpServer)
  1052  			if err != nil {
  1053  				return err
  1054  			}
  1055  			err = m.persistence.SaveMessages([]*common.Message{updateMessage})
  1056  			if err != nil {
  1057  				return err
  1058  			}
  1059  			state.Response.AddMessage(updateMessage)
  1060  
  1061  			err = chat.UpdateFromMessage(updateMessage, m.getTimesource())
  1062  			if err != nil {
  1063  				return err
  1064  			}
  1065  			chat.UnviewedMessagesCount++
  1066  
  1067  			// Dispatch profile message to add a contact to the encrypted profile part
  1068  			err = m.DispatchProfileShowcase()
  1069  			if err != nil {
  1070  				return err
  1071  			}
  1072  		}
  1073  
  1074  		state.Response.AddChat(chat)
  1075  		state.AllChats.Store(chat.ID, chat)
  1076  	}
  1077  
  1078  	if request != nil {
  1079  		if isOutgoing {
  1080  			notification := m.generateOutgoingContactRequestNotification(contact, request)
  1081  			err = m.addActivityCenterNotification(state.Response, notification, nil)
  1082  			if err != nil {
  1083  				return err
  1084  			}
  1085  		} else {
  1086  			err = m.createIncomingContactRequestNotification(contact, state, request, processingResponse.newContactRequestReceived)
  1087  			if err != nil {
  1088  				return err
  1089  			}
  1090  
  1091  			// With devices 1 and 2 paired, and userA logged in on both, while userB is on device 3:
  1092  			// When userA on device 1 sends a contact request to userB, userB accepts it on device 3.
  1093  			// The confirmation is sent to devices 1 and 2.
  1094  			// However, the contactRequestID in `AcceptContactRequestMessage` uses keccak256(...) instead of defaultContactRequestID(contact.ID).
  1095  			// Device 1 processes this, but device 2 doesn't due to an error `ErrRecordNotFound` from `m.persistence.MessageByID(contactRequestID)`.
  1096  			// The correct notification ID on device 2 should be defaultContactRequestID(contact.ID).
  1097  			// Thus, we must sync the accepted decision to device 2.
  1098  			err = m.syncActivityCenterAcceptedByIDs(context.TODO(), []types.HexBytes{types.FromHex(defaultContactRequestID(contact.ID))}, m.GetCurrentTimeInMillis())
  1099  			if err != nil {
  1100  				m.logger.Warn("could not sync activity center notification as accepted", zap.Error(err))
  1101  			}
  1102  		}
  1103  	}
  1104  
  1105  	state.ModifiedContacts.Store(contact.ID, true)
  1106  	state.AllContacts.Store(contact.ID, contact)
  1107  	return nil
  1108  }
  1109  
  1110  func (m *Messenger) HandleAcceptContactRequest(state *ReceivedMessageState, message *protobuf.AcceptContactRequest, statusMessage *v1protocol.StatusMessage) error {
  1111  	err := m.handleAcceptContactRequestMessage(state, message.Clock, message.Id, false)
  1112  	if err != nil {
  1113  		m.logger.Warn("could not accept contact request", zap.Error(err))
  1114  	}
  1115  
  1116  	return nil
  1117  }
  1118  
  1119  func (m *Messenger) handleRetractContactRequest(state *ReceivedMessageState, contact *Contact, message *protobuf.RetractContactRequest) error {
  1120  	if contact.ID == m.myHexIdentity() {
  1121  		m.logger.Debug("retraction coming from us, ignoring")
  1122  		return nil
  1123  	}
  1124  
  1125  	m.logger.Debug("handling retracted contact request", zap.Uint64("clock", message.Clock))
  1126  	r := contact.ContactRequestRetracted(message.Clock, false)
  1127  	if !r.processed {
  1128  		m.logger.Debug("not handling retract since clock lower")
  1129  		return nil
  1130  	}
  1131  
  1132  	// System message for mutual state update
  1133  	chat, clock, err := m.getOneToOneAndNextClock(contact)
  1134  	if err != nil {
  1135  		return err
  1136  	}
  1137  
  1138  	timestamp := m.getTimesource().GetCurrentTime()
  1139  	updateMessage, err := m.prepareMutualStateUpdateMessage(contact.ID, MutualStateUpdateTypeRemoved, clock, timestamp, false)
  1140  	if err != nil {
  1141  		return err
  1142  	}
  1143  
  1144  	// Dispatch profile message to remove a contact from the encrypted profile part
  1145  	err = m.DispatchProfileShowcase()
  1146  	if err != nil {
  1147  		return err
  1148  	}
  1149  
  1150  	err = m.prepareMessage(updateMessage, m.httpServer)
  1151  	if err != nil {
  1152  		return err
  1153  	}
  1154  	err = m.persistence.SaveMessages([]*common.Message{updateMessage})
  1155  	if err != nil {
  1156  		return err
  1157  	}
  1158  	state.Response.AddMessage(updateMessage)
  1159  
  1160  	err = chat.UpdateFromMessage(updateMessage, m.getTimesource())
  1161  	if err != nil {
  1162  		return err
  1163  	}
  1164  	chat.UnviewedMessagesCount++
  1165  	state.Response.AddChat(chat)
  1166  
  1167  	notification := &ActivityCenterNotification{
  1168  		ID:        types.FromHex(uuid.New().String()),
  1169  		Type:      ActivityCenterNotificationTypeContactRemoved,
  1170  		Name:      contact.PrimaryName(),
  1171  		Author:    contact.ID,
  1172  		Timestamp: m.getTimesource().GetCurrentTime(),
  1173  		ChatID:    contact.ID,
  1174  		Read:      false,
  1175  		UpdatedAt: m.GetCurrentTimeInMillis(),
  1176  	}
  1177  
  1178  	err = m.addActivityCenterNotification(state.Response, notification, nil)
  1179  	if err != nil {
  1180  		m.logger.Warn("failed to create activity center notification", zap.Error(err))
  1181  		return err
  1182  	}
  1183  
  1184  	m.allContacts.Store(contact.ID, contact)
  1185  
  1186  	return nil
  1187  }
  1188  
  1189  func (m *Messenger) HandleRetractContactRequest(state *ReceivedMessageState, message *protobuf.RetractContactRequest, statusMessage *v1protocol.StatusMessage) error {
  1190  	contact := state.CurrentMessageState.Contact
  1191  	err := m.handleRetractContactRequest(state, contact, message)
  1192  	if err != nil {
  1193  		return err
  1194  	}
  1195  	if contact.ID != m.myHexIdentity() {
  1196  		state.ModifiedContacts.Store(contact.ID, true)
  1197  	}
  1198  
  1199  	return nil
  1200  }
  1201  
  1202  func (m *Messenger) HandleContactUpdate(state *ReceivedMessageState, message *protobuf.ContactUpdate, statusMessage *v1protocol.StatusMessage) error {
  1203  
  1204  	logger := m.logger.With(zap.String("site", "HandleContactUpdate"))
  1205  	if common.IsPubKeyEqual(state.CurrentMessageState.PublicKey, &m.identity.PublicKey) {
  1206  		logger.Warn("coming from us, ignoring")
  1207  		return nil
  1208  	}
  1209  
  1210  	contact := state.CurrentMessageState.Contact
  1211  	chat, ok := state.AllChats.Load(contact.ID)
  1212  
  1213  	allowed, err := m.isMessageAllowedFrom(state.CurrentMessageState.Contact.ID, chat)
  1214  	if err != nil {
  1215  		return err
  1216  	}
  1217  	if !allowed {
  1218  		return ErrMessageNotAllowed
  1219  	}
  1220  
  1221  	if err = utils.ValidateDisplayName(&message.DisplayName); err != nil {
  1222  		return err
  1223  	}
  1224  
  1225  	if !ok {
  1226  		chat = OneToOneFromPublicKey(state.CurrentMessageState.PublicKey, state.Timesource)
  1227  		// We don't want to show the chat to the user
  1228  		chat.Active = false
  1229  	}
  1230  
  1231  	logger.Debug("Handling contact update")
  1232  
  1233  	if message.ContactRequestPropagatedState != nil {
  1234  		logger.Debug("handling contact request propagated state", zap.Any("state before update", contact.ContactRequestPropagatedState()))
  1235  		result := contact.ContactRequestPropagatedStateReceived(message.ContactRequestPropagatedState)
  1236  		if result.sendBackState {
  1237  			logger.Debug("sending back state")
  1238  			// This is a bit dangerous, since it might trigger a ping-pong of contact updates
  1239  			// also it should backoff/debounce
  1240  			_, err = m.sendContactUpdate(context.Background(), contact.ID, contact.DisplayName, contact.EnsName, "", contact.CustomizationColor, m.dispatchMessage)
  1241  			if err != nil {
  1242  				return err
  1243  			}
  1244  
  1245  		}
  1246  		if result.newContactRequestReceived {
  1247  			contactRequest, err := m.createContactRequestForContactUpdate(contact, state)
  1248  			if err != nil {
  1249  				return err
  1250  			}
  1251  
  1252  			err = m.createIncomingContactRequestNotification(contact, state, contactRequest, true)
  1253  			if err != nil {
  1254  				return err
  1255  			}
  1256  		}
  1257  
  1258  		logger.Debug("handled propagated state", zap.Any("state after update", contact.ContactRequestPropagatedState()))
  1259  		state.ModifiedContacts.Store(contact.ID, true)
  1260  		state.AllContacts.Store(contact.ID, contact)
  1261  	}
  1262  
  1263  	if contact.LastUpdated < message.Clock {
  1264  		if contact.EnsName != message.EnsName {
  1265  			contact.EnsName = message.EnsName
  1266  			contact.ENSVerified = false
  1267  		}
  1268  
  1269  		if len(message.DisplayName) != 0 {
  1270  			contact.DisplayName = message.DisplayName
  1271  		}
  1272  
  1273  		contact.CustomizationColor = multiaccountscommon.IDToColorFallbackToBlue(message.CustomizationColor)
  1274  
  1275  		r := contact.ContactRequestReceived(message.ContactRequestClock)
  1276  		if r.newContactRequestReceived {
  1277  			err = m.createIncomingContactRequestNotification(contact, state, nil, true)
  1278  			if err != nil {
  1279  				return err
  1280  			}
  1281  		}
  1282  		contact.LastUpdated = message.Clock
  1283  		state.ModifiedContacts.Store(contact.ID, true)
  1284  		state.AllContacts.Store(contact.ID, contact)
  1285  	}
  1286  
  1287  	if chat.LastClockValue < message.Clock {
  1288  		chat.LastClockValue = message.Clock
  1289  	}
  1290  
  1291  	if contact.mutual() && chat.DeletedAtClockValue < message.Clock {
  1292  		chat.Active = true
  1293  	}
  1294  
  1295  	state.Response.AddChat(chat)
  1296  	// TODO(samyoul) remove storing of an updated reference pointer?
  1297  	state.AllChats.Store(chat.ID, chat)
  1298  
  1299  	return nil
  1300  }
  1301  
  1302  func (m *Messenger) HandleSyncPairInstallation(state *ReceivedMessageState, message *protobuf.SyncPairInstallation, statusMessage *v1protocol.StatusMessage) error {
  1303  	logger := m.logger.With(zap.String("site", "HandlePairInstallation"))
  1304  	if err := ValidateReceivedPairInstallation(message, state.CurrentMessageState.WhisperTimestamp); err != nil {
  1305  		logger.Warn("failed to validate message", zap.Error(err))
  1306  		return err
  1307  	}
  1308  
  1309  	installation, ok := state.AllInstallations.Load(message.InstallationId)
  1310  	if !ok {
  1311  		return errors.New("installation not found")
  1312  	}
  1313  
  1314  	metadata := &multidevice.InstallationMetadata{
  1315  		Name:       message.Name,
  1316  		DeviceType: message.DeviceType,
  1317  	}
  1318  
  1319  	installation.InstallationMetadata = metadata
  1320  	// TODO(samyoul) remove storing of an updated reference pointer?
  1321  	state.AllInstallations.Store(message.InstallationId, installation)
  1322  	state.ModifiedInstallations.Store(message.InstallationId, true)
  1323  
  1324  	return nil
  1325  }
  1326  
  1327  func (m *Messenger) HandleHistoryArchiveMagnetlinkMessage(state *ReceivedMessageState, communityPubKey *ecdsa.PublicKey, magnetlink string, clock uint64) error {
  1328  	id := types.HexBytes(crypto.CompressPubkey(communityPubKey))
  1329  
  1330  	community, err := m.communitiesManager.GetByID(id)
  1331  	if err != nil && err != communities.ErrOrgNotFound {
  1332  		m.logger.Debug("Couldn't get community for community with id: ", zap.Any("id", id))
  1333  		return err
  1334  	}
  1335  	if community == nil {
  1336  		return nil
  1337  	}
  1338  
  1339  	settings, err := m.communitiesManager.GetCommunitySettingsByID(id)
  1340  	if err != nil {
  1341  		m.logger.Debug("Couldn't get community settings for community with id: ", zap.Any("id", id))
  1342  		return err
  1343  	}
  1344  	if settings == nil {
  1345  		return nil
  1346  	}
  1347  
  1348  	if m.archiveManager.IsReady() && settings.HistoryArchiveSupportEnabled {
  1349  		lastClock, err := m.communitiesManager.GetMagnetlinkMessageClock(id)
  1350  		if err != nil {
  1351  			return err
  1352  		}
  1353  		lastSeenMagnetlink, err := m.communitiesManager.GetLastSeenMagnetlink(id)
  1354  		if err != nil {
  1355  			return err
  1356  		}
  1357  		// We are only interested in a community archive magnet link
  1358  		// if it originates from a community that the current account is
  1359  		// part of and doesn't own the private key at the same time
  1360  		if !community.IsControlNode() && community.Joined() && clock >= lastClock {
  1361  			if lastSeenMagnetlink == magnetlink {
  1362  				m.logger.Debug("already processed this magnetlink")
  1363  				return nil
  1364  			}
  1365  
  1366  			m.archiveManager.UnseedHistoryArchiveTorrent(id)
  1367  			currentTask := m.archiveManager.GetHistoryArchiveDownloadTask(id.String())
  1368  
  1369  			go func(currentTask *communities.HistoryArchiveDownloadTask, communityID types.HexBytes) {
  1370  
  1371  				// Cancel ongoing download/import task
  1372  				if currentTask != nil && !currentTask.IsCancelled() {
  1373  					currentTask.Cancel()
  1374  					currentTask.Waiter.Wait()
  1375  				}
  1376  
  1377  				// Create new task
  1378  				task := &communities.HistoryArchiveDownloadTask{
  1379  					CancelChan: make(chan struct{}),
  1380  					Waiter:     *new(sync.WaitGroup),
  1381  					Cancelled:  false,
  1382  				}
  1383  
  1384  				m.archiveManager.AddHistoryArchiveDownloadTask(communityID.String(), task)
  1385  
  1386  				// this wait groups tracks the ongoing task for a particular community
  1387  				task.Waiter.Add(1)
  1388  				defer task.Waiter.Done()
  1389  
  1390  				// this wait groups tracks all ongoing tasks across communities
  1391  				m.shutdownWaitGroup.Add(1)
  1392  				defer m.shutdownWaitGroup.Done()
  1393  				m.downloadAndImportHistoryArchives(communityID, magnetlink, task.CancelChan)
  1394  			}(currentTask, id)
  1395  
  1396  			return m.communitiesManager.UpdateMagnetlinkMessageClock(id, clock)
  1397  		}
  1398  	}
  1399  	return nil
  1400  }
  1401  
  1402  func (m *Messenger) downloadAndImportHistoryArchives(id types.HexBytes, magnetlink string, cancel chan struct{}) {
  1403  	downloadTaskInfo, err := m.archiveManager.DownloadHistoryArchivesByMagnetlink(id, magnetlink, cancel)
  1404  	if err != nil {
  1405  		logMsg := "failed to download history archive data"
  1406  		if err == communities.ErrTorrentTimedout {
  1407  			m.logger.Debug("torrent has timed out, trying once more...")
  1408  			downloadTaskInfo, err = m.archiveManager.DownloadHistoryArchivesByMagnetlink(id, magnetlink, cancel)
  1409  			if err != nil {
  1410  				m.logger.Error(logMsg, zap.Error(err))
  1411  				return
  1412  			}
  1413  		} else {
  1414  			m.logger.Debug(logMsg, zap.Error(err))
  1415  			return
  1416  		}
  1417  	}
  1418  
  1419  	if downloadTaskInfo.Cancelled {
  1420  		if downloadTaskInfo.TotalDownloadedArchivesCount > 0 {
  1421  			m.logger.Debug(fmt.Sprintf("downloaded %d of %d archives so far", downloadTaskInfo.TotalDownloadedArchivesCount, downloadTaskInfo.TotalArchivesCount))
  1422  		}
  1423  		return
  1424  	}
  1425  
  1426  	err = m.communitiesManager.UpdateLastSeenMagnetlink(id, magnetlink)
  1427  	if err != nil {
  1428  		m.logger.Error("couldn't update last seen magnetlink", zap.Error(err))
  1429  	}
  1430  
  1431  	err = m.checkIfIMemberOfCommunity(id)
  1432  	if err != nil {
  1433  		return
  1434  	}
  1435  
  1436  	err = m.importHistoryArchives(id, cancel)
  1437  	if err != nil {
  1438  		m.logger.Error("failed to import history archives", zap.Error(err))
  1439  		m.config.messengerSignalsHandler.DownloadingHistoryArchivesFinished(types.EncodeHex(id))
  1440  		return
  1441  	}
  1442  
  1443  	m.config.messengerSignalsHandler.DownloadingHistoryArchivesFinished(types.EncodeHex(id))
  1444  }
  1445  
  1446  func (m *Messenger) handleArchiveMessages(archiveMessages []*protobuf.WakuMessage) (*MessengerResponse, error) {
  1447  
  1448  	messagesToHandle := make(map[transport.Filter][]*types.Message)
  1449  
  1450  	for _, message := range archiveMessages {
  1451  		filter := m.transport.FilterByTopic(message.Topic)
  1452  		if filter != nil {
  1453  			shhMessage := &types.Message{
  1454  				Sig:          message.Sig,
  1455  				Timestamp:    uint32(message.Timestamp),
  1456  				Topic:        types.BytesToTopic(message.Topic),
  1457  				Payload:      message.Payload,
  1458  				Padding:      message.Padding,
  1459  				Hash:         message.Hash,
  1460  				ThirdPartyID: message.ThirdPartyId,
  1461  			}
  1462  			messagesToHandle[*filter] = append(messagesToHandle[*filter], shhMessage)
  1463  		}
  1464  	}
  1465  
  1466  	importedMessages := make(map[transport.Filter][]*types.Message, 0)
  1467  	otherMessages := make(map[transport.Filter][]*types.Message, 0)
  1468  
  1469  	for filter, messages := range messagesToHandle {
  1470  		for _, message := range messages {
  1471  			if message.ThirdPartyID != "" {
  1472  				importedMessages[filter] = append(importedMessages[filter], message)
  1473  			} else {
  1474  				otherMessages[filter] = append(otherMessages[filter], message)
  1475  			}
  1476  		}
  1477  	}
  1478  
  1479  	err := m.handleImportedMessages(importedMessages)
  1480  	if err != nil {
  1481  		m.logger.Error("failed to handle imported messages", zap.Error(err))
  1482  		return nil, err
  1483  	}
  1484  
  1485  	response, err := m.handleRetrievedMessages(otherMessages, false, true)
  1486  	if err != nil {
  1487  		m.logger.Error("failed to write history archive messages to database", zap.Error(err))
  1488  		return nil, err
  1489  	}
  1490  
  1491  	return response, nil
  1492  }
  1493  
  1494  func (m *Messenger) HandleCommunityCancelRequestToJoin(state *ReceivedMessageState, cancelRequestToJoinProto *protobuf.CommunityCancelRequestToJoin, statusMessage *v1protocol.StatusMessage) error {
  1495  	signer := state.CurrentMessageState.PublicKey
  1496  	if cancelRequestToJoinProto.CommunityId == nil {
  1497  		return ErrInvalidCommunityID
  1498  	}
  1499  
  1500  	requestToJoin, err := m.communitiesManager.HandleCommunityCancelRequestToJoin(signer, cancelRequestToJoinProto)
  1501  	if err != nil {
  1502  		return err
  1503  	}
  1504  
  1505  	state.Response.AddRequestToJoinCommunity(requestToJoin)
  1506  
  1507  	// delete activity center notification
  1508  	notification, err := m.persistence.GetActivityCenterNotificationByID(requestToJoin.ID)
  1509  	if err != nil {
  1510  		return err
  1511  	}
  1512  
  1513  	if notification != nil {
  1514  		updatedAt := m.GetCurrentTimeInMillis()
  1515  		notification.UpdatedAt = updatedAt
  1516  		// we shouldn't sync deleted notification here,
  1517  		// as the same user on different devices will receive the same message(CommunityCancelRequestToJoin) ?
  1518  		err = m.persistence.DeleteActivityCenterNotificationByID(types.FromHex(requestToJoin.ID.String()), updatedAt)
  1519  		if err != nil {
  1520  			m.logger.Error("failed to delete notification from Activity Center", zap.Error(err))
  1521  			return err
  1522  		}
  1523  
  1524  		// sending signal to client to remove the activity center notification from UI
  1525  		response := &MessengerResponse{}
  1526  		response.AddActivityCenterNotification(notification)
  1527  
  1528  		signal.SendNewMessages(response)
  1529  	}
  1530  
  1531  	return nil
  1532  }
  1533  
  1534  // HandleCommunityRequestToJoin handles an community request to join
  1535  func (m *Messenger) HandleCommunityRequestToJoin(state *ReceivedMessageState, requestToJoinProto *protobuf.CommunityRequestToJoin, statusMessage *v1protocol.StatusMessage) error {
  1536  	signer := state.CurrentMessageState.PublicKey
  1537  	community, requestToJoin, err := m.communitiesManager.HandleCommunityRequestToJoin(signer, statusMessage.TransportLayer.Dst, requestToJoinProto)
  1538  	if err != nil {
  1539  		return err
  1540  	}
  1541  
  1542  	switch requestToJoin.State {
  1543  	case communities.RequestToJoinStatePending:
  1544  		contact, _ := state.AllContacts.Load(contactIDFromPublicKey(signer))
  1545  		contact.CustomizationColor = multiaccountscommon.IDToColorFallbackToBlue(requestToJoinProto.CustomizationColor)
  1546  		if len(requestToJoinProto.DisplayName) != 0 {
  1547  			contact.DisplayName = requestToJoinProto.DisplayName
  1548  			state.ModifiedContacts.Store(contact.ID, true)
  1549  			state.AllContacts.Store(contact.ID, contact)
  1550  			state.ModifiedContacts.Store(contact.ID, true)
  1551  		}
  1552  
  1553  		state.Response.AddRequestToJoinCommunity(requestToJoin)
  1554  
  1555  		state.Response.AddNotification(NewCommunityRequestToJoinNotification(requestToJoin.ID.String(), community, contact))
  1556  
  1557  		// Activity Center notification, new for pending state
  1558  		notification := &ActivityCenterNotification{
  1559  			ID:               types.FromHex(requestToJoin.ID.String()),
  1560  			Type:             ActivityCenterNotificationTypeCommunityMembershipRequest,
  1561  			Timestamp:        m.getTimesource().GetCurrentTime(),
  1562  			Author:           contact.ID,
  1563  			CommunityID:      community.IDString(),
  1564  			MembershipStatus: ActivityCenterMembershipStatusPending,
  1565  			Deleted:          false,
  1566  			UpdatedAt:        m.GetCurrentTimeInMillis(),
  1567  		}
  1568  		err = m.addActivityCenterNotification(state.Response, notification, nil)
  1569  		if err != nil {
  1570  			m.logger.Error("failed to save notification", zap.Error(err))
  1571  			return err
  1572  		}
  1573  
  1574  	case communities.RequestToJoinStateDeclined:
  1575  		response, err := m.declineRequestToJoinCommunity(requestToJoin)
  1576  		if err == nil {
  1577  			err := state.Response.Merge(response)
  1578  			if err != nil {
  1579  				return err
  1580  			}
  1581  		} else {
  1582  			return err
  1583  		}
  1584  
  1585  	case communities.RequestToJoinStateAccepted:
  1586  		response, err := m.acceptRequestToJoinCommunity(requestToJoin)
  1587  		if err == nil {
  1588  			err := state.Response.Merge(response) // new member has been added
  1589  			if err != nil {
  1590  				return err
  1591  			}
  1592  		} else if err == communities.ErrNoPermissionToJoin {
  1593  			// only control node will end up here as it's the only one that
  1594  			// performed token permission checks
  1595  			response, err = m.declineRequestToJoinCommunity(requestToJoin)
  1596  			if err == nil {
  1597  				err := state.Response.Merge(response)
  1598  				if err != nil {
  1599  					return err
  1600  				}
  1601  			} else {
  1602  				return err
  1603  			}
  1604  		} else {
  1605  			return err
  1606  		}
  1607  
  1608  	case communities.RequestToJoinStateCanceled:
  1609  		// cancellation is handled by separate message
  1610  		fallthrough
  1611  	case communities.RequestToJoinStateAwaitingAddresses:
  1612  		// ownership changed request is handled only if owner kicked members and saved
  1613  		// temporary RequestToJoinStateAwaitingAddresses request
  1614  		fallthrough
  1615  	case communities.RequestToJoinStateAcceptedPending, communities.RequestToJoinStateDeclinedPending:
  1616  		// request can be marked as pending only manually
  1617  		return errors.New("invalid request state")
  1618  	}
  1619  
  1620  	return nil
  1621  }
  1622  
  1623  // HandleCommunityEditSharedAddresses handles an edit a user has made to their shared addresses
  1624  func (m *Messenger) HandleCommunityEditSharedAddresses(state *ReceivedMessageState, editRevealedAddressesProto *protobuf.CommunityEditSharedAddresses, statusMessage *v1protocol.StatusMessage) error {
  1625  	signer := state.CurrentMessageState.PublicKey
  1626  	if editRevealedAddressesProto.CommunityId == nil {
  1627  		return ErrInvalidCommunityID
  1628  	}
  1629  
  1630  	err := m.communitiesManager.HandleCommunityEditSharedAddresses(signer, editRevealedAddressesProto)
  1631  	if err != nil {
  1632  		return err
  1633  	}
  1634  
  1635  	community, err := m.communitiesManager.GetByIDString(string(editRevealedAddressesProto.GetCommunityId()))
  1636  	if err != nil {
  1637  		return err
  1638  	}
  1639  
  1640  	state.Response.AddCommunity(community)
  1641  	return nil
  1642  }
  1643  
  1644  func (m *Messenger) HandleCommunityRequestToJoinResponse(state *ReceivedMessageState, requestToJoinResponseProto *protobuf.CommunityRequestToJoinResponse, statusMessage *v1protocol.StatusMessage) error {
  1645  	signer := state.CurrentMessageState.PublicKey
  1646  	if requestToJoinResponseProto.CommunityId == nil {
  1647  		return ErrInvalidCommunityID
  1648  	}
  1649  
  1650  	myRequestToJoinId := communities.CalculateRequestID(m.IdentityPublicKeyString(), requestToJoinResponseProto.CommunityId)
  1651  
  1652  	requestToJoin, err := m.communitiesManager.GetRequestToJoin(myRequestToJoinId)
  1653  	if err != nil {
  1654  		return err
  1655  	}
  1656  
  1657  	if requestToJoin.State == communities.RequestToJoinStateCanceled {
  1658  		return nil
  1659  	}
  1660  
  1661  	community, err := m.communitiesManager.GetByID(requestToJoinResponseProto.CommunityId)
  1662  	if err != nil {
  1663  		return err
  1664  	}
  1665  
  1666  	// check if it is outdated approved request to join
  1667  	clockSeconds := requestToJoinResponseProto.Clock / 1000
  1668  	isClockOutdated := clockSeconds < requestToJoin.Clock
  1669  	isDuplicateAfterMemberLeaves := clockSeconds == requestToJoin.Clock &&
  1670  		requestToJoin.State == communities.RequestToJoinStateAccepted && !community.Joined()
  1671  
  1672  	if requestToJoin.State != communities.RequestToJoinStatePending &&
  1673  		(isClockOutdated || isDuplicateAfterMemberLeaves) {
  1674  		m.logger.Error(ErrOutdatedCommunityRequestToJoin.Error(),
  1675  			zap.String("communityId", community.IDString()),
  1676  			zap.Bool("joined", community.Joined()),
  1677  			zap.Uint64("requestToJoinResponseProto.Clock", requestToJoinResponseProto.Clock),
  1678  			zap.Uint64("requestToJoin.Clock", requestToJoin.Clock),
  1679  			zap.Uint8("state", uint8(requestToJoin.State)))
  1680  		return ErrOutdatedCommunityRequestToJoin
  1681  	}
  1682  
  1683  	updatedRequest, err := m.communitiesManager.HandleCommunityRequestToJoinResponse(signer, requestToJoinResponseProto)
  1684  	if err != nil {
  1685  		return err
  1686  	}
  1687  
  1688  	if updatedRequest != nil {
  1689  		state.Response.AddRequestToJoinCommunity(updatedRequest)
  1690  	}
  1691  
  1692  	community, err = m.communitiesManager.GetByID(requestToJoinResponseProto.CommunityId)
  1693  	if err != nil {
  1694  		return err
  1695  	}
  1696  
  1697  	if requestToJoinResponseProto.Accepted && community != nil && community.HasMember(&m.identity.PublicKey) {
  1698  
  1699  		communityShardKey := &protobuf.CommunityShardKey{
  1700  			CommunityId: requestToJoinResponseProto.CommunityId,
  1701  			PrivateKey:  requestToJoinResponseProto.ProtectedTopicPrivateKey,
  1702  			Clock:       requestToJoinResponseProto.Community.Clock,
  1703  			Shard:       requestToJoinResponseProto.Shard,
  1704  		}
  1705  
  1706  		err = m.handleCommunityShardAndFiltersFromProto(community, communityShardKey)
  1707  		if err != nil {
  1708  			return err
  1709  		}
  1710  
  1711  		// Note: we can't guarantee that REQUEST_TO_JOIN_RESPONSE msg will be delivered before
  1712  		// COMMUNITY_DESCRIPTION msg, so this msg can return an ErrOrgAlreadyJoined if we
  1713  		// have been joined during COMMUNITY_DESCRIPTION
  1714  		response, err := m.JoinCommunity(context.Background(), requestToJoinResponseProto.CommunityId, false)
  1715  		if err != nil && err != communities.ErrOrgAlreadyJoined {
  1716  			return err
  1717  		}
  1718  
  1719  		var communitySettings *communities.CommunitySettings
  1720  		if response != nil {
  1721  			// we merge to include chats in response signal to joining a community
  1722  			err = state.Response.Merge(response)
  1723  			if err != nil {
  1724  				return err
  1725  			}
  1726  
  1727  			if len(response.Communities()) > 0 {
  1728  				communitySettings = response.CommunitiesSettings()[0]
  1729  				community = response.Communities()[0]
  1730  			}
  1731  		}
  1732  
  1733  		if communitySettings == nil {
  1734  			communitySettings, err = m.communitiesManager.GetCommunitySettingsByID(requestToJoinResponseProto.CommunityId)
  1735  			if err != nil {
  1736  				return nil
  1737  			}
  1738  		}
  1739  
  1740  		magnetlink := requestToJoinResponseProto.MagnetUri
  1741  		if m.archiveManager.IsReady() && communitySettings != nil && communitySettings.HistoryArchiveSupportEnabled && magnetlink != "" {
  1742  
  1743  			currentTask := m.archiveManager.GetHistoryArchiveDownloadTask(community.IDString())
  1744  			go func(currentTask *communities.HistoryArchiveDownloadTask) {
  1745  
  1746  				// Cancel ongoing download/import task
  1747  				if currentTask != nil && !currentTask.IsCancelled() {
  1748  					currentTask.Cancel()
  1749  					currentTask.Waiter.Wait()
  1750  				}
  1751  
  1752  				task := &communities.HistoryArchiveDownloadTask{
  1753  					CancelChan: make(chan struct{}),
  1754  					Waiter:     *new(sync.WaitGroup),
  1755  					Cancelled:  false,
  1756  				}
  1757  				m.archiveManager.AddHistoryArchiveDownloadTask(community.IDString(), task)
  1758  
  1759  				task.Waiter.Add(1)
  1760  				defer task.Waiter.Done()
  1761  
  1762  				m.shutdownWaitGroup.Add(1)
  1763  				defer m.shutdownWaitGroup.Done()
  1764  
  1765  				m.downloadAndImportHistoryArchives(community.ID(), magnetlink, task.CancelChan)
  1766  			}(currentTask)
  1767  
  1768  			clock := requestToJoinResponseProto.Community.ArchiveMagnetlinkClock
  1769  			return m.communitiesManager.UpdateMagnetlinkMessageClock(community.ID(), clock)
  1770  		}
  1771  	}
  1772  
  1773  	return nil
  1774  }
  1775  
  1776  func (m *Messenger) HandleCommunityRequestToLeave(state *ReceivedMessageState, requestToLeaveProto *protobuf.CommunityRequestToLeave, statusMessage *v1protocol.StatusMessage) error {
  1777  	signer := state.CurrentMessageState.PublicKey
  1778  	if requestToLeaveProto.CommunityId == nil {
  1779  		return ErrInvalidCommunityID
  1780  	}
  1781  
  1782  	err := m.communitiesManager.HandleCommunityRequestToLeave(signer, requestToLeaveProto)
  1783  	if err != nil {
  1784  		return err
  1785  	}
  1786  
  1787  	response, err := m.RemoveUserFromCommunity(requestToLeaveProto.CommunityId, common.PubkeyToHex(signer))
  1788  	if err != nil {
  1789  		return err
  1790  	}
  1791  
  1792  	if len(response.Communities()) > 0 {
  1793  		state.Response.AddCommunity(response.Communities()[0])
  1794  	}
  1795  
  1796  	return nil
  1797  }
  1798  
  1799  func (m *Messenger) handleEditMessage(state *ReceivedMessageState, editMessage EditMessage) error {
  1800  	if err := ValidateEditMessage(editMessage.EditMessage); err != nil {
  1801  		return err
  1802  	}
  1803  	messageID := editMessage.MessageId
  1804  
  1805  	originalMessage, err := m.getMessageFromResponseOrDatabase(state.Response, messageID)
  1806  
  1807  	if err == common.ErrRecordNotFound {
  1808  		return m.persistence.SaveEdit(&editMessage)
  1809  	} else if err != nil {
  1810  		return err
  1811  	}
  1812  
  1813  	originalMessageMentioned := originalMessage.Mentioned
  1814  
  1815  	chat, ok := m.allChats.Load(originalMessage.LocalChatID)
  1816  	if !ok {
  1817  		return errors.New("chat not found")
  1818  	}
  1819  
  1820  	// Check edit is valid
  1821  	if originalMessage.From != editMessage.From {
  1822  		return errors.New("invalid edit, not the right author")
  1823  	}
  1824  
  1825  	// Check that edit should be applied
  1826  	if originalMessage.EditedAt >= editMessage.Clock {
  1827  		return m.persistence.SaveEdit(&editMessage)
  1828  	}
  1829  
  1830  	// applyEditMessage modifies the message. Changing the variable name to make it clearer
  1831  	editedMessage := originalMessage
  1832  	// Update message and return it
  1833  	err = m.applyEditMessage(editMessage.EditMessage, editedMessage)
  1834  	if err != nil {
  1835  		return err
  1836  	}
  1837  
  1838  	needToSaveChat := false
  1839  	if chat.LastMessage != nil && chat.LastMessage.ID == editedMessage.ID {
  1840  		chat.LastMessage = editedMessage
  1841  		needToSaveChat = true
  1842  	}
  1843  	responseTo, err := m.persistence.MessageByID(editedMessage.ResponseTo)
  1844  
  1845  	if err != nil && err != common.ErrRecordNotFound {
  1846  		return err
  1847  	}
  1848  
  1849  	err = state.updateExistingActivityCenterNotification(m.identity.PublicKey, m, editedMessage, responseTo)
  1850  	if err != nil {
  1851  		return err
  1852  	}
  1853  
  1854  	editedMessageHasMentions := editedMessage.Mentioned
  1855  
  1856  	// Messages in OneToOne chats increase the UnviewedMentionsCount whether or not they include a Mention
  1857  	if !chat.OneToOne() {
  1858  		if editedMessageHasMentions && !originalMessageMentioned && !editedMessage.Seen {
  1859  			// Increase unviewed count when the edited message has a mention and didn't have one before
  1860  			chat.UnviewedMentionsCount++
  1861  			needToSaveChat = true
  1862  		} else if !editedMessageHasMentions && originalMessageMentioned && !editedMessage.Seen {
  1863  			// Opposite of above, the message had a mention, but no longer does, so we reduce the count
  1864  			chat.UnviewedMentionsCount--
  1865  			needToSaveChat = true
  1866  		}
  1867  	}
  1868  
  1869  	if needToSaveChat {
  1870  		err := m.saveChat(chat)
  1871  		if err != nil {
  1872  			return err
  1873  		}
  1874  	}
  1875  
  1876  	state.Response.AddMessage(editedMessage)
  1877  
  1878  	// pull updated messages
  1879  	updatedMessages, err := m.persistence.MessagesByResponseTo(messageID)
  1880  	if err != nil {
  1881  		return err
  1882  	}
  1883  	state.Response.AddMessages(updatedMessages)
  1884  
  1885  	state.Response.AddChat(chat)
  1886  
  1887  	return nil
  1888  }
  1889  
  1890  func (m *Messenger) HandleEditMessage(state *ReceivedMessageState, editProto *protobuf.EditMessage, statusMessage *v1protocol.StatusMessage) error {
  1891  	return m.handleEditMessage(state, EditMessage{
  1892  		EditMessage: editProto,
  1893  		From:        state.CurrentMessageState.Contact.ID,
  1894  		ID:          state.CurrentMessageState.MessageID,
  1895  		SigPubKey:   state.CurrentMessageState.PublicKey,
  1896  	})
  1897  }
  1898  
  1899  func (m *Messenger) handleDeleteMessage(state *ReceivedMessageState, deleteMessage *DeleteMessage) error {
  1900  	if deleteMessage == nil {
  1901  		return nil
  1902  	}
  1903  	if err := ValidateDeleteMessage(deleteMessage.DeleteMessage); err != nil {
  1904  		return err
  1905  	}
  1906  
  1907  	messageID := deleteMessage.MessageId
  1908  	// Check if it's already in the response
  1909  	originalMessage := state.Response.GetMessage(messageID)
  1910  	// otherwise pull from database
  1911  	if originalMessage == nil {
  1912  		var err error
  1913  		originalMessage, err = m.persistence.MessageByID(messageID)
  1914  
  1915  		if err != nil && err != common.ErrRecordNotFound {
  1916  			return err
  1917  		}
  1918  	}
  1919  
  1920  	if originalMessage == nil {
  1921  		return m.persistence.SaveDelete(deleteMessage)
  1922  	}
  1923  
  1924  	chat, ok := m.allChats.Load(originalMessage.LocalChatID)
  1925  	if !ok {
  1926  		return errors.New("chat not found")
  1927  	}
  1928  
  1929  	var canDeleteMessageForEveryone = false
  1930  	if originalMessage.From != deleteMessage.From {
  1931  		fromPublicKey, err := common.HexToPubkey(deleteMessage.From)
  1932  		if err != nil {
  1933  			return err
  1934  		}
  1935  		if chat.ChatType == ChatTypeCommunityChat {
  1936  			canDeleteMessageForEveryone = m.CanDeleteMessageForEveryoneInCommunity(chat.CommunityID, fromPublicKey)
  1937  			if !canDeleteMessageForEveryone {
  1938  				return ErrInvalidDeletePermission
  1939  			}
  1940  		} else if chat.ChatType == ChatTypePrivateGroupChat {
  1941  			canDeleteMessageForEveryone = m.CanDeleteMessageForEveryoneInPrivateGroupChat(chat, fromPublicKey)
  1942  			if !canDeleteMessageForEveryone {
  1943  				return ErrInvalidDeletePermission
  1944  			}
  1945  		}
  1946  
  1947  		// Check edit is valid
  1948  		if !canDeleteMessageForEveryone {
  1949  			return errors.New("invalid delete, not the right author")
  1950  		}
  1951  	}
  1952  
  1953  	messagesToDelete, err := m.getOtherMessagesInAlbum(originalMessage, originalMessage.LocalChatID)
  1954  	if err != nil {
  1955  		return err
  1956  	}
  1957  
  1958  	unreadCountDecreased := false
  1959  	for _, messageToDelete := range messagesToDelete {
  1960  		messageToDelete.Deleted = true
  1961  		messageToDelete.DeletedBy = deleteMessage.DeleteMessage.DeletedBy
  1962  		err := m.persistence.SaveMessages([]*common.Message{messageToDelete})
  1963  		if err != nil {
  1964  			return err
  1965  		}
  1966  
  1967  		// we shouldn't sync deleted notification here,
  1968  		// as the same user on different devices will receive the same message(DeleteMessage) ?
  1969  		m.logger.Debug("deleting activity center notification for message", zap.String("chatID", chat.ID), zap.String("messageID", messageToDelete.ID))
  1970  		_, err = m.persistence.DeleteActivityCenterNotificationForMessage(chat.ID, messageToDelete.ID, m.GetCurrentTimeInMillis())
  1971  
  1972  		if err != nil {
  1973  			m.logger.Warn("failed to delete notifications for deleted message", zap.Error(err))
  1974  			return err
  1975  		}
  1976  
  1977  		// Reduce chat mention count and unread count if unread
  1978  		if !messageToDelete.Seen && !unreadCountDecreased {
  1979  			unreadCountDecreased = true
  1980  			if chat.UnviewedMessagesCount > 0 {
  1981  				chat.UnviewedMessagesCount--
  1982  			}
  1983  			if chat.UnviewedMentionsCount > 0 && (messageToDelete.Mentioned || messageToDelete.Replied) {
  1984  				chat.UnviewedMentionsCount--
  1985  			}
  1986  			err := m.saveChat(chat)
  1987  			if err != nil {
  1988  				return err
  1989  			}
  1990  		}
  1991  
  1992  		state.Response.AddRemovedMessage(&RemovedMessage{MessageID: messageToDelete.ID, ChatID: chat.ID, DeletedBy: deleteMessage.DeleteMessage.DeletedBy})
  1993  		state.Response.AddNotification(DeletedMessageNotification(messageToDelete.ID, chat))
  1994  		state.Response.AddActivityCenterNotification(&ActivityCenterNotification{
  1995  			ID:      types.FromHex(messageToDelete.ID),
  1996  			Deleted: true,
  1997  		})
  1998  
  1999  		if chat.LastMessage != nil && chat.LastMessage.ID == messageToDelete.ID {
  2000  			chat.LastMessage = messageToDelete
  2001  			err = m.saveChat(chat)
  2002  			if err != nil {
  2003  				return nil
  2004  			}
  2005  		}
  2006  
  2007  		messages, err := m.persistence.LatestMessageByChatID(chat.ID)
  2008  		if err != nil {
  2009  			return err
  2010  		}
  2011  		if len(messages) > 0 {
  2012  			previousNotDeletedMessage := messages[0]
  2013  			if previousNotDeletedMessage != nil && !previousNotDeletedMessage.Seen && chat.OneToOne() && !chat.Active {
  2014  				m.createMessageNotification(chat, state, previousNotDeletedMessage)
  2015  			}
  2016  		}
  2017  
  2018  		// pull updated messages
  2019  		updatedMessages, err := m.persistence.MessagesByResponseTo(messageToDelete.ID)
  2020  		if err != nil {
  2021  			return err
  2022  		}
  2023  		state.Response.AddMessages(updatedMessages)
  2024  	}
  2025  
  2026  	state.Response.AddChat(chat)
  2027  
  2028  	return nil
  2029  }
  2030  
  2031  func (m *Messenger) HandleDeleteMessage(state *ReceivedMessageState, deleteProto *protobuf.DeleteMessage, statusMessage *v1protocol.StatusMessage) error {
  2032  	return m.handleDeleteMessage(state, &DeleteMessage{
  2033  		DeleteMessage: deleteProto,
  2034  		From:          state.CurrentMessageState.Contact.ID,
  2035  		ID:            state.CurrentMessageState.MessageID,
  2036  		SigPubKey:     state.CurrentMessageState.PublicKey,
  2037  	})
  2038  }
  2039  
  2040  func (m *Messenger) getMessageFromResponseOrDatabase(response *MessengerResponse, messageID string) (*common.Message, error) {
  2041  	originalMessage := response.GetMessage(messageID)
  2042  	// otherwise pull from database
  2043  	if originalMessage != nil {
  2044  		return originalMessage, nil
  2045  	}
  2046  
  2047  	return m.persistence.MessageByID(messageID)
  2048  }
  2049  
  2050  func (m *Messenger) HandleSyncDeleteForMeMessage(state *ReceivedMessageState, deleteForMeMessage *protobuf.SyncDeleteForMeMessage, statusMessage *v1protocol.StatusMessage) error {
  2051  	if err := ValidateDeleteForMeMessage(deleteForMeMessage); err != nil {
  2052  		return err
  2053  	}
  2054  
  2055  	messageID := deleteForMeMessage.MessageId
  2056  	// Check if it's already in the response
  2057  	originalMessage, err := m.getMessageFromResponseOrDatabase(state.Response, messageID)
  2058  
  2059  	if err == common.ErrRecordNotFound {
  2060  		return m.persistence.SaveOrUpdateDeleteForMeMessage(deleteForMeMessage)
  2061  	} else if err != nil {
  2062  		return err
  2063  	}
  2064  
  2065  	chat, ok := m.allChats.Load(originalMessage.LocalChatID)
  2066  	if !ok {
  2067  		return errors.New("chat not found")
  2068  	}
  2069  
  2070  	messagesToDelete, err := m.getOtherMessagesInAlbum(originalMessage, originalMessage.LocalChatID)
  2071  	if err != nil {
  2072  		return err
  2073  	}
  2074  
  2075  	for _, messageToDelete := range messagesToDelete {
  2076  		messageToDelete.DeletedForMe = true
  2077  
  2078  		err := m.persistence.SaveMessages([]*common.Message{messageToDelete})
  2079  		if err != nil {
  2080  			return err
  2081  		}
  2082  
  2083  		// we shouldn't sync deleted notification here,
  2084  		// as the same user on different devices will receive the same message(DeleteForMeMessage) ?
  2085  		m.logger.Debug("deleting activity center notification for message", zap.String("chatID", chat.ID), zap.String("messageID", messageToDelete.ID))
  2086  		_, err = m.persistence.DeleteActivityCenterNotificationForMessage(chat.ID, messageToDelete.ID, m.GetCurrentTimeInMillis())
  2087  		if err != nil {
  2088  			m.logger.Warn("failed to delete notifications for deleted message", zap.Error(err))
  2089  			return err
  2090  		}
  2091  
  2092  		if chat.LastMessage != nil && chat.LastMessage.ID == messageToDelete.ID {
  2093  			chat.LastMessage = messageToDelete
  2094  			err = m.saveChat(chat)
  2095  			if err != nil {
  2096  				return nil
  2097  			}
  2098  		}
  2099  
  2100  		state.Response.AddMessage(messageToDelete)
  2101  	}
  2102  	state.Response.AddChat(chat)
  2103  
  2104  	return nil
  2105  }
  2106  
  2107  func handleContactRequestChatMessage(receivedMessage *common.Message, contact *Contact, outgoing bool, logger *zap.Logger) (bool, error) {
  2108  	receivedMessage.ContactRequestState = common.ContactRequestStatePending
  2109  
  2110  	var response ContactRequestProcessingResponse
  2111  
  2112  	if outgoing {
  2113  		response = contact.ContactRequestSent(receivedMessage.Clock)
  2114  	} else {
  2115  		response = contact.ContactRequestReceived(receivedMessage.Clock)
  2116  	}
  2117  	if !response.processed {
  2118  		logger.Info("not handling contact message since clock lower")
  2119  		return false, nil
  2120  
  2121  	}
  2122  
  2123  	if contact.mutual() {
  2124  		receivedMessage.ContactRequestState = common.ContactRequestStateAccepted
  2125  	}
  2126  
  2127  	return response.newContactRequestReceived, nil
  2128  }
  2129  
  2130  func (m *Messenger) handleChatMessage(state *ReceivedMessageState, forceSeen bool) error {
  2131  	logger := m.logger.With(zap.String("site", "handleChatMessage"))
  2132  	if err := ValidateReceivedChatMessage(state.CurrentMessageState.Message, state.CurrentMessageState.WhisperTimestamp); err != nil {
  2133  		logger.Warn("failed to validate message", zap.Error(err))
  2134  		return err
  2135  	}
  2136  
  2137  	receivedMessage := &common.Message{
  2138  		ID:               state.CurrentMessageState.MessageID,
  2139  		ChatMessage:      state.CurrentMessageState.Message,
  2140  		From:             state.CurrentMessageState.Contact.ID,
  2141  		Alias:            state.CurrentMessageState.Contact.Alias,
  2142  		SigPubKey:        state.CurrentMessageState.PublicKey,
  2143  		Identicon:        state.CurrentMessageState.Contact.Identicon,
  2144  		WhisperTimestamp: state.CurrentMessageState.WhisperTimestamp,
  2145  	}
  2146  
  2147  	// is the message coming from us?
  2148  	isSyncMessage := common.IsPubKeyEqual(receivedMessage.SigPubKey, &m.identity.PublicKey)
  2149  
  2150  	if forceSeen || isSyncMessage {
  2151  		receivedMessage.Seen = true
  2152  	}
  2153  
  2154  	err := receivedMessage.PrepareContent(m.myHexIdentity())
  2155  	if err != nil {
  2156  		return fmt.Errorf("failed to prepare message content: %v", err)
  2157  	}
  2158  
  2159  	// If the message is a reply, we check if it's a reply to one of own own messages
  2160  	if receivedMessage.ResponseTo != "" {
  2161  		repliedTo, err := m.persistence.MessageByID(receivedMessage.ResponseTo)
  2162  		if err != nil && (err == sql.ErrNoRows || err == common.ErrRecordNotFound) {
  2163  			logger.Error("failed to get quoted message", zap.Error(err))
  2164  		} else if err != nil {
  2165  			return err
  2166  		} else if repliedTo.From == m.myHexIdentity() {
  2167  			receivedMessage.Replied = true
  2168  		}
  2169  	}
  2170  
  2171  	chat, err := m.matchChatEntity(receivedMessage, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE)
  2172  	if err != nil {
  2173  		return err // matchChatEntity returns a descriptive error message
  2174  	}
  2175  
  2176  	if chat.ReadMessagesAtClockValue >= receivedMessage.Clock {
  2177  		receivedMessage.Seen = true
  2178  	}
  2179  
  2180  	allowed, err := m.isMessageAllowedFrom(state.CurrentMessageState.Contact.ID, chat)
  2181  	if err != nil {
  2182  		return err
  2183  	}
  2184  
  2185  	if !allowed {
  2186  		return ErrMessageNotAllowed
  2187  	}
  2188  
  2189  	if chat.ChatType == ChatTypeCommunityChat {
  2190  		communityID, err := types.DecodeHex(chat.CommunityID)
  2191  		if err != nil {
  2192  			return err
  2193  		}
  2194  
  2195  		community, err := m.GetCommunityByID(communityID)
  2196  		if err != nil {
  2197  			return err
  2198  		}
  2199  
  2200  		if community == nil {
  2201  			logger.Warn("community not found for msg",
  2202  				zap.String("messageID", receivedMessage.ID),
  2203  				zap.String("from", receivedMessage.From),
  2204  				zap.String("communityID", chat.CommunityID))
  2205  			return communities.ErrOrgNotFound
  2206  		}
  2207  
  2208  		pk, err := common.HexToPubkey(state.CurrentMessageState.Contact.ID)
  2209  		if err != nil {
  2210  			return err
  2211  		}
  2212  
  2213  		if community.IsBanned(pk) {
  2214  			logger.Warn("skipping msg from banned user",
  2215  				zap.String("messageID", receivedMessage.ID),
  2216  				zap.String("from", receivedMessage.From),
  2217  				zap.String("communityID", chat.CommunityID))
  2218  			return errors.New("received a messaged from banned user")
  2219  		}
  2220  	}
  2221  
  2222  	// It looks like status-mobile created profile chats as public chats
  2223  	// so for now we need to check for the presence of "@" in their chatID
  2224  	if chat.Public() && !chat.ProfileUpdates() {
  2225  		switch receivedMessage.ContentType {
  2226  		case protobuf.ChatMessage_IMAGE:
  2227  			return errors.New("images are not allowed in public chats")
  2228  		case protobuf.ChatMessage_AUDIO:
  2229  			return errors.New("audio messages are not allowed in public chats")
  2230  		}
  2231  	}
  2232  
  2233  	// If profile updates check if author is the same as chat profile public key
  2234  	if chat.ProfileUpdates() && receivedMessage.From != chat.Profile {
  2235  		return nil
  2236  	}
  2237  
  2238  	// If deleted-at is greater, ignore message
  2239  	if chat.DeletedAtClockValue >= receivedMessage.Clock {
  2240  		return nil
  2241  	}
  2242  
  2243  	// Set the LocalChatID for the message
  2244  	receivedMessage.LocalChatID = chat.ID
  2245  
  2246  	if err := m.updateChatFirstMessageTimestamp(chat, whisperToUnixTimestamp(receivedMessage.WhisperTimestamp), state.Response); err != nil {
  2247  		return err
  2248  	}
  2249  
  2250  	// Our own message, mark as sent
  2251  	if isSyncMessage {
  2252  		receivedMessage.OutgoingStatus = common.OutgoingStatusSent
  2253  	} else if !receivedMessage.Seen {
  2254  		// Increase unviewed count
  2255  		skipUpdateUnviewedCountForAlbums := false
  2256  		if receivedMessage.ContentType == protobuf.ChatMessage_IMAGE {
  2257  			image := receivedMessage.GetImage()
  2258  
  2259  			if image != nil && image.AlbumId != "" {
  2260  				// Skip unviewed counts increasing for other messages from album if we have it in memory
  2261  				for _, message := range state.Response.Messages() {
  2262  					if receivedMessage.ContentType == protobuf.ChatMessage_IMAGE {
  2263  						img := message.GetImage()
  2264  						if img != nil && img.AlbumId != "" && img.AlbumId == image.AlbumId {
  2265  							skipUpdateUnviewedCountForAlbums = true
  2266  							break
  2267  						}
  2268  					}
  2269  				}
  2270  
  2271  				if !skipUpdateUnviewedCountForAlbums {
  2272  					messages, err := m.persistence.AlbumMessages(chat.ID, image.AlbumId)
  2273  					if err != nil {
  2274  						return err
  2275  					}
  2276  
  2277  					// Skip unviewed counts increasing for other messages from album if we have it in db
  2278  					skipUpdateUnviewedCountForAlbums = len(messages) > 0
  2279  				}
  2280  			}
  2281  		}
  2282  		if !skipUpdateUnviewedCountForAlbums {
  2283  			m.updateUnviewedCounts(chat, receivedMessage)
  2284  		}
  2285  	}
  2286  
  2287  	contact := state.CurrentMessageState.Contact
  2288  
  2289  	if receivedMessage.ContentType == protobuf.ChatMessage_DISCORD_MESSAGE {
  2290  		discordMessage := receivedMessage.GetDiscordMessage()
  2291  		discordMessageAuthor := discordMessage.GetAuthor()
  2292  		discordMessageAttachments := discordMessage.GetAttachments()
  2293  
  2294  		state.Response.AddDiscordMessage(discordMessage)
  2295  		state.Response.AddDiscordMessageAuthor(discordMessageAuthor)
  2296  
  2297  		if len(discordMessageAttachments) > 0 {
  2298  			state.Response.AddDiscordMessageAttachments(discordMessageAttachments)
  2299  		}
  2300  	}
  2301  
  2302  	err = m.checkForEdits(receivedMessage)
  2303  	if err != nil {
  2304  		return err
  2305  	}
  2306  
  2307  	err = m.checkForDeletes(receivedMessage)
  2308  	if err != nil {
  2309  		return err
  2310  	}
  2311  
  2312  	err = m.checkForDeleteForMes(receivedMessage)
  2313  	if err != nil {
  2314  		return err
  2315  	}
  2316  
  2317  	if !receivedMessage.Deleted && !receivedMessage.DeletedForMe {
  2318  		err = chat.UpdateFromMessage(receivedMessage, m.getTimesource())
  2319  		if err != nil {
  2320  			return err
  2321  		}
  2322  	}
  2323  	// Set in the modified maps chat
  2324  	state.Response.AddChat(chat)
  2325  	// TODO(samyoul) remove storing of an updated reference pointer?
  2326  	m.allChats.Store(chat.ID, chat)
  2327  
  2328  	if !isSyncMessage && receivedMessage.EnsName != "" {
  2329  		oldRecord, err := m.ensVerifier.Add(contact.ID, receivedMessage.EnsName, receivedMessage.Clock)
  2330  		if err != nil {
  2331  			m.logger.Warn("failed to verify ENS name", zap.Error(err))
  2332  		} else if oldRecord == nil {
  2333  			// If oldRecord is nil, a new verification process will take place
  2334  			// so we reset the record
  2335  			contact.ENSVerified = false
  2336  			state.ModifiedContacts.Store(contact.ID, true)
  2337  			state.AllContacts.Store(contact.ID, contact)
  2338  		}
  2339  	}
  2340  
  2341  	if !isSyncMessage && contact.DisplayName != receivedMessage.DisplayName && len(receivedMessage.DisplayName) != 0 {
  2342  		contact.DisplayName = receivedMessage.DisplayName
  2343  		state.ModifiedContacts.Store(contact.ID, true)
  2344  	}
  2345  
  2346  	if customizationColor := multiaccountscommon.IDToColorFallbackToBlue(receivedMessage.CustomizationColor); !isSyncMessage && receivedMessage.CustomizationColor != 0 && contact.CustomizationColor != customizationColor {
  2347  		contact.CustomizationColor = customizationColor
  2348  		state.ModifiedContacts.Store(contact.ID, true)
  2349  	}
  2350  
  2351  	if receivedMessage.ContentType == protobuf.ChatMessage_COMMUNITY {
  2352  		m.logger.Debug("Handling community content type")
  2353  
  2354  		signer, description, err := communities.UnwrapCommunityDescriptionMessage(receivedMessage.GetCommunity())
  2355  		if err != nil {
  2356  			return err
  2357  		}
  2358  
  2359  		err = m.handleCommunityDescription(state, signer, description, receivedMessage.GetCommunity(), nil, receivedMessage.GetShard())
  2360  		if err != nil {
  2361  			return err
  2362  		}
  2363  
  2364  		if len(description.ID) != 0 {
  2365  			receivedMessage.CommunityID = description.ID
  2366  		} else {
  2367  			// Backward compatibility
  2368  			receivedMessage.CommunityID = types.EncodeHex(crypto.CompressPubkey(signer))
  2369  		}
  2370  	}
  2371  
  2372  	err = m.addPeersyncingMessage(chat, state.CurrentMessageState.StatusMessage)
  2373  	if err != nil {
  2374  		m.logger.Warn("failed to add peersyncing message", zap.Error(err))
  2375  	}
  2376  
  2377  	// If we receive some propagated state from someone who's not
  2378  	// our paired device, we handle it
  2379  	if receivedMessage.ContactRequestPropagatedState != nil && !isSyncMessage {
  2380  		result := contact.ContactRequestPropagatedStateReceived(receivedMessage.ContactRequestPropagatedState)
  2381  		if result.sendBackState {
  2382  			_, err = m.sendContactUpdate(context.Background(), contact.ID, "", "", "", "", m.dispatchMessage)
  2383  			if err != nil {
  2384  				return err
  2385  			}
  2386  		}
  2387  		if result.newContactRequestReceived {
  2388  
  2389  			if contact.hasAddedUs() && !contact.mutual() {
  2390  				receivedMessage.ContactRequestState = common.ContactRequestStatePending
  2391  			}
  2392  
  2393  			// Add mutual state update message for outgoing contact request
  2394  			clock := receivedMessage.Clock - 1
  2395  			updateMessage, err := m.prepareMutualStateUpdateMessage(contact.ID, MutualStateUpdateTypeSent, clock, receivedMessage.Timestamp, false)
  2396  			if err != nil {
  2397  				return err
  2398  			}
  2399  
  2400  			err = m.prepareMessage(updateMessage, m.httpServer)
  2401  			if err != nil {
  2402  				return err
  2403  			}
  2404  			err = m.persistence.SaveMessages([]*common.Message{updateMessage})
  2405  			if err != nil {
  2406  				return err
  2407  			}
  2408  			state.Response.AddMessage(updateMessage)
  2409  
  2410  			err = m.createIncomingContactRequestNotification(contact, state, receivedMessage, true)
  2411  			if err != nil {
  2412  				return err
  2413  			}
  2414  		}
  2415  		state.ModifiedContacts.Store(contact.ID, true)
  2416  		state.AllContacts.Store(contact.ID, contact)
  2417  	}
  2418  
  2419  	if receivedMessage.ContentType == protobuf.ChatMessage_CONTACT_REQUEST && chat.OneToOne() {
  2420  		chatContact := contact
  2421  		if isSyncMessage {
  2422  			chatContact, err = m.BuildContact(&requests.BuildContact{PublicKey: chat.ID})
  2423  			if err != nil {
  2424  				return err
  2425  			}
  2426  		}
  2427  
  2428  		if receivedMessage.CustomizationColor != 0 {
  2429  			chatContact.CustomizationColor = multiaccountscommon.IDToColorFallbackToBlue(receivedMessage.CustomizationColor)
  2430  		}
  2431  
  2432  		if chatContact.mutual() || chatContact.dismissed() {
  2433  			m.logger.Info("ignoring contact request message for a mutual or dismissed contact")
  2434  			return nil
  2435  		}
  2436  
  2437  		sendNotification, err := handleContactRequestChatMessage(receivedMessage, chatContact, isSyncMessage, m.logger)
  2438  		if err != nil {
  2439  			m.logger.Error("failed to handle contact request message", zap.Error(err))
  2440  			return err
  2441  		}
  2442  		state.ModifiedContacts.Store(chatContact.ID, true)
  2443  		state.AllContacts.Store(chatContact.ID, chatContact)
  2444  
  2445  		if sendNotification {
  2446  			err = m.createIncomingContactRequestNotification(chatContact, state, receivedMessage, true)
  2447  			if err != nil {
  2448  				return err
  2449  			}
  2450  		}
  2451  	} else if receivedMessage.ContentType == protobuf.ChatMessage_COMMUNITY {
  2452  		chat.Highlight = true
  2453  	}
  2454  
  2455  	receivedMessage.New = true
  2456  	state.Response.AddMessage(receivedMessage)
  2457  
  2458  	return nil
  2459  }
  2460  
  2461  func (m *Messenger) addPeersyncingMessage(chat *Chat, msg *v1protocol.StatusMessage) error {
  2462  	if msg == nil {
  2463  		return nil
  2464  	}
  2465  	var syncMessageType peersyncing.SyncMessageType
  2466  	if chat.OneToOne() {
  2467  		syncMessageType = peersyncing.SyncMessageOneToOneType
  2468  	} else if chat.CommunityChat() {
  2469  		syncMessageType = peersyncing.SyncMessageCommunityType
  2470  	} else if chat.PrivateGroupChat() {
  2471  		syncMessageType = peersyncing.SyncMessagePrivateGroup
  2472  	}
  2473  	syncMessage := peersyncing.SyncMessage{
  2474  		Type:      syncMessageType,
  2475  		ID:        msg.ApplicationLayer.ID,
  2476  		ChatID:    []byte(chat.ID),
  2477  		Payload:   msg.EncryptionLayer.Payload,
  2478  		Timestamp: uint64(msg.TransportLayer.Message.Timestamp),
  2479  	}
  2480  	return m.peersyncing.Add(syncMessage)
  2481  }
  2482  
  2483  func (m *Messenger) HandleChatMessage(state *ReceivedMessageState, message *protobuf.ChatMessage, statusMessage *v1protocol.StatusMessage, fromArchive bool) error {
  2484  	state.CurrentMessageState.Message = message
  2485  	return m.handleChatMessage(state, fromArchive)
  2486  }
  2487  
  2488  func (m *Messenger) HandleRequestAddressForTransaction(messageState *ReceivedMessageState, command *protobuf.RequestAddressForTransaction, statusMessage *v1protocol.StatusMessage) error {
  2489  	err := ValidateReceivedRequestAddressForTransaction(command, messageState.CurrentMessageState.WhisperTimestamp)
  2490  	if err != nil {
  2491  		return err
  2492  	}
  2493  	message := &common.Message{
  2494  		ChatMessage: &protobuf.ChatMessage{
  2495  			Clock:     command.Clock,
  2496  			Timestamp: messageState.CurrentMessageState.WhisperTimestamp,
  2497  			Text:      "Request address for transaction",
  2498  			// ChatId is only used as-is for messages sent to oneself (i.e: mostly sync) so no need to check it here
  2499  			ChatId:      command.GetChatId(),
  2500  			MessageType: protobuf.MessageType_ONE_TO_ONE,
  2501  			ContentType: protobuf.ChatMessage_TRANSACTION_COMMAND,
  2502  		},
  2503  		CommandParameters: &common.CommandParameters{
  2504  			ID:           messageState.CurrentMessageState.MessageID,
  2505  			Value:        command.Value,
  2506  			Contract:     command.Contract,
  2507  			CommandState: common.CommandStateRequestAddressForTransaction,
  2508  		},
  2509  	}
  2510  	return m.handleCommandMessage(messageState, message)
  2511  }
  2512  
  2513  func (m *Messenger) HandleSyncSetting(messageState *ReceivedMessageState, message *protobuf.SyncSetting, statusMessage *v1protocol.StatusMessage) error {
  2514  	settingField, err := m.extractAndSaveSyncSetting(message)
  2515  	if err != nil {
  2516  		return err
  2517  	}
  2518  
  2519  	if settingField == nil {
  2520  		return nil
  2521  	}
  2522  
  2523  	switch message.GetType() {
  2524  	case protobuf.SyncSetting_DISPLAY_NAME:
  2525  		if newName := message.GetValueString(); newName != "" && m.account.Name != newName {
  2526  			m.account.Name = newName
  2527  			if err := m.multiAccounts.SaveAccount(*m.account); err != nil {
  2528  				return err
  2529  			}
  2530  		}
  2531  	case protobuf.SyncSetting_MNEMONIC_REMOVED:
  2532  		if message.GetValueBool() {
  2533  			if err := m.settings.DeleteMnemonic(); err != nil {
  2534  				return err
  2535  			}
  2536  			messageState.Response.AddSetting(&settings.SyncSettingField{SettingField: settings.Mnemonic})
  2537  		}
  2538  		return nil
  2539  	}
  2540  	messageState.Response.AddSetting(settingField)
  2541  	return nil
  2542  }
  2543  
  2544  func (m *Messenger) HandleSyncAccountCustomizationColor(state *ReceivedMessageState, message *protobuf.SyncAccountCustomizationColor, statusMessage *v1protocol.StatusMessage) error {
  2545  	affected, err := m.multiAccounts.UpdateAccountCustomizationColor(message.GetKeyUid(), message.GetCustomizationColor(), message.GetUpdatedAt())
  2546  	if err != nil {
  2547  		return err
  2548  	}
  2549  
  2550  	if affected > 0 {
  2551  		m.account.CustomizationColor = multiaccountscommon.CustomizationColor(message.GetCustomizationColor())
  2552  		state.Response.CustomizationColor = message.GetCustomizationColor()
  2553  	}
  2554  	return nil
  2555  }
  2556  
  2557  func (m *Messenger) HandleRequestTransaction(messageState *ReceivedMessageState, command *protobuf.RequestTransaction, statusMessage *v1protocol.StatusMessage) error {
  2558  	err := ValidateReceivedRequestTransaction(command, messageState.CurrentMessageState.WhisperTimestamp)
  2559  	if err != nil {
  2560  		return err
  2561  	}
  2562  	message := &common.Message{
  2563  		ChatMessage: &protobuf.ChatMessage{
  2564  			Clock:     command.Clock,
  2565  			Timestamp: messageState.CurrentMessageState.WhisperTimestamp,
  2566  			Text:      "Request transaction",
  2567  			// ChatId is only used for messages sent to oneself (i.e: mostly sync) so no need to check it here
  2568  			ChatId:      command.GetChatId(),
  2569  			MessageType: protobuf.MessageType_ONE_TO_ONE,
  2570  			ContentType: protobuf.ChatMessage_TRANSACTION_COMMAND,
  2571  		},
  2572  		CommandParameters: &common.CommandParameters{
  2573  			ID:           messageState.CurrentMessageState.MessageID,
  2574  			Value:        command.Value,
  2575  			Contract:     command.Contract,
  2576  			CommandState: common.CommandStateRequestTransaction,
  2577  			Address:      command.Address,
  2578  		},
  2579  	}
  2580  	return m.handleCommandMessage(messageState, message)
  2581  }
  2582  
  2583  func (m *Messenger) HandleAcceptRequestAddressForTransaction(messageState *ReceivedMessageState, command *protobuf.AcceptRequestAddressForTransaction, statusMessage *v1protocol.StatusMessage) error {
  2584  	err := ValidateReceivedAcceptRequestAddressForTransaction(command, messageState.CurrentMessageState.WhisperTimestamp)
  2585  	if err != nil {
  2586  		return err
  2587  	}
  2588  	initialMessage, err := m.persistence.MessageByID(command.Id)
  2589  	if err != nil {
  2590  		return err
  2591  	}
  2592  	if initialMessage == nil {
  2593  		return errors.New("message not found")
  2594  	}
  2595  
  2596  	if initialMessage.LocalChatID != messageState.CurrentMessageState.Contact.ID {
  2597  		return errors.New("From must match")
  2598  	}
  2599  
  2600  	if initialMessage.OutgoingStatus == "" {
  2601  		return errors.New("Initial message must originate from us")
  2602  	}
  2603  
  2604  	if initialMessage.CommandParameters.CommandState != common.CommandStateRequestAddressForTransaction {
  2605  		return errors.New("Wrong state for command")
  2606  	}
  2607  
  2608  	initialMessage.Clock = command.Clock
  2609  	initialMessage.Timestamp = messageState.CurrentMessageState.WhisperTimestamp
  2610  	initialMessage.Text = requestAddressForTransactionAcceptedMessage
  2611  	initialMessage.CommandParameters.Address = command.Address
  2612  	initialMessage.Seen = false
  2613  	initialMessage.CommandParameters.CommandState = common.CommandStateRequestAddressForTransactionAccepted
  2614  	initialMessage.ChatId = command.GetChatId()
  2615  
  2616  	// Hide previous message
  2617  	previousMessage, err := m.persistence.MessageByCommandID(messageState.CurrentMessageState.Contact.ID, command.Id)
  2618  	if err != nil && err != common.ErrRecordNotFound {
  2619  		return err
  2620  	}
  2621  
  2622  	if previousMessage != nil {
  2623  		err = m.persistence.HideMessage(previousMessage.ID)
  2624  		if err != nil {
  2625  			return err
  2626  		}
  2627  
  2628  		initialMessage.Replace = previousMessage.ID
  2629  	}
  2630  
  2631  	return m.handleCommandMessage(messageState, initialMessage)
  2632  }
  2633  
  2634  func (m *Messenger) HandleSendTransaction(messageState *ReceivedMessageState, command *protobuf.SendTransaction, statusMessage *v1protocol.StatusMessage) error {
  2635  	err := ValidateReceivedSendTransaction(command, messageState.CurrentMessageState.WhisperTimestamp)
  2636  	if err != nil {
  2637  		return err
  2638  	}
  2639  	transactionToValidate := &TransactionToValidate{
  2640  		MessageID:       messageState.CurrentMessageState.MessageID,
  2641  		CommandID:       command.Id,
  2642  		TransactionHash: command.TransactionHash,
  2643  		FirstSeen:       messageState.CurrentMessageState.WhisperTimestamp,
  2644  		Signature:       command.Signature,
  2645  		Validate:        true,
  2646  		From:            messageState.CurrentMessageState.PublicKey,
  2647  		RetryCount:      0,
  2648  	}
  2649  	m.logger.Info("Saving transction to validate", zap.Any("transaction", transactionToValidate))
  2650  
  2651  	return m.persistence.SaveTransactionToValidate(transactionToValidate)
  2652  }
  2653  
  2654  func (m *Messenger) HandleDeclineRequestAddressForTransaction(messageState *ReceivedMessageState, command *protobuf.DeclineRequestAddressForTransaction, statusMessage *v1protocol.StatusMessage) error {
  2655  	err := ValidateReceivedDeclineRequestAddressForTransaction(command, messageState.CurrentMessageState.WhisperTimestamp)
  2656  	if err != nil {
  2657  		return err
  2658  	}
  2659  	oldMessage, err := m.persistence.MessageByID(command.Id)
  2660  	if err != nil {
  2661  		return err
  2662  	}
  2663  	if oldMessage == nil {
  2664  		return errors.New("message not found")
  2665  	}
  2666  
  2667  	if oldMessage.LocalChatID != messageState.CurrentMessageState.Contact.ID {
  2668  		return errors.New("From must match")
  2669  	}
  2670  
  2671  	if oldMessage.OutgoingStatus == "" {
  2672  		return errors.New("Initial message must originate from us")
  2673  	}
  2674  
  2675  	if oldMessage.CommandParameters.CommandState != common.CommandStateRequestAddressForTransaction {
  2676  		return errors.New("Wrong state for command")
  2677  	}
  2678  
  2679  	oldMessage.Clock = command.Clock
  2680  	oldMessage.Timestamp = messageState.CurrentMessageState.WhisperTimestamp
  2681  	oldMessage.Text = requestAddressForTransactionDeclinedMessage
  2682  	oldMessage.Seen = false
  2683  	oldMessage.CommandParameters.CommandState = common.CommandStateRequestAddressForTransactionDeclined
  2684  	oldMessage.ChatId = command.GetChatId()
  2685  
  2686  	// Hide previous message
  2687  	err = m.persistence.HideMessage(command.Id)
  2688  	if err != nil {
  2689  		return err
  2690  	}
  2691  	oldMessage.Replace = command.Id
  2692  
  2693  	return m.handleCommandMessage(messageState, oldMessage)
  2694  }
  2695  
  2696  func (m *Messenger) HandleDeclineRequestTransaction(messageState *ReceivedMessageState, command *protobuf.DeclineRequestTransaction, statusMessage *v1protocol.StatusMessage) error {
  2697  	err := ValidateReceivedDeclineRequestTransaction(command, messageState.CurrentMessageState.WhisperTimestamp)
  2698  	if err != nil {
  2699  		return err
  2700  	}
  2701  	oldMessage, err := m.persistence.MessageByID(command.Id)
  2702  	if err != nil {
  2703  		return err
  2704  	}
  2705  	if oldMessage == nil {
  2706  		return errors.New("message not found")
  2707  	}
  2708  
  2709  	if oldMessage.LocalChatID != messageState.CurrentMessageState.Contact.ID {
  2710  		return errors.New("From must match")
  2711  	}
  2712  
  2713  	if oldMessage.OutgoingStatus == "" {
  2714  		return errors.New("Initial message must originate from us")
  2715  	}
  2716  
  2717  	if oldMessage.CommandParameters.CommandState != common.CommandStateRequestTransaction {
  2718  		return errors.New("Wrong state for command")
  2719  	}
  2720  
  2721  	oldMessage.Clock = command.Clock
  2722  	oldMessage.Timestamp = messageState.CurrentMessageState.WhisperTimestamp
  2723  	oldMessage.Text = transactionRequestDeclinedMessage
  2724  	oldMessage.Seen = false
  2725  	oldMessage.CommandParameters.CommandState = common.CommandStateRequestTransactionDeclined
  2726  	oldMessage.ChatId = command.GetChatId()
  2727  
  2728  	// Hide previous message
  2729  	err = m.persistence.HideMessage(command.Id)
  2730  	if err != nil {
  2731  		return err
  2732  	}
  2733  	oldMessage.Replace = command.Id
  2734  
  2735  	return m.handleCommandMessage(messageState, oldMessage)
  2736  }
  2737  
  2738  func (m *Messenger) matchChatEntity(chatEntity common.ChatEntity, messageType protobuf.ApplicationMetadataMessage_Type) (*Chat, error) {
  2739  	if chatEntity.GetSigPubKey() == nil {
  2740  		m.logger.Error("public key can't be empty")
  2741  		return nil, errors.New("received a chatEntity with empty public key")
  2742  	}
  2743  
  2744  	switch {
  2745  	case chatEntity.GetMessageType() == protobuf.MessageType_PUBLIC_GROUP:
  2746  		// For public messages, all outgoing and incoming messages have the same chatID
  2747  		// equal to a public chat name.
  2748  		chatID := chatEntity.GetChatId()
  2749  		chat, ok := m.allChats.Load(chatID)
  2750  		if !ok {
  2751  			return nil, errors.New("received a public chatEntity from non-existing chat")
  2752  		}
  2753  		if !chat.Public() && !chat.ProfileUpdates() && !chat.Timeline() {
  2754  			return nil, ErrMessageForWrongChatType
  2755  		}
  2756  		return chat, nil
  2757  	case chatEntity.GetMessageType() == protobuf.MessageType_ONE_TO_ONE && common.IsPubKeyEqual(chatEntity.GetSigPubKey(), &m.identity.PublicKey):
  2758  		// It's a private message coming from us so we rely on Message.ChatID
  2759  		// If chat does not exist, it should be created to support multidevice synchronization.
  2760  		chatID := chatEntity.GetChatId()
  2761  		chat, ok := m.allChats.Load(chatID)
  2762  		if !ok {
  2763  			if len(chatID) != PubKeyStringLength {
  2764  				return nil, errors.New("invalid pubkey length")
  2765  			}
  2766  			bytePubKey, err := hex.DecodeString(chatID[2:])
  2767  			if err != nil {
  2768  				return nil, errors.Wrap(err, "failed to decode hex chatID")
  2769  			}
  2770  
  2771  			pubKey, err := crypto.UnmarshalPubkey(bytePubKey)
  2772  			if err != nil {
  2773  				return nil, errors.Wrap(err, "failed to decode pubkey")
  2774  			}
  2775  
  2776  			chat = CreateOneToOneChat(chatID[:8], pubKey, m.getTimesource())
  2777  		}
  2778  		// if we are the sender, the chat must be active
  2779  		chat.Active = true
  2780  		return chat, nil
  2781  	case chatEntity.GetMessageType() == protobuf.MessageType_ONE_TO_ONE:
  2782  		// It's an incoming private chatEntity. ChatID is calculated from the signature.
  2783  		// If a chat does not exist, a new one is created and saved.
  2784  		chatID := contactIDFromPublicKey(chatEntity.GetSigPubKey())
  2785  		chat, ok := m.allChats.Load(chatID)
  2786  		if !ok {
  2787  			// TODO: this should be a three-word name used in the mobile client
  2788  			chat = CreateOneToOneChat(chatID[:8], chatEntity.GetSigPubKey(), m.getTimesource())
  2789  			chat.Active = false
  2790  		}
  2791  		// We set the chat as inactive and will create a notification
  2792  		// if it's not coming from a contact
  2793  		contact, ok := m.allContacts.Load(chatID)
  2794  		chat.Active = chat.Active || (ok && contact.added())
  2795  		return chat, nil
  2796  	case chatEntity.GetMessageType() == protobuf.MessageType_COMMUNITY_CHAT:
  2797  		chatID := chatEntity.GetChatId()
  2798  		chat, ok := m.allChats.Load(chatID)
  2799  		if !ok {
  2800  			return nil, errors.New("received community chat chatEntity for non-existing chat")
  2801  		}
  2802  
  2803  		if chat.CommunityID == "" || chat.ChatType != ChatTypeCommunityChat {
  2804  			return nil, errors.New("not an community chat")
  2805  		}
  2806  
  2807  		canPost, err := m.communitiesManager.CanPost(chatEntity.GetSigPubKey(), chat.CommunityID, chat.CommunityChatID(), messageType)
  2808  		if err != nil {
  2809  			return nil, err
  2810  		}
  2811  
  2812  		if !canPost {
  2813  			return nil, errors.New("user can't post in community")
  2814  		}
  2815  
  2816  		return chat, nil
  2817  
  2818  	case chatEntity.GetMessageType() == protobuf.MessageType_PRIVATE_GROUP:
  2819  		// In the case of a group chatEntity, ChatID is the same for all messages belonging to a group.
  2820  		// It needs to be verified if the signature public key belongs to the chat.
  2821  		chatID := chatEntity.GetChatId()
  2822  		chat, ok := m.allChats.Load(chatID)
  2823  		if !ok {
  2824  			return nil, errors.New("received group chat chatEntity for non-existing chat")
  2825  		}
  2826  
  2827  		senderKeyHex := contactIDFromPublicKey(chatEntity.GetSigPubKey())
  2828  		myKeyHex := contactIDFromPublicKey(&m.identity.PublicKey)
  2829  		senderIsMember := false
  2830  		iAmMember := false
  2831  		for _, member := range chat.Members {
  2832  			if member.ID == senderKeyHex {
  2833  				senderIsMember = true
  2834  			}
  2835  			if member.ID == myKeyHex {
  2836  				iAmMember = true
  2837  			}
  2838  		}
  2839  
  2840  		if senderIsMember && iAmMember {
  2841  			return chat, nil
  2842  		}
  2843  
  2844  		return nil, errors.New("did not find a matching group chat")
  2845  	default:
  2846  		return nil, errors.New("can not match a chat because there is no valid case")
  2847  	}
  2848  }
  2849  
  2850  func (m *Messenger) messageExists(messageID string, existingMessagesMap map[string]bool) (bool, error) {
  2851  	if _, ok := existingMessagesMap[messageID]; ok {
  2852  		return true, nil
  2853  	}
  2854  
  2855  	existingMessagesMap[messageID] = true
  2856  
  2857  	// Check against the database, this is probably a bit slow for
  2858  	// each message, but for now might do, we'll make it faster later
  2859  	existingMessage, err := m.persistence.MessageByID(messageID)
  2860  	if err != nil && err != common.ErrRecordNotFound {
  2861  		return false, err
  2862  	}
  2863  	if existingMessage != nil {
  2864  		return true, nil
  2865  	}
  2866  	return false, nil
  2867  }
  2868  
  2869  func (m *Messenger) HandleEmojiReaction(state *ReceivedMessageState, pbEmojiR *protobuf.EmojiReaction, statusMessage *v1protocol.StatusMessage) error {
  2870  	logger := m.logger.With(zap.String("site", "HandleEmojiReaction"))
  2871  	if err := ValidateReceivedEmojiReaction(pbEmojiR, state.Timesource.GetCurrentTime()); err != nil {
  2872  		logger.Error("invalid emoji reaction", zap.Error(err))
  2873  		return err
  2874  	}
  2875  
  2876  	from := state.CurrentMessageState.Contact.ID
  2877  
  2878  	emojiReaction := &EmojiReaction{
  2879  		EmojiReaction: pbEmojiR,
  2880  		From:          from,
  2881  		SigPubKey:     state.CurrentMessageState.PublicKey,
  2882  	}
  2883  
  2884  	existingEmoji, err := m.persistence.EmojiReactionByID(emojiReaction.ID())
  2885  	if err != common.ErrRecordNotFound && err != nil {
  2886  		return err
  2887  	}
  2888  
  2889  	if existingEmoji != nil && existingEmoji.Clock >= pbEmojiR.Clock {
  2890  		// this is not a valid emoji, ignoring
  2891  		return nil
  2892  	}
  2893  
  2894  	chat, err := m.matchChatEntity(emojiReaction, protobuf.ApplicationMetadataMessage_EMOJI_REACTION)
  2895  	if err != nil {
  2896  		return err // matchChatEntity returns a descriptive error message
  2897  	}
  2898  
  2899  	// Set local chat id
  2900  	emojiReaction.LocalChatID = chat.ID
  2901  
  2902  	logger.Debug("Handling emoji reaction")
  2903  
  2904  	if chat.LastClockValue < pbEmojiR.Clock {
  2905  		chat.LastClockValue = pbEmojiR.Clock
  2906  	}
  2907  
  2908  	state.Response.AddChat(chat)
  2909  	// TODO(samyoul) remove storing of an updated reference pointer?
  2910  	state.AllChats.Store(chat.ID, chat)
  2911  
  2912  	// save emoji reaction
  2913  	err = m.persistence.SaveEmojiReaction(emojiReaction)
  2914  	if err != nil {
  2915  		return err
  2916  	}
  2917  
  2918  	state.EmojiReactions[emojiReaction.ID()] = emojiReaction
  2919  
  2920  	return nil
  2921  }
  2922  
  2923  func (m *Messenger) HandleGroupChatInvitation(state *ReceivedMessageState, pbGHInvitations *protobuf.GroupChatInvitation, statusMessage *v1protocol.StatusMessage) error {
  2924  	allowed, err := m.isMessageAllowedFrom(state.CurrentMessageState.Contact.ID, nil)
  2925  	if err != nil {
  2926  		return err
  2927  	}
  2928  
  2929  	if !allowed {
  2930  		return ErrMessageNotAllowed
  2931  	}
  2932  	logger := m.logger.With(zap.String("site", "HandleGroupChatInvitation"))
  2933  	if err := ValidateReceivedGroupChatInvitation(pbGHInvitations); err != nil {
  2934  		logger.Error("invalid group chat invitation", zap.Error(err))
  2935  		return err
  2936  	}
  2937  
  2938  	groupChatInvitation := &GroupChatInvitation{
  2939  		GroupChatInvitation: pbGHInvitations,
  2940  		SigPubKey:           state.CurrentMessageState.PublicKey,
  2941  	}
  2942  
  2943  	//From is the PK of author of invitation request
  2944  	if groupChatInvitation.State == protobuf.GroupChatInvitation_REJECTED {
  2945  		//rejected so From is the current user who received this rejection
  2946  		groupChatInvitation.From = types.EncodeHex(crypto.FromECDSAPub(&m.identity.PublicKey))
  2947  	} else {
  2948  		//invitation request, so From is the author of message
  2949  		groupChatInvitation.From = state.CurrentMessageState.Contact.ID
  2950  	}
  2951  
  2952  	existingInvitation, err := m.persistence.InvitationByID(groupChatInvitation.ID())
  2953  	if err != common.ErrRecordNotFound && err != nil {
  2954  		return err
  2955  	}
  2956  
  2957  	if existingInvitation != nil && existingInvitation.Clock >= pbGHInvitations.Clock {
  2958  		// this is not a valid invitation, ignoring
  2959  		return nil
  2960  	}
  2961  
  2962  	// save invitation
  2963  	err = m.persistence.SaveInvitation(groupChatInvitation)
  2964  	if err != nil {
  2965  		return err
  2966  	}
  2967  
  2968  	state.GroupChatInvitations[groupChatInvitation.ID()] = groupChatInvitation
  2969  
  2970  	return nil
  2971  }
  2972  
  2973  func (m *Messenger) HandleContactCodeAdvertisement(state *ReceivedMessageState, cca *protobuf.ContactCodeAdvertisement, statusMessage *v1protocol.StatusMessage) error {
  2974  	if cca.ChatIdentity == nil {
  2975  		return nil
  2976  	}
  2977  	return m.HandleChatIdentity(state, cca.ChatIdentity, nil)
  2978  }
  2979  
  2980  // HandleChatIdentity handles an incoming protobuf.ChatIdentity
  2981  // extracts contact information stored in the protobuf and adds it to the user's contact for update.
  2982  func (m *Messenger) HandleChatIdentity(state *ReceivedMessageState, ci *protobuf.ChatIdentity, statusMessage *v1protocol.StatusMessage) error {
  2983  	s, err := m.settings.GetSettings()
  2984  	if err != nil {
  2985  		return err
  2986  	}
  2987  
  2988  	contact := state.CurrentMessageState.Contact
  2989  	viewFromContacts := s.ProfilePicturesVisibility == settings.ProfilePicturesVisibilityContactsOnly
  2990  	viewFromNoOne := s.ProfilePicturesVisibility == settings.ProfilePicturesVisibilityNone
  2991  
  2992  	m.logger.Debug("settings found",
  2993  		zap.Bool("viewFromContacts", viewFromContacts),
  2994  		zap.Bool("viewFromNoOne", viewFromNoOne),
  2995  	)
  2996  
  2997  	// If we don't want to view profile images from anyone, don't process identity images.
  2998  	// We don't want to store the profile images of other users, even if we don't display images.
  2999  	inOurContacts, ok := m.allContacts.Load(state.CurrentMessageState.Contact.ID)
  3000  
  3001  	isContact := ok && inOurContacts.added()
  3002  	if viewFromNoOne && !isContact {
  3003  		return nil
  3004  	}
  3005  
  3006  	// If there are no images attached to a ChatIdentity, check if message is allowed
  3007  	// Or if there are images and visibility is set to from contacts only, check if message is allowed
  3008  	// otherwise process the images without checking if the message is allowed
  3009  	if len(ci.Images) == 0 || (len(ci.Images) > 0 && (viewFromContacts)) {
  3010  		allowed, err := m.isMessageAllowedFrom(state.CurrentMessageState.Contact.ID, nil)
  3011  		if err != nil {
  3012  			return err
  3013  		}
  3014  
  3015  		if !allowed {
  3016  			return ErrMessageNotAllowed
  3017  		}
  3018  	}
  3019  
  3020  	err = DecryptIdentityImagesWithIdentityPrivateKey(ci.Images, m.identity, state.CurrentMessageState.PublicKey)
  3021  	if err != nil {
  3022  		return err
  3023  	}
  3024  
  3025  	// Remove any images still encrypted after the decryption process
  3026  	for name, image := range ci.Images {
  3027  		if image.Encrypted {
  3028  			delete(ci.Images, name)
  3029  		}
  3030  	}
  3031  
  3032  	if len(ci.Images) == 0 {
  3033  		contact.Images = nil
  3034  	}
  3035  
  3036  	clockChanged, imagesChanged, err := m.persistence.UpdateContactChatIdentity(contact.ID, ci)
  3037  	if err != nil {
  3038  		return err
  3039  	}
  3040  	contactModified := false
  3041  
  3042  	if imagesChanged {
  3043  		for imageType, image := range ci.Images {
  3044  			if contact.Images == nil {
  3045  				contact.Images = make(map[string]images.IdentityImage)
  3046  			}
  3047  			contact.Images[imageType] = images.IdentityImage{Name: imageType, Payload: image.Payload, Clock: ci.Clock}
  3048  
  3049  		}
  3050  		if err = m.updateContactImagesURL(contact); err != nil {
  3051  			return err
  3052  		}
  3053  
  3054  		contactModified = true
  3055  	}
  3056  
  3057  	if clockChanged {
  3058  		if err = utils.ValidateDisplayName(&ci.DisplayName); err != nil {
  3059  			return err
  3060  		}
  3061  
  3062  		if contact.DisplayName != ci.DisplayName && len(ci.DisplayName) != 0 {
  3063  			contact.DisplayName = ci.DisplayName
  3064  			contactModified = true
  3065  		}
  3066  
  3067  		if customizationColor := multiaccountscommon.IDToColorFallbackToBlue(ci.CustomizationColor); contact.CustomizationColor != customizationColor {
  3068  			contact.CustomizationColor = customizationColor
  3069  			contactModified = true
  3070  		}
  3071  
  3072  		if err = ValidateBio(&ci.Description); err != nil {
  3073  			return err
  3074  		}
  3075  
  3076  		if contact.Bio != ci.Description {
  3077  			contact.Bio = ci.Description
  3078  			contactModified = true
  3079  		}
  3080  
  3081  		if ci.ProfileShowcase != nil {
  3082  			err := m.BuildProfileShowcaseFromIdentity(state, ci.ProfileShowcase)
  3083  			if err != nil {
  3084  				return err
  3085  			}
  3086  			state.Response.AddUpdatedProfileShowcaseContactID(contact.ID)
  3087  		}
  3088  	}
  3089  
  3090  	if contactModified {
  3091  		state.ModifiedContacts.Store(contact.ID, true)
  3092  		state.AllContacts.Store(contact.ID, contact)
  3093  	}
  3094  
  3095  	return nil
  3096  }
  3097  
  3098  func (m *Messenger) HandleAnonymousMetricBatch(state *ReceivedMessageState, amb *protobuf.AnonymousMetricBatch, statusMessage *v1protocol.StatusMessage) error {
  3099  
  3100  	// TODO
  3101  	return nil
  3102  }
  3103  
  3104  func (m *Messenger) checkForEdits(message *common.Message) error {
  3105  	// Check for any pending edit
  3106  	// If any pending edits are available and valid, apply them
  3107  	edits, err := m.persistence.GetEdits(message.ID, message.From)
  3108  	if err != nil {
  3109  		return err
  3110  	}
  3111  
  3112  	if len(edits) == 0 {
  3113  		return nil
  3114  	}
  3115  
  3116  	// Apply the first edit that is valid
  3117  	for _, e := range edits {
  3118  		if e.Clock >= message.Clock {
  3119  			// Update message and return it
  3120  			err := m.applyEditMessage(e.EditMessage, message)
  3121  			if err != nil {
  3122  				return err
  3123  			}
  3124  			return nil
  3125  		}
  3126  	}
  3127  
  3128  	return nil
  3129  }
  3130  
  3131  func (m *Messenger) getMessagesToCheckForDelete(message *common.Message) ([]*common.Message, error) {
  3132  	var messagesToCheck []*common.Message
  3133  	if message.ContentType == protobuf.ChatMessage_IMAGE {
  3134  		image := message.GetImage()
  3135  		if image != nil && image.AlbumId != "" {
  3136  			messagesInTheAlbum, err := m.persistence.albumMessages(message.ChatId, image.GetAlbumId())
  3137  			if err != nil {
  3138  				return nil, err
  3139  			}
  3140  			messagesToCheck = append(messagesToCheck, messagesInTheAlbum...)
  3141  		}
  3142  	}
  3143  	messagesToCheck = append(messagesToCheck, message)
  3144  	return messagesToCheck, nil
  3145  }
  3146  
  3147  func (m *Messenger) checkForDeletes(message *common.Message) error {
  3148  	// Get all messages part of the album
  3149  	messagesToCheck, err := m.getMessagesToCheckForDelete(message)
  3150  	if err != nil {
  3151  		return err
  3152  	}
  3153  
  3154  	var messageDeletes []*DeleteMessage
  3155  	applyDelete := false
  3156  	// Loop all messages part of the album, if one of them is marked as deleted, we delete them all
  3157  	for _, messageToCheck := range messagesToCheck {
  3158  		// Check for any pending deletes
  3159  		// If any pending deletes are available and valid, apply them
  3160  		messageDeletes, err = m.persistence.GetDeletes(messageToCheck.ID, messageToCheck.From)
  3161  		if err != nil {
  3162  			return err
  3163  		}
  3164  
  3165  		if len(messageDeletes) == 0 {
  3166  			continue
  3167  		}
  3168  		// Once one messageDelete has been found, we apply it to all the images in the album
  3169  		applyDelete = true
  3170  		break
  3171  	}
  3172  	if applyDelete {
  3173  		for _, messageToCheck := range messagesToCheck {
  3174  			err := m.applyDeleteMessage(messageDeletes, messageToCheck)
  3175  			if err != nil {
  3176  				return err
  3177  			}
  3178  		}
  3179  	}
  3180  	return nil
  3181  }
  3182  
  3183  func (m *Messenger) checkForDeleteForMes(message *common.Message) error {
  3184  	messagesToCheck, err := m.getMessagesToCheckForDelete(message)
  3185  	if err != nil {
  3186  		return err
  3187  	}
  3188  
  3189  	var messageDeleteForMes []*protobuf.SyncDeleteForMeMessage
  3190  	applyDelete := false
  3191  	for _, messageToCheck := range messagesToCheck {
  3192  		if !applyDelete {
  3193  			// Check for any pending delete for mes
  3194  			// If any pending deletes are available and valid, apply them
  3195  			messageDeleteForMes, err = m.persistence.GetDeleteForMeMessagesByMessageID(messageToCheck.ID)
  3196  			if err != nil {
  3197  				return err
  3198  			}
  3199  
  3200  			if len(messageDeleteForMes) == 0 {
  3201  				continue
  3202  			}
  3203  		}
  3204  		// Once one messageDeleteForMes has been found, we apply it to all the images in the album
  3205  		applyDelete = true
  3206  
  3207  		err := m.applyDeleteForMeMessage(messageToCheck)
  3208  		if err != nil {
  3209  			return err
  3210  		}
  3211  	}
  3212  	return nil
  3213  }
  3214  
  3215  func (m *Messenger) isMessageAllowedFrom(publicKey string, chat *Chat) (bool, error) {
  3216  	onlyFromContacts, err := m.settings.GetMessagesFromContactsOnly()
  3217  	if err != nil {
  3218  		return false, err
  3219  	}
  3220  
  3221  	if !onlyFromContacts {
  3222  		return true, nil
  3223  	}
  3224  
  3225  	// if it's from us, it's allowed
  3226  	if m.myHexIdentity() == publicKey {
  3227  		return true, nil
  3228  	}
  3229  
  3230  	// If the chat is public, we allow it
  3231  	if chat != nil && chat.Public() {
  3232  		return true, nil
  3233  	}
  3234  
  3235  	contact, contactOk := m.allContacts.Load(publicKey)
  3236  
  3237  	// If the chat is active, we allow it
  3238  	if chat != nil && chat.Active {
  3239  		if contactOk {
  3240  			// If the chat is active and it is a 1x1 chat, we need to make sure the contact is added and not removed
  3241  			return contact.added(), nil
  3242  		}
  3243  		return true, nil
  3244  	}
  3245  
  3246  	if !contactOk {
  3247  		// If it's not in contacts, we don't allow it
  3248  		return false, nil
  3249  	}
  3250  
  3251  	// Otherwise we check if we added it
  3252  	return contact.added(), nil
  3253  }
  3254  
  3255  func (m *Messenger) updateUnviewedCounts(chat *Chat, message *common.Message) {
  3256  	chat.UnviewedMessagesCount++
  3257  	if message.Mentioned || message.Replied || chat.OneToOne() {
  3258  		chat.UnviewedMentionsCount++
  3259  	}
  3260  }
  3261  
  3262  func mapSyncAccountToAccount(message *protobuf.SyncAccount, accountOperability accounts.AccountOperable, accType accounts.AccountType) *accounts.Account {
  3263  	return &accounts.Account{
  3264  		Address:               types.BytesToAddress(message.Address),
  3265  		KeyUID:                message.KeyUid,
  3266  		PublicKey:             types.HexBytes(message.PublicKey),
  3267  		Type:                  accType,
  3268  		Path:                  message.Path,
  3269  		Name:                  message.Name,
  3270  		ColorID:               multiaccountscommon.CustomizationColor(message.ColorId),
  3271  		Emoji:                 message.Emoji,
  3272  		Wallet:                message.Wallet,
  3273  		Chat:                  message.Chat,
  3274  		Hidden:                message.Hidden,
  3275  		Clock:                 message.Clock,
  3276  		Operable:              accountOperability,
  3277  		Removed:               message.Removed,
  3278  		Position:              message.Position,
  3279  		ProdPreferredChainIDs: message.ProdPreferredChainIDs,
  3280  		TestPreferredChainIDs: message.TestPreferredChainIDs,
  3281  	}
  3282  }
  3283  
  3284  func (m *Messenger) resolveAccountOperability(syncAcc *protobuf.SyncAccount, recoverinrecoveringFromWakuInitiatedByKeycard bool,
  3285  	syncKpMigratedToKeycard bool, dbKpMigratedToKeycard bool, accountReceivedFromLocalPairing bool) (accounts.AccountOperable, error) {
  3286  	if accountReceivedFromLocalPairing {
  3287  		return accounts.AccountOperable(syncAcc.Operable), nil
  3288  	}
  3289  
  3290  	if syncKpMigratedToKeycard || recoverinrecoveringFromWakuInitiatedByKeycard && m.account.KeyUID == syncAcc.KeyUid {
  3291  		return accounts.AccountFullyOperable, nil
  3292  	}
  3293  
  3294  	accountsOperability := accounts.AccountNonOperable
  3295  	dbAccount, err := m.settings.GetAccountByAddress(types.BytesToAddress(syncAcc.Address))
  3296  	if err != nil && err != accounts.ErrDbAccountNotFound {
  3297  		return accountsOperability, err
  3298  	}
  3299  	if dbAccount != nil {
  3300  		// We're here when we receive a keypair from the paired device which has just migrated from keycard to app.
  3301  		if !syncKpMigratedToKeycard && dbKpMigratedToKeycard {
  3302  			return accounts.AccountNonOperable, nil
  3303  		}
  3304  		return dbAccount.Operable, nil
  3305  	}
  3306  
  3307  	if !syncKpMigratedToKeycard {
  3308  		// We're here when we receive a keypair from the paired device which is either:
  3309  		// 1. regular keypair or
  3310  		// 2. was just converted from keycard to a regular keypair.
  3311  		dbKeycardsForKeyUID, err := m.settings.GetKeycardsWithSameKeyUID(syncAcc.KeyUid)
  3312  		if err != nil {
  3313  			return accounts.AccountNonOperable, err
  3314  		}
  3315  
  3316  		if len(dbKeycardsForKeyUID) > 0 {
  3317  			// We're here in case 2. from above and in this case we need to mark all accounts for this keypair non operable
  3318  			return accounts.AccountNonOperable, nil
  3319  		}
  3320  	}
  3321  
  3322  	if syncAcc.Chat || syncAcc.Wallet {
  3323  		accountsOperability = accounts.AccountFullyOperable
  3324  	} else {
  3325  		partiallyOrFullyOperable, err := m.settings.IsAnyAccountPartiallyOrFullyOperableForKeyUID(syncAcc.KeyUid)
  3326  		if err != nil {
  3327  			if err == accounts.ErrDbKeypairNotFound {
  3328  				return accounts.AccountNonOperable, nil
  3329  			}
  3330  			return accounts.AccountNonOperable, err
  3331  		}
  3332  		if partiallyOrFullyOperable {
  3333  			accountsOperability = accounts.AccountPartiallyOperable
  3334  		}
  3335  	}
  3336  
  3337  	return accountsOperability, nil
  3338  }
  3339  
  3340  func (m *Messenger) handleSyncWatchOnlyAccount(message *protobuf.SyncAccount, fromBackup bool) (*accounts.Account, error) {
  3341  	if message.KeyUid != "" {
  3342  		return nil, ErrNotWatchOnlyAccount
  3343  	}
  3344  
  3345  	accountOperability := accounts.AccountFullyOperable
  3346  
  3347  	accAddress := types.BytesToAddress(message.Address)
  3348  	dbAccount, err := m.settings.GetAccountByAddress(accAddress)
  3349  	if err != nil && err != accounts.ErrDbAccountNotFound {
  3350  		return nil, err
  3351  	}
  3352  
  3353  	if dbAccount != nil {
  3354  		if message.Clock <= dbAccount.Clock {
  3355  			return nil, ErrTryingToStoreOldWalletAccount
  3356  		}
  3357  
  3358  		if message.Removed {
  3359  			err = m.settings.RemoveAccount(accAddress, message.Clock)
  3360  			if err != nil {
  3361  				return nil, err
  3362  			}
  3363  			// if keypair is retrieved from backed up data, no need for resolving accounts positions
  3364  			if !fromBackup {
  3365  				err = m.settings.ResolveAccountsPositions(message.Clock)
  3366  				if err != nil {
  3367  					return nil, err
  3368  				}
  3369  			}
  3370  			dbAccount.Removed = true
  3371  			return dbAccount, nil
  3372  		}
  3373  	}
  3374  
  3375  	acc := mapSyncAccountToAccount(message, accountOperability, accounts.AccountTypeWatch)
  3376  
  3377  	err = m.settings.SaveOrUpdateAccounts([]*accounts.Account{acc}, false)
  3378  	if err != nil {
  3379  		return nil, err
  3380  	}
  3381  
  3382  	if m.config.accountsFeed != nil {
  3383  		var eventType accountsevent.EventType
  3384  		if acc.Removed {
  3385  			eventType = accountsevent.EventTypeRemoved
  3386  		} else {
  3387  			eventType = accountsevent.EventTypeAdded
  3388  		}
  3389  		m.config.accountsFeed.Send(accountsevent.Event{
  3390  			Type:     eventType,
  3391  			Accounts: []gethcommon.Address{gethcommon.Address(acc.Address)},
  3392  		})
  3393  	}
  3394  	return acc, nil
  3395  }
  3396  
  3397  func (m *Messenger) handleSyncTokenPreferences(message *protobuf.SyncTokenPreferences) ([]walletsettings.TokenPreferences, error) {
  3398  	if len(message.Preferences) == 0 {
  3399  		return nil, nil
  3400  	}
  3401  
  3402  	dbLastUpdate, err := m.settings.GetClockOfLastTokenPreferencesChange()
  3403  	if err != nil {
  3404  		return nil, err
  3405  	}
  3406  
  3407  	groupByCommunity, err := m.settings.GetTokenGroupByCommunity()
  3408  	if err != nil {
  3409  		return nil, err
  3410  	}
  3411  
  3412  	// Since adding new token preferences updates `ClockOfLastTokenPreferencesChange` we should handle token preferences changes
  3413  	// even they are with the same clock, that ensures the correct order in case of syncing devices.
  3414  	if message.Clock < dbLastUpdate {
  3415  		return nil, ErrTryingToApplyOldTokenPreferences
  3416  	}
  3417  
  3418  	var tokenPreferences []walletsettings.TokenPreferences
  3419  	for _, pref := range message.Preferences {
  3420  		tokenPref := walletsettings.TokenPreferences{
  3421  			Key:           pref.Key,
  3422  			Position:      int(pref.Position),
  3423  			GroupPosition: int(pref.GroupPosition),
  3424  			Visible:       pref.Visible,
  3425  			CommunityID:   pref.CommunityId,
  3426  		}
  3427  		tokenPreferences = append(tokenPreferences, tokenPref)
  3428  	}
  3429  
  3430  	err = m.settings.UpdateTokenPreferences(tokenPreferences, groupByCommunity, message.Testnet, message.Clock)
  3431  	if err != nil {
  3432  		return nil, err
  3433  	}
  3434  	return tokenPreferences, nil
  3435  }
  3436  
  3437  func (m *Messenger) handleSyncCollectiblePreferences(message *protobuf.SyncCollectiblePreferences) ([]walletsettings.CollectiblePreferences, error) {
  3438  	if len(message.Preferences) == 0 {
  3439  		return nil, nil
  3440  	}
  3441  
  3442  	dbLastUpdate, err := m.settings.GetClockOfLastCollectiblePreferencesChange()
  3443  	if err != nil {
  3444  		return nil, err
  3445  	}
  3446  
  3447  	groupByCommunity, err := m.settings.GetCollectibleGroupByCommunity()
  3448  	if err != nil {
  3449  		return nil, err
  3450  	}
  3451  
  3452  	groupByCollection, err := m.settings.GetCollectibleGroupByCollection()
  3453  	if err != nil {
  3454  		return nil, err
  3455  	}
  3456  
  3457  	// Since adding new collectible preferences updates `ClockOfLastCollectiblePreferencesChange` we should handle collectible
  3458  	// preferences changes even they are with the same clock, that ensures the correct order in case of syncing devices.
  3459  	if message.Clock < dbLastUpdate {
  3460  		return nil, ErrTryingToApplyOldCollectiblePreferences
  3461  	}
  3462  
  3463  	var collectiblePreferences []walletsettings.CollectiblePreferences
  3464  	for _, pref := range message.Preferences {
  3465  		collectiblePref := walletsettings.CollectiblePreferences{
  3466  			Type:     walletsettings.CollectiblePreferencesType(pref.Type),
  3467  			Key:      pref.Key,
  3468  			Position: int(pref.Position),
  3469  			Visible:  pref.Visible,
  3470  		}
  3471  		collectiblePreferences = append(collectiblePreferences, collectiblePref)
  3472  	}
  3473  
  3474  	err = m.settings.UpdateCollectiblePreferences(collectiblePreferences, groupByCommunity, groupByCollection, message.Testnet, message.Clock)
  3475  	if err != nil {
  3476  		return nil, err
  3477  	}
  3478  	return collectiblePreferences, nil
  3479  }
  3480  
  3481  func (m *Messenger) handleSyncAccountsPositions(message *protobuf.SyncAccountsPositions) ([]*accounts.Account, error) {
  3482  	if len(message.Accounts) == 0 {
  3483  		return nil, nil
  3484  	}
  3485  
  3486  	dbLastUpdate, err := m.settings.GetClockOfLastAccountsPositionChange()
  3487  	if err != nil {
  3488  		return nil, err
  3489  	}
  3490  
  3491  	// Since adding new account updates `ClockOfLastAccountsPositionChange` we should handle account order changes
  3492  	// even they are with the same clock, that ensures the correct order in case of syncing devices.
  3493  	if message.Clock < dbLastUpdate {
  3494  		return nil, ErrTryingToApplyOldWalletAccountsOrder
  3495  	}
  3496  
  3497  	var accs []*accounts.Account
  3498  	for _, sAcc := range message.Accounts {
  3499  		acc := &accounts.Account{
  3500  			Address:  types.BytesToAddress(sAcc.Address),
  3501  			KeyUID:   sAcc.KeyUid,
  3502  			Position: sAcc.Position,
  3503  		}
  3504  		accs = append(accs, acc)
  3505  	}
  3506  
  3507  	err = m.settings.SetWalletAccountsPositions(accs, message.Clock)
  3508  	if err != nil {
  3509  		return nil, err
  3510  	}
  3511  
  3512  	return accs, nil
  3513  }
  3514  
  3515  func (m *Messenger) handleProfileKeypairMigration(state *ReceivedMessageState, fromLocalPairing bool, message *protobuf.SyncKeypair) (handled bool, err error) {
  3516  	if message == nil {
  3517  		return false, errors.New("handleProfileKeypairMigration receive a nil message")
  3518  	}
  3519  
  3520  	if fromLocalPairing {
  3521  		return false, nil
  3522  	}
  3523  
  3524  	if m.account.KeyUID != message.KeyUid {
  3525  		return false, nil
  3526  	}
  3527  
  3528  	dbKeypair, err := m.settings.GetKeypairByKeyUID(message.KeyUid)
  3529  	if err != nil {
  3530  		return false, err
  3531  	}
  3532  
  3533  	if dbKeypair.Clock >= message.Clock {
  3534  		return false, nil
  3535  	}
  3536  
  3537  	migrationNeeded := dbKeypair.MigratedToKeycard() && len(message.Keycards) == 0 || // `true` if profile keypair was migrated to the app on one of paired devices
  3538  		!dbKeypair.MigratedToKeycard() && len(message.Keycards) > 0 // `true` if profile keypair was migrated to a Keycard on one of paired devices
  3539  	err = m.settings.SaveSettingField(settings.ProfileMigrationNeeded, migrationNeeded)
  3540  	if err != nil {
  3541  		return false, err
  3542  	}
  3543  
  3544  	state.Response.AddSetting(&settings.SyncSettingField{SettingField: settings.ProfileMigrationNeeded, Value: migrationNeeded})
  3545  
  3546  	return migrationNeeded, nil
  3547  }
  3548  
  3549  func (m *Messenger) handleSyncKeypair(message *protobuf.SyncKeypair, fromLocalPairing bool, acNofificationCallback func() error) (*accounts.Keypair, error) {
  3550  	if message == nil {
  3551  		return nil, errors.New("handleSyncKeypair receive a nil message")
  3552  	}
  3553  	dbKeypair, err := m.settings.GetKeypairByKeyUID(message.KeyUid)
  3554  	if err != nil && err != accounts.ErrDbKeypairNotFound {
  3555  		return nil, err
  3556  	}
  3557  
  3558  	kp := &accounts.Keypair{
  3559  		KeyUID:                  message.KeyUid,
  3560  		Name:                    message.Name,
  3561  		Type:                    accounts.KeypairType(message.Type),
  3562  		DerivedFrom:             message.DerivedFrom,
  3563  		LastUsedDerivationIndex: message.LastUsedDerivationIndex,
  3564  		SyncedFrom:              message.SyncedFrom,
  3565  		Clock:                   message.Clock,
  3566  		Removed:                 message.Removed,
  3567  	}
  3568  
  3569  	if dbKeypair != nil {
  3570  		if dbKeypair.Clock >= kp.Clock {
  3571  			return nil, ErrTryingToStoreOldKeypair
  3572  		}
  3573  		// in case of keypair update, we need to keep `synced_from` field as it was when keypair was introduced to this device for the first time
  3574  		// but in case if keypair on this device came from the backup (e.g. device A recovered from waku, then device B paired with the device A
  3575  		// via local pairing, before device A made its keypairs fully operable) we need to update syncedFrom when user on this device when that
  3576  		// keypair becomes operable on any of other paired devices
  3577  		if dbKeypair.SyncedFrom != accounts.SyncedFromBackup {
  3578  			kp.SyncedFrom = dbKeypair.SyncedFrom
  3579  		}
  3580  	}
  3581  
  3582  	syncKpMigratedToKeycard := len(message.Keycards) > 0
  3583  	recoveringFromWaku := message.SyncedFrom == accounts.SyncedFromBackup
  3584  
  3585  	multiAcc, err := m.multiAccounts.GetAccount(kp.KeyUID)
  3586  	if err != nil {
  3587  		return nil, err
  3588  	}
  3589  	recoverinrecoveringFromWakuInitiatedByKeycard := recoveringFromWaku && multiAcc != nil && multiAcc.RefersToKeycard()
  3590  	for _, sAcc := range message.Accounts {
  3591  		accountOperability, err := m.resolveAccountOperability(sAcc,
  3592  			recoverinrecoveringFromWakuInitiatedByKeycard,
  3593  			syncKpMigratedToKeycard,
  3594  			dbKeypair != nil && dbKeypair.MigratedToKeycard(),
  3595  			fromLocalPairing)
  3596  		if err != nil {
  3597  			return nil, err
  3598  		}
  3599  		acc := mapSyncAccountToAccount(sAcc, accountOperability, accounts.GetAccountTypeForKeypairType(kp.Type))
  3600  
  3601  		kp.Accounts = append(kp.Accounts, acc)
  3602  	}
  3603  
  3604  	if !fromLocalPairing && !recoverinrecoveringFromWakuInitiatedByKeycard {
  3605  		if kp.Removed ||
  3606  			dbKeypair != nil && !dbKeypair.MigratedToKeycard() && syncKpMigratedToKeycard {
  3607  			// delete all keystore files
  3608  			err = m.deleteKeystoreFilesForKeypair(dbKeypair)
  3609  			if err != nil {
  3610  				return nil, err
  3611  			}
  3612  
  3613  			if syncKpMigratedToKeycard {
  3614  				err = m.settings.MarkKeypairFullyOperable(dbKeypair.KeyUID, 0, false)
  3615  				if err != nil {
  3616  					return nil, err
  3617  				}
  3618  			}
  3619  		} else if dbKeypair != nil {
  3620  			for _, dbAcc := range dbKeypair.Accounts {
  3621  				removeAcc := false
  3622  				for _, acc := range kp.Accounts {
  3623  					if dbAcc.Address == acc.Address && acc.Removed && !dbAcc.Removed {
  3624  						removeAcc = true
  3625  						break
  3626  					}
  3627  				}
  3628  				if removeAcc {
  3629  					err = m.deleteKeystoreFileForAddress(dbAcc.Address)
  3630  					if err != nil {
  3631  						return nil, err
  3632  					}
  3633  				}
  3634  			}
  3635  		}
  3636  	}
  3637  
  3638  	// deleting keypair will delete related keycards as well
  3639  	err = m.settings.RemoveKeypair(message.KeyUid, message.Clock)
  3640  	if err != nil && err != accounts.ErrDbKeypairNotFound {
  3641  		return nil, err
  3642  	}
  3643  
  3644  	// if entire keypair was removed and keypair is already in db, there is no point to continue
  3645  	if kp.Removed && dbKeypair != nil {
  3646  		// if keypair is retrieved from backed up data, no need for resolving accounts positions
  3647  		if message.SyncedFrom != accounts.SyncedFromBackup {
  3648  			err = m.settings.ResolveAccountsPositions(message.Clock)
  3649  			if err != nil {
  3650  				return nil, err
  3651  			}
  3652  		}
  3653  		return kp, nil
  3654  	}
  3655  
  3656  	// save keypair first
  3657  	err = m.settings.SaveOrUpdateKeypair(kp)
  3658  	if err != nil {
  3659  		return nil, err
  3660  	}
  3661  
  3662  	// if keypair is retrieved from backed up data, no need for resolving accounts positions
  3663  	if message.SyncedFrom != accounts.SyncedFromBackup {
  3664  		// then resolve accounts positions, cause some accounts might be removed
  3665  		err = m.settings.ResolveAccountsPositions(message.Clock)
  3666  		if err != nil {
  3667  			return nil, err
  3668  		}
  3669  
  3670  		// if keypair is coming from paired device (means not from backup) and it's not among known, active keypairs,
  3671  		// we need to add an activity center notification
  3672  		if !kp.Removed && dbKeypair == nil {
  3673  			defer func() {
  3674  				err = acNofificationCallback()
  3675  			}()
  3676  		}
  3677  	}
  3678  
  3679  	for _, sKc := range message.Keycards {
  3680  		kc := accounts.Keycard{}
  3681  		kc.FromSyncKeycard(sKc)
  3682  		err = m.settings.SaveOrUpdateKeycard(kc, message.Clock, false)
  3683  		if err != nil {
  3684  			return nil, err
  3685  		}
  3686  		kp.Keycards = append(kp.Keycards, &kc)
  3687  	}
  3688  
  3689  	// getting keypair form the db, cause keypair related accounts positions might be changed
  3690  	dbKeypair, err = m.settings.GetKeypairByKeyUID(message.KeyUid)
  3691  	if err != nil {
  3692  		return nil, err
  3693  	}
  3694  
  3695  	if m.config.accountsFeed != nil {
  3696  		addedAddresses := []gethcommon.Address{}
  3697  		removedAddresses := []gethcommon.Address{}
  3698  		if dbKeypair.Removed {
  3699  			for _, acc := range dbKeypair.Accounts {
  3700  				removedAddresses = append(removedAddresses, gethcommon.Address(acc.Address))
  3701  			}
  3702  		} else {
  3703  			for _, acc := range dbKeypair.Accounts {
  3704  				if acc.Chat {
  3705  					continue
  3706  				}
  3707  				if acc.Removed {
  3708  					removedAddresses = append(removedAddresses, gethcommon.Address(acc.Address))
  3709  				} else {
  3710  					addedAddresses = append(addedAddresses, gethcommon.Address(acc.Address))
  3711  				}
  3712  			}
  3713  		}
  3714  		if len(addedAddresses) > 0 {
  3715  			m.config.accountsFeed.Send(accountsevent.Event{
  3716  				Type:     accountsevent.EventTypeAdded,
  3717  				Accounts: addedAddresses,
  3718  			})
  3719  		}
  3720  		if len(removedAddresses) > 0 {
  3721  			m.config.accountsFeed.Send(accountsevent.Event{
  3722  				Type:     accountsevent.EventTypeRemoved,
  3723  				Accounts: removedAddresses,
  3724  			})
  3725  		}
  3726  	}
  3727  
  3728  	return dbKeypair, nil
  3729  }
  3730  
  3731  func (m *Messenger) HandleSyncAccountsPositions(state *ReceivedMessageState, message *protobuf.SyncAccountsPositions, statusMessage *v1protocol.StatusMessage) error {
  3732  	accs, err := m.handleSyncAccountsPositions(message)
  3733  	if err != nil {
  3734  		if err == ErrTryingToApplyOldWalletAccountsOrder ||
  3735  			err == accounts.ErrAccountWrongPosition ||
  3736  			err == accounts.ErrNotTheSameNumberOdAccountsToApplyReordering ||
  3737  			err == accounts.ErrNotTheSameAccountsToApplyReordering {
  3738  			m.logger.Warn("syncing accounts order issue", zap.Error(err))
  3739  			return nil
  3740  		}
  3741  		return err
  3742  	}
  3743  
  3744  	state.Response.AccountsPositions = append(state.Response.AccountsPositions, accs...)
  3745  
  3746  	return nil
  3747  }
  3748  
  3749  func (m *Messenger) HandleSyncTokenPreferences(state *ReceivedMessageState, message *protobuf.SyncTokenPreferences, statusMessage *v1protocol.StatusMessage) error {
  3750  	tokenPreferences, err := m.handleSyncTokenPreferences(message)
  3751  	if err != nil {
  3752  		if err == ErrTryingToApplyOldTokenPreferences {
  3753  			m.logger.Warn("syncing token preferences issue", zap.Error(err))
  3754  			return nil
  3755  		}
  3756  		return err
  3757  	}
  3758  
  3759  	state.Response.TokenPreferences = append(state.Response.TokenPreferences, tokenPreferences...)
  3760  
  3761  	return nil
  3762  }
  3763  
  3764  func (m *Messenger) HandleSyncCollectiblePreferences(state *ReceivedMessageState, message *protobuf.SyncCollectiblePreferences, statusMessage *v1protocol.StatusMessage) error {
  3765  	collectiblePreferences, err := m.handleSyncCollectiblePreferences(message)
  3766  	if err != nil {
  3767  		if err == ErrTryingToApplyOldCollectiblePreferences {
  3768  			m.logger.Warn("syncing collectible preferences issue", zap.Error(err))
  3769  			return nil
  3770  		}
  3771  		return err
  3772  	}
  3773  
  3774  	state.Response.CollectiblePreferences = append(state.Response.CollectiblePreferences, collectiblePreferences...)
  3775  
  3776  	return nil
  3777  }
  3778  
  3779  func (m *Messenger) HandleSyncAccount(state *ReceivedMessageState, message *protobuf.SyncAccount, statusMessage *v1protocol.StatusMessage) error {
  3780  	acc, err := m.handleSyncWatchOnlyAccount(message, false)
  3781  	if err != nil {
  3782  		if err == ErrTryingToStoreOldWalletAccount {
  3783  			return nil
  3784  		}
  3785  		return err
  3786  	}
  3787  
  3788  	state.Response.WatchOnlyAccounts = append(state.Response.WatchOnlyAccounts, acc)
  3789  
  3790  	return nil
  3791  }
  3792  
  3793  func (m *Messenger) HandleSyncKeypair(state *ReceivedMessageState, message *protobuf.SyncKeypair, statusMessage *v1protocol.StatusMessage) error {
  3794  	return m.handleSyncKeypairInternal(state, message, false)
  3795  }
  3796  
  3797  func (m *Messenger) handleSyncKeypairInternal(state *ReceivedMessageState, message *protobuf.SyncKeypair, fromLocalPairing bool) error {
  3798  	if message == nil {
  3799  		return errors.New("handleSyncKeypairInternal receive a nil message")
  3800  	}
  3801  
  3802  	if m.walletAPI != nil {
  3803  		err := m.walletAPI.SetPairingsJSONFileContent(message.KeycardPairings)
  3804  		if err != nil {
  3805  			return err
  3806  		}
  3807  	}
  3808  
  3809  	// check for the profile keypair migration first on paired device
  3810  	handled, err := m.handleProfileKeypairMigration(state, fromLocalPairing, message)
  3811  	if err != nil {
  3812  		return err
  3813  	}
  3814  
  3815  	if handled {
  3816  		return nil
  3817  	}
  3818  
  3819  	kp, err := m.handleSyncKeypair(message, fromLocalPairing, func() error {
  3820  		return m.addNewKeypairAddedOnPairedDeviceACNotification(message.KeyUid, state.Response)
  3821  	})
  3822  	if err != nil {
  3823  		if err == ErrTryingToStoreOldKeypair {
  3824  			return nil
  3825  		}
  3826  		return err
  3827  	}
  3828  
  3829  	state.Response.Keypairs = append(state.Response.Keypairs, kp)
  3830  
  3831  	return nil
  3832  }
  3833  
  3834  func (m *Messenger) HandleSyncContactRequestDecision(state *ReceivedMessageState, message *protobuf.SyncContactRequestDecision, statusMessage *v1protocol.StatusMessage) error {
  3835  	var err error
  3836  	var response *MessengerResponse
  3837  
  3838  	if message.DecisionStatus == protobuf.SyncContactRequestDecision_ACCEPTED {
  3839  		response, err = m.updateAcceptedContactRequest(nil, message.RequestId, message.ContactId, true)
  3840  	} else {
  3841  		response, err = m.declineContactRequest(message.RequestId, message.ContactId, true)
  3842  	}
  3843  	if err != nil {
  3844  		return err
  3845  	}
  3846  
  3847  	return state.Response.Merge(response)
  3848  }
  3849  
  3850  func (m *Messenger) HandlePushNotificationRegistration(state *ReceivedMessageState, encryptedRegistration []byte, statusMessage *v1protocol.StatusMessage) error {
  3851  	if m.pushNotificationServer == nil {
  3852  		return nil
  3853  	}
  3854  	publicKey := state.CurrentMessageState.PublicKey
  3855  
  3856  	return m.pushNotificationServer.HandlePushNotificationRegistration(publicKey, encryptedRegistration)
  3857  }
  3858  
  3859  func (m *Messenger) HandlePushNotificationResponse(state *ReceivedMessageState, message *protobuf.PushNotificationResponse, statusMessage *v1protocol.StatusMessage) error {
  3860  	if m.pushNotificationClient == nil {
  3861  		return nil
  3862  	}
  3863  	publicKey := state.CurrentMessageState.PublicKey
  3864  
  3865  	return m.pushNotificationClient.HandlePushNotificationResponse(publicKey, message)
  3866  }
  3867  
  3868  func (m *Messenger) HandlePushNotificationRegistrationResponse(state *ReceivedMessageState, message *protobuf.PushNotificationRegistrationResponse, statusMessage *v1protocol.StatusMessage) error {
  3869  	if m.pushNotificationClient == nil {
  3870  		return nil
  3871  	}
  3872  	publicKey := state.CurrentMessageState.PublicKey
  3873  
  3874  	return m.pushNotificationClient.HandlePushNotificationRegistrationResponse(publicKey, message)
  3875  }
  3876  
  3877  func (m *Messenger) HandlePushNotificationQuery(state *ReceivedMessageState, message *protobuf.PushNotificationQuery, statusMessage *v1protocol.StatusMessage) error {
  3878  	if m.pushNotificationServer == nil {
  3879  		return nil
  3880  	}
  3881  	publicKey := state.CurrentMessageState.PublicKey
  3882  
  3883  	return m.pushNotificationServer.HandlePushNotificationQuery(publicKey, statusMessage.ApplicationLayer.ID, message)
  3884  }
  3885  
  3886  func (m *Messenger) HandlePushNotificationQueryResponse(state *ReceivedMessageState, message *protobuf.PushNotificationQueryResponse, statusMessage *v1protocol.StatusMessage) error {
  3887  	if m.pushNotificationClient == nil {
  3888  		return nil
  3889  	}
  3890  	publicKey := state.CurrentMessageState.PublicKey
  3891  
  3892  	return m.pushNotificationClient.HandlePushNotificationQueryResponse(publicKey, message)
  3893  }
  3894  
  3895  func (m *Messenger) HandlePushNotificationRequest(state *ReceivedMessageState, message *protobuf.PushNotificationRequest, statusMessage *v1protocol.StatusMessage) error {
  3896  	if m.pushNotificationServer == nil {
  3897  		return nil
  3898  	}
  3899  	publicKey := state.CurrentMessageState.PublicKey
  3900  
  3901  	return m.pushNotificationServer.HandlePushNotificationRequest(publicKey, statusMessage.ApplicationLayer.ID, message)
  3902  }
  3903  
  3904  func (m *Messenger) HandleCommunityDescription(state *ReceivedMessageState, message *protobuf.CommunityDescription, statusMessage *v1protocol.StatusMessage) error {
  3905  	// shard passed as nil since it is handled within by using default shard
  3906  	err := m.handleCommunityDescription(state, state.CurrentMessageState.PublicKey, message, statusMessage.EncryptionLayer.Payload, nil, nil)
  3907  	if err != nil {
  3908  		m.logger.Warn("failed to handle CommunityDescription", zap.Error(err))
  3909  		return err
  3910  	}
  3911  	return nil
  3912  }
  3913  
  3914  func (m *Messenger) HandleSyncBookmark(state *ReceivedMessageState, message *protobuf.SyncBookmark, statusMessage *v1protocol.StatusMessage) error {
  3915  	bookmark := &browsers.Bookmark{
  3916  		URL:      message.Url,
  3917  		Name:     message.Name,
  3918  		ImageURL: message.ImageUrl,
  3919  		Removed:  message.Removed,
  3920  		Clock:    message.Clock,
  3921  	}
  3922  	state.AllBookmarks[message.Url] = bookmark
  3923  	return nil
  3924  }
  3925  
  3926  func (m *Messenger) HandleSyncClearHistory(state *ReceivedMessageState, message *protobuf.SyncClearHistory, statusMessage *v1protocol.StatusMessage) error {
  3927  	chatID := message.ChatId
  3928  	existingChat, ok := state.AllChats.Load(chatID)
  3929  	if !ok {
  3930  		return ErrChatNotFound
  3931  	}
  3932  
  3933  	if existingChat.DeletedAtClockValue >= message.ClearedAt {
  3934  		return nil
  3935  	}
  3936  
  3937  	err := m.persistence.ClearHistoryFromSyncMessage(existingChat, message.ClearedAt)
  3938  	if err != nil {
  3939  		return err
  3940  	}
  3941  
  3942  	if existingChat.Public() {
  3943  		err = m.transport.ClearProcessedMessageIDsCache()
  3944  		if err != nil {
  3945  			return err
  3946  		}
  3947  	}
  3948  
  3949  	state.AllChats.Store(chatID, existingChat)
  3950  	state.Response.AddChat(existingChat)
  3951  	state.Response.AddClearedHistory(&ClearedHistory{
  3952  		ClearedAt: message.ClearedAt,
  3953  		ChatID:    chatID,
  3954  	})
  3955  	return nil
  3956  }
  3957  
  3958  func (m *Messenger) HandleSyncTrustedUser(state *ReceivedMessageState, message *protobuf.SyncTrustedUser, statusMessage *v1protocol.StatusMessage) error {
  3959  	updated, err := m.verificationDatabase.UpsertTrustStatus(message.Id, verification.TrustStatus(message.Status), message.Clock)
  3960  	if err != nil {
  3961  		return err
  3962  	}
  3963  
  3964  	if updated {
  3965  		state.AllTrustStatus[message.Id] = verification.TrustStatus(message.Status)
  3966  
  3967  		contact, ok := m.allContacts.Load(message.Id)
  3968  		if !ok {
  3969  			m.logger.Info("contact not found")
  3970  			return nil
  3971  		}
  3972  
  3973  		contact.TrustStatus = verification.TrustStatus(message.Status)
  3974  		m.allContacts.Store(contact.ID, contact)
  3975  		state.ModifiedContacts.Store(contact.ID, true)
  3976  	}
  3977  
  3978  	return nil
  3979  }
  3980  func (m *Messenger) HandleCommunityMessageArchiveMagnetlink(state *ReceivedMessageState, message *protobuf.CommunityMessageArchiveMagnetlink, statusMessage *v1protocol.StatusMessage) error {
  3981  	return m.HandleHistoryArchiveMagnetlinkMessage(state, state.CurrentMessageState.PublicKey, message.MagnetUri, message.Clock)
  3982  }
  3983  
  3984  func (m *Messenger) addNewKeypairAddedOnPairedDeviceACNotification(keyUID string, response *MessengerResponse) error {
  3985  	kp, err := m.settings.GetKeypairByKeyUID(keyUID)
  3986  	if err != nil {
  3987  		return err
  3988  	}
  3989  
  3990  	notification := &ActivityCenterNotification{
  3991  		ID:        types.FromHex(uuid.New().String()),
  3992  		Type:      ActivityCenterNotificationTypeNewKeypairAddedToPairedDevice,
  3993  		Timestamp: m.getTimesource().GetCurrentTime(),
  3994  		Read:      false,
  3995  		UpdatedAt: m.GetCurrentTimeInMillis(),
  3996  		Message: &common.Message{
  3997  			ChatMessage: &protobuf.ChatMessage{
  3998  				Text: kp.Name,
  3999  			},
  4000  			ID: kp.KeyUID,
  4001  		},
  4002  	}
  4003  
  4004  	err = m.addActivityCenterNotification(response, notification, nil)
  4005  	if err != nil {
  4006  		m.logger.Warn("failed to create activity center notification", zap.Error(err))
  4007  		return err
  4008  	}
  4009  	return nil
  4010  }
  4011  
  4012  func (m *Messenger) HandleSyncProfileShowcasePreferences(state *ReceivedMessageState, p *protobuf.SyncProfileShowcasePreferences, statusMessage *v1protocol.StatusMessage) error {
  4013  	_, err := m.saveProfileShowcasePreferencesProto(p, false)
  4014  	return err
  4015  }