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 }