github.com/status-im/status-go@v1.1.0/protocol/messenger.go (about) 1 package protocol 2 3 import ( 4 "bytes" 5 "context" 6 "crypto/ecdsa" 7 "database/sql" 8 "encoding/json" 9 "fmt" 10 "math/rand" 11 "os" 12 "strconv" 13 "strings" 14 "sync" 15 "time" 16 17 "github.com/golang/protobuf/proto" 18 "github.com/google/uuid" 19 "github.com/libp2p/go-libp2p/core/peer" 20 "github.com/pkg/errors" 21 "go.uber.org/zap" 22 "golang.org/x/time/rate" 23 24 datasyncnode "github.com/status-im/mvds/node" 25 26 gethcommon "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/common/hexutil" 28 "github.com/ethereum/go-ethereum/p2p" 29 30 "github.com/status-im/status-go/account" 31 "github.com/status-im/status-go/appmetrics" 32 utils "github.com/status-im/status-go/common" 33 "github.com/status-im/status-go/connection" 34 "github.com/status-im/status-go/contracts" 35 "github.com/status-im/status-go/deprecation" 36 "github.com/status-im/status-go/eth-node/crypto" 37 "github.com/status-im/status-go/eth-node/types" 38 "github.com/status-im/status-go/images" 39 multiaccountscommon "github.com/status-im/status-go/multiaccounts/common" 40 41 "github.com/status-im/status-go/multiaccounts" 42 "github.com/status-im/status-go/multiaccounts/accounts" 43 "github.com/status-im/status-go/multiaccounts/settings" 44 "github.com/status-im/status-go/protocol/anonmetrics" 45 "github.com/status-im/status-go/protocol/common" 46 "github.com/status-im/status-go/protocol/common/shard" 47 "github.com/status-im/status-go/protocol/communities" 48 "github.com/status-im/status-go/protocol/encryption" 49 "github.com/status-im/status-go/protocol/encryption/multidevice" 50 "github.com/status-im/status-go/protocol/encryption/sharedsecret" 51 "github.com/status-im/status-go/protocol/ens" 52 "github.com/status-im/status-go/protocol/identity/alias" 53 "github.com/status-im/status-go/protocol/identity/identicon" 54 "github.com/status-im/status-go/protocol/peersyncing" 55 "github.com/status-im/status-go/protocol/protobuf" 56 "github.com/status-im/status-go/protocol/pushnotificationclient" 57 "github.com/status-im/status-go/protocol/pushnotificationserver" 58 "github.com/status-im/status-go/protocol/requests" 59 "github.com/status-im/status-go/protocol/sqlite" 60 "github.com/status-im/status-go/protocol/storenodes" 61 "github.com/status-im/status-go/protocol/transport" 62 v1protocol "github.com/status-im/status-go/protocol/v1" 63 "github.com/status-im/status-go/protocol/verification" 64 "github.com/status-im/status-go/server" 65 "github.com/status-im/status-go/services/browsers" 66 ensservice "github.com/status-im/status-go/services/ens" 67 "github.com/status-im/status-go/services/ext/mailservers" 68 localnotifications "github.com/status-im/status-go/services/local-notifications" 69 mailserversDB "github.com/status-im/status-go/services/mailservers" 70 "github.com/status-im/status-go/services/wallet" 71 "github.com/status-im/status-go/services/wallet/community" 72 "github.com/status-im/status-go/services/wallet/token" 73 "github.com/status-im/status-go/signal" 74 "github.com/status-im/status-go/telemetry" 75 ) 76 77 const ( 78 PubKeyStringLength = 132 79 80 transactionSentTxt = "Transaction sent" 81 82 publicChat ChatContext = "public-chat" 83 privateChat ChatContext = "private-chat" 84 ) 85 86 // errors 87 var ( 88 ErrChatNotFoundError = errors.New("Chat not found") 89 ) 90 91 const communityAdvertiseIntervalSecond int64 = 24 * 60 * 60 92 93 // messageCacheIntervalMs is how long we should keep processed messages in the cache, in ms 94 var messageCacheIntervalMs uint64 = 1000 * 60 * 60 * 48 95 96 // Messenger is a entity managing chats and messages. 97 // It acts as a bridge between the application and encryption 98 // layers. 99 // It needs to expose an interface to manage installations 100 // because installations are managed by the user. 101 // Similarly, it needs to expose an interface to manage 102 // mailservers because they can also be managed by the user. 103 type Messenger struct { 104 node types.Node 105 server *p2p.Server 106 peerStore *mailservers.PeerStore 107 config *config 108 identity *ecdsa.PrivateKey 109 persistence *sqlitePersistence 110 transport *transport.Transport 111 encryptor *encryption.Protocol 112 sender *common.MessageSender 113 ensVerifier *ens.Verifier 114 anonMetricsClient *anonmetrics.Client 115 anonMetricsServer *anonmetrics.Server 116 pushNotificationClient *pushnotificationclient.Client 117 pushNotificationServer *pushnotificationserver.Server 118 communitiesManager *communities.Manager 119 archiveManager communities.ArchiveService 120 communitiesKeyDistributor communities.KeyDistributor 121 accountsManager account.Manager 122 mentionsManager *MentionManager 123 storeNodeRequestsManager *StoreNodeRequestManager 124 logger *zap.Logger 125 126 outputCSV bool 127 csvFile *os.File 128 129 verifyTransactionClient EthClient 130 featureFlags common.FeatureFlags 131 shutdownTasks []func() error 132 shouldPublishContactCode bool 133 systemMessagesTranslations *systemMessageTranslationsMap 134 allChats *chatMap 135 selfContact *Contact 136 selfContactSubscriptions []chan *SelfContactChangeEvent 137 allContacts *contactMap 138 allInstallations *installationMap 139 modifiedInstallations *stringBoolMap 140 installationID string 141 mailserverCycle mailserverCycle 142 communityStorenodes *storenodes.CommunityStorenodes 143 database *sql.DB 144 multiAccounts *multiaccounts.Database 145 settings *accounts.Database 146 account *multiaccounts.Account 147 mailserversDatabase *mailserversDB.Database 148 browserDatabase *browsers.Database 149 httpServer *server.MediaServer 150 151 started bool 152 quit chan struct{} 153 ctx context.Context 154 cancel context.CancelFunc 155 shutdownWaitGroup sync.WaitGroup 156 157 importingCommunities map[string]bool 158 importingChannels map[string]bool 159 importRateLimiter *rate.Limiter 160 importDelayer struct { 161 wait chan struct{} 162 once sync.Once 163 } 164 165 connectionState connection.State 166 telemetryClient *telemetry.Client 167 contractMaker *contracts.ContractMaker 168 verificationDatabase *verification.Persistence 169 savedAddressesManager *wallet.SavedAddressesManager 170 walletAPI *wallet.API 171 172 // TODO(samyoul) Determine if/how the remaining usage of this mutex can be removed 173 mutex sync.Mutex 174 mailPeersMutex sync.RWMutex 175 handleMessagesMutex sync.Mutex 176 handleImportMessagesMutex sync.Mutex 177 178 // flag to disable checking #hasPairedDevices 179 localPairing bool 180 // flag to enable backedup messages processing, false by default 181 processBackedupMessages bool 182 183 communityTokensService communities.CommunityTokensServiceInterface 184 185 // used to track dispatched messages 186 dispatchMessageTestCallback func(common.RawMessage) 187 188 // used to track unhandled messages 189 unhandledMessagesTracker func(*v1protocol.StatusMessage, error) 190 191 // enables control over chat messages iteration 192 retrievedMessagesIteratorFactory func(map[transport.Filter][]*types.Message) MessagesIterator 193 194 peersyncing *peersyncing.PeerSyncing 195 peersyncingOffers map[string]uint64 196 peersyncingRequests map[string]uint64 197 198 mvdsStatusChangeEvent chan datasyncnode.PeerStatusChangeEvent 199 } 200 201 type connStatus int 202 203 const ( 204 disconnected connStatus = iota + 1 205 connected 206 ) 207 208 type peerStatus struct { 209 status connStatus 210 canConnectAfter time.Time 211 lastConnectionAttempt time.Time 212 mailserver mailserversDB.Mailserver 213 } 214 type mailserverCycle struct { 215 sync.RWMutex 216 allMailservers []mailserversDB.Mailserver 217 activeMailserver *mailserversDB.Mailserver 218 peers map[string]peerStatus 219 availabilitySubscriptions *availabilitySubscriptions 220 } 221 222 type availabilitySubscriptions struct { 223 sync.Mutex 224 subscriptions []chan struct{} 225 } 226 227 func (s *availabilitySubscriptions) Subscribe() <-chan struct{} { 228 s.Lock() 229 defer s.Unlock() 230 c := make(chan struct{}) 231 s.subscriptions = append(s.subscriptions, c) 232 return c 233 } 234 235 func (s *availabilitySubscriptions) EmitMailserverAvailable() { 236 s.Lock() 237 defer s.Unlock() 238 239 for _, subs := range s.subscriptions { 240 close(subs) 241 } 242 s.subscriptions = nil 243 } 244 245 type EnvelopeEventsInterceptor struct { 246 EnvelopeEventsHandler transport.EnvelopeEventsHandler 247 Messenger *Messenger 248 } 249 250 type LatestContactRequest struct { 251 MessageID string 252 ContactRequestState common.ContactRequestState 253 ContactID string 254 } 255 256 func (m *Messenger) GetOwnPrimaryName() (string, error) { 257 ensName, err := m.settings.ENSName() 258 if err != nil { 259 return ensName, nil 260 } 261 return m.settings.DisplayName() 262 } 263 264 func (m *Messenger) ResolvePrimaryName(mentionID string) (string, error) { 265 if mentionID == m.myHexIdentity() { 266 return m.GetOwnPrimaryName() 267 } 268 contact, ok := m.allContacts.Load(mentionID) 269 if !ok { 270 var err error 271 contact, err = buildContactFromPkString(mentionID) 272 if err != nil { 273 return mentionID, err 274 } 275 } 276 return contact.PrimaryName(), nil 277 } 278 279 // EnvelopeSent triggered when envelope delivered at least to 1 peer. 280 func (interceptor EnvelopeEventsInterceptor) EnvelopeSent(identifiers [][]byte) { 281 if interceptor.Messenger != nil { 282 signalIDs := make([][]byte, 0, len(identifiers)) 283 for _, identifierBytes := range identifiers { 284 messageID := types.EncodeHex(identifierBytes) 285 err := interceptor.Messenger.processSentMessage(messageID) 286 if err != nil { 287 interceptor.Messenger.logger.Info("messenger failed to process sent messages", zap.Error(err)) 288 } 289 290 message, err := interceptor.Messenger.MessageByID(messageID) 291 if err != nil { 292 interceptor.Messenger.logger.Error("failed to query message outgoing status", zap.Error(err)) 293 continue 294 } 295 if message.OutgoingStatus == common.OutgoingStatusDelivered { 296 // We don't want to send the signal if the message was already marked as delivered 297 continue 298 } 299 signalIDs = append(signalIDs, identifierBytes) 300 } 301 interceptor.EnvelopeEventsHandler.EnvelopeSent(signalIDs) 302 } else { 303 // NOTE(rasom): In case if interceptor.Messenger is not nil and 304 // some error occurred on processing sent message we don't want 305 // to send envelop.sent signal to the client, thus `else` cause 306 // is necessary. 307 interceptor.EnvelopeEventsHandler.EnvelopeSent(identifiers) 308 } 309 } 310 311 // EnvelopeExpired triggered when envelope is expired but wasn't delivered to any peer. 312 func (interceptor EnvelopeEventsInterceptor) EnvelopeExpired(identifiers [][]byte, err error) { 313 //we don't track expired events in Messenger, so just redirect to handler 314 interceptor.EnvelopeEventsHandler.EnvelopeExpired(identifiers, err) 315 } 316 317 // MailServerRequestCompleted triggered when the mailserver sends a message to notify that the request has been completed 318 func (interceptor EnvelopeEventsInterceptor) MailServerRequestCompleted(requestID types.Hash, lastEnvelopeHash types.Hash, cursor []byte, err error) { 319 //we don't track mailserver requests in Messenger, so just redirect to handler 320 interceptor.EnvelopeEventsHandler.MailServerRequestCompleted(requestID, lastEnvelopeHash, cursor, err) 321 } 322 323 // MailServerRequestExpired triggered when the mailserver request expires 324 func (interceptor EnvelopeEventsInterceptor) MailServerRequestExpired(hash types.Hash) { 325 //we don't track mailserver requests in Messenger, so just redirect to handler 326 interceptor.EnvelopeEventsHandler.MailServerRequestExpired(hash) 327 } 328 329 func NewMessenger( 330 nodeName string, 331 identity *ecdsa.PrivateKey, 332 node types.Node, 333 installationID string, 334 peerStore *mailservers.PeerStore, 335 version string, 336 opts ...Option, 337 ) (*Messenger, error) { 338 var messenger *Messenger 339 340 c := messengerDefaultConfig() 341 342 for _, opt := range opts { 343 if err := opt(&c); err != nil { 344 return nil, err 345 } 346 } 347 348 logger := c.logger 349 if c.logger == nil { 350 var err error 351 if logger, err = zap.NewDevelopment(); err != nil { 352 return nil, errors.Wrap(err, "failed to create a logger") 353 } 354 } 355 356 if c.systemMessagesTranslations == nil { 357 c.systemMessagesTranslations = defaultSystemMessagesTranslations 358 } 359 360 // Configure the database. 361 if c.appDb == nil { 362 return nil, errors.New("database instance or database path needs to be provided") 363 } 364 database := c.appDb 365 366 // Apply any post database creation changes to the database 367 for _, opt := range c.afterDbCreatedHooks { 368 if err := opt(&c); err != nil { 369 return nil, err 370 } 371 } 372 373 // Apply migrations for all components. 374 err := sqlite.Migrate(database) 375 if err != nil { 376 return nil, errors.Wrap(err, "failed to apply migrations") 377 } 378 379 // Initialize transport layer. 380 var transp *transport.Transport 381 var peerId peer.ID 382 383 if waku, err := node.GetWaku(nil); err == nil && waku != nil { 384 transp, err = transport.NewTransport( 385 waku, 386 identity, 387 database, 388 "waku_keys", 389 nil, 390 c.envelopesMonitorConfig, 391 logger, 392 ) 393 if err != nil { 394 return nil, errors.Wrap(err, "failed to create Transport") 395 } 396 } else { 397 logger.Info("failed to find Waku service; trying WakuV2", zap.Error(err)) 398 wakuV2, err := node.GetWakuV2(nil) 399 if err != nil || wakuV2 == nil { 400 return nil, errors.Wrap(err, "failed to find Whisper and Waku V1/V2 services") 401 } 402 peerId = wakuV2.PeerID() 403 transp, err = transport.NewTransport( 404 wakuV2, 405 identity, 406 database, 407 "wakuv2_keys", 408 nil, 409 c.envelopesMonitorConfig, 410 logger, 411 ) 412 if err != nil { 413 return nil, errors.Wrap(err, "failed to create Transport") 414 } 415 } 416 417 // Initialize encryption layer. 418 encryptionProtocol := encryption.New( 419 database, 420 installationID, 421 logger, 422 ) 423 424 sender, err := common.NewMessageSender( 425 identity, 426 database, 427 encryptionProtocol, 428 transp, 429 logger, 430 c.featureFlags, 431 ) 432 if err != nil { 433 return nil, errors.Wrap(err, "failed to create messageSender") 434 } 435 436 // Initialise anon metrics client 437 var anonMetricsClient *anonmetrics.Client 438 if c.anonMetricsClientConfig != nil && 439 c.anonMetricsClientConfig.ShouldSend && 440 c.anonMetricsClientConfig.Active == anonmetrics.ActiveClientPhrase { 441 442 anonMetricsClient = anonmetrics.NewClient(sender) 443 anonMetricsClient.Config = c.anonMetricsClientConfig 444 anonMetricsClient.Identity = identity 445 anonMetricsClient.DB = appmetrics.NewDB(database) 446 anonMetricsClient.Logger = logger 447 } 448 449 // Initialise anon metrics server 450 var anonMetricsServer *anonmetrics.Server 451 if c.anonMetricsServerConfig != nil && 452 c.anonMetricsServerConfig.Enabled && 453 c.anonMetricsServerConfig.Active == anonmetrics.ActiveServerPhrase { 454 455 server, err := anonmetrics.NewServer(c.anonMetricsServerConfig.PostgresURI) 456 if err != nil { 457 return nil, errors.Wrap(err, "failed to create anonmetrics.Server") 458 } 459 460 anonMetricsServer = server 461 anonMetricsServer.Config = c.anonMetricsServerConfig 462 anonMetricsServer.Logger = logger 463 } 464 465 // Initialize push notification server 466 var pushNotificationServer *pushnotificationserver.Server 467 if c.pushNotificationServerConfig != nil && c.pushNotificationServerConfig.Enabled { 468 c.pushNotificationServerConfig.Identity = identity 469 pushNotificationServerPersistence := pushnotificationserver.NewSQLitePersistence(database) 470 pushNotificationServer = pushnotificationserver.New(c.pushNotificationServerConfig, pushNotificationServerPersistence, sender) 471 } 472 473 // Initialize push notification client 474 pushNotificationClientPersistence := pushnotificationclient.NewPersistence(database) 475 pushNotificationClientConfig := c.pushNotificationClientConfig 476 if pushNotificationClientConfig == nil { 477 pushNotificationClientConfig = &pushnotificationclient.Config{} 478 } 479 480 sqlitePersistence := newSQLitePersistence(database) 481 // Overriding until we handle different identities 482 pushNotificationClientConfig.Identity = identity 483 pushNotificationClientConfig.Logger = logger 484 pushNotificationClientConfig.InstallationID = installationID 485 486 pushNotificationClient := pushnotificationclient.New(pushNotificationClientPersistence, pushNotificationClientConfig, sender, sqlitePersistence) 487 488 ensVerifier := ens.New(node, logger, transp, database, c.verifyENSURL, c.verifyENSContractAddress) 489 490 managerOptions := []communities.ManagerOption{ 491 communities.WithAccountManager(c.accountsManager), 492 } 493 494 var walletAPI *wallet.API 495 if c.walletService != nil { 496 walletAPI = wallet.NewAPI(c.walletService) 497 managerOptions = append(managerOptions, communities.WithCollectiblesManager(walletAPI)) 498 } else if c.collectiblesManager != nil { 499 managerOptions = append(managerOptions, communities.WithCollectiblesManager(c.collectiblesManager)) 500 } 501 502 if c.tokenManager != nil { 503 managerOptions = append(managerOptions, communities.WithTokenManager(c.tokenManager)) 504 } else if c.rpcClient != nil { 505 tokenManager := token.NewTokenManager(c.walletDb, c.rpcClient, community.NewManager(database, c.httpServer, nil), c.rpcClient.NetworkManager, database, c.httpServer, nil, nil, nil, token.NewPersistence(c.walletDb)) 506 managerOptions = append(managerOptions, communities.WithTokenManager(communities.NewDefaultTokenManager(tokenManager, c.rpcClient.NetworkManager))) 507 } 508 509 if c.walletConfig != nil { 510 managerOptions = append(managerOptions, communities.WithWalletConfig(c.walletConfig)) 511 } 512 513 if c.communityTokensService != nil { 514 managerOptions = append(managerOptions, communities.WithCommunityTokensService(c.communityTokensService)) 515 } 516 517 managerOptions = append(managerOptions, c.communityManagerOptions...) 518 519 communitiesKeyDistributor := &CommunitiesKeyDistributorImpl{ 520 sender: sender, 521 encryptor: encryptionProtocol, 522 } 523 524 communitiesManager, err := communities.NewManager( 525 identity, 526 installationID, 527 database, 528 encryptionProtocol, 529 logger, 530 ensVerifier, 531 c.communityTokensService, 532 transp, 533 transp, 534 communitiesKeyDistributor, 535 c.httpServer, 536 managerOptions..., 537 ) 538 if err != nil { 539 return nil, err 540 } 541 542 amc := &communities.ArchiveManagerConfig{ 543 TorrentConfig: c.torrentConfig, 544 Logger: logger, 545 Persistence: communitiesManager.GetPersistence(), 546 Transport: transp, 547 Identity: identity, 548 Encryptor: encryptionProtocol, 549 Publisher: communitiesManager, 550 } 551 552 // Depending on the OS go will choose whether to use the "communities/manager_archive_nop.go" or 553 // "communities/manager_archive.go" version of this function based on the build instructions for those files. 554 // See those file for more details. 555 archiveManager := communities.NewArchiveManager(amc) 556 if err != nil { 557 return nil, err 558 } 559 560 settings, err := accounts.NewDB(database) 561 if err != nil { 562 return nil, err 563 } 564 565 savedAddressesManager := wallet.NewSavedAddressesManager(c.walletDb) 566 567 selfContact, err := buildSelfContact(identity, settings, c.multiAccount, c.account) 568 if err != nil { 569 return nil, fmt.Errorf("failed to build contact of ourself: %w", err) 570 } 571 572 ctx, cancel := context.WithCancel(context.Background()) 573 574 var telemetryClient *telemetry.Client 575 if c.telemetryServerURL != "" { 576 options := []telemetry.TelemetryClientOption{ 577 telemetry.WithPeerID(peerId.String()), 578 } 579 telemetryClient = telemetry.NewClient(logger, c.telemetryServerURL, c.account.KeyUID, nodeName, version, options...) 580 if c.wakuService != nil { 581 c.wakuService.SetStatusTelemetryClient(telemetryClient) 582 } 583 go telemetryClient.Start(ctx) 584 } 585 586 messenger = &Messenger{ 587 config: &c, 588 node: node, 589 identity: identity, 590 persistence: sqlitePersistence, 591 transport: transp, 592 encryptor: encryptionProtocol, 593 sender: sender, 594 anonMetricsClient: anonMetricsClient, 595 anonMetricsServer: anonMetricsServer, 596 telemetryClient: telemetryClient, 597 communityTokensService: c.communityTokensService, 598 pushNotificationClient: pushNotificationClient, 599 pushNotificationServer: pushNotificationServer, 600 communitiesManager: communitiesManager, 601 communitiesKeyDistributor: communitiesKeyDistributor, 602 archiveManager: archiveManager, 603 accountsManager: c.accountsManager, 604 ensVerifier: ensVerifier, 605 featureFlags: c.featureFlags, 606 systemMessagesTranslations: c.systemMessagesTranslations, 607 allChats: new(chatMap), 608 selfContact: selfContact, 609 allContacts: &contactMap{ 610 logger: logger, 611 me: selfContact, 612 }, 613 allInstallations: new(installationMap), 614 installationID: installationID, 615 modifiedInstallations: new(stringBoolMap), 616 verifyTransactionClient: c.verifyTransactionClient, 617 database: database, 618 multiAccounts: c.multiAccount, 619 settings: settings, 620 peersyncing: peersyncing.New(peersyncing.Config{Database: database, Timesource: transp}), 621 peersyncingOffers: make(map[string]uint64), 622 peersyncingRequests: make(map[string]uint64), 623 peerStore: peerStore, 624 mvdsStatusChangeEvent: make(chan datasyncnode.PeerStatusChangeEvent, 5), 625 verificationDatabase: verification.NewPersistence(database), 626 mailserverCycle: mailserverCycle{ 627 peers: make(map[string]peerStatus), 628 availabilitySubscriptions: &availabilitySubscriptions{}, 629 }, 630 mailserversDatabase: c.mailserversDatabase, 631 communityStorenodes: storenodes.NewCommunityStorenodes(storenodes.NewDB(database), logger), 632 account: c.account, 633 quit: make(chan struct{}), 634 ctx: ctx, 635 cancel: cancel, 636 importingCommunities: make(map[string]bool), 637 importingChannels: make(map[string]bool), 638 importRateLimiter: rate.NewLimiter(rate.Every(importSlowRate), 1), 639 importDelayer: struct { 640 wait chan struct{} 641 once sync.Once 642 }{wait: make(chan struct{})}, 643 browserDatabase: c.browserDatabase, 644 httpServer: c.httpServer, 645 shutdownTasks: []func() error{ 646 ensVerifier.Stop, 647 pushNotificationClient.Stop, 648 communitiesManager.Stop, 649 archiveManager.Stop, 650 encryptionProtocol.Stop, 651 func() error { 652 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 653 defer cancel() 654 err := transp.ResetFilters(ctx) 655 if err != nil { 656 logger.Warn("could not reset filters", zap.Error(err)) 657 } 658 // We don't want to thrown an error in this case, this is a soft 659 // fail 660 return nil 661 }, 662 transp.Stop, 663 func() error { sender.Stop(); return nil }, 664 // Currently this often fails, seems like it's safe to ignore them 665 // https://github.com/uber-go/zap/issues/328 666 func() error { _ = logger.Sync; return nil }, 667 database.Close, 668 }, 669 logger: logger, 670 savedAddressesManager: savedAddressesManager, 671 retrievedMessagesIteratorFactory: NewDefaultMessagesIterator, 672 } 673 674 if c.rpcClient != nil { 675 contractMaker, err := contracts.NewContractMaker(c.rpcClient) 676 if err != nil { 677 return nil, err 678 } 679 messenger.contractMaker = contractMaker 680 } 681 682 messenger.mentionsManager = NewMentionManager(messenger) 683 messenger.storeNodeRequestsManager = NewStoreNodeRequestManager(messenger) 684 685 if c.walletService != nil { 686 messenger.walletAPI = walletAPI 687 } 688 689 if c.outputMessagesCSV { 690 messenger.outputCSV = c.outputMessagesCSV 691 csvFile, err := os.Create("messages-" + fmt.Sprint(time.Now().Unix()) + ".csv") 692 if err != nil { 693 return nil, err 694 } 695 696 _, err = csvFile.Write([]byte("timestamp\tmessageID\tfrom\ttopic\tchatID\tmessageType\tmessage\n")) 697 if err != nil { 698 return nil, err 699 } 700 701 messenger.csvFile = csvFile 702 messenger.shutdownTasks = append(messenger.shutdownTasks, csvFile.Close) 703 } 704 705 if anonMetricsClient != nil { 706 messenger.shutdownTasks = append(messenger.shutdownTasks, anonMetricsClient.Stop) 707 } 708 if anonMetricsServer != nil { 709 messenger.shutdownTasks = append(messenger.shutdownTasks, anonMetricsServer.Stop) 710 } 711 712 if c.envelopesMonitorConfig != nil { 713 interceptor := EnvelopeEventsInterceptor{c.envelopesMonitorConfig.EnvelopeEventsHandler, messenger} 714 err := messenger.transport.SetEnvelopeEventsHandler(interceptor) 715 if err != nil { 716 logger.Info("Unable to set envelopes event handler", zap.Error(err)) 717 } 718 } 719 720 return messenger, nil 721 } 722 723 func (m *Messenger) SetP2PServer(server *p2p.Server) { 724 m.server = server 725 } 726 727 func (m *Messenger) EnableBackedupMessagesProcessing() { 728 m.processBackedupMessages = true 729 } 730 731 func (m *Messenger) processSentMessage(id string) error { 732 if m.connectionState.Offline { 733 return errors.New("Can't mark message as sent while offline") 734 } 735 736 rawMessage, err := m.persistence.RawMessageByID(id) 737 // If we have no raw message, we create a temporary one, so that 738 // the sent status is preserved 739 if err == sql.ErrNoRows || rawMessage == nil { 740 rawMessage = &common.RawMessage{ 741 ID: id, 742 MessageType: protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, 743 } 744 } else if err != nil { 745 return errors.Wrapf(err, "Can't get raw message with id %v", id) 746 } 747 748 rawMessage.Sent = true 749 750 err = m.persistence.SaveRawMessage(rawMessage) 751 if err != nil { 752 return errors.Wrapf(err, "Can't save raw message marked as sent") 753 } 754 755 err = m.UpdateMessageOutgoingStatus(id, common.OutgoingStatusSent) 756 if err != nil { 757 return err 758 } 759 760 return nil 761 } 762 763 func (m *Messenger) ToForeground() { 764 if m.httpServer != nil { 765 m.httpServer.ToForeground() 766 } 767 768 m.asyncRequestAllHistoricMessages() 769 } 770 771 func (m *Messenger) ToBackground() { 772 if m.httpServer != nil { 773 m.httpServer.ToBackground() 774 } 775 } 776 777 func (m *Messenger) Start() (*MessengerResponse, error) { 778 if m.started { 779 return nil, errors.New("messenger already started") 780 } 781 m.started = true 782 783 err := m.InitFilters() 784 if err != nil { 785 return nil, err 786 } 787 788 now := time.Now().UnixMilli() 789 if err := m.settings.CheckAndDeleteExpiredKeypairsAndAccounts(uint64(now)); err != nil { 790 return nil, err 791 } 792 793 m.logger.Info("starting messenger", zap.String("identity", types.EncodeHex(crypto.FromECDSAPub(&m.identity.PublicKey)))) 794 // Start push notification server 795 if m.pushNotificationServer != nil { 796 if err := m.pushNotificationServer.Start(); err != nil { 797 return nil, err 798 } 799 } 800 801 // Start push notification client 802 if m.pushNotificationClient != nil { 803 m.handlePushNotificationClientRegistrations(m.pushNotificationClient.SubscribeToRegistrations()) 804 805 if err := m.pushNotificationClient.Start(); err != nil { 806 return nil, err 807 } 808 } 809 810 // Start anonymous metrics client 811 if m.anonMetricsClient != nil { 812 if err := m.anonMetricsClient.Start(); err != nil { 813 return nil, err 814 } 815 } 816 817 ensSubscription := m.ensVerifier.Subscribe() 818 819 // Subscrbe 820 if err := m.ensVerifier.Start(); err != nil { 821 return nil, err 822 } 823 824 if err := m.communitiesManager.Start(); err != nil { 825 return nil, err 826 } 827 828 // set shared secret handles 829 m.sender.SetHandleSharedSecrets(m.handleSharedSecrets) 830 if err := m.sender.StartDatasync(m.mvdsStatusChangeEvent, m.sendDataSync); err != nil { 831 return nil, err 832 } 833 834 subscriptions, err := m.encryptor.Start(m.identity) 835 if err != nil { 836 return nil, err 837 } 838 839 // handle stored shared secrets 840 err = m.handleSharedSecrets(subscriptions.SharedSecrets) 841 if err != nil { 842 return nil, err 843 } 844 845 m.handleEncryptionLayerSubscriptions(subscriptions) 846 m.handleCommunitiesSubscription(m.communitiesManager.Subscribe()) 847 m.handleCommunitiesHistoryArchivesSubscription(m.communitiesManager.Subscribe()) 848 m.updateCommunitiesActiveMembersPeriodically() 849 m.schedulePublishGrantsForControlledCommunities() 850 m.handleENSVerificationSubscription(ensSubscription) 851 m.watchConnectionChange() 852 m.watchChatsToUnmute() 853 m.watchCommunitiesToUnmute() 854 m.watchExpiredMessages() 855 m.watchIdentityImageChanges() 856 m.watchWalletBalances() 857 m.watchPendingCommunityRequestToJoin() 858 m.broadcastLatestUserStatus() 859 m.timeoutAutomaticStatusUpdates() 860 if !m.config.featureFlags.DisableCheckingForBackup { 861 m.startBackupLoop() 862 } 863 if !m.config.featureFlags.DisableAutoMessageLoop { 864 err = m.startAutoMessageLoop() 865 if err != nil { 866 return nil, err 867 } 868 } 869 m.startPeerSyncingLoop() 870 m.startSyncSettingsLoop() 871 m.startSettingsChangesLoop() 872 m.startCommunityRekeyLoop() 873 if m.config.codeControlFlags.CuratedCommunitiesUpdateLoopEnabled { 874 m.startCuratedCommunitiesUpdateLoop() 875 } 876 m.startMessageSegmentsCleanupLoop() 877 m.startHashRatchetEncryptedMessagesCleanupLoop() 878 m.startRequestMissingCommunityChannelsHRKeysLoop() 879 880 if err := m.cleanTopics(); err != nil { 881 return nil, err 882 } 883 response := &MessengerResponse{} 884 885 mailservers, err := m.allMailservers() 886 if err != nil { 887 return nil, err 888 } 889 890 response.Mailservers = mailservers 891 err = m.StartMailserverCycle(mailservers) 892 if err != nil { 893 return nil, err 894 } 895 896 if err := m.communityStorenodes.ReloadFromDB(); err != nil { 897 return nil, err 898 } 899 900 go m.checkForMissingMessagesLoop() 901 902 controlledCommunities, err := m.communitiesManager.Controlled() 903 if err != nil { 904 return nil, err 905 } 906 907 if m.archiveManager.IsReady() { 908 available := m.mailserverCycle.availabilitySubscriptions.Subscribe() 909 go func() { 910 <-available 911 m.InitHistoryArchiveTasks(controlledCommunities) 912 }() 913 } 914 915 for _, c := range controlledCommunities { 916 if c.Joined() && c.HasTokenPermissions() { 917 go m.communitiesManager.StartMembersReevaluationLoop(c.ID(), false) 918 } 919 } 920 921 joinedCommunities, err := m.communitiesManager.Joined() 922 if err != nil { 923 return nil, err 924 } 925 926 for _, joinedCommunity := range joinedCommunities { 927 // resume importing message history archives in case 928 // imports have been interrupted previously 929 err := m.resumeHistoryArchivesImport(joinedCommunity.ID()) 930 if err != nil { 931 return nil, err 932 } 933 } 934 m.enableHistoryArchivesImportAfterDelay() 935 936 if m.httpServer != nil { 937 err = m.httpServer.Start() 938 if err != nil { 939 return nil, err 940 } 941 } 942 943 err = m.GarbageCollectRemovedBookmarks() 944 if err != nil { 945 return nil, err 946 } 947 948 err = m.garbageCollectRemovedSavedAddresses() 949 if err != nil { 950 return nil, err 951 } 952 953 displayName, err := m.settings.DisplayName() 954 if err != nil { 955 return nil, err 956 } 957 if err := utils.ValidateDisplayName(&displayName); err != nil { 958 // Somehow a wrong display name was saved. We need to update it so that others accept our messages 959 pubKey, err := m.settings.GetPublicKey() 960 if err != nil { 961 return nil, err 962 } 963 replacementDisplayName := pubKey[:12] 964 m.logger.Warn("unaccepted display name was saved to the setting, reverting to pubkey substring", zap.String("displayName", displayName), zap.String("replacement", replacementDisplayName)) 965 966 if err := m.SetDisplayName(replacementDisplayName); err != nil { 967 // We do not return the error as we do not want to block the login for it 968 m.logger.Warn("error setting display name", zap.Error(err)) 969 } 970 } 971 972 return response, nil 973 } 974 975 func (m *Messenger) SetMediaServer(server *server.MediaServer) { 976 m.httpServer = server 977 m.communitiesManager.SetMediaServer(server) 978 } 979 980 func (m *Messenger) IdentityPublicKey() *ecdsa.PublicKey { 981 return &m.identity.PublicKey 982 } 983 984 func (m *Messenger) IdentityPublicKeyCompressed() []byte { 985 return crypto.CompressPubkey(m.IdentityPublicKey()) 986 } 987 988 func (m *Messenger) IdentityPublicKeyString() string { 989 return types.EncodeHex(crypto.FromECDSAPub(m.IdentityPublicKey())) 990 } 991 992 // cleanTopics remove any topic that does not have a Listen flag set 993 func (m *Messenger) cleanTopics() error { 994 if m.mailserversDatabase == nil { 995 return nil 996 } 997 var filters []*transport.Filter 998 for _, f := range m.transport.Filters() { 999 if f.Listen && !f.Ephemeral { 1000 filters = append(filters, f) 1001 } 1002 } 1003 1004 m.logger.Debug("keeping topics", zap.Any("filters", filters)) 1005 1006 return m.mailserversDatabase.SetTopics(filters) 1007 } 1008 1009 // handle connection change is called each time we go from offline/online or viceversa 1010 func (m *Messenger) handleConnectionChange(online bool) { 1011 // Update pushNotificationClient 1012 if m.pushNotificationClient != nil { 1013 if online { 1014 m.pushNotificationClient.Online() 1015 } else { 1016 m.pushNotificationClient.Offline() 1017 } 1018 } 1019 1020 // Update torrent manager 1021 if m.archiveManager != nil { 1022 m.archiveManager.SetOnline(online) 1023 } 1024 1025 // Publish contact code 1026 if online && m.shouldPublishContactCode { 1027 if err := m.publishContactCode(); err != nil { 1028 m.logger.Error("could not publish on contact code", zap.Error(err)) 1029 } 1030 m.shouldPublishContactCode = false 1031 } 1032 1033 // Start fetching messages from store nodes 1034 if online { 1035 m.asyncRequestAllHistoricMessages() 1036 } 1037 1038 // Update ENS verifier 1039 m.ensVerifier.SetOnline(online) 1040 } 1041 1042 func (m *Messenger) Online() bool { 1043 switch m.transport.WakuVersion() { 1044 case 2: 1045 return m.transport.PeerCount() > 0 1046 default: 1047 return m.node.PeersCount() > 0 1048 } 1049 } 1050 1051 func (m *Messenger) buildContactCodeAdvertisement() (*protobuf.ContactCodeAdvertisement, error) { 1052 if m.pushNotificationClient == nil || !m.pushNotificationClient.Enabled() { 1053 return nil, nil 1054 } 1055 m.logger.Debug("adding push notification info to contact code bundle") 1056 info, err := m.pushNotificationClient.MyPushNotificationQueryInfo() 1057 if err != nil { 1058 return nil, err 1059 } 1060 if len(info) == 0 { 1061 return nil, nil 1062 } 1063 return &protobuf.ContactCodeAdvertisement{ 1064 PushNotificationInfo: info, 1065 }, nil 1066 } 1067 1068 // publishContactCode sends a public message wrapped in the encryption 1069 // layer, which will propagate our bundle 1070 func (m *Messenger) publishContactCode() error { 1071 var payload []byte 1072 m.logger.Debug("sending contact code") 1073 contactCodeAdvertisement, err := m.buildContactCodeAdvertisement() 1074 if err != nil { 1075 m.logger.Error("could not build contact code advertisement", zap.Error(err)) 1076 } 1077 1078 if contactCodeAdvertisement == nil { 1079 contactCodeAdvertisement = &protobuf.ContactCodeAdvertisement{} 1080 } 1081 1082 err = m.attachChatIdentity(contactCodeAdvertisement) 1083 if err != nil { 1084 return err 1085 } 1086 1087 if contactCodeAdvertisement.ChatIdentity != nil { 1088 m.logger.Debug("attached chat identity", zap.Int("images len", len(contactCodeAdvertisement.ChatIdentity.Images))) 1089 } else { 1090 m.logger.Debug("no attached chat identity") 1091 } 1092 1093 payload, err = proto.Marshal(contactCodeAdvertisement) 1094 if err != nil { 1095 return err 1096 } 1097 1098 contactCodeTopic := transport.ContactCodeTopic(&m.identity.PublicKey) 1099 rawMessage := common.RawMessage{ 1100 LocalChatID: contactCodeTopic, 1101 MessageType: protobuf.ApplicationMetadataMessage_CONTACT_CODE_ADVERTISEMENT, 1102 Payload: payload, 1103 Priority: &common.LowPriority, 1104 } 1105 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 1106 defer cancel() 1107 1108 _, err = m.sender.SendPublic(ctx, contactCodeTopic, rawMessage) 1109 if err != nil { 1110 m.logger.Warn("failed to send a contact code", zap.Error(err)) 1111 } 1112 1113 joinedCommunities, err := m.communitiesManager.Joined() 1114 if err != nil { 1115 return err 1116 } 1117 for _, community := range joinedCommunities { 1118 rawMessage.LocalChatID = community.MemberUpdateChannelID() 1119 rawMessage.PubsubTopic = community.PubsubTopic() 1120 _, err = m.sender.SendPublic(ctx, rawMessage.LocalChatID, rawMessage) 1121 if err != nil { 1122 return err 1123 } 1124 } 1125 1126 m.logger.Debug("contact code sent") 1127 return err 1128 } 1129 1130 // contactCodeAdvertisement attaches a protobuf.ChatIdentity to the given protobuf.ContactCodeAdvertisement, 1131 // if the `shouldPublish` conditions are met 1132 func (m *Messenger) attachChatIdentity(cca *protobuf.ContactCodeAdvertisement) error { 1133 contactCodeTopic := transport.ContactCodeTopic(&m.identity.PublicKey) 1134 shouldPublish, err := m.shouldPublishChatIdentity(contactCodeTopic) 1135 if err != nil { 1136 return err 1137 } 1138 1139 if !shouldPublish { 1140 return nil 1141 } 1142 1143 cca.ChatIdentity, err = m.createChatIdentity(privateChat) 1144 if err != nil { 1145 return err 1146 } 1147 1148 img, err := m.multiAccounts.GetIdentityImage(m.account.KeyUID, images.SmallDimName) 1149 if err != nil { 1150 return err 1151 } 1152 1153 displayName, err := m.settings.DisplayName() 1154 if err != nil { 1155 return err 1156 } 1157 1158 bio, err := m.settings.Bio() 1159 if err != nil { 1160 return err 1161 } 1162 1163 profileShowcase, err := m.GetProfileShowcaseForSelfIdentity() 1164 if err != nil { 1165 return err 1166 } 1167 1168 identityHash, err := m.getIdentityHash(displayName, bio, img, profileShowcase, multiaccountscommon.IDToColorFallbackToBlue(cca.ChatIdentity.CustomizationColor)) 1169 if err != nil { 1170 return err 1171 } 1172 1173 err = m.persistence.SaveWhenChatIdentityLastPublished(contactCodeTopic, identityHash) 1174 if err != nil { 1175 return err 1176 } 1177 1178 return nil 1179 } 1180 1181 // handleStandaloneChatIdentity sends a standalone ChatIdentity message to a public or private channel if the publish criteria is met 1182 func (m *Messenger) handleStandaloneChatIdentity(chat *Chat) error { 1183 if chat.ChatType != ChatTypePublic && chat.ChatType != ChatTypeOneToOne { 1184 return nil 1185 } 1186 shouldPublishChatIdentity, err := m.shouldPublishChatIdentity(chat.ID) 1187 if err != nil { 1188 return err 1189 } 1190 if !shouldPublishChatIdentity { 1191 return nil 1192 } 1193 1194 chatContext := GetChatContextFromChatType(chat.ChatType) 1195 1196 ci, err := m.createChatIdentity(chatContext) 1197 if err != nil { 1198 return err 1199 } 1200 1201 payload, err := proto.Marshal(ci) 1202 if err != nil { 1203 return err 1204 } 1205 1206 rawMessage := common.RawMessage{ 1207 LocalChatID: chat.ID, 1208 MessageType: protobuf.ApplicationMetadataMessage_CHAT_IDENTITY, 1209 Payload: payload, 1210 Priority: &common.LowPriority, 1211 } 1212 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 1213 defer cancel() 1214 if chat.ChatType == ChatTypePublic { 1215 _, err = m.sender.SendPublic(ctx, chat.ID, rawMessage) 1216 if err != nil { 1217 return err 1218 } 1219 } else { 1220 pk, err := chat.PublicKey() 1221 if err != nil { 1222 return err 1223 } 1224 _, err = m.sender.SendPrivate(ctx, pk, &rawMessage) 1225 if err != nil { 1226 return err 1227 } 1228 1229 } 1230 1231 img, err := m.multiAccounts.GetIdentityImage(m.account.KeyUID, images.SmallDimName) 1232 if err != nil { 1233 return err 1234 } 1235 1236 displayName, err := m.settings.DisplayName() 1237 if err != nil { 1238 return err 1239 } 1240 1241 bio, err := m.settings.Bio() 1242 if err != nil { 1243 return err 1244 } 1245 1246 profileShowcase, err := m.GetProfileShowcaseForSelfIdentity() 1247 if err != nil { 1248 return err 1249 } 1250 1251 identityHash, err := m.getIdentityHash(displayName, bio, img, profileShowcase, multiaccountscommon.IDToColorFallbackToBlue(ci.CustomizationColor)) 1252 if err != nil { 1253 return err 1254 } 1255 1256 err = m.persistence.SaveWhenChatIdentityLastPublished(chat.ID, identityHash) 1257 if err != nil { 1258 return err 1259 } 1260 1261 return nil 1262 } 1263 1264 func (m *Messenger) getIdentityHash(displayName, bio string, img *images.IdentityImage, profileShowcase *protobuf.ProfileShowcase, customizationColor multiaccountscommon.CustomizationColor) ([]byte, error) { 1265 profileShowcaseData, err := proto.Marshal(profileShowcase) 1266 if err != nil { 1267 return []byte{}, err 1268 } 1269 1270 if img == nil { 1271 return crypto.Keccak256([]byte(displayName), []byte(bio), profileShowcaseData, []byte(customizationColor)), nil 1272 } 1273 1274 return crypto.Keccak256(img.Payload, []byte(displayName), []byte(bio), profileShowcaseData, []byte(customizationColor)), nil 1275 } 1276 1277 // shouldPublishChatIdentity returns true if the last time the ChatIdentity was attached was more than 24 hours ago 1278 func (m *Messenger) shouldPublishChatIdentity(chatID string) (bool, error) { 1279 if m.account == nil { 1280 return false, nil 1281 } 1282 1283 // Check we have at least one image or a display name 1284 img, err := m.multiAccounts.GetIdentityImage(m.account.KeyUID, images.SmallDimName) 1285 if err != nil { 1286 return false, err 1287 } 1288 1289 displayName, err := m.settings.DisplayName() 1290 if err != nil { 1291 return false, err 1292 } 1293 1294 if img == nil && displayName == "" { 1295 return false, nil 1296 } 1297 1298 lp, hash, err := m.persistence.GetWhenChatIdentityLastPublished(chatID) 1299 if err != nil { 1300 return false, err 1301 } 1302 1303 bio, err := m.settings.Bio() 1304 if err != nil { 1305 return false, err 1306 } 1307 1308 profileShowcase, err := m.GetProfileShowcaseForSelfIdentity() 1309 if err != nil { 1310 return false, err 1311 } 1312 1313 identityHash, err := m.getIdentityHash(displayName, bio, img, profileShowcase, m.account.GetCustomizationColor()) 1314 if err != nil { 1315 return false, err 1316 } 1317 1318 if !bytes.Equal(hash, identityHash) { 1319 return true, nil 1320 } 1321 1322 // Note: If Alice does not add bob as a contact she will not update her contact code with images 1323 return lp == 0 || time.Now().Unix()-lp > 24*60*60, nil 1324 } 1325 1326 // createChatIdentity creates a context based protobuf.ChatIdentity. 1327 // context 'public-chat' will attach only the 'thumbnail' IdentityImage 1328 // context 'private-chat' will attach all IdentityImage 1329 func (m *Messenger) createChatIdentity(context ChatContext) (*protobuf.ChatIdentity, error) { 1330 m.logger.Info("called createChatIdentity", 1331 zap.String("account keyUID", m.account.KeyUID), 1332 zap.String("context", string(context)), 1333 ) 1334 1335 displayName, err := m.settings.DisplayName() 1336 if err != nil { 1337 return nil, err 1338 } 1339 1340 bio, err := m.settings.Bio() 1341 if err != nil { 1342 return nil, err 1343 } 1344 1345 profileShowcase, err := m.GetProfileShowcaseForSelfIdentity() 1346 if err != nil { 1347 return nil, err 1348 } 1349 1350 ci := &protobuf.ChatIdentity{ 1351 Clock: m.transport.GetCurrentTime(), 1352 EnsName: "", // TODO add ENS name handling to dedicate PR 1353 DisplayName: displayName, 1354 Description: bio, 1355 ProfileShowcase: profileShowcase, 1356 CustomizationColor: m.account.GetCustomizationColorID(), 1357 } 1358 1359 err = m.attachIdentityImagesToChatIdentity(context, ci) 1360 if err != nil { 1361 return nil, err 1362 } 1363 1364 return ci, nil 1365 } 1366 1367 // adaptIdentityImageToProtobuf Adapts a images.IdentityImage to protobuf.IdentityImage 1368 func (m *Messenger) adaptIdentityImageToProtobuf(img *images.IdentityImage) *protobuf.IdentityImage { 1369 return &protobuf.IdentityImage{ 1370 Payload: img.Payload, 1371 SourceType: protobuf.IdentityImage_RAW_PAYLOAD, // TODO add ENS avatar handling to dedicated PR 1372 ImageFormat: images.GetProtobufImageFormat(img.Payload), 1373 } 1374 } 1375 1376 func (m *Messenger) attachIdentityImagesToChatIdentity(context ChatContext, ci *protobuf.ChatIdentity) error { 1377 s, err := m.getSettings() 1378 if err != nil { 1379 return err 1380 } 1381 1382 if s.ProfilePicturesShowTo == settings.ProfilePicturesShowToNone { 1383 m.logger.Info(fmt.Sprintf("settings.ProfilePicturesShowTo is set to '%d', skipping attaching IdentityImages", s.ProfilePicturesShowTo)) 1384 return nil 1385 } 1386 1387 ciis := make(map[string]*protobuf.IdentityImage) 1388 1389 switch context { 1390 case publicChat: 1391 m.logger.Info(fmt.Sprintf("handling %s ChatIdentity", context)) 1392 1393 img, err := m.multiAccounts.GetIdentityImage(m.account.KeyUID, images.SmallDimName) 1394 if err != nil { 1395 return err 1396 } 1397 1398 if img == nil { 1399 return nil 1400 } 1401 1402 ciis[images.SmallDimName] = m.adaptIdentityImageToProtobuf(img) 1403 ci.Images = ciis 1404 1405 case privateChat: 1406 m.logger.Info(fmt.Sprintf("handling %s ChatIdentity", context)) 1407 1408 imgs, err := m.multiAccounts.GetIdentityImages(m.account.KeyUID) 1409 if err != nil { 1410 return err 1411 } 1412 1413 for _, img := range imgs { 1414 ciis[img.Name] = m.adaptIdentityImageToProtobuf(img) 1415 } 1416 ci.Images = ciis 1417 1418 default: 1419 return fmt.Errorf("unknown ChatIdentity context '%s'", context) 1420 } 1421 1422 if s.ProfilePicturesShowTo == settings.ProfilePicturesShowToContactsOnly { 1423 err := EncryptIdentityImagesWithContactPubKeys(ci.Images, m) 1424 if err != nil { 1425 return err 1426 } 1427 } 1428 1429 return nil 1430 } 1431 1432 // handleSharedSecrets process the negotiated secrets received from the encryption layer 1433 func (m *Messenger) handleSharedSecrets(secrets []*sharedsecret.Secret) error { 1434 for _, secret := range secrets { 1435 fSecret := types.NegotiatedSecret{ 1436 PublicKey: secret.Identity, 1437 Key: secret.Key, 1438 } 1439 _, err := m.transport.ProcessNegotiatedSecret(fSecret) 1440 if err != nil { 1441 return err 1442 } 1443 } 1444 return nil 1445 } 1446 1447 // handleInstallations adds the installations in the installations map 1448 func (m *Messenger) handleInstallations(installations []*multidevice.Installation) { 1449 for _, installation := range installations { 1450 if installation.Identity == contactIDFromPublicKey(&m.identity.PublicKey) { 1451 if _, ok := m.allInstallations.Load(installation.ID); !ok { 1452 m.allInstallations.Store(installation.ID, installation) 1453 m.modifiedInstallations.Store(installation.ID, true) 1454 } 1455 } 1456 } 1457 } 1458 1459 // handleEncryptionLayerSubscriptions handles events from the encryption layer 1460 func (m *Messenger) handleEncryptionLayerSubscriptions(subscriptions *encryption.Subscriptions) { 1461 go func() { 1462 for { 1463 select { 1464 case <-subscriptions.SendContactCode: 1465 if err := m.publishContactCode(); err != nil { 1466 m.logger.Error("failed to publish contact code", zap.Error(err)) 1467 } 1468 // we also piggy-back to clean up cached messages 1469 if err := m.transport.CleanMessagesProcessed(m.getTimesource().GetCurrentTime() - messageCacheIntervalMs); err != nil { 1470 m.logger.Error("failed to clean processed messages", zap.Error(err)) 1471 } 1472 1473 case keys := <-subscriptions.NewHashRatchetKeys: 1474 if m.communitiesManager == nil { 1475 continue 1476 } 1477 if err := m.communitiesManager.NewHashRatchetKeys(keys); err != nil { 1478 m.logger.Error("failed to invalidate cache for decrypted communities", zap.Error(err)) 1479 } 1480 case <-subscriptions.Quit: 1481 m.logger.Debug("quitting encryption subscription loop") 1482 return 1483 } 1484 } 1485 }() 1486 } 1487 1488 func (m *Messenger) handleENSVerified(records []*ens.VerificationRecord) { 1489 var contacts []*Contact 1490 for _, record := range records { 1491 m.logger.Info("handling record", zap.Any("record", record)) 1492 contact, ok := m.allContacts.Load(record.PublicKey) 1493 if !ok { 1494 m.logger.Info("contact not found") 1495 continue 1496 } 1497 1498 contact.ENSVerified = record.Verified 1499 contact.EnsName = record.Name 1500 contacts = append(contacts, contact) 1501 } 1502 1503 m.logger.Info("handled records", zap.Any("contacts", contacts)) 1504 if len(contacts) != 0 { 1505 if err := m.persistence.SaveContacts(contacts); err != nil { 1506 m.logger.Error("failed to save contacts", zap.Error(err)) 1507 return 1508 } 1509 } 1510 1511 m.PublishMessengerResponse(&MessengerResponse{Contacts: contacts}) 1512 } 1513 1514 func (m *Messenger) handleENSVerificationSubscription(c chan []*ens.VerificationRecord) { 1515 go func() { 1516 for { 1517 select { 1518 case records, more := <-c: 1519 if !more { 1520 m.logger.Info("No more records, quitting") 1521 return 1522 } 1523 if len(records) != 0 { 1524 m.logger.Info("handling records", zap.Any("records", records)) 1525 m.handleENSVerified(records) 1526 } 1527 case <-m.quit: 1528 return 1529 } 1530 } 1531 }() 1532 } 1533 1534 // watchConnectionChange checks the connection status and call handleConnectionChange when this changes 1535 func (m *Messenger) watchConnectionChange() { 1536 state := m.Online() 1537 // lastCheck, sleepDetention and keepAlive helps us recognizing when computer was offline because of sleep, lid closed, etc. 1538 lastCheck := time.Now().Unix() 1539 sleepDetentionInSecs := int64(20) 1540 keepAlivePeriod := 15 * time.Second // must be lower than sleepDetentionInSecs 1541 1542 processNewState := func(newState bool) { 1543 now := time.Now().Unix() 1544 force := now-lastCheck > sleepDetentionInSecs 1545 lastCheck = now 1546 if !force && state == newState { 1547 return 1548 } 1549 state = newState 1550 m.logger.Debug("connection changed", zap.Bool("online", state), zap.Bool("force", force)) 1551 m.handleConnectionChange(state) 1552 } 1553 1554 pollConnectionStatus := func() { 1555 func() { 1556 for { 1557 select { 1558 case <-time.After(200 * time.Millisecond): 1559 processNewState(m.Online()) 1560 case <-m.quit: 1561 return 1562 } 1563 } 1564 }() 1565 } 1566 1567 subscribedConnectionStatus := func(subscription *types.ConnStatusSubscription) { 1568 defer subscription.Unsubscribe() 1569 ticker := time.NewTicker(keepAlivePeriod) 1570 defer ticker.Stop() 1571 for { 1572 select { 1573 case status := <-subscription.C: 1574 processNewState(status.IsOnline) 1575 case <-ticker.C: 1576 processNewState(m.Online()) 1577 case <-m.quit: 1578 return 1579 } 1580 } 1581 } 1582 1583 m.logger.Debug("watching connection changes") 1584 m.handleConnectionChange(state) 1585 1586 waku, err := m.node.GetWakuV2(nil) 1587 if err != nil { 1588 // No waku v2, we can't watch connection changes 1589 // Instead we will poll the connection status. 1590 m.logger.Warn("using WakuV1, can't watch connection changes, this might be have side-effects") 1591 go pollConnectionStatus() 1592 return 1593 } 1594 1595 // Wakuv2 is not going to return an error 1596 // from SubscribeToConnStatusChanges 1597 subscription, _ := waku.SubscribeToConnStatusChanges() 1598 1599 go subscribedConnectionStatus(subscription) 1600 } 1601 1602 // watchChatsToUnmute checks every minute to identify and unmute chats that should no longer be muted. 1603 func (m *Messenger) watchChatsToUnmute() { 1604 m.logger.Debug("Checking for chats to unmute every minute") 1605 go func() { 1606 for { 1607 // Execute the check immediately upon starting 1608 response := &MessengerResponse{} 1609 currTime := time.Now() 1610 1611 m.allChats.Range(func(chatID string, c *Chat) bool { 1612 chatMuteTill := c.MuteTill 1613 if currTime.After(chatMuteTill) && !chatMuteTill.Equal(time.Time{}) && c.Muted { 1614 err := m.persistence.UnmuteChat(c.ID) 1615 if err != nil { 1616 m.logger.Warn("watchChatsToUnmute error", zap.Any("Couldn't unmute chat", err)) 1617 return false 1618 } 1619 c.Muted = false 1620 c.MuteTill = time.Time{} 1621 response.AddChat(c) 1622 } 1623 return true 1624 }) 1625 1626 if !response.IsEmpty() { 1627 signal.SendNewMessages(response) 1628 } 1629 1630 // Calculate the time until the next whole minute 1631 now := time.Now() 1632 waitDuration := time.Until(now.Truncate(time.Minute).Add(time.Minute)) 1633 1634 // Wait until the next minute 1635 select { 1636 case <-time.After(waitDuration): 1637 // Continue to next iteration 1638 case <-m.quit: 1639 return 1640 } 1641 } 1642 }() 1643 } 1644 1645 // watchCommunitiesToUnmute checks every minute to identify and unmute communities that should no longer be muted. 1646 func (m *Messenger) watchCommunitiesToUnmute() { 1647 m.logger.Debug("Checking for communities to unmute every minute") 1648 go func() { 1649 for { 1650 // Execute the check immediately upon starting 1651 response, err := m.CheckCommunitiesToUnmute() 1652 if err != nil { 1653 m.logger.Warn("watchCommunitiesToUnmute error", zap.Any("Couldn't unmute communities", err)) 1654 } else if !response.IsEmpty() { 1655 signal.SendNewMessages(response) 1656 } 1657 1658 // Calculate the time until the next whole minute 1659 now := time.Now() 1660 waitDuration := time.Until(now.Truncate(time.Minute).Add(time.Minute)) 1661 1662 // Wait until the next minute 1663 select { 1664 case <-time.After(waitDuration): 1665 // Continue to next iteration 1666 case <-m.quit: 1667 return 1668 } 1669 } 1670 }() 1671 } 1672 1673 // watchIdentityImageChanges checks for identity images changes and publishes to the contact code when it happens 1674 func (m *Messenger) watchIdentityImageChanges() { 1675 m.logger.Debug("watching identity image changes") 1676 if m.multiAccounts == nil { 1677 return 1678 } 1679 1680 channel := m.multiAccounts.SubscribeToIdentityImageChanges() 1681 1682 go func() { 1683 for { 1684 select { 1685 case change := <-channel: 1686 identityImages, err := m.multiAccounts.GetIdentityImages(m.account.KeyUID) 1687 if err != nil { 1688 m.logger.Error("failed to get profile pictures to save self contact", zap.Error(err)) 1689 break 1690 } 1691 1692 identityImagesMap := make(map[string]images.IdentityImage) 1693 for _, img := range identityImages { 1694 identityImagesMap[img.Name] = *img 1695 } 1696 m.selfContact.Images = identityImagesMap 1697 m.publishSelfContactSubscriptions(&SelfContactChangeEvent{ImagesChanged: true}) 1698 1699 if change.PublishExpected { 1700 err = m.syncProfilePictures(m.dispatchMessage, identityImages) 1701 if err != nil { 1702 m.logger.Error("failed to sync profile pictures to paired devices", zap.Error(err)) 1703 } 1704 err = m.PublishIdentityImage() 1705 if err != nil { 1706 m.logger.Error("failed to publish identity image", zap.Error(err)) 1707 } 1708 } 1709 case <-m.quit: 1710 return 1711 } 1712 } 1713 }() 1714 } 1715 1716 func (m *Messenger) watchPendingCommunityRequestToJoin() { 1717 m.logger.Debug("watching community request to join") 1718 1719 go func() { 1720 for { 1721 select { 1722 case <-time.After(time.Minute * 10): 1723 _, err := m.CheckAndDeletePendingRequestToJoinCommunity(context.Background(), false) 1724 if err != nil { 1725 m.logger.Error("failed to check and delete pending request to join community", zap.Error(err)) 1726 } 1727 case <-m.quit: 1728 return 1729 } 1730 } 1731 }() 1732 } 1733 1734 func (m *Messenger) PublishIdentityImage() error { 1735 // Reset last published time for ChatIdentity so new contact can receive data 1736 err := m.resetLastPublishedTimeForChatIdentity() 1737 if err != nil { 1738 m.logger.Error("failed to reset publish time", zap.Error(err)) 1739 return err 1740 } 1741 1742 // If not online, we schedule it 1743 if !m.Online() { 1744 m.shouldPublishContactCode = true 1745 return nil 1746 } 1747 1748 return m.publishContactCode() 1749 } 1750 1751 // handlePushNotificationClientRegistration handles registration events 1752 func (m *Messenger) handlePushNotificationClientRegistrations(c chan struct{}) { 1753 go func() { 1754 for { 1755 _, more := <-c 1756 if !more { 1757 return 1758 } 1759 if err := m.publishContactCode(); err != nil { 1760 m.logger.Error("failed to publish contact code", zap.Error(err)) 1761 } 1762 1763 } 1764 }() 1765 } 1766 1767 // InitFilters analyzes chats and contacts in order to setup filters 1768 // which are responsible for retrieving messages. 1769 func (m *Messenger) InitFilters() error { 1770 1771 // Seed the for color generation 1772 rand.Seed(time.Now().Unix()) 1773 1774 logger := m.logger.With(zap.String("site", "Init")) 1775 1776 // Community requests will arrive in this pubsub topic 1777 err := m.SubscribeToPubsubTopic(shard.DefaultNonProtectedPubsubTopic(), nil) 1778 if err != nil { 1779 return err 1780 } 1781 1782 var ( 1783 filtersToInit []transport.FiltersToInitialize 1784 publicKeys []*ecdsa.PublicKey 1785 ) 1786 1787 joinedCommunities, err := m.communitiesManager.Joined() 1788 if err != nil { 1789 return err 1790 } 1791 for _, org := range joinedCommunities { 1792 // the org advertise on the public topic derived by the pk 1793 filtersToInit = append(filtersToInit, m.DefaultFilters(org)...) 1794 1795 // This is for status-go versions that didn't have `CommunitySettings` 1796 // We need to ensure communities that existed before community settings 1797 // were introduced will have community settings as well 1798 exists, err := m.communitiesManager.CommunitySettingsExist(org.ID()) 1799 if err != nil { 1800 logger.Warn("failed to check if community settings exist", zap.Error(err)) 1801 continue 1802 } 1803 1804 if !exists { 1805 communitySettings := communities.CommunitySettings{ 1806 CommunityID: org.IDString(), 1807 HistoryArchiveSupportEnabled: true, 1808 } 1809 1810 err = m.communitiesManager.SaveCommunitySettings(communitySettings) 1811 if err != nil { 1812 logger.Warn("failed to save community settings", zap.Error(err)) 1813 } 1814 continue 1815 } 1816 1817 // In case we do have settings, but the history archive support is disabled 1818 // for this community, we enable it, as this should be the default for all 1819 // non-admin communities 1820 communitySettings, err := m.communitiesManager.GetCommunitySettingsByID(org.ID()) 1821 if err != nil { 1822 logger.Warn("failed to fetch community settings", zap.Error(err)) 1823 continue 1824 } 1825 1826 if !org.IsControlNode() && !communitySettings.HistoryArchiveSupportEnabled { 1827 communitySettings.HistoryArchiveSupportEnabled = true 1828 err = m.communitiesManager.UpdateCommunitySettings(*communitySettings) 1829 if err != nil { 1830 logger.Warn("failed to update community settings", zap.Error(err)) 1831 } 1832 } 1833 } 1834 1835 spectatedCommunities, err := m.communitiesManager.Spectated() 1836 if err != nil { 1837 return err 1838 } 1839 for _, org := range spectatedCommunities { 1840 filtersToInit = append(filtersToInit, m.DefaultFilters(org)...) 1841 } 1842 1843 // Get chat IDs and public keys from the existing chats. 1844 // TODO: Get only active chats by the query. 1845 chats, err := m.persistence.Chats() 1846 if err != nil { 1847 return err 1848 } 1849 1850 communityInfo := make(map[string]*communities.Community) 1851 for _, chat := range chats { 1852 if err := chat.Validate(); err != nil { 1853 logger.Warn("failed to validate chat", zap.Error(err)) 1854 continue 1855 } 1856 1857 if err = m.initChatFirstMessageTimestamp(chat); err != nil { 1858 logger.Warn("failed to init first message timestamp", zap.Error(err)) 1859 continue 1860 } 1861 1862 if !chat.Active || chat.Timeline() { 1863 m.allChats.Store(chat.ID, chat) 1864 continue 1865 } 1866 1867 switch chat.ChatType { 1868 case ChatTypePublic, ChatTypeProfile: 1869 filtersToInit = append(filtersToInit, transport.FiltersToInitialize{ChatID: chat.ID}) 1870 case ChatTypeCommunityChat: 1871 community, ok := communityInfo[chat.CommunityID] 1872 if !ok { 1873 community, err = m.communitiesManager.GetByIDString(chat.CommunityID) 1874 if err != nil { 1875 return err 1876 } 1877 communityInfo[chat.CommunityID] = community 1878 } 1879 1880 if chat.UnviewedMessagesCount > 0 || chat.UnviewedMentionsCount > 0 { 1881 // Make sure the unread count is 0 for the channels the user cannot view 1882 // It's possible that the users received messages to a channel before permissions were added 1883 canView := community.CanView(&m.identity.PublicKey, chat.CommunityChatID()) 1884 1885 if !canView { 1886 chat.UnviewedMessagesCount = 0 1887 chat.UnviewedMentionsCount = 0 1888 } 1889 } 1890 1891 filtersToInit = append(filtersToInit, transport.FiltersToInitialize{ChatID: chat.ID, PubsubTopic: community.PubsubTopic()}) 1892 case ChatTypeOneToOne: 1893 pk, err := chat.PublicKey() 1894 if err != nil { 1895 return err 1896 } 1897 publicKeys = append(publicKeys, pk) 1898 case ChatTypePrivateGroupChat: 1899 for _, member := range chat.Members { 1900 publicKey, err := member.PublicKey() 1901 if err != nil { 1902 return errors.Wrapf(err, "invalid public key for member %s in chat %s", member.ID, chat.Name) 1903 } 1904 publicKeys = append(publicKeys, publicKey) 1905 } 1906 default: 1907 return errors.New("invalid chat type") 1908 } 1909 1910 m.allChats.Store(chat.ID, chat) 1911 } 1912 1913 // Timeline and profile chats are deprecated. 1914 // This code can be removed after some reasonable time. 1915 1916 // upsert timeline chat 1917 if !deprecation.ChatProfileDeprecated { 1918 err = m.ensureTimelineChat() 1919 if err != nil { 1920 return err 1921 } 1922 } 1923 1924 // upsert profile chat 1925 if !deprecation.ChatTimelineDeprecated { 1926 err = m.ensureMyOwnProfileChat() 1927 if err != nil { 1928 return err 1929 } 1930 } 1931 1932 // Get chat IDs and public keys from the contacts. 1933 contacts, err := m.persistence.Contacts() 1934 if err != nil { 1935 return err 1936 } 1937 for idx, contact := range contacts { 1938 if err = m.updateContactImagesURL(contact); err != nil { 1939 return err 1940 } 1941 m.allContacts.Store(contact.ID, contacts[idx]) 1942 // We only need filters for contacts added by us and not blocked. 1943 if !contact.added() || contact.Blocked { 1944 continue 1945 } 1946 publicKey, err := contact.PublicKey() 1947 if err != nil { 1948 logger.Error("failed to get contact's public key", zap.Error(err)) 1949 continue 1950 } 1951 publicKeys = append(publicKeys, publicKey) 1952 } 1953 1954 _, err = m.transport.InitFilters(filtersToInit, publicKeys) 1955 if err != nil { 1956 return err 1957 } 1958 1959 // Init filters for the communities we control 1960 var communityFiltersToInitialize []transport.CommunityFilterToInitialize 1961 controlledCommunities, err := m.communitiesManager.Controlled() 1962 if err != nil { 1963 return err 1964 } 1965 1966 for _, c := range controlledCommunities { 1967 communityFiltersToInitialize = append(communityFiltersToInitialize, transport.CommunityFilterToInitialize{ 1968 Shard: c.Shard(), 1969 PrivKey: c.PrivateKey(), 1970 }) 1971 } 1972 1973 _, err = m.InitCommunityFilters(communityFiltersToInitialize) 1974 if err != nil { 1975 return err 1976 } 1977 1978 return nil 1979 } 1980 1981 // Shutdown takes care of ensuring a clean shutdown of Messenger 1982 func (m *Messenger) Shutdown() (err error) { 1983 if m == nil { 1984 return nil 1985 } 1986 1987 select { 1988 case _, ok := <-m.quit: 1989 if !ok { 1990 return errors.New("messenger already shutdown") 1991 } 1992 default: 1993 } 1994 1995 close(m.quit) 1996 m.cancel() 1997 m.shutdownWaitGroup.Wait() 1998 for i, task := range m.shutdownTasks { 1999 m.logger.Debug("running shutdown task", zap.Int("n", i)) 2000 if tErr := task(); tErr != nil { 2001 m.logger.Info("shutdown task failed", zap.Error(tErr)) 2002 if err == nil { 2003 // First error appeared. 2004 err = tErr 2005 } else { 2006 // We return all errors. They will be concatenated in the order of occurrence, 2007 // however, they will also be returned as a single error. 2008 err = errors.Wrap(err, tErr.Error()) 2009 } 2010 } 2011 } 2012 return 2013 } 2014 2015 // NOT IMPLEMENTED 2016 func (m *Messenger) SelectMailserver(id string) error { 2017 return ErrNotImplemented 2018 } 2019 2020 // NOT IMPLEMENTED 2021 func (m *Messenger) AddMailserver(enode string) error { 2022 return ErrNotImplemented 2023 } 2024 2025 // NOT IMPLEMENTED 2026 func (m *Messenger) RemoveMailserver(id string) error { 2027 return ErrNotImplemented 2028 } 2029 2030 // NOT IMPLEMENTED 2031 func (m *Messenger) Mailservers() ([]string, error) { 2032 return nil, ErrNotImplemented 2033 } 2034 2035 func (m *Messenger) initChatFirstMessageTimestamp(chat *Chat) error { 2036 if !chat.CommunityChat() || chat.FirstMessageTimestamp != FirstMessageTimestampUndefined { 2037 return nil 2038 } 2039 2040 oldestMessageTimestamp, hasAnyMessage, err := m.persistence.OldestMessageWhisperTimestampByChatID(chat.ID) 2041 if err != nil { 2042 return err 2043 } 2044 2045 if hasAnyMessage { 2046 if oldestMessageTimestamp == FirstMessageTimestampUndefined { 2047 return nil 2048 } 2049 return m.updateChatFirstMessageTimestamp(chat, whisperToUnixTimestamp(oldestMessageTimestamp), &MessengerResponse{}) 2050 } 2051 2052 return m.updateChatFirstMessageTimestamp(chat, FirstMessageTimestampNoMessage, &MessengerResponse{}) 2053 } 2054 2055 func (m *Messenger) addMessagesAndChat(chat *Chat, messages []*common.Message, response *MessengerResponse) (*MessengerResponse, error) { 2056 response.AddChat(chat) 2057 response.AddMessages(messages) 2058 err := m.persistence.SaveMessages(response.Messages()) 2059 if err != nil { 2060 return nil, err 2061 } 2062 2063 return response, m.saveChat(chat) 2064 } 2065 2066 func (m *Messenger) reregisterForPushNotifications() error { 2067 m.logger.Info("contact state changed, re-registering for push notification") 2068 if m.pushNotificationClient == nil { 2069 return nil 2070 } 2071 2072 return m.pushNotificationClient.Reregister(m.pushNotificationOptions()) 2073 } 2074 2075 // ReSendChatMessage pulls a message from the database and sends it again 2076 func (m *Messenger) ReSendChatMessage(ctx context.Context, messageID string) error { 2077 return m.reSendRawMessage(ctx, messageID) 2078 } 2079 2080 func (m *Messenger) SetLocalPairing(localPairing bool) { 2081 m.localPairing = localPairing 2082 } 2083 func (m *Messenger) hasPairedDevices() bool { 2084 logger := m.logger.Named("hasPairedDevices") 2085 2086 if m.localPairing { 2087 return true 2088 } 2089 2090 var count int 2091 m.allInstallations.Range(func(installationID string, installation *multidevice.Installation) (shouldContinue bool) { 2092 if installation.Enabled { 2093 count++ 2094 } 2095 return true 2096 }) 2097 logger.Debug("installations info", 2098 zap.Int("Number of installations", m.allInstallations.Len()), 2099 zap.Int("Number of enabled installations", count)) 2100 return count > 1 2101 } 2102 2103 func (m *Messenger) HasPairedDevices() bool { 2104 return m.hasPairedDevices() 2105 } 2106 2107 // sendToPairedDevices will check if we have any paired devices and send to them if necessary 2108 func (m *Messenger) sendToPairedDevices(ctx context.Context, spec common.RawMessage) error { 2109 hasPairedDevices := m.hasPairedDevices() 2110 // We send a message to any paired device 2111 if hasPairedDevices { 2112 _, err := m.sender.SendPrivate(ctx, &m.identity.PublicKey, &spec) 2113 if err != nil { 2114 return err 2115 } 2116 } 2117 return nil 2118 } 2119 2120 func (m *Messenger) dispatchPairInstallationMessage(ctx context.Context, spec common.RawMessage) (common.RawMessage, error) { 2121 var err error 2122 var id []byte 2123 2124 id, err = m.sender.SendPairInstallation(ctx, &m.identity.PublicKey, spec) 2125 2126 if err != nil { 2127 return spec, err 2128 } 2129 spec.ID = types.EncodeHex(id) 2130 spec.SendCount++ 2131 err = m.persistence.SaveRawMessage(&spec) 2132 if err != nil { 2133 return spec, err 2134 } 2135 2136 return spec, nil 2137 } 2138 2139 func (m *Messenger) dispatchMessage(ctx context.Context, rawMessage common.RawMessage) (common.RawMessage, error) { 2140 var err error 2141 var id []byte 2142 logger := m.logger.With(zap.String("site", "dispatchMessage"), zap.String("chatID", rawMessage.LocalChatID)) 2143 chat, ok := m.allChats.Load(rawMessage.LocalChatID) 2144 if !ok { 2145 return rawMessage, errors.New("no chat found") 2146 } 2147 2148 switch chat.ChatType { 2149 case ChatTypeOneToOne: 2150 publicKey, err := chat.PublicKey() 2151 if err != nil { 2152 return rawMessage, err 2153 } 2154 2155 //SendPrivate will alter message identity and possibly datasyncid, so we save an unchanged 2156 //message for sending to paired devices later 2157 specCopyForPairedDevices := rawMessage 2158 if !common.IsPubKeyEqual(publicKey, &m.identity.PublicKey) || rawMessage.SkipEncryptionLayer { 2159 id, err = m.sender.SendPrivate(ctx, publicKey, &rawMessage) 2160 2161 if err != nil { 2162 return rawMessage, err 2163 } 2164 } 2165 2166 err = m.sendToPairedDevices(ctx, specCopyForPairedDevices) 2167 2168 if err != nil { 2169 return rawMessage, err 2170 } 2171 2172 case ChatTypePublic, ChatTypeProfile: 2173 logger.Debug("sending public message", zap.String("chatName", chat.Name)) 2174 id, err = m.sender.SendPublic(ctx, chat.ID, rawMessage) 2175 if err != nil { 2176 return rawMessage, err 2177 } 2178 2179 case ChatTypeCommunityChat: 2180 community, err := m.communitiesManager.GetByIDString(chat.CommunityID) 2181 if err != nil { 2182 return rawMessage, err 2183 } 2184 rawMessage.PubsubTopic = community.PubsubTopic() 2185 2186 canPost, err := m.communitiesManager.CanPost(&m.identity.PublicKey, chat.CommunityID, chat.CommunityChatID(), rawMessage.MessageType) 2187 if err != nil { 2188 return rawMessage, err 2189 } 2190 2191 if !canPost { 2192 m.logger.Error("can't post on chat", 2193 zap.String("chatID", chat.ID), 2194 zap.String("chatName", chat.Name), 2195 zap.Any("messageType", rawMessage.MessageType), 2196 ) 2197 return rawMessage, fmt.Errorf("can't post message type '%d' on chat '%s'", rawMessage.MessageType, chat.ID) 2198 } 2199 2200 logger.Debug("sending community chat message", zap.String("chatName", chat.Name)) 2201 isCommunityEncrypted, err := m.communitiesManager.IsEncrypted(chat.CommunityID) 2202 if err != nil { 2203 return rawMessage, err 2204 } 2205 isChannelEncrypted, err := m.communitiesManager.IsChannelEncrypted(chat.CommunityID, chat.ID) 2206 if err != nil { 2207 return rawMessage, err 2208 } 2209 isEncrypted := isCommunityEncrypted || isChannelEncrypted 2210 if !isEncrypted { 2211 id, err = m.sender.SendPublic(ctx, chat.ID, rawMessage) 2212 if err != nil { 2213 return rawMessage, err 2214 } 2215 } else { 2216 rawMessage.CommunityID, err = types.DecodeHex(chat.CommunityID) 2217 if err != nil { 2218 return rawMessage, err 2219 } 2220 2221 if isChannelEncrypted { 2222 rawMessage.HashRatchetGroupID = []byte(chat.ID) 2223 } else { 2224 rawMessage.HashRatchetGroupID = rawMessage.CommunityID 2225 } 2226 2227 id, err = m.sender.SendCommunityMessage(ctx, &rawMessage) 2228 if err != nil { 2229 return rawMessage, err 2230 } 2231 } 2232 case ChatTypePrivateGroupChat: 2233 logger.Debug("sending group message", zap.String("chatName", chat.Name)) 2234 if rawMessage.Recipients == nil { 2235 rawMessage.Recipients, err = chat.MembersAsPublicKeys() 2236 if err != nil { 2237 return rawMessage, err 2238 } 2239 } 2240 2241 hasPairedDevices := m.hasPairedDevices() 2242 2243 if !hasPairedDevices { 2244 2245 // Filter out my key from the recipients 2246 n := 0 2247 for _, recipient := range rawMessage.Recipients { 2248 if !common.IsPubKeyEqual(recipient, &m.identity.PublicKey) { 2249 rawMessage.Recipients[n] = recipient 2250 n++ 2251 } 2252 } 2253 rawMessage.Recipients = rawMessage.Recipients[:n] 2254 } 2255 2256 // We won't really send the message out if there's no recipients 2257 if len(rawMessage.Recipients) == 0 { 2258 rawMessage.Sent = true 2259 } 2260 2261 // We skip wrapping in some cases (emoji reactions for example) 2262 if !rawMessage.SkipGroupMessageWrap { 2263 rawMessage.MessageType = protobuf.ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE 2264 } 2265 2266 id, err = m.sender.SendGroup(ctx, rawMessage.Recipients, rawMessage) 2267 if err != nil { 2268 return rawMessage, err 2269 } 2270 2271 default: 2272 return rawMessage, errors.New("chat type not supported") 2273 } 2274 rawMessage.ID = types.EncodeHex(id) 2275 rawMessage.SendCount++ 2276 rawMessage.LastSent = m.getTimesource().GetCurrentTime() 2277 err = m.persistence.SaveRawMessage(&rawMessage) 2278 if err != nil { 2279 return rawMessage, err 2280 } 2281 2282 if m.dispatchMessageTestCallback != nil { 2283 m.dispatchMessageTestCallback(rawMessage) 2284 } 2285 return rawMessage, nil 2286 } 2287 2288 // SendChatMessage takes a minimal message and sends it based on the corresponding chat 2289 func (m *Messenger) SendChatMessage(ctx context.Context, message *common.Message) (*MessengerResponse, error) { 2290 return m.sendChatMessage(ctx, message) 2291 } 2292 2293 // SendChatMessages takes a array of messages and sends it based on the corresponding chats 2294 func (m *Messenger) SendChatMessages(ctx context.Context, messages []*common.Message) (*MessengerResponse, error) { 2295 var response MessengerResponse 2296 2297 generatedAlbumID, err := uuid.NewRandom() 2298 if err != nil { 2299 return nil, err 2300 } 2301 2302 imagesCount := uint32(0) 2303 for _, message := range messages { 2304 if message.ContentType == protobuf.ChatMessage_IMAGE { 2305 imagesCount++ 2306 } 2307 2308 } 2309 2310 for _, message := range messages { 2311 if message.ContentType == protobuf.ChatMessage_IMAGE && len(messages) > 1 { 2312 err = message.SetAlbumIDAndImagesCount(generatedAlbumID.String(), imagesCount) 2313 if err != nil { 2314 return nil, err 2315 } 2316 } 2317 messageResponse, err := m.SendChatMessage(ctx, message) 2318 if err != nil { 2319 return nil, err 2320 } 2321 err = response.Merge(messageResponse) 2322 if err != nil { 2323 return nil, err 2324 } 2325 } 2326 2327 return &response, nil 2328 } 2329 2330 // sendChatMessage takes a minimal message and sends it based on the corresponding chat 2331 func (m *Messenger) sendChatMessage(ctx context.Context, message *common.Message) (*MessengerResponse, error) { 2332 displayName, err := m.settings.DisplayName() 2333 if err != nil { 2334 return nil, err 2335 } 2336 2337 message.DisplayName = displayName 2338 2339 replacedText, err := m.mentionsManager.ReplaceWithPublicKey(message.ChatId, message.Text) 2340 if err == nil { 2341 message.Text = replacedText 2342 } else { 2343 m.logger.Error("failed to replace text with public key", zap.String("chatID", message.ChatId), zap.String("text", message.Text)) 2344 } 2345 2346 if len(message.ImagePath) != 0 { 2347 2348 err := message.LoadImage() 2349 if err != nil { 2350 return nil, err 2351 } 2352 2353 } else if len(message.CommunityID) != 0 { 2354 community, err := m.communitiesManager.GetByIDString(message.CommunityID) 2355 if err != nil { 2356 return nil, err 2357 } 2358 2359 wrappedCommunity, err := community.ToProtocolMessageBytes() 2360 if err != nil { 2361 return nil, err 2362 } 2363 2364 message.Payload = &protobuf.ChatMessage_Community{Community: wrappedCommunity} 2365 message.Shard = community.Shard().Protobuffer() 2366 2367 message.ContentType = protobuf.ChatMessage_COMMUNITY 2368 } else if len(message.AudioPath) != 0 { 2369 err := message.LoadAudio() 2370 if err != nil { 2371 return nil, err 2372 } 2373 } 2374 2375 // We consider link previews non-critical data, so we do not want to block 2376 // messages from being sent. 2377 2378 unfurledLinks, err := message.ConvertLinkPreviewsToProto() 2379 if err != nil { 2380 m.logger.Error("failed to convert link previews", zap.Error(err)) 2381 } else { 2382 message.UnfurledLinks = unfurledLinks 2383 } 2384 2385 unfurledStatusLinks, err := message.ConvertStatusLinkPreviewsToProto() 2386 if err != nil { 2387 m.logger.Error("failed to convert status link previews", zap.Error(err)) 2388 } else { 2389 message.UnfurledStatusLinks = unfurledStatusLinks 2390 } 2391 2392 var response MessengerResponse 2393 2394 // A valid added chat is required. 2395 chat, ok := m.allChats.Load(message.ChatId) 2396 if !ok { 2397 return nil, ErrChatNotFoundError 2398 } 2399 2400 err = m.handleStandaloneChatIdentity(chat) 2401 if err != nil { 2402 return nil, err 2403 } 2404 2405 err = extendMessageFromChat(message, chat, &m.identity.PublicKey, m.getTimesource()) 2406 if err != nil { 2407 return nil, err 2408 } 2409 2410 err = m.addContactRequestPropagatedState(message) 2411 if err != nil { 2412 return nil, err 2413 } 2414 2415 encodedMessage, err := m.encodeChatEntity(chat, message) 2416 if err != nil { 2417 return nil, err 2418 } 2419 2420 rawMessage := common.RawMessage{ 2421 LocalChatID: chat.ID, 2422 SendPushNotification: m.featureFlags.PushNotifications, 2423 Payload: encodedMessage, 2424 MessageType: protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, 2425 ResendType: chat.DefaultResendType(), 2426 } 2427 2428 // We want to save the raw message before dispatching it, to avoid race conditions 2429 // since it might get dispatched and confirmed before it's saved. 2430 // This is not the best solution, probably it would be better to split 2431 // the sent status in a different table and join on query for messages, 2432 // but that's a much larger change and it would require an expensive migration of clients 2433 rawMessage.BeforeDispatch = func(rawMessage *common.RawMessage) error { 2434 2435 if rawMessage.Sent { 2436 message.OutgoingStatus = common.OutgoingStatusSent 2437 } 2438 message.ID = rawMessage.ID 2439 err = message.PrepareContent(common.PubkeyToHex(&m.identity.PublicKey)) 2440 if err != nil { 2441 return err 2442 } 2443 2444 err = chat.UpdateFromMessage(message, m.getTimesource()) 2445 if err != nil { 2446 return err 2447 } 2448 2449 err := m.persistence.SaveMessages([]*common.Message{message}) 2450 if err != nil { 2451 return err 2452 } 2453 2454 var syncMessageType peersyncing.SyncMessageType 2455 if chat.OneToOne() { 2456 syncMessageType = peersyncing.SyncMessageOneToOneType 2457 } else if chat.CommunityChat() { 2458 syncMessageType = peersyncing.SyncMessageCommunityType 2459 } else if chat.PrivateGroupChat() { 2460 syncMessageType = peersyncing.SyncMessagePrivateGroup 2461 } 2462 2463 wrappedMessage, err := v1protocol.WrapMessageV1(rawMessage.Payload, rawMessage.MessageType, rawMessage.Sender) 2464 if err != nil { 2465 return errors.Wrap(err, "failed to wrap message") 2466 } 2467 2468 syncMessage := peersyncing.SyncMessage{ 2469 Type: syncMessageType, 2470 ID: types.Hex2Bytes(rawMessage.ID), 2471 ChatID: []byte(chat.ID), 2472 Payload: wrappedMessage, 2473 Timestamp: m.transport.GetCurrentTime() / 1000, 2474 } 2475 2476 // If the chat type is not supported, skip saving it 2477 if syncMessageType == 0 { 2478 return nil 2479 } 2480 2481 // ensure that the message is saved only once 2482 rawMessage.BeforeDispatch = nil 2483 2484 return m.peersyncing.Add(syncMessage) 2485 } 2486 2487 rawMessage, err = m.dispatchMessage(ctx, rawMessage) 2488 if err != nil { 2489 return nil, err 2490 } 2491 2492 msg, err := m.pullMessagesAndResponsesFromDB([]*common.Message{message}) 2493 if err != nil { 2494 return nil, err 2495 } 2496 2497 if err := m.updateChatFirstMessageTimestamp(chat, whisperToUnixTimestamp(message.WhisperTimestamp), &response); err != nil { 2498 return nil, err 2499 } 2500 2501 response.SetMessages(msg) 2502 response.AddChat(chat) 2503 2504 m.logger.Debug("inside sendChatMessage", 2505 zap.String("id", message.ID), 2506 zap.String("from", message.From), 2507 zap.String("displayName", message.DisplayName), 2508 zap.String("ChatId", message.ChatId), 2509 zap.String("Clock", strconv.FormatUint(message.Clock, 10)), 2510 zap.String("Timestamp", strconv.FormatUint(message.Timestamp, 10)), 2511 ) 2512 err = m.prepareMessages(response.messages) 2513 2514 if err != nil { 2515 return nil, err 2516 } 2517 2518 return &response, m.saveChat(chat) 2519 } 2520 2521 func whisperToUnixTimestamp(whisperTimestamp uint64) uint32 { 2522 return uint32(whisperTimestamp / 1000) 2523 } 2524 2525 func (m *Messenger) updateChatFirstMessageTimestamp(chat *Chat, timestamp uint32, response *MessengerResponse) error { 2526 // Currently supported only for communities 2527 if !chat.CommunityChat() { 2528 return nil 2529 } 2530 2531 community, err := m.communitiesManager.GetByIDString(chat.CommunityID) 2532 if err != nil { 2533 return err 2534 } 2535 2536 if community.IsControlNode() && chat.UpdateFirstMessageTimestamp(timestamp) { 2537 community, changes, err := m.communitiesManager.EditChatFirstMessageTimestamp(community.ID(), chat.ID, chat.FirstMessageTimestamp) 2538 if err != nil { 2539 return err 2540 } 2541 2542 response.AddCommunity(community) 2543 response.CommunityChanges = append(response.CommunityChanges, changes) 2544 } 2545 2546 return nil 2547 } 2548 2549 func (m *Messenger) ShareImageMessage(request *requests.ShareImageMessage) (*MessengerResponse, error) { 2550 if err := request.Validate(); err != nil { 2551 return nil, err 2552 } 2553 response := &MessengerResponse{} 2554 2555 msg, err := m.persistence.MessageByID(request.MessageID) 2556 if err != nil { 2557 return nil, err 2558 } 2559 2560 var messages []*common.Message 2561 for _, pk := range request.Users { 2562 message := common.NewMessage() 2563 message.ChatId = pk.String() 2564 message.Payload = msg.Payload 2565 message.Text = "This message has been shared with you" 2566 message.ContentType = protobuf.ChatMessage_IMAGE 2567 messages = append(messages, message) 2568 2569 r, err := m.CreateOneToOneChat(&requests.CreateOneToOneChat{ID: pk}) 2570 if err != nil { 2571 return nil, err 2572 } 2573 2574 if err := response.Merge(r); err != nil { 2575 return nil, err 2576 } 2577 } 2578 2579 sendMessagesResponse, err := m.SendChatMessages(context.Background(), messages) 2580 if err != nil { 2581 return nil, err 2582 } 2583 2584 if err := response.Merge(sendMessagesResponse); err != nil { 2585 return nil, err 2586 } 2587 2588 return response, nil 2589 } 2590 2591 func (m *Messenger) InstallationID() string { 2592 return m.installationID 2593 } 2594 2595 func (m *Messenger) KeyUID() string { 2596 return m.account.KeyUID 2597 } 2598 2599 // syncChat sync a chat with paired devices 2600 func (m *Messenger) syncChat(ctx context.Context, chatToSync *Chat, rawMessageHandler RawMessageHandler) error { 2601 var err error 2602 if !m.hasPairedDevices() { 2603 return nil 2604 } 2605 clock, chat := m.getLastClockWithRelatedChat() 2606 2607 syncMessage := &protobuf.SyncChat{ 2608 Clock: clock, 2609 Id: chatToSync.ID, 2610 Name: chatToSync.Name, 2611 ChatType: uint32(chatToSync.ChatType), 2612 Active: chatToSync.Active, 2613 } 2614 chatMuteTill, _ := time.Parse(time.RFC3339, chatToSync.MuteTill.Format(time.RFC3339)) 2615 if chatToSync.Muted && chatMuteTill.Equal(time.Time{}) { 2616 // Only set Muted if it is "permanently" muted 2617 syncMessage.Muted = true 2618 } 2619 if chatToSync.OneToOne() { 2620 syncMessage.Name = "" // The Name is useless in 1-1 chats 2621 } 2622 if chatToSync.PrivateGroupChat() { 2623 syncMessage.MembershipUpdateEvents = make([]*protobuf.MembershipUpdateEvents, len(chatToSync.MembershipUpdates)) 2624 for i, membershipUpdate := range chatToSync.MembershipUpdates { 2625 syncMessage.MembershipUpdateEvents[i] = &protobuf.MembershipUpdateEvents{ 2626 Clock: membershipUpdate.ClockValue, 2627 Type: uint32(membershipUpdate.Type), 2628 Members: membershipUpdate.Members, 2629 Name: membershipUpdate.Name, 2630 Signature: membershipUpdate.Signature, 2631 ChatId: membershipUpdate.ChatID, 2632 From: membershipUpdate.From, 2633 RawPayload: membershipUpdate.RawPayload, 2634 Color: membershipUpdate.Color, 2635 Image: membershipUpdate.Image, 2636 } 2637 } 2638 } 2639 encodedMessage, err := proto.Marshal(syncMessage) 2640 if err != nil { 2641 return err 2642 } 2643 2644 rawMessage := common.RawMessage{ 2645 LocalChatID: chat.ID, 2646 Payload: encodedMessage, 2647 MessageType: protobuf.ApplicationMetadataMessage_SYNC_CHAT, 2648 ResendType: common.ResendTypeDataSync, 2649 } 2650 2651 _, err = rawMessageHandler(ctx, rawMessage) 2652 if err != nil { 2653 return err 2654 } 2655 2656 chat.LastClockValue = clock 2657 return m.saveChat(chat) 2658 } 2659 2660 func (m *Messenger) syncClearHistory(ctx context.Context, publicChat *Chat, rawMessageHandler RawMessageHandler) error { 2661 var err error 2662 if !m.hasPairedDevices() { 2663 return nil 2664 } 2665 clock, chat := m.getLastClockWithRelatedChat() 2666 2667 syncMessage := &protobuf.SyncClearHistory{ 2668 ChatId: publicChat.ID, 2669 ClearedAt: publicChat.DeletedAtClockValue, 2670 } 2671 2672 encodedMessage, err := proto.Marshal(syncMessage) 2673 if err != nil { 2674 return err 2675 } 2676 2677 rawMessage := common.RawMessage{ 2678 LocalChatID: chat.ID, 2679 Payload: encodedMessage, 2680 MessageType: protobuf.ApplicationMetadataMessage_SYNC_CLEAR_HISTORY, 2681 ResendType: common.ResendTypeDataSync, 2682 } 2683 2684 _, err = rawMessageHandler(ctx, rawMessage) 2685 if err != nil { 2686 return err 2687 } 2688 2689 chat.LastClockValue = clock 2690 return m.saveChat(chat) 2691 } 2692 2693 func (m *Messenger) syncChatRemoving(ctx context.Context, id string, rawMessageHandler RawMessageHandler) error { 2694 var err error 2695 if !m.hasPairedDevices() { 2696 return nil 2697 } 2698 clock, chat := m.getLastClockWithRelatedChat() 2699 2700 syncMessage := &protobuf.SyncChatRemoved{ 2701 Clock: clock, 2702 Id: id, 2703 } 2704 encodedMessage, err := proto.Marshal(syncMessage) 2705 if err != nil { 2706 return err 2707 } 2708 2709 rawMessage := common.RawMessage{ 2710 LocalChatID: chat.ID, 2711 Payload: encodedMessage, 2712 MessageType: protobuf.ApplicationMetadataMessage_SYNC_CHAT_REMOVED, 2713 ResendType: common.ResendTypeDataSync, 2714 } 2715 2716 _, err = rawMessageHandler(ctx, rawMessage) 2717 if err != nil { 2718 return err 2719 } 2720 2721 chat.LastClockValue = clock 2722 return m.saveChat(chat) 2723 } 2724 2725 // syncContact sync as contact with paired devices 2726 func (m *Messenger) syncContact(ctx context.Context, contact *Contact, rawMessageHandler RawMessageHandler) error { 2727 var err error 2728 if contact.IsSyncing { 2729 return nil 2730 } 2731 if !m.hasPairedDevices() { 2732 return nil 2733 } 2734 clock, chat := m.getLastClockWithRelatedChat() 2735 2736 syncMessage := m.buildSyncContactMessage(contact) 2737 2738 encodedMessage, err := proto.Marshal(syncMessage) 2739 if err != nil { 2740 return err 2741 } 2742 2743 rawMessage := common.RawMessage{ 2744 LocalChatID: chat.ID, 2745 Payload: encodedMessage, 2746 MessageType: protobuf.ApplicationMetadataMessage_SYNC_INSTALLATION_CONTACT_V2, 2747 ResendType: common.ResendTypeDataSync, 2748 } 2749 2750 _, err = rawMessageHandler(ctx, rawMessage) 2751 if err != nil { 2752 return err 2753 } 2754 2755 chat.LastClockValue = clock 2756 return m.saveChat(chat) 2757 } 2758 2759 func (m *Messenger) propagateSyncInstallationCommunityWithHRKeys(msg *protobuf.SyncInstallationCommunity, c *communities.Community) error { 2760 communityKeys, err := m.encryptor.GetAllHRKeysMarshaledV1(c.ID()) 2761 if err != nil { 2762 return err 2763 } 2764 msg.EncryptionKeysV1 = communityKeys 2765 2766 communityAndChannelKeys := [][]byte{} 2767 communityKeys, err = m.encryptor.GetAllHRKeysMarshaledV2(c.ID()) 2768 if err != nil { 2769 return err 2770 } 2771 if len(communityKeys) > 0 { 2772 communityAndChannelKeys = append(communityAndChannelKeys, communityKeys) 2773 } 2774 2775 for channelID := range c.Chats() { 2776 channelKeys, err := m.encryptor.GetAllHRKeysMarshaledV2([]byte(c.IDString() + channelID)) 2777 if err != nil { 2778 return err 2779 } 2780 if len(channelKeys) > 0 { 2781 communityAndChannelKeys = append(communityAndChannelKeys, channelKeys) 2782 } 2783 } 2784 msg.EncryptionKeysV2 = communityAndChannelKeys 2785 2786 return nil 2787 } 2788 2789 func (m *Messenger) buildSyncInstallationCommunity(community *communities.Community, clock uint64) (*protobuf.SyncInstallationCommunity, error) { 2790 communitySettings, err := m.communitiesManager.GetCommunitySettingsByID(community.ID()) 2791 if err != nil { 2792 return nil, err 2793 } 2794 2795 syncControlNode, err := m.communitiesManager.GetSyncControlNode(community.ID()) 2796 if err != nil { 2797 return nil, err 2798 } 2799 2800 syncMessage, err := community.ToSyncInstallationCommunityProtobuf(clock, communitySettings, syncControlNode) 2801 if err != nil { 2802 return nil, err 2803 } 2804 2805 err = m.propagateSyncInstallationCommunityWithHRKeys(syncMessage, community) 2806 if err != nil { 2807 return nil, err 2808 } 2809 2810 return syncMessage, nil 2811 } 2812 2813 func (m *Messenger) syncCommunity(ctx context.Context, community *communities.Community, rawMessageHandler RawMessageHandler) error { 2814 logger := m.logger.Named("syncCommunity") 2815 if !m.hasPairedDevices() { 2816 logger.Debug("device has no paired devices") 2817 return nil 2818 } 2819 2820 logger.Debug("device has paired device(s)") 2821 2822 clock, chat := m.getLastClockWithRelatedChat() 2823 2824 syncMessage, err := m.buildSyncInstallationCommunity(community, clock) 2825 if err != nil { 2826 return err 2827 } 2828 2829 encodedMessage, err := proto.Marshal(syncMessage) 2830 if err != nil { 2831 return err 2832 } 2833 2834 rawMessage := common.RawMessage{ 2835 LocalChatID: chat.ID, 2836 Payload: encodedMessage, 2837 MessageType: protobuf.ApplicationMetadataMessage_SYNC_INSTALLATION_COMMUNITY, 2838 ResendType: common.ResendTypeDataSync, 2839 } 2840 2841 _, err = rawMessageHandler(ctx, rawMessage) 2842 if err != nil { 2843 return err 2844 } 2845 logger.Debug("message dispatched") 2846 2847 chat.LastClockValue = clock 2848 return m.saveChat(chat) 2849 } 2850 2851 func (m *Messenger) SyncBookmark(ctx context.Context, bookmark *browsers.Bookmark, rawMessageHandler RawMessageHandler) error { 2852 if !m.hasPairedDevices() { 2853 return nil 2854 } 2855 2856 clock, chat := m.getLastClockWithRelatedChat() 2857 2858 syncMessage := &protobuf.SyncBookmark{ 2859 Clock: clock, 2860 Url: bookmark.URL, 2861 Name: bookmark.Name, 2862 ImageUrl: bookmark.ImageURL, 2863 Removed: bookmark.Removed, 2864 DeletedAt: bookmark.DeletedAt, 2865 } 2866 encodedMessage, err := proto.Marshal(syncMessage) 2867 if err != nil { 2868 return err 2869 } 2870 2871 rawMessage := common.RawMessage{ 2872 LocalChatID: chat.ID, 2873 Payload: encodedMessage, 2874 MessageType: protobuf.ApplicationMetadataMessage_SYNC_BOOKMARK, 2875 ResendType: common.ResendTypeDataSync, 2876 } 2877 _, err = rawMessageHandler(ctx, rawMessage) 2878 if err != nil { 2879 return err 2880 } 2881 2882 chat.LastClockValue = clock 2883 return m.saveChat(chat) 2884 } 2885 2886 func (m *Messenger) SyncEnsNamesWithDispatchMessage(ctx context.Context, usernameDetail *ensservice.UsernameDetail) error { 2887 return m.syncEnsUsernameDetail(ctx, usernameDetail, m.dispatchMessage) 2888 } 2889 2890 func (m *Messenger) syncEnsUsernameDetails(ctx context.Context, rawMessageHandler RawMessageHandler) error { 2891 if !m.hasPairedDevices() { 2892 return nil 2893 } 2894 2895 ensNameDetails, err := m.getEnsUsernameDetails() 2896 if err != nil { 2897 return err 2898 } 2899 for _, d := range ensNameDetails { 2900 if err = m.syncEnsUsernameDetail(ctx, d, rawMessageHandler); err != nil { 2901 return err 2902 } 2903 } 2904 return nil 2905 } 2906 2907 func (m *Messenger) saveEnsUsernameDetailProto(syncMessage *protobuf.SyncEnsUsernameDetail) (*ensservice.UsernameDetail, error) { 2908 ud := &ensservice.UsernameDetail{ 2909 Username: syncMessage.Username, 2910 Clock: syncMessage.Clock, 2911 ChainID: syncMessage.ChainId, 2912 Removed: syncMessage.Removed, 2913 } 2914 db := ensservice.NewEnsDatabase(m.database) 2915 err := db.SaveOrUpdateEnsUsername(ud) 2916 if err != nil { 2917 return nil, err 2918 } 2919 return ud, nil 2920 } 2921 2922 func (m *Messenger) HandleSyncEnsUsernameDetail(state *ReceivedMessageState, syncMessage *protobuf.SyncEnsUsernameDetail, statusMessage *v1protocol.StatusMessage) error { 2923 ud, err := m.saveEnsUsernameDetailProto(syncMessage) 2924 if err != nil { 2925 return err 2926 } 2927 state.Response.AddEnsUsernameDetail(ud) 2928 return nil 2929 } 2930 2931 func (m *Messenger) syncEnsUsernameDetail(ctx context.Context, usernameDetail *ensservice.UsernameDetail, rawMessageHandler RawMessageHandler) error { 2932 syncMessage := &protobuf.SyncEnsUsernameDetail{ 2933 Clock: usernameDetail.Clock, 2934 Username: usernameDetail.Username, 2935 ChainId: usernameDetail.ChainID, 2936 Removed: usernameDetail.Removed, 2937 } 2938 encodedMessage, err := proto.Marshal(syncMessage) 2939 if err != nil { 2940 return err 2941 } 2942 2943 _, chat := m.getLastClockWithRelatedChat() 2944 rawMessage := common.RawMessage{ 2945 LocalChatID: chat.ID, 2946 Payload: encodedMessage, 2947 MessageType: protobuf.ApplicationMetadataMessage_SYNC_ENS_USERNAME_DETAIL, 2948 ResendType: common.ResendTypeDataSync, 2949 } 2950 2951 _, err = rawMessageHandler(ctx, rawMessage) 2952 return err 2953 } 2954 2955 func (m *Messenger) syncAccountCustomizationColor(ctx context.Context, acc *multiaccounts.Account) error { 2956 if !m.hasPairedDevices() { 2957 return nil 2958 } 2959 2960 _, chat := m.getLastClockWithRelatedChat() 2961 2962 message := &protobuf.SyncAccountCustomizationColor{ 2963 KeyUid: acc.KeyUID, 2964 CustomizationColor: string(acc.CustomizationColor), 2965 UpdatedAt: acc.CustomizationColorClock, 2966 } 2967 2968 encodedMessage, err := proto.Marshal(message) 2969 if err != nil { 2970 return err 2971 } 2972 2973 rawMessage := common.RawMessage{ 2974 LocalChatID: chat.ID, 2975 Payload: encodedMessage, 2976 MessageType: protobuf.ApplicationMetadataMessage_SYNC_ACCOUNT_CUSTOMIZATION_COLOR, 2977 ResendType: common.ResendTypeDataSync, 2978 } 2979 2980 _, err = m.dispatchMessage(ctx, rawMessage) 2981 return err 2982 } 2983 2984 func (m *Messenger) SyncTrustedUser(ctx context.Context, publicKey string, ts verification.TrustStatus, rawMessageHandler RawMessageHandler) error { 2985 if !m.hasPairedDevices() { 2986 return nil 2987 } 2988 2989 clock, chat := m.getLastClockWithRelatedChat() 2990 2991 syncMessage := &protobuf.SyncTrustedUser{ 2992 Clock: clock, 2993 Id: publicKey, 2994 Status: protobuf.SyncTrustedUser_TrustStatus(ts), 2995 } 2996 encodedMessage, err := proto.Marshal(syncMessage) 2997 if err != nil { 2998 return err 2999 } 3000 3001 rawMessage := common.RawMessage{ 3002 LocalChatID: chat.ID, 3003 Payload: encodedMessage, 3004 MessageType: protobuf.ApplicationMetadataMessage_SYNC_TRUSTED_USER, 3005 ResendType: common.ResendTypeDataSync, 3006 } 3007 3008 _, err = rawMessageHandler(ctx, rawMessage) 3009 if err != nil { 3010 return err 3011 } 3012 3013 chat.LastClockValue = clock 3014 return m.saveChat(chat) 3015 } 3016 3017 func (m *Messenger) SyncVerificationRequest(ctx context.Context, vr *verification.Request, rawMessageHandler RawMessageHandler) error { 3018 if !m.hasPairedDevices() { 3019 return nil 3020 } 3021 3022 clock, chat := m.getLastClockWithRelatedChat() 3023 3024 syncMessage := &protobuf.SyncVerificationRequest{ 3025 Id: vr.ID, 3026 Clock: clock, 3027 From: vr.From, 3028 To: vr.To, 3029 Challenge: vr.Challenge, 3030 Response: vr.Response, 3031 RequestedAt: vr.RequestedAt, 3032 RepliedAt: vr.RepliedAt, 3033 VerificationStatus: protobuf.SyncVerificationRequest_VerificationStatus(vr.RequestStatus), 3034 } 3035 encodedMessage, err := proto.Marshal(syncMessage) 3036 if err != nil { 3037 return err 3038 } 3039 3040 rawMessage := common.RawMessage{ 3041 LocalChatID: chat.ID, 3042 Payload: encodedMessage, 3043 MessageType: protobuf.ApplicationMetadataMessage_SYNC_VERIFICATION_REQUEST, 3044 ResendType: common.ResendTypeDataSync, 3045 } 3046 3047 _, err = rawMessageHandler(ctx, rawMessage) 3048 if err != nil { 3049 return err 3050 } 3051 3052 chat.LastClockValue = clock 3053 return m.saveChat(chat) 3054 } 3055 3056 // RetrieveAll retrieves messages from all filters, processes them and returns a 3057 // MessengerResponse to the client 3058 func (m *Messenger) RetrieveAll() (*MessengerResponse, error) { 3059 chatWithMessages, err := m.transport.RetrieveRawAll() 3060 if err != nil { 3061 return nil, err 3062 } 3063 3064 return m.handleRetrievedMessages(chatWithMessages, true, false) 3065 } 3066 3067 func (m *Messenger) StartRetrieveMessagesLoop(tick time.Duration, cancel <-chan struct{}) { 3068 m.shutdownWaitGroup.Add(1) 3069 go func() { 3070 defer m.shutdownWaitGroup.Done() 3071 ticker := time.NewTicker(tick) 3072 defer ticker.Stop() 3073 for { 3074 select { 3075 case <-ticker.C: 3076 m.ProcessAllMessages() 3077 case <-cancel: 3078 return 3079 } 3080 } 3081 }() 3082 } 3083 3084 func (m *Messenger) ProcessAllMessages() { 3085 response, err := m.RetrieveAll() 3086 if err != nil { 3087 m.logger.Error("failed to retrieve raw messages", zap.Error(err)) 3088 return 3089 } 3090 m.PublishMessengerResponse(response) 3091 } 3092 3093 func (m *Messenger) PublishMessengerResponse(response *MessengerResponse) { 3094 if response.IsEmpty() { 3095 return 3096 } 3097 3098 notifications := response.Notifications() 3099 // Clear notifications as not used for now 3100 response.ClearNotifications() 3101 signal.SendNewMessages(response) 3102 localnotifications.PushMessages(notifications) 3103 } 3104 3105 func (m *Messenger) GetStats() types.StatsSummary { 3106 return m.transport.GetStats() 3107 } 3108 3109 func (m *Messenger) GetTransport() *transport.Transport { 3110 return m.transport 3111 } 3112 3113 type CurrentMessageState struct { 3114 // Message is the protobuf message received 3115 Message *protobuf.ChatMessage 3116 // MessageID is the ID of the message 3117 MessageID string 3118 // WhisperTimestamp is the whisper timestamp of the message 3119 WhisperTimestamp uint64 3120 // Contact is the contact associated with the author of the message 3121 Contact *Contact 3122 // PublicKey is the public key of the author of the message 3123 PublicKey *ecdsa.PublicKey 3124 3125 StatusMessage *v1protocol.StatusMessage 3126 } 3127 3128 type ReceivedMessageState struct { 3129 // State on the message being processed 3130 CurrentMessageState *CurrentMessageState 3131 // AllChats in memory 3132 AllChats *chatMap 3133 // All contacts in memory 3134 AllContacts *contactMap 3135 // List of contacts modified 3136 ModifiedContacts *stringBoolMap 3137 // All installations in memory 3138 AllInstallations *installationMap 3139 // List of communities modified 3140 ModifiedInstallations *stringBoolMap 3141 // Map of existing messages 3142 ExistingMessagesMap map[string]bool 3143 // EmojiReactions is a list of emoji reactions for the current batch 3144 // indexed by from-message-id-emoji-type 3145 EmojiReactions map[string]*EmojiReaction 3146 // GroupChatInvitations is a list of invitation requests or rejections 3147 GroupChatInvitations map[string]*GroupChatInvitation 3148 // Response to the client 3149 Response *MessengerResponse 3150 ResolvePrimaryName func(string) (string, error) 3151 // Timesource is a time source for clock values/timestamps. 3152 Timesource common.TimeSource 3153 AllBookmarks map[string]*browsers.Bookmark 3154 AllVerificationRequests []*verification.Request 3155 AllTrustStatus map[string]verification.TrustStatus 3156 } 3157 3158 // addNewMessageNotification takes a common.Message and generates a new NotificationBody and appends it to the 3159 // []Response.Notifications if the message is m.New 3160 func (r *ReceivedMessageState) addNewMessageNotification(publicKey ecdsa.PublicKey, m *common.Message, responseTo *common.Message, profilePicturesVisibility int) error { 3161 if !m.New { 3162 return nil 3163 } 3164 3165 pubKey, err := m.GetSenderPubKey() 3166 if err != nil { 3167 return err 3168 } 3169 contactID := contactIDFromPublicKey(pubKey) 3170 3171 chat, ok := r.AllChats.Load(m.LocalChatID) 3172 if !ok { 3173 return fmt.Errorf("chat ID '%s' not present", m.LocalChatID) 3174 } 3175 3176 contact, ok := r.AllContacts.Load(contactID) 3177 if !ok { 3178 return fmt.Errorf("contact ID '%s' not present", contactID) 3179 } 3180 3181 if !chat.Muted { 3182 if showMessageNotification(publicKey, m, chat, responseTo) { 3183 notification, err := NewMessageNotification(m.ID, m, chat, contact, r.ResolvePrimaryName, profilePicturesVisibility) 3184 if err != nil { 3185 return err 3186 } 3187 r.Response.AddNotification(notification) 3188 } 3189 } 3190 3191 return nil 3192 } 3193 3194 // updateExistingActivityCenterNotification updates AC notification if it exists and hasn't been read yet 3195 func (r *ReceivedMessageState) updateExistingActivityCenterNotification(publicKey ecdsa.PublicKey, m *Messenger, message *common.Message, responseTo *common.Message) error { 3196 notification, err := m.persistence.GetActivityCenterNotificationByID(types.FromHex(message.ID)) 3197 if err != nil { 3198 return err 3199 } 3200 3201 if notification == nil || notification.Read { 3202 return nil 3203 } 3204 3205 notification.Message = message 3206 notification.ReplyMessage = responseTo 3207 notification.UpdatedAt = m.GetCurrentTimeInMillis() 3208 3209 err = m.addActivityCenterNotification(r.Response, notification, nil) 3210 if err != nil { 3211 return err 3212 } 3213 3214 return nil 3215 } 3216 3217 // function returns if the community is joined before the clock 3218 func (m *Messenger) isCommunityJoinedBeforeClock(publicKey ecdsa.PublicKey, communityID string, clock uint64) (bool, error) { 3219 community, err := m.communitiesManager.GetByIDString(communityID) 3220 if err != nil { 3221 return false, err 3222 } 3223 3224 if !community.Joined() || clock < uint64(community.JoinedAt()) { 3225 joinedClock, err := m.communitiesManager.GetCommunityRequestToJoinClock(&publicKey, communityID) 3226 if err != nil { 3227 return false, err 3228 } 3229 3230 // no request to join, or request to join is after the message 3231 if joinedClock == 0 || clock < joinedClock { 3232 return false, nil 3233 } 3234 return true, nil 3235 } 3236 return true, nil 3237 } 3238 3239 // addNewActivityCenterNotification takes a common.Message and generates a new ActivityCenterNotification and appends it to the 3240 // []Response.ActivityCenterNotifications if the message is m.New 3241 func (r *ReceivedMessageState) addNewActivityCenterNotification(publicKey ecdsa.PublicKey, m *Messenger, message *common.Message, responseTo *common.Message) error { 3242 if !message.New { 3243 return nil 3244 } 3245 3246 chat, ok := r.AllChats.Load(message.LocalChatID) 3247 if !ok { 3248 return fmt.Errorf("chat ID '%s' not present", message.LocalChatID) 3249 } 3250 3251 isNotification, notificationType := showMentionOrReplyActivityCenterNotification(publicKey, message, chat, responseTo) 3252 if !isNotification { 3253 return nil 3254 } 3255 3256 if chat.CommunityChat() { 3257 // Ignore mentions & replies in community before joining 3258 ok, err := m.isCommunityJoinedBeforeClock(publicKey, chat.CommunityID, message.Clock) 3259 if err != nil || !ok { 3260 return nil 3261 } 3262 } 3263 3264 // Use albumId as notificationId to prevent multiple notifications 3265 // for same message with multiple images 3266 var notificationID string 3267 3268 image := message.GetImage() 3269 var albumMessages = []*common.Message{} 3270 if image != nil && image.GetAlbumId() != "" { 3271 notificationID = image.GetAlbumId() 3272 album, err := m.persistence.albumMessages(message.LocalChatID, image.AlbumId) 3273 if err != nil { 3274 return err 3275 } 3276 if m.httpServer != nil { 3277 err = m.prepareMessagesList(album) 3278 if err != nil { 3279 return err 3280 } 3281 } 3282 3283 albumMessages = album 3284 } else { 3285 notificationID = message.ID 3286 } 3287 3288 notification := &ActivityCenterNotification{ 3289 ID: types.FromHex(notificationID), 3290 Name: chat.Name, 3291 Message: message, 3292 ReplyMessage: responseTo, 3293 Type: notificationType, 3294 Timestamp: message.WhisperTimestamp, 3295 ChatID: chat.ID, 3296 CommunityID: chat.CommunityID, 3297 Author: message.From, 3298 UpdatedAt: m.GetCurrentTimeInMillis(), 3299 AlbumMessages: albumMessages, 3300 Read: message.Seen, 3301 } 3302 3303 return m.addActivityCenterNotification(r.Response, notification, nil) 3304 } 3305 3306 func (m *Messenger) buildMessageState() *ReceivedMessageState { 3307 return &ReceivedMessageState{ 3308 AllChats: m.allChats, 3309 AllContacts: m.allContacts, 3310 ModifiedContacts: new(stringBoolMap), 3311 AllInstallations: m.allInstallations, 3312 ModifiedInstallations: m.modifiedInstallations, 3313 ExistingMessagesMap: make(map[string]bool), 3314 EmojiReactions: make(map[string]*EmojiReaction), 3315 GroupChatInvitations: make(map[string]*GroupChatInvitation), 3316 Response: &MessengerResponse{}, 3317 Timesource: m.getTimesource(), 3318 ResolvePrimaryName: m.ResolvePrimaryName, 3319 AllBookmarks: make(map[string]*browsers.Bookmark), 3320 AllTrustStatus: make(map[string]verification.TrustStatus), 3321 } 3322 } 3323 3324 func (m *Messenger) outputToCSV(timestamp uint32, messageID types.HexBytes, from string, topic types.TopicType, chatID string, msgType protobuf.ApplicationMetadataMessage_Type, parsedMessage interface{}) { 3325 if !m.outputCSV { 3326 return 3327 } 3328 3329 msgJSON, err := json.Marshal(parsedMessage) 3330 if err != nil { 3331 m.logger.Error("could not marshall message", zap.Error(err)) 3332 return 3333 } 3334 3335 line := fmt.Sprintf("%d\t%s\t%s\t%s\t%s\t%s\t%s\n", timestamp, messageID.String(), from, topic.String(), chatID, msgType, msgJSON) 3336 _, err = m.csvFile.Write([]byte(line)) 3337 if err != nil { 3338 m.logger.Error("could not write to csv", zap.Error(err)) 3339 return 3340 } 3341 } 3342 3343 func (m *Messenger) shouldSkipDuplicate(messageType protobuf.ApplicationMetadataMessage_Type) bool { 3344 // Permit re-processing of ApplicationMetadataMessage_COMMUNITY_DESCRIPTION messages, 3345 // as they may be queued pending receipt of decryption keys. 3346 allowedDuplicateTypes := map[protobuf.ApplicationMetadataMessage_Type]struct{}{ 3347 protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION: struct{}{}, 3348 } 3349 if _, isAllowedDuplicate := allowedDuplicateTypes[messageType]; isAllowedDuplicate { 3350 return false 3351 } 3352 3353 return true 3354 } 3355 3356 func (m *Messenger) handleImportedMessages(messagesToHandle map[transport.Filter][]*types.Message) error { 3357 3358 messageState := m.buildMessageState() 3359 3360 logger := m.logger.With(zap.String("site", "handleImportedMessages")) 3361 3362 for filter, messages := range messagesToHandle { 3363 for _, shhMessage := range messages { 3364 3365 handleMessageResponse, err := m.sender.HandleMessages(shhMessage) 3366 if err != nil { 3367 logger.Info("failed to decode messages", zap.Error(err)) 3368 continue 3369 } 3370 statusMessages := handleMessageResponse.StatusMessages 3371 3372 for _, msg := range statusMessages { 3373 logger := logger.With(zap.String("message-id", msg.TransportLayer.Message.ThirdPartyID)) 3374 logger.Debug("processing message") 3375 3376 publicKey := msg.SigPubKey() 3377 senderID := contactIDFromPublicKey(publicKey) 3378 3379 if len(msg.EncryptionLayer.HashRatchetInfo) != 0 { 3380 err := m.communitiesManager.NewHashRatchetKeys(msg.EncryptionLayer.HashRatchetInfo) 3381 if err != nil { 3382 m.logger.Warn("failed to invalidate communities description cache", zap.Error(err)) 3383 } 3384 3385 } 3386 // Don't process duplicates 3387 messageID := msg.TransportLayer.Message.ThirdPartyID 3388 exists, err := m.messageExists(messageID, messageState.ExistingMessagesMap) 3389 if err != nil { 3390 logger.Warn("failed to check message exists", zap.Error(err)) 3391 } 3392 if exists && m.shouldSkipDuplicate(msg.ApplicationLayer.Type) { 3393 logger.Debug("skipping duplicate", zap.String("messageID", messageID)) 3394 continue 3395 } 3396 3397 var contact *Contact 3398 if c, ok := messageState.AllContacts.Load(senderID); ok { 3399 contact = c 3400 } else { 3401 c, err := buildContact(senderID, publicKey) 3402 if err != nil { 3403 logger.Info("failed to build contact", zap.Error(err)) 3404 continue 3405 } 3406 contact = c 3407 messageState.AllContacts.Store(senderID, contact) 3408 } 3409 messageState.CurrentMessageState = &CurrentMessageState{ 3410 MessageID: messageID, 3411 WhisperTimestamp: uint64(msg.TransportLayer.Message.Timestamp) * 1000, 3412 Contact: contact, 3413 PublicKey: publicKey, 3414 StatusMessage: msg, 3415 } 3416 3417 if msg.ApplicationLayer.Payload != nil { 3418 3419 logger.Debug("Handling parsed message") 3420 3421 switch msg.ApplicationLayer.Type { 3422 3423 case protobuf.ApplicationMetadataMessage_CHAT_MESSAGE: 3424 err = m.handleChatMessageProtobuf(messageState, msg.ApplicationLayer.Payload, msg, filter, true) 3425 if err != nil { 3426 logger.Warn("failed to handle ChatMessage", zap.Error(err)) 3427 continue 3428 } 3429 3430 case protobuf.ApplicationMetadataMessage_PIN_MESSAGE: 3431 err = m.handlePinMessageProtobuf(messageState, msg.ApplicationLayer.Payload, msg, filter, true) 3432 if err != nil { 3433 logger.Warn("failed to handle PinMessage", zap.Error(err)) 3434 } 3435 } 3436 } 3437 } 3438 } 3439 } 3440 3441 importMessageAuthors := messageState.Response.DiscordMessageAuthors() 3442 if len(importMessageAuthors) > 0 { 3443 err := m.persistence.SaveDiscordMessageAuthors(importMessageAuthors) 3444 if err != nil { 3445 return err 3446 } 3447 } 3448 3449 importMessagesToSave := messageState.Response.DiscordMessages() 3450 if len(importMessagesToSave) > 0 { 3451 m.logger.Debug("saving discord messages", zap.Int("count", len(importMessagesToSave))) 3452 m.handleImportMessagesMutex.Lock() 3453 err := m.persistence.SaveDiscordMessages(importMessagesToSave) 3454 if err != nil { 3455 m.logger.Debug("failed to save discord messages", zap.Error(err)) 3456 m.handleImportMessagesMutex.Unlock() 3457 return err 3458 } 3459 m.handleImportMessagesMutex.Unlock() 3460 } 3461 3462 messageAttachmentsToSave := messageState.Response.DiscordMessageAttachments() 3463 if len(messageAttachmentsToSave) > 0 { 3464 m.logger.Debug("saving discord message attachments", zap.Int("count", len(messageAttachmentsToSave))) 3465 m.handleImportMessagesMutex.Lock() 3466 err := m.persistence.SaveDiscordMessageAttachments(messageAttachmentsToSave) 3467 if err != nil { 3468 m.logger.Debug("failed to save discord message attachments", zap.Error(err)) 3469 m.handleImportMessagesMutex.Unlock() 3470 return err 3471 } 3472 m.handleImportMessagesMutex.Unlock() 3473 } 3474 3475 messagesToSave := messageState.Response.Messages() 3476 if len(messagesToSave) > 0 { 3477 m.logger.Debug("saving %d app messages", zap.Int("count", len(messagesToSave))) 3478 m.handleMessagesMutex.Lock() 3479 err := m.SaveMessages(messagesToSave) 3480 if err != nil { 3481 m.handleMessagesMutex.Unlock() 3482 return err 3483 } 3484 m.handleMessagesMutex.Unlock() 3485 } 3486 3487 // Save chats if they were modified 3488 if len(messageState.Response.chats) > 0 { 3489 err := m.saveChats(messageState.Response.Chats()) 3490 if err != nil { 3491 return err 3492 } 3493 } 3494 return nil 3495 } 3496 3497 func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filter][]*types.Message, storeWakuMessages bool, fromArchive bool) (*MessengerResponse, error) { 3498 3499 m.handleMessagesMutex.Lock() 3500 defer m.handleMessagesMutex.Unlock() 3501 3502 messageState := m.buildMessageState() 3503 3504 logger := m.logger.With(zap.String("site", "RetrieveAll")) 3505 3506 controlledCommunitiesChatIDs, err := m.communitiesManager.GetOwnedCommunitiesChatIDs() 3507 if err != nil { 3508 logger.Info("failed to retrieve admin communities", zap.Error(err)) 3509 } 3510 3511 iterator := m.retrievedMessagesIteratorFactory(chatWithMessages) 3512 for iterator.HasNext() { 3513 filter, messages := iterator.Next() 3514 3515 var processedMessages []string 3516 for _, shhMessage := range messages { 3517 logger := logger.With(zap.String("hash", types.EncodeHex(shhMessage.Hash))) 3518 // Indicates tha all messages in the batch have been processed correctly 3519 allMessagesProcessed := true 3520 3521 if controlledCommunitiesChatIDs[filter.ChatID] && storeWakuMessages { 3522 logger.Debug("storing waku message") 3523 err := m.communitiesManager.StoreWakuMessage(shhMessage) 3524 if err != nil { 3525 logger.Warn("failed to store waku message", zap.Error(err)) 3526 } 3527 } 3528 3529 handleMessagesResponse, err := m.sender.HandleMessages(shhMessage) 3530 if err != nil { 3531 if m.telemetryClient != nil { 3532 go m.telemetryClient.UpdateEnvelopeProcessingError(shhMessage, err) 3533 } 3534 logger.Info("failed to decode messages", zap.Error(err)) 3535 continue 3536 } 3537 3538 if handleMessagesResponse == nil { 3539 continue 3540 } 3541 3542 statusMessages := handleMessagesResponse.StatusMessages 3543 3544 if m.telemetryClient != nil { 3545 m.telemetryClient.PushReceivedMessages(m.ctx, telemetry.ReceivedMessages{ 3546 Filter: filter, 3547 SSHMessage: shhMessage, 3548 Messages: statusMessages, 3549 }) 3550 } 3551 3552 err = m.handleDatasyncMetadata(handleMessagesResponse) 3553 if err != nil { 3554 m.logger.Warn("failed to handle datasync metadata", zap.Error(err)) 3555 } 3556 3557 logger.Debug("processing messages further", zap.Int("count", len(statusMessages))) 3558 3559 for _, msg := range statusMessages { 3560 logger := logger.With(zap.String("message-id", msg.ApplicationLayer.ID.String())) 3561 3562 publicKey := msg.SigPubKey() 3563 3564 m.handleInstallations(msg.EncryptionLayer.Installations) 3565 err := m.handleSharedSecrets(msg.EncryptionLayer.SharedSecrets) 3566 if err != nil { 3567 // log and continue, non-critical error 3568 logger.Warn("failed to handle shared secrets") 3569 } 3570 3571 senderID := contactIDFromPublicKey(publicKey) 3572 ownID := contactIDFromPublicKey(m.IdentityPublicKey()) 3573 logger.Info("processing message", zap.Any("type", msg.ApplicationLayer.Type), zap.String("senderID", senderID)) 3574 3575 if senderID == ownID { 3576 // Skip own messages of certain types 3577 if msg.ApplicationLayer.Type == protobuf.ApplicationMetadataMessage_CONTACT_CODE_ADVERTISEMENT { 3578 continue 3579 } 3580 } 3581 3582 contact, contactFound := messageState.AllContacts.Load(senderID) 3583 3584 // Check for messages from blocked users 3585 if contactFound && contact.Blocked { 3586 continue 3587 } 3588 3589 // Don't process duplicates 3590 messageID := types.EncodeHex(msg.ApplicationLayer.ID) 3591 exists, err := m.messageExists(messageID, messageState.ExistingMessagesMap) 3592 if err != nil { 3593 logger.Warn("failed to check message exists", zap.Error(err)) 3594 } 3595 if exists && m.shouldSkipDuplicate(msg.ApplicationLayer.Type) { 3596 logger.Debug("skipping duplicate", zap.String("messageID", messageID)) 3597 continue 3598 } 3599 3600 if !contactFound { 3601 c, err := buildContact(senderID, publicKey) 3602 if err != nil { 3603 logger.Info("failed to build contact", zap.Error(err)) 3604 allMessagesProcessed = false 3605 continue 3606 } 3607 contact = c 3608 if msg.ApplicationLayer.Type != protobuf.ApplicationMetadataMessage_PUSH_NOTIFICATION_QUERY { 3609 messageState.AllContacts.Store(senderID, contact) 3610 } 3611 } 3612 messageState.CurrentMessageState = &CurrentMessageState{ 3613 MessageID: messageID, 3614 WhisperTimestamp: uint64(msg.TransportLayer.Message.Timestamp) * 1000, 3615 Contact: contact, 3616 PublicKey: publicKey, 3617 StatusMessage: msg, 3618 } 3619 3620 if msg.ApplicationLayer.Payload != nil { 3621 3622 err := m.dispatchToHandler(messageState, msg.ApplicationLayer.Payload, msg, filter, fromArchive) 3623 if err != nil { 3624 allMessagesProcessed = false 3625 logger.Warn("failed to process protobuf", zap.Error(err)) 3626 if m.unhandledMessagesTracker != nil { 3627 m.unhandledMessagesTracker(msg, err) 3628 } 3629 continue 3630 } 3631 logger.Debug("Handled parsed message") 3632 3633 } else { 3634 logger.Debug("parsed message is nil") 3635 } 3636 } 3637 3638 m.processCommunityChanges(messageState) 3639 3640 // NOTE: for now we confirm messages as processed regardless whether we 3641 // actually processed them, this is because we need to differentiate 3642 // from messages that we want to retry to process and messages that 3643 // are never going to be processed 3644 m.transport.MarkP2PMessageAsProcessed(gethcommon.BytesToHash(shhMessage.Hash)) 3645 3646 if allMessagesProcessed { 3647 processedMessages = append(processedMessages, types.EncodeHex(shhMessage.Hash)) 3648 } 3649 } 3650 3651 if len(processedMessages) != 0 { 3652 if err := m.transport.ConfirmMessagesProcessed(processedMessages, m.getTimesource().GetCurrentTime()); err != nil { 3653 logger.Warn("failed to confirm processed messages", zap.Error(err)) 3654 } 3655 } 3656 } 3657 3658 return m.saveDataAndPrepareResponse(messageState) 3659 } 3660 3661 func (m *Messenger) saveDataAndPrepareResponse(messageState *ReceivedMessageState) (*MessengerResponse, error) { 3662 var err error 3663 var contactsToSave []*Contact 3664 messageState.ModifiedContacts.Range(func(id string, value bool) (shouldContinue bool) { 3665 contact, ok := messageState.AllContacts.Load(id) 3666 if ok { 3667 contactsToSave = append(contactsToSave, contact) 3668 messageState.Response.AddContact(contact) 3669 } 3670 return true 3671 }) 3672 3673 // Hydrate chat alias and identicon 3674 for id := range messageState.Response.chats { 3675 chat, _ := messageState.AllChats.Load(id) 3676 if chat == nil { 3677 continue 3678 } 3679 if chat.OneToOne() { 3680 contact, ok := m.allContacts.Load(chat.ID) 3681 if ok { 3682 chat.Alias = contact.Alias 3683 chat.Identicon = contact.Identicon 3684 } 3685 } 3686 3687 messageState.Response.AddChat(chat) 3688 } 3689 3690 messageState.ModifiedInstallations.Range(func(id string, value bool) (shouldContinue bool) { 3691 installation, _ := messageState.AllInstallations.Load(id) 3692 messageState.Response.AddInstallation(installation) 3693 if installation.InstallationMetadata != nil { 3694 err = m.setInstallationMetadata(id, installation.InstallationMetadata) 3695 if err != nil { 3696 return false 3697 } 3698 } 3699 3700 return true 3701 }) 3702 if err != nil { 3703 return nil, err 3704 } 3705 3706 if len(messageState.Response.chats) > 0 { 3707 err = m.saveChats(messageState.Response.Chats()) 3708 if err != nil { 3709 return nil, err 3710 } 3711 } 3712 3713 messagesToSave := messageState.Response.Messages() 3714 if len(messagesToSave) > 0 { 3715 err = m.SaveMessages(messagesToSave) 3716 if err != nil { 3717 return nil, err 3718 } 3719 } 3720 3721 for _, emojiReaction := range messageState.EmojiReactions { 3722 messageState.Response.AddEmojiReaction(emojiReaction) 3723 } 3724 3725 for _, groupChatInvitation := range messageState.GroupChatInvitations { 3726 messageState.Response.Invitations = append(messageState.Response.Invitations, groupChatInvitation) 3727 } 3728 3729 if len(contactsToSave) > 0 { 3730 err = m.persistence.SaveContacts(contactsToSave) 3731 if err != nil { 3732 return nil, err 3733 } 3734 } 3735 3736 newMessagesIds := map[string]struct{}{} 3737 for _, message := range messagesToSave { 3738 if message.New { 3739 newMessagesIds[message.ID] = struct{}{} 3740 } 3741 } 3742 3743 messagesWithResponses, err := m.pullMessagesAndResponsesFromDB(messagesToSave) 3744 if err != nil { 3745 return nil, err 3746 } 3747 messagesByID := map[string]*common.Message{} 3748 for _, message := range messagesWithResponses { 3749 messagesByID[message.ID] = message 3750 } 3751 messageState.Response.SetMessages(messagesWithResponses) 3752 3753 notificationsEnabled, err := m.settings.GetNotificationsEnabled() 3754 if err != nil { 3755 return nil, err 3756 } 3757 3758 profilePicturesVisibility, err := m.settings.GetProfilePicturesVisibility() 3759 if err != nil { 3760 return nil, err 3761 } 3762 3763 err = m.prepareMessages(messageState.Response.messages) 3764 if err != nil { 3765 return nil, err 3766 } 3767 3768 for _, message := range messageState.Response.messages { 3769 if _, ok := newMessagesIds[message.ID]; ok { 3770 message.New = true 3771 3772 if notificationsEnabled { 3773 // Create notification body to be eventually passed to `localnotifications.SendMessageNotifications()` 3774 if err = messageState.addNewMessageNotification(m.identity.PublicKey, message, messagesByID[message.ResponseTo], profilePicturesVisibility); err != nil { 3775 return nil, err 3776 } 3777 } 3778 3779 // Create activity center notification body to be eventually passed to `activitycenter.SendActivityCenterNotifications()` 3780 if err = messageState.addNewActivityCenterNotification(m.identity.PublicKey, m, message, messagesByID[message.ResponseTo]); err != nil { 3781 return nil, err 3782 } 3783 } 3784 } 3785 3786 // Reset installations 3787 m.modifiedInstallations = new(stringBoolMap) 3788 3789 if len(messageState.AllBookmarks) > 0 { 3790 bookmarks, err := m.storeSyncBookmarks(messageState.AllBookmarks) 3791 if err != nil { 3792 return nil, err 3793 } 3794 messageState.Response.AddBookmarks(bookmarks) 3795 } 3796 3797 if len(messageState.AllVerificationRequests) > 0 { 3798 for _, vr := range messageState.AllVerificationRequests { 3799 messageState.Response.AddVerificationRequest(vr) 3800 } 3801 } 3802 3803 if len(messageState.AllTrustStatus) > 0 { 3804 messageState.Response.AddTrustStatuses(messageState.AllTrustStatus) 3805 } 3806 3807 // Hydrate pinned messages 3808 for _, pinnedMessage := range messageState.Response.PinMessages() { 3809 if pinnedMessage.Pinned { 3810 pinnedMessage.Message = &common.PinnedMessage{ 3811 Message: messageState.Response.GetMessage(pinnedMessage.MessageId), 3812 PinnedBy: pinnedMessage.From, 3813 PinnedAt: pinnedMessage.Clock, 3814 } 3815 } 3816 } 3817 3818 return messageState.Response, nil 3819 } 3820 3821 func (m *Messenger) storeSyncBookmarks(bookmarkMap map[string]*browsers.Bookmark) ([]*browsers.Bookmark, error) { 3822 var bookmarks []*browsers.Bookmark 3823 for _, bookmark := range bookmarkMap { 3824 bookmarks = append(bookmarks, bookmark) 3825 } 3826 return m.browserDatabase.StoreSyncBookmarks(bookmarks) 3827 } 3828 3829 func (m *Messenger) MessageByID(id string) (*common.Message, error) { 3830 msg, err := m.persistence.MessageByID(id) 3831 if err != nil { 3832 return nil, err 3833 } 3834 if m.httpServer != nil { 3835 err = m.prepareMessage(msg, m.httpServer) 3836 if err != nil { 3837 return nil, err 3838 } 3839 } 3840 return msg, nil 3841 } 3842 3843 func (m *Messenger) MessagesExist(ids []string) (map[string]bool, error) { 3844 return m.persistence.MessagesExist(ids) 3845 } 3846 3847 func (m *Messenger) FirstUnseenMessageID(chatID string) (string, error) { 3848 return m.persistence.FirstUnseenMessageID(chatID) 3849 } 3850 3851 func (m *Messenger) latestIncomingMessageClock(chatID string) (uint64, error) { 3852 return m.persistence.latestIncomingMessageClock(chatID) 3853 } 3854 3855 func (m *Messenger) MessageByChatID(chatID, cursor string, limit int) ([]*common.Message, string, error) { 3856 chat, err := m.persistence.Chat(chatID) 3857 if err != nil { 3858 return nil, "", err 3859 } 3860 3861 if chat == nil { 3862 return nil, "", ErrChatNotFound 3863 } 3864 3865 var msgs []*common.Message 3866 var nextCursor string 3867 3868 if chat.Timeline() { 3869 var chatIDs = []string{"@" + contactIDFromPublicKey(&m.identity.PublicKey)} 3870 m.allContacts.Range(func(contactID string, contact *Contact) (shouldContinue bool) { 3871 if contact.added() { 3872 chatIDs = append(chatIDs, "@"+contact.ID) 3873 } 3874 return true 3875 }) 3876 msgs, nextCursor, err = m.persistence.MessageByChatIDs(chatIDs, cursor, limit) 3877 if err != nil { 3878 return nil, "", err 3879 } 3880 } else { 3881 msgs, nextCursor, err = m.persistence.MessageByChatID(chatID, cursor, limit) 3882 if err != nil { 3883 return nil, "", err 3884 } 3885 3886 } 3887 3888 if m.httpServer != nil { 3889 err = m.prepareMessagesList(msgs) 3890 if err != nil { 3891 return nil, "", err 3892 } 3893 } 3894 3895 return msgs, nextCursor, nil 3896 } 3897 3898 func (m *Messenger) prepareMessages(messages map[string]*common.Message) error { 3899 if m.httpServer == nil { 3900 return nil 3901 } 3902 for idx := range messages { 3903 err := m.prepareMessage(messages[idx], m.httpServer) 3904 if err != nil { 3905 return err 3906 } 3907 } 3908 return nil 3909 } 3910 3911 func (m *Messenger) prepareMessagesList(messages []*common.Message) error { 3912 if m.httpServer == nil { 3913 return nil 3914 } 3915 for idx := range messages { 3916 err := m.prepareMessage(messages[idx], m.httpServer) 3917 if err != nil { 3918 return err 3919 } 3920 } 3921 return nil 3922 } 3923 3924 func extractQuotedImages(messages []*common.Message, s *server.MediaServer) []string { 3925 var quotedImages []string 3926 3927 for _, message := range messages { 3928 if message.ChatMessage != nil && message.ChatMessage.ContentType == protobuf.ChatMessage_IMAGE { 3929 quotedImages = append(quotedImages, s.MakeImageURL(message.ID)) 3930 } 3931 } 3932 return quotedImages 3933 } 3934 3935 func (m *Messenger) prepareTokenData(tokenData *ActivityTokenData, s *server.MediaServer) error { 3936 if tokenData.TokenType == int(protobuf.CommunityTokenType_ERC721) { 3937 tokenData.ImageURL = s.MakeWalletCollectibleImagesURL(tokenData.CollectibleID) 3938 } else if tokenData.TokenType == int(protobuf.CommunityTokenType_ERC20) { 3939 tokenData.ImageURL = s.MakeCommunityTokenImagesURL(tokenData.CommunityID, tokenData.ChainID, tokenData.Symbol) 3940 } 3941 return nil 3942 } 3943 3944 func (m *Messenger) prepareMessage(msg *common.Message, s *server.MediaServer) error { 3945 if msg.QuotedMessage != nil && msg.QuotedMessage.ContentType == int64(protobuf.ChatMessage_IMAGE) { 3946 msg.QuotedMessage.ImageLocalURL = s.MakeImageURL(msg.QuotedMessage.ID) 3947 3948 quotedMessage, err := m.MessageByID(msg.QuotedMessage.ID) 3949 if err != nil { 3950 return err 3951 } 3952 if quotedMessage == nil { 3953 return errors.New("message not found") 3954 } 3955 3956 if quotedMessage.ChatMessage != nil { 3957 image := quotedMessage.ChatMessage.GetImage() 3958 albumID := quotedMessage.ChatMessage.GetImage().AlbumId 3959 3960 if image != nil && image.GetAlbumId() != "" { 3961 albumMessages, err := m.persistence.albumMessages(quotedMessage.LocalChatID, albumID) 3962 if err != nil { 3963 return err 3964 } 3965 3966 quotedImages := extractQuotedImages(albumMessages, s) 3967 quotedImagesJSON, err := json.Marshal(quotedImages) 3968 if err != nil { 3969 return err 3970 } 3971 3972 msg.QuotedMessage.AlbumImages = quotedImagesJSON 3973 } 3974 } 3975 } 3976 if msg.QuotedMessage != nil && msg.QuotedMessage.ContentType == int64(protobuf.ChatMessage_AUDIO) { 3977 msg.QuotedMessage.AudioLocalURL = s.MakeAudioURL(msg.QuotedMessage.ID) 3978 } 3979 if msg.QuotedMessage != nil && msg.QuotedMessage.ContentType == int64(protobuf.ChatMessage_STICKER) { 3980 msg.QuotedMessage.HasSticker = true 3981 } 3982 if msg.QuotedMessage != nil && msg.QuotedMessage.ContentType == int64(protobuf.ChatMessage_DISCORD_MESSAGE) { 3983 dm := msg.QuotedMessage.DiscordMessage 3984 exists, err := m.persistence.HasDiscordMessageAuthorImagePayload(dm.Author.Id) 3985 if err != nil { 3986 return err 3987 } 3988 3989 if exists { 3990 msg.QuotedMessage.DiscordMessage.Author.LocalUrl = s.MakeDiscordAuthorAvatarURL(dm.Author.Id) 3991 } 3992 } 3993 3994 if msg.ContentType == protobuf.ChatMessage_IMAGE { 3995 msg.ImageLocalURL = s.MakeImageURL(msg.ID) 3996 } 3997 3998 if msg.ContentType == protobuf.ChatMessage_DISCORD_MESSAGE { 3999 4000 dm := msg.GetDiscordMessage() 4001 exists, err := m.persistence.HasDiscordMessageAuthorImagePayload(dm.Author.Id) 4002 if err != nil { 4003 return err 4004 } 4005 4006 if exists { 4007 dm.Author.LocalUrl = s.MakeDiscordAuthorAvatarURL(dm.Author.Id) 4008 } 4009 4010 for idx, attachment := range dm.Attachments { 4011 if strings.Contains(attachment.ContentType, "image") { 4012 hasPayload, err := m.persistence.HasDiscordMessageAttachmentPayload(attachment.Id, dm.Id) 4013 if err != nil { 4014 m.logger.Error("failed to check if message attachment exist", zap.Error(err)) 4015 continue 4016 } 4017 if hasPayload { 4018 localURL := s.MakeDiscordAttachmentURL(dm.Id, attachment.Id) 4019 dm.Attachments[idx].LocalUrl = localURL 4020 } 4021 } 4022 } 4023 msg.Payload = &protobuf.ChatMessage_DiscordMessage{ 4024 DiscordMessage: dm, 4025 } 4026 } 4027 if msg.ContentType == protobuf.ChatMessage_AUDIO { 4028 msg.AudioLocalURL = s.MakeAudioURL(msg.ID) 4029 } 4030 if msg.ContentType == protobuf.ChatMessage_STICKER { 4031 msg.StickerLocalURL = s.MakeStickerURL(msg.GetSticker().Hash) 4032 } 4033 msg.LinkPreviews = msg.ConvertFromProtoToLinkPreviews(s.MakeLinkPreviewThumbnailURL, s.MakeLinkPreviewFaviconURL) 4034 msg.StatusLinkPreviews = msg.ConvertFromProtoToStatusLinkPreviews(s.MakeStatusLinkPreviewThumbnailURL) 4035 4036 return nil 4037 } 4038 4039 func (m *Messenger) AllMessageByChatIDWhichMatchTerm(chatID string, searchTerm string, caseSensitive bool) ([]*common.Message, error) { 4040 _, err := m.persistence.Chat(chatID) 4041 if err != nil { 4042 return nil, err 4043 } 4044 4045 messages, err := m.persistence.AllMessageByChatIDWhichMatchTerm(chatID, searchTerm, caseSensitive) 4046 if err != nil { 4047 return nil, err 4048 } 4049 4050 return m.filterOutHiddenChatMessages(messages) 4051 4052 } 4053 4054 func (m *Messenger) AllMessagesFromChatsAndCommunitiesWhichMatchTerm(communityIds []string, chatIds []string, searchTerm string, caseSensitive bool) ([]*common.Message, error) { 4055 messages, err := m.persistence.AllMessagesFromChatsAndCommunitiesWhichMatchTerm(communityIds, chatIds, searchTerm, caseSensitive) 4056 if err != nil { 4057 return nil, err 4058 } 4059 4060 return m.filterOutHiddenChatMessages(messages) 4061 } 4062 4063 func (m *Messenger) filterOutHiddenChatMessages(messages []*common.Message) ([]*common.Message, error) { 4064 communitiesCache := make(map[string]*communities.Community) 4065 chatVisibilityCache := make(map[string]bool) 4066 var filteredMessages []*common.Message 4067 4068 for _, message := range messages { 4069 chatVisible, ok := chatVisibilityCache[message.ChatId] 4070 if ok && chatVisible { 4071 filteredMessages = append(filteredMessages, message) 4072 continue 4073 } 4074 4075 chat, ok := m.allChats.Load(message.ChatId) 4076 if !ok { 4077 return nil, ErrChatNotFoundError 4078 } 4079 4080 if chat.CommunityID == "" { 4081 filteredMessages = append(filteredMessages, message) 4082 continue 4083 } 4084 4085 community, ok := communitiesCache[chat.CommunityID] 4086 if !ok { 4087 communityID, err := hexutil.Decode(chat.CommunityID) 4088 if err != nil { 4089 return nil, err 4090 } 4091 comm, err := m.communitiesManager.GetByID(communityID) 4092 if err != nil { 4093 if err == communities.ErrOrgNotFound { 4094 continue 4095 } 4096 return nil, err 4097 } 4098 communitiesCache[chat.CommunityID] = comm 4099 community = comm 4100 } 4101 4102 canView := community.CanView(&m.identity.PublicKey, chat.CommunityChannelID()) 4103 chatVisibilityCache[chat.ID] = canView 4104 4105 if canView { 4106 filteredMessages = append(filteredMessages, message) 4107 } 4108 } 4109 4110 return filteredMessages, nil 4111 } 4112 4113 func (m *Messenger) SaveMessages(messages []*common.Message) error { 4114 return m.persistence.SaveMessages(messages) 4115 } 4116 4117 func (m *Messenger) DeleteMessage(id string) error { 4118 return m.persistence.DeleteMessage(id) 4119 } 4120 4121 func (m *Messenger) DeleteMessagesByChatID(id string) error { 4122 return m.persistence.DeleteMessagesByChatID(id) 4123 } 4124 4125 func (m *Messenger) markMessageAsUnreadImpl(chatID string, messageID string) (uint64, uint64, error) { 4126 count, countWithMentions, err := m.persistence.MarkMessageAsUnread(chatID, messageID) 4127 4128 if err != nil { 4129 return 0, 0, err 4130 } 4131 4132 chat, err := m.persistence.Chat(chatID) 4133 if err != nil { 4134 return 0, 0, err 4135 } 4136 m.allChats.Store(chatID, chat) 4137 return count, countWithMentions, nil 4138 } 4139 4140 func (m *Messenger) MarkMessageAsUnread(chatID string, messageID string) (*MessengerResponse, error) { 4141 count, countWithMentions, err := m.markMessageAsUnreadImpl(chatID, messageID) 4142 if err != nil { 4143 return nil, err 4144 } 4145 4146 response := &MessengerResponse{} 4147 response.AddSeenAndUnseenMessages(&SeenUnseenMessages{ 4148 ChatID: chatID, 4149 Count: count, 4150 CountWithMentions: countWithMentions, 4151 Seen: false, 4152 }) 4153 4154 ids, err := m.persistence.GetMessageIdsWithGreaterTimestamp(chatID, messageID) 4155 if err != nil { 4156 return nil, err 4157 } 4158 4159 hexBytesIds := []types.HexBytes{} 4160 for _, id := range ids { 4161 hexBytesIds = append(hexBytesIds, types.FromHex(id)) 4162 } 4163 4164 updatedAt := m.GetCurrentTimeInMillis() 4165 notifications, err := m.persistence.MarkActivityCenterNotificationsUnread(hexBytesIds, updatedAt) 4166 if err != nil { 4167 return nil, err 4168 } 4169 4170 response.AddActivityCenterNotifications(notifications) 4171 4172 return response, nil 4173 } 4174 4175 // MarkMessagesSeen marks messages with `ids` as seen in the chat `chatID`. 4176 // It returns the number of affected messages or error. If there is an error, 4177 // the number of affected messages is always zero. 4178 func (m *Messenger) markMessagesSeenImpl(chatID string, ids []string) (uint64, uint64, *Chat, error) { 4179 count, countWithMentions, err := m.persistence.MarkMessagesSeen(chatID, ids) 4180 if err != nil { 4181 return 0, 0, nil, err 4182 } 4183 chat, err := m.persistence.Chat(chatID) 4184 if err != nil { 4185 return 0, 0, nil, err 4186 } 4187 m.allChats.Store(chatID, chat) 4188 return count, countWithMentions, chat, nil 4189 } 4190 4191 // Deprecated: Use MarkMessagesRead instead 4192 func (m *Messenger) MarkMessagesSeen(chatID string, ids []string) (uint64, uint64, []*ActivityCenterNotification, error) { 4193 count, countWithMentions, _, err := m.markMessagesSeenImpl(chatID, ids) 4194 if err != nil { 4195 return 0, 0, nil, err 4196 } 4197 4198 hexBytesIds := []types.HexBytes{} 4199 for _, id := range ids { 4200 hexBytesIds = append(hexBytesIds, types.FromHex(id)) 4201 } 4202 4203 // Mark notifications as read in the database 4204 updatedAt := m.GetCurrentTimeInMillis() 4205 err = m.persistence.MarkActivityCenterNotificationsRead(hexBytesIds, updatedAt) 4206 if err != nil { 4207 return 0, 0, nil, err 4208 } 4209 4210 notifications, err := m.persistence.GetActivityCenterNotificationsByID(hexBytesIds) 4211 if err != nil { 4212 return 0, 0, nil, err 4213 } 4214 4215 return count, countWithMentions, notifications, nil 4216 } 4217 4218 func (m *Messenger) MarkMessagesRead(chatID string, ids []string) (*MessengerResponse, error) { 4219 count, countWithMentions, _, err := m.markMessagesSeenImpl(chatID, ids) 4220 if err != nil { 4221 return nil, err 4222 } 4223 4224 response := &MessengerResponse{} 4225 response.AddSeenAndUnseenMessages(&SeenUnseenMessages{ 4226 ChatID: chatID, 4227 Count: count, 4228 CountWithMentions: countWithMentions, 4229 Seen: true, 4230 }) 4231 4232 hexBytesIds := []types.HexBytes{} 4233 for _, id := range ids { 4234 hexBytesIds = append(hexBytesIds, types.FromHex(id)) 4235 } 4236 4237 // Mark notifications as read in the database 4238 updatedAt := m.GetCurrentTimeInMillis() 4239 err = m.persistence.MarkActivityCenterNotificationsRead(hexBytesIds, updatedAt) 4240 if err != nil { 4241 return nil, err 4242 } 4243 4244 notifications, err := m.persistence.GetActivityCenterNotificationsByID(hexBytesIds) 4245 if err != nil { 4246 return nil, err 4247 } 4248 4249 response.AddActivityCenterNotifications(notifications) 4250 4251 return response, nil 4252 } 4253 4254 func (m *Messenger) syncChatMessagesRead(ctx context.Context, chatID string, clock uint64, rawMessageHandler RawMessageHandler) error { 4255 if !m.hasPairedDevices() { 4256 return nil 4257 } 4258 4259 _, chat := m.getLastClockWithRelatedChat() 4260 4261 syncMessage := &protobuf.SyncChatMessagesRead{ 4262 Clock: clock, 4263 Id: chatID, 4264 } 4265 encodedMessage, err := proto.Marshal(syncMessage) 4266 if err != nil { 4267 return err 4268 } 4269 4270 rawMessage := common.RawMessage{ 4271 LocalChatID: chat.ID, 4272 Payload: encodedMessage, 4273 MessageType: protobuf.ApplicationMetadataMessage_SYNC_CHAT_MESSAGES_READ, 4274 ResendType: common.ResendTypeDataSync, 4275 } 4276 4277 _, err = rawMessageHandler(ctx, rawMessage) 4278 4279 return err 4280 } 4281 4282 func (m *Messenger) markAllRead(chatID string, clock uint64, shouldBeSynced bool) error { 4283 chat, ok := m.allChats.Load(chatID) 4284 if !ok { 4285 return ErrChatNotFoundError 4286 } 4287 4288 _, _, err := m.persistence.MarkAllRead(chatID, clock) 4289 if err != nil { 4290 return err 4291 } 4292 4293 if shouldBeSynced { 4294 err := m.syncChatMessagesRead(context.Background(), chatID, clock, m.dispatchMessage) 4295 if err != nil { 4296 return err 4297 } 4298 } 4299 4300 chat.ReadMessagesAtClockValue = clock 4301 chat.Highlight = false 4302 4303 chat.UnviewedMessagesCount = 0 4304 chat.UnviewedMentionsCount = 0 4305 4306 if chat.LastMessage != nil { 4307 chat.LastMessage.Seen = true 4308 } 4309 4310 // TODO(samyoul) remove storing of an updated reference pointer? 4311 m.allChats.Store(chat.ID, chat) 4312 return m.persistence.SaveChats([]*Chat{chat}) 4313 } 4314 4315 func (m *Messenger) MarkAllRead(ctx context.Context, chatID string) (*MessengerResponse, error) { 4316 response := &MessengerResponse{} 4317 4318 notifications, err := m.DismissAllActivityCenterNotificationsFromChatID(ctx, chatID, m.GetCurrentTimeInMillis()) 4319 if err != nil { 4320 return nil, err 4321 } 4322 response.AddActivityCenterNotifications(notifications) 4323 4324 clock, _ := m.latestIncomingMessageClock(chatID) 4325 4326 if clock == 0 { 4327 chat, ok := m.allChats.Load(chatID) 4328 if !ok { 4329 return nil, ErrChatNotFoundError 4330 } 4331 clock, _ = chat.NextClockAndTimestamp(m.getTimesource()) 4332 } 4333 4334 err = m.markAllRead(chatID, clock, true) 4335 if err != nil { 4336 return nil, err 4337 } 4338 return response, nil 4339 } 4340 4341 func (m *Messenger) MarkAllReadInCommunity(ctx context.Context, communityID string) (*MessengerResponse, error) { 4342 response := &MessengerResponse{} 4343 4344 notifications, err := m.DismissAllActivityCenterNotificationsFromCommunity(ctx, communityID, m.GetCurrentTimeInMillis()) 4345 if err != nil { 4346 return nil, err 4347 } 4348 response.AddActivityCenterNotifications(notifications) 4349 4350 chatIDs, err := m.persistence.AllChatIDsByCommunity(nil, communityID) 4351 if err != nil { 4352 return nil, err 4353 } 4354 4355 err = m.persistence.MarkAllReadMultiple(chatIDs) 4356 if err != nil { 4357 return nil, err 4358 } 4359 4360 for _, chatID := range chatIDs { 4361 chat, ok := m.allChats.Load(chatID) 4362 4363 if ok { 4364 chat.UnviewedMessagesCount = 0 4365 chat.UnviewedMentionsCount = 0 4366 m.allChats.Store(chat.ID, chat) 4367 response.AddChat(chat) 4368 } else { 4369 err = fmt.Errorf("chat with chatID %s not found", chatID) 4370 } 4371 } 4372 return response, err 4373 } 4374 4375 // MuteChat signals to the messenger that we don't want to be notified 4376 // on new messages from this chat 4377 func (m *Messenger) MuteChat(request *requests.MuteChat) (time.Time, error) { 4378 chat, ok := m.allChats.Load(request.ChatID) 4379 if !ok { 4380 // Only one to one chan be muted when it's not in the database 4381 publicKey, err := common.HexToPubkey(request.ChatID) 4382 if err != nil { 4383 return time.Time{}, err 4384 } 4385 4386 // Create a one to one chat and set active to false 4387 chat = CreateOneToOneChat(request.ChatID, publicKey, m.getTimesource()) 4388 chat.Active = false 4389 err = m.initChatSyncFields(chat) 4390 if err != nil { 4391 return time.Time{}, err 4392 } 4393 err = m.saveChat(chat) 4394 if err != nil { 4395 return time.Time{}, err 4396 } 4397 } 4398 4399 var contact *Contact 4400 if chat.OneToOne() { 4401 contact, _ = m.allContacts.Load(request.ChatID) 4402 } 4403 4404 var MuteTill time.Time 4405 4406 switch request.MutedType { 4407 case MuteTill1Min: 4408 MuteTill = time.Now().Add(MuteFor1MinDuration) 4409 case MuteFor15Min: 4410 MuteTill = time.Now().Add(MuteFor15MinsDuration) 4411 case MuteFor1Hr: 4412 MuteTill = time.Now().Add(MuteFor1HrsDuration) 4413 case MuteFor8Hr: 4414 MuteTill = time.Now().Add(MuteFor8HrsDuration) 4415 case MuteFor24Hr: 4416 MuteTill = time.Now().Add(MuteFor24HrsDuration) 4417 case MuteFor1Week: 4418 MuteTill = time.Now().Add(MuteFor1WeekDuration) 4419 default: 4420 MuteTill = time.Time{} 4421 } 4422 err := m.saveChat(chat) 4423 if err != nil { 4424 return time.Time{}, err 4425 } 4426 4427 muteTillTimeRemoveMs, err := time.Parse(time.RFC3339, MuteTill.Format(time.RFC3339)) 4428 4429 if err != nil { 4430 return time.Time{}, err 4431 } 4432 4433 return m.muteChat(chat, contact, muteTillTimeRemoveMs) 4434 } 4435 4436 func (m *Messenger) MuteChatV2(muteParams *requests.MuteChat) (time.Time, error) { 4437 return m.MuteChat(muteParams) 4438 } 4439 4440 func (m *Messenger) muteChat(chat *Chat, contact *Contact, mutedTill time.Time) (time.Time, error) { 4441 err := m.persistence.MuteChat(chat.ID, mutedTill) 4442 if err != nil { 4443 return time.Time{}, err 4444 } 4445 4446 chat.Muted = true 4447 chat.MuteTill = mutedTill 4448 // TODO(samyoul) remove storing of an updated reference pointer? 4449 m.allChats.Store(chat.ID, chat) 4450 4451 if contact != nil { 4452 err := m.syncContact(context.Background(), contact, m.dispatchMessage) 4453 if err != nil { 4454 return time.Time{}, err 4455 } 4456 } 4457 4458 if !chat.MuteTill.IsZero() { 4459 err := m.reregisterForPushNotifications() 4460 if err != nil { 4461 return time.Time{}, err 4462 } 4463 return mutedTill, nil 4464 } 4465 4466 return time.Time{}, m.reregisterForPushNotifications() 4467 } 4468 4469 // UnmuteChat signals to the messenger that we want to be notified 4470 // on new messages from this chat 4471 func (m *Messenger) UnmuteChat(chatID string) error { 4472 chat, ok := m.allChats.Load(chatID) 4473 if !ok { 4474 return ErrChatNotFoundError 4475 } 4476 4477 var contact *Contact 4478 if chat.OneToOne() { 4479 contact, _ = m.allContacts.Load(chatID) 4480 } 4481 4482 return m.unmuteChat(chat, contact) 4483 } 4484 4485 func (m *Messenger) unmuteChat(chat *Chat, contact *Contact) error { 4486 err := m.persistence.UnmuteChat(chat.ID) 4487 if err != nil { 4488 return err 4489 } 4490 4491 chat.Muted = false 4492 chat.MuteTill = time.Time{} 4493 // TODO(samyoul) remove storing of an updated reference pointer? 4494 m.allChats.Store(chat.ID, chat) 4495 4496 if chat.CommunityChat() { 4497 community, err := m.communitiesManager.GetByIDString(chat.CommunityID) 4498 if err != nil { 4499 return err 4500 } 4501 4502 err = m.communitiesManager.SetMuted(community.ID(), false) 4503 if err != nil { 4504 return err 4505 } 4506 } 4507 4508 if contact != nil { 4509 err := m.syncContact(context.Background(), contact, m.dispatchMessage) 4510 if err != nil { 4511 return err 4512 } 4513 } 4514 return m.reregisterForPushNotifications() 4515 } 4516 4517 func (m *Messenger) UpdateMessageOutgoingStatus(id, newOutgoingStatus string) error { 4518 return m.persistence.UpdateMessageOutgoingStatus(id, newOutgoingStatus) 4519 } 4520 4521 // Identicon returns an identicon based on the input string 4522 func Identicon(id string) (string, error) { 4523 return identicon.GenerateBase64(id) 4524 } 4525 4526 // GenerateAlias name returns the generated name given a public key hex encoded prefixed with 0x 4527 func GenerateAlias(id string) (string, error) { 4528 return alias.GenerateFromPublicKeyString(id) 4529 } 4530 4531 func (m *Messenger) RequestTransaction(ctx context.Context, chatID, value, contract, address string) (*MessengerResponse, error) { 4532 var response MessengerResponse 4533 4534 // A valid added chat is required. 4535 chat, ok := m.allChats.Load(chatID) 4536 if !ok { 4537 return nil, ErrChatNotFoundError 4538 } 4539 if chat.ChatType != ChatTypeOneToOne { 4540 return nil, errors.New("Need to be a one-to-one chat") 4541 } 4542 4543 message := common.NewMessage() 4544 err := extendMessageFromChat(message, chat, &m.identity.PublicKey, m.transport) 4545 if err != nil { 4546 return nil, err 4547 } 4548 4549 message.MessageType = protobuf.MessageType_ONE_TO_ONE 4550 message.ContentType = protobuf.ChatMessage_TRANSACTION_COMMAND 4551 message.Seen = true 4552 message.Text = "Request transaction" 4553 4554 request := &protobuf.RequestTransaction{ 4555 Clock: message.Clock, 4556 Address: address, 4557 Value: value, 4558 Contract: contract, 4559 ChatId: chatID, 4560 } 4561 encodedMessage, err := proto.Marshal(request) 4562 if err != nil { 4563 return nil, err 4564 } 4565 resendType := common.ResendTypeRawMessage 4566 if chat.ChatType == ChatTypeOneToOne { 4567 resendType = common.ResendTypeDataSync 4568 } 4569 rawMessage, err := m.dispatchMessage(ctx, common.RawMessage{ 4570 LocalChatID: chat.ID, 4571 Payload: encodedMessage, 4572 MessageType: protobuf.ApplicationMetadataMessage_REQUEST_TRANSACTION, 4573 ResendType: resendType, 4574 }) 4575 4576 message.CommandParameters = &common.CommandParameters{ 4577 ID: rawMessage.ID, 4578 Value: value, 4579 Address: address, 4580 Contract: contract, 4581 CommandState: common.CommandStateRequestTransaction, 4582 } 4583 4584 if err != nil { 4585 return nil, err 4586 } 4587 messageID := rawMessage.ID 4588 4589 message.ID = messageID 4590 message.CommandParameters.ID = messageID 4591 err = message.PrepareContent(common.PubkeyToHex(&m.identity.PublicKey)) 4592 if err != nil { 4593 return nil, err 4594 } 4595 4596 err = chat.UpdateFromMessage(message, m.transport) 4597 if err != nil { 4598 return nil, err 4599 } 4600 4601 err = m.persistence.SaveMessages([]*common.Message{message}) 4602 if err != nil { 4603 return nil, err 4604 } 4605 4606 return m.addMessagesAndChat(chat, []*common.Message{message}, &response) 4607 } 4608 4609 func (m *Messenger) RequestAddressForTransaction(ctx context.Context, chatID, from, value, contract string) (*MessengerResponse, error) { 4610 var response MessengerResponse 4611 4612 // A valid added chat is required. 4613 chat, ok := m.allChats.Load(chatID) 4614 if !ok { 4615 return nil, ErrChatNotFoundError 4616 } 4617 if chat.ChatType != ChatTypeOneToOne { 4618 return nil, errors.New("Need to be a one-to-one chat") 4619 } 4620 4621 message := common.NewMessage() 4622 err := extendMessageFromChat(message, chat, &m.identity.PublicKey, m.transport) 4623 if err != nil { 4624 return nil, err 4625 } 4626 4627 message.MessageType = protobuf.MessageType_ONE_TO_ONE 4628 message.ContentType = protobuf.ChatMessage_TRANSACTION_COMMAND 4629 message.Seen = true 4630 message.Text = "Request address for transaction" 4631 4632 request := &protobuf.RequestAddressForTransaction{ 4633 Clock: message.Clock, 4634 Value: value, 4635 Contract: contract, 4636 ChatId: chatID, 4637 } 4638 encodedMessage, err := proto.Marshal(request) 4639 if err != nil { 4640 return nil, err 4641 } 4642 4643 resendType := common.ResendTypeRawMessage 4644 if chat.ChatType == ChatTypeOneToOne { 4645 resendType = common.ResendTypeDataSync 4646 } 4647 rawMessage, err := m.dispatchMessage(ctx, common.RawMessage{ 4648 LocalChatID: chat.ID, 4649 Payload: encodedMessage, 4650 MessageType: protobuf.ApplicationMetadataMessage_REQUEST_ADDRESS_FOR_TRANSACTION, 4651 ResendType: resendType, 4652 }) 4653 4654 message.CommandParameters = &common.CommandParameters{ 4655 ID: rawMessage.ID, 4656 From: from, 4657 Value: value, 4658 Contract: contract, 4659 CommandState: common.CommandStateRequestAddressForTransaction, 4660 } 4661 4662 if err != nil { 4663 return nil, err 4664 } 4665 messageID := rawMessage.ID 4666 4667 message.ID = messageID 4668 message.CommandParameters.ID = messageID 4669 err = message.PrepareContent(common.PubkeyToHex(&m.identity.PublicKey)) 4670 if err != nil { 4671 return nil, err 4672 } 4673 4674 err = chat.UpdateFromMessage(message, m.transport) 4675 if err != nil { 4676 return nil, err 4677 } 4678 4679 err = m.persistence.SaveMessages([]*common.Message{message}) 4680 if err != nil { 4681 return nil, err 4682 } 4683 4684 return m.addMessagesAndChat(chat, []*common.Message{message}, &response) 4685 } 4686 4687 func (m *Messenger) AcceptRequestAddressForTransaction(ctx context.Context, messageID, address string) (*MessengerResponse, error) { 4688 var response MessengerResponse 4689 4690 message, err := m.MessageByID(messageID) 4691 if err != nil { 4692 return nil, err 4693 } 4694 4695 if message == nil { 4696 return nil, errors.New("message not found") 4697 } 4698 4699 chatID := message.LocalChatID 4700 4701 // A valid added chat is required. 4702 chat, ok := m.allChats.Load(chatID) 4703 if !ok { 4704 return nil, ErrChatNotFoundError 4705 } 4706 if chat.ChatType != ChatTypeOneToOne { 4707 return nil, errors.New("Need to be a one-to-one chat") 4708 } 4709 4710 clock, timestamp := chat.NextClockAndTimestamp(m.transport) 4711 message.Clock = clock 4712 message.WhisperTimestamp = timestamp 4713 message.Timestamp = timestamp 4714 message.Text = "Request address for transaction accepted" 4715 message.Seen = true 4716 message.OutgoingStatus = common.OutgoingStatusSending 4717 4718 // Hide previous message 4719 previousMessage, err := m.persistence.MessageByCommandID(chatID, messageID) 4720 if err != nil { 4721 return nil, err 4722 } 4723 4724 if previousMessage == nil { 4725 return nil, errors.New("No previous message found") 4726 } 4727 4728 err = m.persistence.HideMessage(previousMessage.ID) 4729 if err != nil { 4730 return nil, err 4731 } 4732 4733 message.Replace = previousMessage.ID 4734 4735 request := &protobuf.AcceptRequestAddressForTransaction{ 4736 Clock: message.Clock, 4737 Id: messageID, 4738 Address: address, 4739 ChatId: chatID, 4740 } 4741 encodedMessage, err := proto.Marshal(request) 4742 if err != nil { 4743 return nil, err 4744 } 4745 4746 resendType := common.ResendTypeRawMessage 4747 if chat.ChatType == ChatTypeOneToOne { 4748 resendType = common.ResendTypeDataSync 4749 } 4750 rawMessage, err := m.dispatchMessage(ctx, common.RawMessage{ 4751 LocalChatID: chat.ID, 4752 Payload: encodedMessage, 4753 MessageType: protobuf.ApplicationMetadataMessage_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION, 4754 ResendType: resendType, 4755 }) 4756 4757 if err != nil { 4758 return nil, err 4759 } 4760 4761 message.ID = rawMessage.ID 4762 message.CommandParameters.Address = address 4763 message.CommandParameters.CommandState = common.CommandStateRequestAddressForTransactionAccepted 4764 4765 err = message.PrepareContent(common.PubkeyToHex(&m.identity.PublicKey)) 4766 if err != nil { 4767 return nil, err 4768 } 4769 4770 err = chat.UpdateFromMessage(message, m.transport) 4771 if err != nil { 4772 return nil, err 4773 } 4774 4775 err = m.persistence.SaveMessages([]*common.Message{message}) 4776 if err != nil { 4777 return nil, err 4778 } 4779 4780 return m.addMessagesAndChat(chat, []*common.Message{message}, &response) 4781 } 4782 4783 func (m *Messenger) DeclineRequestTransaction(ctx context.Context, messageID string) (*MessengerResponse, error) { 4784 var response MessengerResponse 4785 4786 message, err := m.MessageByID(messageID) 4787 if err != nil { 4788 return nil, err 4789 } 4790 4791 if message == nil { 4792 return nil, errors.New("message not found") 4793 } 4794 4795 chatID := message.LocalChatID 4796 4797 // A valid added chat is required. 4798 chat, ok := m.allChats.Load(chatID) 4799 if !ok { 4800 return nil, ErrChatNotFoundError 4801 } 4802 if chat.ChatType != ChatTypeOneToOne { 4803 return nil, errors.New("Need to be a one-to-one chat") 4804 } 4805 4806 clock, timestamp := chat.NextClockAndTimestamp(m.transport) 4807 message.Clock = clock 4808 message.WhisperTimestamp = timestamp 4809 message.Timestamp = timestamp 4810 message.Text = "Transaction request declined" 4811 message.Seen = true 4812 message.OutgoingStatus = common.OutgoingStatusSending 4813 message.Replace = messageID 4814 4815 err = m.persistence.HideMessage(messageID) 4816 if err != nil { 4817 return nil, err 4818 } 4819 4820 request := &protobuf.DeclineRequestTransaction{ 4821 Clock: message.Clock, 4822 Id: messageID, 4823 ChatId: chatID, 4824 } 4825 encodedMessage, err := proto.Marshal(request) 4826 if err != nil { 4827 return nil, err 4828 } 4829 4830 resendType := common.ResendTypeRawMessage 4831 if chat.ChatType == ChatTypeOneToOne { 4832 resendType = common.ResendTypeDataSync 4833 } 4834 rawMessage, err := m.dispatchMessage(ctx, common.RawMessage{ 4835 LocalChatID: chat.ID, 4836 Payload: encodedMessage, 4837 MessageType: protobuf.ApplicationMetadataMessage_DECLINE_REQUEST_TRANSACTION, 4838 ResendType: resendType, 4839 }) 4840 4841 if err != nil { 4842 return nil, err 4843 } 4844 4845 message.ID = rawMessage.ID 4846 message.CommandParameters.CommandState = common.CommandStateRequestTransactionDeclined 4847 4848 err = message.PrepareContent(common.PubkeyToHex(&m.identity.PublicKey)) 4849 if err != nil { 4850 return nil, err 4851 } 4852 4853 err = chat.UpdateFromMessage(message, m.transport) 4854 if err != nil { 4855 return nil, err 4856 } 4857 4858 err = m.persistence.SaveMessages([]*common.Message{message}) 4859 if err != nil { 4860 return nil, err 4861 } 4862 4863 return m.addMessagesAndChat(chat, []*common.Message{message}, &response) 4864 } 4865 4866 func (m *Messenger) DeclineRequestAddressForTransaction(ctx context.Context, messageID string) (*MessengerResponse, error) { 4867 var response MessengerResponse 4868 4869 message, err := m.MessageByID(messageID) 4870 if err != nil { 4871 return nil, err 4872 } 4873 4874 if message == nil { 4875 return nil, errors.New("message not found") 4876 } 4877 4878 chatID := message.LocalChatID 4879 4880 // A valid added chat is required. 4881 chat, ok := m.allChats.Load(chatID) 4882 if !ok { 4883 return nil, ErrChatNotFoundError 4884 } 4885 if chat.ChatType != ChatTypeOneToOne { 4886 return nil, errors.New("Need to be a one-to-one chat") 4887 } 4888 4889 clock, timestamp := chat.NextClockAndTimestamp(m.transport) 4890 message.Clock = clock 4891 message.WhisperTimestamp = timestamp 4892 message.Timestamp = timestamp 4893 message.Text = "Request address for transaction declined" 4894 message.Seen = true 4895 message.OutgoingStatus = common.OutgoingStatusSending 4896 message.Replace = messageID 4897 4898 err = m.persistence.HideMessage(messageID) 4899 if err != nil { 4900 return nil, err 4901 } 4902 4903 request := &protobuf.DeclineRequestAddressForTransaction{ 4904 Clock: message.Clock, 4905 Id: messageID, 4906 ChatId: chatID, 4907 } 4908 encodedMessage, err := proto.Marshal(request) 4909 if err != nil { 4910 return nil, err 4911 } 4912 4913 resendType := common.ResendTypeRawMessage 4914 if chat.ChatType == ChatTypeOneToOne { 4915 resendType = common.ResendTypeDataSync 4916 } 4917 rawMessage, err := m.dispatchMessage(ctx, common.RawMessage{ 4918 LocalChatID: chat.ID, 4919 Payload: encodedMessage, 4920 MessageType: protobuf.ApplicationMetadataMessage_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION, 4921 ResendType: resendType, 4922 }) 4923 4924 if err != nil { 4925 return nil, err 4926 } 4927 4928 message.ID = rawMessage.ID 4929 message.CommandParameters.CommandState = common.CommandStateRequestAddressForTransactionDeclined 4930 4931 err = message.PrepareContent(common.PubkeyToHex(&m.identity.PublicKey)) 4932 if err != nil { 4933 return nil, err 4934 } 4935 4936 err = chat.UpdateFromMessage(message, m.transport) 4937 if err != nil { 4938 return nil, err 4939 } 4940 4941 err = m.persistence.SaveMessages([]*common.Message{message}) 4942 if err != nil { 4943 return nil, err 4944 } 4945 4946 return m.addMessagesAndChat(chat, []*common.Message{message}, &response) 4947 } 4948 4949 func (m *Messenger) AcceptRequestTransaction(ctx context.Context, transactionHash, messageID string, signature []byte) (*MessengerResponse, error) { 4950 var response MessengerResponse 4951 4952 message, err := m.MessageByID(messageID) 4953 if err != nil { 4954 return nil, err 4955 } 4956 4957 if message == nil { 4958 return nil, errors.New("message not found") 4959 } 4960 4961 chatID := message.LocalChatID 4962 4963 // A valid added chat is required. 4964 chat, ok := m.allChats.Load(chatID) 4965 if !ok { 4966 return nil, ErrChatNotFoundError 4967 } 4968 if chat.ChatType != ChatTypeOneToOne { 4969 return nil, errors.New("Need to be a one-to-one chat") 4970 } 4971 4972 clock, timestamp := chat.NextClockAndTimestamp(m.transport) 4973 message.Clock = clock 4974 message.WhisperTimestamp = timestamp 4975 message.Timestamp = timestamp 4976 message.Seen = true 4977 message.Text = transactionSentTxt 4978 message.OutgoingStatus = common.OutgoingStatusSending 4979 4980 // Hide previous message 4981 previousMessage, err := m.persistence.MessageByCommandID(chatID, messageID) 4982 if err != nil && err != common.ErrRecordNotFound { 4983 return nil, err 4984 } 4985 4986 if previousMessage != nil { 4987 err = m.persistence.HideMessage(previousMessage.ID) 4988 if err != nil { 4989 return nil, err 4990 } 4991 message.Replace = previousMessage.ID 4992 } 4993 4994 err = m.persistence.HideMessage(messageID) 4995 if err != nil { 4996 return nil, err 4997 } 4998 4999 request := &protobuf.SendTransaction{ 5000 Clock: message.Clock, 5001 Id: messageID, 5002 TransactionHash: transactionHash, 5003 Signature: signature, 5004 ChatId: chatID, 5005 } 5006 encodedMessage, err := proto.Marshal(request) 5007 if err != nil { 5008 return nil, err 5009 } 5010 5011 resendType := common.ResendTypeRawMessage 5012 if chat.ChatType == ChatTypeOneToOne { 5013 resendType = common.ResendTypeDataSync 5014 } 5015 rawMessage, err := m.dispatchMessage(ctx, common.RawMessage{ 5016 LocalChatID: chat.ID, 5017 Payload: encodedMessage, 5018 MessageType: protobuf.ApplicationMetadataMessage_SEND_TRANSACTION, 5019 ResendType: resendType, 5020 }) 5021 5022 if err != nil { 5023 return nil, err 5024 } 5025 5026 message.ID = rawMessage.ID 5027 message.CommandParameters.TransactionHash = transactionHash 5028 message.CommandParameters.Signature = signature 5029 message.CommandParameters.CommandState = common.CommandStateTransactionSent 5030 5031 err = message.PrepareContent(common.PubkeyToHex(&m.identity.PublicKey)) 5032 if err != nil { 5033 return nil, err 5034 } 5035 5036 err = chat.UpdateFromMessage(message, m.transport) 5037 if err != nil { 5038 return nil, err 5039 } 5040 5041 err = m.persistence.SaveMessages([]*common.Message{message}) 5042 if err != nil { 5043 return nil, err 5044 } 5045 5046 return m.addMessagesAndChat(chat, []*common.Message{message}, &response) 5047 } 5048 5049 func (m *Messenger) SendTransaction(ctx context.Context, chatID, value, contract, transactionHash string, signature []byte) (*MessengerResponse, error) { 5050 var response MessengerResponse 5051 5052 // A valid added chat is required. 5053 chat, ok := m.allChats.Load(chatID) 5054 if !ok { 5055 return nil, ErrChatNotFoundError 5056 } 5057 if chat.ChatType != ChatTypeOneToOne { 5058 return nil, errors.New("Need to be a one-to-one chat") 5059 } 5060 5061 message := common.NewMessage() 5062 err := extendMessageFromChat(message, chat, &m.identity.PublicKey, m.transport) 5063 if err != nil { 5064 return nil, err 5065 } 5066 5067 message.MessageType = protobuf.MessageType_ONE_TO_ONE 5068 message.ContentType = protobuf.ChatMessage_TRANSACTION_COMMAND 5069 message.LocalChatID = chatID 5070 5071 clock, timestamp := chat.NextClockAndTimestamp(m.transport) 5072 message.Clock = clock 5073 message.WhisperTimestamp = timestamp 5074 message.Seen = true 5075 message.Timestamp = timestamp 5076 message.Text = transactionSentTxt 5077 5078 request := &protobuf.SendTransaction{ 5079 Clock: message.Clock, 5080 TransactionHash: transactionHash, 5081 Signature: signature, 5082 ChatId: chatID, 5083 } 5084 encodedMessage, err := proto.Marshal(request) 5085 if err != nil { 5086 return nil, err 5087 } 5088 5089 resendType := common.ResendTypeRawMessage 5090 if chat.ChatType == ChatTypeOneToOne { 5091 resendType = common.ResendTypeDataSync 5092 } 5093 rawMessage, err := m.dispatchMessage(ctx, common.RawMessage{ 5094 LocalChatID: chat.ID, 5095 Payload: encodedMessage, 5096 MessageType: protobuf.ApplicationMetadataMessage_SEND_TRANSACTION, 5097 ResendType: resendType, 5098 }) 5099 5100 if err != nil { 5101 return nil, err 5102 } 5103 5104 message.ID = rawMessage.ID 5105 message.CommandParameters = &common.CommandParameters{ 5106 TransactionHash: transactionHash, 5107 Value: value, 5108 Contract: contract, 5109 Signature: signature, 5110 CommandState: common.CommandStateTransactionSent, 5111 } 5112 5113 err = message.PrepareContent(common.PubkeyToHex(&m.identity.PublicKey)) 5114 if err != nil { 5115 return nil, err 5116 } 5117 5118 err = chat.UpdateFromMessage(message, m.transport) 5119 if err != nil { 5120 return nil, err 5121 } 5122 5123 err = m.persistence.SaveMessages([]*common.Message{message}) 5124 if err != nil { 5125 return nil, err 5126 } 5127 5128 return m.addMessagesAndChat(chat, []*common.Message{message}, &response) 5129 } 5130 5131 func (m *Messenger) ValidateTransactions(ctx context.Context, addresses []types.Address) (*MessengerResponse, error) { 5132 if m.verifyTransactionClient == nil { 5133 return nil, nil 5134 } 5135 5136 logger := m.logger.With(zap.String("site", "ValidateTransactions")) 5137 logger.Debug("Validating transactions") 5138 txs, err := m.persistence.TransactionsToValidate() 5139 if err != nil { 5140 logger.Error("Error pulling", zap.Error(err)) 5141 return nil, err 5142 } 5143 logger.Debug("Txs", zap.Int("count", len(txs)), zap.Any("txs", txs)) 5144 var response MessengerResponse 5145 validator := NewTransactionValidator(addresses, m.persistence, m.verifyTransactionClient, m.logger) 5146 responses, err := validator.ValidateTransactions(ctx) 5147 if err != nil { 5148 logger.Error("Error validating", zap.Error(err)) 5149 return nil, err 5150 } 5151 for _, validationResult := range responses { 5152 var message *common.Message 5153 chatID := contactIDFromPublicKey(validationResult.Transaction.From) 5154 chat, ok := m.allChats.Load(chatID) 5155 if !ok { 5156 chat = OneToOneFromPublicKey(validationResult.Transaction.From, m.transport) 5157 } 5158 if validationResult.Message != nil { 5159 message = validationResult.Message 5160 } else { 5161 message = common.NewMessage() 5162 err := extendMessageFromChat(message, chat, &m.identity.PublicKey, m.transport) 5163 if err != nil { 5164 return nil, err 5165 } 5166 } 5167 5168 message.MessageType = protobuf.MessageType_ONE_TO_ONE 5169 message.ContentType = protobuf.ChatMessage_TRANSACTION_COMMAND 5170 message.LocalChatID = chatID 5171 message.OutgoingStatus = "" 5172 5173 clock, timestamp := chat.NextClockAndTimestamp(m.transport) 5174 message.Clock = clock 5175 message.Timestamp = timestamp 5176 message.WhisperTimestamp = timestamp 5177 message.Text = "Transaction received" 5178 message.Seen = false 5179 5180 message.ID = validationResult.Transaction.MessageID 5181 if message.CommandParameters == nil { 5182 message.CommandParameters = &common.CommandParameters{} 5183 } else { 5184 message.CommandParameters = validationResult.Message.CommandParameters 5185 } 5186 5187 message.CommandParameters.Value = validationResult.Value 5188 message.CommandParameters.Contract = validationResult.Contract 5189 message.CommandParameters.Address = validationResult.Address 5190 message.CommandParameters.CommandState = common.CommandStateTransactionSent 5191 message.CommandParameters.TransactionHash = validationResult.Transaction.TransactionHash 5192 5193 err = message.PrepareContent(common.PubkeyToHex(&m.identity.PublicKey)) 5194 if err != nil { 5195 return nil, err 5196 } 5197 5198 err = chat.UpdateFromMessage(message, m.transport) 5199 if err != nil { 5200 return nil, err 5201 } 5202 5203 if len(message.CommandParameters.ID) != 0 { 5204 // Hide previous message 5205 previousMessage, err := m.persistence.MessageByCommandID(chatID, message.CommandParameters.ID) 5206 if err != nil && err != common.ErrRecordNotFound { 5207 return nil, err 5208 } 5209 5210 if previousMessage != nil { 5211 err = m.persistence.HideMessage(previousMessage.ID) 5212 if err != nil { 5213 return nil, err 5214 } 5215 message.Replace = previousMessage.ID 5216 } 5217 } 5218 5219 response.AddMessage(message) 5220 m.allChats.Store(chat.ID, chat) 5221 response.AddChat(chat) 5222 5223 contact, err := m.getOrBuildContactFromMessage(message) 5224 if err != nil { 5225 return nil, err 5226 } 5227 5228 notificationsEnabled, err := m.settings.GetNotificationsEnabled() 5229 if err != nil { 5230 return nil, err 5231 } 5232 5233 profilePicturesVisibility, err := m.settings.GetProfilePicturesVisibility() 5234 if err != nil { 5235 return nil, err 5236 } 5237 5238 if notificationsEnabled { 5239 notification, err := NewMessageNotification(message.ID, message, chat, contact, m.ResolvePrimaryName, profilePicturesVisibility) 5240 if err != nil { 5241 return nil, err 5242 } 5243 response.AddNotification(notification) 5244 } 5245 5246 } 5247 5248 if len(response.messages) > 0 { 5249 err = m.SaveMessages(response.Messages()) 5250 if err != nil { 5251 return nil, err 5252 } 5253 } 5254 return &response, nil 5255 } 5256 5257 // pullMessagesAndResponsesFromDB pulls all the messages and the one that have 5258 // been replied to from the database 5259 func (m *Messenger) pullMessagesAndResponsesFromDB(messages []*common.Message) ([]*common.Message, error) { 5260 var messageIDs []string 5261 for _, message := range messages { 5262 messageIDs = append(messageIDs, message.ID) 5263 if len(message.ResponseTo) != 0 { 5264 messageIDs = append(messageIDs, message.ResponseTo) 5265 } 5266 5267 } 5268 // We pull from the database all the messages & replies involved, 5269 // so we let the db build the correct messages 5270 return m.persistence.MessagesByIDs(messageIDs) 5271 } 5272 5273 func (m *Messenger) SignMessage(message string) ([]byte, error) { 5274 hash := crypto.TextHash([]byte(message)) 5275 return crypto.Sign(hash, m.identity) 5276 } 5277 5278 func (m *Messenger) CreateCommunityTokenDeploymentSignature(ctx context.Context, chainID uint64, addressFrom string, communityID string) ([]byte, error) { 5279 return m.communitiesManager.CreateCommunityTokenDeploymentSignature(ctx, chainID, addressFrom, communityID) 5280 } 5281 5282 func (m *Messenger) getTimesource() common.TimeSource { 5283 return m.transport 5284 } 5285 5286 func (m *Messenger) GetCurrentTimeInMillis() uint64 { 5287 return m.getTimesource().GetCurrentTime() 5288 } 5289 5290 // AddPushNotificationsServer adds a push notification server 5291 func (m *Messenger) AddPushNotificationsServer(ctx context.Context, publicKey *ecdsa.PublicKey, serverType pushnotificationclient.ServerType) error { 5292 if m.pushNotificationClient == nil { 5293 return errors.New("push notification client not enabled") 5294 } 5295 return m.pushNotificationClient.AddPushNotificationsServer(publicKey, serverType) 5296 } 5297 5298 // RemovePushNotificationServer removes a push notification server 5299 func (m *Messenger) RemovePushNotificationServer(ctx context.Context, publicKey *ecdsa.PublicKey) error { 5300 if m.pushNotificationClient == nil { 5301 return errors.New("push notification client not enabled") 5302 } 5303 return m.pushNotificationClient.RemovePushNotificationServer(publicKey) 5304 } 5305 5306 // UnregisterFromPushNotifications unregister from any server 5307 func (m *Messenger) UnregisterFromPushNotifications(ctx context.Context) error { 5308 return m.pushNotificationClient.Unregister() 5309 } 5310 5311 // DisableSendingPushNotifications signals the client not to send any push notification 5312 func (m *Messenger) DisableSendingPushNotifications() error { 5313 if m.pushNotificationClient == nil { 5314 return errors.New("push notification client not enabled") 5315 } 5316 m.pushNotificationClient.DisableSending() 5317 return nil 5318 } 5319 5320 // EnableSendingPushNotifications signals the client to send push notifications 5321 func (m *Messenger) EnableSendingPushNotifications() error { 5322 if m.pushNotificationClient == nil { 5323 return errors.New("push notification client not enabled") 5324 } 5325 m.pushNotificationClient.EnableSending() 5326 return nil 5327 } 5328 5329 func (m *Messenger) pushNotificationOptions() *pushnotificationclient.RegistrationOptions { 5330 var contactIDs []*ecdsa.PublicKey 5331 var mutedChatIDs []string 5332 var publicChatIDs []string 5333 var blockedChatIDs []string 5334 5335 m.allContacts.Range(func(contactID string, contact *Contact) (shouldContinue bool) { 5336 if contact.added() && !contact.Blocked { 5337 pk, err := contact.PublicKey() 5338 if err != nil { 5339 m.logger.Warn("could not parse contact public key") 5340 return true 5341 } 5342 contactIDs = append(contactIDs, pk) 5343 } else if contact.Blocked { 5344 blockedChatIDs = append(blockedChatIDs, contact.ID) 5345 } 5346 return true 5347 }) 5348 5349 m.allChats.Range(func(chatID string, chat *Chat) (shouldContinue bool) { 5350 if chat.Muted { 5351 mutedChatIDs = append(mutedChatIDs, chat.ID) 5352 return true 5353 } 5354 if chat.Active && (chat.Public() || chat.CommunityChat()) { 5355 publicChatIDs = append(publicChatIDs, chat.ID) 5356 } 5357 return true 5358 }) 5359 5360 return &pushnotificationclient.RegistrationOptions{ 5361 ContactIDs: contactIDs, 5362 MutedChatIDs: mutedChatIDs, 5363 PublicChatIDs: publicChatIDs, 5364 BlockedChatIDs: blockedChatIDs, 5365 } 5366 } 5367 5368 // RegisterForPushNotification register deviceToken with any push notification server enabled 5369 func (m *Messenger) RegisterForPushNotifications(ctx context.Context, deviceToken, apnTopic string, tokenType protobuf.PushNotificationRegistration_TokenType) error { 5370 if m.pushNotificationClient == nil { 5371 return errors.New("push notification client not enabled") 5372 } 5373 m.mutex.Lock() 5374 defer m.mutex.Unlock() 5375 5376 err := m.pushNotificationClient.Register(deviceToken, apnTopic, tokenType, m.pushNotificationOptions()) 5377 if err != nil { 5378 m.logger.Error("failed to register for push notifications", zap.Error(err)) 5379 return err 5380 } 5381 return nil 5382 } 5383 5384 // RegisteredForPushNotifications returns whether we successfully registered with all the servers 5385 func (m *Messenger) RegisteredForPushNotifications() (bool, error) { 5386 if m.pushNotificationClient == nil { 5387 return false, errors.New("no push notification client") 5388 } 5389 return m.pushNotificationClient.Registered() 5390 } 5391 5392 // EnablePushNotificationsFromContactsOnly is used to indicate that we want to received push notifications only from contacts 5393 func (m *Messenger) EnablePushNotificationsFromContactsOnly() error { 5394 if m.pushNotificationClient == nil { 5395 return errors.New("no push notification client") 5396 } 5397 m.mutex.Lock() 5398 defer m.mutex.Unlock() 5399 5400 return m.pushNotificationClient.EnablePushNotificationsFromContactsOnly(m.pushNotificationOptions()) 5401 } 5402 5403 // DisablePushNotificationsFromContactsOnly is used to indicate that we want to received push notifications from anyone 5404 func (m *Messenger) DisablePushNotificationsFromContactsOnly() error { 5405 if m.pushNotificationClient == nil { 5406 return errors.New("no push notification client") 5407 } 5408 m.mutex.Lock() 5409 defer m.mutex.Unlock() 5410 5411 return m.pushNotificationClient.DisablePushNotificationsFromContactsOnly(m.pushNotificationOptions()) 5412 } 5413 5414 // EnablePushNotificationsBlockMentions is used to indicate that we dont want to received push notifications for mentions 5415 func (m *Messenger) EnablePushNotificationsBlockMentions() error { 5416 if m.pushNotificationClient == nil { 5417 return errors.New("no push notification client") 5418 } 5419 m.mutex.Lock() 5420 defer m.mutex.Unlock() 5421 5422 return m.pushNotificationClient.EnablePushNotificationsBlockMentions(m.pushNotificationOptions()) 5423 } 5424 5425 // DisablePushNotificationsBlockMentions is used to indicate that we want to received push notifications for mentions 5426 func (m *Messenger) DisablePushNotificationsBlockMentions() error { 5427 if m.pushNotificationClient == nil { 5428 return errors.New("no push notification client") 5429 } 5430 m.mutex.Lock() 5431 defer m.mutex.Unlock() 5432 5433 return m.pushNotificationClient.DisablePushNotificationsBlockMentions(m.pushNotificationOptions()) 5434 } 5435 5436 // GetPushNotificationsServers returns the servers used for push notifications 5437 func (m *Messenger) GetPushNotificationsServers() ([]*pushnotificationclient.PushNotificationServer, error) { 5438 if m.pushNotificationClient == nil { 5439 return nil, errors.New("no push notification client") 5440 } 5441 return m.pushNotificationClient.GetServers() 5442 } 5443 5444 // StartPushNotificationsServer initialize and start a push notification server, using the current messenger identity key 5445 func (m *Messenger) StartPushNotificationsServer() error { 5446 if m.pushNotificationServer == nil { 5447 pushNotificationServerPersistence := pushnotificationserver.NewSQLitePersistence(m.database) 5448 config := &pushnotificationserver.Config{ 5449 Enabled: true, 5450 Logger: m.logger, 5451 Identity: m.identity, 5452 } 5453 m.pushNotificationServer = pushnotificationserver.New(config, pushNotificationServerPersistence, m.sender) 5454 } 5455 5456 return m.pushNotificationServer.Start() 5457 } 5458 5459 // StopPushNotificationServer stops the push notification server if running 5460 func (m *Messenger) StopPushNotificationsServer() error { 5461 m.pushNotificationServer = nil 5462 return nil 5463 } 5464 5465 func generateAliasAndIdenticon(pk string) (string, string, error) { 5466 identicon, err := identicon.GenerateBase64(pk) 5467 if err != nil { 5468 return "", "", err 5469 } 5470 5471 name, err := alias.GenerateFromPublicKeyString(pk) 5472 if err != nil { 5473 return "", "", err 5474 } 5475 return name, identicon, nil 5476 5477 } 5478 5479 func (m *Messenger) encodeChatEntity(chat *Chat, message common.ChatEntity) ([]byte, error) { 5480 var encodedMessage []byte 5481 var err error 5482 l := m.logger.With(zap.String("site", "Send"), zap.String("chatID", chat.ID)) 5483 5484 switch chat.ChatType { 5485 case ChatTypeOneToOne: 5486 l.Debug("sending private message") 5487 message.SetMessageType(protobuf.MessageType_ONE_TO_ONE) 5488 encodedMessage, err = proto.Marshal(message.GetProtobuf()) 5489 if err != nil { 5490 return nil, err 5491 } 5492 5493 case ChatTypePublic, ChatTypeProfile: 5494 l.Debug("sending public message", zap.String("chatName", chat.Name)) 5495 message.SetMessageType(protobuf.MessageType_PUBLIC_GROUP) 5496 encodedMessage, err = proto.Marshal(message.GetProtobuf()) 5497 if err != nil { 5498 return nil, err 5499 } 5500 5501 case ChatTypeCommunityChat: 5502 l.Debug("sending community chat message", zap.String("chatName", chat.Name)) 5503 message.SetMessageType(protobuf.MessageType_COMMUNITY_CHAT) 5504 encodedMessage, err = proto.Marshal(message.GetProtobuf()) 5505 if err != nil { 5506 return nil, err 5507 } 5508 5509 case ChatTypePrivateGroupChat: 5510 message.SetMessageType(protobuf.MessageType_PRIVATE_GROUP) 5511 l.Debug("sending group message", zap.String("chatName", chat.Name)) 5512 if !message.WrapGroupMessage() { 5513 encodedMessage, err = proto.Marshal(message.GetProtobuf()) 5514 if err != nil { 5515 return nil, err 5516 } 5517 } else { 5518 5519 group, err := newProtocolGroupFromChat(chat) 5520 if err != nil { 5521 return nil, err 5522 } 5523 5524 // NOTE(cammellos): Disabling for now since the optimiziation is not 5525 // applicable anymore after we changed group rules to allow 5526 // anyone to change group details 5527 encodedMessage, err = m.sender.EncodeMembershipUpdate(group, message) 5528 if err != nil { 5529 return nil, err 5530 } 5531 } 5532 5533 default: 5534 return nil, errors.New("chat type not supported") 5535 } 5536 5537 return encodedMessage, nil 5538 } 5539 5540 func (m *Messenger) getOrBuildContactFromMessage(msg *common.Message) (*Contact, error) { 5541 if c, ok := m.allContacts.Load(msg.From); ok { 5542 return c, nil 5543 } 5544 5545 senderPubKey, err := msg.GetSenderPubKey() 5546 if err != nil { 5547 return nil, err 5548 } 5549 senderID := contactIDFromPublicKey(senderPubKey) 5550 c, err := buildContact(senderID, senderPubKey) 5551 if err != nil { 5552 return nil, err 5553 } 5554 5555 // TODO(samyoul) remove storing of an updated reference pointer? 5556 m.allContacts.Store(msg.From, c) 5557 return c, nil 5558 } 5559 5560 func (m *Messenger) BloomFilter() []byte { 5561 return m.transport.BloomFilter() 5562 } 5563 5564 func (m *Messenger) getSettings() (settings.Settings, error) { 5565 sDB, err := accounts.NewDB(m.database) 5566 if err != nil { 5567 return settings.Settings{}, err 5568 } 5569 return sDB.GetSettings() 5570 } 5571 5572 func (m *Messenger) getEnsUsernameDetails() (result []*ensservice.UsernameDetail, err error) { 5573 db := ensservice.NewEnsDatabase(m.database) 5574 return db.GetEnsUsernames(nil) 5575 } 5576 5577 func ToVerificationRequest(message *protobuf.SyncVerificationRequest) *verification.Request { 5578 return &verification.Request{ 5579 From: message.From, 5580 To: message.To, 5581 Challenge: message.Challenge, 5582 Response: message.Response, 5583 RequestedAt: message.RequestedAt, 5584 RepliedAt: message.RepliedAt, 5585 RequestStatus: verification.RequestStatus(message.VerificationStatus), 5586 } 5587 } 5588 5589 func (m *Messenger) HandleSyncVerificationRequest(state *ReceivedMessageState, message *protobuf.SyncVerificationRequest, statusMessage *v1protocol.StatusMessage) error { 5590 verificationRequest := ToVerificationRequest(message) 5591 5592 err := m.verificationDatabase.SaveVerificationRequest(verificationRequest) 5593 if err != nil { 5594 return err 5595 } 5596 5597 myPubKey := hexutil.Encode(crypto.FromECDSAPub(&m.identity.PublicKey)) 5598 5599 state.AllVerificationRequests = append(state.AllVerificationRequests, verificationRequest) 5600 5601 if message.From == myPubKey { // Verification requests we sent 5602 contact, ok := m.allContacts.Load(message.To) 5603 if !ok { 5604 m.logger.Info("contact not found") 5605 return nil 5606 } 5607 5608 contact.VerificationStatus = VerificationStatus(message.VerificationStatus) 5609 if err := m.persistence.SaveContact(contact, nil); err != nil { 5610 return err 5611 } 5612 5613 m.allContacts.Store(contact.ID, contact) 5614 state.ModifiedContacts.Store(contact.ID, true) 5615 5616 // TODO: create activity center notif 5617 5618 } 5619 // else { // Verification requests we received 5620 // // TODO: activity center notif 5621 //} 5622 5623 return nil 5624 } 5625 5626 func (m *Messenger) ImageServerURL() string { 5627 return m.httpServer.MakeImageServerURL() 5628 } 5629 5630 func (m *Messenger) myHexIdentity() string { 5631 return common.PubkeyToHex(&m.identity.PublicKey) 5632 } 5633 5634 func (m *Messenger) GetMentionsManager() *MentionManager { 5635 return m.mentionsManager 5636 } 5637 5638 func (m *Messenger) getOtherMessagesInAlbum(message *common.Message, chatID string) ([]*common.Message, error) { 5639 var connectedMessages []*common.Message 5640 // In case of Image messages, we need to delete all the images in the album 5641 if message.ContentType == protobuf.ChatMessage_IMAGE { 5642 image := message.GetImage() 5643 if image != nil && image.AlbumId != "" { 5644 messagesInTheAlbum, err := m.persistence.albumMessages(chatID, image.GetAlbumId()) 5645 if err != nil { 5646 return nil, err 5647 } 5648 connectedMessages = append(connectedMessages, messagesInTheAlbum...) 5649 return connectedMessages, nil 5650 } 5651 } 5652 return append(connectedMessages, message), nil 5653 } 5654 5655 func (m *Messenger) withChatClock(callback func(string, uint64) error) error { 5656 clock, chat := m.getLastClockWithRelatedChat() 5657 err := callback(chat.ID, clock) 5658 if err != nil { 5659 return err 5660 } 5661 chat.LastClockValue = clock 5662 return m.saveChat(chat) 5663 } 5664 5665 func (m *Messenger) syncDeleteForMeMessage(ctx context.Context, rawMessageDispatcher RawMessageHandler) error { 5666 deleteForMes, err := m.persistence.GetDeleteForMeMessages() 5667 if err != nil { 5668 return err 5669 } 5670 5671 return m.withChatClock(func(chatID string, _ uint64) error { 5672 for _, deleteForMe := range deleteForMes { 5673 encodedMessage, err2 := proto.Marshal(deleteForMe) 5674 if err2 != nil { 5675 return err2 5676 } 5677 rawMessage := common.RawMessage{ 5678 LocalChatID: chatID, 5679 Payload: encodedMessage, 5680 MessageType: protobuf.ApplicationMetadataMessage_SYNC_DELETE_FOR_ME_MESSAGE, 5681 ResendType: common.ResendTypeDataSync, 5682 } 5683 _, err2 = rawMessageDispatcher(ctx, rawMessage) 5684 if err2 != nil { 5685 return err2 5686 } 5687 } 5688 return nil 5689 }) 5690 } 5691 5692 func (m *Messenger) GetDeleteForMeMessages() ([]*protobuf.SyncDeleteForMeMessage, error) { 5693 return m.persistence.GetDeleteForMeMessages() 5694 } 5695 5696 func (m *Messenger) startCleanupLoop(name string, cleanupFunc func() error) { 5697 logger := m.logger.Named(name) 5698 5699 go func() { 5700 // Delay by a few minutes to minimize messenger's startup time 5701 var interval time.Duration = 5 * time.Minute 5702 for { 5703 select { 5704 case <-time.After(interval): 5705 // Set the regular interval after the first execution 5706 interval = 1 * time.Hour 5707 5708 err := cleanupFunc() 5709 if err != nil { 5710 logger.Error("failed to cleanup", zap.Error(err)) 5711 } 5712 5713 case <-m.quit: 5714 return 5715 } 5716 } 5717 }() 5718 } 5719 5720 func (m *Messenger) startMessageSegmentsCleanupLoop() { 5721 m.startCleanupLoop("messageSegmentsCleanupLoop", m.sender.CleanupSegments) 5722 } 5723 5724 func (m *Messenger) startHashRatchetEncryptedMessagesCleanupLoop() { 5725 m.startCleanupLoop("hashRatchetEncryptedMessagesCleanupLoop", m.sender.CleanupHashRatchetEncryptedMessages) 5726 } 5727 5728 func (m *Messenger) FindStatusMessageIDForBridgeMessageID(bridgeMessageID string) (string, error) { 5729 return m.persistence.FindStatusMessageIDForBridgeMessageID(bridgeMessageID) 5730 }