2019-11-21 16:19:22 +00:00
package protocol
2019-07-17 22:25:42 +00:00
import (
2020-12-10 10:12:51 +00:00
"bytes"
2019-07-17 22:25:42 +00:00
"context"
"crypto/ecdsa"
2020-07-14 14:07:19 +00:00
"database/sql"
2020-08-07 13:49:37 +00:00
"encoding/hex"
2020-12-02 14:00:28 +00:00
"fmt"
2020-05-13 13:16:17 +00:00
"io/ioutil"
2020-12-15 14:43:41 +00:00
"math"
2019-12-02 15:34:05 +00:00
"math/rand"
2020-05-13 13:16:17 +00:00
"os"
2020-07-07 13:55:24 +00:00
"reflect"
2019-12-02 15:34:05 +00:00
"sync"
2019-07-17 22:25:42 +00:00
"time"
"github.com/pkg/errors"
2019-09-02 09:29:06 +00:00
"go.uber.org/zap"
2019-07-17 22:25:42 +00:00
2020-12-02 14:00:28 +00:00
"github.com/davecgh/go-spew/spew"
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
"github.com/golang/protobuf/proto"
2020-01-02 09:10:19 +00:00
2021-03-31 16:23:45 +00:00
"github.com/status-im/status-go/appdatabase"
2021-09-01 12:02:18 +00:00
"github.com/status-im/status-go/appmetrics"
2021-05-14 10:55:42 +00:00
"github.com/status-im/status-go/connection"
2019-11-23 17:57:05 +00:00
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
2020-11-05 17:35:20 +00:00
userimage "github.com/status-im/status-go/images"
2020-11-25 00:34:32 +00:00
"github.com/status-im/status-go/multiaccounts"
2021-03-31 16:23:45 +00:00
"github.com/status-im/status-go/multiaccounts/accounts"
2021-09-01 12:02:18 +00:00
"github.com/status-im/status-go/protocol/anonmetrics"
2020-06-17 18:55:49 +00:00
"github.com/status-im/status-go/protocol/audio"
2020-07-22 07:41:40 +00:00
"github.com/status-im/status-go/protocol/common"
2020-11-18 09:16:51 +00:00
"github.com/status-im/status-go/protocol/communities"
2019-11-21 16:19:22 +00:00
"github.com/status-im/status-go/protocol/encryption"
"github.com/status-im/status-go/protocol/encryption/multidevice"
"github.com/status-im/status-go/protocol/encryption/sharedsecret"
2021-01-11 10:32:51 +00:00
"github.com/status-im/status-go/protocol/ens"
2019-11-21 16:19:22 +00:00
"github.com/status-im/status-go/protocol/identity/alias"
"github.com/status-im/status-go/protocol/identity/identicon"
2020-05-13 13:16:17 +00:00
"github.com/status-im/status-go/protocol/images"
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
"github.com/status-im/status-go/protocol/protobuf"
2020-07-22 07:41:40 +00:00
"github.com/status-im/status-go/protocol/pushnotificationclient"
"github.com/status-im/status-go/protocol/pushnotificationserver"
2019-11-21 16:19:22 +00:00
"github.com/status-im/status-go/protocol/sqlite"
2020-01-13 19:17:30 +00:00
"github.com/status-im/status-go/protocol/transport"
2019-11-21 16:19:22 +00:00
v1protocol "github.com/status-im/status-go/protocol/v1"
2021-01-14 22:15:13 +00:00
"github.com/status-im/status-go/services/mailservers"
2019-07-17 22:25:42 +00:00
)
2021-04-22 13:36:18 +00:00
//todo: kozieiev: get rid of wakutransp word
2020-12-15 16:29:44 +00:00
type chatContext string
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
2020-12-15 16:29:44 +00:00
const (
PubKeyStringLength = 132
transactionSentTxt = "Transaction sent"
publicChat chatContext = "public-chat"
privateChat chatContext = "private-chat"
)
2020-02-10 11:22:37 +00:00
2020-12-15 14:43:41 +00:00
const emojiResendMinDelay = 30
const emojiResendMaxCount = 3
2020-11-18 09:16:51 +00:00
var communityAdvertiseIntervalSecond int64 = 60 * 60
2021-01-08 15:21:25 +00:00
// messageCacheIntervalMs is how long we should keep processed messages in the cache, in ms
var messageCacheIntervalMs uint64 = 1000 * 60 * 60 * 48
2019-07-17 22:25:42 +00:00
// Messenger is a entity managing chats and messages.
// It acts as a bridge between the application and encryption
// layers.
// It needs to expose an interface to manage installations
// because installations are managed by the user.
// Similarly, it needs to expose an interface to manage
// mailservers because they can also be managed by the user.
type Messenger struct {
2019-12-02 15:34:05 +00:00
node types . Node
2020-07-31 09:46:38 +00:00
config * config
2019-12-02 15:34:05 +00:00
identity * ecdsa . PrivateKey
persistence * sqlitePersistence
2021-04-22 13:36:18 +00:00
transport * transport . Transport
2019-12-02 15:34:05 +00:00
encryptor * encryption . Protocol
2021-06-23 14:13:48 +00:00
sender * common . MessageSender
2021-01-11 10:32:51 +00:00
ensVerifier * ens . Verifier
2021-09-01 12:02:18 +00:00
anonMetricsClient * anonmetrics . Client
anonMetricsServer * anonmetrics . Server
2020-07-22 07:41:40 +00:00
pushNotificationClient * pushnotificationclient . Client
pushNotificationServer * pushnotificationserver . Server
2020-11-18 09:16:51 +00:00
communitiesManager * communities . Manager
2019-12-02 15:34:05 +00:00
logger * zap . Logger
2020-01-10 18:59:01 +00:00
verifyTransactionClient EthClient
2020-07-06 08:54:22 +00:00
featureFlags common . FeatureFlags
2019-07-26 07:17:29 +00:00
shutdownTasks [ ] func ( ) error
2020-12-21 08:41:50 +00:00
shouldPublishContactCode bool
2021-03-29 15:41:30 +00:00
systemMessagesTranslations * systemMessageTranslationsMap
allChats * chatMap
allContacts * contactMap
allInstallations * installationMap
modifiedInstallations * stringBoolMap
2020-01-10 18:59:01 +00:00
installationID string
2020-07-07 09:00:04 +00:00
mailserver [ ] byte
2020-07-14 14:07:19 +00:00
database * sql . DB
2020-11-24 13:13:46 +00:00
multiAccounts * multiaccounts . Database
2021-03-31 16:23:45 +00:00
settings * accounts . Database
2020-12-09 14:03:43 +00:00
account * multiaccounts . Account
2021-01-14 22:15:13 +00:00
mailserversDatabase * mailservers . Database
2020-08-27 12:38:59 +00:00
quit chan struct { }
2021-04-19 12:09:46 +00:00
requestedCommunities map [ string ] * transport . Filter
2021-05-14 10:55:42 +00:00
connectionState connection . State
2020-01-10 18:59:01 +00:00
2021-03-29 15:41:30 +00:00
// TODO(samyoul) Determine if/how the remaining usage of this mutex can be removed
2020-01-10 18:59:01 +00:00
mutex sync . Mutex
2019-07-17 22:25:42 +00:00
}
2019-07-30 06:14:13 +00:00
type dbConfig struct {
dbPath string
dbKey string
}
2020-12-15 14:43:41 +00:00
type EnvelopeEventsInterceptor struct {
EnvelopeEventsHandler transport . EnvelopeEventsHandler
Messenger * Messenger
}
// EnvelopeSent triggered when envelope delivered at least to 1 peer.
func ( interceptor EnvelopeEventsInterceptor ) EnvelopeSent ( identifiers [ ] [ ] byte ) {
if interceptor . Messenger != nil {
var ids [ ] string
for _ , identifierBytes := range identifiers {
ids = append ( ids , types . EncodeHex ( identifierBytes ) )
}
err := interceptor . Messenger . processSentMessages ( ids )
if err != nil {
interceptor . Messenger . logger . Info ( "Messenger failed to process sent messages" , zap . Error ( err ) )
}
}
interceptor . EnvelopeEventsHandler . EnvelopeSent ( identifiers )
}
// EnvelopeExpired triggered when envelope is expired but wasn't delivered to any peer.
func ( interceptor EnvelopeEventsInterceptor ) EnvelopeExpired ( identifiers [ ] [ ] byte , err error ) {
//we don't track expired events in Messenger, so just redirect to handler
interceptor . EnvelopeEventsHandler . EnvelopeExpired ( identifiers , err )
}
// MailServerRequestCompleted triggered when the mailserver sends a message to notify that the request has been completed
func ( interceptor EnvelopeEventsInterceptor ) MailServerRequestCompleted ( requestID types . Hash , lastEnvelopeHash types . Hash , cursor [ ] byte , err error ) {
//we don't track mailserver requests in Messenger, so just redirect to handler
interceptor . EnvelopeEventsHandler . MailServerRequestCompleted ( requestID , lastEnvelopeHash , cursor , err )
}
// MailServerRequestExpired triggered when the mailserver request expires
func ( interceptor EnvelopeEventsInterceptor ) MailServerRequestExpired ( hash types . Hash ) {
//we don't track mailserver requests in Messenger, so just redirect to handler
interceptor . EnvelopeEventsHandler . MailServerRequestExpired ( hash )
}
2019-07-17 22:25:42 +00:00
func NewMessenger (
identity * ecdsa . PrivateKey ,
2019-11-23 17:57:05 +00:00
node types . Node ,
2019-07-17 22:25:42 +00:00
installationID string ,
opts ... Option ,
) ( * Messenger , error ) {
var messenger * Messenger
c := config { }
for _ , opt := range opts {
if err := opt ( & c ) ; err != nil {
return nil , err
}
}
logger := c . logger
if c . logger == nil {
var err error
if logger , err = zap . NewDevelopment ( ) ; err != nil {
return nil , errors . Wrap ( err , "failed to create a logger" )
}
}
2019-12-02 15:34:05 +00:00
if c . systemMessagesTranslations == nil {
c . systemMessagesTranslations = defaultSystemMessagesTranslations
}
2019-07-30 06:14:13 +00:00
// Configure the database.
database := c . db
2019-09-26 09:26:33 +00:00
if c . db == nil && c . dbConfig == ( dbConfig { } ) {
return nil , errors . New ( "database instance or database path needs to be provided" )
}
if c . db == nil {
2019-07-30 06:14:13 +00:00
logger . Info ( "opening a database" , zap . String ( "dbPath" , c . dbConfig . dbPath ) )
2019-09-26 09:26:33 +00:00
var err error
2021-03-31 16:23:45 +00:00
database , err = appdatabase . InitializeDB ( c . dbConfig . dbPath , c . dbConfig . dbKey )
2019-07-30 06:14:13 +00:00
if err != nil {
return nil , errors . Wrap ( err , "failed to initialize database from the db config" )
}
}
2019-09-26 09:26:33 +00:00
2019-07-30 06:14:13 +00:00
// Apply migrations for all components.
2020-01-13 19:17:30 +00:00
err := sqlite . Migrate ( database )
2019-07-30 06:14:13 +00:00
if err != nil {
return nil , errors . Wrap ( err , "failed to apply migrations" )
2019-07-17 22:25:42 +00:00
}
2019-07-30 06:14:13 +00:00
// Initialize transport layer.
2021-06-16 20:19:45 +00:00
var transp * transport . Transport
if waku , err := node . GetWaku ( nil ) ; err == nil && waku != nil {
transp , err = transport . NewTransport (
waku ,
identity ,
database ,
"waku_keys" ,
nil ,
c . envelopesMonitorConfig ,
logger ,
)
if err != nil {
return nil , errors . Wrap ( err , "failed to create Transport" )
}
} else {
logger . Info ( "failed to find Waku service; trying WakuV2" , zap . Error ( err ) )
wakuV2 , err := node . GetWakuV2 ( nil )
if err != nil || wakuV2 == nil {
return nil , errors . Wrap ( err , "failed to find Whisper and Waku V1/V2 services" )
}
transp , err = transport . NewTransport (
wakuV2 ,
identity ,
database ,
"wakuv2_keys" ,
nil ,
c . envelopesMonitorConfig ,
logger ,
)
if err != nil {
return nil , errors . Wrap ( err , "failed to create Transport" )
}
2019-07-17 22:25:42 +00:00
}
2019-07-30 06:14:13 +00:00
// Initialize encryption layer.
encryptionProtocol := encryption . New (
database ,
2019-07-17 22:25:42 +00:00
installationID ,
logger ,
)
2019-07-26 07:17:29 +00:00
2021-06-23 14:13:48 +00:00
sender , err := common . NewMessageSender (
2019-09-02 09:29:06 +00:00
identity ,
2019-08-27 12:04:15 +00:00
database ,
2019-09-02 09:29:06 +00:00
encryptionProtocol ,
2020-01-13 19:17:30 +00:00
transp ,
2019-08-29 06:33:46 +00:00
logger ,
2019-09-02 09:29:06 +00:00
c . featureFlags ,
2019-07-26 07:17:29 +00:00
)
2019-08-27 12:04:15 +00:00
if err != nil {
2021-06-23 14:13:48 +00:00
return nil , errors . Wrap ( err , "failed to create messageSender" )
2019-08-27 12:04:15 +00:00
}
2021-09-01 12:02:18 +00:00
// Initialise anon metrics client
var anonMetricsClient * anonmetrics . Client
if c . anonMetricsClientConfig != nil &&
c . anonMetricsClientConfig . ShouldSend &&
c . anonMetricsClientConfig . Active == anonmetrics . ActiveClientPhrase {
anonMetricsClient = anonmetrics . NewClient ( sender )
anonMetricsClient . Config = c . anonMetricsClientConfig
anonMetricsClient . Identity = identity
anonMetricsClient . DB = appmetrics . NewDB ( database )
anonMetricsClient . Logger = logger
}
// Initialise anon metrics server
var anonMetricsServer * anonmetrics . Server
if c . anonMetricsServerConfig != nil &&
c . anonMetricsServerConfig . Enabled &&
c . anonMetricsServerConfig . Active == anonmetrics . ActiveServerPhrase {
server , err := anonmetrics . NewServer ( c . anonMetricsServerConfig . PostgresURI )
if err != nil {
return nil , errors . Wrap ( err , "failed to create anonmetrics.Server" )
}
anonMetricsServer = server
anonMetricsServer . Config = c . anonMetricsServerConfig
anonMetricsServer . Logger = logger
}
2020-07-22 07:41:40 +00:00
// Initialize push notification server
var pushNotificationServer * pushnotificationserver . Server
2020-08-20 07:26:00 +00:00
if c . pushNotificationServerConfig != nil && c . pushNotificationServerConfig . Enabled {
2020-07-14 14:07:19 +00:00
c . pushNotificationServerConfig . Identity = identity
2020-07-22 07:41:40 +00:00
pushNotificationServerPersistence := pushnotificationserver . NewSQLitePersistence ( database )
2021-06-23 14:13:48 +00:00
pushNotificationServer = pushnotificationserver . New ( c . pushNotificationServerConfig , pushNotificationServerPersistence , sender )
2020-07-06 08:54:22 +00:00
}
2020-07-22 07:41:40 +00:00
// Initialize push notification client
pushNotificationClientPersistence := pushnotificationclient . NewPersistence ( database )
2020-07-15 12:25:01 +00:00
pushNotificationClientConfig := c . pushNotificationClientConfig
if pushNotificationClientConfig == nil {
2020-07-22 07:41:40 +00:00
pushNotificationClientConfig = & pushnotificationclient . Config { }
2020-07-07 13:55:24 +00:00
}
2020-07-15 12:25:01 +00:00
2021-03-09 12:48:15 +00:00
sqlitePersistence := NewSQLitePersistence ( database )
2020-07-22 07:41:40 +00:00
// Overriding until we handle different identities
2020-07-15 12:25:01 +00:00
pushNotificationClientConfig . Identity = identity
pushNotificationClientConfig . Logger = logger
pushNotificationClientConfig . InstallationID = installationID
2021-06-23 14:13:48 +00:00
pushNotificationClient := pushnotificationclient . New ( pushNotificationClientPersistence , pushNotificationClientConfig , sender , sqlitePersistence )
2020-07-06 08:54:22 +00:00
2021-01-11 10:32:51 +00:00
ensVerifier := ens . New ( node , logger , transp , database , c . verifyENSURL , c . verifyENSContractAddress )
communitiesManager , err := communities . NewManager ( & identity . PublicKey , database , logger , ensVerifier )
2020-11-18 09:16:51 +00:00
if err != nil {
return nil , err
}
2021-04-07 12:57:14 +00:00
settings := accounts . NewDB ( database )
2019-07-17 22:25:42 +00:00
messenger = & Messenger {
2020-07-31 09:46:38 +00:00
config : & c ,
2019-11-23 17:57:05 +00:00
node : node ,
2019-07-17 22:25:42 +00:00
identity : identity ,
2021-03-09 12:48:15 +00:00
persistence : sqlitePersistence ,
2020-01-13 19:17:30 +00:00
transport : transp ,
2019-07-17 22:25:42 +00:00
encryptor : encryptionProtocol ,
2021-06-23 14:13:48 +00:00
sender : sender ,
2021-09-01 12:02:18 +00:00
anonMetricsClient : anonMetricsClient ,
anonMetricsServer : anonMetricsServer ,
2020-06-30 08:30:58 +00:00
pushNotificationClient : pushNotificationClient ,
2020-07-03 10:08:47 +00:00
pushNotificationServer : pushNotificationServer ,
2020-11-18 09:16:51 +00:00
communitiesManager : communitiesManager ,
2021-01-11 10:32:51 +00:00
ensVerifier : ensVerifier ,
2019-07-17 22:25:42 +00:00
featureFlags : c . featureFlags ,
2019-12-02 15:34:05 +00:00
systemMessagesTranslations : c . systemMessagesTranslations ,
2021-03-29 15:41:30 +00:00
allChats : new ( chatMap ) ,
allContacts : new ( contactMap ) ,
allInstallations : new ( installationMap ) ,
2020-01-10 18:59:01 +00:00
installationID : installationID ,
2021-03-29 15:41:30 +00:00
modifiedInstallations : new ( stringBoolMap ) ,
2020-01-10 18:59:01 +00:00
verifyTransactionClient : c . verifyTransactionClient ,
2020-07-14 14:07:19 +00:00
database : database ,
2020-11-24 13:13:46 +00:00
multiAccounts : c . multiAccount ,
2021-04-07 12:57:14 +00:00
settings : settings ,
2021-01-14 22:15:13 +00:00
mailserversDatabase : c . mailserversDatabase ,
2020-12-09 14:03:43 +00:00
account : c . account ,
2020-08-27 12:38:59 +00:00
quit : make ( chan struct { } ) ,
2021-04-19 12:09:46 +00:00
requestedCommunities : make ( map [ string ] * transport . Filter ) ,
2019-07-17 22:25:42 +00:00
shutdownTasks : [ ] func ( ) error {
2021-01-11 10:32:51 +00:00
ensVerifier . Stop ,
2020-07-10 13:26:06 +00:00
pushNotificationClient . Stop ,
2020-11-18 09:16:51 +00:00
communitiesManager . Stop ,
2020-07-31 09:08:09 +00:00
encryptionProtocol . Stop ,
2020-01-13 19:17:30 +00:00
transp . ResetFilters ,
transp . Stop ,
2021-06-23 14:13:48 +00:00
func ( ) error { sender . Stop ( ) ; return nil } ,
2019-07-17 22:25:42 +00:00
// Currently this often fails, seems like it's safe to ignore them
// https://github.com/uber-go/zap/issues/328
func ( ) error { _ = logger . Sync ; return nil } ,
2021-01-14 22:15:13 +00:00
database . Close ,
2019-07-17 22:25:42 +00:00
} ,
logger : logger ,
}
2021-09-01 12:02:18 +00:00
if anonMetricsClient != nil {
messenger . shutdownTasks = append ( messenger . shutdownTasks , anonMetricsClient . Stop )
}
if anonMetricsServer != nil {
messenger . shutdownTasks = append ( messenger . shutdownTasks , anonMetricsServer . Stop )
}
2020-12-15 14:43:41 +00:00
if c . envelopesMonitorConfig != nil {
interceptor := EnvelopeEventsInterceptor { c . envelopesMonitorConfig . EnvelopeEventsHandler , messenger }
err := messenger . transport . SetEnvelopeEventsHandler ( interceptor )
if err != nil {
logger . Info ( "Unable to set envelopes event handler" , zap . Error ( err ) )
}
}
2019-07-17 22:25:42 +00:00
return messenger , nil
}
2020-12-15 14:43:41 +00:00
func ( m * Messenger ) processSentMessages ( ids [ ] string ) error {
for _ , id := range ids {
rawMessage , err := m . persistence . RawMessageByID ( id )
if err != nil {
return errors . Wrapf ( err , "Can't get raw message with id %v" , id )
}
rawMessage . Sent = true
err = m . persistence . SaveRawMessage ( rawMessage )
if err != nil {
return errors . Wrapf ( err , "Can't save raw message marked as sent" )
}
}
return nil
}
2020-11-18 09:16:51 +00:00
func shouldResendEmojiReaction ( message * common . RawMessage , t common . TimeSource ) ( bool , error ) {
2020-12-15 14:43:41 +00:00
if message . MessageType != protobuf . ApplicationMetadataMessage_EMOJI_REACTION {
return false , errors . New ( "Should resend only emoji reactions" )
}
if message . Sent {
return false , errors . New ( "Should resend only non-sent messages" )
}
if message . SendCount > emojiResendMaxCount {
return false , nil
}
//exponential backoff depends on how many attempts to send message already made
backoff := uint64 ( math . Pow ( 2 , float64 ( message . SendCount - 1 ) ) ) * emojiResendMinDelay * uint64 ( time . Second )
backoffElapsed := t . GetCurrentTime ( ) > ( message . LastSent + backoff )
return backoffElapsed , nil
}
func ( m * Messenger ) resendExpiredEmojiReactions ( ) error {
ids , err := m . persistence . ExpiredEmojiReactionsIDs ( emojiResendMaxCount )
if err != nil {
return errors . Wrapf ( err , "Can't get expired reactions from db" )
}
for _ , id := range ids {
rawMessage , err := m . persistence . RawMessageByID ( id )
if err != nil {
return errors . Wrapf ( err , "Can't get raw message with id %v" , id )
}
if ok , err := shouldResendEmojiReaction ( rawMessage , m . getTimesource ( ) ) ; ok {
err = m . persistence . SaveRawMessage ( rawMessage )
if err != nil {
return errors . Wrapf ( err , "Can't save raw message marked as non-expired" )
}
err = m . reSendRawMessage ( context . Background ( ) , rawMessage . ID )
if err != nil {
return errors . Wrapf ( err , "Can't resend expired message with id %v" , rawMessage . ID )
}
} else {
return err
}
}
return nil
}
2021-01-14 22:15:13 +00:00
func ( m * Messenger ) Start ( ) ( * MessengerResponse , error ) {
2020-07-14 14:07:19 +00:00
m . logger . Info ( "starting messenger" , zap . String ( "identity" , types . EncodeHex ( crypto . FromECDSAPub ( & m . identity . PublicKey ) ) ) )
2020-07-10 13:26:06 +00:00
// Start push notification server
if m . pushNotificationServer != nil {
if err := m . pushNotificationServer . Start ( ) ; err != nil {
2021-01-14 22:15:13 +00:00
return nil , err
2020-07-10 13:26:06 +00:00
}
}
2020-07-22 07:41:40 +00:00
// Start push notification client
2020-07-10 13:26:06 +00:00
if m . pushNotificationClient != nil {
2020-08-18 15:07:48 +00:00
m . handlePushNotificationClientRegistrations ( m . pushNotificationClient . SubscribeToRegistrations ( ) )
2020-07-10 13:26:06 +00:00
if err := m . pushNotificationClient . Start ( ) ; err != nil {
2021-01-14 22:15:13 +00:00
return nil , err
2020-07-10 13:26:06 +00:00
}
}
2021-09-01 12:02:18 +00:00
// Start anonymous metrics client
if m . anonMetricsClient != nil {
if err := m . anonMetricsClient . Start ( ) ; err != nil {
return nil , err
}
}
2021-01-11 10:32:51 +00:00
ensSubscription := m . ensVerifier . Subscribe ( )
// Subscrbe
if err := m . ensVerifier . Start ( ) ; err != nil {
return nil , err
}
if err := m . communitiesManager . Start ( ) ; err != nil {
return nil , err
}
2020-07-31 12:22:05 +00:00
// set shared secret handles
2021-06-23 14:13:48 +00:00
m . sender . SetHandleSharedSecrets ( m . handleSharedSecrets )
2020-07-31 12:22:05 +00:00
2020-07-31 09:08:09 +00:00
subscriptions , err := m . encryptor . Start ( m . identity )
if err != nil {
2021-01-14 22:15:13 +00:00
return nil , err
2020-07-31 09:08:09 +00:00
}
2020-07-31 12:22:05 +00:00
// handle stored shared secrets
err = m . handleSharedSecrets ( subscriptions . SharedSecrets )
if err != nil {
2021-01-14 22:15:13 +00:00
return nil , err
2020-07-31 12:22:05 +00:00
}
2020-07-31 09:08:09 +00:00
m . handleEncryptionLayerSubscriptions ( subscriptions )
2020-11-18 09:16:51 +00:00
m . handleCommunitiesSubscription ( m . communitiesManager . Subscribe ( ) )
2020-08-27 12:38:59 +00:00
m . handleConnectionChange ( m . online ( ) )
2021-01-11 10:32:51 +00:00
m . handleENSVerificationSubscription ( ensSubscription )
2020-08-27 12:38:59 +00:00
m . watchConnectionChange ( )
2020-12-15 14:43:41 +00:00
m . watchExpiredEmojis ( )
2020-12-21 08:41:50 +00:00
m . watchIdentityImageChanges ( )
2021-07-22 17:41:49 +00:00
m . broadcastLatestUserStatus ( )
2021-01-14 22:15:13 +00:00
if err := m . cleanTopics ( ) ; err != nil {
return nil , err
}
2021-03-25 15:15:22 +00:00
response := & MessengerResponse { }
2021-01-14 22:15:13 +00:00
if m . mailserversDatabase != nil {
mailservers , err := m . mailserversDatabase . Mailservers ( )
if err != nil {
return nil , err
}
response . Mailservers = mailservers
}
return response , nil
}
// cleanTopics remove any topic that does not have a Listen flag set
func ( m * Messenger ) cleanTopics ( ) error {
if m . mailserversDatabase == nil {
return nil
}
var filters [ ] * transport . Filter
for _ , f := range m . transport . Filters ( ) {
if f . Listen && ! f . Ephemeral {
filters = append ( filters , f )
}
}
m . logger . Debug ( "keeping topics" , zap . Any ( "filters" , filters ) )
return m . mailserversDatabase . SetTopics ( filters )
2020-07-31 09:08:09 +00:00
}
2020-08-27 12:38:59 +00:00
// handle connection change is called each time we go from offline/online or viceversa
func ( m * Messenger ) handleConnectionChange ( online bool ) {
if online {
if m . pushNotificationClient != nil {
m . pushNotificationClient . Online ( )
}
2020-12-21 08:41:50 +00:00
if m . shouldPublishContactCode {
2021-01-25 13:49:13 +00:00
if err := m . publishContactCode ( ) ; err != nil {
2020-12-21 08:41:50 +00:00
m . logger . Error ( "could not publish on contact code" , zap . Error ( err ) )
return
}
m . shouldPublishContactCode = false
}
2020-08-27 12:38:59 +00:00
} else {
if m . pushNotificationClient != nil {
m . pushNotificationClient . Offline ( )
}
}
2021-01-11 10:32:51 +00:00
m . ensVerifier . SetOnline ( online )
2020-08-27 12:38:59 +00:00
}
func ( m * Messenger ) online ( ) bool {
2021-08-30 14:57:28 +00:00
switch m . transport . WakuVersion ( ) {
case 2 :
return m . transport . PeerCount ( ) > 0
default :
return m . node . PeersCount ( ) > 0
2021-07-21 19:02:50 +00:00
}
2020-08-27 12:38:59 +00:00
}
2020-08-18 15:07:48 +00:00
func ( m * Messenger ) buildContactCodeAdvertisement ( ) ( * protobuf . ContactCodeAdvertisement , error ) {
if m . pushNotificationClient == nil || ! m . pushNotificationClient . Enabled ( ) {
return nil , nil
}
m . logger . Debug ( "adding push notification info to contact code bundle" )
info , err := m . pushNotificationClient . MyPushNotificationQueryInfo ( )
if err != nil {
return nil , err
}
if len ( info ) == 0 {
return nil , nil
}
return & protobuf . ContactCodeAdvertisement {
PushNotificationInfo : info ,
} , nil
}
2021-01-25 13:49:13 +00:00
// publishContactCode sends a public message wrapped in the encryption
2020-07-31 12:22:05 +00:00
// layer, which will propagate our bundle
2021-01-25 13:49:13 +00:00
func ( m * Messenger ) publishContactCode ( ) error {
2020-07-31 13:46:27 +00:00
var payload [ ] byte
2020-08-18 15:07:48 +00:00
m . logger . Debug ( "sending contact code" )
contactCodeAdvertisement , err := m . buildContactCodeAdvertisement ( )
if err != nil {
m . logger . Error ( "could not build contact code advertisement" , zap . Error ( err ) )
}
2020-11-18 12:41:36 +00:00
if contactCodeAdvertisement == nil {
contactCodeAdvertisement = & protobuf . ContactCodeAdvertisement { }
}
2021-01-25 13:49:13 +00:00
err = m . attachChatIdentity ( contactCodeAdvertisement )
2020-11-05 17:35:20 +00:00
if err != nil {
return err
}
2020-11-18 12:41:36 +00:00
payload , err = proto . Marshal ( contactCodeAdvertisement )
if err != nil {
return err
2020-07-31 13:46:27 +00:00
}
2020-07-31 12:22:05 +00:00
contactCodeTopic := transport . ContactCodeTopic ( & m . identity . PublicKey )
rawMessage := common . RawMessage {
LocalChatID : contactCodeTopic ,
2020-08-18 15:07:48 +00:00
MessageType : protobuf . ApplicationMetadataMessage_CONTACT_CODE_ADVERTISEMENT ,
2020-07-31 13:46:27 +00:00
Payload : payload ,
2020-07-31 12:22:05 +00:00
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , 5 * time . Second )
defer cancel ( )
2021-06-23 14:13:48 +00:00
_ , err = m . sender . SendPublic ( ctx , contactCodeTopic , rawMessage )
2020-07-31 12:22:05 +00:00
if err != nil {
m . logger . Warn ( "failed to send a contact code" , zap . Error ( err ) )
}
return err
}
2020-11-05 17:35:20 +00:00
// contactCodeAdvertisement attaches a protobuf.ChatIdentity to the given protobuf.ContactCodeAdvertisement,
2020-11-09 15:16:36 +00:00
// if the `shouldPublish` conditions are met
2021-01-25 13:49:13 +00:00
func ( m * Messenger ) attachChatIdentity ( cca * protobuf . ContactCodeAdvertisement ) error {
2020-11-09 15:16:36 +00:00
contactCodeTopic := transport . ContactCodeTopic ( & m . identity . PublicKey )
shouldPublish , err := m . shouldPublishChatIdentity ( contactCodeTopic )
2020-11-05 17:35:20 +00:00
if err != nil {
return err
}
2021-01-25 13:49:13 +00:00
if ! shouldPublish {
return nil
}
2020-11-05 17:35:20 +00:00
2021-01-25 13:49:13 +00:00
cca . ChatIdentity , err = m . createChatIdentity ( privateChat )
if err != nil {
return err
}
2020-12-10 10:12:51 +00:00
2021-01-25 13:49:13 +00:00
img , err := m . multiAccounts . GetIdentityImage ( m . account . KeyUID , userimage . SmallDimName )
if err != nil {
return err
}
if img == nil {
return errors . New ( "could not find image" )
}
err = m . persistence . SaveWhenChatIdentityLastPublished ( contactCodeTopic , img . Hash ( ) )
if err != nil {
return err
2020-11-05 17:35:20 +00:00
}
return nil
}
2020-11-09 15:16:36 +00:00
// handleStandaloneChatIdentity sends a standalone ChatIdentity message to a public channel if the publish criteria is met
func ( m * Messenger ) handleStandaloneChatIdentity ( chat * Chat ) error {
if chat . ChatType != ChatTypePublic {
return nil
}
shouldPublishChatIdentity , err := m . shouldPublishChatIdentity ( chat . ID )
if err != nil {
return err
}
if ! shouldPublishChatIdentity {
return nil
}
2020-12-15 16:29:44 +00:00
ci , err := m . createChatIdentity ( publicChat )
2020-11-09 15:16:36 +00:00
if err != nil {
return err
}
2020-11-05 17:35:20 +00:00
2020-11-09 15:16:36 +00:00
payload , err := proto . Marshal ( ci )
2020-11-05 17:35:20 +00:00
if err != nil {
return err
}
2020-11-09 15:16:36 +00:00
rawMessage := common . RawMessage {
LocalChatID : chat . ID ,
MessageType : protobuf . ApplicationMetadataMessage_CHAT_IDENTITY ,
Payload : payload ,
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , 5 * time . Second )
defer cancel ( )
2021-06-23 14:13:48 +00:00
_ , err = m . sender . SendPublic ( ctx , chat . ID , rawMessage )
2020-11-09 15:16:36 +00:00
if err != nil {
return err
2020-11-05 17:35:20 +00:00
}
2020-12-10 10:12:51 +00:00
img , err := m . multiAccounts . GetIdentityImage ( m . account . KeyUID , userimage . SmallDimName )
if err != nil {
return err
}
if img == nil {
return errors . New ( "could not find image" )
}
err = m . persistence . SaveWhenChatIdentityLastPublished ( chat . ID , img . Hash ( ) )
2020-11-09 15:16:36 +00:00
if err != nil {
return err
}
return nil
}
// shouldPublishChatIdentity returns true if the last time the ChatIdentity was attached was more than 24 hours ago
2020-11-24 23:16:19 +00:00
func ( m * Messenger ) shouldPublishChatIdentity ( chatID string ) ( bool , error ) {
2021-01-25 13:49:13 +00:00
if m . account == nil {
return false , nil
}
2020-12-10 08:42:36 +00:00
// Check we have at least one image
2020-12-10 10:12:51 +00:00
img , err := m . multiAccounts . GetIdentityImage ( m . account . KeyUID , userimage . SmallDimName )
2020-12-10 08:42:36 +00:00
if err != nil {
return false , err
}
2020-12-10 10:12:51 +00:00
if img == nil {
2020-12-10 08:42:36 +00:00
return false , nil
}
2020-12-10 10:12:51 +00:00
lp , hash , err := m . persistence . GetWhenChatIdentityLastPublished ( chatID )
2020-11-09 15:16:36 +00:00
if err != nil {
return false , err
}
2020-12-10 10:12:51 +00:00
if ! bytes . Equal ( hash , img . Hash ( ) ) {
return true , nil
}
2020-12-16 18:28:34 +00:00
return lp == 0 || time . Now ( ) . Unix ( ) - lp > 24 * 60 * 60 , nil
2020-11-09 15:16:36 +00:00
}
// createChatIdentity creates a context based protobuf.ChatIdentity.
// context 'public-chat' will attach only the 'thumbnail' IdentityImage
2020-11-18 12:41:36 +00:00
// context 'private-chat' will attach all IdentityImage
2020-12-15 16:29:44 +00:00
func ( m * Messenger ) createChatIdentity ( context chatContext ) ( * protobuf . ChatIdentity , error ) {
2020-12-09 14:03:43 +00:00
m . logger . Info ( fmt . Sprintf ( "account keyUID '%s'" , m . account . KeyUID ) )
2020-12-02 14:00:28 +00:00
m . logger . Info ( fmt . Sprintf ( "context '%s'" , context ) )
2020-11-09 15:16:36 +00:00
ci := & protobuf . ChatIdentity {
2020-11-05 17:35:20 +00:00
Clock : m . transport . GetCurrentTime ( ) ,
EnsName : "" , // TODO add ENS name handling to dedicate PR
}
2021-02-09 13:58:21 +00:00
err := m . attachIdentityImagesToChatIdentity ( context , ci )
if err != nil {
return nil , err
}
return ci , nil
}
// adaptIdentityImageToProtobuf Adapts a images.IdentityImage to protobuf.IdentityImage
func ( m * Messenger ) adaptIdentityImageToProtobuf ( img * userimage . IdentityImage ) * protobuf . IdentityImage {
return & protobuf . IdentityImage {
Payload : img . Payload ,
SourceType : protobuf . IdentityImage_RAW_PAYLOAD , // TODO add ENS avatar handling to dedicated PR
ImageType : images . ImageType ( img . Payload ) ,
}
}
func ( m * Messenger ) attachIdentityImagesToChatIdentity ( context chatContext , ci * protobuf . ChatIdentity ) error {
s , err := m . getSettings ( )
if err != nil {
return err
}
2020-11-05 17:35:20 +00:00
2020-11-09 15:16:36 +00:00
ciis := make ( map [ string ] * protobuf . IdentityImage )
switch context {
2020-12-15 16:29:44 +00:00
case publicChat :
m . logger . Info ( fmt . Sprintf ( "handling %s ChatIdentity" , context ) )
2020-12-02 14:00:28 +00:00
2021-02-09 13:58:21 +00:00
if s . ProfilePicturesVisibility != accounts . ProfilePicturesVisibilityEveryone {
m . logger . Info ( fmt . Sprintf ( "settings.ProfilePicturesVisibility is set to '%d', public chat requires '%d'" , s . ProfilePicturesVisibility , accounts . ProfilePicturesVisibilityEveryone ) )
}
2020-12-09 14:03:43 +00:00
img , err := m . multiAccounts . GetIdentityImage ( m . account . KeyUID , userimage . SmallDimName )
2020-11-09 15:16:36 +00:00
if err != nil {
2021-02-09 13:58:21 +00:00
return err
2020-11-09 15:16:36 +00:00
}
2020-12-15 16:29:44 +00:00
m . logger . Debug ( fmt . Sprintf ( "%s images.IdentityImage '%s'" , context , spew . Sdump ( img ) ) )
2020-12-02 14:00:28 +00:00
2020-11-09 15:16:36 +00:00
ciis [ userimage . SmallDimName ] = m . adaptIdentityImageToProtobuf ( img )
2020-12-15 16:29:44 +00:00
m . logger . Debug ( fmt . Sprintf ( "%s protobuf.IdentityImage '%s'" , context , spew . Sdump ( ciis ) ) )
2020-11-09 15:16:36 +00:00
ci . Images = ciis
2020-12-15 16:29:44 +00:00
case privateChat :
m . logger . Info ( fmt . Sprintf ( "handling %s ChatIdentity" , context ) )
2021-02-09 13:58:21 +00:00
if s . ProfilePicturesVisibility == accounts . ProfilePicturesVisibilityEveryone {
m . logger . Info ( fmt . Sprintf ( "settings.ProfilePicturesVisibility is set to '%d', public chat requires '%d'" , s . ProfilePicturesVisibility , accounts . ProfilePicturesVisibilityEveryone ) )
}
2020-12-09 14:03:43 +00:00
imgs , err := m . multiAccounts . GetIdentityImages ( m . account . KeyUID )
2020-11-09 15:16:36 +00:00
if err != nil {
2021-02-09 13:58:21 +00:00
return err
2020-11-09 15:16:36 +00:00
}
2020-12-15 16:29:44 +00:00
m . logger . Debug ( fmt . Sprintf ( "%s images.IdentityImage '%s'" , context , spew . Sdump ( imgs ) ) )
2020-12-02 14:00:28 +00:00
2020-11-09 15:16:36 +00:00
for _ , img := range imgs {
ciis [ img . Name ] = m . adaptIdentityImageToProtobuf ( img )
}
2020-12-15 16:29:44 +00:00
m . logger . Debug ( fmt . Sprintf ( "%s protobuf.IdentityImage '%s'" , context , spew . Sdump ( ciis ) ) )
2020-11-09 15:16:36 +00:00
ci . Images = ciis
2020-12-15 16:29:44 +00:00
default :
2021-02-09 13:58:21 +00:00
return fmt . Errorf ( "unknown ChatIdentity context '%s'" , context )
2020-11-09 15:16:36 +00:00
}
2021-02-09 13:58:21 +00:00
return nil
2020-11-05 17:35:20 +00:00
}
2020-07-31 12:22:05 +00:00
// handleSharedSecrets process the negotiated secrets received from the encryption layer
func ( m * Messenger ) handleSharedSecrets ( secrets [ ] * sharedsecret . Secret ) error {
2020-07-31 09:46:38 +00:00
for _ , secret := range secrets {
fSecret := types . NegotiatedSecret {
PublicKey : secret . Identity ,
Key : secret . Key ,
}
2021-05-14 10:55:42 +00:00
_ , err := m . transport . ProcessNegotiatedSecret ( fSecret )
2020-07-31 09:46:38 +00:00
if err != nil {
2020-07-31 12:22:05 +00:00
return err
2020-07-31 09:46:38 +00:00
}
}
2020-07-31 12:22:05 +00:00
return nil
2020-07-31 09:46:38 +00:00
}
2020-07-31 12:22:05 +00:00
// handleInstallations adds the installations in the installations map
func ( m * Messenger ) handleInstallations ( installations [ ] * multidevice . Installation ) {
2020-07-31 09:08:09 +00:00
for _ , installation := range installations {
if installation . Identity == contactIDFromPublicKey ( & m . identity . PublicKey ) {
2021-03-29 15:41:30 +00:00
if _ , ok := m . allInstallations . Load ( installation . ID ) ; ! ok {
m . allInstallations . Store ( installation . ID , installation )
m . modifiedInstallations . Store ( installation . ID , true )
2020-07-31 09:08:09 +00:00
}
}
}
}
2020-07-31 09:46:38 +00:00
// handleEncryptionLayerSubscriptions handles events from the encryption layer
2020-07-31 09:08:09 +00:00
func ( m * Messenger ) handleEncryptionLayerSubscriptions ( subscriptions * encryption . Subscriptions ) {
go func ( ) {
for {
select {
2020-07-31 12:22:05 +00:00
case <- subscriptions . SendContactCode :
2021-01-25 13:49:13 +00:00
if err := m . publishContactCode ( ) ; err != nil {
2020-07-31 12:22:05 +00:00
m . logger . Error ( "failed to publish contact code" , zap . Error ( err ) )
2020-07-31 09:46:38 +00:00
}
2021-01-08 15:21:25 +00:00
// we also piggy-back to clean up cached messages
if err := m . transport . CleanMessagesProcessed ( m . getTimesource ( ) . GetCurrentTime ( ) - messageCacheIntervalMs ) ; err != nil {
m . logger . Error ( "failed to clean processed messages" , zap . Error ( err ) )
}
2020-07-31 09:46:38 +00:00
2020-07-31 09:08:09 +00:00
case <- subscriptions . Quit :
m . logger . Debug ( "quitting encryption subscription loop" )
return
}
}
} ( )
2020-01-29 19:40:06 +00:00
}
2021-01-11 10:32:51 +00:00
func ( m * Messenger ) handleENSVerified ( records [ ] * ens . VerificationRecord ) {
var contacts [ ] * Contact
for _ , record := range records {
m . logger . Info ( "handling record" , zap . Any ( "record" , record ) )
2021-03-29 15:41:30 +00:00
contact , ok := m . allContacts . Load ( record . PublicKey )
2021-01-11 10:32:51 +00:00
if ! ok {
m . logger . Info ( "contact not found" )
continue
}
2020-11-18 09:16:51 +00:00
2021-01-11 10:32:51 +00:00
contact . ENSVerified = record . Verified
contact . Name = record . Name
contacts = append ( contacts , contact )
2020-11-18 09:16:51 +00:00
}
2021-01-11 10:32:51 +00:00
m . logger . Info ( "handled records" , zap . Any ( "contacts" , contacts ) )
if len ( contacts ) != 0 {
if err := m . persistence . SaveContacts ( contacts ) ; err != nil {
m . logger . Error ( "failed to save contacts" , zap . Error ( err ) )
return
}
2020-11-18 09:16:51 +00:00
}
2021-01-11 10:32:51 +00:00
m . logger . Info ( "calling on contacts" )
if m . config . onContactENSVerified != nil {
m . logger . Info ( "called on contacts" )
response := & MessengerResponse { Contacts : contacts }
m . config . onContactENSVerified ( response )
2020-11-18 09:16:51 +00:00
}
2021-01-11 10:32:51 +00:00
}
2020-11-18 09:16:51 +00:00
2021-01-11 10:32:51 +00:00
func ( m * Messenger ) handleENSVerificationSubscription ( c chan [ ] * ens . VerificationRecord ) {
2020-11-18 09:16:51 +00:00
go func ( ) {
for {
select {
2021-01-11 10:32:51 +00:00
case records , more := <- c :
2020-11-18 09:16:51 +00:00
if ! more {
2021-01-11 10:32:51 +00:00
m . logger . Info ( "No more records, quitting" )
2020-11-18 09:16:51 +00:00
return
}
2021-01-11 10:32:51 +00:00
if len ( records ) != 0 {
m . logger . Info ( "handling records" , zap . Any ( "records" , records ) )
m . handleENSVerified ( records )
2020-11-18 09:16:51 +00:00
}
case <- m . quit :
return
}
}
} ( )
}
2020-08-27 12:38:59 +00:00
// watchConnectionChange checks the connection status and call handleConnectionChange when this changes
func ( m * Messenger ) watchConnectionChange ( ) {
m . logger . Debug ( "watching connection changes" )
state := m . online ( )
go func ( ) {
for {
select {
case <- time . After ( 200 * time . Millisecond ) :
newState := m . online ( )
if state != newState {
state = newState
m . logger . Debug ( "connection changed" , zap . Bool ( "online" , state ) )
m . handleConnectionChange ( state )
}
case <- m . quit :
return
}
}
2020-12-15 14:43:41 +00:00
} ( )
}
2020-08-27 12:38:59 +00:00
2020-12-15 14:43:41 +00:00
// watchExpiredEmojis regularly checks for expired emojis and invoke their resending
func ( m * Messenger ) watchExpiredEmojis ( ) {
m . logger . Debug ( "watching expired emojis" )
go func ( ) {
for {
select {
case <- time . After ( time . Second ) :
if m . online ( ) {
err := m . resendExpiredEmojiReactions ( )
if err != nil {
m . logger . Debug ( "Error when resending expired emoji reactions" , zap . Error ( err ) )
}
}
case <- m . quit :
return
}
}
2020-08-27 12:38:59 +00:00
} ( )
}
2020-12-21 08:41:50 +00:00
// watchIdentityImageChanges checks for identity images changes and publishes to the contact code when it happens
func ( m * Messenger ) watchIdentityImageChanges ( ) {
m . logger . Debug ( "watching identity image changes" )
if m . multiAccounts == nil {
return
}
channel := m . multiAccounts . SubscribeToIdentityImageChanges ( )
go func ( ) {
for {
select {
case <- channel :
if m . online ( ) {
2021-01-25 13:49:13 +00:00
if err := m . publishContactCode ( ) ; err != nil {
2020-12-21 08:41:50 +00:00
m . logger . Error ( "failed to publish contact code" , zap . Error ( err ) )
}
} else {
m . shouldPublishContactCode = true
}
case <- m . quit :
return
}
}
} ( )
}
2020-08-18 15:07:48 +00:00
// handlePushNotificationClientRegistration handles registration events
func ( m * Messenger ) handlePushNotificationClientRegistrations ( c chan struct { } ) {
go func ( ) {
for {
_ , more := <- c
if ! more {
return
}
2021-01-25 13:49:13 +00:00
if err := m . publishContactCode ( ) ; err != nil {
2020-08-18 15:07:48 +00:00
m . logger . Error ( "failed to publish contact code" , zap . Error ( err ) )
}
}
} ( )
}
2019-08-29 06:33:46 +00:00
// Init analyzes chats and contacts in order to setup filters
// which are responsible for retrieving messages.
func ( m * Messenger ) Init ( ) error {
2019-12-02 15:34:05 +00:00
// Seed the for color generation
rand . Seed ( time . Now ( ) . Unix ( ) )
2019-08-29 06:33:46 +00:00
logger := m . logger . With ( zap . String ( "site" , "Init" ) )
var (
publicChatIDs [ ] string
publicKeys [ ] * ecdsa . PublicKey
)
2021-01-11 10:32:51 +00:00
joinedCommunities , err := m . communitiesManager . Joined ( )
2020-11-18 09:16:51 +00:00
if err != nil {
return err
}
2021-01-11 10:32:51 +00:00
for _ , org := range joinedCommunities {
2020-11-18 09:16:51 +00:00
// the org advertise on the public topic derived by the pk
publicChatIDs = append ( publicChatIDs , org . IDString ( ) )
}
2021-01-11 10:32:51 +00:00
// Init filters for the communities we are an admin of
var adminCommunitiesPks [ ] * ecdsa . PrivateKey
adminCommunities , err := m . communitiesManager . Created ( )
if err != nil {
return err
}
for _ , c := range adminCommunities {
adminCommunitiesPks = append ( adminCommunitiesPks , c . PrivateKey ( ) )
}
_ , err = m . transport . InitCommunityFilters ( adminCommunitiesPks )
if err != nil {
return err
}
2019-08-29 06:33:46 +00:00
// Get chat IDs and public keys from the existing chats.
// TODO: Get only active chats by the query.
2019-12-02 15:34:05 +00:00
chats , err := m . persistence . Chats ( )
2019-08-29 06:33:46 +00:00
if err != nil {
return err
}
for _ , chat := range chats {
2020-02-07 11:56:30 +00:00
if err := chat . Validate ( ) ; err != nil {
logger . Warn ( "failed to validate chat" , zap . Error ( err ) )
continue
}
2021-03-29 15:41:30 +00:00
m . allChats . Store ( chat . ID , chat )
2021-08-25 08:59:53 +00:00
2020-11-06 10:57:05 +00:00
if ! chat . Active || chat . Timeline ( ) {
2019-08-29 06:33:46 +00:00
continue
}
2020-11-06 10:57:05 +00:00
2019-08-29 06:33:46 +00:00
switch chat . ChatType {
2020-10-20 15:10:28 +00:00
case ChatTypePublic , ChatTypeProfile :
2019-08-29 06:33:46 +00:00
publicChatIDs = append ( publicChatIDs , chat . ID )
2020-11-18 09:16:51 +00:00
case ChatTypeCommunityChat :
publicChatIDs = append ( publicChatIDs , chat . ID )
2019-08-29 06:33:46 +00:00
case ChatTypeOneToOne :
2019-12-02 15:34:05 +00:00
pk , err := chat . PublicKey ( )
if err != nil {
return err
}
publicKeys = append ( publicKeys , pk )
2019-08-29 06:33:46 +00:00
case ChatTypePrivateGroupChat :
for _ , member := range chat . Members {
publicKey , err := member . PublicKey ( )
if err != nil {
return errors . Wrapf ( err , "invalid public key for member %s in chat %s" , member . ID , chat . Name )
}
publicKeys = append ( publicKeys , publicKey )
}
default :
return errors . New ( "invalid chat type" )
}
}
2021-03-25 15:15:22 +00:00
// upsert timeline chat
err = m . ensureTimelineChat ( )
if err != nil {
return err
}
2021-07-22 17:41:49 +00:00
// upsert profile chat
2021-03-25 15:15:22 +00:00
err = m . ensureMyOwnProfileChat ( )
if err != nil {
return err
}
2019-08-29 06:33:46 +00:00
// Get chat IDs and public keys from the contacts.
2019-12-02 15:34:05 +00:00
contacts , err := m . persistence . Contacts ( )
2019-08-29 06:33:46 +00:00
if err != nil {
return err
}
2021-04-07 12:57:14 +00:00
for idx , contact := range contacts {
m . allContacts . Store ( contact . ID , contacts [ idx ] )
2019-08-29 06:33:46 +00:00
// We only need filters for contacts added by us and not blocked.
if ! contact . IsAdded ( ) || contact . IsBlocked ( ) {
continue
}
publicKey , err := contact . PublicKey ( )
if err != nil {
logger . Error ( "failed to get contact's public key" , zap . Error ( err ) )
continue
}
publicKeys = append ( publicKeys , publicKey )
}
2020-01-10 18:59:01 +00:00
installations , err := m . encryptor . GetOurInstallations ( & m . identity . PublicKey )
if err != nil {
return err
}
for _ , installation := range installations {
2021-03-29 15:41:30 +00:00
m . allInstallations . Store ( installation . ID , installation )
2020-01-10 18:59:01 +00:00
}
2019-09-02 09:29:06 +00:00
_ , err = m . transport . InitFilters ( publicChatIDs , publicKeys )
2019-08-29 06:33:46 +00:00
return err
}
2019-07-17 22:25:42 +00:00
// Shutdown takes care of ensuring a clean shutdown of Messenger
func ( m * Messenger ) Shutdown ( ) ( err error ) {
2021-01-14 22:15:13 +00:00
close ( m . quit )
for i , task := range m . shutdownTasks {
m . logger . Debug ( "running shutdown task" , zap . Int ( "n" , i ) )
2019-07-17 22:25:42 +00:00
if tErr := task ( ) ; tErr != nil {
2021-01-14 22:15:13 +00:00
m . logger . Info ( "shutdown task failed" , zap . Error ( tErr ) )
2019-07-17 22:25:42 +00:00
if err == nil {
// First error appeared.
err = tErr
} else {
// We return all errors. They will be concatenated in the order of occurrence,
// however, they will also be returned as a single error.
err = errors . Wrap ( err , tErr . Error ( ) )
}
}
}
return
}
func ( m * Messenger ) EnableInstallation ( id string ) error {
2021-03-29 15:41:30 +00:00
installation , ok := m . allInstallations . Load ( id )
2020-01-10 18:59:01 +00:00
if ! ok {
return errors . New ( "no installation found" )
}
err := m . encryptor . EnableInstallation ( & m . identity . PublicKey , id )
if err != nil {
return err
}
installation . Enabled = true
2021-03-29 15:41:30 +00:00
// TODO(samyoul) remove storing of an updated reference pointer?
m . allInstallations . Store ( id , installation )
2020-01-10 18:59:01 +00:00
return nil
2019-07-17 22:25:42 +00:00
}
func ( m * Messenger ) DisableInstallation ( id string ) error {
2021-03-29 15:41:30 +00:00
installation , ok := m . allInstallations . Load ( id )
2020-01-10 18:59:01 +00:00
if ! ok {
return errors . New ( "no installation found" )
}
err := m . encryptor . DisableInstallation ( & m . identity . PublicKey , id )
if err != nil {
return err
}
installation . Enabled = false
2021-03-29 15:41:30 +00:00
// TODO(samyoul) remove storing of an updated reference pointer?
m . allInstallations . Store ( id , installation )
2020-01-10 18:59:01 +00:00
return nil
2019-07-17 22:25:42 +00:00
}
2020-01-10 18:59:01 +00:00
func ( m * Messenger ) Installations ( ) [ ] * multidevice . Installation {
2021-03-29 15:41:30 +00:00
installations := make ( [ ] * multidevice . Installation , m . allInstallations . Len ( ) )
2020-01-10 18:59:01 +00:00
var i = 0
2021-03-29 15:41:30 +00:00
m . allInstallations . Range ( func ( installationID string , installation * multidevice . Installation ) ( shouldContinue bool ) {
2020-01-10 18:59:01 +00:00
installations [ i ] = installation
i ++
2021-03-29 15:41:30 +00:00
return true
} )
2020-01-10 18:59:01 +00:00
return installations
2019-07-17 22:25:42 +00:00
}
2020-01-10 18:59:01 +00:00
func ( m * Messenger ) setInstallationMetadata ( id string , data * multidevice . InstallationMetadata ) error {
2021-03-29 15:41:30 +00:00
installation , ok := m . allInstallations . Load ( id )
2020-01-10 18:59:01 +00:00
if ! ok {
return errors . New ( "no installation found" )
}
installation . InstallationMetadata = data
2019-07-17 22:25:42 +00:00
return m . encryptor . SetInstallationMetadata ( & m . identity . PublicKey , id , data )
}
2020-01-10 18:59:01 +00:00
func ( m * Messenger ) SetInstallationMetadata ( id string , data * multidevice . InstallationMetadata ) error {
return m . setInstallationMetadata ( id , data )
}
2019-07-17 22:25:42 +00:00
// NOT IMPLEMENTED
func ( m * Messenger ) SelectMailserver ( id string ) error {
return ErrNotImplemented
}
// NOT IMPLEMENTED
func ( m * Messenger ) AddMailserver ( enode string ) error {
return ErrNotImplemented
}
// NOT IMPLEMENTED
func ( m * Messenger ) RemoveMailserver ( id string ) error {
return ErrNotImplemented
}
// NOT IMPLEMENTED
func ( m * Messenger ) Mailservers ( ) ( [ ] string , error ) {
return nil , ErrNotImplemented
}
2019-12-02 15:34:05 +00:00
func ( m * Messenger ) CreateGroupChatWithMembers ( ctx context . Context , name string , members [ ] string ) ( * MessengerResponse , error ) {
var response MessengerResponse
logger := m . logger . With ( zap . String ( "site" , "CreateGroupChatWithMembers" ) )
logger . Info ( "Creating group chat" , zap . String ( "name" , name ) , zap . Any ( "members" , members ) )
2020-02-07 11:30:26 +00:00
chat := CreateGroupChat ( m . getTimesource ( ) )
2020-02-29 08:26:08 +00:00
clock , _ := chat . NextClockAndTimestamp ( m . getTimesource ( ) )
group , err := v1protocol . NewGroupWithCreator ( name , clock , m . identity )
2019-10-14 14:10:48 +00:00
if err != nil {
return nil , err
}
2020-02-29 08:26:08 +00:00
chat . LastClockValue = clock
2020-04-22 12:58:28 +00:00
2021-04-07 12:57:14 +00:00
chat . updateChatFromGroupMembershipChanges ( group )
2021-05-14 10:55:42 +00:00
chat . Joined = int64 ( m . getTimesource ( ) . GetCurrentTime ( ) )
2019-12-02 15:34:05 +00:00
2020-02-29 08:26:08 +00:00
clock , _ = chat . NextClockAndTimestamp ( m . getTimesource ( ) )
2020-10-30 11:26:08 +00:00
2019-12-02 15:34:05 +00:00
// Add members
2020-10-30 11:26:08 +00:00
if len ( members ) > 0 {
event := v1protocol . NewMembersAddedEvent ( members , clock )
event . ChatID = chat . ID
err = event . Sign ( m . identity )
if err != nil {
return nil , err
}
2019-12-02 15:34:05 +00:00
2020-10-30 11:26:08 +00:00
err = group . ProcessEvent ( event )
if err != nil {
return nil , err
}
2019-12-02 15:34:05 +00:00
}
2020-10-30 11:26:08 +00:00
2020-11-18 09:16:51 +00:00
recipients , err := stringSliceToPublicKeys ( group . Members ( ) )
2019-12-02 15:34:05 +00:00
if err != nil {
return nil , err
}
2021-06-23 14:13:48 +00:00
encodedMessage , err := m . sender . EncodeMembershipUpdate ( group , nil )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2021-03-29 15:41:30 +00:00
m . allChats . Store ( chat . ID , & chat )
2020-01-10 18:59:01 +00:00
2020-07-28 13:22:22 +00:00
_ , err = m . dispatchMessage ( ctx , common . RawMessage {
2021-01-08 19:33:19 +00:00
LocalChatID : chat . ID ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE ,
Recipients : recipients ,
2020-01-10 18:59:01 +00:00
} )
if err != nil {
2019-12-02 15:34:05 +00:00
return nil , err
}
2020-01-10 18:59:01 +00:00
2021-04-07 12:57:14 +00:00
chat . updateChatFromGroupMembershipChanges ( group )
2019-12-02 15:34:05 +00:00
2021-06-25 08:30:18 +00:00
return m . addMessagesAndChat ( & chat , buildSystemMessages ( chat . MembershipUpdates , m . systemMessagesTranslations ) , & response )
}
func ( m * Messenger ) addMessagesAndChat ( chat * Chat , messages [ ] * common . Message , response * MessengerResponse ) ( * MessengerResponse , error ) {
response . AddChat ( chat )
response . AddMessages ( messages )
err := m . persistence . SaveMessages ( response . Messages ( ) )
2020-01-17 12:39:09 +00:00
if err != nil {
return nil , err
}
2021-06-25 08:30:18 +00:00
return response , m . saveChat ( chat )
2019-10-14 14:10:48 +00:00
}
2020-08-07 13:49:37 +00:00
func ( m * Messenger ) CreateGroupChatFromInvitation ( name string , chatID string , adminPK string ) ( * MessengerResponse , error ) {
var response MessengerResponse
logger := m . logger . With ( zap . String ( "site" , "CreateGroupChatFromInvitation" ) )
logger . Info ( "Creating group chat from invitation" , zap . String ( "name" , name ) )
chat := CreateGroupChat ( m . getTimesource ( ) )
chat . ID = chatID
chat . Name = name
chat . InvitationAdmin = adminPK
2021-01-11 10:32:51 +00:00
response . AddChat ( & chat )
2020-08-07 13:49:37 +00:00
return & response , m . saveChat ( & chat )
}
2019-12-02 15:34:05 +00:00
func ( m * Messenger ) RemoveMemberFromGroupChat ( ctx context . Context , chatID string , member string ) ( * MessengerResponse , error ) {
var response MessengerResponse
logger := m . logger . With ( zap . String ( "site" , "RemoveMemberFromGroupChat" ) )
logger . Info ( "Removing member form group chat" , zap . String ( "chatID" , chatID ) , zap . String ( "member" , member ) )
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2019-12-02 15:34:05 +00:00
if ! ok {
2020-04-14 11:48:32 +00:00
return nil , ErrChatNotFound
2019-12-02 15:34:05 +00:00
}
2019-10-14 14:10:48 +00:00
group , err := newProtocolGroupFromChat ( chat )
if err != nil {
2019-12-02 15:34:05 +00:00
return nil , err
2019-10-14 14:10:48 +00:00
}
2019-12-02 15:34:05 +00:00
// We save the initial recipients as we want to send updates to also
// the members kicked out
2020-11-18 09:16:51 +00:00
oldRecipients , err := stringSliceToPublicKeys ( group . Members ( ) )
2019-12-02 15:34:05 +00:00
if err != nil {
return nil , err
2019-10-14 14:10:48 +00:00
}
2019-12-02 15:34:05 +00:00
2020-01-20 16:44:32 +00:00
clock , _ := chat . NextClockAndTimestamp ( m . getTimesource ( ) )
2019-12-02 15:34:05 +00:00
// Remove member
2020-01-15 07:25:09 +00:00
event := v1protocol . NewMemberRemovedEvent ( member , clock )
2019-12-02 15:34:05 +00:00
event . ChatID = chat . ID
err = event . Sign ( m . identity )
2019-10-14 14:10:48 +00:00
if err != nil {
2019-12-02 15:34:05 +00:00
return nil , err
2019-10-14 14:10:48 +00:00
}
2019-12-02 15:34:05 +00:00
err = group . ProcessEvent ( event )
if err != nil {
return nil , err
}
2020-01-10 18:59:01 +00:00
2021-06-23 14:13:48 +00:00
encodedMessage , err := m . sender . EncodeMembershipUpdate ( group , nil )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-07-28 13:22:22 +00:00
_ , err = m . dispatchMessage ( ctx , common . RawMessage {
2021-01-08 19:33:19 +00:00
LocalChatID : chat . ID ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE ,
Recipients : oldRecipients ,
2020-01-10 18:59:01 +00:00
} )
if err != nil {
2019-12-02 15:34:05 +00:00
return nil , err
2019-10-14 14:10:48 +00:00
}
2020-01-10 18:59:01 +00:00
2021-04-07 12:57:14 +00:00
chat . updateChatFromGroupMembershipChanges ( group )
2020-04-22 12:58:28 +00:00
2021-06-25 08:30:18 +00:00
return m . addMessagesAndChat ( chat , buildSystemMessages ( chat . MembershipUpdates , m . systemMessagesTranslations ) , & response )
2019-10-14 14:10:48 +00:00
}
2019-12-02 15:34:05 +00:00
func ( m * Messenger ) AddMembersToGroupChat ( ctx context . Context , chatID string , members [ ] string ) ( * MessengerResponse , error ) {
var response MessengerResponse
logger := m . logger . With ( zap . String ( "site" , "AddMembersFromGroupChat" ) )
logger . Info ( "Adding members form group chat" , zap . String ( "chatID" , chatID ) , zap . Any ( "members" , members ) )
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2019-12-02 15:34:05 +00:00
if ! ok {
2020-04-14 11:48:32 +00:00
return nil , ErrChatNotFound
2019-12-02 15:34:05 +00:00
}
2019-10-14 14:10:48 +00:00
group , err := newProtocolGroupFromChat ( chat )
if err != nil {
2019-12-02 15:34:05 +00:00
return nil , err
}
2020-01-20 16:44:32 +00:00
clock , _ := chat . NextClockAndTimestamp ( m . getTimesource ( ) )
2019-12-02 15:34:05 +00:00
// Add members
2020-01-15 07:25:09 +00:00
event := v1protocol . NewMembersAddedEvent ( members , clock )
2019-12-02 15:34:05 +00:00
event . ChatID = chat . ID
err = event . Sign ( m . identity )
if err != nil {
return nil , err
}
2020-08-07 13:49:37 +00:00
//approve invitations
for _ , member := range members {
logger . Info ( "ApproveInvitationByChatIdAndFrom" , zap . String ( "chatID" , chatID ) , zap . Any ( "member" , member ) )
groupChatInvitation := & GroupChatInvitation {
GroupChatInvitation : protobuf . GroupChatInvitation {
ChatId : chat . ID ,
} ,
From : member ,
}
groupChatInvitation , err = m . persistence . InvitationByID ( groupChatInvitation . ID ( ) )
2020-10-08 10:46:03 +00:00
if err != nil && err != common . ErrRecordNotFound {
2020-08-07 13:49:37 +00:00
return nil , err
}
if groupChatInvitation != nil {
groupChatInvitation . State = protobuf . GroupChatInvitation_APPROVED
err := m . persistence . SaveInvitation ( groupChatInvitation )
if err != nil {
return nil , err
}
response . Invitations = append ( response . Invitations , groupChatInvitation )
}
}
2019-12-02 15:34:05 +00:00
err = group . ProcessEvent ( event )
if err != nil {
return nil , err
}
2020-11-18 09:16:51 +00:00
recipients , err := stringSliceToPublicKeys ( group . Members ( ) )
2019-12-02 15:34:05 +00:00
if err != nil {
return nil , err
}
2021-06-23 14:13:48 +00:00
encodedMessage , err := m . sender . EncodeMembershipUpdate ( group , nil )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-07-28 13:22:22 +00:00
_ , err = m . dispatchMessage ( ctx , common . RawMessage {
2021-01-08 19:33:19 +00:00
LocalChatID : chat . ID ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE ,
Recipients : recipients ,
2020-01-10 18:59:01 +00:00
} )
if err != nil {
2019-12-02 15:34:05 +00:00
return nil , err
}
2020-01-10 18:59:01 +00:00
2021-04-07 12:57:14 +00:00
chat . updateChatFromGroupMembershipChanges ( group )
2019-12-02 15:34:05 +00:00
2021-06-25 08:30:18 +00:00
return m . addMessagesAndChat ( chat , buildSystemMessages ( [ ] v1protocol . MembershipUpdateEvent { event } , m . systemMessagesTranslations ) , & response )
2019-12-02 15:34:05 +00:00
}
2020-04-14 11:48:32 +00:00
func ( m * Messenger ) ChangeGroupChatName ( ctx context . Context , chatID string , name string ) ( * MessengerResponse , error ) {
logger := m . logger . With ( zap . String ( "site" , "ChangeGroupChatName" ) )
logger . Info ( "Changing group chat name" , zap . String ( "chatID" , chatID ) , zap . String ( "name" , name ) )
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2020-04-14 11:48:32 +00:00
if ! ok {
return nil , ErrChatNotFound
}
group , err := newProtocolGroupFromChat ( chat )
if err != nil {
return nil , err
}
clock , _ := chat . NextClockAndTimestamp ( m . getTimesource ( ) )
// Add members
event := v1protocol . NewNameChangedEvent ( name , clock )
event . ChatID = chat . ID
err = event . Sign ( m . identity )
if err != nil {
return nil , err
}
// Update in-memory group
err = group . ProcessEvent ( event )
if err != nil {
return nil , err
}
2020-11-18 09:16:51 +00:00
recipients , err := stringSliceToPublicKeys ( group . Members ( ) )
2020-04-14 11:48:32 +00:00
if err != nil {
return nil , err
}
2021-06-23 14:13:48 +00:00
encodedMessage , err := m . sender . EncodeMembershipUpdate ( group , nil )
2020-04-14 11:48:32 +00:00
if err != nil {
return nil , err
}
2020-07-28 13:22:22 +00:00
_ , err = m . dispatchMessage ( ctx , common . RawMessage {
2021-01-08 19:33:19 +00:00
LocalChatID : chat . ID ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE ,
Recipients : recipients ,
2020-04-14 11:48:32 +00:00
} )
if err != nil {
return nil , err
}
2021-04-07 12:57:14 +00:00
chat . updateChatFromGroupMembershipChanges ( group )
2020-04-14 11:48:32 +00:00
var response MessengerResponse
2021-06-25 08:30:18 +00:00
return m . addMessagesAndChat ( chat , buildSystemMessages ( [ ] v1protocol . MembershipUpdateEvent { event } , m . systemMessagesTranslations ) , & response )
2020-04-14 11:48:32 +00:00
}
2020-08-07 13:49:37 +00:00
func ( m * Messenger ) SendGroupChatInvitationRequest ( ctx context . Context , chatID string , adminPK string ,
message string ) ( * MessengerResponse , error ) {
logger := m . logger . With ( zap . String ( "site" , "SendGroupChatInvitationRequest" ) )
logger . Info ( "Sending group chat invitation request" , zap . String ( "chatID" , chatID ) ,
zap . String ( "adminPK" , adminPK ) , zap . String ( "message" , message ) )
var response MessengerResponse
// Get chat and clock
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2020-08-07 13:49:37 +00:00
if ! ok {
return nil , ErrChatNotFound
}
clock , _ := chat . NextClockAndTimestamp ( m . getTimesource ( ) )
invitationR := & GroupChatInvitation {
GroupChatInvitation : protobuf . GroupChatInvitation {
Clock : clock ,
ChatId : chatID ,
IntroductionMessage : message ,
State : protobuf . GroupChatInvitation_REQUEST ,
} ,
From : types . EncodeHex ( crypto . FromECDSAPub ( & m . identity . PublicKey ) ) ,
}
encodedMessage , err := proto . Marshal ( invitationR . GetProtobuf ( ) )
if err != nil {
return nil , err
}
spec := common . RawMessage {
LocalChatID : adminPK ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_GROUP_CHAT_INVITATION ,
ResendAutomatically : true ,
}
pkey , err := hex . DecodeString ( adminPK [ 2 : ] )
if err != nil {
return nil , err
}
// Safety check, make sure is well formed
adminpk , err := crypto . UnmarshalPubkey ( pkey )
if err != nil {
return nil , err
}
2021-06-23 14:13:48 +00:00
id , err := m . sender . SendPrivate ( ctx , adminpk , & spec )
2020-08-07 13:49:37 +00:00
if err != nil {
return nil , err
}
spec . ID = types . EncodeHex ( id )
spec . SendCount ++
err = m . persistence . SaveRawMessage ( & spec )
if err != nil {
return nil , err
}
response . Invitations = [ ] * GroupChatInvitation { invitationR }
err = m . persistence . SaveInvitation ( invitationR )
if err != nil {
return nil , err
}
return & response , nil
}
func ( m * Messenger ) GetGroupChatInvitations ( ) ( [ ] * GroupChatInvitation , error ) {
return m . persistence . GetGroupChatInvitations ( )
}
func ( m * Messenger ) SendGroupChatInvitationRejection ( ctx context . Context , invitationRequestID string ) ( * MessengerResponse , error ) {
logger := m . logger . With ( zap . String ( "site" , "SendGroupChatInvitationRejection" ) )
logger . Info ( "Sending group chat invitation reject" , zap . String ( "invitationRequestID" , invitationRequestID ) )
invitationR , err := m . persistence . InvitationByID ( invitationRequestID )
if err != nil {
return nil , err
}
invitationR . State = protobuf . GroupChatInvitation_REJECTED
// Get chat and clock
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( invitationR . ChatId )
2020-08-07 13:49:37 +00:00
if ! ok {
return nil , ErrChatNotFound
}
clock , _ := chat . NextClockAndTimestamp ( m . getTimesource ( ) )
invitationR . Clock = clock
encodedMessage , err := proto . Marshal ( invitationR . GetProtobuf ( ) )
if err != nil {
return nil , err
}
spec := common . RawMessage {
LocalChatID : invitationR . From ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_GROUP_CHAT_INVITATION ,
ResendAutomatically : true ,
}
pkey , err := hex . DecodeString ( invitationR . From [ 2 : ] )
if err != nil {
return nil , err
}
// Safety check, make sure is well formed
userpk , err := crypto . UnmarshalPubkey ( pkey )
if err != nil {
return nil , err
}
2021-06-23 14:13:48 +00:00
id , err := m . sender . SendPrivate ( ctx , userpk , & spec )
2020-08-07 13:49:37 +00:00
if err != nil {
return nil , err
}
spec . ID = types . EncodeHex ( id )
spec . SendCount ++
err = m . persistence . SaveRawMessage ( & spec )
if err != nil {
return nil , err
}
var response MessengerResponse
response . Invitations = [ ] * GroupChatInvitation { invitationR }
err = m . persistence . SaveInvitation ( invitationR )
if err != nil {
return nil , err
}
return & response , nil
}
2019-12-02 15:34:05 +00:00
func ( m * Messenger ) AddAdminsToGroupChat ( ctx context . Context , chatID string , members [ ] string ) ( * MessengerResponse , error ) {
var response MessengerResponse
logger := m . logger . With ( zap . String ( "site" , "AddAdminsToGroupChat" ) )
logger . Info ( "Add admins to group chat" , zap . String ( "chatID" , chatID ) , zap . Any ( "members" , members ) )
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2019-12-02 15:34:05 +00:00
if ! ok {
2020-04-14 11:48:32 +00:00
return nil , ErrChatNotFound
2019-12-02 15:34:05 +00:00
}
group , err := newProtocolGroupFromChat ( chat )
if err != nil {
return nil , err
}
2020-01-20 16:44:32 +00:00
clock , _ := chat . NextClockAndTimestamp ( m . getTimesource ( ) )
2019-12-02 15:34:05 +00:00
// Add members
2020-01-15 07:25:09 +00:00
event := v1protocol . NewAdminsAddedEvent ( members , clock )
2019-12-02 15:34:05 +00:00
event . ChatID = chat . ID
err = event . Sign ( m . identity )
if err != nil {
return nil , err
}
err = group . ProcessEvent ( event )
if err != nil {
return nil , err
}
2020-11-18 09:16:51 +00:00
recipients , err := stringSliceToPublicKeys ( group . Members ( ) )
2019-12-02 15:34:05 +00:00
if err != nil {
return nil , err
}
2021-06-23 14:13:48 +00:00
encodedMessage , err := m . sender . EncodeMembershipUpdate ( group , nil )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-07-28 13:22:22 +00:00
_ , err = m . dispatchMessage ( ctx , common . RawMessage {
2021-01-08 19:33:19 +00:00
LocalChatID : chat . ID ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE ,
Recipients : recipients ,
2020-01-10 18:59:01 +00:00
} )
if err != nil {
2019-12-02 15:34:05 +00:00
return nil , err
}
2020-01-10 18:59:01 +00:00
2021-04-07 12:57:14 +00:00
chat . updateChatFromGroupMembershipChanges ( group )
2021-06-25 08:30:18 +00:00
return m . addMessagesAndChat ( chat , buildSystemMessages ( [ ] v1protocol . MembershipUpdateEvent { event } , m . systemMessagesTranslations ) , & response )
2019-12-02 15:34:05 +00:00
}
func ( m * Messenger ) ConfirmJoiningGroup ( ctx context . Context , chatID string ) ( * MessengerResponse , error ) {
var response MessengerResponse
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2019-12-02 15:34:05 +00:00
if ! ok {
2020-04-14 11:48:32 +00:00
return nil , ErrChatNotFound
2019-12-02 15:34:05 +00:00
}
2021-01-11 10:32:51 +00:00
_ , err := m . Join ( chat )
2019-12-02 15:34:05 +00:00
if err != nil {
return nil , err
}
group , err := newProtocolGroupFromChat ( chat )
if err != nil {
return nil , err
2019-10-14 14:10:48 +00:00
}
2020-01-20 16:44:32 +00:00
clock , _ := chat . NextClockAndTimestamp ( m . getTimesource ( ) )
2019-11-21 16:19:22 +00:00
event := v1protocol . NewMemberJoinedEvent (
2020-01-15 07:25:09 +00:00
clock ,
2019-10-14 14:10:48 +00:00
)
2019-12-02 15:34:05 +00:00
event . ChatID = chat . ID
err = event . Sign ( m . identity )
2019-10-14 14:10:48 +00:00
if err != nil {
2019-12-02 15:34:05 +00:00
return nil , err
2019-10-14 14:10:48 +00:00
}
2019-12-02 15:34:05 +00:00
err = group . ProcessEvent ( event )
if err != nil {
return nil , err
}
2020-11-18 09:16:51 +00:00
recipients , err := stringSliceToPublicKeys ( group . Members ( ) )
2019-12-02 15:34:05 +00:00
if err != nil {
return nil , err
}
2021-06-23 14:13:48 +00:00
encodedMessage , err := m . sender . EncodeMembershipUpdate ( group , nil )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-07-28 13:22:22 +00:00
_ , err = m . dispatchMessage ( ctx , common . RawMessage {
2021-01-08 19:33:19 +00:00
LocalChatID : chat . ID ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE ,
Recipients : recipients ,
2020-01-10 18:59:01 +00:00
} )
if err != nil {
2019-12-02 15:34:05 +00:00
return nil , err
2019-10-14 14:10:48 +00:00
}
2020-01-10 18:59:01 +00:00
2021-04-07 12:57:14 +00:00
chat . updateChatFromGroupMembershipChanges ( group )
2021-05-14 10:55:42 +00:00
chat . Joined = int64 ( m . getTimesource ( ) . GetCurrentTime ( ) )
2019-12-02 15:34:05 +00:00
2021-06-25 08:30:18 +00:00
return m . addMessagesAndChat ( chat , buildSystemMessages ( [ ] v1protocol . MembershipUpdateEvent { event } , m . systemMessagesTranslations ) , & response )
2019-10-14 14:10:48 +00:00
}
2020-04-14 11:49:03 +00:00
func ( m * Messenger ) LeaveGroupChat ( ctx context . Context , chatID string , remove bool ) ( * MessengerResponse , error ) {
2019-12-02 15:34:05 +00:00
var response MessengerResponse
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2019-12-02 15:34:05 +00:00
if ! ok {
2020-04-14 11:48:32 +00:00
return nil , ErrChatNotFound
2019-10-14 14:10:48 +00:00
}
2019-12-02 15:34:05 +00:00
2021-04-07 12:57:14 +00:00
joined := chat . HasJoinedMember ( common . PubkeyToHex ( & m . identity . PublicKey ) )
2019-12-02 15:34:05 +00:00
2021-04-07 12:57:14 +00:00
if joined {
group , err := newProtocolGroupFromChat ( chat )
if err != nil {
return nil , err
}
clock , _ := chat . NextClockAndTimestamp ( m . getTimesource ( ) )
event := v1protocol . NewMemberRemovedEvent (
contactIDFromPublicKey ( & m . identity . PublicKey ) ,
clock ,
)
event . ChatID = chat . ID
err = event . Sign ( m . identity )
if err != nil {
return nil , err
}
2019-12-02 15:34:05 +00:00
2021-04-07 12:57:14 +00:00
err = group . ProcessEvent ( event )
if err != nil {
return nil , err
}
2019-12-02 15:34:05 +00:00
2021-04-07 12:57:14 +00:00
recipients , err := stringSliceToPublicKeys ( group . Members ( ) )
if err != nil {
return nil , err
}
2019-12-02 15:34:05 +00:00
2021-06-23 14:13:48 +00:00
encodedMessage , err := m . sender . EncodeMembershipUpdate ( group , nil )
2021-04-07 12:57:14 +00:00
if err != nil {
return nil , err
}
_ , err = m . dispatchMessage ( ctx , common . RawMessage {
LocalChatID : chat . ID ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE ,
Recipients : recipients ,
} )
if err != nil {
return nil , err
}
2020-01-10 18:59:01 +00:00
2021-04-07 12:57:14 +00:00
chat . updateChatFromGroupMembershipChanges ( group )
2021-06-03 13:11:55 +00:00
response . AddMessages ( buildSystemMessages ( [ ] v1protocol . MembershipUpdateEvent { event } , m . systemMessagesTranslations ) )
err = m . persistence . SaveMessages ( response . Messages ( ) )
2021-04-07 12:57:14 +00:00
if err != nil {
return nil , err
}
}
2020-04-22 12:58:28 +00:00
2020-04-14 11:49:03 +00:00
if remove {
chat . Active = false
}
2019-12-02 15:34:05 +00:00
2021-01-11 10:32:51 +00:00
response . AddChat ( chat )
2020-01-17 12:39:09 +00:00
2019-12-02 15:34:05 +00:00
return & response , m . saveChat ( chat )
}
2020-08-18 15:07:48 +00:00
func ( m * Messenger ) reregisterForPushNotifications ( ) error {
m . logger . Info ( "contact state changed, re-registering for push notification" )
if m . pushNotificationClient == nil {
return nil
}
2020-09-02 14:11:16 +00:00
return m . pushNotificationClient . Reregister ( m . pushNotificationOptions ( ) )
2020-08-18 15:07:48 +00:00
}
2020-12-15 14:43:41 +00:00
// pull a message from the database and send it again
func ( m * Messenger ) reSendRawMessage ( ctx context . Context , messageID string ) error {
2020-01-10 18:59:01 +00:00
message , err := m . persistence . RawMessageByID ( messageID )
2019-09-26 07:01:17 +00:00
if err != nil {
2020-01-10 18:59:01 +00:00
return err
2019-07-17 22:25:42 +00:00
}
2020-01-10 18:59:01 +00:00
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( message . LocalChatID )
2020-01-10 18:59:01 +00:00
if ! ok {
return errors . New ( "chat not found" )
}
2020-07-28 13:22:22 +00:00
_ , err = m . dispatchMessage ( ctx , common . RawMessage {
2020-07-15 06:31:39 +00:00
LocalChatID : chat . ID ,
Payload : message . Payload ,
MessageType : message . MessageType ,
Recipients : message . Recipients ,
ResendAutomatically : message . ResendAutomatically ,
2020-12-15 14:43:41 +00:00
SendCount : message . SendCount ,
2020-01-10 18:59:01 +00:00
} )
return err
}
2020-12-15 14:43:41 +00:00
// ReSendChatMessage pulls a message from the database and sends it again
func ( m * Messenger ) ReSendChatMessage ( ctx context . Context , messageID string ) error {
return m . reSendRawMessage ( ctx , messageID )
}
2020-01-10 18:59:01 +00:00
func ( m * Messenger ) hasPairedDevices ( ) bool {
2021-08-06 15:40:23 +00:00
logger := m . logger . Named ( "hasPairedDevices" )
2020-01-10 18:59:01 +00:00
var count int
2021-03-29 15:41:30 +00:00
m . allInstallations . Range ( func ( installationID string , installation * multidevice . Installation ) ( shouldContinue bool ) {
if installation . Enabled {
2020-02-10 11:22:37 +00:00
count ++
2020-01-10 18:59:01 +00:00
}
2021-03-29 15:41:30 +00:00
return true
} )
2021-08-06 15:40:23 +00:00
logger . Debug ( "installations info" ,
zap . Int ( "Number of installations" , m . allInstallations . Len ( ) ) ,
zap . Int ( "Number of enabled installations" , count ) )
2020-01-10 18:59:01 +00:00
return count > 1
}
// sendToPairedDevices will check if we have any paired devices and send to them if necessary
2020-07-28 13:22:22 +00:00
func ( m * Messenger ) sendToPairedDevices ( ctx context . Context , spec common . RawMessage ) error {
2020-01-10 18:59:01 +00:00
hasPairedDevices := m . hasPairedDevices ( )
// We send a message to any paired device
if hasPairedDevices {
2021-06-23 14:13:48 +00:00
_ , err := m . sender . SendPrivate ( ctx , & m . identity . PublicKey , & spec )
2020-01-10 18:59:01 +00:00
if err != nil {
return err
}
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
}
2020-01-10 18:59:01 +00:00
return nil
}
2019-07-17 22:25:42 +00:00
2020-07-28 13:22:22 +00:00
func ( m * Messenger ) dispatchPairInstallationMessage ( ctx context . Context , spec common . RawMessage ) ( [ ] byte , error ) {
2020-01-10 18:59:01 +00:00
var err error
var id [ ] byte
2021-06-23 14:13:48 +00:00
id , err = m . sender . SendPairInstallation ( ctx , & m . identity . PublicKey , spec )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
spec . ID = types . EncodeHex ( id )
2020-02-10 11:22:37 +00:00
spec . SendCount ++
2020-07-28 13:22:22 +00:00
err = m . persistence . SaveRawMessage ( & spec )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
return id , nil
}
2021-01-22 13:59:45 +00:00
func ( m * Messenger ) dispatchMessage ( ctx context . Context , spec common . RawMessage ) ( common . RawMessage , error ) {
2020-01-10 18:59:01 +00:00
var err error
var id [ ] byte
logger := m . logger . With ( zap . String ( "site" , "dispatchMessage" ) , zap . String ( "chatID" , spec . LocalChatID ) )
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( spec . LocalChatID )
2019-12-02 15:34:05 +00:00
if ! ok {
2021-01-22 13:59:45 +00:00
return spec , errors . New ( "no chat found" )
2019-07-17 22:25:42 +00:00
}
2019-10-14 14:10:48 +00:00
switch chat . ChatType {
case ChatTypeOneToOne :
2019-12-02 15:34:05 +00:00
publicKey , err := chat . PublicKey ( )
if err != nil {
2021-01-22 13:59:45 +00:00
return spec , err
2019-12-02 15:34:05 +00:00
}
2021-02-23 15:47:45 +00:00
//SendPrivate will alter message identity and possibly datasyncid, so we save an unchanged
//message for sending to paired devices later
specCopyForPairedDevices := spec
2020-07-06 08:54:22 +00:00
if ! common . IsPubKeyEqual ( publicKey , & m . identity . PublicKey ) {
2021-06-23 14:13:48 +00:00
id , err = m . sender . SendPrivate ( ctx , publicKey , & spec )
2019-12-02 15:34:05 +00:00
2020-01-10 18:59:01 +00:00
if err != nil {
2021-01-22 13:59:45 +00:00
return spec , err
2020-01-10 18:59:01 +00:00
}
2019-10-14 14:10:48 +00:00
}
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
2021-02-23 15:47:45 +00:00
err = m . sendToPairedDevices ( ctx , specCopyForPairedDevices )
2019-12-02 15:34:05 +00:00
2019-10-14 14:10:48 +00:00
if err != nil {
2021-01-22 13:59:45 +00:00
return spec , err
2019-10-14 14:10:48 +00:00
}
2020-01-10 18:59:01 +00:00
2020-10-20 15:10:28 +00:00
case ChatTypePublic , ChatTypeProfile :
2020-01-10 18:59:01 +00:00
logger . Debug ( "sending public message" , zap . String ( "chatName" , chat . Name ) )
2021-06-23 14:13:48 +00:00
id , err = m . sender . SendPublic ( ctx , chat . ID , spec )
2019-10-14 14:10:48 +00:00
if err != nil {
2021-01-22 13:59:45 +00:00
return spec , err
2019-10-14 14:10:48 +00:00
}
2020-11-18 09:16:51 +00:00
case ChatTypeCommunityChat :
// TODO: add grant
canPost , err := m . communitiesManager . CanPost ( & m . identity . PublicKey , chat . CommunityID , chat . CommunityChatID ( ) , nil )
if err != nil {
2021-01-22 13:59:45 +00:00
return spec , err
2020-11-18 09:16:51 +00:00
}
2020-12-22 16:20:12 +00:00
// We allow emoji reactions by anyone
if spec . MessageType != protobuf . ApplicationMetadataMessage_EMOJI_REACTION && ! canPost {
2020-11-18 09:16:51 +00:00
m . logger . Error ( "can't post on chat" , zap . String ( "chat-id" , chat . ID ) , zap . String ( "chat-name" , chat . Name ) )
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
2021-01-22 13:59:45 +00:00
return spec , errors . New ( "can't post on chat" )
2020-11-18 09:16:51 +00:00
}
logger . Debug ( "sending community chat message" , zap . String ( "chatName" , chat . Name ) )
2021-06-23 14:13:48 +00:00
id , err = m . sender . SendPublic ( ctx , chat . ID , spec )
2020-11-18 09:16:51 +00:00
if err != nil {
2021-01-22 13:59:45 +00:00
return spec , err
2020-11-18 09:16:51 +00:00
}
2020-01-10 18:59:01 +00:00
case ChatTypePrivateGroupChat :
logger . Debug ( "sending group message" , zap . String ( "chatName" , chat . Name ) )
if spec . Recipients == nil {
2021-01-15 17:47:30 +00:00
// Anything that is not a membership update message is only dispatched to joined users
// NOTE: I think here it might make sense to always invite to joined users apart from the
// initial message
if spec . MessageType != protobuf . ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE {
2020-09-03 09:54:05 +00:00
spec . Recipients , err = chat . JoinedMembersAsPublicKeys ( )
if err != nil {
2021-01-22 13:59:45 +00:00
return spec , err
2020-09-03 09:54:05 +00:00
}
} else {
spec . Recipients , err = chat . MembersAsPublicKeys ( )
if err != nil {
2021-01-22 13:59:45 +00:00
return spec , err
2020-09-03 09:54:05 +00:00
}
2019-10-14 14:10:48 +00:00
}
}
2021-01-15 17:47:30 +00:00
2020-01-10 18:59:01 +00:00
hasPairedDevices := m . hasPairedDevices ( )
if ! hasPairedDevices {
2021-03-09 12:48:15 +00:00
2020-01-10 18:59:01 +00:00
// Filter out my key from the recipients
n := 0
for _ , recipient := range spec . Recipients {
2020-07-06 08:54:22 +00:00
if ! common . IsPubKeyEqual ( recipient , & m . identity . PublicKey ) {
2020-01-10 18:59:01 +00:00
spec . Recipients [ n ] = recipient
n ++
}
}
spec . Recipients = spec . Recipients [ : n ]
2019-10-14 14:10:48 +00:00
}
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
2021-01-22 13:59:45 +00:00
// We won't really send the message out if there's no recipients
if len ( spec . Recipients ) == 0 {
spec . Sent = true
}
2021-01-15 17:47:30 +00:00
// We skip wrapping in some cases (emoji reactions for example)
if ! spec . SkipGroupMessageWrap {
spec . MessageType = protobuf . ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE
}
2021-01-22 13:59:45 +00:00
2021-06-23 14:13:48 +00:00
id , err = m . sender . SendGroup ( ctx , spec . Recipients , spec )
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
if err != nil {
2021-01-22 13:59:45 +00:00
return spec , err
2019-07-17 22:25:42 +00:00
}
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
2019-10-14 14:10:48 +00:00
default :
2021-01-22 13:59:45 +00:00
return spec , errors . New ( "chat type not supported" )
2019-10-14 14:10:48 +00:00
}
2020-01-10 18:59:01 +00:00
spec . ID = types . EncodeHex ( id )
2020-02-10 11:22:37 +00:00
spec . SendCount ++
2020-12-15 14:43:41 +00:00
spec . LastSent = m . getTimesource ( ) . GetCurrentTime ( )
2020-07-28 13:22:22 +00:00
err = m . persistence . SaveRawMessage ( & spec )
2019-12-02 15:34:05 +00:00
if err != nil {
2021-01-22 13:59:45 +00:00
return spec , err
2019-12-02 15:34:05 +00:00
}
2021-01-22 13:59:45 +00:00
return spec , nil
2019-07-17 22:25:42 +00:00
}
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
// SendChatMessage takes a minimal message and sends it based on the corresponding chat
2020-09-01 13:27:01 +00:00
func ( m * Messenger ) SendChatMessage ( ctx context . Context , message * common . Message ) ( * MessengerResponse , error ) {
2020-12-01 09:43:46 +00:00
return m . sendChatMessage ( ctx , message )
}
// SendChatMessages takes a array of messages and sends it based on the corresponding chats
func ( m * Messenger ) SendChatMessages ( ctx context . Context , messages [ ] * common . Message ) ( * MessengerResponse , error ) {
var response MessengerResponse
2019-12-02 15:34:05 +00:00
2020-12-01 09:43:46 +00:00
for _ , message := range messages {
2021-03-29 15:41:30 +00:00
messageResponse , err := m . SendChatMessage ( ctx , message )
2020-12-01 09:43:46 +00:00
if err != nil {
return nil , err
}
err = response . Merge ( messageResponse )
if err != nil {
return nil , err
}
}
return & response , nil
}
// SendChatMessage takes a minimal message and sends it based on the corresponding chat
func ( m * Messenger ) sendChatMessage ( ctx context . Context , message * common . Message ) ( * MessengerResponse , error ) {
2020-05-13 13:16:17 +00:00
if len ( message . ImagePath ) != 0 {
file , err := os . Open ( message . ImagePath )
if err != nil {
return nil , err
}
defer file . Close ( )
payload , err := ioutil . ReadAll ( file )
if err != nil {
return nil , err
}
image := protobuf . ImageMessage {
Payload : payload ,
Type : images . ImageType ( payload ) ,
}
message . Payload = & protobuf . ChatMessage_Image { Image : & image }
2020-11-18 09:16:51 +00:00
} else if len ( message . CommunityID ) != 0 {
community , err := m . communitiesManager . GetByIDString ( message . CommunityID )
if err != nil {
return nil , err
}
if community == nil {
return nil , errors . New ( "community not found" )
}
wrappedCommunity , err := community . ToBytes ( )
if err != nil {
return nil , err
}
message . Payload = & protobuf . ChatMessage_Community { Community : wrappedCommunity }
message . ContentType = protobuf . ChatMessage_COMMUNITY
2020-06-17 18:55:49 +00:00
2020-11-18 09:16:51 +00:00
} else if len ( message . AudioPath ) != 0 {
2020-06-17 18:55:49 +00:00
file , err := os . Open ( message . AudioPath )
if err != nil {
return nil , err
}
defer file . Close ( )
payload , err := ioutil . ReadAll ( file )
if err != nil {
return nil , err
}
2020-06-23 14:30:39 +00:00
audioMessage := message . GetAudio ( )
if audioMessage == nil {
return nil , errors . New ( "no audio has been passed" )
2020-06-17 18:55:49 +00:00
}
2020-06-23 14:30:39 +00:00
audioMessage . Payload = payload
audioMessage . Type = audio . Type ( payload )
message . Payload = & protobuf . ChatMessage_Audio { Audio : audioMessage }
2020-07-16 06:21:02 +00:00
err = os . Remove ( message . AudioPath )
if err != nil {
return nil , err
}
2020-06-17 18:55:49 +00:00
}
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
var response MessengerResponse
// A valid added chat is required.
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( message . ChatId )
2019-12-02 15:34:05 +00:00
if ! ok {
return nil , errors . New ( "Chat not found" )
2019-07-17 22:25:42 +00:00
}
2020-11-09 15:16:36 +00:00
err := m . handleStandaloneChatIdentity ( chat )
if err != nil {
return nil , err
}
err = extendMessageFromChat ( message , chat , & m . identity . PublicKey , m . getTimesource ( ) )
2019-07-26 07:17:29 +00:00
if err != nil {
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
return nil , err
2019-07-26 07:17:29 +00:00
}
2020-07-26 22:06:58 +00:00
encodedMessage , err := m . encodeChatEntity ( chat , message )
if err != nil {
return nil , err
2019-09-26 07:01:17 +00:00
}
2021-01-22 13:59:45 +00:00
rawMessage := common . RawMessage {
2020-07-22 07:41:40 +00:00
LocalChatID : chat . ID ,
2020-09-02 14:11:16 +00:00
SendPushNotification : m . featureFlags . PushNotifications ,
2020-07-22 07:41:40 +00:00
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_CHAT_MESSAGE ,
ResendAutomatically : true ,
2021-01-22 13:59:45 +00:00
}
rawMessage , err = m . dispatchMessage ( ctx , rawMessage )
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
if err != nil {
return nil , err
2019-07-17 22:25:42 +00:00
}
2021-01-22 13:59:45 +00:00
if rawMessage . Sent {
message . OutgoingStatus = common . OutgoingStatusSent
}
message . ID = rawMessage . ID
2021-05-25 09:40:02 +00:00
err = message . PrepareContent ( common . PubkeyToHex ( & m . identity . PublicKey ) )
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
if err != nil {
return nil , err
2019-07-17 22:25:42 +00:00
}
2020-01-20 16:44:32 +00:00
err = chat . UpdateFromMessage ( message , m . getTimesource ( ) )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2019-07-17 22:25:42 +00:00
2020-09-01 13:27:01 +00:00
err = m . persistence . SaveMessages ( [ ] * common . Message { message } )
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
if err != nil {
return nil , err
}
2021-06-03 13:11:55 +00:00
msg , err := m . pullMessagesAndResponsesFromDB ( [ ] * common . Message { message } )
Add replies to messages
Currently replies to messages are handled in status-react.
This causes some issues with the fact that sometimes replies might come
out of order, they might be offloaded to the database etc.
This commit changes the behavior so that status-go always returns the
replies, and in case a reply comes out of order (first the reply, later
the message being replied to), it will include in the messages the
updated message.
It also adds some fields (RTL,Replace,LineCount) to the database which
were not previously saved, resulting in some potential bugs.
The method that we use to pull replies is currently a bit naive, we just
pull all the message again from the database, but has the advantage of
being simple. It will go through performance testing to make sure
performnace are acceptable, if so I think it's reasonable to avoid some
complexity.
2020-04-08 13:42:02 +00:00
if err != nil {
return nil , err
}
2021-06-03 13:11:55 +00:00
response . SetMessages ( msg )
Add replies to messages
Currently replies to messages are handled in status-react.
This causes some issues with the fact that sometimes replies might come
out of order, they might be offloaded to the database etc.
This commit changes the behavior so that status-go always returns the
replies, and in case a reply comes out of order (first the reply, later
the message being replied to), it will include in the messages the
updated message.
It also adds some fields (RTL,Replace,LineCount) to the database which
were not previously saved, resulting in some potential bugs.
The method that we use to pull replies is currently a bit naive, we just
pull all the message again from the database, but has the advantage of
being simple. It will go through performance testing to make sure
performnace are acceptable, if so I think it's reasonable to avoid some
complexity.
2020-04-08 13:42:02 +00:00
2021-01-11 10:32:51 +00:00
response . AddChat ( chat )
2019-12-02 15:34:05 +00:00
return & response , m . saveChat ( chat )
2019-07-17 22:25:42 +00:00
}
2020-01-15 07:25:09 +00:00
// SyncDevices sends all public chats and contacts to paired devices
2020-11-24 13:42:36 +00:00
// TODO remove use of photoPath in contacts
2021-03-29 15:41:30 +00:00
func ( m * Messenger ) SyncDevices ( ctx context . Context , ensName , photoPath string ) ( err error ) {
2020-01-15 07:25:09 +00:00
myID := contactIDFromPublicKey ( & m . identity . PublicKey )
2021-03-29 15:41:30 +00:00
if _ , err = m . sendContactUpdate ( ctx , myID , ensName , photoPath ) ; err != nil {
2020-01-15 07:25:09 +00:00
return err
}
2021-03-29 15:41:30 +00:00
m . allChats . Range ( func ( chatID string , chat * Chat ) ( shouldContinue bool ) {
2021-03-04 13:02:08 +00:00
if ! chat . Timeline ( ) && ! chat . ProfileUpdates ( ) && chat . Public ( ) && chat . Active {
2021-03-29 15:41:30 +00:00
err = m . syncPublicChat ( ctx , chat )
if err != nil {
return false
2020-01-15 07:25:09 +00:00
}
}
2021-03-29 15:41:30 +00:00
return true
} )
if err != nil {
return err
2020-01-15 07:25:09 +00:00
}
2021-03-29 15:41:30 +00:00
m . allContacts . Range ( func ( contactID string , contact * Contact ) ( shouldContinue bool ) {
2021-09-03 08:26:05 +00:00
if contact . ID != myID &&
( contact . LocalNickname != "" || contact . IsAdded ( ) || contact . IsBlocked ( ) ) {
2021-03-29 15:41:30 +00:00
if err = m . syncContact ( ctx , contact ) ; err != nil {
return false
2020-01-15 07:25:09 +00:00
}
}
2021-03-29 15:41:30 +00:00
return true
} )
2020-01-15 07:25:09 +00:00
2021-08-06 15:40:23 +00:00
cs , err := m . communitiesManager . JoinedAndPendingCommunitiesWithRequests ( )
if err != nil {
return err
}
for _ , c := range cs {
if err = m . syncCommunity ( ctx , c ) ; err != nil {
return err
}
}
2021-03-29 15:41:30 +00:00
return err
2020-01-15 07:25:09 +00:00
}
2021-08-06 15:40:23 +00:00
func ( m * Messenger ) getLastClockWithRelatedChat ( ) ( uint64 , * Chat ) {
chatID := contactIDFromPublicKey ( & m . identity . PublicKey )
chat , ok := m . allChats . Load ( chatID )
if ! ok {
chat = OneToOneFromPublicKey ( & m . identity . PublicKey , m . getTimesource ( ) )
// We don't want to show the chat to the user
chat . Active = false
}
m . allChats . Store ( chat . ID , chat )
clock , _ := chat . NextClockAndTimestamp ( m . getTimesource ( ) )
return clock , chat
}
2020-01-10 18:59:01 +00:00
// SendPairInstallation sends a pair installation message
func ( m * Messenger ) SendPairInstallation ( ctx context . Context ) ( * MessengerResponse , error ) {
var err error
var response MessengerResponse
2019-12-02 15:34:05 +00:00
2021-03-29 15:41:30 +00:00
installation , ok := m . allInstallations . Load ( m . installationID )
2020-01-10 18:59:01 +00:00
if ! ok {
return nil , errors . New ( "no installation found" )
2019-12-02 15:34:05 +00:00
}
2020-01-10 18:59:01 +00:00
if installation . InstallationMetadata == nil {
return nil , errors . New ( "no installation metadata" )
}
2021-08-06 15:40:23 +00:00
clock , chat := m . getLastClockWithRelatedChat ( )
2020-01-10 18:59:01 +00:00
pairMessage := & protobuf . PairInstallation {
Clock : clock ,
Name : installation . InstallationMetadata . Name ,
InstallationId : installation . ID ,
DeviceType : installation . InstallationMetadata . DeviceType }
encodedMessage , err := proto . Marshal ( pairMessage )
if err != nil {
return nil , err
}
2020-07-28 13:22:22 +00:00
_ , err = m . dispatchPairInstallationMessage ( ctx , common . RawMessage {
2021-08-06 15:40:23 +00:00
LocalChatID : chat . ID ,
2020-01-10 18:59:01 +00:00
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_PAIR_INSTALLATION ,
ResendAutomatically : true ,
} )
if err != nil {
return nil , err
}
2021-01-11 10:32:51 +00:00
response . AddChat ( chat )
2019-12-02 15:34:05 +00:00
2020-01-10 18:59:01 +00:00
chat . LastClockValue = clock
err = m . saveChat ( chat )
if err != nil {
return nil , err
}
return & response , nil
2019-12-02 15:34:05 +00:00
}
2020-01-15 07:25:09 +00:00
// syncPublicChat sync a public chat with paired devices
func ( m * Messenger ) syncPublicChat ( ctx context . Context , publicChat * Chat ) error {
var err error
if ! m . hasPairedDevices ( ) {
return nil
}
2021-08-06 15:40:23 +00:00
clock , chat := m . getLastClockWithRelatedChat ( )
2020-01-15 07:25:09 +00:00
syncMessage := & protobuf . SyncInstallationPublicChat {
Clock : clock ,
Id : publicChat . ID ,
}
encodedMessage , err := proto . Marshal ( syncMessage )
if err != nil {
return err
}
2020-07-28 13:22:22 +00:00
_ , err = m . dispatchMessage ( ctx , common . RawMessage {
2021-08-06 15:40:23 +00:00
LocalChatID : chat . ID ,
2020-01-15 07:25:09 +00:00
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_SYNC_INSTALLATION_PUBLIC_CHAT ,
ResendAutomatically : true ,
} )
if err != nil {
return err
}
chat . LastClockValue = clock
return m . saveChat ( chat )
}
2020-01-10 18:59:01 +00:00
// syncContact sync as contact with paired devices
func ( m * Messenger ) syncContact ( ctx context . Context , contact * Contact ) error {
var err error
2021-09-03 08:26:05 +00:00
if contact . IsSyncing {
return nil
}
2020-01-10 18:59:01 +00:00
if ! m . hasPairedDevices ( ) {
return nil
2019-12-02 15:34:05 +00:00
}
2021-08-06 15:40:23 +00:00
clock , chat := m . getLastClockWithRelatedChat ( )
2020-01-10 18:59:01 +00:00
2021-09-03 08:26:05 +00:00
var ensName string
if contact . ENSVerified {
ensName = contact . Name
}
oneToOneChat , ok := m . allChats . Load ( contact . ID )
muted := false
if ok {
muted = oneToOneChat . Muted
}
syncMessage := & protobuf . SyncInstallationContactV2 {
2020-08-20 14:06:38 +00:00
Clock : clock ,
Id : contact . ID ,
2021-09-03 08:26:05 +00:00
EnsName : ensName ,
2020-08-20 14:06:38 +00:00
LocalNickname : contact . LocalNickname ,
2021-09-03 08:26:05 +00:00
Added : contact . IsAdded ( ) ,
Blocked : contact . IsBlocked ( ) ,
Muted : muted ,
Removed : contact . Removed ,
2020-01-10 18:59:01 +00:00
}
2021-09-03 08:26:05 +00:00
2020-01-10 18:59:01 +00:00
encodedMessage , err := proto . Marshal ( syncMessage )
if err != nil {
return err
}
2020-07-28 13:22:22 +00:00
_ , err = m . dispatchMessage ( ctx , common . RawMessage {
2021-08-06 15:40:23 +00:00
LocalChatID : chat . ID ,
2020-01-10 18:59:01 +00:00
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_SYNC_INSTALLATION_CONTACT ,
ResendAutomatically : true ,
} )
if err != nil {
return err
}
chat . LastClockValue = clock
return m . saveChat ( chat )
}
2021-08-06 15:40:23 +00:00
func ( m * Messenger ) syncCommunity ( ctx context . Context , community * communities . Community ) error {
logger := m . logger . Named ( "syncCommunity" )
if ! m . hasPairedDevices ( ) {
logger . Debug ( "device has no paired devices" )
return nil
}
logger . Debug ( "device has paired device(s)" )
clock , chat := m . getLastClockWithRelatedChat ( )
syncMessage , err := community . ToSyncCommunityProtobuf ( clock )
if err != nil {
return err
}
encodedMessage , err := proto . Marshal ( syncMessage )
if err != nil {
return err
}
_ , err = m . dispatchMessage ( ctx , common . RawMessage {
LocalChatID : chat . ID ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_SYNC_INSTALLATION_COMMUNITY ,
ResendAutomatically : true ,
} )
if err != nil {
return err
}
logger . Debug ( "message dispatched" )
chat . LastClockValue = clock
return m . saveChat ( chat )
}
2020-01-10 18:59:01 +00:00
// RetrieveAll retrieves messages from all filters, processes them and returns a
// MessengerResponse to the client
func ( m * Messenger ) RetrieveAll ( ) ( * MessengerResponse , error ) {
chatWithMessages , err := m . transport . RetrieveRawAll ( )
if err != nil {
return nil , err
2019-12-02 15:34:05 +00:00
}
2020-01-10 18:59:01 +00:00
return m . handleRetrievedMessages ( chatWithMessages )
}
2021-08-03 19:27:15 +00:00
func ( m * Messenger ) GetStats ( ) types . StatsSummary {
return m . transport . GetStats ( )
}
2020-01-10 18:59:01 +00:00
type CurrentMessageState struct {
// Message is the protobuf message received
Message protobuf . ChatMessage
// MessageID is the ID of the message
MessageID string
// WhisperTimestamp is the whisper timestamp of the message
WhisperTimestamp uint64
// Contact is the contact associated with the author of the message
Contact * Contact
// PublicKey is the public key of the author of the message
PublicKey * ecdsa . PublicKey
}
type ReceivedMessageState struct {
// State on the message being processed
CurrentMessageState * CurrentMessageState
// AllChats in memory
2021-03-29 15:41:30 +00:00
AllChats * chatMap
2020-01-10 18:59:01 +00:00
// All contacts in memory
2021-03-29 15:41:30 +00:00
AllContacts * contactMap
2020-02-10 11:22:37 +00:00
// List of contacts modified
2021-03-29 15:41:30 +00:00
ModifiedContacts * stringBoolMap
2020-01-10 18:59:01 +00:00
// All installations in memory
2021-03-29 15:41:30 +00:00
AllInstallations * installationMap
2020-11-18 09:16:51 +00:00
// List of communities modified
2021-03-29 15:41:30 +00:00
ModifiedInstallations * stringBoolMap
2020-01-10 18:59:01 +00:00
// Map of existing messages
ExistingMessagesMap map [ string ] bool
2020-07-27 12:27:48 +00:00
// EmojiReactions is a list of emoji reactions for the current batch
// indexed by from-message-id-emoji-type
EmojiReactions map [ string ] * EmojiReaction
2020-08-07 13:49:37 +00:00
// GroupChatInvitations is a list of invitation requests or rejections
GroupChatInvitations map [ string ] * GroupChatInvitation
2020-01-10 18:59:01 +00:00
// Response to the client
Response * MessengerResponse
2020-02-07 11:30:26 +00:00
// Timesource is a time source for clock values/timestamps.
2020-11-18 09:16:51 +00:00
Timesource common . TimeSource
2019-12-02 15:34:05 +00:00
}
2021-02-23 15:47:45 +00:00
func ( m * Messenger ) markDeliveredMessages ( acks [ ] [ ] byte ) {
for _ , ack := range acks {
2021-03-09 12:48:15 +00:00
//get message ID from database by datasync ID, with at-least-one
// semantic
messageIDBytes , err := m . persistence . MarkAsConfirmed ( ack , true )
2021-02-23 15:47:45 +00:00
if err != nil {
m . logger . Info ( "got datasync acknowledge for message we don't have in db" , zap . String ( "ack" , hex . EncodeToString ( ack ) ) )
continue
}
2021-03-09 12:48:15 +00:00
messageID := messageIDBytes . String ( )
2021-02-23 15:47:45 +00:00
//mark messages as delivered
err = m . UpdateMessageOutgoingStatus ( messageID , common . OutgoingStatusDelivered )
if err != nil {
m . logger . Debug ( "Can't set message status as delivered" , zap . Error ( err ) )
}
//send signal to client that message status updated
2021-04-19 12:09:46 +00:00
if m . config . messengerSignalsHandler != nil {
2021-02-23 15:47:45 +00:00
message , err := m . persistence . MessageByID ( messageID )
if err != nil {
m . logger . Debug ( "Can't get message from database" , zap . Error ( err ) )
continue
}
2021-04-19 12:09:46 +00:00
m . config . messengerSignalsHandler . MessageDelivered ( message . LocalChatID , messageID )
2021-02-23 15:47:45 +00:00
}
}
}
2021-03-31 16:23:45 +00:00
// addNewMessageNotification takes a common.Message and generates a new NotificationBody and appends it to the
2021-02-23 07:37:08 +00:00
// []Response.Notifications if the message is m.New
2021-02-22 16:12:59 +00:00
func ( r * ReceivedMessageState ) addNewMessageNotification ( publicKey ecdsa . PublicKey , m * common . Message , responseTo * common . Message ) error {
2021-02-23 07:37:08 +00:00
if ! m . New {
return nil
}
pubKey , err := m . GetSenderPubKey ( )
if err != nil {
return err
}
contactID := contactIDFromPublicKey ( pubKey )
2021-03-29 15:41:30 +00:00
chat , ok := r . AllChats . Load ( m . LocalChatID )
if ! ok {
return fmt . Errorf ( "chat ID '%s' not present" , m . LocalChatID )
}
contact , ok := r . AllContacts . Load ( contactID )
if ! ok {
return fmt . Errorf ( "contact ID '%s' not present" , contactID )
}
2021-02-22 16:12:59 +00:00
2021-03-31 16:23:45 +00:00
if showMessageNotification ( publicKey , m , chat , responseTo ) {
notification , err := NewMessageNotification ( m . ID , m , chat , contact , r . AllContacts )
if err != nil {
return err
}
r . Response . AddNotification ( notification )
2021-02-22 16:12:59 +00:00
}
2021-02-23 07:37:08 +00:00
return nil
}
2021-05-29 17:05:25 +00:00
// addNewActivityCenterNotification takes a common.Message and generates a new ActivityCenterNotification and appends it to the
// []Response.ActivityCenterNotifications if the message is m.New
func ( r * ReceivedMessageState ) addNewActivityCenterNotification ( publicKey ecdsa . PublicKey , m * Messenger , message * common . Message , responseTo * common . Message ) error {
if ! message . New {
return nil
}
chat , ok := r . AllChats . Load ( message . LocalChatID )
if ! ok {
return fmt . Errorf ( "chat ID '%s' not present" , message . LocalChatID )
}
2021-06-11 20:14:05 +00:00
isNotification , notificationType := showMentionOrReplyActivityCenterNotification ( publicKey , message , chat , responseTo )
if isNotification {
2021-05-29 17:05:25 +00:00
notification := & ActivityCenterNotification {
2021-07-15 20:21:44 +00:00
ID : types . FromHex ( message . ID ) ,
Name : chat . Name ,
Message : message ,
ReplyMessage : responseTo ,
Type : notificationType ,
Timestamp : message . WhisperTimestamp ,
ChatID : chat . ID ,
Author : message . From ,
2021-05-29 17:05:25 +00:00
}
err := m . persistence . SaveActivityCenterNotification ( notification )
if err != nil {
m . logger . Warn ( "failed to save notification" , zap . Error ( err ) )
return err
}
r . Response . AddActivityCenterNotification ( notification )
}
return nil
}
2019-12-02 15:34:05 +00:00
func ( m * Messenger ) handleRetrievedMessages ( chatWithMessages map [ transport . Filter ] [ ] * types . Message ) ( * MessengerResponse , error ) {
2021-06-07 11:45:06 +00:00
response := & MessengerResponse { }
2020-01-10 18:59:01 +00:00
messageState := & ReceivedMessageState {
AllChats : m . allChats ,
AllContacts : m . allContacts ,
2021-03-29 15:41:30 +00:00
ModifiedContacts : new ( stringBoolMap ) ,
2020-01-10 18:59:01 +00:00
AllInstallations : m . allInstallations ,
ModifiedInstallations : m . modifiedInstallations ,
ExistingMessagesMap : make ( map [ string ] bool ) ,
2020-07-27 12:27:48 +00:00
EmojiReactions : make ( map [ string ] * EmojiReaction ) ,
2020-08-07 13:49:37 +00:00
GroupChatInvitations : make ( map [ string ] * GroupChatInvitation ) ,
2021-06-07 11:45:06 +00:00
Response : response ,
2020-01-20 16:44:32 +00:00
Timesource : m . getTimesource ( ) ,
2019-12-02 15:34:05 +00:00
}
logger := m . logger . With ( zap . String ( "site" , "RetrieveAll" ) )
2021-02-23 15:47:45 +00:00
2020-01-28 11:16:28 +00:00
for _ , messages := range chatWithMessages {
2021-01-08 15:21:25 +00:00
var processedMessages [ ] string
2019-10-09 14:22:53 +00:00
for _ , shhMessage := range messages {
2021-01-08 15:21:25 +00:00
// Indicates tha all messages in the batch have been processed correctly
allMessagesProcessed := true
2021-06-23 14:13:48 +00:00
statusMessages , acks , err := m . sender . HandleMessages ( shhMessage , true )
2019-09-02 09:29:06 +00:00
if err != nil {
logger . Info ( "failed to decode messages" , zap . Error ( err ) )
continue
}
2021-02-23 15:47:45 +00:00
m . markDeliveredMessages ( acks )
2019-09-26 07:01:17 +00:00
2020-03-09 06:19:23 +00:00
logger . Debug ( "processing messages further" , zap . Int ( "count" , len ( statusMessages ) ) )
2019-11-15 08:52:28 +00:00
for _ , msg := range statusMessages {
2019-12-02 15:34:05 +00:00
publicKey := msg . SigPubKey ( )
2020-07-31 12:22:05 +00:00
m . handleInstallations ( msg . Installations )
err := m . handleSharedSecrets ( msg . SharedSecrets )
if err != nil {
// log and continue, non-critical error
logger . Warn ( "failed to handle shared secrets" )
}
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
// Check for messages from blocked users
2020-01-15 07:25:09 +00:00
senderID := contactIDFromPublicKey ( publicKey )
2021-03-29 15:41:30 +00:00
if contact , ok := messageState . AllContacts . Load ( senderID ) ; ok && contact . IsBlocked ( ) {
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
continue
}
2021-02-23 15:47:45 +00:00
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
// Don't process duplicates
2019-12-02 15:34:05 +00:00
messageID := types . EncodeHex ( msg . ID )
2021-06-07 12:38:13 +00:00
exists , err := m . messageExists ( messageID , messageState . ExistingMessagesMap )
2019-12-02 15:34:05 +00:00
if err != nil {
logger . Warn ( "failed to check message exists" , zap . Error ( err ) )
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
}
2019-12-02 15:34:05 +00:00
if exists {
2020-08-18 15:07:48 +00:00
logger . Debug ( "messageExists" , zap . String ( "messageID" , messageID ) )
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
continue
}
var contact * Contact
2021-03-29 15:41:30 +00:00
if c , ok := messageState . AllContacts . Load ( senderID ) ; ok {
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
contact = c
} else {
2020-12-22 10:49:25 +00:00
c , err := buildContact ( senderID , publicKey )
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
if err != nil {
logger . Info ( "failed to build contact" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
continue
}
contact = c
2021-03-29 15:41:30 +00:00
messageState . AllContacts . Store ( senderID , contact )
messageState . ModifiedContacts . Store ( contact . ID , true )
2019-12-02 15:34:05 +00:00
}
2020-01-10 18:59:01 +00:00
messageState . CurrentMessageState = & CurrentMessageState {
2019-12-02 15:34:05 +00:00
MessageID : messageID ,
WhisperTimestamp : uint64 ( msg . TransportMessage . Timestamp ) * 1000 ,
Contact : contact ,
PublicKey : publicKey ,
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
}
2019-11-15 08:52:28 +00:00
if msg . ParsedMessage != nil {
2021-02-23 15:47:45 +00:00
2020-01-10 18:59:01 +00:00
logger . Debug ( "Handling parsed message" )
2020-07-27 10:13:22 +00:00
switch msg . ParsedMessage . Interface ( ) . ( type ) {
2019-12-02 15:34:05 +00:00
case protobuf . MembershipUpdateMessage :
2020-01-10 18:59:01 +00:00
logger . Debug ( "Handling MembershipUpdateMessage" )
2020-07-27 10:13:22 +00:00
rawMembershipUpdate := msg . ParsedMessage . Interface ( ) . ( protobuf . MembershipUpdateMessage )
2020-01-10 18:59:01 +00:00
2021-03-29 15:41:30 +00:00
chat , _ := messageState . AllChats . Load ( rawMembershipUpdate . ChatId )
2021-06-07 12:38:13 +00:00
err = m . HandleMembershipUpdate ( messageState , chat , rawMembershipUpdate , m . systemMessagesTranslations )
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
if err != nil {
2020-01-10 18:59:01 +00:00
logger . Warn ( "failed to handle MembershipUpdate" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
continue
}
2020-01-10 18:59:01 +00:00
case protobuf . ChatMessage :
logger . Debug ( "Handling ChatMessage" )
2020-07-27 10:13:22 +00:00
messageState . CurrentMessageState . Message = msg . ParsedMessage . Interface ( ) . ( protobuf . ChatMessage )
2021-06-07 12:38:13 +00:00
err = m . HandleChatMessage ( messageState )
2020-01-10 18:59:01 +00:00
if err != nil {
logger . Warn ( "failed to handle ChatMessage" , zap . Error ( err ) )
2021-06-07 11:45:06 +00:00
allMessagesProcessed = false
continue
}
case protobuf . EditMessage :
logger . Debug ( "Handling EditMessage" )
editProto := msg . ParsedMessage . Interface ( ) . ( protobuf . EditMessage )
editMessage := EditMessage {
EditMessage : editProto ,
From : contact . ID ,
ID : messageID ,
SigPubKey : publicKey ,
}
err = m . HandleEditMessage ( response , editMessage )
if err != nil {
logger . Warn ( "failed to handle EditMessage" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-01-10 18:59:01 +00:00
continue
}
2020-07-25 11:46:43 +00:00
2021-07-26 21:06:32 +00:00
case protobuf . DeleteMessage :
logger . Debug ( "Handling DeleteMessage" )
deleteProto := msg . ParsedMessage . Interface ( ) . ( protobuf . DeleteMessage )
deleteMessage := DeleteMessage {
DeleteMessage : deleteProto ,
From : contact . ID ,
ID : messageID ,
SigPubKey : publicKey ,
}
2021-08-19 13:16:45 +00:00
err = m . HandleDeleteMessage ( messageState , deleteMessage )
2021-07-26 21:06:32 +00:00
if err != nil {
logger . Warn ( "failed to handle DeleteMessage" , zap . Error ( err ) )
allMessagesProcessed = false
continue
}
2021-05-14 21:22:50 +00:00
case protobuf . PinMessage :
pinMessage := msg . ParsedMessage . Interface ( ) . ( protobuf . PinMessage )
2021-06-07 12:38:13 +00:00
err = m . HandlePinMessage ( messageState , pinMessage )
2021-05-14 21:22:50 +00:00
if err != nil {
logger . Warn ( "failed to handle PinMessage" , zap . Error ( err ) )
allMessagesProcessed = false
continue
}
2020-01-10 18:59:01 +00:00
case protobuf . PairInstallation :
2020-07-06 08:54:22 +00:00
if ! common . IsPubKeyEqual ( messageState . CurrentMessageState . PublicKey , & m . identity . PublicKey ) {
2020-01-10 18:59:01 +00:00
logger . Warn ( "not coming from us, ignoring" )
continue
}
2020-07-27 10:13:22 +00:00
p := msg . ParsedMessage . Interface ( ) . ( protobuf . PairInstallation )
2020-01-10 18:59:01 +00:00
logger . Debug ( "Handling PairInstallation" , zap . Any ( "message" , p ) )
2021-06-07 12:38:13 +00:00
err = m . HandlePairInstallation ( messageState , p )
2019-12-02 15:34:05 +00:00
if err != nil {
2020-01-10 18:59:01 +00:00
logger . Warn ( "failed to handle PairInstallation" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
continue
}
2021-07-22 17:41:49 +00:00
case protobuf . StatusUpdate :
p := msg . ParsedMessage . Interface ( ) . ( protobuf . StatusUpdate )
logger . Debug ( "Handling StatusUpdate" , zap . Any ( "message" , p ) )
err = m . HandleStatusUpdate ( messageState , p )
if err != nil {
logger . Warn ( "failed to handle StatusMessage" , zap . Error ( err ) )
allMessagesProcessed = false
continue
}
2020-01-10 18:59:01 +00:00
case protobuf . SyncInstallationContact :
2021-09-03 08:26:05 +00:00
logger . Warn ( "SyncInstallationContact is not supported" )
continue
case protobuf . SyncInstallationContactV2 :
2020-07-06 08:54:22 +00:00
if ! common . IsPubKeyEqual ( messageState . CurrentMessageState . PublicKey , & m . identity . PublicKey ) {
2020-01-10 18:59:01 +00:00
logger . Warn ( "not coming from us, ignoring" )
continue
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
}
2021-09-03 08:26:05 +00:00
p := msg . ParsedMessage . Interface ( ) . ( protobuf . SyncInstallationContactV2 )
2020-01-10 18:59:01 +00:00
logger . Debug ( "Handling SyncInstallationContact" , zap . Any ( "message" , p ) )
2021-06-07 12:38:13 +00:00
err = m . HandleSyncInstallationContact ( messageState , p )
2020-01-10 18:59:01 +00:00
if err != nil {
logger . Warn ( "failed to handle SyncInstallationContact" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-01-10 18:59:01 +00:00
continue
}
2020-07-25 11:46:43 +00:00
2020-01-15 07:25:09 +00:00
case protobuf . SyncInstallationPublicChat :
2020-07-06 08:54:22 +00:00
if ! common . IsPubKeyEqual ( messageState . CurrentMessageState . PublicKey , & m . identity . PublicKey ) {
2020-01-15 07:25:09 +00:00
logger . Warn ( "not coming from us, ignoring" )
continue
}
2020-07-27 10:13:22 +00:00
p := msg . ParsedMessage . Interface ( ) . ( protobuf . SyncInstallationPublicChat )
2020-01-15 07:25:09 +00:00
logger . Debug ( "Handling SyncInstallationPublicChat" , zap . Any ( "message" , p ) )
2021-06-07 12:38:13 +00:00
addedChat := m . HandleSyncInstallationPublicChat ( messageState , p )
2020-07-25 11:46:43 +00:00
2021-05-14 10:55:42 +00:00
// We join and re-register as we want to receive mentions from the newly joined public chat
if addedChat != nil {
2021-09-23 12:56:38 +00:00
_ , err = m . createPublicChat ( addedChat . ID , messageState . Response )
2021-05-14 10:55:42 +00:00
if err != nil {
allMessagesProcessed = false
logger . Error ( "error joining chat" , zap . Error ( err ) )
continue
}
2020-09-03 07:19:46 +00:00
}
2021-08-06 15:40:23 +00:00
case protobuf . SyncCommunity :
if ! common . IsPubKeyEqual ( messageState . CurrentMessageState . PublicKey , & m . identity . PublicKey ) {
logger . Warn ( "not coming from us, ignoring" )
continue
}
community := msg . ParsedMessage . Interface ( ) . ( protobuf . SyncCommunity )
logger . Debug ( "Handling SyncCommunity" , zap . Any ( "message" , community ) )
err = m . handleSyncCommunity ( messageState , community )
if err != nil {
logger . Warn ( "failed to handle SyncCommunity" , zap . Error ( err ) )
allMessagesProcessed = false
continue
}
2020-01-10 18:59:01 +00:00
case protobuf . RequestAddressForTransaction :
2020-07-27 10:13:22 +00:00
command := msg . ParsedMessage . Interface ( ) . ( protobuf . RequestAddressForTransaction )
2020-01-10 18:59:01 +00:00
logger . Debug ( "Handling RequestAddressForTransaction" , zap . Any ( "message" , command ) )
2021-06-07 12:38:13 +00:00
err = m . HandleRequestAddressForTransaction ( messageState , command )
2020-01-10 18:59:01 +00:00
if err != nil {
logger . Warn ( "failed to handle RequestAddressForTransaction" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-01-10 18:59:01 +00:00
continue
}
2020-07-25 11:46:43 +00:00
2020-01-10 18:59:01 +00:00
case protobuf . SendTransaction :
2020-07-27 10:13:22 +00:00
command := msg . ParsedMessage . Interface ( ) . ( protobuf . SendTransaction )
2020-01-10 18:59:01 +00:00
logger . Debug ( "Handling SendTransaction" , zap . Any ( "message" , command ) )
2021-06-07 12:38:13 +00:00
err = m . HandleSendTransaction ( messageState , command )
2020-01-10 18:59:01 +00:00
if err != nil {
logger . Warn ( "failed to handle SendTransaction" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-01-10 18:59:01 +00:00
continue
}
2020-07-25 11:46:43 +00:00
2020-01-10 18:59:01 +00:00
case protobuf . AcceptRequestAddressForTransaction :
2020-07-27 10:13:22 +00:00
command := msg . ParsedMessage . Interface ( ) . ( protobuf . AcceptRequestAddressForTransaction )
2020-01-10 18:59:01 +00:00
logger . Debug ( "Handling AcceptRequestAddressForTransaction" )
2021-06-07 12:38:13 +00:00
err = m . HandleAcceptRequestAddressForTransaction ( messageState , command )
2020-01-10 18:59:01 +00:00
if err != nil {
logger . Warn ( "failed to handle AcceptRequestAddressForTransaction" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-01-10 18:59:01 +00:00
continue
}
2019-12-02 15:34:05 +00:00
2020-01-10 18:59:01 +00:00
case protobuf . DeclineRequestAddressForTransaction :
2020-07-27 10:13:22 +00:00
command := msg . ParsedMessage . Interface ( ) . ( protobuf . DeclineRequestAddressForTransaction )
2020-01-10 18:59:01 +00:00
logger . Debug ( "Handling DeclineRequestAddressForTransaction" )
2021-06-07 12:38:13 +00:00
err = m . HandleDeclineRequestAddressForTransaction ( messageState , command )
2020-01-10 18:59:01 +00:00
if err != nil {
logger . Warn ( "failed to handle DeclineRequestAddressForTransaction" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-01-10 18:59:01 +00:00
continue
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
}
2020-01-10 18:59:01 +00:00
case protobuf . DeclineRequestTransaction :
2020-07-27 10:13:22 +00:00
command := msg . ParsedMessage . Interface ( ) . ( protobuf . DeclineRequestTransaction )
2020-01-10 18:59:01 +00:00
logger . Debug ( "Handling DeclineRequestTransaction" )
2021-06-07 12:38:13 +00:00
err = m . HandleDeclineRequestTransaction ( messageState , command )
2019-12-02 15:34:05 +00:00
if err != nil {
2020-01-10 18:59:01 +00:00
logger . Warn ( "failed to handle DeclineRequestTransaction" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2019-12-02 15:34:05 +00:00
continue
}
2020-01-10 18:59:01 +00:00
case protobuf . RequestTransaction :
2020-07-27 10:13:22 +00:00
command := msg . ParsedMessage . Interface ( ) . ( protobuf . RequestTransaction )
2021-04-07 12:57:14 +00:00
2020-01-10 18:59:01 +00:00
logger . Debug ( "Handling RequestTransaction" )
2021-06-07 12:38:13 +00:00
err = m . HandleRequestTransaction ( messageState , command )
2020-01-10 18:59:01 +00:00
if err != nil {
logger . Warn ( "failed to handle RequestTransaction" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-01-10 18:59:01 +00:00
continue
}
2020-07-25 11:46:43 +00:00
2020-01-10 18:59:01 +00:00
case protobuf . ContactUpdate :
2021-09-03 08:26:05 +00:00
if common . IsPubKeyEqual ( messageState . CurrentMessageState . PublicKey , & m . identity . PublicKey ) {
logger . Warn ( "coming from us, ignoring" )
continue
}
2020-07-27 10:13:22 +00:00
contactUpdate := msg . ParsedMessage . Interface ( ) . ( protobuf . ContactUpdate )
2021-06-07 12:38:13 +00:00
err = m . HandleContactUpdate ( messageState , contactUpdate )
2020-01-10 18:59:01 +00:00
if err != nil {
logger . Warn ( "failed to handle ContactUpdate" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-01-10 18:59:01 +00:00
continue
2019-12-02 15:34:05 +00:00
}
2020-07-06 08:54:22 +00:00
case protobuf . PushNotificationQuery :
logger . Debug ( "Received PushNotificationQuery" )
if m . pushNotificationServer == nil {
continue
}
logger . Debug ( "Handling PushNotificationQuery" )
2020-07-27 10:13:22 +00:00
if err := m . pushNotificationServer . HandlePushNotificationQuery ( publicKey , msg . ID , msg . ParsedMessage . Interface ( ) . ( protobuf . PushNotificationQuery ) ) ; err != nil {
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-07-06 08:54:22 +00:00
logger . Warn ( "failed to handle PushNotificationQuery" , zap . Error ( err ) )
}
// We continue in any case, no changes to messenger
continue
2020-07-09 16:52:26 +00:00
case protobuf . PushNotificationRegistrationResponse :
logger . Debug ( "Received PushNotificationRegistrationResponse" )
if m . pushNotificationClient == nil {
continue
}
logger . Debug ( "Handling PushNotificationRegistrationResponse" )
2020-07-27 10:13:22 +00:00
if err := m . pushNotificationClient . HandlePushNotificationRegistrationResponse ( publicKey , msg . ParsedMessage . Interface ( ) . ( protobuf . PushNotificationRegistrationResponse ) ) ; err != nil {
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-07-09 16:52:26 +00:00
logger . Warn ( "failed to handle PushNotificationRegistrationResponse" , zap . Error ( err ) )
}
// We continue in any case, no changes to messenger
continue
2020-07-31 13:46:27 +00:00
case protobuf . ContactCodeAdvertisement :
logger . Debug ( "Received ContactCodeAdvertisement" )
2020-11-18 12:41:36 +00:00
cca := msg . ParsedMessage . Interface ( ) . ( protobuf . ContactCodeAdvertisement )
if cca . ChatIdentity != nil {
logger . Debug ( "Received ContactCodeAdvertisement ChatIdentity" )
2021-06-07 12:38:13 +00:00
err = m . HandleChatIdentity ( messageState , * cca . ChatIdentity )
2020-11-18 12:41:36 +00:00
if err != nil {
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-11-18 12:41:36 +00:00
logger . Warn ( "failed to handle ContactCodeAdvertisement ChatIdentity" , zap . Error ( err ) )
// No continue as Chat Identity may fail but the rest of the cca may process fine.
}
}
2020-07-31 13:46:27 +00:00
if m . pushNotificationClient == nil {
continue
}
2020-08-18 15:07:48 +00:00
logger . Debug ( "Handling ContactCodeAdvertisement" )
2020-11-18 12:41:36 +00:00
if err := m . pushNotificationClient . HandleContactCodeAdvertisement ( publicKey , cca ) ; err != nil {
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-07-31 13:46:27 +00:00
logger . Warn ( "failed to handle ContactCodeAdvertisement" , zap . Error ( err ) )
}
2020-11-18 12:41:36 +00:00
2020-07-31 13:46:27 +00:00
// We continue in any case, no changes to messenger
continue
2020-07-20 08:06:24 +00:00
case protobuf . PushNotificationResponse :
logger . Debug ( "Received PushNotificationResponse" )
if m . pushNotificationClient == nil {
continue
}
logger . Debug ( "Handling PushNotificationResponse" )
2020-07-27 10:13:22 +00:00
if err := m . pushNotificationClient . HandlePushNotificationResponse ( publicKey , msg . ParsedMessage . Interface ( ) . ( protobuf . PushNotificationResponse ) ) ; err != nil {
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-07-20 08:06:24 +00:00
logger . Warn ( "failed to handle PushNotificationResponse" , zap . Error ( err ) )
}
// We continue in any case, no changes to messenger
continue
2020-07-09 16:52:26 +00:00
case protobuf . PushNotificationQueryResponse :
logger . Debug ( "Received PushNotificationQueryResponse" )
if m . pushNotificationClient == nil {
continue
}
logger . Debug ( "Handling PushNotificationQueryResponse" )
2020-07-27 10:13:22 +00:00
if err := m . pushNotificationClient . HandlePushNotificationQueryResponse ( publicKey , msg . ParsedMessage . Interface ( ) . ( protobuf . PushNotificationQueryResponse ) ) ; err != nil {
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-07-09 16:52:26 +00:00
logger . Warn ( "failed to handle PushNotificationQueryResponse" , zap . Error ( err ) )
}
// We continue in any case, no changes to messenger
continue
2020-07-06 08:54:22 +00:00
case protobuf . PushNotificationRequest :
logger . Debug ( "Received PushNotificationRequest" )
if m . pushNotificationServer == nil {
continue
}
logger . Debug ( "Handling PushNotificationRequest" )
2020-08-26 05:54:00 +00:00
if err := m . pushNotificationServer . HandlePushNotificationRequest ( publicKey , msg . ID , msg . ParsedMessage . Interface ( ) . ( protobuf . PushNotificationRequest ) ) ; err != nil {
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-07-06 08:54:22 +00:00
logger . Warn ( "failed to handle PushNotificationRequest" , zap . Error ( err ) )
}
// We continue in any case, no changes to messenger
continue
2020-07-24 13:47:58 +00:00
case protobuf . EmojiReaction :
2020-07-25 11:46:43 +00:00
logger . Debug ( "Handling EmojiReaction" )
2021-06-07 12:38:13 +00:00
err = m . HandleEmojiReaction ( messageState , msg . ParsedMessage . Interface ( ) . ( protobuf . EmojiReaction ) )
2020-07-24 13:47:58 +00:00
if err != nil {
logger . Warn ( "failed to handle EmojiReaction" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-07-24 13:47:58 +00:00
continue
}
2020-08-07 13:49:37 +00:00
case protobuf . GroupChatInvitation :
logger . Debug ( "Handling GroupChatInvitation" )
2021-06-07 12:38:13 +00:00
err = m . HandleGroupChatInvitation ( messageState , msg . ParsedMessage . Interface ( ) . ( protobuf . GroupChatInvitation ) )
2020-08-07 13:49:37 +00:00
if err != nil {
logger . Warn ( "failed to handle GroupChatInvitation" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-08-07 13:49:37 +00:00
continue
}
2020-11-18 12:41:36 +00:00
case protobuf . ChatIdentity :
2021-06-07 12:38:13 +00:00
err = m . HandleChatIdentity ( messageState , msg . ParsedMessage . Interface ( ) . ( protobuf . ChatIdentity ) )
2020-11-18 12:41:36 +00:00
if err != nil {
logger . Warn ( "failed to handle ChatIdentity" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-11-18 12:41:36 +00:00
continue
}
2020-07-06 08:54:22 +00:00
2020-11-18 09:16:51 +00:00
case protobuf . CommunityDescription :
logger . Debug ( "Handling CommunityDescription" )
2021-06-01 09:29:37 +00:00
err = m . handleCommunityDescription ( messageState , publicKey , msg . ParsedMessage . Interface ( ) . ( protobuf . CommunityDescription ) , msg . DecryptedPayload )
2020-11-18 09:16:51 +00:00
if err != nil {
logger . Warn ( "failed to handle CommunityDescription" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-11-18 09:16:51 +00:00
continue
}
2021-04-19 12:09:46 +00:00
//if community was among requested ones, send its info and remove filter
for communityID := range m . requestedCommunities {
if _ , ok := messageState . Response . communities [ communityID ] ; ok {
m . passStoredCommunityInfoToSignalHandler ( communityID )
}
}
2020-11-18 09:16:51 +00:00
case protobuf . CommunityInvitation :
logger . Debug ( "Handling CommunityInvitation" )
invitation := msg . ParsedMessage . Interface ( ) . ( protobuf . CommunityInvitation )
2021-06-07 12:38:13 +00:00
err = m . HandleCommunityInvitation ( messageState , publicKey , invitation , invitation . CommunityDescription )
2020-11-18 09:16:51 +00:00
if err != nil {
2021-01-11 10:32:51 +00:00
logger . Warn ( "failed to handle CommunityInvitation" , zap . Error ( err ) )
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-11-18 09:16:51 +00:00
continue
}
2021-01-11 10:32:51 +00:00
case protobuf . CommunityRequestToJoin :
logger . Debug ( "Handling CommunityRequestToJoin" )
request := msg . ParsedMessage . Interface ( ) . ( protobuf . CommunityRequestToJoin )
2021-06-07 12:38:13 +00:00
err = m . HandleCommunityRequestToJoin ( messageState , publicKey , request )
2021-01-11 10:32:51 +00:00
if err != nil {
logger . Warn ( "failed to handle CommunityRequestToJoin" , zap . Error ( err ) )
continue
}
2021-09-01 12:02:18 +00:00
case protobuf . AnonymousMetricBatch :
logger . Debug ( "Handling AnonymousMetricBatch" )
if m . anonMetricsServer == nil {
logger . Warn ( "unable to handle AnonymousMetricBatch, anonMetricsServer is nil" )
continue
}
ams , err := m . anonMetricsServer . StoreMetrics ( msg . ParsedMessage . Interface ( ) . ( protobuf . AnonymousMetricBatch ) )
if err != nil {
logger . Warn ( "failed to store AnonymousMetricBatch" , zap . Error ( err ) )
continue
}
messageState . Response . AnonymousMetrics = append ( messageState . Response . AnonymousMetrics , ams ... )
2019-12-02 15:34:05 +00:00
default :
2020-07-07 13:55:24 +00:00
// Check if is an encrypted PushNotificationRegistration
if msg . Type == protobuf . ApplicationMetadataMessage_PUSH_NOTIFICATION_REGISTRATION {
logger . Debug ( "Received PushNotificationRegistration" )
if m . pushNotificationServer == nil {
continue
}
logger . Debug ( "Handling PushNotificationRegistration" )
2020-07-27 10:13:22 +00:00
if err := m . pushNotificationServer . HandlePushNotificationRegistration ( publicKey , msg . ParsedMessage . Interface ( ) . ( [ ] byte ) ) ; err != nil {
2021-01-08 15:21:25 +00:00
allMessagesProcessed = false
2020-07-07 13:55:24 +00:00
logger . Warn ( "failed to handle PushNotificationRegistration" , zap . Error ( err ) )
}
// We continue in any case, no changes to messenger
continue
}
2020-07-27 10:13:22 +00:00
logger . Debug ( "message not handled" , zap . Any ( "messageType" , reflect . TypeOf ( msg . ParsedMessage . Interface ( ) ) ) )
2020-01-28 11:16:28 +00:00
2019-11-15 08:52:28 +00:00
}
2020-08-18 15:07:48 +00:00
} else {
logger . Debug ( "parsed message is nil" )
2019-11-15 08:52:28 +00:00
}
}
2021-01-08 15:21:25 +00:00
2021-01-11 10:32:51 +00:00
// Process any community changes
for _ , changes := range messageState . Response . CommunityChanges {
if changes . ShouldMemberJoin {
2021-07-22 17:41:49 +00:00
response , err := m . joinCommunity ( context . TODO ( ) , changes . Community . ID ( ) )
2021-01-11 10:32:51 +00:00
if err != nil {
logger . Error ( "cannot join community" , zap . Error ( err ) )
continue
}
if err := messageState . Response . Merge ( response ) ; err != nil {
logger . Error ( "cannot merge join community response" , zap . Error ( err ) )
continue
}
} else if changes . ShouldMemberLeave {
response , err := m . leaveCommunity ( changes . Community . ID ( ) )
if err != nil {
logger . Error ( "cannot join community" , zap . Error ( err ) )
continue
}
if err := messageState . Response . Merge ( response ) ; err != nil {
logger . Error ( "cannot merge join community response" , zap . Error ( err ) )
continue
}
}
}
// Clean up as not used by clients currently
messageState . Response . CommunityChanges = nil
2021-01-08 15:21:25 +00:00
if allMessagesProcessed {
processedMessages = append ( processedMessages , types . EncodeHex ( shhMessage . Hash ) )
}
}
if len ( processedMessages ) != 0 {
if err := m . transport . ConfirmMessagesProcessed ( processedMessages , m . getTimesource ( ) . GetCurrentTime ( ) ) ; err != nil {
logger . Warn ( "failed to confirm processed messages" , zap . Error ( err ) )
}
2019-09-02 09:29:06 +00:00
}
}
2020-04-17 11:22:38 +00:00
var contactsToSave [ ] * Contact
2021-03-29 15:41:30 +00:00
messageState . ModifiedContacts . Range ( func ( id string , value bool ) ( shouldContinue bool ) {
contact , ok := messageState . AllContacts . Load ( id )
if ok {
2020-04-17 11:22:38 +00:00
// We save all contacts so we can pull back name/image,
// but we only send to client those
// that have some custom fields
contactsToSave = append ( contactsToSave , contact )
if contact . HasCustomFields ( ) {
messageState . Response . Contacts = append ( messageState . Response . Contacts , contact )
}
}
2021-03-29 15:41:30 +00:00
return true
} )
2019-12-02 15:34:05 +00:00
2021-01-11 10:32:51 +00:00
// Hydrate chat alias and identicon
for id := range messageState . Response . chats {
2021-03-29 15:41:30 +00:00
chat , _ := messageState . AllChats . Load ( id )
2020-05-20 12:16:12 +00:00
if chat . OneToOne ( ) {
2021-03-29 15:41:30 +00:00
contact , ok := m . allContacts . Load ( chat . ID )
2020-05-20 12:16:12 +00:00
if ok {
chat . Alias = contact . Alias
chat . Identicon = contact . Identicon
}
}
2021-01-11 10:32:51 +00:00
messageState . Response . AddChat ( chat )
2020-05-20 12:16:12 +00:00
}
2021-03-29 15:41:30 +00:00
var err error
messageState . ModifiedInstallations . Range ( func ( id string , value bool ) ( shouldContinue bool ) {
installation , _ := messageState . AllInstallations . Load ( id )
2020-01-10 18:59:01 +00:00
messageState . Response . Installations = append ( messageState . Response . Installations , installation )
if installation . InstallationMetadata != nil {
2021-03-29 15:41:30 +00:00
err = m . setInstallationMetadata ( id , installation . InstallationMetadata )
2020-01-10 18:59:01 +00:00
if err != nil {
2021-03-29 15:41:30 +00:00
return false
2020-01-10 18:59:01 +00:00
}
}
2021-03-29 15:41:30 +00:00
return true
} )
if err != nil {
return nil , err
2019-09-26 07:01:17 +00:00
}
2021-01-11 10:32:51 +00:00
if len ( messageState . Response . chats ) > 0 {
err = m . saveChats ( messageState . Response . Chats ( ) )
2019-12-02 15:34:05 +00:00
if err != nil {
return nil , err
}
}
2021-01-11 10:32:51 +00:00
2021-05-27 17:24:04 +00:00
if len ( messageState . Response . pinMessages ) > 0 {
err = m . SavePinMessages ( messageState . Response . PinMessages ( ) )
2019-12-02 15:34:05 +00:00
if err != nil {
return nil , err
}
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
}
2021-05-27 17:24:04 +00:00
2021-06-03 13:11:55 +00:00
messagesToSave := messageState . Response . Messages ( )
if len ( messageState . Response . messages ) > 0 {
err = m . SaveMessages ( messagesToSave )
2021-05-14 21:22:50 +00:00
if err != nil {
return nil , err
}
}
2019-09-26 07:01:17 +00:00
2020-07-27 12:27:48 +00:00
for _ , emojiReaction := range messageState . EmojiReactions {
messageState . Response . EmojiReactions = append ( messageState . Response . EmojiReactions , emojiReaction )
}
2020-08-07 13:49:37 +00:00
for _ , groupChatInvitation := range messageState . GroupChatInvitations {
messageState . Response . Invitations = append ( messageState . Response . Invitations , groupChatInvitation )
}
2020-04-17 11:22:38 +00:00
if len ( contactsToSave ) > 0 {
err = m . persistence . SaveContacts ( contactsToSave )
2019-12-02 15:34:05 +00:00
if err != nil {
return nil , err
}
}
2019-09-26 07:01:17 +00:00
2020-11-10 15:08:32 +00:00
newMessagesIds := map [ string ] struct { } { }
2021-06-03 13:11:55 +00:00
for _ , message := range messagesToSave {
2021-06-25 08:30:18 +00:00
if message . New {
newMessagesIds [ message . ID ] = struct { } { }
}
2020-11-10 15:08:32 +00:00
}
2021-06-03 13:11:55 +00:00
messagesWithResponses , err := m . pullMessagesAndResponsesFromDB ( messagesToSave )
Add replies to messages
Currently replies to messages are handled in status-react.
This causes some issues with the fact that sometimes replies might come
out of order, they might be offloaded to the database etc.
This commit changes the behavior so that status-go always returns the
replies, and in case a reply comes out of order (first the reply, later
the message being replied to), it will include in the messages the
updated message.
It also adds some fields (RTL,Replace,LineCount) to the database which
were not previously saved, resulting in some potential bugs.
The method that we use to pull replies is currently a bit naive, we just
pull all the message again from the database, but has the advantage of
being simple. It will go through performance testing to make sure
performnace are acceptable, if so I think it's reasonable to avoid some
complexity.
2020-04-08 13:42:02 +00:00
if err != nil {
return nil , err
}
2021-02-22 16:12:59 +00:00
messagesByID := map [ string ] * common . Message { }
for _ , message := range messagesWithResponses {
messagesByID [ message . ID ] = message
}
2021-06-03 13:11:55 +00:00
messageState . Response . SetMessages ( messagesWithResponses )
Add replies to messages
Currently replies to messages are handled in status-react.
This causes some issues with the fact that sometimes replies might come
out of order, they might be offloaded to the database etc.
This commit changes the behavior so that status-go always returns the
replies, and in case a reply comes out of order (first the reply, later
the message being replied to), it will include in the messages the
updated message.
It also adds some fields (RTL,Replace,LineCount) to the database which
were not previously saved, resulting in some potential bugs.
The method that we use to pull replies is currently a bit naive, we just
pull all the message again from the database, but has the advantage of
being simple. It will go through performance testing to make sure
performnace are acceptable, if so I think it's reasonable to avoid some
complexity.
2020-04-08 13:42:02 +00:00
2021-03-31 16:23:45 +00:00
notificationsEnabled , err := m . settings . GetNotificationsEnabled ( )
if err != nil {
return nil , err
}
2021-06-03 13:11:55 +00:00
for _ , message := range messageState . Response . messages {
2020-11-10 15:08:32 +00:00
if _ , ok := newMessagesIds [ message . ID ] ; ok {
message . New = true
2021-02-23 07:37:08 +00:00
2021-03-31 16:23:45 +00:00
if notificationsEnabled {
// Create notification body to be eventually passed to `localnotifications.SendMessageNotifications()`
if err = messageState . addNewMessageNotification ( m . identity . PublicKey , message , messagesByID [ message . ResponseTo ] ) ; err != nil {
return nil , err
}
2021-02-23 07:37:08 +00:00
}
2021-05-29 17:05:25 +00:00
// Create activity center notification body to be eventually passed to `activitycenter.SendActivityCenterNotifications()`
if err = messageState . addNewActivityCenterNotification ( m . identity . PublicKey , m , message , messagesByID [ message . ResponseTo ] ) ; err != nil {
return nil , err
}
2020-11-10 15:08:32 +00:00
}
}
2020-01-10 18:59:01 +00:00
// Reset installations
2021-03-29 15:41:30 +00:00
m . modifiedInstallations = new ( stringBoolMap )
2020-01-10 18:59:01 +00:00
return messageState . Response , nil
2019-09-26 07:01:17 +00:00
}
2020-07-22 07:41:40 +00:00
// SetMailserver sets the currently used mailserver
2020-07-07 09:00:04 +00:00
func ( m * Messenger ) SetMailserver ( peer [ ] byte ) {
m . mailserver = peer
}
2019-11-06 16:23:11 +00:00
func ( m * Messenger ) RequestHistoricMessages (
ctx context . Context ,
from , to uint32 ,
cursor [ ] byte ,
2021-07-21 19:02:50 +00:00
storeCursor * types . StoreRequestCursor ,
2021-04-19 12:09:46 +00:00
waitForResponse bool ,
2021-07-21 19:02:50 +00:00
) ( [ ] byte , * types . StoreRequestCursor , error ) {
2021-04-19 12:09:46 +00:00
if m . mailserver == nil {
2021-07-21 19:02:50 +00:00
return nil , nil , errors . New ( "no mailserver selected" )
2021-04-19 12:09:46 +00:00
}
2021-07-21 19:02:50 +00:00
return m . transport . SendMessagesRequest ( ctx , m . mailserver , from , to , cursor , storeCursor , waitForResponse )
2021-04-19 12:09:46 +00:00
}
2020-09-01 13:27:01 +00:00
func ( m * Messenger ) MessageByID ( id string ) ( * common . Message , error ) {
2019-08-06 21:50:13 +00:00
return m . persistence . MessageByID ( id )
}
2019-08-20 11:20:25 +00:00
func ( m * Messenger ) MessagesExist ( ids [ ] string ) ( map [ string ] bool , error ) {
return m . persistence . MessagesExist ( ids )
2019-08-06 21:50:13 +00:00
}
2020-09-01 13:27:01 +00:00
func ( m * Messenger ) MessageByChatID ( chatID , cursor string , limit int ) ( [ ] * common . Message , string , error ) {
2020-11-03 10:16:05 +00:00
chat , err := m . persistence . Chat ( chatID )
if err != nil {
return nil , "" , err
}
if chat . Timeline ( ) {
var chatIDs = [ ] string { "@" + contactIDFromPublicKey ( & m . identity . PublicKey ) }
2021-01-27 09:33:50 +00:00
contacts , err := m . persistence . Contacts ( )
if err != nil {
return nil , "" , err
}
for _ , contact := range contacts {
2020-11-03 10:16:05 +00:00
if contact . IsAdded ( ) {
chatIDs = append ( chatIDs , "@" + contact . ID )
}
}
return m . persistence . MessageByChatIDs ( chatIDs , cursor , limit )
}
2020-11-05 16:07:24 +00:00
return m . persistence . MessageByChatID ( chatID , cursor , limit )
2019-08-06 21:50:13 +00:00
}
2021-08-04 19:31:44 +00:00
func ( m * Messenger ) AllMessageByChatIDWhichMatchTerm ( chatID string , searchTerm string , caseSensitive bool ) ( [ ] * common . Message , error ) {
_ , err := m . persistence . Chat ( chatID )
if err != nil {
return nil , err
}
return m . persistence . AllMessageByChatIDWhichMatchTerm ( chatID , searchTerm , caseSensitive )
}
2021-08-19 19:47:03 +00:00
func ( m * Messenger ) AllMessagesFromChatsAndCommunitiesWhichMatchTerm ( communityIds [ ] string , chatIds [ ] string , searchTerm string , caseSensitive bool ) ( [ ] * common . Message , error ) {
return m . persistence . AllMessagesFromChatsAndCommunitiesWhichMatchTerm ( communityIds , chatIds , searchTerm , caseSensitive )
}
2020-09-01 13:27:01 +00:00
func ( m * Messenger ) SaveMessages ( messages [ ] * common . Message ) error {
2020-05-20 12:16:12 +00:00
return m . persistence . SaveMessages ( messages )
2019-08-06 21:50:13 +00:00
}
2019-08-20 11:20:25 +00:00
func ( m * Messenger ) DeleteMessage ( id string ) error {
return m . persistence . DeleteMessage ( id )
2019-08-06 21:50:13 +00:00
}
2019-08-20 11:20:25 +00:00
func ( m * Messenger ) DeleteMessagesByChatID ( id string ) error {
return m . persistence . DeleteMessagesByChatID ( id )
2019-08-06 21:50:13 +00:00
}
2020-04-06 12:08:53 +00:00
// MarkMessagesSeen marks messages with `ids` as seen in the chat `chatID`.
// It returns the number of affected messages or error. If there is an error,
// the number of affected messages is always zero.
2021-08-31 08:49:39 +00:00
func ( m * Messenger ) MarkMessagesSeen ( chatID string , ids [ ] string ) ( uint64 , uint64 , error ) {
count , countWithMentions , err := m . persistence . MarkMessagesSeen ( chatID , ids )
2019-12-02 15:34:05 +00:00
if err != nil {
2021-08-31 08:49:39 +00:00
return 0 , 0 , err
2019-12-02 15:34:05 +00:00
}
chat , err := m . persistence . Chat ( chatID )
if err != nil {
2021-08-31 08:49:39 +00:00
return 0 , 0 , err
2019-12-02 15:34:05 +00:00
}
2021-03-29 15:41:30 +00:00
m . allChats . Store ( chatID , chat )
2021-08-31 08:49:39 +00:00
return count , countWithMentions , nil
2019-08-06 21:50:13 +00:00
}
2020-02-26 12:31:48 +00:00
func ( m * Messenger ) MarkAllRead ( chatID string ) error {
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2020-02-26 12:31:48 +00:00
if ! ok {
return errors . New ( "chat not found" )
}
err := m . persistence . MarkAllRead ( chatID )
if err != nil {
return err
}
chat . UnviewedMessagesCount = 0
2021-05-26 06:38:25 +00:00
chat . UnviewedMentionsCount = 0
2021-03-29 15:41:30 +00:00
// TODO(samyoul) remove storing of an updated reference pointer?
m . allChats . Store ( chat . ID , chat )
2020-02-26 12:31:48 +00:00
return nil
}
2021-09-20 06:33:36 +00:00
func ( m * Messenger ) MarkAllReadInCommunity ( communityID string ) ( [ ] string , error ) {
chatIDs , err := m . persistence . AllChatIDsByCommunity ( communityID )
if err != nil {
return nil , err
}
err = m . persistence . MarkAllReadMultiple ( chatIDs )
if err != nil {
return nil , err
}
for _ , chatID := range chatIDs {
chat , ok := m . allChats . Load ( chatID )
if ok {
chat . UnviewedMessagesCount = 0
chat . UnviewedMentionsCount = 0
m . allChats . Store ( chat . ID , chat )
} else {
err = errors . New ( fmt . Sprintf ( "chat with chatID %s not found" , chatID ) )
}
}
return chatIDs , err
}
2020-06-26 07:46:14 +00:00
// MuteChat signals to the messenger that we don't want to be notified
// on new messages from this chat
func ( m * Messenger ) MuteChat ( chatID string ) error {
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2020-06-26 07:46:14 +00:00
if ! ok {
2021-06-04 07:18:32 +00:00
// Only one to one chan be muted when it's not in the database
publicKey , err := common . HexToPubkey ( chatID )
if err != nil {
return err
}
// Create a one to one chat and set active to false
chat = CreateOneToOneChat ( chatID , publicKey , m . getTimesource ( ) )
chat . Active = false
err = m . initChatSyncFields ( chat )
if err != nil {
return err
}
err = m . saveChat ( chat )
if err != nil {
return err
}
2020-06-26 07:46:14 +00:00
}
2021-09-03 08:26:05 +00:00
var contact * Contact
if chat . OneToOne ( ) {
contact , _ = m . allContacts . Load ( chatID )
}
return m . muteChat ( chat , contact )
}
func ( m * Messenger ) muteChat ( chat * Chat , contact * Contact ) error {
m . logger . Info ( "MUTING" , zap . Any ( "CHAT ID" , chat . ID ) )
err := m . persistence . MuteChat ( chat . ID )
2020-06-26 07:46:14 +00:00
if err != nil {
return err
}
chat . Muted = true
2021-03-29 15:41:30 +00:00
// TODO(samyoul) remove storing of an updated reference pointer?
m . allChats . Store ( chat . ID , chat )
2020-08-18 15:07:48 +00:00
2021-09-03 08:26:05 +00:00
if contact != nil {
err := m . syncContact ( context . Background ( ) , contact )
if err != nil {
return err
}
}
2020-08-18 15:07:48 +00:00
return m . reregisterForPushNotifications ( )
2020-06-26 07:46:14 +00:00
}
// UnmuteChat signals to the messenger that we want to be notified
// on new messages from this chat
func ( m * Messenger ) UnmuteChat ( chatID string ) error {
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2020-06-26 07:46:14 +00:00
if ! ok {
return errors . New ( "chat not found" )
}
2021-09-03 08:26:05 +00:00
var contact * Contact
if chat . OneToOne ( ) {
contact , _ = m . allContacts . Load ( chatID )
}
return m . unmuteChat ( chat , contact )
}
func ( m * Messenger ) unmuteChat ( chat * Chat , contact * Contact ) error {
err := m . persistence . UnmuteChat ( chat . ID )
2020-06-26 07:46:14 +00:00
if err != nil {
return err
}
chat . Muted = false
2021-03-29 15:41:30 +00:00
// TODO(samyoul) remove storing of an updated reference pointer?
m . allChats . Store ( chat . ID , chat )
2021-09-03 08:26:05 +00:00
if contact != nil {
err := m . syncContact ( context . Background ( ) , contact )
if err != nil {
return err
}
}
2020-08-18 15:07:48 +00:00
return m . reregisterForPushNotifications ( )
2020-06-26 07:46:14 +00:00
}
2019-08-06 21:50:13 +00:00
func ( m * Messenger ) UpdateMessageOutgoingStatus ( id , newOutgoingStatus string ) error {
return m . persistence . UpdateMessageOutgoingStatus ( id , newOutgoingStatus )
}
2019-09-26 07:01:17 +00:00
// Identicon returns an identicon based on the input string
func Identicon ( id string ) ( string , error ) {
return identicon . GenerateBase64 ( id )
}
// GenerateAlias name returns the generated name given a public key hex encoded prefixed with 0x
func GenerateAlias ( id string ) ( string , error ) {
return alias . GenerateFromPublicKeyString ( id )
}
2020-01-10 18:59:01 +00:00
func ( m * Messenger ) RequestTransaction ( ctx context . Context , chatID , value , contract , address string ) ( * MessengerResponse , error ) {
var response MessengerResponse
// A valid added chat is required.
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2020-01-10 18:59:01 +00:00
if ! ok {
return nil , errors . New ( "Chat not found" )
}
if chat . ChatType != ChatTypeOneToOne {
return nil , errors . New ( "Need to be a one-to-one chat" )
}
2020-09-01 13:27:01 +00:00
message := & common . Message { }
2020-01-20 16:44:32 +00:00
err := extendMessageFromChat ( message , chat , & m . identity . PublicKey , m . transport )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-07-25 11:46:43 +00:00
message . MessageType = protobuf . MessageType_ONE_TO_ONE
2020-01-10 18:59:01 +00:00
message . ContentType = protobuf . ChatMessage_TRANSACTION_COMMAND
2020-12-07 15:13:39 +00:00
message . Seen = true
2020-01-10 18:59:01 +00:00
message . Text = "Request transaction"
request := & protobuf . RequestTransaction {
Clock : message . Clock ,
Address : address ,
Value : value ,
Contract : contract ,
2021-07-07 11:18:18 +00:00
ChatId : chatID ,
2020-01-10 18:59:01 +00:00
}
encodedMessage , err := proto . Marshal ( request )
if err != nil {
return nil , err
}
2021-01-22 13:59:45 +00:00
rawMessage , err := m . dispatchMessage ( ctx , common . RawMessage {
2020-01-10 18:59:01 +00:00
LocalChatID : chat . ID ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_REQUEST_TRANSACTION ,
ResendAutomatically : true ,
} )
2020-09-01 13:27:01 +00:00
message . CommandParameters = & common . CommandParameters {
2021-01-22 13:59:45 +00:00
ID : rawMessage . ID ,
2020-01-10 18:59:01 +00:00
Value : value ,
Address : address ,
Contract : contract ,
2020-09-01 13:27:01 +00:00
CommandState : common . CommandStateRequestTransaction ,
2020-01-10 18:59:01 +00:00
}
if err != nil {
return nil , err
}
2021-01-22 13:59:45 +00:00
messageID := rawMessage . ID
2020-01-10 18:59:01 +00:00
message . ID = messageID
message . CommandParameters . ID = messageID
2021-05-25 09:40:02 +00:00
err = message . PrepareContent ( common . PubkeyToHex ( & m . identity . PublicKey ) )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-01-20 16:44:32 +00:00
err = chat . UpdateFromMessage ( message , m . transport )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-09-01 13:27:01 +00:00
err = m . persistence . SaveMessages ( [ ] * common . Message { message } )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2021-06-25 08:30:18 +00:00
return m . addMessagesAndChat ( chat , [ ] * common . Message { message } , & response )
2020-01-10 18:59:01 +00:00
}
func ( m * Messenger ) RequestAddressForTransaction ( ctx context . Context , chatID , from , value , contract string ) ( * MessengerResponse , error ) {
var response MessengerResponse
// A valid added chat is required.
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2020-01-10 18:59:01 +00:00
if ! ok {
return nil , errors . New ( "Chat not found" )
}
if chat . ChatType != ChatTypeOneToOne {
return nil , errors . New ( "Need to be a one-to-one chat" )
}
2020-09-01 13:27:01 +00:00
message := & common . Message { }
2020-01-20 16:44:32 +00:00
err := extendMessageFromChat ( message , chat , & m . identity . PublicKey , m . transport )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-07-25 11:46:43 +00:00
message . MessageType = protobuf . MessageType_ONE_TO_ONE
2020-01-10 18:59:01 +00:00
message . ContentType = protobuf . ChatMessage_TRANSACTION_COMMAND
2020-12-07 15:13:39 +00:00
message . Seen = true
2020-01-10 18:59:01 +00:00
message . Text = "Request address for transaction"
request := & protobuf . RequestAddressForTransaction {
Clock : message . Clock ,
Value : value ,
Contract : contract ,
2021-07-07 11:18:18 +00:00
ChatId : chatID ,
2020-01-10 18:59:01 +00:00
}
encodedMessage , err := proto . Marshal ( request )
if err != nil {
return nil , err
}
2021-01-22 13:59:45 +00:00
rawMessage , err := m . dispatchMessage ( ctx , common . RawMessage {
2020-01-10 18:59:01 +00:00
LocalChatID : chat . ID ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_REQUEST_ADDRESS_FOR_TRANSACTION ,
ResendAutomatically : true ,
} )
2020-09-01 13:27:01 +00:00
message . CommandParameters = & common . CommandParameters {
2021-01-22 13:59:45 +00:00
ID : rawMessage . ID ,
2020-01-10 18:59:01 +00:00
From : from ,
Value : value ,
Contract : contract ,
2020-09-01 13:27:01 +00:00
CommandState : common . CommandStateRequestAddressForTransaction ,
2020-01-10 18:59:01 +00:00
}
if err != nil {
return nil , err
}
2021-01-22 13:59:45 +00:00
messageID := rawMessage . ID
2020-01-10 18:59:01 +00:00
message . ID = messageID
message . CommandParameters . ID = messageID
2021-05-25 09:40:02 +00:00
err = message . PrepareContent ( common . PubkeyToHex ( & m . identity . PublicKey ) )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-01-20 16:44:32 +00:00
err = chat . UpdateFromMessage ( message , m . transport )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-09-01 13:27:01 +00:00
err = m . persistence . SaveMessages ( [ ] * common . Message { message } )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2021-06-25 08:30:18 +00:00
return m . addMessagesAndChat ( chat , [ ] * common . Message { message } , & response )
2020-01-10 18:59:01 +00:00
}
func ( m * Messenger ) AcceptRequestAddressForTransaction ( ctx context . Context , messageID , address string ) ( * MessengerResponse , error ) {
var response MessengerResponse
message , err := m . MessageByID ( messageID )
if err != nil {
return nil , err
}
if message == nil {
return nil , errors . New ( "message not found" )
}
chatID := message . LocalChatID
// A valid added chat is required.
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2020-01-10 18:59:01 +00:00
if ! ok {
return nil , errors . New ( "Chat not found" )
}
if chat . ChatType != ChatTypeOneToOne {
return nil , errors . New ( "Need to be a one-to-one chat" )
}
2020-01-20 16:44:32 +00:00
clock , timestamp := chat . NextClockAndTimestamp ( m . transport )
2020-01-10 18:59:01 +00:00
message . Clock = clock
message . WhisperTimestamp = timestamp
message . Timestamp = timestamp
message . Text = "Request address for transaction accepted"
2020-12-07 15:13:39 +00:00
message . Seen = true
2020-09-01 13:27:01 +00:00
message . OutgoingStatus = common . OutgoingStatusSending
2020-01-10 18:59:01 +00:00
// Hide previous message
2020-01-17 12:39:09 +00:00
previousMessage , err := m . persistence . MessageByCommandID ( chatID , messageID )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
if previousMessage == nil {
return nil , errors . New ( "No previous message found" )
}
err = m . persistence . HideMessage ( previousMessage . ID )
if err != nil {
return nil , err
}
message . Replace = previousMessage . ID
request := & protobuf . AcceptRequestAddressForTransaction {
Clock : message . Clock ,
Id : messageID ,
Address : address ,
2021-07-07 11:18:18 +00:00
ChatId : chatID ,
2020-01-10 18:59:01 +00:00
}
encodedMessage , err := proto . Marshal ( request )
if err != nil {
return nil , err
}
2021-01-22 13:59:45 +00:00
rawMessage , err := m . dispatchMessage ( ctx , common . RawMessage {
2020-01-10 18:59:01 +00:00
LocalChatID : chat . ID ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION ,
ResendAutomatically : true ,
} )
if err != nil {
return nil , err
}
2021-01-22 13:59:45 +00:00
message . ID = rawMessage . ID
2020-01-10 18:59:01 +00:00
message . CommandParameters . Address = address
2020-09-01 13:27:01 +00:00
message . CommandParameters . CommandState = common . CommandStateRequestAddressForTransactionAccepted
2020-01-10 18:59:01 +00:00
2021-05-25 09:40:02 +00:00
err = message . PrepareContent ( common . PubkeyToHex ( & m . identity . PublicKey ) )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-01-20 16:44:32 +00:00
err = chat . UpdateFromMessage ( message , m . transport )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-09-01 13:27:01 +00:00
err = m . persistence . SaveMessages ( [ ] * common . Message { message } )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2021-06-25 08:30:18 +00:00
return m . addMessagesAndChat ( chat , [ ] * common . Message { message } , & response )
2020-01-10 18:59:01 +00:00
}
func ( m * Messenger ) DeclineRequestTransaction ( ctx context . Context , messageID string ) ( * MessengerResponse , error ) {
var response MessengerResponse
message , err := m . MessageByID ( messageID )
if err != nil {
return nil , err
}
if message == nil {
return nil , errors . New ( "message not found" )
}
chatID := message . LocalChatID
// A valid added chat is required.
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2020-01-10 18:59:01 +00:00
if ! ok {
return nil , errors . New ( "Chat not found" )
}
if chat . ChatType != ChatTypeOneToOne {
return nil , errors . New ( "Need to be a one-to-one chat" )
}
2020-01-20 16:44:32 +00:00
clock , timestamp := chat . NextClockAndTimestamp ( m . transport )
2020-01-10 18:59:01 +00:00
message . Clock = clock
message . WhisperTimestamp = timestamp
message . Timestamp = timestamp
message . Text = "Transaction request declined"
2020-12-07 15:13:39 +00:00
message . Seen = true
2020-09-01 13:27:01 +00:00
message . OutgoingStatus = common . OutgoingStatusSending
2020-01-10 18:59:01 +00:00
message . Replace = messageID
err = m . persistence . HideMessage ( messageID )
if err != nil {
return nil , err
}
request := & protobuf . DeclineRequestTransaction {
2021-07-07 11:18:18 +00:00
Clock : message . Clock ,
Id : messageID ,
ChatId : chatID ,
2020-01-10 18:59:01 +00:00
}
encodedMessage , err := proto . Marshal ( request )
if err != nil {
return nil , err
}
2021-01-22 13:59:45 +00:00
rawMessage , err := m . dispatchMessage ( ctx , common . RawMessage {
2020-01-10 18:59:01 +00:00
LocalChatID : chat . ID ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_DECLINE_REQUEST_TRANSACTION ,
ResendAutomatically : true ,
} )
if err != nil {
return nil , err
}
2021-01-22 13:59:45 +00:00
message . ID = rawMessage . ID
2020-09-01 13:27:01 +00:00
message . CommandParameters . CommandState = common . CommandStateRequestTransactionDeclined
2020-01-10 18:59:01 +00:00
2021-05-25 09:40:02 +00:00
err = message . PrepareContent ( common . PubkeyToHex ( & m . identity . PublicKey ) )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-01-20 16:44:32 +00:00
err = chat . UpdateFromMessage ( message , m . transport )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-09-01 13:27:01 +00:00
err = m . persistence . SaveMessages ( [ ] * common . Message { message } )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2021-06-25 08:30:18 +00:00
return m . addMessagesAndChat ( chat , [ ] * common . Message { message } , & response )
2020-01-10 18:59:01 +00:00
}
func ( m * Messenger ) DeclineRequestAddressForTransaction ( ctx context . Context , messageID string ) ( * MessengerResponse , error ) {
var response MessengerResponse
message , err := m . MessageByID ( messageID )
if err != nil {
return nil , err
}
if message == nil {
return nil , errors . New ( "message not found" )
}
chatID := message . LocalChatID
// A valid added chat is required.
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2020-01-10 18:59:01 +00:00
if ! ok {
return nil , errors . New ( "Chat not found" )
}
if chat . ChatType != ChatTypeOneToOne {
return nil , errors . New ( "Need to be a one-to-one chat" )
}
2020-01-20 16:44:32 +00:00
clock , timestamp := chat . NextClockAndTimestamp ( m . transport )
2020-01-10 18:59:01 +00:00
message . Clock = clock
message . WhisperTimestamp = timestamp
message . Timestamp = timestamp
message . Text = "Request address for transaction declined"
2020-12-07 15:13:39 +00:00
message . Seen = true
2020-09-01 13:27:01 +00:00
message . OutgoingStatus = common . OutgoingStatusSending
2020-01-10 18:59:01 +00:00
message . Replace = messageID
err = m . persistence . HideMessage ( messageID )
if err != nil {
return nil , err
}
request := & protobuf . DeclineRequestAddressForTransaction {
2021-07-07 11:18:18 +00:00
Clock : message . Clock ,
Id : messageID ,
ChatId : chatID ,
2020-01-10 18:59:01 +00:00
}
encodedMessage , err := proto . Marshal ( request )
if err != nil {
return nil , err
}
2021-01-22 13:59:45 +00:00
rawMessage , err := m . dispatchMessage ( ctx , common . RawMessage {
2020-01-10 18:59:01 +00:00
LocalChatID : chat . ID ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION ,
ResendAutomatically : true ,
} )
if err != nil {
return nil , err
}
2021-01-22 13:59:45 +00:00
message . ID = rawMessage . ID
2020-09-01 13:27:01 +00:00
message . CommandParameters . CommandState = common . CommandStateRequestAddressForTransactionDeclined
2020-01-10 18:59:01 +00:00
2021-05-25 09:40:02 +00:00
err = message . PrepareContent ( common . PubkeyToHex ( & m . identity . PublicKey ) )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-01-20 16:44:32 +00:00
err = chat . UpdateFromMessage ( message , m . transport )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-09-01 13:27:01 +00:00
err = m . persistence . SaveMessages ( [ ] * common . Message { message } )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2021-06-25 08:30:18 +00:00
return m . addMessagesAndChat ( chat , [ ] * common . Message { message } , & response )
2020-01-10 18:59:01 +00:00
}
func ( m * Messenger ) AcceptRequestTransaction ( ctx context . Context , transactionHash , messageID string , signature [ ] byte ) ( * MessengerResponse , error ) {
var response MessengerResponse
message , err := m . MessageByID ( messageID )
if err != nil {
return nil , err
}
if message == nil {
return nil , errors . New ( "message not found" )
}
chatID := message . LocalChatID
// A valid added chat is required.
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2020-01-10 18:59:01 +00:00
if ! ok {
return nil , errors . New ( "Chat not found" )
}
if chat . ChatType != ChatTypeOneToOne {
return nil , errors . New ( "Need to be a one-to-one chat" )
}
2020-01-20 16:44:32 +00:00
clock , timestamp := chat . NextClockAndTimestamp ( m . transport )
2020-01-10 18:59:01 +00:00
message . Clock = clock
message . WhisperTimestamp = timestamp
message . Timestamp = timestamp
2020-12-07 15:13:39 +00:00
message . Seen = true
2020-02-10 11:22:37 +00:00
message . Text = transactionSentTxt
2020-09-01 13:27:01 +00:00
message . OutgoingStatus = common . OutgoingStatusSending
2020-01-10 18:59:01 +00:00
// Hide previous message
2020-01-17 12:39:09 +00:00
previousMessage , err := m . persistence . MessageByCommandID ( chatID , messageID )
2020-10-08 10:46:03 +00:00
if err != nil && err != common . ErrRecordNotFound {
2020-01-10 18:59:01 +00:00
return nil , err
}
if previousMessage != nil {
err = m . persistence . HideMessage ( previousMessage . ID )
if err != nil {
return nil , err
}
message . Replace = previousMessage . ID
}
err = m . persistence . HideMessage ( messageID )
if err != nil {
return nil , err
}
request := & protobuf . SendTransaction {
Clock : message . Clock ,
Id : messageID ,
TransactionHash : transactionHash ,
Signature : signature ,
2021-07-07 11:18:18 +00:00
ChatId : chatID ,
2020-01-10 18:59:01 +00:00
}
encodedMessage , err := proto . Marshal ( request )
if err != nil {
return nil , err
}
2021-01-22 13:59:45 +00:00
rawMessage , err := m . dispatchMessage ( ctx , common . RawMessage {
2020-01-10 18:59:01 +00:00
LocalChatID : chat . ID ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_SEND_TRANSACTION ,
ResendAutomatically : true ,
} )
if err != nil {
return nil , err
}
2021-01-22 13:59:45 +00:00
message . ID = rawMessage . ID
2020-01-10 18:59:01 +00:00
message . CommandParameters . TransactionHash = transactionHash
message . CommandParameters . Signature = signature
2020-09-01 13:27:01 +00:00
message . CommandParameters . CommandState = common . CommandStateTransactionSent
2020-01-10 18:59:01 +00:00
2021-05-25 09:40:02 +00:00
err = message . PrepareContent ( common . PubkeyToHex ( & m . identity . PublicKey ) )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-01-20 16:44:32 +00:00
err = chat . UpdateFromMessage ( message , m . transport )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-09-01 13:27:01 +00:00
err = m . persistence . SaveMessages ( [ ] * common . Message { message } )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2021-06-25 08:30:18 +00:00
return m . addMessagesAndChat ( chat , [ ] * common . Message { message } , & response )
2020-01-10 18:59:01 +00:00
}
2020-01-15 07:25:09 +00:00
func ( m * Messenger ) SendTransaction ( ctx context . Context , chatID , value , contract , transactionHash string , signature [ ] byte ) ( * MessengerResponse , error ) {
2020-01-10 18:59:01 +00:00
var response MessengerResponse
// A valid added chat is required.
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2020-01-10 18:59:01 +00:00
if ! ok {
return nil , errors . New ( "Chat not found" )
}
if chat . ChatType != ChatTypeOneToOne {
return nil , errors . New ( "Need to be a one-to-one chat" )
}
2020-09-01 13:27:01 +00:00
message := & common . Message { }
2020-01-20 16:44:32 +00:00
err := extendMessageFromChat ( message , chat , & m . identity . PublicKey , m . transport )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-07-25 11:46:43 +00:00
message . MessageType = protobuf . MessageType_ONE_TO_ONE
2020-01-10 18:59:01 +00:00
message . ContentType = protobuf . ChatMessage_TRANSACTION_COMMAND
message . LocalChatID = chatID
2020-01-20 16:44:32 +00:00
clock , timestamp := chat . NextClockAndTimestamp ( m . transport )
2020-01-10 18:59:01 +00:00
message . Clock = clock
message . WhisperTimestamp = timestamp
2020-12-07 15:13:39 +00:00
message . Seen = true
2020-01-10 18:59:01 +00:00
message . Timestamp = timestamp
2020-02-10 11:22:37 +00:00
message . Text = transactionSentTxt
2020-01-10 18:59:01 +00:00
request := & protobuf . SendTransaction {
Clock : message . Clock ,
TransactionHash : transactionHash ,
Signature : signature ,
2021-07-07 11:18:18 +00:00
ChatId : chatID ,
2020-01-10 18:59:01 +00:00
}
encodedMessage , err := proto . Marshal ( request )
if err != nil {
return nil , err
}
2021-01-22 13:59:45 +00:00
rawMessage , err := m . dispatchMessage ( ctx , common . RawMessage {
2020-01-10 18:59:01 +00:00
LocalChatID : chat . ID ,
Payload : encodedMessage ,
MessageType : protobuf . ApplicationMetadataMessage_SEND_TRANSACTION ,
ResendAutomatically : true ,
} )
if err != nil {
return nil , err
}
2021-01-22 13:59:45 +00:00
message . ID = rawMessage . ID
2020-09-01 13:27:01 +00:00
message . CommandParameters = & common . CommandParameters {
2020-01-10 18:59:01 +00:00
TransactionHash : transactionHash ,
2020-01-15 07:25:09 +00:00
Value : value ,
Contract : contract ,
2020-01-10 18:59:01 +00:00
Signature : signature ,
2020-09-01 13:27:01 +00:00
CommandState : common . CommandStateTransactionSent ,
2020-01-10 18:59:01 +00:00
}
2021-05-25 09:40:02 +00:00
err = message . PrepareContent ( common . PubkeyToHex ( & m . identity . PublicKey ) )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-01-20 16:44:32 +00:00
err = chat . UpdateFromMessage ( message , m . transport )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-09-01 13:27:01 +00:00
err = m . persistence . SaveMessages ( [ ] * common . Message { message } )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2021-06-25 08:30:18 +00:00
return m . addMessagesAndChat ( chat , [ ] * common . Message { message } , & response )
2020-01-10 18:59:01 +00:00
}
func ( m * Messenger ) ValidateTransactions ( ctx context . Context , addresses [ ] types . Address ) ( * MessengerResponse , error ) {
if m . verifyTransactionClient == nil {
return nil , nil
}
logger := m . logger . With ( zap . String ( "site" , "ValidateTransactions" ) )
logger . Debug ( "Validating transactions" )
txs , err := m . persistence . TransactionsToValidate ( )
if err != nil {
logger . Error ( "Error pulling" , zap . Error ( err ) )
return nil , err
}
logger . Debug ( "Txs" , zap . Int ( "count" , len ( txs ) ) , zap . Any ( "txs" , txs ) )
var response MessengerResponse
validator := NewTransactionValidator ( addresses , m . persistence , m . verifyTransactionClient , m . logger )
responses , err := validator . ValidateTransactions ( ctx )
if err != nil {
logger . Error ( "Error validating" , zap . Error ( err ) )
return nil , err
}
for _ , validationResult := range responses {
2020-09-01 13:27:01 +00:00
var message * common . Message
2020-01-15 07:25:09 +00:00
chatID := contactIDFromPublicKey ( validationResult . Transaction . From )
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2020-01-10 18:59:01 +00:00
if ! ok {
2020-01-20 16:44:32 +00:00
chat = OneToOneFromPublicKey ( validationResult . Transaction . From , m . transport )
2020-01-10 18:59:01 +00:00
}
if validationResult . Message != nil {
message = validationResult . Message
} else {
2020-09-01 13:27:01 +00:00
message = & common . Message { }
2020-01-20 16:44:32 +00:00
err := extendMessageFromChat ( message , chat , & m . identity . PublicKey , m . transport )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
}
2020-07-25 11:46:43 +00:00
message . MessageType = protobuf . MessageType_ONE_TO_ONE
2020-01-10 18:59:01 +00:00
message . ContentType = protobuf . ChatMessage_TRANSACTION_COMMAND
message . LocalChatID = chatID
message . OutgoingStatus = ""
2020-01-20 16:44:32 +00:00
clock , timestamp := chat . NextClockAndTimestamp ( m . transport )
2020-01-10 18:59:01 +00:00
message . Clock = clock
message . Timestamp = timestamp
message . WhisperTimestamp = timestamp
message . Text = "Transaction received"
2020-04-06 12:08:53 +00:00
message . Seen = false
2020-01-10 18:59:01 +00:00
message . ID = validationResult . Transaction . MessageID
if message . CommandParameters == nil {
2020-09-01 13:27:01 +00:00
message . CommandParameters = & common . CommandParameters { }
2020-01-10 18:59:01 +00:00
} else {
message . CommandParameters = validationResult . Message . CommandParameters
}
message . CommandParameters . Value = validationResult . Value
message . CommandParameters . Contract = validationResult . Contract
message . CommandParameters . Address = validationResult . Address
2020-09-01 13:27:01 +00:00
message . CommandParameters . CommandState = common . CommandStateTransactionSent
2020-01-10 18:59:01 +00:00
message . CommandParameters . TransactionHash = validationResult . Transaction . TransactionHash
2021-05-25 09:40:02 +00:00
err = message . PrepareContent ( common . PubkeyToHex ( & m . identity . PublicKey ) )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-01-20 16:44:32 +00:00
err = chat . UpdateFromMessage ( message , m . transport )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
2020-01-17 12:39:09 +00:00
if len ( message . CommandParameters . ID ) != 0 {
// Hide previous message
previousMessage , err := m . persistence . MessageByCommandID ( chatID , message . CommandParameters . ID )
2020-10-08 10:46:03 +00:00
if err != nil && err != common . ErrRecordNotFound {
2020-01-10 18:59:01 +00:00
return nil , err
}
2020-01-17 12:39:09 +00:00
if previousMessage != nil {
err = m . persistence . HideMessage ( previousMessage . ID )
if err != nil {
return nil , err
}
message . Replace = previousMessage . ID
}
2020-01-10 18:59:01 +00:00
}
2021-06-03 13:11:55 +00:00
response . AddMessage ( message )
2021-03-29 15:41:30 +00:00
m . allChats . Store ( chat . ID , chat )
2021-01-11 10:32:51 +00:00
response . AddChat ( chat )
2020-01-10 18:59:01 +00:00
2021-02-23 07:37:08 +00:00
contact , err := m . getOrBuildContactFromMessage ( message )
if err != nil {
return nil , err
}
2021-03-31 16:23:45 +00:00
notificationsEnabled , err := m . settings . GetNotificationsEnabled ( )
if err != nil {
return nil , err
}
if notificationsEnabled {
notification , err := NewMessageNotification ( message . ID , message , chat , contact , m . allContacts )
if err != nil {
return nil , err
}
response . AddNotification ( notification )
}
2021-02-23 07:37:08 +00:00
2020-01-10 18:59:01 +00:00
}
2021-06-03 13:11:55 +00:00
if len ( response . messages ) > 0 {
err = m . SaveMessages ( response . Messages ( ) )
2020-01-10 18:59:01 +00:00
if err != nil {
return nil , err
}
}
return & response , nil
}
2020-01-20 16:44:32 +00:00
Add replies to messages
Currently replies to messages are handled in status-react.
This causes some issues with the fact that sometimes replies might come
out of order, they might be offloaded to the database etc.
This commit changes the behavior so that status-go always returns the
replies, and in case a reply comes out of order (first the reply, later
the message being replied to), it will include in the messages the
updated message.
It also adds some fields (RTL,Replace,LineCount) to the database which
were not previously saved, resulting in some potential bugs.
The method that we use to pull replies is currently a bit naive, we just
pull all the message again from the database, but has the advantage of
being simple. It will go through performance testing to make sure
performnace are acceptable, if so I think it's reasonable to avoid some
complexity.
2020-04-08 13:42:02 +00:00
// pullMessagesAndResponsesFromDB pulls all the messages and the one that have
// been replied to from the database
2020-09-01 13:27:01 +00:00
func ( m * Messenger ) pullMessagesAndResponsesFromDB ( messages [ ] * common . Message ) ( [ ] * common . Message , error ) {
Add replies to messages
Currently replies to messages are handled in status-react.
This causes some issues with the fact that sometimes replies might come
out of order, they might be offloaded to the database etc.
This commit changes the behavior so that status-go always returns the
replies, and in case a reply comes out of order (first the reply, later
the message being replied to), it will include in the messages the
updated message.
It also adds some fields (RTL,Replace,LineCount) to the database which
were not previously saved, resulting in some potential bugs.
The method that we use to pull replies is currently a bit naive, we just
pull all the message again from the database, but has the advantage of
being simple. It will go through performance testing to make sure
performnace are acceptable, if so I think it's reasonable to avoid some
complexity.
2020-04-08 13:42:02 +00:00
var messageIDs [ ] string
for _ , message := range messages {
messageIDs = append ( messageIDs , message . ID )
if len ( message . ResponseTo ) != 0 {
messageIDs = append ( messageIDs , message . ResponseTo )
}
}
// We pull from the database all the messages & replies involved,
// so we let the db build the correct messages
return m . persistence . MessagesByIDs ( messageIDs )
}
2020-03-20 08:32:13 +00:00
func ( m * Messenger ) SignMessage ( message string ) ( [ ] byte , error ) {
hash := crypto . TextHash ( [ ] byte ( message ) )
return crypto . Sign ( hash , m . identity )
}
2020-11-18 09:16:51 +00:00
func ( m * Messenger ) getTimesource ( ) common . TimeSource {
2020-01-20 16:44:32 +00:00
return m . transport
}
2020-02-07 11:30:26 +00:00
2020-07-22 07:41:40 +00:00
// AddPushNotificationsServer adds a push notification server
2020-08-20 09:05:39 +00:00
func ( m * Messenger ) AddPushNotificationsServer ( ctx context . Context , publicKey * ecdsa . PublicKey , serverType pushnotificationclient . ServerType ) error {
2020-07-07 09:00:04 +00:00
if m . pushNotificationClient == nil {
return errors . New ( "push notification client not enabled" )
}
2020-08-20 09:05:39 +00:00
return m . pushNotificationClient . AddPushNotificationsServer ( publicKey , serverType )
2020-07-07 09:00:04 +00:00
}
2020-07-17 11:41:49 +00:00
// RemovePushNotificationServer removes a push notification server
func ( m * Messenger ) RemovePushNotificationServer ( ctx context . Context , publicKey * ecdsa . PublicKey ) error {
if m . pushNotificationClient == nil {
return errors . New ( "push notification client not enabled" )
}
return m . pushNotificationClient . RemovePushNotificationServer ( publicKey )
}
2020-07-22 07:41:40 +00:00
// UnregisterFromPushNotifications unregister from any server
2020-07-15 12:43:15 +00:00
func ( m * Messenger ) UnregisterFromPushNotifications ( ctx context . Context ) error {
2020-07-16 07:45:42 +00:00
return m . pushNotificationClient . Unregister ( )
2020-07-15 12:43:15 +00:00
}
2020-07-22 07:41:40 +00:00
// DisableSendingPushNotifications signals the client not to send any push notification
2020-07-15 12:43:15 +00:00
func ( m * Messenger ) DisableSendingPushNotifications ( ) error {
if m . pushNotificationClient == nil {
return errors . New ( "push notification client not enabled" )
}
m . pushNotificationClient . DisableSending ( )
return nil
}
2020-07-22 07:41:40 +00:00
// EnableSendingPushNotifications signals the client to send push notifications
2020-07-15 12:43:15 +00:00
func ( m * Messenger ) EnableSendingPushNotifications ( ) error {
if m . pushNotificationClient == nil {
return errors . New ( "push notification client not enabled" )
}
m . pushNotificationClient . EnableSending ( )
return nil
}
2020-09-02 14:11:16 +00:00
func ( m * Messenger ) pushNotificationOptions ( ) * pushnotificationclient . RegistrationOptions {
2020-07-07 09:00:04 +00:00
var contactIDs [ ] * ecdsa . PublicKey
var mutedChatIDs [ ] string
2020-09-03 07:19:46 +00:00
var publicChatIDs [ ] string
2020-07-07 09:00:04 +00:00
2021-03-29 15:41:30 +00:00
m . allContacts . Range ( func ( contactID string , contact * Contact ) ( shouldContinue bool ) {
2020-09-03 09:54:05 +00:00
if contact . IsAdded ( ) && ! contact . IsBlocked ( ) {
2020-07-07 09:00:04 +00:00
pk , err := contact . PublicKey ( )
if err != nil {
m . logger . Warn ( "could not parse contact public key" )
2021-03-29 15:41:30 +00:00
return true
2020-07-07 09:00:04 +00:00
}
contactIDs = append ( contactIDs , pk )
} else if contact . IsBlocked ( ) {
mutedChatIDs = append ( mutedChatIDs , contact . ID )
}
2021-03-29 15:41:30 +00:00
return true
} )
m . allChats . Range ( func ( chatID string , chat * Chat ) ( shouldContinue bool ) {
2020-07-07 09:00:04 +00:00
if chat . Muted {
mutedChatIDs = append ( mutedChatIDs , chat . ID )
}
2021-09-01 09:03:45 +00:00
if chat . Active && ( chat . Public ( ) || chat . CommunityChat ( ) ) {
2020-09-03 07:19:46 +00:00
publicChatIDs = append ( publicChatIDs , chat . ID )
}
2021-03-29 15:41:30 +00:00
return true
} )
2021-08-31 08:49:39 +00:00
2020-09-02 14:11:16 +00:00
return & pushnotificationclient . RegistrationOptions {
2020-09-03 07:19:46 +00:00
ContactIDs : contactIDs ,
MutedChatIDs : mutedChatIDs ,
PublicChatIDs : publicChatIDs ,
2020-09-02 14:11:16 +00:00
}
2020-07-17 12:29:51 +00:00
}
// RegisterForPushNotification register deviceToken with any push notification server enabled
2020-07-30 08:24:30 +00:00
func ( m * Messenger ) RegisterForPushNotifications ( ctx context . Context , deviceToken , apnTopic string , tokenType protobuf . PushNotificationRegistration_TokenType ) error {
2020-07-17 12:29:51 +00:00
if m . pushNotificationClient == nil {
return errors . New ( "push notification client not enabled" )
}
2020-07-20 13:58:54 +00:00
m . mutex . Lock ( )
defer m . mutex . Unlock ( )
2020-07-17 12:29:51 +00:00
2020-09-02 14:11:16 +00:00
err := m . pushNotificationClient . Register ( deviceToken , apnTopic , tokenType , m . pushNotificationOptions ( ) )
2020-08-18 15:07:48 +00:00
if err != nil {
m . logger . Error ( "failed to register for push notifications" , zap . Error ( err ) )
return err
}
return nil
2020-07-07 09:00:04 +00:00
}
2020-07-22 07:41:40 +00:00
// RegisteredForPushNotifications returns whether we successfully registered with all the servers
2020-07-16 08:36:17 +00:00
func ( m * Messenger ) RegisteredForPushNotifications ( ) ( bool , error ) {
if m . pushNotificationClient == nil {
return false , errors . New ( "no push notification client" )
}
return m . pushNotificationClient . Registered ( )
}
2020-07-22 07:41:40 +00:00
// EnablePushNotificationsFromContactsOnly is used to indicate that we want to received push notifications only from contacts
2020-07-17 11:41:49 +00:00
func ( m * Messenger ) EnablePushNotificationsFromContactsOnly ( ) error {
if m . pushNotificationClient == nil {
return errors . New ( "no push notification client" )
}
2020-07-20 13:58:54 +00:00
m . mutex . Lock ( )
defer m . mutex . Unlock ( )
2020-07-17 11:41:49 +00:00
2020-09-02 14:11:16 +00:00
return m . pushNotificationClient . EnablePushNotificationsFromContactsOnly ( m . pushNotificationOptions ( ) )
2020-07-17 11:41:49 +00:00
}
2020-07-22 07:41:40 +00:00
// DisablePushNotificationsFromContactsOnly is used to indicate that we want to received push notifications from anyone
2020-07-17 11:41:49 +00:00
func ( m * Messenger ) DisablePushNotificationsFromContactsOnly ( ) error {
if m . pushNotificationClient == nil {
return errors . New ( "no push notification client" )
}
2020-07-20 13:58:54 +00:00
m . mutex . Lock ( )
defer m . mutex . Unlock ( )
2020-07-17 11:41:49 +00:00
2020-09-02 14:11:16 +00:00
return m . pushNotificationClient . DisablePushNotificationsFromContactsOnly ( m . pushNotificationOptions ( ) )
2020-07-17 11:41:49 +00:00
}
2020-09-03 07:30:03 +00:00
// EnablePushNotificationsBlockMentions is used to indicate that we dont want to received push notifications for mentions
func ( m * Messenger ) EnablePushNotificationsBlockMentions ( ) error {
if m . pushNotificationClient == nil {
return errors . New ( "no push notification client" )
}
m . mutex . Lock ( )
defer m . mutex . Unlock ( )
return m . pushNotificationClient . EnablePushNotificationsBlockMentions ( m . pushNotificationOptions ( ) )
}
// DisablePushNotificationsBlockMentions is used to indicate that we want to received push notifications for mentions
func ( m * Messenger ) DisablePushNotificationsBlockMentions ( ) error {
if m . pushNotificationClient == nil {
return errors . New ( "no push notification client" )
}
m . mutex . Lock ( )
defer m . mutex . Unlock ( )
return m . pushNotificationClient . DisablePushNotificationsBlockMentions ( m . pushNotificationOptions ( ) )
}
2020-08-20 09:05:39 +00:00
// GetPushNotificationsServers returns the servers used for push notifications
func ( m * Messenger ) GetPushNotificationsServers ( ) ( [ ] * pushnotificationclient . PushNotificationServer , error ) {
2020-07-16 08:36:17 +00:00
if m . pushNotificationClient == nil {
return nil , errors . New ( "no push notification client" )
}
return m . pushNotificationClient . GetServers ( )
}
2020-07-22 07:41:40 +00:00
// StartPushNotificationsServer initialize and start a push notification server, using the current messenger identity key
func ( m * Messenger ) StartPushNotificationsServer ( ) error {
2020-07-14 14:07:19 +00:00
if m . pushNotificationServer == nil {
2020-07-22 07:41:40 +00:00
pushNotificationServerPersistence := pushnotificationserver . NewSQLitePersistence ( m . database )
config := & pushnotificationserver . Config {
2020-08-20 07:26:00 +00:00
Enabled : true ,
2020-07-14 14:07:19 +00:00
Logger : m . logger ,
Identity : m . identity ,
}
2021-06-23 14:13:48 +00:00
m . pushNotificationServer = pushnotificationserver . New ( config , pushNotificationServerPersistence , m . sender )
2020-07-14 14:07:19 +00:00
}
return m . pushNotificationServer . Start ( )
}
2020-07-22 07:41:40 +00:00
// StopPushNotificationServer stops the push notification server if running
func ( m * Messenger ) StopPushNotificationsServer ( ) error {
2020-07-14 14:07:19 +00:00
m . pushNotificationServer = nil
return nil
}
2020-05-20 12:16:12 +00:00
func generateAliasAndIdenticon ( pk string ) ( string , string , error ) {
identicon , err := identicon . GenerateBase64 ( pk )
if err != nil {
return "" , "" , err
}
name , err := alias . GenerateFromPublicKeyString ( pk )
if err != nil {
return "" , "" , err
}
return name , identicon , nil
}
2020-07-20 17:06:38 +00:00
2020-07-27 12:27:48 +00:00
func ( m * Messenger ) SendEmojiReaction ( ctx context . Context , chatID , messageID string , emojiID protobuf . EmojiReaction_Type ) ( * MessengerResponse , error ) {
2020-07-20 17:06:38 +00:00
var response MessengerResponse
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( chatID )
2020-07-20 17:06:38 +00:00
if ! ok {
return nil , ErrChatNotFound
}
clock , _ := chat . NextClockAndTimestamp ( m . getTimesource ( ) )
2020-07-26 22:06:58 +00:00
emojiR := & EmojiReaction {
EmojiReaction : protobuf . EmojiReaction {
Clock : clock ,
MessageId : messageID ,
ChatId : chatID ,
2020-07-28 08:02:51 +00:00
Type : emojiID ,
2020-07-26 22:06:58 +00:00
} ,
2020-07-28 07:53:32 +00:00
LocalChatID : chatID ,
From : types . EncodeHex ( crypto . FromECDSAPub ( & m . identity . PublicKey ) ) ,
2020-07-20 17:06:38 +00:00
}
2020-07-26 22:06:58 +00:00
encodedMessage , err := m . encodeChatEntity ( chat , emojiR )
2020-07-20 17:06:38 +00:00
if err != nil {
return nil , err
}
2020-07-28 13:26:34 +00:00
_ , err = m . dispatchMessage ( ctx , common . RawMessage {
2021-01-15 17:47:30 +00:00
LocalChatID : chatID ,
Payload : encodedMessage ,
SkipGroupMessageWrap : true ,
MessageType : protobuf . ApplicationMetadataMessage_EMOJI_REACTION ,
2020-07-27 12:27:48 +00:00
// Don't resend using datasync, that would create quite a lot
// of traffic if clicking too eagelry
ResendAutomatically : false ,
2020-07-20 17:06:38 +00:00
} )
if err != nil {
return nil , err
}
response . EmojiReactions = [ ] * EmojiReaction { emojiR }
2021-01-11 10:32:51 +00:00
response . AddChat ( chat )
2020-07-20 17:06:38 +00:00
2020-07-21 23:42:55 +00:00
err = m . persistence . SaveEmojiReaction ( emojiR )
if err != nil {
2020-12-15 14:43:41 +00:00
return nil , errors . Wrap ( err , "Can't save emoji reaction in db" )
2020-07-21 23:42:55 +00:00
}
2020-07-20 17:06:38 +00:00
return & response , nil
}
2020-07-27 15:57:01 +00:00
func ( m * Messenger ) EmojiReactionsByChatID ( chatID string , cursor string , limit int ) ( [ ] * EmojiReaction , error ) {
2020-11-16 11:54:39 +00:00
chat , err := m . persistence . Chat ( chatID )
if err != nil {
return nil , err
}
if chat . Timeline ( ) {
var chatIDs = [ ] string { "@" + contactIDFromPublicKey ( & m . identity . PublicKey ) }
2021-03-29 15:41:30 +00:00
m . allContacts . Range ( func ( contactID string , contact * Contact ) ( shouldContinue bool ) {
2020-11-16 11:54:39 +00:00
if contact . IsAdded ( ) {
chatIDs = append ( chatIDs , "@" + contact . ID )
}
2021-03-29 15:41:30 +00:00
return true
} )
2020-11-16 11:54:39 +00:00
return m . persistence . EmojiReactionsByChatIDs ( chatIDs , cursor , limit )
}
2020-07-27 15:57:01 +00:00
return m . persistence . EmojiReactionsByChatID ( chatID , cursor , limit )
}
2020-07-22 00:38:01 +00:00
func ( m * Messenger ) SendEmojiReactionRetraction ( ctx context . Context , emojiReactionID string ) ( * MessengerResponse , error ) {
2020-07-27 12:27:48 +00:00
emojiR , err := m . persistence . EmojiReactionByID ( emojiReactionID )
2020-07-22 00:38:01 +00:00
if err != nil {
return nil , err
}
2020-07-22 00:57:44 +00:00
// Check that the sender is the key owner
pk := types . EncodeHex ( crypto . FromECDSAPub ( & m . identity . PublicKey ) )
2020-07-27 12:27:48 +00:00
if emojiR . From != pk {
2020-07-22 14:54:24 +00:00
return nil , errors . Errorf ( "identity mismatch, " +
"emoji reactions can only be retracted by the reaction sender, " +
2020-07-22 00:57:44 +00:00
"emoji reaction sent by '%s', current identity '%s'" ,
2020-07-27 12:27:48 +00:00
emojiR . From , pk ,
2020-07-22 00:57:44 +00:00
)
}
// Get chat and clock
2021-03-29 15:41:30 +00:00
chat , ok := m . allChats . Load ( emojiR . GetChatId ( ) )
2020-07-22 00:38:01 +00:00
if ! ok {
return nil , ErrChatNotFound
}
clock , _ := chat . NextClockAndTimestamp ( m . getTimesource ( ) )
2020-07-27 12:27:48 +00:00
// Update the relevant fields
emojiR . Clock = clock
emojiR . Retracted = true
encodedMessage , err := m . encodeChatEntity ( chat , emojiR )
2020-07-22 00:38:01 +00:00
if err != nil {
return nil , err
}
// Send the marshalled EmojiReactionRetraction protobuf
2020-07-28 13:26:34 +00:00
_ , err = m . dispatchMessage ( ctx , common . RawMessage {
2021-01-15 17:47:30 +00:00
LocalChatID : emojiR . GetChatId ( ) ,
Payload : encodedMessage ,
SkipGroupMessageWrap : true ,
MessageType : protobuf . ApplicationMetadataMessage_EMOJI_REACTION ,
2020-07-27 12:27:48 +00:00
// Don't resend using datasync, that would create quite a lot
// of traffic if clicking too eagelry
ResendAutomatically : false ,
2020-07-22 00:38:01 +00:00
} )
if err != nil {
return nil , err
}
2020-07-22 00:57:44 +00:00
// Update MessengerResponse
2020-07-22 00:38:01 +00:00
response := MessengerResponse { }
2020-07-27 12:27:48 +00:00
emojiR . Retracted = true
response . EmojiReactions = [ ] * EmojiReaction { emojiR }
2021-01-11 10:32:51 +00:00
response . AddChat ( chat )
2020-07-22 00:38:01 +00:00
2020-07-22 00:57:44 +00:00
// Persist retraction state for emoji reaction
2020-07-28 07:53:32 +00:00
err = m . persistence . SaveEmojiReaction ( emojiR )
2020-07-22 00:43:06 +00:00
if err != nil {
return nil , err
}
2020-07-22 00:38:01 +00:00
return & response , nil
2020-07-20 17:06:38 +00:00
}
2020-07-25 16:13:08 +00:00
2020-07-27 10:13:22 +00:00
func ( m * Messenger ) encodeChatEntity ( chat * Chat , message common . ChatEntity ) ( [ ] byte , error ) {
2020-07-25 16:13:08 +00:00
var encodedMessage [ ] byte
var err error
2020-07-26 22:10:08 +00:00
l := m . logger . With ( zap . String ( "site" , "Send" ) , zap . String ( "chatID" , chat . ID ) )
2020-07-25 16:13:08 +00:00
switch chat . ChatType {
case ChatTypeOneToOne :
2020-07-26 22:10:08 +00:00
l . Debug ( "sending private message" )
2020-07-25 16:13:08 +00:00
message . SetMessageType ( protobuf . MessageType_ONE_TO_ONE )
2020-07-26 22:06:58 +00:00
encodedMessage , err = proto . Marshal ( message . GetProtobuf ( ) )
2020-07-25 16:13:08 +00:00
if err != nil {
return nil , err
}
2021-09-01 12:02:18 +00:00
2020-10-20 15:10:28 +00:00
case ChatTypePublic , ChatTypeProfile :
2020-07-26 22:10:08 +00:00
l . Debug ( "sending public message" , zap . String ( "chatName" , chat . Name ) )
2020-07-25 16:13:08 +00:00
message . SetMessageType ( protobuf . MessageType_PUBLIC_GROUP )
2020-07-26 22:06:58 +00:00
encodedMessage , err = proto . Marshal ( message . GetProtobuf ( ) )
2020-07-25 16:13:08 +00:00
if err != nil {
return nil , err
}
2021-09-01 12:02:18 +00:00
2020-11-18 09:16:51 +00:00
case ChatTypeCommunityChat :
l . Debug ( "sending community chat message" , zap . String ( "chatName" , chat . Name ) )
// TODO: add grant
message . SetMessageType ( protobuf . MessageType_COMMUNITY_CHAT )
encodedMessage , err = proto . Marshal ( message . GetProtobuf ( ) )
if err != nil {
return nil , err
}
2021-09-01 12:02:18 +00:00
2020-07-25 16:13:08 +00:00
case ChatTypePrivateGroupChat :
message . SetMessageType ( protobuf . MessageType_PRIVATE_GROUP )
2020-07-26 22:10:08 +00:00
l . Debug ( "sending group message" , zap . String ( "chatName" , chat . Name ) )
2021-01-15 17:47:30 +00:00
if ! message . WrapGroupMessage ( ) {
encodedMessage , err = proto . Marshal ( message . GetProtobuf ( ) )
if err != nil {
return nil , err
}
} else {
2020-07-25 16:13:08 +00:00
2021-01-15 17:47:30 +00:00
group , err := newProtocolGroupFromChat ( chat )
if err != nil {
return nil , err
}
2020-07-25 16:13:08 +00:00
2021-06-23 14:13:48 +00:00
encodedMessage , err = m . sender . EncodeAbridgedMembershipUpdate ( group , message )
2021-01-15 17:47:30 +00:00
if err != nil {
return nil , err
}
2020-07-25 16:13:08 +00:00
}
default :
return nil , errors . New ( "chat type not supported" )
}
return encodedMessage , nil
}
2021-02-23 07:37:08 +00:00
func ( m * Messenger ) getOrBuildContactFromMessage ( msg * common . Message ) ( * Contact , error ) {
2021-03-29 15:41:30 +00:00
if c , ok := m . allContacts . Load ( msg . From ) ; ok {
2021-02-23 07:37:08 +00:00
return c , nil
}
senderPubKey , err := msg . GetSenderPubKey ( )
if err != nil {
return nil , err
}
senderID := contactIDFromPublicKey ( senderPubKey )
c , err := buildContact ( senderID , senderPubKey )
if err != nil {
return nil , err
}
2021-03-29 15:41:30 +00:00
// TODO(samyoul) remove storing of an updated reference pointer?
m . allContacts . Store ( msg . From , c )
2021-02-23 07:37:08 +00:00
return c , nil
}
2021-08-26 20:25:43 +00:00
func ( m * Messenger ) BloomFilter ( ) [ ] byte {
return m . transport . BloomFilter ( )
}
2021-02-09 13:58:21 +00:00
func ( m * Messenger ) getSettings ( ) ( accounts . Settings , error ) {
sDB := accounts . NewDB ( m . database )
return sDB . GetSettings ( )
}