Merge branch 'feature/push-notification-mentions' into develop
This commit is contained in:
commit
19a82f68ad
|
@ -15,6 +15,8 @@
|
|||
// 0008_add_push_notifications.up.sql (349B)
|
||||
// 0009_enable_sending_push_notifications.down.sql (49B)
|
||||
// 0009_enable_sending_push_notifications.up.sql (49B)
|
||||
// 0010_add_block_mentions.down.sql (83B)
|
||||
// 0010_add_block_mentions.up.sql (89B)
|
||||
// doc.go (74B)
|
||||
|
||||
package migrations
|
||||
|
@ -359,7 +361,7 @@ func _0009_enable_sending_push_notificationsDownSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "0009_enable_sending_push_notifications.down.sql", size: 49, mode: os.FileMode(0644), modTime: time.Unix(1597918101, 0)}
|
||||
info := bindataFileInfo{name: "0009_enable_sending_push_notifications.down.sql", size: 49, mode: os.FileMode(0644), modTime: time.Unix(1598949727, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe9, 0xae, 0x1b, 0x41, 0xcb, 0x9c, 0x2c, 0x93, 0xc6, 0x2a, 0x77, 0x3, 0xb9, 0x51, 0xe0, 0x68, 0x68, 0x0, 0xf7, 0x5b, 0xb3, 0x1e, 0x94, 0x44, 0xba, 0x9c, 0xd0, 0x3b, 0x80, 0x21, 0x6f, 0xb5}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -379,11 +381,51 @@ func _0009_enable_sending_push_notificationsUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "0009_enable_sending_push_notifications.up.sql", size: 49, mode: os.FileMode(0644), modTime: time.Unix(1597918090, 0)}
|
||||
info := bindataFileInfo{name: "0009_enable_sending_push_notifications.up.sql", size: 49, mode: os.FileMode(0644), modTime: time.Unix(1598949727, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1b, 0x80, 0xe4, 0x9c, 0xc8, 0xb8, 0xd5, 0xef, 0xce, 0x74, 0x9b, 0x7b, 0xdd, 0xa, 0x99, 0x1e, 0xef, 0x7f, 0xb8, 0x99, 0x84, 0x4, 0x0, 0x6b, 0x1d, 0x2c, 0xa, 0xf8, 0x2c, 0x4f, 0xb5, 0x44}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __0010_add_block_mentionsDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x28\x4e\x2d\x29\xc9\xcc\x4b\x2f\x56\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\x28\x28\x2d\xce\x88\xcf\xcb\x2f\xc9\x4c\xcb\x4c\x4e\x2c\xc9\xcc\xcf\x2b\x8e\x4f\xca\xc9\x4f\xce\x8e\xcf\x4d\xcd\x03\x73\x15\x9c\xfc\xfd\x7d\x5c\x1d\xfd\x14\x5c\x5c\xdd\x1c\x43\x7d\x42\x14\xdc\x1c\x7d\x82\x5d\xad\xb9\x00\x01\x00\x00\xff\xff\xa8\x45\x75\x3b\x53\x00\x00\x00")
|
||||
|
||||
func _0010_add_block_mentionsDownSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__0010_add_block_mentionsDownSql,
|
||||
"0010_add_block_mentions.down.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _0010_add_block_mentionsDownSql() (*asset, error) {
|
||||
bytes, err := _0010_add_block_mentionsDownSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "0010_add_block_mentions.down.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1599117686, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6d, 0x9e, 0x27, 0x1e, 0xba, 0x9f, 0xca, 0xae, 0x98, 0x2e, 0x6e, 0xe3, 0xdd, 0xac, 0x73, 0x34, 0x4e, 0x69, 0x92, 0xb5, 0xf6, 0x9, 0xab, 0x50, 0x35, 0xd, 0xee, 0xeb, 0x3e, 0xcc, 0x7e, 0xce}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __0010_add_block_mentionsUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x1c\xc7\x31\x0a\x42\x31\x0c\x06\xe0\xdd\x53\xfc\xf7\x70\xca\xb3\x79\x53\x7c\x05\x6d\xe7\xa2\xa5\x6a\x50\x53\x21\xf1\xfe\x82\xe3\x47\x52\xf8\x84\x42\x8b\x30\x7c\x44\xa8\xdd\x1d\x94\x12\x0e\x59\xea\x71\xc3\xe7\xeb\x8f\x66\x33\xf4\xa6\xfd\x12\x3a\xcd\xdb\xf5\x35\xfb\xb3\xbd\x87\xfd\x89\x25\x67\x61\xda\x90\x78\xa5\x2a\x05\x2b\xc9\x99\xf7\xbb\x5f\x00\x00\x00\xff\xff\x2b\x4e\x3f\xc5\x59\x00\x00\x00")
|
||||
|
||||
func _0010_add_block_mentionsUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__0010_add_block_mentionsUpSql,
|
||||
"0010_add_block_mentions.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _0010_add_block_mentionsUpSql() (*asset, error) {
|
||||
bytes, err := _0010_add_block_mentionsUpSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "0010_add_block_mentions.up.sql", size: 89, mode: os.FileMode(0644), modTime: time.Unix(1599118789, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd7, 0x23, 0x85, 0xa2, 0xb5, 0xb6, 0xb4, 0x3f, 0xdc, 0x4e, 0xff, 0xe2, 0x6b, 0x66, 0x68, 0x5e, 0xb2, 0xb4, 0x14, 0xb2, 0x1b, 0x4d, 0xb1, 0xce, 0xf7, 0x6, 0x58, 0xa7, 0xaf, 0x93, 0x3f, 0x25}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2c\xc9\xb1\x0d\xc4\x20\x0c\x05\xd0\x9e\x29\xfe\x02\xd8\xfd\x6d\xe3\x4b\xac\x2f\x44\x82\x09\x78\x7f\xa5\x49\xfd\xa6\x1d\xdd\xe8\xd8\xcf\x55\x8a\x2a\xe3\x47\x1f\xbe\x2c\x1d\x8c\xfa\x6f\xe3\xb4\x34\xd4\xd9\x89\xbb\x71\x59\xb6\x18\x1b\x35\x20\xa2\x9f\x0a\x03\xa2\xe5\x0d\x00\x00\xff\xff\x60\xcd\x06\xbe\x4a\x00\x00\x00")
|
||||
|
||||
func docGoBytes() ([]byte, error) {
|
||||
|
@ -525,6 +567,10 @@ var _bindata = map[string]func() (*asset, error){
|
|||
|
||||
"0009_enable_sending_push_notifications.up.sql": _0009_enable_sending_push_notificationsUpSql,
|
||||
|
||||
"0010_add_block_mentions.down.sql": _0010_add_block_mentionsDownSql,
|
||||
|
||||
"0010_add_block_mentions.up.sql": _0010_add_block_mentionsUpSql,
|
||||
|
||||
"doc.go": docGo,
|
||||
}
|
||||
|
||||
|
@ -584,7 +630,9 @@ var _bintree = &bintree{nil, map[string]*bintree{
|
|||
"0008_add_push_notifications.up.sql": &bintree{_0008_add_push_notificationsUpSql, map[string]*bintree{}},
|
||||
"0009_enable_sending_push_notifications.down.sql": &bintree{_0009_enable_sending_push_notificationsDownSql, map[string]*bintree{}},
|
||||
"0009_enable_sending_push_notifications.up.sql": &bintree{_0009_enable_sending_push_notificationsUpSql, map[string]*bintree{}},
|
||||
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||
"0010_add_block_mentions.down.sql": &bintree{_0010_add_block_mentionsDownSql, map[string]*bintree{}},
|
||||
"0010_add_block_mentions.up.sql": &bintree{_0010_add_block_mentionsUpSql, map[string]*bintree{}},
|
||||
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||
}}
|
||||
|
||||
// RestoreAsset restores an asset under the given directory.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
ALTER settings ADD COLUMN push_notifications_block_mentions BOOLEAN DEFAULT FALSE;
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE settings ADD COLUMN push_notifications_block_mentions BOOLEAN DEFAULT FALSE;
|
|
@ -70,7 +70,9 @@ type Settings struct {
|
|||
PushNotificationsServerEnabled bool `json:"push-notifications-server-enabled?,omitempty"`
|
||||
// PushNotificationsFromContactsOnly indicates whether we should only receive push notifications from contacts
|
||||
PushNotificationsFromContactsOnly bool `json:"push-notifications-from-contacts-only?,omitempty"`
|
||||
RememberSyncingChoice bool `json:"remember-syncing-choice?,omitempty"`
|
||||
// PushNotificationsBlockMentions indicates whether we should receive notifications for mentions
|
||||
PushNotificationsBlockMentions bool `json:"push-notifications-block-mentions?,omitempty"`
|
||||
RememberSyncingChoice bool `json:"remember-syncing-choice?,omitempty"`
|
||||
// RemotePushNotificationsEnabled indicates whether we should be using remote notifications (ios only for now)
|
||||
RemotePushNotificationsEnabled bool `json:"remote-push-notifications-enabled?,omitempty"`
|
||||
SigningPhrase string `json:"signing-phrase"`
|
||||
|
@ -273,6 +275,12 @@ func (db *Database) SaveSetting(setting string, value interface{}) error {
|
|||
return ErrInvalidConfig
|
||||
}
|
||||
update, err = db.db.Prepare("UPDATE settings SET push_notifications_from_contacts_only = ? WHERE synthetic_id = 'id'")
|
||||
case "push-notifications-block-mentions?":
|
||||
_, ok := value.(bool)
|
||||
if !ok {
|
||||
return ErrInvalidConfig
|
||||
}
|
||||
update, err = db.db.Prepare("UPDATE settings SET push_notifications_block_mentions = ? WHERE synthetic_id = 'id'")
|
||||
case "send-push-notifications?":
|
||||
_, ok := value.(bool)
|
||||
if !ok {
|
||||
|
@ -337,7 +345,7 @@ func (db *Database) GetNodeConfig(nodecfg interface{}) error {
|
|||
|
||||
func (db *Database) GetSettings() (Settings, error) {
|
||||
var s Settings
|
||||
err := db.db.QueryRow("SELECT address, chaos_mode, currency, current_network, custom_bootnodes, custom_bootnodes_enabled, dapps_address, eip1581_address, fleet, hide_home_tooltip, installation_id, key_uid, keycard_instance_uid, keycard_paired_on, keycard_pairing, last_updated, latest_derived_path, log_level, mnemonic, name, networks, notifications_enabled, push_notifications_server_enabled, push_notifications_from_contacts_only, remote_push_notifications_enabled, send_push_notifications, photo_path, pinned_mailservers, preferred_name, preview_privacy, public_key, remember_syncing_choice, signing_phrase, stickers_packs_installed, stickers_packs_pending, stickers_recent_stickers, syncing_on_mobile_network, usernames, appearance, wallet_root_address, wallet_set_up_passed, wallet_visible_tokens, waku_enabled, waku_bloom_filter_mode FROM settings WHERE synthetic_id = 'id'").Scan(
|
||||
err := db.db.QueryRow("SELECT address, chaos_mode, currency, current_network, custom_bootnodes, custom_bootnodes_enabled, dapps_address, eip1581_address, fleet, hide_home_tooltip, installation_id, key_uid, keycard_instance_uid, keycard_paired_on, keycard_pairing, last_updated, latest_derived_path, log_level, mnemonic, name, networks, notifications_enabled, push_notifications_server_enabled, push_notifications_from_contacts_only, remote_push_notifications_enabled, send_push_notifications, push_notifications_block_mentions, photo_path, pinned_mailservers, preferred_name, preview_privacy, public_key, remember_syncing_choice, signing_phrase, stickers_packs_installed, stickers_packs_pending, stickers_recent_stickers, syncing_on_mobile_network, usernames, appearance, wallet_root_address, wallet_set_up_passed, wallet_visible_tokens, waku_enabled, waku_bloom_filter_mode FROM settings WHERE synthetic_id = 'id'").Scan(
|
||||
&s.Address,
|
||||
&s.ChaosMode,
|
||||
&s.Currency,
|
||||
|
@ -364,6 +372,7 @@ func (db *Database) GetSettings() (Settings, error) {
|
|||
&s.PushNotificationsFromContactsOnly,
|
||||
&s.RemotePushNotificationsEnabled,
|
||||
&s.SendPushNotifications,
|
||||
&s.PushNotificationsBlockMentions,
|
||||
&s.PhotoPath,
|
||||
&s.PinnedMailserver,
|
||||
&s.PreferredName,
|
||||
|
|
|
@ -30,50 +30,21 @@ import (
|
|||
"github.com/status-im/status-go/whisper/v6"
|
||||
)
|
||||
|
||||
// GetFreePort asks the kernel for a free open port that is ready to use.
|
||||
func getFreePort() (int, error) {
|
||||
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
l, err := net.ListenTCP("tcp", addr)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer l.Close()
|
||||
return l.Addr().(*net.TCPAddr).Port, nil
|
||||
}
|
||||
|
||||
type PeerPoolSimulationSuite struct {
|
||||
suite.Suite
|
||||
|
||||
bootnode *p2p.Server
|
||||
peers []*p2p.Server
|
||||
discovery []discovery.Discovery
|
||||
port uint16
|
||||
rendezvousServer *server.Server
|
||||
}
|
||||
|
||||
func TestPeerPoolSimulationSuite(t *testing.T) {
|
||||
s := &PeerPoolSimulationSuite{}
|
||||
port, err := getFreePort()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
s.port = uint16(port)
|
||||
|
||||
suite.Run(t, s)
|
||||
}
|
||||
|
||||
func (s *PeerPoolSimulationSuite) nextPort() uint16 {
|
||||
port, err := getFreePort()
|
||||
s.Require().NoError(err)
|
||||
return uint16(port)
|
||||
}
|
||||
|
||||
func (s *PeerPoolSimulationSuite) SetupTest() {
|
||||
bootnodePort := s.nextPort()
|
||||
key, _ := crypto.GenerateKey()
|
||||
name := common.MakeName("bootnode", "1.0")
|
||||
// 127.0.0.1 is invalidated by discovery v5
|
||||
|
@ -81,13 +52,14 @@ func (s *PeerPoolSimulationSuite) SetupTest() {
|
|||
Config: p2p.Config{
|
||||
MaxPeers: 10,
|
||||
Name: name,
|
||||
ListenAddr: fmt.Sprintf("0.0.0.0:%d", bootnodePort),
|
||||
ListenAddr: ":0",
|
||||
PrivateKey: key,
|
||||
DiscoveryV5: true,
|
||||
NoDiscovery: true,
|
||||
},
|
||||
}
|
||||
s.Require().NoError(s.bootnode.Start())
|
||||
bootnodePort := uint16(s.bootnode.NodeInfo().Ports.Listener)
|
||||
bootnodeV5 := discv5.NewNode(s.bootnode.DiscV5.Self().ID, net.ParseIP("127.0.0.1"), bootnodePort, bootnodePort)
|
||||
|
||||
// 1 peer to initiate connection, 1 peer as a first candidate, 1 peer - for failover
|
||||
|
@ -100,7 +72,7 @@ func (s *PeerPoolSimulationSuite) SetupTest() {
|
|||
Config: p2p.Config{
|
||||
MaxPeers: 10,
|
||||
Name: common.MakeName("peer-"+strconv.Itoa(i), "1.0"),
|
||||
ListenAddr: fmt.Sprintf("0.0.0.0:%d", s.nextPort()),
|
||||
ListenAddr: ":0",
|
||||
PrivateKey: key,
|
||||
NoDiscovery: true,
|
||||
BootstrapNodesV5: []*discv5.Node{bootnodeV5},
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
v1protocol "github.com/status-im/status-go/protocol/v1"
|
||||
)
|
||||
|
@ -50,8 +51,8 @@ type Chat struct {
|
|||
DeletedAtClockValue uint64 `json:"deletedAtClockValue"`
|
||||
|
||||
// Denormalized fields
|
||||
UnviewedMessagesCount uint `json:"unviewedMessagesCount"`
|
||||
LastMessage *Message `json:"lastMessage"`
|
||||
UnviewedMessagesCount uint `json:"unviewedMessagesCount"`
|
||||
LastMessage *common.Message `json:"lastMessage"`
|
||||
|
||||
// Group chat fields
|
||||
// Members are the members who have been invited to the group chat
|
||||
|
@ -114,6 +115,16 @@ func (c *Chat) MembersAsPublicKeys() ([]*ecdsa.PublicKey, error) {
|
|||
return stringSliceToPublicKeys(publicKeys, true)
|
||||
}
|
||||
|
||||
func (c *Chat) JoinedMembersAsPublicKeys() ([]*ecdsa.PublicKey, error) {
|
||||
var publicKeys []string
|
||||
for _, member := range c.Members {
|
||||
if member.Joined {
|
||||
publicKeys = append(publicKeys, member.ID)
|
||||
}
|
||||
}
|
||||
return stringSliceToPublicKeys(publicKeys, true)
|
||||
}
|
||||
|
||||
func (c *Chat) HasMember(memberID string) bool {
|
||||
for _, member := range c.Members {
|
||||
if memberID == member.ID {
|
||||
|
@ -172,7 +183,7 @@ func (c *Chat) NextClockAndTimestamp(timesource TimeSource) (uint64, uint64) {
|
|||
return clock, timestamp
|
||||
}
|
||||
|
||||
func (c *Chat) UpdateFromMessage(message *Message, timesource TimeSource) error {
|
||||
func (c *Chat) UpdateFromMessage(message *common.Message, timesource TimeSource) error {
|
||||
c.Timestamp = int64(timesource.GetCurrentTime())
|
||||
|
||||
// If the clock of the last message is lower, we set the message
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
)
|
||||
|
||||
type ChatTestSuite struct {
|
||||
|
@ -75,7 +77,7 @@ func (s *ChatTestSuite) TestValidateChat() {
|
|||
func (s *ChatTestSuite) TestUpdateFromMessage() {
|
||||
|
||||
// Base case, clock is higher
|
||||
message := &Message{}
|
||||
message := &common.Message{}
|
||||
chat := &Chat{}
|
||||
|
||||
message.Clock = 1
|
||||
|
@ -84,7 +86,7 @@ func (s *ChatTestSuite) TestUpdateFromMessage() {
|
|||
s.Require().Equal(uint64(1), chat.LastClockValue)
|
||||
|
||||
// Clock is lower and lastMessage is not nil
|
||||
message = &Message{}
|
||||
message = &common.Message{}
|
||||
lastMessage := message
|
||||
chat = &Chat{LastClockValue: 2, LastMessage: lastMessage}
|
||||
|
||||
|
@ -94,7 +96,7 @@ func (s *ChatTestSuite) TestUpdateFromMessage() {
|
|||
s.Require().Equal(uint64(2), chat.LastClockValue)
|
||||
|
||||
// Clock is lower and lastMessage is nil
|
||||
message = &Message{}
|
||||
message = &common.Message{}
|
||||
chat = &Chat{LastClockValue: 2}
|
||||
|
||||
message.Clock = 1
|
||||
|
@ -103,7 +105,7 @@ func (s *ChatTestSuite) TestUpdateFromMessage() {
|
|||
s.Require().Equal(uint64(2), chat.LastClockValue)
|
||||
|
||||
// Clock is higher but lastMessage has lower clock message then the receiving one
|
||||
message = &Message{}
|
||||
message = &common.Message{}
|
||||
chat = &Chat{LastClockValue: 2}
|
||||
|
||||
message.Clock = 1
|
||||
|
@ -112,7 +114,7 @@ func (s *ChatTestSuite) TestUpdateFromMessage() {
|
|||
s.Require().Equal(uint64(2), chat.LastClockValue)
|
||||
|
||||
chat.LastClockValue = 4
|
||||
message = &Message{}
|
||||
message = &common.Message{}
|
||||
message.Clock = 3
|
||||
s.Require().NoError(chat.UpdateFromMessage(message, &testTimeSource{}))
|
||||
s.Require().Equal(chat.LastMessage, message)
|
||||
|
@ -122,7 +124,7 @@ func (s *ChatTestSuite) TestUpdateFromMessage() {
|
|||
|
||||
func (s *ChatTestSuite) TestSerializeJSON() {
|
||||
|
||||
message := &Message{}
|
||||
message := &common.Message{}
|
||||
chat := &Chat{}
|
||||
|
||||
message.Clock = 1
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package protocol
|
||||
package common
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
|
@ -11,7 +11,9 @@ import (
|
|||
"unicode/utf8"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
"github.com/status-im/markdown"
|
||||
"github.com/status-im/markdown/ast"
|
||||
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
)
|
||||
|
@ -117,6 +119,9 @@ type Message struct {
|
|||
// that has been updated
|
||||
Replace string `json:"replace,omitempty"`
|
||||
SigPubKey *ecdsa.PublicKey `json:"-"`
|
||||
|
||||
// Mentions is an array of mentions for a given message
|
||||
Mentions []string
|
||||
}
|
||||
|
||||
func (m *Message) MarshalJSON() ([]byte, error) {
|
||||
|
@ -151,6 +156,7 @@ func (m *Message) MarshalJSON() ([]byte, error) {
|
|||
Timestamp uint64 `json:"timestamp"`
|
||||
ContentType protobuf.ChatMessage_ContentType `json:"contentType"`
|
||||
MessageType protobuf.MessageType `json:"messageType"`
|
||||
Mentions []string `json:"mentions,omitempty"`
|
||||
}{
|
||||
ID: m.ID,
|
||||
WhisperTimestamp: m.WhisperTimestamp,
|
||||
|
@ -174,6 +180,7 @@ func (m *Message) MarshalJSON() ([]byte, error) {
|
|||
Audio: m.Base64Audio,
|
||||
Timestamp: m.Timestamp,
|
||||
ContentType: m.ContentType,
|
||||
Mentions: m.Mentions,
|
||||
MessageType: m.MessageType,
|
||||
CommandParameters: m.CommandParameters,
|
||||
}
|
||||
|
@ -295,10 +302,34 @@ func (m *Message) parseAudio() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// implement interface of https://github.com/status-im/markdown/blob/b9fe921681227b1dace4b56364e15edb3b698308/ast/node.go#L701
|
||||
type MentionNodeVisitor struct {
|
||||
mentions []string
|
||||
}
|
||||
|
||||
func (v *MentionNodeVisitor) Visit(node ast.Node, entering bool) ast.WalkStatus {
|
||||
// only on entering we fetch, otherwise we go on
|
||||
if !entering {
|
||||
return ast.GoToNext
|
||||
}
|
||||
switch n := node.(type) {
|
||||
case *ast.Mention:
|
||||
v.mentions = append(v.mentions, string(n.Literal))
|
||||
}
|
||||
return ast.GoToNext
|
||||
}
|
||||
|
||||
func extractMentions(parsedText ast.Node) []string {
|
||||
visitor := &MentionNodeVisitor{}
|
||||
ast.Walk(parsedText, visitor)
|
||||
return visitor.mentions
|
||||
}
|
||||
|
||||
// PrepareContent return the parsed content of the message, the line-count and whether
|
||||
// is a right-to-left message
|
||||
func (m *Message) PrepareContent() error {
|
||||
parsedText := markdown.Parse([]byte(m.Text), nil)
|
||||
m.Mentions = extractMentions(parsedText)
|
||||
jsonParsedText, err := json.Marshal(parsedText)
|
||||
if err != nil {
|
||||
return err
|
|
@ -325,11 +325,13 @@ func (p *MessageProcessor) SendPublic(
|
|||
}
|
||||
|
||||
var newMessage *types.NewMessage
|
||||
|
||||
messageSpec, err := p.protocol.BuildPublicMessage(p.identity, wrappedMessage)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to wrap a public message in the encryption layer")
|
||||
}
|
||||
|
||||
if !rawMessage.SkipEncryption {
|
||||
messageSpec, err := p.protocol.BuildPublicMessage(p.identity, wrappedMessage)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to wrap a public message in the encryption layer")
|
||||
}
|
||||
newMessage, err = MessageSpecToWhisper(messageSpec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -354,6 +356,13 @@ func (p *MessageProcessor) SendPublic(
|
|||
return nil, err
|
||||
}
|
||||
|
||||
sentMessage := &SentMessage{
|
||||
Spec: messageSpec,
|
||||
MessageIDs: [][]byte{messageID},
|
||||
}
|
||||
|
||||
p.notifyOnSentMessage(sentMessage)
|
||||
|
||||
p.transport.Track([][]byte{messageID}, hash, newMessage)
|
||||
|
||||
return messageID, nil
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package protocol
|
||||
package common
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
@ -7,6 +7,8 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
)
|
||||
|
||||
|
@ -14,7 +16,7 @@ const expectedJPEG = "data:image/jpeg;base64,/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQ
|
|||
const expectedAAC = "data:audio/aac;base64,//FQgBw//NoATGF2YzUyLjcwLjAAQniptokphEFCg5qs1v9fn48+qz1rfWNhwvz+CqB5dipmq3T2PlT1Ld6sPj+19fUt1C3NKV0KowiqohZVCrdf19WMatvV3YbIvAuy/q2RafA8UiZPmZY7DdmHZtP9ri25kedWSiMKQRt79ttlod55LkuX7/f7/f7/f7/YGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYHNqo8g5qs1v9fn48+qz1rfWNhwvz+CqAAAAAAAAAAAAAAAAAAAAAAABw//FQgCNf/CFXbUZfDKFRgsYlKDegtXJH9eLkT54uRM1ckDYDcXRzZGF6Kz5Yps5fTeLY6w7gclwly+0PJL3udY3PyekTFI65bdniF3OjvHeafzZfWTs0qRMSkdll1sbb4SNT5e8vX98ytot6jEZ0NhJi2pBVP/tKV2JMyo36n9uxR2tKR+FoLCsP4SVi49kmvaSCWm5bQD96OmVQA9Q40bqnOa7rT8j9N0TlK991XdcenGTLbyS6eUnN2U1ckf14uRPni5EzVyQAAAAAAAAAAx6Q1flBp+KH2LhgH2Xx+14QB2/jcizm6ngck4vB9DoH9/Vcb7E8Dy+D/1ii1pSPwsUUUXCSsXHsk17SBfKwn2uHr6QAAAAAAAHA//FQgBt//CF3VO1KFCFWcd/r04m+O0758/tXHUlvaqEK9lvhUZXEZMXKMV/LQ6B3/mOl/Mrfs6jpD2b7f+n4yt+tm2x5ZmnpD++dZo/V9VgblI3OW/s1b8qt0h1RBiIRIIYIYQIBeCM8yy7etkwt1JAajRSoZGwwNZ07TTFTyMR1mTUVVUTW97vaDaHU5DV1snBf0mN4fraa+rf/vpdZ8FxqatGjNxPh35UuVfpNqc48W4nZ6rOO/16cTfHad8+f2rjqS3tVAAAAAAAAAAAAAAAAAAAAAAAAAAAO//FQgBm//CEXVPU+GiFsPr7x6+N6v+m+q511I4SgtYVyoyWjcMWMxkaxxDGSx1qVcarjDESt8zLQehx/lkil/GrHBy/NfJcHek0XtfanZJLHNXO2rUnFklPAlQSBS4l0pIoXIfORcXx0UYj1nTsSe1/0wXDkkFCfxWHtqRayOmWm3oS6JGdnZdtjesjByefiS8dLW1tVVVC58ijoxN3gmGFYj07+YJ6eth9fePXxvV/031XOupHCUAAAAAAAAAAAAAAAAAAAAAAAAAAA4P/xUIAcf/whN1T9NsMOEK5rxxxxXnid+f0/Ia195vi6oGH1ZVr6kjqScdSF9lt3qXH+Lxf0fo/Oe53r99IUPzybv/YWGZ7Vgk31MGw+DMp05+3y9fPERUTHlt1c9sUyoqCaD5bdXVz2wkG0hnpDmFy8r0fr3VBn/C7Rmg+L0/45EWfdocGq3HQ1uRro0GJK+vsvo837NR82s01l/n97rsWn7RYNBM3WRcDY3cJKosqMJhgdHtj9yflthd65rxxxxXnid+f0/Ia195vi6oAAAAAAAAAAAAAAAAAAAAAAAAAAAABw"
|
||||
|
||||
func TestPrepareContentImage(t *testing.T) {
|
||||
file, err := os.Open("../_assets/tests/test.jpg")
|
||||
file, err := os.Open("../../_assets/tests/test.jpg")
|
||||
require.NoError(t, err)
|
||||
defer file.Close()
|
||||
|
||||
|
@ -60,7 +62,7 @@ func TestGetImageMessageMIME(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPrepareContentAudio(t *testing.T) {
|
||||
file, err := os.Open("../_assets/tests/test.aac")
|
||||
file, err := os.Open("../../_assets/tests/test.aac")
|
||||
require.NoError(t, err)
|
||||
defer file.Close()
|
||||
|
||||
|
@ -94,3 +96,21 @@ func TestGetAudioMessageMIME(t *testing.T) {
|
|||
_, err = getImageMessageMIME(unknown)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestPrepareContentMentions(t *testing.T) {
|
||||
message := &Message{}
|
||||
pk1, err := crypto.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
pk1String := types.EncodeHex(crypto.FromECDSAPub(&pk1.PublicKey))
|
||||
|
||||
pk2, err := crypto.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
pk2String := types.EncodeHex(crypto.FromECDSAPub(&pk2.PublicKey))
|
||||
|
||||
message.Text = "hey @" + pk1String + " @" + pk2String
|
||||
|
||||
require.NoError(t, message.PrepareContent())
|
||||
require.Len(t, message.Mentions, 2)
|
||||
require.Equal(t, message.Mentions[0], pk1String)
|
||||
require.Equal(t, message.Mentions[1], pk2String)
|
||||
}
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
v1protocol "github.com/status-im/status-go/protocol/v1"
|
||||
)
|
||||
|
@ -27,7 +28,7 @@ func tsprintf(format string, params map[string]string) string {
|
|||
return format
|
||||
}
|
||||
|
||||
func eventToSystemMessage(e v1protocol.MembershipUpdateEvent, translations map[protobuf.MembershipUpdateEvent_EventType]string) *Message {
|
||||
func eventToSystemMessage(e v1protocol.MembershipUpdateEvent, translations map[protobuf.MembershipUpdateEvent_EventType]string) *common.Message {
|
||||
var text string
|
||||
switch e.Type {
|
||||
case protobuf.MembershipUpdateEvent_CHAT_CREATED:
|
||||
|
@ -56,7 +57,7 @@ func eventToSystemMessage(e v1protocol.MembershipUpdateEvent, translations map[p
|
|||
|
||||
}
|
||||
timestamp := v1protocol.TimestampInMsFromTime(time.Now())
|
||||
message := &Message{
|
||||
message := &common.Message{
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
ChatId: e.ChatID,
|
||||
Text: text,
|
||||
|
@ -75,8 +76,8 @@ func eventToSystemMessage(e v1protocol.MembershipUpdateEvent, translations map[p
|
|||
return message
|
||||
}
|
||||
|
||||
func buildSystemMessages(events []v1protocol.MembershipUpdateEvent, translations map[protobuf.MembershipUpdateEvent_EventType]string) []*Message {
|
||||
var messages []*Message
|
||||
func buildSystemMessages(events []v1protocol.MembershipUpdateEvent, translations map[protobuf.MembershipUpdateEvent_EventType]string) []*common.Message {
|
||||
var messages []*common.Message
|
||||
|
||||
for _, e := range events {
|
||||
messages = append(messages, eventToSystemMessage(e, translations))
|
||||
|
|
|
@ -5,11 +5,12 @@ import (
|
|||
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
"github.com/status-im/status-go/protocol/identity/alias"
|
||||
"github.com/status-im/status-go/protocol/identity/identicon"
|
||||
)
|
||||
|
||||
func extendMessageFromChat(message *Message, chat *Chat, key *ecdsa.PublicKey, timesource TimeSource) error {
|
||||
func extendMessageFromChat(message *common.Message, chat *Chat, key *ecdsa.PublicKey, timesource TimeSource) error {
|
||||
clock, timestamp := chat.NextClockAndTimestamp(timesource)
|
||||
|
||||
message.LocalChatID = chat.ID
|
||||
|
@ -19,7 +20,7 @@ func extendMessageFromChat(message *Message, chat *Chat, key *ecdsa.PublicKey, t
|
|||
message.SigPubKey = key
|
||||
message.WhisperTimestamp = timestamp
|
||||
message.Seen = true
|
||||
message.OutgoingStatus = OutgoingStatusSending
|
||||
message.OutgoingStatus = common.OutgoingStatusSending
|
||||
|
||||
identicon, err := identicon.GenerateBase64(message.From)
|
||||
if err != nil {
|
||||
|
|
|
@ -145,7 +145,7 @@ func (m *MessageHandler) HandleMembershipUpdate(messageState *ReceivedMessageSta
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *MessageHandler) handleCommandMessage(state *ReceivedMessageState, message *Message) error {
|
||||
func (m *MessageHandler) handleCommandMessage(state *ReceivedMessageState, message *common.Message) error {
|
||||
message.ID = state.CurrentMessageState.MessageID
|
||||
message.From = state.CurrentMessageState.Contact.ID
|
||||
message.Alias = state.CurrentMessageState.Contact.Alias
|
||||
|
@ -182,7 +182,7 @@ func (m *MessageHandler) handleCommandMessage(state *ReceivedMessageState, messa
|
|||
message.OutgoingStatus = ""
|
||||
} else {
|
||||
// Our own message, mark as sent
|
||||
message.OutgoingStatus = OutgoingStatusSent
|
||||
message.OutgoingStatus = common.OutgoingStatusSent
|
||||
}
|
||||
|
||||
err = chat.UpdateFromMessage(message, state.Timesource)
|
||||
|
@ -248,11 +248,11 @@ func (m *MessageHandler) HandleSyncInstallationContact(state *ReceivedMessageSta
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *MessageHandler) HandleSyncInstallationPublicChat(state *ReceivedMessageState, message protobuf.SyncInstallationPublicChat) error {
|
||||
func (m *MessageHandler) HandleSyncInstallationPublicChat(state *ReceivedMessageState, message protobuf.SyncInstallationPublicChat) bool {
|
||||
chatID := message.Id
|
||||
_, ok := state.AllChats[chatID]
|
||||
if ok {
|
||||
return nil
|
||||
return false
|
||||
}
|
||||
|
||||
chat := CreatePublicChat(chatID, state.Timesource)
|
||||
|
@ -260,7 +260,7 @@ func (m *MessageHandler) HandleSyncInstallationPublicChat(state *ReceivedMessage
|
|||
state.AllChats[chat.ID] = &chat
|
||||
state.ModifiedChats[chat.ID] = true
|
||||
|
||||
return nil
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *MessageHandler) HandleContactUpdate(state *ReceivedMessageState, message protobuf.ContactUpdate) error {
|
||||
|
@ -330,7 +330,7 @@ func (m *MessageHandler) HandleChatMessage(state *ReceivedMessageState) error {
|
|||
logger.Warn("failed to validate message", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
receivedMessage := &Message{
|
||||
receivedMessage := &common.Message{
|
||||
ID: state.CurrentMessageState.MessageID,
|
||||
ChatMessage: state.CurrentMessageState.Message,
|
||||
From: state.CurrentMessageState.Contact.ID,
|
||||
|
@ -369,7 +369,7 @@ func (m *MessageHandler) HandleChatMessage(state *ReceivedMessageState) error {
|
|||
chat.UnviewedMessagesCount++
|
||||
} else {
|
||||
// Our own message, mark as sent
|
||||
receivedMessage.OutgoingStatus = OutgoingStatusSent
|
||||
receivedMessage.OutgoingStatus = common.OutgoingStatusSent
|
||||
}
|
||||
|
||||
err = chat.UpdateFromMessage(receivedMessage, state.Timesource)
|
||||
|
@ -401,7 +401,7 @@ func (m *MessageHandler) HandleRequestAddressForTransaction(messageState *Receiv
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
message := &Message{
|
||||
message := &common.Message{
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
Clock: command.Clock,
|
||||
Timestamp: messageState.CurrentMessageState.WhisperTimestamp,
|
||||
|
@ -410,11 +410,11 @@ func (m *MessageHandler) HandleRequestAddressForTransaction(messageState *Receiv
|
|||
MessageType: protobuf.MessageType_ONE_TO_ONE,
|
||||
ContentType: protobuf.ChatMessage_TRANSACTION_COMMAND,
|
||||
},
|
||||
CommandParameters: &CommandParameters{
|
||||
CommandParameters: &common.CommandParameters{
|
||||
ID: messageState.CurrentMessageState.MessageID,
|
||||
Value: command.Value,
|
||||
Contract: command.Contract,
|
||||
CommandState: CommandStateRequestAddressForTransaction,
|
||||
CommandState: common.CommandStateRequestAddressForTransaction,
|
||||
},
|
||||
}
|
||||
return m.handleCommandMessage(messageState, message)
|
||||
|
@ -425,7 +425,7 @@ func (m *MessageHandler) HandleRequestTransaction(messageState *ReceivedMessageS
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
message := &Message{
|
||||
message := &common.Message{
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
Clock: command.Clock,
|
||||
Timestamp: messageState.CurrentMessageState.WhisperTimestamp,
|
||||
|
@ -434,11 +434,11 @@ func (m *MessageHandler) HandleRequestTransaction(messageState *ReceivedMessageS
|
|||
MessageType: protobuf.MessageType_ONE_TO_ONE,
|
||||
ContentType: protobuf.ChatMessage_TRANSACTION_COMMAND,
|
||||
},
|
||||
CommandParameters: &CommandParameters{
|
||||
CommandParameters: &common.CommandParameters{
|
||||
ID: messageState.CurrentMessageState.MessageID,
|
||||
Value: command.Value,
|
||||
Contract: command.Contract,
|
||||
CommandState: CommandStateRequestTransaction,
|
||||
CommandState: common.CommandStateRequestTransaction,
|
||||
Address: command.Address,
|
||||
},
|
||||
}
|
||||
|
@ -466,7 +466,7 @@ func (m *MessageHandler) HandleAcceptRequestAddressForTransaction(messageState *
|
|||
return errors.New("Initial message must originate from us")
|
||||
}
|
||||
|
||||
if initialMessage.CommandParameters.CommandState != CommandStateRequestAddressForTransaction {
|
||||
if initialMessage.CommandParameters.CommandState != common.CommandStateRequestAddressForTransaction {
|
||||
return errors.New("Wrong state for command")
|
||||
}
|
||||
|
||||
|
@ -475,7 +475,7 @@ func (m *MessageHandler) HandleAcceptRequestAddressForTransaction(messageState *
|
|||
initialMessage.Text = requestAddressForTransactionAcceptedMessage
|
||||
initialMessage.CommandParameters.Address = command.Address
|
||||
initialMessage.Seen = false
|
||||
initialMessage.CommandParameters.CommandState = CommandStateRequestAddressForTransactionAccepted
|
||||
initialMessage.CommandParameters.CommandState = common.CommandStateRequestAddressForTransactionAccepted
|
||||
|
||||
// Hide previous message
|
||||
previousMessage, err := m.persistence.MessageByCommandID(messageState.CurrentMessageState.Contact.ID, command.Id)
|
||||
|
@ -536,7 +536,7 @@ func (m *MessageHandler) HandleDeclineRequestAddressForTransaction(messageState
|
|||
return errors.New("Initial message must originate from us")
|
||||
}
|
||||
|
||||
if oldMessage.CommandParameters.CommandState != CommandStateRequestAddressForTransaction {
|
||||
if oldMessage.CommandParameters.CommandState != common.CommandStateRequestAddressForTransaction {
|
||||
return errors.New("Wrong state for command")
|
||||
}
|
||||
|
||||
|
@ -544,7 +544,7 @@ func (m *MessageHandler) HandleDeclineRequestAddressForTransaction(messageState
|
|||
oldMessage.Timestamp = messageState.CurrentMessageState.WhisperTimestamp
|
||||
oldMessage.Text = requestAddressForTransactionDeclinedMessage
|
||||
oldMessage.Seen = false
|
||||
oldMessage.CommandParameters.CommandState = CommandStateRequestAddressForTransactionDeclined
|
||||
oldMessage.CommandParameters.CommandState = common.CommandStateRequestAddressForTransactionDeclined
|
||||
|
||||
// Hide previous message
|
||||
err = m.persistence.HideMessage(command.Id)
|
||||
|
@ -577,7 +577,7 @@ func (m *MessageHandler) HandleDeclineRequestTransaction(messageState *ReceivedM
|
|||
return errors.New("Initial message must originate from us")
|
||||
}
|
||||
|
||||
if oldMessage.CommandParameters.CommandState != CommandStateRequestTransaction {
|
||||
if oldMessage.CommandParameters.CommandState != common.CommandStateRequestTransaction {
|
||||
return errors.New("Wrong state for command")
|
||||
}
|
||||
|
||||
|
@ -585,7 +585,7 @@ func (m *MessageHandler) HandleDeclineRequestTransaction(messageState *ReceivedM
|
|||
oldMessage.Timestamp = messageState.CurrentMessageState.WhisperTimestamp
|
||||
oldMessage.Text = transactionRequestDeclinedMessage
|
||||
oldMessage.Seen = false
|
||||
oldMessage.CommandParameters.CommandState = CommandStateRequestTransactionDeclined
|
||||
oldMessage.CommandParameters.CommandState = common.CommandStateRequestTransactionDeclined
|
||||
|
||||
// Hide previous message
|
||||
err = m.persistence.HideMessage(command.Id)
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
@ -40,6 +41,7 @@ func (db sqlitePersistence) tableUserMessagesAllFields() string {
|
|||
audio_type,
|
||||
audio_duration_ms,
|
||||
audio_base64,
|
||||
mentions,
|
||||
command_id,
|
||||
command_value,
|
||||
command_from,
|
||||
|
@ -74,6 +76,7 @@ func (db sqlitePersistence) tableUserMessagesAllFieldsJoin() string {
|
|||
m1.image_base64,
|
||||
COALESCE(m1.audio_duration_ms,0),
|
||||
m1.audio_base64,
|
||||
m1.mentions,
|
||||
m1.command_id,
|
||||
m1.command_value,
|
||||
m1.command_from,
|
||||
|
@ -104,18 +107,19 @@ type scanner interface {
|
|||
Scan(dest ...interface{}) error
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message *Message, others ...interface{}) error {
|
||||
func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message *common.Message, others ...interface{}) error {
|
||||
var quotedText sql.NullString
|
||||
var quotedParsedText []byte
|
||||
var quotedFrom sql.NullString
|
||||
var quotedImage sql.NullString
|
||||
var quotedAudio sql.NullString
|
||||
var quotedAudioDuration sql.NullInt64
|
||||
var serializedMentions []byte
|
||||
var alias sql.NullString
|
||||
var identicon sql.NullString
|
||||
|
||||
sticker := &protobuf.StickerMessage{}
|
||||
command := &CommandParameters{}
|
||||
command := &common.CommandParameters{}
|
||||
audio := &protobuf.AudioMessage{}
|
||||
|
||||
args := []interface{}{
|
||||
|
@ -138,6 +142,7 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message
|
|||
&message.Base64Image,
|
||||
&audio.DurationMs,
|
||||
&message.Base64Audio,
|
||||
&serializedMentions,
|
||||
&command.ID,
|
||||
&command.Value,
|
||||
&command.From,
|
||||
|
@ -165,7 +170,7 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message
|
|||
}
|
||||
|
||||
if quotedText.Valid {
|
||||
message.QuotedMessage = &QuotedMessage{
|
||||
message.QuotedMessage = &common.QuotedMessage{
|
||||
From: quotedFrom.String,
|
||||
Text: quotedText.String,
|
||||
ParsedText: quotedParsedText,
|
||||
|
@ -177,6 +182,13 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message
|
|||
message.Alias = alias.String
|
||||
message.Identicon = identicon.String
|
||||
|
||||
if serializedMentions != nil {
|
||||
err := json.Unmarshal(serializedMentions, &message.Mentions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
switch message.ContentType {
|
||||
case protobuf.ChatMessage_STICKER:
|
||||
message.Payload = &protobuf.ChatMessage_Sticker{Sticker: sticker}
|
||||
|
@ -191,7 +203,7 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message
|
|||
return nil
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) tableUserMessagesAllValues(message *Message) ([]interface{}, error) {
|
||||
func (db sqlitePersistence) tableUserMessagesAllValues(message *common.Message) ([]interface{}, error) {
|
||||
sticker := message.GetSticker()
|
||||
if sticker == nil {
|
||||
sticker = &protobuf.StickerMessage{}
|
||||
|
@ -209,7 +221,16 @@ func (db sqlitePersistence) tableUserMessagesAllValues(message *Message) ([]inte
|
|||
|
||||
command := message.CommandParameters
|
||||
if command == nil {
|
||||
command = &CommandParameters{}
|
||||
command = &common.CommandParameters{}
|
||||
}
|
||||
|
||||
var serializedMentions []byte
|
||||
var err error
|
||||
if len(message.Mentions) != 0 {
|
||||
serializedMentions, err = json.Marshal(message.Mentions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return []interface{}{
|
||||
message.ID,
|
||||
|
@ -235,6 +256,7 @@ func (db sqlitePersistence) tableUserMessagesAllValues(message *Message) ([]inte
|
|||
audio.Type,
|
||||
audio.DurationMs,
|
||||
message.Base64Audio,
|
||||
serializedMentions,
|
||||
command.ID,
|
||||
command.Value,
|
||||
command.From,
|
||||
|
@ -250,7 +272,7 @@ func (db sqlitePersistence) tableUserMessagesAllValues(message *Message) ([]inte
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) messageByID(tx *sql.Tx, id string) (*Message, error) {
|
||||
func (db sqlitePersistence) messageByID(tx *sql.Tx, id string) (*common.Message, error) {
|
||||
var err error
|
||||
if tx == nil {
|
||||
tx, err = db.db.BeginTx(context.Background(), &sql.TxOptions{})
|
||||
|
@ -267,7 +289,7 @@ func (db sqlitePersistence) messageByID(tx *sql.Tx, id string) (*Message, error)
|
|||
}()
|
||||
}
|
||||
|
||||
var message Message
|
||||
var message common.Message
|
||||
|
||||
allFields := db.tableUserMessagesAllFieldsJoin()
|
||||
row := tx.QueryRow(
|
||||
|
@ -301,9 +323,9 @@ func (db sqlitePersistence) messageByID(tx *sql.Tx, id string) (*Message, error)
|
|||
}
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) MessageByCommandID(chatID, id string) (*Message, error) {
|
||||
func (db sqlitePersistence) MessageByCommandID(chatID, id string) (*common.Message, error) {
|
||||
|
||||
var message Message
|
||||
var message common.Message
|
||||
|
||||
allFields := db.tableUserMessagesAllFieldsJoin()
|
||||
row := db.db.QueryRow(
|
||||
|
@ -342,7 +364,7 @@ func (db sqlitePersistence) MessageByCommandID(chatID, id string) (*Message, err
|
|||
}
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) MessageByID(id string) (*Message, error) {
|
||||
func (db sqlitePersistence) MessageByID(id string) (*common.Message, error) {
|
||||
return db.messageByID(nil, id)
|
||||
}
|
||||
|
||||
|
@ -377,7 +399,7 @@ func (db sqlitePersistence) MessagesExist(ids []string) (map[string]bool, error)
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) MessagesByIDs(ids []string) ([]*Message, error) {
|
||||
func (db sqlitePersistence) MessagesByIDs(ids []string) ([]*common.Message, error) {
|
||||
if len(ids) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -412,9 +434,9 @@ func (db sqlitePersistence) MessagesByIDs(ids []string) ([]*Message, error) {
|
|||
}
|
||||
defer rows.Close()
|
||||
|
||||
var result []*Message
|
||||
var result []*common.Message
|
||||
for rows.Next() {
|
||||
var message Message
|
||||
var message common.Message
|
||||
if err := db.tableUserMessagesScanAllFields(rows, &message); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -427,7 +449,7 @@ func (db sqlitePersistence) MessagesByIDs(ids []string) ([]*Message, error) {
|
|||
// MessageByChatID returns all messages for a given chatID in descending order.
|
||||
// Ordering is accomplished using two concatenated values: ClockValue and ID.
|
||||
// These two values are also used to compose a cursor which is returned to the result.
|
||||
func (db sqlitePersistence) MessageByChatID(chatID string, currCursor string, limit int) ([]*Message, string, error) {
|
||||
func (db sqlitePersistence) MessageByChatID(chatID string, currCursor string, limit int) ([]*common.Message, string, error) {
|
||||
cursorWhere := ""
|
||||
if currCursor != "" {
|
||||
cursorWhere = "AND cursor <= ?"
|
||||
|
@ -470,12 +492,12 @@ func (db sqlitePersistence) MessageByChatID(chatID string, currCursor string, li
|
|||
defer rows.Close()
|
||||
|
||||
var (
|
||||
result []*Message
|
||||
result []*common.Message
|
||||
cursors []string
|
||||
)
|
||||
for rows.Next() {
|
||||
var (
|
||||
message Message
|
||||
message common.Message
|
||||
cursor string
|
||||
)
|
||||
if err := db.tableUserMessagesScanAllFields(rows, &message, &cursor); err != nil {
|
||||
|
@ -566,7 +588,7 @@ func (db sqlitePersistence) EmojiReactionsByChatID(chatID string, currCursor str
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) SaveMessages(messages []*Message) (err error) {
|
||||
func (db sqlitePersistence) SaveMessages(messages []*common.Message) (err error) {
|
||||
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
|
||||
if err != nil {
|
||||
return
|
||||
|
|
|
@ -91,7 +91,7 @@ type RawResponse struct {
|
|||
|
||||
type MessengerResponse struct {
|
||||
Chats []*Chat `json:"chats,omitempty"`
|
||||
Messages []*Message `json:"messages,omitempty"`
|
||||
Messages []*common.Message `json:"messages,omitempty"`
|
||||
Contacts []*Contact `json:"contacts,omitempty"`
|
||||
Installations []*multidevice.Installation `json:"installations,omitempty"`
|
||||
EmojiReactions []*EmojiReaction `json:"emojiReactions,omitempty"`
|
||||
|
@ -227,7 +227,7 @@ func NewMessenger(
|
|||
pushNotificationClientConfig.Logger = logger
|
||||
pushNotificationClientConfig.InstallationID = installationID
|
||||
|
||||
pushNotificationClient := pushnotificationclient.New(pushNotificationClientPersistence, pushNotificationClientConfig, processor)
|
||||
pushNotificationClient := pushnotificationclient.New(pushNotificationClientPersistence, pushNotificationClientConfig, processor, &sqlitePersistence{db: database})
|
||||
|
||||
handler := newMessageHandler(identity, logger, &sqlitePersistence{db: database})
|
||||
|
||||
|
@ -1358,7 +1358,7 @@ func (m *Messenger) LeaveGroupChat(ctx context.Context, chatID string, remove bo
|
|||
}
|
||||
|
||||
func (m *Messenger) saveChat(chat *Chat) error {
|
||||
_, ok := m.allChats[chat.ID]
|
||||
previousChat, ok := m.allChats[chat.ID]
|
||||
if chat.OneToOne() {
|
||||
name, identicon, err := generateAliasAndIdenticon(chat.ID)
|
||||
if err != nil {
|
||||
|
@ -1370,11 +1370,21 @@ func (m *Messenger) saveChat(chat *Chat) error {
|
|||
}
|
||||
// Sync chat if it's a new active public chat
|
||||
if !ok && chat.Active && chat.Public() {
|
||||
|
||||
if err := m.syncPublicChat(context.Background(), chat); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// We check if it's a new chat, or chat.Active has changed
|
||||
if chat.Public() && (!ok && chat.Active) || (ok && chat.Active != previousChat.Active) {
|
||||
// Re-register for push notifications, as we want to receive mentions
|
||||
if err := m.reregisterForPushNotifications(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
err := m.persistence.SaveChat(*chat)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1424,7 +1434,12 @@ func (m *Messenger) DeleteChat(chatID string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
delete(m.allChats, chatID)
|
||||
chat, ok := m.allChats[chatID]
|
||||
|
||||
if ok && chat.Active && chat.Public() {
|
||||
delete(m.allChats, chatID)
|
||||
return m.reregisterForPushNotifications()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -1490,8 +1505,7 @@ func (m *Messenger) reregisterForPushNotifications() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
contactIDs, mutedChatIDs := m.addedContactsAndMutedChatIDs()
|
||||
return m.pushNotificationClient.Reregister(contactIDs, mutedChatIDs)
|
||||
return m.pushNotificationClient.Reregister(m.pushNotificationOptions())
|
||||
}
|
||||
|
||||
func (m *Messenger) SaveContact(contact *Contact) error {
|
||||
|
@ -1649,9 +1663,18 @@ func (m *Messenger) dispatchMessage(ctx context.Context, spec common.RawMessage)
|
|||
case ChatTypePrivateGroupChat:
|
||||
logger.Debug("sending group message", zap.String("chatName", chat.Name))
|
||||
if spec.Recipients == nil {
|
||||
spec.Recipients, err = chat.MembersAsPublicKeys()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Chat messages are only dispatched to users who joined
|
||||
if spec.MessageType == protobuf.ApplicationMetadataMessage_CHAT_MESSAGE {
|
||||
spec.Recipients, err = chat.JoinedMembersAsPublicKeys()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
} else {
|
||||
spec.Recipients, err = chat.MembersAsPublicKeys()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
hasPairedDevices := m.hasPairedDevices()
|
||||
|
@ -1689,7 +1712,7 @@ func (m *Messenger) dispatchMessage(ctx context.Context, spec common.RawMessage)
|
|||
}
|
||||
|
||||
// SendChatMessage takes a minimal message and sends it based on the corresponding chat
|
||||
func (m *Messenger) SendChatMessage(ctx context.Context, message *Message) (*MessengerResponse, error) {
|
||||
func (m *Messenger) SendChatMessage(ctx context.Context, message *common.Message) (*MessengerResponse, error) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
|
@ -1758,7 +1781,7 @@ func (m *Messenger) SendChatMessage(ctx context.Context, message *Message) (*Mes
|
|||
|
||||
id, err := m.dispatchMessage(ctx, common.RawMessage{
|
||||
LocalChatID: chat.ID,
|
||||
SendPushNotification: m.featureFlags.PushNotifications && !chat.Public(),
|
||||
SendPushNotification: m.featureFlags.PushNotifications,
|
||||
Payload: encodedMessage,
|
||||
MessageType: protobuf.ApplicationMetadataMessage_CHAT_MESSAGE,
|
||||
ResendAutomatically: true,
|
||||
|
@ -1778,12 +1801,12 @@ func (m *Messenger) SendChatMessage(ctx context.Context, message *Message) (*Mes
|
|||
return nil, err
|
||||
}
|
||||
|
||||
err = m.persistence.SaveMessages([]*Message{message})
|
||||
err = m.persistence.SaveMessages([]*common.Message{message})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response.Messages, err = m.pullMessagesAndResponsesFromDB([]*Message{message})
|
||||
response.Messages, err = m.pullMessagesAndResponsesFromDB([]*common.Message{message})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -2251,10 +2274,17 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
|
|||
|
||||
p := msg.ParsedMessage.Interface().(protobuf.SyncInstallationPublicChat)
|
||||
logger.Debug("Handling SyncInstallationPublicChat", zap.Any("message", p))
|
||||
err = m.handler.HandleSyncInstallationPublicChat(messageState, p)
|
||||
if err != nil {
|
||||
logger.Warn("failed to handle SyncInstallationPublicChat", zap.Error(err))
|
||||
continue
|
||||
added := m.handler.HandleSyncInstallationPublicChat(messageState, p)
|
||||
|
||||
// We re-register as we want to receive mentions from the newly joined public chat
|
||||
if added {
|
||||
logger.Debug("newly synced public chat, re-registering for push notifications")
|
||||
err := m.reregisterForPushNotifications()
|
||||
if err != nil {
|
||||
|
||||
logger.Warn("could not re-register for push notifications", zap.Error(err))
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
case protobuf.RequestAddressForTransaction:
|
||||
|
@ -2540,7 +2570,7 @@ func (m *Messenger) ConfirmMessagesProcessed(messageIDs [][]byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *Messenger) MessageByID(id string) (*Message, error) {
|
||||
func (m *Messenger) MessageByID(id string) (*common.Message, error) {
|
||||
return m.persistence.MessageByID(id)
|
||||
}
|
||||
|
||||
|
@ -2548,11 +2578,11 @@ func (m *Messenger) MessagesExist(ids []string) (map[string]bool, error) {
|
|||
return m.persistence.MessagesExist(ids)
|
||||
}
|
||||
|
||||
func (m *Messenger) MessageByChatID(chatID, cursor string, limit int) ([]*Message, string, error) {
|
||||
func (m *Messenger) MessageByChatID(chatID, cursor string, limit int) ([]*common.Message, string, error) {
|
||||
return m.persistence.MessageByChatID(chatID, cursor, limit)
|
||||
}
|
||||
|
||||
func (m *Messenger) SaveMessages(messages []*Message) error {
|
||||
func (m *Messenger) SaveMessages(messages []*common.Message) error {
|
||||
return m.persistence.SaveMessages(messages)
|
||||
}
|
||||
|
||||
|
@ -2733,7 +2763,7 @@ func (m *Messenger) RequestTransaction(ctx context.Context, chatID, value, contr
|
|||
return nil, errors.New("Need to be a one-to-one chat")
|
||||
}
|
||||
|
||||
message := &Message{}
|
||||
message := &common.Message{}
|
||||
err := extendMessageFromChat(message, chat, &m.identity.PublicKey, m.transport)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -2760,12 +2790,12 @@ func (m *Messenger) RequestTransaction(ctx context.Context, chatID, value, contr
|
|||
ResendAutomatically: true,
|
||||
})
|
||||
|
||||
message.CommandParameters = &CommandParameters{
|
||||
message.CommandParameters = &common.CommandParameters{
|
||||
ID: types.EncodeHex(id),
|
||||
Value: value,
|
||||
Address: address,
|
||||
Contract: contract,
|
||||
CommandState: CommandStateRequestTransaction,
|
||||
CommandState: common.CommandStateRequestTransaction,
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -2785,13 +2815,13 @@ func (m *Messenger) RequestTransaction(ctx context.Context, chatID, value, contr
|
|||
return nil, err
|
||||
}
|
||||
|
||||
err = m.persistence.SaveMessages([]*Message{message})
|
||||
err = m.persistence.SaveMessages([]*common.Message{message})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response.Chats = []*Chat{chat}
|
||||
response.Messages = []*Message{message}
|
||||
response.Messages = []*common.Message{message}
|
||||
return &response, m.saveChat(chat)
|
||||
}
|
||||
|
||||
|
@ -2810,7 +2840,7 @@ func (m *Messenger) RequestAddressForTransaction(ctx context.Context, chatID, fr
|
|||
return nil, errors.New("Need to be a one-to-one chat")
|
||||
}
|
||||
|
||||
message := &Message{}
|
||||
message := &common.Message{}
|
||||
err := extendMessageFromChat(message, chat, &m.identity.PublicKey, m.transport)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -2836,12 +2866,12 @@ func (m *Messenger) RequestAddressForTransaction(ctx context.Context, chatID, fr
|
|||
ResendAutomatically: true,
|
||||
})
|
||||
|
||||
message.CommandParameters = &CommandParameters{
|
||||
message.CommandParameters = &common.CommandParameters{
|
||||
ID: types.EncodeHex(id),
|
||||
From: from,
|
||||
Value: value,
|
||||
Contract: contract,
|
||||
CommandState: CommandStateRequestAddressForTransaction,
|
||||
CommandState: common.CommandStateRequestAddressForTransaction,
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -2861,13 +2891,13 @@ func (m *Messenger) RequestAddressForTransaction(ctx context.Context, chatID, fr
|
|||
return nil, err
|
||||
}
|
||||
|
||||
err = m.persistence.SaveMessages([]*Message{message})
|
||||
err = m.persistence.SaveMessages([]*common.Message{message})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response.Chats = []*Chat{chat}
|
||||
response.Messages = []*Message{message}
|
||||
response.Messages = []*common.Message{message}
|
||||
return &response, m.saveChat(chat)
|
||||
}
|
||||
|
||||
|
@ -2902,7 +2932,7 @@ func (m *Messenger) AcceptRequestAddressForTransaction(ctx context.Context, mess
|
|||
message.WhisperTimestamp = timestamp
|
||||
message.Timestamp = timestamp
|
||||
message.Text = "Request address for transaction accepted"
|
||||
message.OutgoingStatus = OutgoingStatusSending
|
||||
message.OutgoingStatus = common.OutgoingStatusSending
|
||||
|
||||
// Hide previous message
|
||||
previousMessage, err := m.persistence.MessageByCommandID(chatID, messageID)
|
||||
|
@ -2944,7 +2974,7 @@ func (m *Messenger) AcceptRequestAddressForTransaction(ctx context.Context, mess
|
|||
|
||||
message.ID = types.EncodeHex(newMessageID)
|
||||
message.CommandParameters.Address = address
|
||||
message.CommandParameters.CommandState = CommandStateRequestAddressForTransactionAccepted
|
||||
message.CommandParameters.CommandState = common.CommandStateRequestAddressForTransactionAccepted
|
||||
|
||||
err = message.PrepareContent()
|
||||
if err != nil {
|
||||
|
@ -2956,13 +2986,13 @@ func (m *Messenger) AcceptRequestAddressForTransaction(ctx context.Context, mess
|
|||
return nil, err
|
||||
}
|
||||
|
||||
err = m.persistence.SaveMessages([]*Message{message})
|
||||
err = m.persistence.SaveMessages([]*common.Message{message})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response.Chats = []*Chat{chat}
|
||||
response.Messages = []*Message{message}
|
||||
response.Messages = []*common.Message{message}
|
||||
return &response, m.saveChat(chat)
|
||||
}
|
||||
|
||||
|
@ -2997,7 +3027,7 @@ func (m *Messenger) DeclineRequestTransaction(ctx context.Context, messageID str
|
|||
message.WhisperTimestamp = timestamp
|
||||
message.Timestamp = timestamp
|
||||
message.Text = "Transaction request declined"
|
||||
message.OutgoingStatus = OutgoingStatusSending
|
||||
message.OutgoingStatus = common.OutgoingStatusSending
|
||||
message.Replace = messageID
|
||||
|
||||
err = m.persistence.HideMessage(messageID)
|
||||
|
@ -3026,7 +3056,7 @@ func (m *Messenger) DeclineRequestTransaction(ctx context.Context, messageID str
|
|||
}
|
||||
|
||||
message.ID = types.EncodeHex(newMessageID)
|
||||
message.CommandParameters.CommandState = CommandStateRequestTransactionDeclined
|
||||
message.CommandParameters.CommandState = common.CommandStateRequestTransactionDeclined
|
||||
|
||||
err = message.PrepareContent()
|
||||
if err != nil {
|
||||
|
@ -3038,13 +3068,13 @@ func (m *Messenger) DeclineRequestTransaction(ctx context.Context, messageID str
|
|||
return nil, err
|
||||
}
|
||||
|
||||
err = m.persistence.SaveMessages([]*Message{message})
|
||||
err = m.persistence.SaveMessages([]*common.Message{message})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response.Chats = []*Chat{chat}
|
||||
response.Messages = []*Message{message}
|
||||
response.Messages = []*common.Message{message}
|
||||
return &response, m.saveChat(chat)
|
||||
}
|
||||
|
||||
|
@ -3079,7 +3109,7 @@ func (m *Messenger) DeclineRequestAddressForTransaction(ctx context.Context, mes
|
|||
message.WhisperTimestamp = timestamp
|
||||
message.Timestamp = timestamp
|
||||
message.Text = "Request address for transaction declined"
|
||||
message.OutgoingStatus = OutgoingStatusSending
|
||||
message.OutgoingStatus = common.OutgoingStatusSending
|
||||
message.Replace = messageID
|
||||
|
||||
err = m.persistence.HideMessage(messageID)
|
||||
|
@ -3108,7 +3138,7 @@ func (m *Messenger) DeclineRequestAddressForTransaction(ctx context.Context, mes
|
|||
}
|
||||
|
||||
message.ID = types.EncodeHex(newMessageID)
|
||||
message.CommandParameters.CommandState = CommandStateRequestAddressForTransactionDeclined
|
||||
message.CommandParameters.CommandState = common.CommandStateRequestAddressForTransactionDeclined
|
||||
|
||||
err = message.PrepareContent()
|
||||
if err != nil {
|
||||
|
@ -3120,13 +3150,13 @@ func (m *Messenger) DeclineRequestAddressForTransaction(ctx context.Context, mes
|
|||
return nil, err
|
||||
}
|
||||
|
||||
err = m.persistence.SaveMessages([]*Message{message})
|
||||
err = m.persistence.SaveMessages([]*common.Message{message})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response.Chats = []*Chat{chat}
|
||||
response.Messages = []*Message{message}
|
||||
response.Messages = []*common.Message{message}
|
||||
return &response, m.saveChat(chat)
|
||||
}
|
||||
|
||||
|
@ -3161,7 +3191,7 @@ func (m *Messenger) AcceptRequestTransaction(ctx context.Context, transactionHas
|
|||
message.WhisperTimestamp = timestamp
|
||||
message.Timestamp = timestamp
|
||||
message.Text = transactionSentTxt
|
||||
message.OutgoingStatus = OutgoingStatusSending
|
||||
message.OutgoingStatus = common.OutgoingStatusSending
|
||||
|
||||
// Hide previous message
|
||||
previousMessage, err := m.persistence.MessageByCommandID(chatID, messageID)
|
||||
|
@ -3207,7 +3237,7 @@ func (m *Messenger) AcceptRequestTransaction(ctx context.Context, transactionHas
|
|||
message.ID = types.EncodeHex(newMessageID)
|
||||
message.CommandParameters.TransactionHash = transactionHash
|
||||
message.CommandParameters.Signature = signature
|
||||
message.CommandParameters.CommandState = CommandStateTransactionSent
|
||||
message.CommandParameters.CommandState = common.CommandStateTransactionSent
|
||||
|
||||
err = message.PrepareContent()
|
||||
if err != nil {
|
||||
|
@ -3219,13 +3249,13 @@ func (m *Messenger) AcceptRequestTransaction(ctx context.Context, transactionHas
|
|||
return nil, err
|
||||
}
|
||||
|
||||
err = m.persistence.SaveMessages([]*Message{message})
|
||||
err = m.persistence.SaveMessages([]*common.Message{message})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response.Chats = []*Chat{chat}
|
||||
response.Messages = []*Message{message}
|
||||
response.Messages = []*common.Message{message}
|
||||
return &response, m.saveChat(chat)
|
||||
}
|
||||
|
||||
|
@ -3244,7 +3274,7 @@ func (m *Messenger) SendTransaction(ctx context.Context, chatID, value, contract
|
|||
return nil, errors.New("Need to be a one-to-one chat")
|
||||
}
|
||||
|
||||
message := &Message{}
|
||||
message := &common.Message{}
|
||||
err := extendMessageFromChat(message, chat, &m.identity.PublicKey, m.transport)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -3282,12 +3312,12 @@ func (m *Messenger) SendTransaction(ctx context.Context, chatID, value, contract
|
|||
}
|
||||
|
||||
message.ID = types.EncodeHex(newMessageID)
|
||||
message.CommandParameters = &CommandParameters{
|
||||
message.CommandParameters = &common.CommandParameters{
|
||||
TransactionHash: transactionHash,
|
||||
Value: value,
|
||||
Contract: contract,
|
||||
Signature: signature,
|
||||
CommandState: CommandStateTransactionSent,
|
||||
CommandState: common.CommandStateTransactionSent,
|
||||
}
|
||||
|
||||
err = message.PrepareContent()
|
||||
|
@ -3300,13 +3330,13 @@ func (m *Messenger) SendTransaction(ctx context.Context, chatID, value, contract
|
|||
return nil, err
|
||||
}
|
||||
|
||||
err = m.persistence.SaveMessages([]*Message{message})
|
||||
err = m.persistence.SaveMessages([]*common.Message{message})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response.Chats = []*Chat{chat}
|
||||
response.Messages = []*Message{message}
|
||||
response.Messages = []*common.Message{message}
|
||||
return &response, m.saveChat(chat)
|
||||
}
|
||||
|
||||
|
@ -3335,7 +3365,7 @@ func (m *Messenger) ValidateTransactions(ctx context.Context, addresses []types.
|
|||
return nil, err
|
||||
}
|
||||
for _, validationResult := range responses {
|
||||
var message *Message
|
||||
var message *common.Message
|
||||
chatID := contactIDFromPublicKey(validationResult.Transaction.From)
|
||||
chat, ok := m.allChats[chatID]
|
||||
if !ok {
|
||||
|
@ -3344,7 +3374,7 @@ func (m *Messenger) ValidateTransactions(ctx context.Context, addresses []types.
|
|||
if validationResult.Message != nil {
|
||||
message = validationResult.Message
|
||||
} else {
|
||||
message = &Message{}
|
||||
message = &common.Message{}
|
||||
err := extendMessageFromChat(message, chat, &m.identity.PublicKey, m.transport)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -3365,7 +3395,7 @@ func (m *Messenger) ValidateTransactions(ctx context.Context, addresses []types.
|
|||
|
||||
message.ID = validationResult.Transaction.MessageID
|
||||
if message.CommandParameters == nil {
|
||||
message.CommandParameters = &CommandParameters{}
|
||||
message.CommandParameters = &common.CommandParameters{}
|
||||
} else {
|
||||
message.CommandParameters = validationResult.Message.CommandParameters
|
||||
}
|
||||
|
@ -3373,7 +3403,7 @@ func (m *Messenger) ValidateTransactions(ctx context.Context, addresses []types.
|
|||
message.CommandParameters.Value = validationResult.Value
|
||||
message.CommandParameters.Contract = validationResult.Contract
|
||||
message.CommandParameters.Address = validationResult.Address
|
||||
message.CommandParameters.CommandState = CommandStateTransactionSent
|
||||
message.CommandParameters.CommandState = common.CommandStateTransactionSent
|
||||
message.CommandParameters.TransactionHash = validationResult.Transaction.TransactionHash
|
||||
|
||||
err = message.PrepareContent()
|
||||
|
@ -3422,7 +3452,7 @@ func (m *Messenger) ValidateTransactions(ctx context.Context, addresses []types.
|
|||
|
||||
// pullMessagesAndResponsesFromDB pulls all the messages and the one that have
|
||||
// been replied to from the database
|
||||
func (m *Messenger) pullMessagesAndResponsesFromDB(messages []*Message) ([]*Message, error) {
|
||||
func (m *Messenger) pullMessagesAndResponsesFromDB(messages []*common.Message) ([]*common.Message, error) {
|
||||
var messageIDs []string
|
||||
for _, message := range messages {
|
||||
messageIDs = append(messageIDs, message.ID)
|
||||
|
@ -3488,12 +3518,13 @@ func (m *Messenger) EnableSendingPushNotifications() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *Messenger) addedContactsAndMutedChatIDs() ([]*ecdsa.PublicKey, []string) {
|
||||
func (m *Messenger) pushNotificationOptions() *pushnotificationclient.RegistrationOptions {
|
||||
var contactIDs []*ecdsa.PublicKey
|
||||
var mutedChatIDs []string
|
||||
var publicChatIDs []string
|
||||
|
||||
for _, contact := range m.allContacts {
|
||||
if contact.IsAdded() {
|
||||
if contact.IsAdded() && !contact.IsBlocked() {
|
||||
pk, err := contact.PublicKey()
|
||||
if err != nil {
|
||||
m.logger.Warn("could not parse contact public key")
|
||||
|
@ -3508,9 +3539,16 @@ func (m *Messenger) addedContactsAndMutedChatIDs() ([]*ecdsa.PublicKey, []string
|
|||
if chat.Muted {
|
||||
mutedChatIDs = append(mutedChatIDs, chat.ID)
|
||||
}
|
||||
if chat.Active && chat.Public() {
|
||||
publicChatIDs = append(publicChatIDs, chat.ID)
|
||||
}
|
||||
|
||||
}
|
||||
return contactIDs, mutedChatIDs
|
||||
return &pushnotificationclient.RegistrationOptions{
|
||||
ContactIDs: contactIDs,
|
||||
MutedChatIDs: mutedChatIDs,
|
||||
PublicChatIDs: publicChatIDs,
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterForPushNotification register deviceToken with any push notification server enabled
|
||||
|
@ -3521,8 +3559,7 @@ func (m *Messenger) RegisterForPushNotifications(ctx context.Context, deviceToke
|
|||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
contactIDs, mutedChatIDs := m.addedContactsAndMutedChatIDs()
|
||||
err := m.pushNotificationClient.Register(deviceToken, apnTopic, tokenType, contactIDs, mutedChatIDs)
|
||||
err := m.pushNotificationClient.Register(deviceToken, apnTopic, tokenType, m.pushNotificationOptions())
|
||||
if err != nil {
|
||||
m.logger.Error("failed to register for push notifications", zap.Error(err))
|
||||
return err
|
||||
|
@ -3546,8 +3583,7 @@ func (m *Messenger) EnablePushNotificationsFromContactsOnly() error {
|
|||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
contactIDs, mutedChatIDs := m.addedContactsAndMutedChatIDs()
|
||||
return m.pushNotificationClient.EnablePushNotificationsFromContactsOnly(contactIDs, mutedChatIDs)
|
||||
return m.pushNotificationClient.EnablePushNotificationsFromContactsOnly(m.pushNotificationOptions())
|
||||
}
|
||||
|
||||
// DisablePushNotificationsFromContactsOnly is used to indicate that we want to received push notifications from anyone
|
||||
|
@ -3558,8 +3594,29 @@ func (m *Messenger) DisablePushNotificationsFromContactsOnly() error {
|
|||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
contactIDs, mutedChatIDs := m.addedContactsAndMutedChatIDs()
|
||||
return m.pushNotificationClient.DisablePushNotificationsFromContactsOnly(contactIDs, mutedChatIDs)
|
||||
return m.pushNotificationClient.DisablePushNotificationsFromContactsOnly(m.pushNotificationOptions())
|
||||
}
|
||||
|
||||
// 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())
|
||||
}
|
||||
|
||||
// GetPushNotificationsServers returns the servers used for push notifications
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
enstypes "github.com/status-im/status-go/eth-node/types/ens"
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
"github.com/status-im/status-go/protocol/tt"
|
||||
v1protocol "github.com/status-im/status-go/protocol/v1"
|
||||
|
@ -288,9 +289,9 @@ func (s *MessengerSuite) TestInit() {
|
|||
}
|
||||
}
|
||||
|
||||
func buildTestMessage(chat Chat) *Message {
|
||||
func buildTestMessage(chat Chat) *common.Message {
|
||||
clock, timestamp := chat.NextClockAndTimestamp(&testTimeSource{})
|
||||
message := &Message{}
|
||||
message := &common.Message{}
|
||||
message.Text = "text-input-message"
|
||||
message.ChatId = chat.ID
|
||||
message.Clock = clock
|
||||
|
@ -322,7 +323,7 @@ func (s *MessengerSuite) TestMarkMessagesSeen() {
|
|||
inputMessage2.ID = "2"
|
||||
inputMessage2.Seen = false
|
||||
|
||||
err = s.m.SaveMessages([]*Message{inputMessage1, inputMessage2})
|
||||
err = s.m.SaveMessages([]*common.Message{inputMessage1, inputMessage2})
|
||||
s.Require().NoError(err)
|
||||
|
||||
count, err := s.m.MarkMessagesSeen(chat.ID, []string{inputMessage1.ID})
|
||||
|
@ -346,7 +347,7 @@ func (s *MessengerSuite) TestMarkAllRead() {
|
|||
inputMessage2.ID = "2"
|
||||
inputMessage2.Seen = false
|
||||
|
||||
err = s.m.SaveMessages([]*Message{inputMessage1, inputMessage2})
|
||||
err = s.m.SaveMessages([]*common.Message{inputMessage1, inputMessage2})
|
||||
s.Require().NoError(err)
|
||||
|
||||
err = s.m.MarkAllRead(chat.ID)
|
||||
|
@ -374,7 +375,7 @@ func (s *MessengerSuite) TestSendPublic() {
|
|||
s.Require().NotEqual(uint64(0), chat.Timestamp, "it sets the timestamp")
|
||||
s.Require().Equal("0x"+hex.EncodeToString(crypto.FromECDSAPub(&s.privateKey.PublicKey)), outputMessage.From, "it sets the From field")
|
||||
s.Require().True(outputMessage.Seen, "it marks the message as seen")
|
||||
s.Require().Equal(outputMessage.OutgoingStatus, OutgoingStatusSending, "it marks the message as sending")
|
||||
s.Require().Equal(outputMessage.OutgoingStatus, common.OutgoingStatusSending, "it marks the message as sending")
|
||||
s.Require().NotEmpty(outputMessage.ID, "it sets the ID field")
|
||||
s.Require().Equal(protobuf.MessageType_PUBLIC_GROUP, outputMessage.MessageType)
|
||||
|
||||
|
@ -389,7 +390,7 @@ func (s *MessengerSuite) TestSendPrivateOneToOne() {
|
|||
pkString := hex.EncodeToString(crypto.FromECDSAPub(&recipientKey.PublicKey))
|
||||
chat := CreateOneToOneChat(pkString, &recipientKey.PublicKey, s.m.transport)
|
||||
|
||||
inputMessage := &Message{}
|
||||
inputMessage := &common.Message{}
|
||||
inputMessage.ChatId = chat.ID
|
||||
chat.LastClockValue = uint64(100000000000000)
|
||||
err = s.m.SaveChat(&chat)
|
||||
|
@ -405,7 +406,7 @@ func (s *MessengerSuite) TestSendPrivateOneToOne() {
|
|||
s.Require().NotEqual(uint64(0), chat.Timestamp, "it sets the timestamp")
|
||||
s.Require().Equal("0x"+hex.EncodeToString(crypto.FromECDSAPub(&s.privateKey.PublicKey)), outputMessage.From, "it sets the From field")
|
||||
s.Require().True(outputMessage.Seen, "it marks the message as seen")
|
||||
s.Require().Equal(outputMessage.OutgoingStatus, OutgoingStatusSending, "it marks the message as sending")
|
||||
s.Require().Equal(outputMessage.OutgoingStatus, common.OutgoingStatusSending, "it marks the message as sending")
|
||||
s.Require().NotEmpty(outputMessage.ID, "it sets the ID field")
|
||||
s.Require().Equal(protobuf.MessageType_ONE_TO_ONE, outputMessage.MessageType)
|
||||
}
|
||||
|
@ -422,13 +423,13 @@ func (s *MessengerSuite) TestSendPrivateGroup() {
|
|||
_, err = s.m.AddMembersToGroupChat(context.Background(), chat.ID, members)
|
||||
s.NoError(err)
|
||||
|
||||
inputMessage := &Message{}
|
||||
inputMessage := &common.Message{}
|
||||
inputMessage.ChatId = chat.ID
|
||||
chat.LastClockValue = uint64(100000000000000)
|
||||
err = s.m.SaveChat(chat)
|
||||
s.NoError(err)
|
||||
response, err = s.m.SendChatMessage(context.Background(), inputMessage)
|
||||
s.NoError(err)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(1, len(response.Messages), "it returns the message")
|
||||
outputMessage := response.Messages[0]
|
||||
|
||||
|
@ -438,7 +439,7 @@ func (s *MessengerSuite) TestSendPrivateGroup() {
|
|||
s.Require().NotEqual(uint64(0), chat.Timestamp, "it sets the timestamp")
|
||||
s.Require().Equal("0x"+hex.EncodeToString(crypto.FromECDSAPub(&s.privateKey.PublicKey)), outputMessage.From, "it sets the From field")
|
||||
s.Require().True(outputMessage.Seen, "it marks the message as seen")
|
||||
s.Require().Equal(outputMessage.OutgoingStatus, OutgoingStatusSending, "it marks the message as sending")
|
||||
s.Require().Equal(outputMessage.OutgoingStatus, common.OutgoingStatusSending, "it marks the message as sending")
|
||||
s.Require().NotEmpty(outputMessage.ID, "it sets the ID field")
|
||||
s.Require().Equal(protobuf.MessageType_PRIVATE_GROUP, outputMessage.MessageType)
|
||||
}
|
||||
|
@ -450,7 +451,7 @@ func (s *MessengerSuite) TestSendPrivateEmptyGroup() {
|
|||
|
||||
chat := response.Chats[0]
|
||||
|
||||
inputMessage := &Message{}
|
||||
inputMessage := &common.Message{}
|
||||
inputMessage.ChatId = chat.ID
|
||||
chat.LastClockValue = uint64(100000000000000)
|
||||
err = s.m.SaveChat(chat)
|
||||
|
@ -466,7 +467,7 @@ func (s *MessengerSuite) TestSendPrivateEmptyGroup() {
|
|||
s.Require().NotEqual(uint64(0), chat.Timestamp, "it sets the timestamp")
|
||||
s.Require().Equal("0x"+hex.EncodeToString(crypto.FromECDSAPub(&s.privateKey.PublicKey)), outputMessage.From, "it sets the From field")
|
||||
s.Require().True(outputMessage.Seen, "it marks the message as seen")
|
||||
s.Require().Equal(outputMessage.OutgoingStatus, OutgoingStatusSending, "it marks the message as sending")
|
||||
s.Require().Equal(outputMessage.OutgoingStatus, common.OutgoingStatusSending, "it marks the message as sending")
|
||||
s.Require().NotEmpty(outputMessage.ID, "it sets the ID field")
|
||||
s.Require().Equal(protobuf.MessageType_PRIVATE_GROUP, outputMessage.MessageType)
|
||||
}
|
||||
|
@ -962,7 +963,7 @@ func (s *MessengerSuite) TestChatPersistencePublic() {
|
|||
LastClockValue: 20,
|
||||
DeletedAtClockValue: 30,
|
||||
UnviewedMessagesCount: 40,
|
||||
LastMessage: &Message{},
|
||||
LastMessage: &common.Message{},
|
||||
}
|
||||
|
||||
s.Require().NoError(s.m.SaveChat(&chat))
|
||||
|
@ -987,7 +988,7 @@ func (s *MessengerSuite) TestDeleteChat() {
|
|||
LastClockValue: 20,
|
||||
DeletedAtClockValue: 30,
|
||||
UnviewedMessagesCount: 40,
|
||||
LastMessage: &Message{},
|
||||
LastMessage: &common.Message{},
|
||||
}
|
||||
|
||||
s.Require().NoError(s.m.SaveChat(&chat))
|
||||
|
@ -1010,7 +1011,7 @@ func (s *MessengerSuite) TestChatPersistenceUpdate() {
|
|||
LastClockValue: 20,
|
||||
DeletedAtClockValue: 30,
|
||||
UnviewedMessagesCount: 40,
|
||||
LastMessage: &Message{},
|
||||
LastMessage: &common.Message{},
|
||||
}
|
||||
|
||||
s.Require().NoError(s.m.SaveChat(&chat))
|
||||
|
@ -1044,7 +1045,7 @@ func (s *MessengerSuite) TestChatPersistenceOneToOne() {
|
|||
LastClockValue: 20,
|
||||
DeletedAtClockValue: 30,
|
||||
UnviewedMessagesCount: 40,
|
||||
LastMessage: &Message{},
|
||||
LastMessage: &common.Message{},
|
||||
}
|
||||
contact := Contact{
|
||||
ID: testPK,
|
||||
|
@ -1133,7 +1134,7 @@ func (s *MessengerSuite) TestChatPersistencePrivateGroupChat() {
|
|||
LastClockValue: 20,
|
||||
DeletedAtClockValue: 30,
|
||||
UnviewedMessagesCount: 40,
|
||||
LastMessage: &Message{},
|
||||
LastMessage: &common.Message{},
|
||||
}
|
||||
s.Require().NoError(s.m.SaveChat(&chat))
|
||||
savedChats := s.m.Chats()
|
||||
|
@ -1211,7 +1212,7 @@ func (s *MessengerSuite) TestBlockContact() {
|
|||
|
||||
contact.Name = "blocked"
|
||||
|
||||
messages := []*Message{
|
||||
messages := []*common.Message{
|
||||
{
|
||||
ID: "test-1",
|
||||
LocalChatID: chat2.ID,
|
||||
|
@ -1479,7 +1480,7 @@ func (s *MessengerSuite) TestDeclineRequestAddressForTransaction() {
|
|||
s.Require().Equal(value, senderMessage.CommandParameters.Value)
|
||||
s.Require().Equal(contract, senderMessage.CommandParameters.Contract)
|
||||
s.Require().Equal(initialCommandID, senderMessage.CommandParameters.ID)
|
||||
s.Require().Equal(CommandStateRequestAddressForTransaction, senderMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateRequestAddressForTransaction, senderMessage.CommandParameters.CommandState)
|
||||
|
||||
// Wait for the message to reach its destination
|
||||
response, err = WaitOnMessengerResponse(
|
||||
|
@ -1500,7 +1501,7 @@ func (s *MessengerSuite) TestDeclineRequestAddressForTransaction() {
|
|||
s.Require().Equal(value, receiverMessage.CommandParameters.Value)
|
||||
s.Require().Equal(contract, receiverMessage.CommandParameters.Contract)
|
||||
s.Require().Equal(initialCommandID, receiverMessage.CommandParameters.ID)
|
||||
s.Require().Equal(CommandStateRequestAddressForTransaction, receiverMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateRequestAddressForTransaction, receiverMessage.CommandParameters.CommandState)
|
||||
|
||||
// We decline the request
|
||||
response, err = theirMessenger.DeclineRequestAddressForTransaction(context.Background(), receiverMessage.ID)
|
||||
|
@ -1514,7 +1515,7 @@ func (s *MessengerSuite) TestDeclineRequestAddressForTransaction() {
|
|||
s.Require().NotNil(senderMessage.CommandParameters)
|
||||
s.Require().Equal(value, senderMessage.CommandParameters.Value)
|
||||
s.Require().Equal(contract, senderMessage.CommandParameters.Contract)
|
||||
s.Require().Equal(CommandStateRequestAddressForTransactionDeclined, senderMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateRequestAddressForTransactionDeclined, senderMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(initialCommandID, senderMessage.CommandParameters.ID)
|
||||
s.Require().Equal(receiverMessage.ID, senderMessage.Replace)
|
||||
|
||||
|
@ -1535,7 +1536,7 @@ func (s *MessengerSuite) TestDeclineRequestAddressForTransaction() {
|
|||
s.Require().NotNil(receiverMessage.CommandParameters)
|
||||
s.Require().Equal(value, receiverMessage.CommandParameters.Value)
|
||||
s.Require().Equal(contract, receiverMessage.CommandParameters.Contract)
|
||||
s.Require().Equal(CommandStateRequestAddressForTransactionDeclined, receiverMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateRequestAddressForTransactionDeclined, receiverMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(initialCommandID, receiverMessage.CommandParameters.ID)
|
||||
s.Require().Equal(initialCommandID, receiverMessage.Replace)
|
||||
s.Require().NoError(theirMessenger.Shutdown())
|
||||
|
@ -1574,7 +1575,7 @@ func (s *MessengerSuite) TestSendEthTransaction() {
|
|||
s.Require().Equal(contract, senderMessage.CommandParameters.Contract)
|
||||
s.Require().Equal(value, senderMessage.CommandParameters.Value)
|
||||
s.Require().Equal(signature, senderMessage.CommandParameters.Signature)
|
||||
s.Require().Equal(CommandStateTransactionSent, senderMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateTransactionSent, senderMessage.CommandParameters.CommandState)
|
||||
s.Require().NotEmpty(senderMessage.ID)
|
||||
s.Require().Equal("", senderMessage.Replace)
|
||||
|
||||
|
@ -1638,7 +1639,7 @@ func (s *MessengerSuite) TestSendEthTransaction() {
|
|||
s.Require().Equal(transactionHash, receiverMessage.CommandParameters.TransactionHash)
|
||||
s.Require().Equal(receiverAddressString, receiverMessage.CommandParameters.Address)
|
||||
s.Require().Equal("", receiverMessage.CommandParameters.ID)
|
||||
s.Require().Equal(CommandStateTransactionSent, receiverMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateTransactionSent, receiverMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(senderMessage.ID, receiverMessage.ID)
|
||||
s.Require().Equal("", receiverMessage.Replace)
|
||||
s.Require().NoError(theirMessenger.Shutdown())
|
||||
|
@ -1677,7 +1678,7 @@ func (s *MessengerSuite) TestSendTokenTransaction() {
|
|||
s.Require().Equal(value, senderMessage.CommandParameters.Value)
|
||||
s.Require().Equal(contract, senderMessage.CommandParameters.Contract)
|
||||
s.Require().Equal(signature, senderMessage.CommandParameters.Signature)
|
||||
s.Require().Equal(CommandStateTransactionSent, senderMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateTransactionSent, senderMessage.CommandParameters.CommandState)
|
||||
s.Require().NotEmpty(senderMessage.ID)
|
||||
|
||||
var transactions []*TransactionToValidate
|
||||
|
@ -1741,7 +1742,7 @@ func (s *MessengerSuite) TestSendTokenTransaction() {
|
|||
s.Require().Equal(transactionHash, receiverMessage.CommandParameters.TransactionHash)
|
||||
s.Require().Equal(receiverAddressString, receiverMessage.CommandParameters.Address)
|
||||
s.Require().Equal("", receiverMessage.CommandParameters.ID)
|
||||
s.Require().Equal(CommandStateTransactionSent, receiverMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateTransactionSent, receiverMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(senderMessage.ID, receiverMessage.ID)
|
||||
s.Require().Equal(senderMessage.Replace, senderMessage.Replace)
|
||||
s.Require().NoError(theirMessenger.Shutdown())
|
||||
|
@ -1775,7 +1776,7 @@ func (s *MessengerSuite) TestAcceptRequestAddressForTransaction() {
|
|||
s.Require().Equal(value, senderMessage.CommandParameters.Value)
|
||||
s.Require().Equal(contract, senderMessage.CommandParameters.Contract)
|
||||
s.Require().Equal(initialCommandID, senderMessage.CommandParameters.ID)
|
||||
s.Require().Equal(CommandStateRequestAddressForTransaction, senderMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateRequestAddressForTransaction, senderMessage.CommandParameters.CommandState)
|
||||
|
||||
// Wait for the message to reach its destination
|
||||
response, err = WaitOnMessengerResponse(
|
||||
|
@ -1796,7 +1797,7 @@ func (s *MessengerSuite) TestAcceptRequestAddressForTransaction() {
|
|||
s.Require().Equal(value, receiverMessage.CommandParameters.Value)
|
||||
s.Require().Equal(contract, receiverMessage.CommandParameters.Contract)
|
||||
s.Require().Equal(initialCommandID, receiverMessage.CommandParameters.ID)
|
||||
s.Require().Equal(CommandStateRequestAddressForTransaction, receiverMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateRequestAddressForTransaction, receiverMessage.CommandParameters.CommandState)
|
||||
|
||||
// We accept the request
|
||||
response, err = theirMessenger.AcceptRequestAddressForTransaction(context.Background(), receiverMessage.ID, "some-address")
|
||||
|
@ -1810,7 +1811,7 @@ func (s *MessengerSuite) TestAcceptRequestAddressForTransaction() {
|
|||
s.Require().NotNil(senderMessage.CommandParameters)
|
||||
s.Require().Equal(value, senderMessage.CommandParameters.Value)
|
||||
s.Require().Equal(contract, senderMessage.CommandParameters.Contract)
|
||||
s.Require().Equal(CommandStateRequestAddressForTransactionAccepted, senderMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateRequestAddressForTransactionAccepted, senderMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(initialCommandID, senderMessage.CommandParameters.ID)
|
||||
s.Require().Equal("some-address", senderMessage.CommandParameters.Address)
|
||||
s.Require().Equal(receiverMessage.ID, senderMessage.Replace)
|
||||
|
@ -1832,7 +1833,7 @@ func (s *MessengerSuite) TestAcceptRequestAddressForTransaction() {
|
|||
s.Require().NotNil(receiverMessage.CommandParameters)
|
||||
s.Require().Equal(value, receiverMessage.CommandParameters.Value)
|
||||
s.Require().Equal(contract, receiverMessage.CommandParameters.Contract)
|
||||
s.Require().Equal(CommandStateRequestAddressForTransactionAccepted, receiverMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateRequestAddressForTransactionAccepted, receiverMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(initialCommandID, receiverMessage.CommandParameters.ID)
|
||||
s.Require().Equal("some-address", receiverMessage.CommandParameters.Address)
|
||||
s.Require().Equal(initialCommandID, receiverMessage.Replace)
|
||||
|
@ -1868,7 +1869,7 @@ func (s *MessengerSuite) TestDeclineRequestTransaction() {
|
|||
s.Require().Equal(contract, senderMessage.CommandParameters.Contract)
|
||||
s.Require().Equal(receiverAddressString, senderMessage.CommandParameters.Address)
|
||||
s.Require().Equal(initialCommandID, senderMessage.CommandParameters.ID)
|
||||
s.Require().Equal(CommandStateRequestTransaction, senderMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateRequestTransaction, senderMessage.CommandParameters.CommandState)
|
||||
|
||||
// Wait for the message to reach its destination
|
||||
response, err = WaitOnMessengerResponse(
|
||||
|
@ -1890,7 +1891,7 @@ func (s *MessengerSuite) TestDeclineRequestTransaction() {
|
|||
s.Require().Equal(contract, receiverMessage.CommandParameters.Contract)
|
||||
s.Require().Equal(receiverAddressString, receiverMessage.CommandParameters.Address)
|
||||
s.Require().Equal(initialCommandID, receiverMessage.CommandParameters.ID)
|
||||
s.Require().Equal(CommandStateRequestTransaction, receiverMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateRequestTransaction, receiverMessage.CommandParameters.CommandState)
|
||||
|
||||
response, err = theirMessenger.DeclineRequestTransaction(context.Background(), initialCommandID)
|
||||
s.Require().NoError(err)
|
||||
|
@ -1904,7 +1905,7 @@ func (s *MessengerSuite) TestDeclineRequestTransaction() {
|
|||
s.Require().Equal("Transaction request declined", senderMessage.Text)
|
||||
s.Require().Equal(initialCommandID, senderMessage.CommandParameters.ID)
|
||||
s.Require().Equal(receiverMessage.ID, senderMessage.Replace)
|
||||
s.Require().Equal(CommandStateRequestTransactionDeclined, senderMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateRequestTransactionDeclined, senderMessage.CommandParameters.CommandState)
|
||||
|
||||
// Wait for the message to reach its destination
|
||||
response, err = WaitOnMessengerResponse(
|
||||
|
@ -1924,7 +1925,7 @@ func (s *MessengerSuite) TestDeclineRequestTransaction() {
|
|||
s.Require().Equal("Transaction request declined", receiverMessage.Text)
|
||||
s.Require().Equal(initialCommandID, receiverMessage.CommandParameters.ID)
|
||||
s.Require().Equal(initialCommandID, receiverMessage.Replace)
|
||||
s.Require().Equal(CommandStateRequestTransactionDeclined, receiverMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateRequestTransactionDeclined, receiverMessage.CommandParameters.CommandState)
|
||||
s.Require().NoError(theirMessenger.Shutdown())
|
||||
}
|
||||
|
||||
|
@ -1957,7 +1958,7 @@ func (s *MessengerSuite) TestRequestTransaction() {
|
|||
s.Require().Equal(contract, senderMessage.CommandParameters.Contract)
|
||||
s.Require().Equal(receiverAddressString, senderMessage.CommandParameters.Address)
|
||||
s.Require().Equal(initialCommandID, senderMessage.CommandParameters.ID)
|
||||
s.Require().Equal(CommandStateRequestTransaction, senderMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateRequestTransaction, senderMessage.CommandParameters.CommandState)
|
||||
|
||||
// Wait for the message to reach its destination
|
||||
response, err = WaitOnMessengerResponse(
|
||||
|
@ -1979,7 +1980,7 @@ func (s *MessengerSuite) TestRequestTransaction() {
|
|||
s.Require().Equal(contract, receiverMessage.CommandParameters.Contract)
|
||||
s.Require().Equal(receiverAddressString, receiverMessage.CommandParameters.Address)
|
||||
s.Require().Equal(initialCommandID, receiverMessage.CommandParameters.ID)
|
||||
s.Require().Equal(CommandStateRequestTransaction, receiverMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateRequestTransaction, receiverMessage.CommandParameters.CommandState)
|
||||
|
||||
transactionHash := "0x412a851ac2ae51cad34a56c8a9cfee55d577ac5e1ac71cf488a2f2093a373799"
|
||||
signature, err := buildSignature(theirMessenger.identity, &theirMessenger.identity.PublicKey, transactionHash)
|
||||
|
@ -2003,7 +2004,7 @@ func (s *MessengerSuite) TestRequestTransaction() {
|
|||
s.Require().Equal(signature, senderMessage.CommandParameters.Signature)
|
||||
s.Require().NotEmpty(senderMessage.ID)
|
||||
s.Require().Equal(receiverMessage.ID, senderMessage.Replace)
|
||||
s.Require().Equal(CommandStateTransactionSent, senderMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateTransactionSent, senderMessage.CommandParameters.CommandState)
|
||||
|
||||
var transactions []*TransactionToValidate
|
||||
// Wait for the message to reach its destination
|
||||
|
@ -2068,7 +2069,7 @@ func (s *MessengerSuite) TestRequestTransaction() {
|
|||
s.Require().Equal(receiverAddressString, receiverMessage.CommandParameters.Address)
|
||||
s.Require().Equal(initialCommandID, receiverMessage.CommandParameters.ID)
|
||||
s.Require().Equal(signature, receiverMessage.CommandParameters.Signature)
|
||||
s.Require().Equal(CommandStateTransactionSent, receiverMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(common.CommandStateTransactionSent, receiverMessage.CommandParameters.CommandState)
|
||||
s.Require().Equal(senderMessage.ID, receiverMessage.ID)
|
||||
s.Require().Equal(senderMessage.Replace, senderMessage.Replace)
|
||||
s.Require().NoError(theirMessenger.Shutdown())
|
||||
|
@ -2102,7 +2103,7 @@ func (m *mockSendMessagesRequest) SendMessagesRequest(peerID []byte, request typ
|
|||
}
|
||||
|
||||
func (s *MessengerSuite) TestMessageJSON() {
|
||||
message := &Message{
|
||||
message := &common.Message{
|
||||
ID: "test-1",
|
||||
LocalChatID: "local-chat-id",
|
||||
Alias: "alias",
|
||||
|
@ -2121,7 +2122,7 @@ func (s *MessengerSuite) TestMessageJSON() {
|
|||
s.Require().NoError(err)
|
||||
s.Require().Equal(expectedJSON, string(messageJSON))
|
||||
|
||||
decodedMessage := &Message{}
|
||||
decodedMessage := &common.Message{}
|
||||
err = json.Unmarshal([]byte(expectedJSON), decodedMessage)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(message, decodedMessage)
|
||||
|
@ -2186,14 +2187,14 @@ func (s *MessageHandlerSuite) TestRun() {
|
|||
Name string
|
||||
Error bool
|
||||
Chat Chat // Chat to create
|
||||
Message Message
|
||||
Message common.Message
|
||||
SigPubKey *ecdsa.PublicKey
|
||||
ExpectedChatID string
|
||||
}{
|
||||
{
|
||||
Name: "Public chat",
|
||||
Chat: CreatePublicChat("test-chat", &testTimeSource{}),
|
||||
Message: Message{
|
||||
Message: common.Message{
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
ChatId: "test-chat",
|
||||
MessageType: protobuf.MessageType_PUBLIC_GROUP,
|
||||
|
@ -2205,7 +2206,7 @@ func (s *MessageHandlerSuite) TestRun() {
|
|||
{
|
||||
Name: "Private message from myself with existing chat",
|
||||
Chat: CreateOneToOneChat("test-private-chat", &key1.PublicKey, &testTimeSource{}),
|
||||
Message: Message{
|
||||
Message: common.Message{
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
ChatId: "test-chat",
|
||||
MessageType: protobuf.MessageType_ONE_TO_ONE,
|
||||
|
@ -2217,7 +2218,7 @@ func (s *MessageHandlerSuite) TestRun() {
|
|||
{
|
||||
Name: "Private message from other with existing chat",
|
||||
Chat: CreateOneToOneChat("test-private-chat", &key2.PublicKey, &testTimeSource{}),
|
||||
Message: Message{
|
||||
Message: common.Message{
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
ChatId: "test-chat",
|
||||
MessageType: protobuf.MessageType_ONE_TO_ONE,
|
||||
|
@ -2229,7 +2230,7 @@ func (s *MessageHandlerSuite) TestRun() {
|
|||
},
|
||||
{
|
||||
Name: "Private message from myself without chat",
|
||||
Message: Message{
|
||||
Message: common.Message{
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
ChatId: "test-chat",
|
||||
MessageType: protobuf.MessageType_ONE_TO_ONE,
|
||||
|
@ -2241,7 +2242,7 @@ func (s *MessageHandlerSuite) TestRun() {
|
|||
},
|
||||
{
|
||||
Name: "Private message from other without chat",
|
||||
Message: Message{
|
||||
Message: common.Message{
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
ChatId: "test-chat",
|
||||
MessageType: protobuf.MessageType_ONE_TO_ONE,
|
||||
|
@ -2258,7 +2259,7 @@ func (s *MessageHandlerSuite) TestRun() {
|
|||
},
|
||||
{
|
||||
Name: "Private group message",
|
||||
Message: Message{
|
||||
Message: common.Message{
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
ChatId: "non-existing-chat",
|
||||
MessageType: protobuf.MessageType_PRIVATE_GROUP,
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
// 1596805115_create_group_chat_invitations_table.up.sql (231B)
|
||||
// 1597322655_add_invitation_admin_chat_field.up.sql (54B)
|
||||
// 1597757544_add_nickname.up.sql (52B)
|
||||
// 1598955122_add_mentions.down.sql (0)
|
||||
// 1598955122_add_mentions.up.sql (52B)
|
||||
// 1599641390_add_emoji_reactions_index.down.sql (67B)
|
||||
// 1599641390_add_emoji_reactions_index.up.sql (126B)
|
||||
// doc.go (850B)
|
||||
|
@ -533,6 +535,46 @@ func _1597757544_add_nicknameUpSql() (*asset, error) {
|
|||
return a, nil
|
||||
}
|
||||
|
||||
var __1598955122_add_mentionsDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x01\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00")
|
||||
|
||||
func _1598955122_add_mentionsDownSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1598955122_add_mentionsDownSql,
|
||||
"1598955122_add_mentions.down.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1598955122_add_mentionsDownSql() (*asset, error) {
|
||||
bytes, err := _1598955122_add_mentionsDownSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1598955122_add_mentions.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1599679300, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __1598955122_add_mentionsUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x28\x2d\x4e\x2d\x8a\xcf\x4d\x2d\x2e\x4e\x4c\x4f\x2d\x56\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\xc8\x4d\xcd\x2b\xc9\xcc\xcf\x2b\x56\x70\xf2\xf1\x77\xb2\xe6\x02\x04\x00\x00\xff\xff\xca\xf8\x74\x41\x34\x00\x00\x00")
|
||||
|
||||
func _1598955122_add_mentionsUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1598955122_add_mentionsUpSql,
|
||||
"1598955122_add_mentions.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1598955122_add_mentionsUpSql() (*asset, error) {
|
||||
bytes, err := _1598955122_add_mentionsUpSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1598955122_add_mentions.up.sql", size: 52, mode: os.FileMode(0644), modTime: time.Unix(1599679300, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8d, 0x22, 0x17, 0x92, 0xd2, 0x11, 0x4e, 0x7, 0x93, 0x9a, 0x55, 0xfd, 0xb, 0x97, 0xc4, 0x63, 0x6a, 0x81, 0x97, 0xcd, 0xb2, 0xf8, 0x4b, 0x5f, 0x3c, 0xfa, 0x3a, 0x38, 0x53, 0x10, 0xed, 0x9d}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __1599641390_add_emoji_reactions_indexDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x09\xf2\x0f\x50\xf0\xf4\x73\x71\x8d\x50\x48\xcd\xcd\xcf\xca\x8c\x2f\x4a\x4d\x4c\x2e\xc9\xcc\xcf\x2b\x8e\xcf\x4d\x2d\x2e\x4e\x4c\x4f\x8d\xcf\x4c\x89\xcf\xc9\x4f\x4e\xcc\x89\x4f\xce\x48\x2c\x01\xf1\x8a\x52\x4b\x8a\x12\x93\x4b\x52\x53\xe2\x33\x53\x2a\xac\xb9\x00\x01\x00\x00\xff\xff\xb2\x85\x84\xa0\x43\x00\x00\x00")
|
||||
|
||||
func _1599641390_add_emoji_reactions_indexDownSqlBytes() ([]byte, error) {
|
||||
|
@ -548,7 +590,7 @@ func _1599641390_add_emoji_reactions_indexDownSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1599641390_add_emoji_reactions_index.down.sql", size: 67, mode: os.FileMode(0644), modTime: time.Unix(1599641440, 0)}
|
||||
info := bindataFileInfo{name: "1599641390_add_emoji_reactions_index.down.sql", size: 67, mode: os.FileMode(0644), modTime: time.Unix(1599679300, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x89, 0x39, 0x0, 0x51, 0x5b, 0x48, 0xc3, 0xf3, 0x6a, 0x96, 0xf1, 0xd2, 0xa6, 0x60, 0xa8, 0x68, 0x21, 0xb5, 0xa0, 0x11, 0x11, 0x99, 0xde, 0xad, 0xa6, 0xa7, 0x56, 0xc1, 0xb2, 0xa6, 0x63, 0xe4}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -568,7 +610,7 @@ func _1599641390_add_emoji_reactions_indexUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1599641390_add_emoji_reactions_index.up.sql", size: 126, mode: os.FileMode(0644), modTime: time.Unix(1599641420, 0)}
|
||||
info := bindataFileInfo{name: "1599641390_add_emoji_reactions_index.up.sql", size: 126, mode: os.FileMode(0644), modTime: time.Unix(1599679300, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf9, 0xd8, 0xdc, 0xa7, 0xb, 0x92, 0x7a, 0x61, 0x37, 0x24, 0x1c, 0x77, 0x5e, 0xe, 0x7e, 0xfc, 0x9f, 0x98, 0x7b, 0x65, 0xe7, 0xf9, 0x71, 0x57, 0x89, 0x2d, 0x90, 0x1b, 0xf6, 0x5e, 0x37, 0xe8}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -728,6 +770,10 @@ var _bindata = map[string]func() (*asset, error){
|
|||
|
||||
"1597757544_add_nickname.up.sql": _1597757544_add_nicknameUpSql,
|
||||
|
||||
"1598955122_add_mentions.down.sql": _1598955122_add_mentionsDownSql,
|
||||
|
||||
"1598955122_add_mentions.up.sql": _1598955122_add_mentionsUpSql,
|
||||
|
||||
"1599641390_add_emoji_reactions_index.down.sql": _1599641390_add_emoji_reactions_indexDownSql,
|
||||
|
||||
"1599641390_add_emoji_reactions_index.up.sql": _1599641390_add_emoji_reactions_indexUpSql,
|
||||
|
@ -798,6 +844,8 @@ var _bintree = &bintree{nil, map[string]*bintree{
|
|||
"1596805115_create_group_chat_invitations_table.up.sql": &bintree{_1596805115_create_group_chat_invitations_tableUpSql, map[string]*bintree{}},
|
||||
"1597322655_add_invitation_admin_chat_field.up.sql": &bintree{_1597322655_add_invitation_admin_chat_fieldUpSql, map[string]*bintree{}},
|
||||
"1597757544_add_nickname.up.sql": &bintree{_1597757544_add_nicknameUpSql, map[string]*bintree{}},
|
||||
"1598955122_add_mentions.down.sql": &bintree{_1598955122_add_mentionsDownSql, map[string]*bintree{}},
|
||||
"1598955122_add_mentions.up.sql": &bintree{_1598955122_add_mentionsUpSql, map[string]*bintree{}},
|
||||
"1599641390_add_emoji_reactions_index.down.sql": &bintree{_1599641390_add_emoji_reactions_indexDownSql, map[string]*bintree{}},
|
||||
"1599641390_add_emoji_reactions_index.up.sql": &bintree{_1599641390_add_emoji_reactions_indexUpSql, map[string]*bintree{}},
|
||||
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE user_messages ADD COLUMN mentions BLOB;
|
|
@ -266,7 +266,7 @@ func (db sqlitePersistence) chats(tx *sql.Tx) (chats []*Chat, err error) {
|
|||
|
||||
// Restore last message
|
||||
if lastMessageBytes != nil {
|
||||
message := &Message{}
|
||||
message := &common.Message{}
|
||||
if err = json.Unmarshal(lastMessageBytes, message); err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -346,7 +346,7 @@ func (db sqlitePersistence) Chat(chatID string) (*Chat, error) {
|
|||
|
||||
// Restore last message
|
||||
if lastMessageBytes != nil {
|
||||
message := &Message{}
|
||||
message := &common.Message{}
|
||||
if err = json.Unmarshal(lastMessageBytes, message); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
"github.com/status-im/status-go/protocol/sqlite"
|
||||
)
|
||||
|
@ -101,9 +104,9 @@ func TestMessageByChatID(t *testing.T) {
|
|||
count := 1000
|
||||
pageSize := 50
|
||||
|
||||
var messages []*Message
|
||||
var messages []*common.Message
|
||||
for i := 0; i < count; i++ {
|
||||
messages = append(messages, &Message{
|
||||
messages = append(messages, &common.Message{
|
||||
ID: strconv.Itoa(i),
|
||||
LocalChatID: chatID,
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
|
@ -114,7 +117,7 @@ func TestMessageByChatID(t *testing.T) {
|
|||
|
||||
// Add some other chats.
|
||||
if count%5 == 0 {
|
||||
messages = append(messages, &Message{
|
||||
messages = append(messages, &common.Message{
|
||||
ID: strconv.Itoa(count + i),
|
||||
LocalChatID: "other-chat",
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
|
@ -130,7 +133,7 @@ func TestMessageByChatID(t *testing.T) {
|
|||
outOfOrderCount := pageSize + 1
|
||||
allCount := count + outOfOrderCount
|
||||
for i := 0; i < pageSize+1; i++ {
|
||||
messages = append(messages, &Message{
|
||||
messages = append(messages, &common.Message{
|
||||
ID: strconv.Itoa(count*2 + i),
|
||||
LocalChatID: chatID,
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
|
@ -145,13 +148,13 @@ func TestMessageByChatID(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
var (
|
||||
result []*Message
|
||||
result []*common.Message
|
||||
cursor string
|
||||
iter int
|
||||
)
|
||||
for {
|
||||
var (
|
||||
items []*Message
|
||||
items []*common.Message
|
||||
err error
|
||||
)
|
||||
|
||||
|
@ -181,7 +184,7 @@ func TestMessageReplies(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
p := sqlitePersistence{db: db}
|
||||
chatID := testPublicChatID
|
||||
message1 := &Message{
|
||||
message1 := &common.Message{
|
||||
ID: "id-1",
|
||||
LocalChatID: chatID,
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
|
@ -190,7 +193,7 @@ func TestMessageReplies(t *testing.T) {
|
|||
},
|
||||
From: "1",
|
||||
}
|
||||
message2 := &Message{
|
||||
message2 := &common.Message{
|
||||
ID: "id-2",
|
||||
LocalChatID: chatID,
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
|
@ -202,7 +205,7 @@ func TestMessageReplies(t *testing.T) {
|
|||
From: "2",
|
||||
}
|
||||
|
||||
message3 := &Message{
|
||||
message3 := &common.Message{
|
||||
ID: "id-3",
|
||||
LocalChatID: chatID,
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
|
@ -213,7 +216,7 @@ func TestMessageReplies(t *testing.T) {
|
|||
From: "3",
|
||||
}
|
||||
|
||||
messages := []*Message{message1, message2, message3}
|
||||
messages := []*common.Message{message1, message2, message3}
|
||||
|
||||
err = p.SaveMessages(messages)
|
||||
require.NoError(t, err)
|
||||
|
@ -225,7 +228,7 @@ func TestMessageReplies(t *testing.T) {
|
|||
require.Nil(t, retrievedMessages[0].QuotedMessage)
|
||||
|
||||
require.Equal(t, "id-1", retrievedMessages[1].ResponseTo)
|
||||
require.Equal(t, &QuotedMessage{From: "1", Text: "content-1"}, retrievedMessages[1].QuotedMessage)
|
||||
require.Equal(t, &common.QuotedMessage{From: "1", Text: "content-1"}, retrievedMessages[1].QuotedMessage)
|
||||
|
||||
require.Equal(t, "", retrievedMessages[2].ResponseTo)
|
||||
require.Nil(t, retrievedMessages[2].QuotedMessage)
|
||||
|
@ -240,10 +243,10 @@ func TestMessageByChatIDWithTheSameClocks(t *testing.T) {
|
|||
count := len(clockValues)
|
||||
pageSize := 2
|
||||
|
||||
var messages []*Message
|
||||
var messages []*common.Message
|
||||
|
||||
for i, clock := range clockValues {
|
||||
messages = append(messages, &Message{
|
||||
messages = append(messages, &common.Message{
|
||||
ID: strconv.Itoa(i),
|
||||
LocalChatID: chatID,
|
||||
ChatMessage: protobuf.ChatMessage{
|
||||
|
@ -257,13 +260,13 @@ func TestMessageByChatIDWithTheSameClocks(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
var (
|
||||
result []*Message
|
||||
result []*common.Message
|
||||
cursor string
|
||||
iter int
|
||||
)
|
||||
for {
|
||||
var (
|
||||
items []*Message
|
||||
items []*common.Message
|
||||
err error
|
||||
)
|
||||
|
||||
|
@ -322,14 +325,14 @@ func TestDeleteMessagesByChatID(t *testing.T) {
|
|||
err = insertMinimalMessage(p, "2")
|
||||
require.NoError(t, err)
|
||||
|
||||
m, _, err := p.MessageByChatID("chat-id", "", 10)
|
||||
m, _, err := p.MessageByChatID(testPublicChatID, "", 10)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(m))
|
||||
|
||||
err = p.DeleteMessagesByChatID("chat-id")
|
||||
err = p.DeleteMessagesByChatID(testPublicChatID)
|
||||
require.NoError(t, err)
|
||||
|
||||
m, _, err = p.MessageByChatID("chat-id", "", 10)
|
||||
m, _, err = p.MessageByChatID(testPublicChatID, "", 10)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(m))
|
||||
|
||||
|
@ -388,7 +391,7 @@ func TestPersistenceEmojiReactions(t *testing.T) {
|
|||
from2 := "from-2"
|
||||
from3 := "from-3"
|
||||
|
||||
chatID := "chat-id"
|
||||
chatID := testPublicChatID
|
||||
|
||||
err = insertMinimalMessage(p, id1)
|
||||
require.NoError(t, err)
|
||||
|
@ -485,9 +488,9 @@ func openTestDB() (*sql.DB, error) {
|
|||
}
|
||||
|
||||
func insertMinimalMessage(p sqlitePersistence, id string) error {
|
||||
return p.SaveMessages([]*Message{{
|
||||
return p.SaveMessages([]*common.Message{{
|
||||
ID: id,
|
||||
LocalChatID: "chat-id",
|
||||
LocalChatID: testPublicChatID,
|
||||
ChatMessage: protobuf.ChatMessage{Text: "some-text"},
|
||||
From: "me",
|
||||
}})
|
||||
|
@ -510,7 +513,7 @@ func TestMessagesAudioDurationMsNull(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Len(t, m, 1)
|
||||
|
||||
m, _, err = p.MessageByChatID("chat-id", "", 10)
|
||||
m, _, err = p.MessageByChatID(testPublicChatID, "", 10)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, m, 1)
|
||||
}
|
||||
|
@ -521,7 +524,7 @@ func TestSaveChat(t *testing.T) {
|
|||
p := sqlitePersistence{db: db}
|
||||
|
||||
chat := CreatePublicChat("test-chat", &testTimeSource{})
|
||||
chat.LastMessage = &Message{}
|
||||
chat.LastMessage = &common.Message{}
|
||||
err = p.SaveChat(chat)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -529,3 +532,33 @@ func TestSaveChat(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, &chat, retrievedChat)
|
||||
}
|
||||
|
||||
func TestSaveMentions(t *testing.T) {
|
||||
chatID := testPublicChatID
|
||||
db, err := openTestDB()
|
||||
require.NoError(t, err)
|
||||
p := sqlitePersistence{db: db}
|
||||
|
||||
key, err := crypto.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
pkString := types.EncodeHex(crypto.FromECDSAPub(&key.PublicKey))
|
||||
|
||||
message := common.Message{
|
||||
ID: "1",
|
||||
LocalChatID: chatID,
|
||||
ChatMessage: protobuf.ChatMessage{Text: "some-text"},
|
||||
From: "me",
|
||||
Mentions: []string{pkString},
|
||||
}
|
||||
|
||||
err = p.SaveMessages([]*common.Message{&message})
|
||||
require.NoError(t, err)
|
||||
|
||||
retrievedMessages, _, err := p.MessageByChatID(chatID, "", 10)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, retrievedMessages, 1)
|
||||
require.Len(t, retrievedMessages[0].Mentions, 1)
|
||||
require.Equal(t, retrievedMessages[0].Mentions, message.Mentions)
|
||||
|
||||
}
|
||||
|
|
|
@ -174,9 +174,7 @@ func init() {
|
|||
proto.RegisterType((*ApplicationMetadataMessage)(nil), "protobuf.ApplicationMetadataMessage")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("application_metadata_message.proto", fileDescriptor_ad09a6406fcf24c7)
|
||||
}
|
||||
func init() { proto.RegisterFile("application_metadata_message.proto", fileDescriptor_ad09a6406fcf24c7) }
|
||||
|
||||
var fileDescriptor_ad09a6406fcf24c7 = []byte{
|
||||
// 493 bytes of a gzipped FileDescriptorProto
|
||||
|
|
|
@ -123,9 +123,7 @@ func init() {
|
|||
proto.RegisterType((*GroupChatInvitation)(nil), "protobuf.GroupChatInvitation")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("group_chat_invitation.proto", fileDescriptor_a6a73333de6a8ebe)
|
||||
}
|
||||
func init() { proto.RegisterFile("group_chat_invitation.proto", fileDescriptor_a6a73333de6a8ebe) }
|
||||
|
||||
var fileDescriptor_a6a73333de6a8ebe = []byte{
|
||||
// 234 bytes of a gzipped FileDescriptorProto
|
||||
|
|
|
@ -335,9 +335,7 @@ func init() {
|
|||
proto.RegisterType((*SyncInstallation)(nil), "protobuf.SyncInstallation")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("pairing.proto", fileDescriptor_d61ab7221f0b5518)
|
||||
}
|
||||
func init() { proto.RegisterFile("pairing.proto", fileDescriptor_d61ab7221f0b5518) }
|
||||
|
||||
var fileDescriptor_d61ab7221f0b5518 = []byte{
|
||||
// 397 bytes of a gzipped FileDescriptorProto
|
||||
|
|
|
@ -142,21 +142,23 @@ func (PushNotificationReport_ErrorType) EnumDescriptor() ([]byte, []int) {
|
|||
}
|
||||
|
||||
type PushNotificationRegistration struct {
|
||||
TokenType PushNotificationRegistration_TokenType `protobuf:"varint,1,opt,name=token_type,json=tokenType,proto3,enum=protobuf.PushNotificationRegistration_TokenType" json:"token_type,omitempty"`
|
||||
DeviceToken string `protobuf:"bytes,2,opt,name=device_token,json=deviceToken,proto3" json:"device_token,omitempty"`
|
||||
InstallationId string `protobuf:"bytes,3,opt,name=installation_id,json=installationId,proto3" json:"installation_id,omitempty"`
|
||||
AccessToken string `protobuf:"bytes,4,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"`
|
||||
Enabled bool `protobuf:"varint,5,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
||||
Version uint64 `protobuf:"varint,6,opt,name=version,proto3" json:"version,omitempty"`
|
||||
AllowedKeyList [][]byte `protobuf:"bytes,7,rep,name=allowed_key_list,json=allowedKeyList,proto3" json:"allowed_key_list,omitempty"`
|
||||
BlockedChatList [][]byte `protobuf:"bytes,8,rep,name=blocked_chat_list,json=blockedChatList,proto3" json:"blocked_chat_list,omitempty"`
|
||||
Unregister bool `protobuf:"varint,9,opt,name=unregister,proto3" json:"unregister,omitempty"`
|
||||
Grant []byte `protobuf:"bytes,10,opt,name=grant,proto3" json:"grant,omitempty"`
|
||||
AllowFromContactsOnly bool `protobuf:"varint,11,opt,name=allow_from_contacts_only,json=allowFromContactsOnly,proto3" json:"allow_from_contacts_only,omitempty"`
|
||||
ApnTopic string `protobuf:"bytes,12,opt,name=apn_topic,json=apnTopic,proto3" json:"apn_topic,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
TokenType PushNotificationRegistration_TokenType `protobuf:"varint,1,opt,name=token_type,json=tokenType,proto3,enum=protobuf.PushNotificationRegistration_TokenType" json:"token_type,omitempty"`
|
||||
DeviceToken string `protobuf:"bytes,2,opt,name=device_token,json=deviceToken,proto3" json:"device_token,omitempty"`
|
||||
InstallationId string `protobuf:"bytes,3,opt,name=installation_id,json=installationId,proto3" json:"installation_id,omitempty"`
|
||||
AccessToken string `protobuf:"bytes,4,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"`
|
||||
Enabled bool `protobuf:"varint,5,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
||||
Version uint64 `protobuf:"varint,6,opt,name=version,proto3" json:"version,omitempty"`
|
||||
AllowedKeyList [][]byte `protobuf:"bytes,7,rep,name=allowed_key_list,json=allowedKeyList,proto3" json:"allowed_key_list,omitempty"`
|
||||
BlockedChatList [][]byte `protobuf:"bytes,8,rep,name=blocked_chat_list,json=blockedChatList,proto3" json:"blocked_chat_list,omitempty"`
|
||||
Unregister bool `protobuf:"varint,9,opt,name=unregister,proto3" json:"unregister,omitempty"`
|
||||
Grant []byte `protobuf:"bytes,10,opt,name=grant,proto3" json:"grant,omitempty"`
|
||||
AllowFromContactsOnly bool `protobuf:"varint,11,opt,name=allow_from_contacts_only,json=allowFromContactsOnly,proto3" json:"allow_from_contacts_only,omitempty"`
|
||||
ApnTopic string `protobuf:"bytes,12,opt,name=apn_topic,json=apnTopic,proto3" json:"apn_topic,omitempty"`
|
||||
BlockMentions bool `protobuf:"varint,13,opt,name=block_mentions,json=blockMentions,proto3" json:"block_mentions,omitempty"`
|
||||
AllowedMentionsChatList [][]byte `protobuf:"bytes,14,rep,name=allowed_mentions_chat_list,json=allowedMentionsChatList,proto3" json:"allowed_mentions_chat_list,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *PushNotificationRegistration) Reset() { *m = PushNotificationRegistration{} }
|
||||
|
@ -268,6 +270,20 @@ func (m *PushNotificationRegistration) GetApnTopic() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (m *PushNotificationRegistration) GetBlockMentions() bool {
|
||||
if m != nil {
|
||||
return m.BlockMentions
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *PushNotificationRegistration) GetAllowedMentionsChatList() [][]byte {
|
||||
if m != nil {
|
||||
return m.AllowedMentionsChatList
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PushNotificationRegistrationResponse struct {
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
Error PushNotificationRegistrationResponse_ErrorType `protobuf:"varint,2,opt,name=error,proto3,enum=protobuf.PushNotificationRegistrationResponse_ErrorType" json:"error,omitempty"`
|
||||
|
@ -550,6 +566,7 @@ type PushNotification struct {
|
|||
InstallationId string `protobuf:"bytes,4,opt,name=installation_id,json=installationId,proto3" json:"installation_id,omitempty"`
|
||||
Message []byte `protobuf:"bytes,5,opt,name=message,proto3" json:"message,omitempty"`
|
||||
Type PushNotification_PushNotificationType `protobuf:"varint,6,opt,name=type,proto3,enum=protobuf.PushNotification_PushNotificationType" json:"type,omitempty"`
|
||||
Author []byte `protobuf:"bytes,7,opt,name=author,proto3" json:"author,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
|
@ -622,6 +639,13 @@ func (m *PushNotification) GetType() PushNotification_PushNotificationType {
|
|||
return PushNotification_UNKNOWN_PUSH_NOTIFICATION_TYPE
|
||||
}
|
||||
|
||||
func (m *PushNotification) GetAuthor() []byte {
|
||||
if m != nil {
|
||||
return m.Author
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PushNotificationRequest struct {
|
||||
Requests []*PushNotification `protobuf:"bytes,1,rep,name=requests,proto3" json:"requests,omitempty"`
|
||||
MessageId []byte `protobuf:"bytes,2,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"`
|
||||
|
@ -799,65 +823,68 @@ func init() {
|
|||
func init() { proto.RegisterFile("push_notifications.proto", fileDescriptor_200acd86044eaa5d) }
|
||||
|
||||
var fileDescriptor_200acd86044eaa5d = []byte{
|
||||
// 952 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x51, 0x6f, 0xe3, 0x44,
|
||||
0x10, 0xc6, 0x4e, 0xda, 0x24, 0x93, 0x90, 0xba, 0xab, 0xb6, 0x67, 0x0e, 0x7a, 0x04, 0x83, 0x44,
|
||||
0xd4, 0x87, 0x80, 0x8a, 0xc4, 0x9d, 0x78, 0x22, 0xa4, 0x4e, 0xcf, 0x6a, 0x63, 0x87, 0x8d, 0xcb,
|
||||
0xe9, 0x24, 0x24, 0xcb, 0xb1, 0x37, 0xad, 0x55, 0xd7, 0x6b, 0xbc, 0x9b, 0xa2, 0xbc, 0xf1, 0x03,
|
||||
0x78, 0xe1, 0x95, 0x9f, 0xc1, 0x33, 0xff, 0x80, 0x3f, 0x85, 0xbc, 0xb6, 0xd3, 0xb4, 0x71, 0xd3,
|
||||
0x22, 0xf1, 0x94, 0xcc, 0x37, 0x3b, 0x33, 0xbb, 0xf3, 0xcd, 0x37, 0x06, 0x35, 0x9e, 0xb3, 0x2b,
|
||||
0x27, 0xa2, 0x3c, 0x98, 0x05, 0x9e, 0xcb, 0x03, 0x1a, 0xb1, 0x5e, 0x9c, 0x50, 0x4e, 0x51, 0x5d,
|
||||
0xfc, 0x4c, 0xe7, 0x33, 0xed, 0xef, 0x2a, 0x7c, 0x32, 0x9e, 0xb3, 0x2b, 0x73, 0xe5, 0x14, 0x26,
|
||||
0x97, 0x01, 0xe3, 0x89, 0xf8, 0x8f, 0x2c, 0x00, 0x4e, 0xaf, 0x49, 0xe4, 0xf0, 0x45, 0x4c, 0x54,
|
||||
0xa9, 0x23, 0x75, 0xdb, 0xc7, 0x5f, 0xf7, 0x8a, 0xf8, 0xde, 0xa6, 0xd8, 0x9e, 0x9d, 0x06, 0xda,
|
||||
0x8b, 0x98, 0xe0, 0x06, 0x2f, 0xfe, 0xa2, 0xcf, 0xa0, 0xe5, 0x93, 0xdb, 0xc0, 0x23, 0x8e, 0xc0,
|
||||
0x54, 0xb9, 0x23, 0x75, 0x1b, 0xb8, 0x99, 0x61, 0x22, 0x02, 0x7d, 0x09, 0x3b, 0x41, 0xc4, 0xb8,
|
||||
0x1b, 0x86, 0x22, 0x8f, 0x13, 0xf8, 0x6a, 0x45, 0x9c, 0x6a, 0xaf, 0xc2, 0x86, 0x9f, 0xe6, 0x72,
|
||||
0x3d, 0x8f, 0x30, 0x96, 0xe7, 0xaa, 0x66, 0xb9, 0x32, 0x2c, 0xcb, 0xa5, 0x42, 0x8d, 0x44, 0xee,
|
||||
0x34, 0x24, 0xbe, 0xba, 0xd5, 0x91, 0xba, 0x75, 0x5c, 0x98, 0xa9, 0xe7, 0x96, 0x24, 0x2c, 0xa0,
|
||||
0x91, 0xba, 0xdd, 0x91, 0xba, 0x55, 0x5c, 0x98, 0xa8, 0x0b, 0x8a, 0x1b, 0x86, 0xf4, 0x57, 0xe2,
|
||||
0x3b, 0xd7, 0x64, 0xe1, 0x84, 0x01, 0xe3, 0x6a, 0xad, 0x53, 0xe9, 0xb6, 0x70, 0x3b, 0xc7, 0xcf,
|
||||
0xc8, 0xe2, 0x3c, 0x60, 0x1c, 0x1d, 0xc1, 0xee, 0x34, 0xa4, 0xde, 0x35, 0xf1, 0x1d, 0xef, 0xca,
|
||||
0xe5, 0xd9, 0xd1, 0xba, 0x38, 0xba, 0x93, 0x3b, 0x06, 0x57, 0x2e, 0x17, 0x67, 0x5f, 0x01, 0xcc,
|
||||
0xa3, 0x44, 0xf4, 0x87, 0x24, 0x6a, 0x43, 0x5c, 0x66, 0x05, 0x41, 0x7b, 0xb0, 0x75, 0x99, 0xb8,
|
||||
0x11, 0x57, 0xa1, 0x23, 0x75, 0x5b, 0x38, 0x33, 0xd0, 0x6b, 0x50, 0x45, 0x4d, 0x67, 0x96, 0xd0,
|
||||
0x1b, 0xc7, 0xa3, 0x11, 0x77, 0x3d, 0xce, 0x1c, 0x1a, 0x85, 0x0b, 0xb5, 0x29, 0x72, 0xec, 0x0b,
|
||||
0xff, 0x30, 0xa1, 0x37, 0x83, 0xdc, 0x6b, 0x45, 0xe1, 0x02, 0x7d, 0x0c, 0x0d, 0x37, 0x8e, 0x1c,
|
||||
0x4e, 0xe3, 0xc0, 0x53, 0x5b, 0xa2, 0x31, 0x75, 0x37, 0x8e, 0xec, 0xd4, 0xd6, 0x86, 0xd0, 0x58,
|
||||
0x92, 0x83, 0x0e, 0x00, 0x5d, 0x98, 0x67, 0xa6, 0xf5, 0xce, 0x74, 0x6c, 0xeb, 0x4c, 0x37, 0x1d,
|
||||
0xfb, 0xfd, 0x58, 0x57, 0x3e, 0x40, 0x1f, 0x42, 0xa3, 0x3f, 0xce, 0x31, 0x45, 0x42, 0x08, 0xda,
|
||||
0x43, 0x03, 0xeb, 0x3f, 0xf4, 0x27, 0x7a, 0x8e, 0xc9, 0xda, 0x5f, 0x32, 0x7c, 0xb1, 0x69, 0x04,
|
||||
0x30, 0x61, 0x31, 0x8d, 0x18, 0x49, 0x9b, 0xcd, 0xe6, 0x82, 0x16, 0x31, 0x43, 0x75, 0x5c, 0x98,
|
||||
0xc8, 0x84, 0x2d, 0x92, 0x24, 0x34, 0x11, 0x83, 0xd0, 0x3e, 0x7e, 0xf3, 0xbc, 0xd9, 0x2a, 0x12,
|
||||
0xf7, 0xf4, 0x34, 0x56, 0xcc, 0x58, 0x96, 0x06, 0x1d, 0x02, 0x24, 0xe4, 0x97, 0x39, 0x61, 0xbc,
|
||||
0x98, 0x9b, 0x16, 0x6e, 0xe4, 0x88, 0xe1, 0x6b, 0xbf, 0x49, 0xd0, 0x58, 0xc6, 0xac, 0x3e, 0x5d,
|
||||
0xc7, 0xd8, 0xc2, 0xc5, 0xd3, 0xf7, 0x61, 0x77, 0xd4, 0x3f, 0x1f, 0x5a, 0x78, 0xa4, 0x9f, 0x38,
|
||||
0x23, 0x7d, 0x32, 0xe9, 0x9f, 0xea, 0x8a, 0x84, 0xf6, 0x40, 0xf9, 0x49, 0xc7, 0x13, 0xc3, 0x32,
|
||||
0x9d, 0x91, 0x31, 0x19, 0xf5, 0xed, 0xc1, 0x5b, 0x45, 0x46, 0x2f, 0xe1, 0xe0, 0xc2, 0x9c, 0x5c,
|
||||
0x8c, 0xc7, 0x16, 0xb6, 0xf5, 0x93, 0xd5, 0x1e, 0x56, 0xd2, 0xa6, 0x19, 0xa6, 0xad, 0x63, 0xb3,
|
||||
0x7f, 0x9e, 0x55, 0x50, 0xaa, 0xda, 0x1c, 0xd4, 0x9c, 0xa9, 0x01, 0xf5, 0x49, 0xdf, 0xbf, 0x25,
|
||||
0x09, 0x0f, 0x18, 0xb9, 0x21, 0x11, 0x47, 0xef, 0xe1, 0x60, 0x4d, 0xb5, 0x4e, 0x10, 0xcd, 0xa8,
|
||||
0x2a, 0x75, 0x2a, 0xdd, 0xe6, 0xf1, 0xe7, 0x8f, 0xb7, 0xe7, 0xc7, 0x39, 0x49, 0x16, 0x46, 0x34,
|
||||
0xa3, 0x78, 0x2f, 0x7e, 0xe0, 0x4a, 0x51, 0xed, 0x0d, 0xec, 0x97, 0x86, 0xa0, 0x4f, 0xa1, 0x19,
|
||||
0xcf, 0xa7, 0x61, 0xe0, 0xa5, 0xd3, 0xce, 0x44, 0xa1, 0x16, 0x86, 0x0c, 0x3a, 0x23, 0x0b, 0xa6,
|
||||
0xfd, 0x2e, 0xc3, 0x47, 0x8f, 0x56, 0x5b, 0x13, 0xa1, 0xb4, 0x2e, 0xc2, 0x12, 0x41, 0xcb, 0xa5,
|
||||
0x82, 0x3e, 0x04, 0xb8, 0xbb, 0x4a, 0x41, 0xde, 0xf2, 0x26, 0xa5, 0xc2, 0xac, 0x96, 0x0a, 0x73,
|
||||
0x29, 0xa6, 0xad, 0x55, 0x31, 0x3d, 0x2e, 0xf9, 0x23, 0xd8, 0x65, 0x24, 0xb9, 0x25, 0x89, 0xb3,
|
||||
0x52, 0xbf, 0x26, 0x62, 0x77, 0x32, 0xc7, 0xb8, 0xb8, 0x85, 0xf6, 0x87, 0x04, 0x87, 0xa5, 0xed,
|
||||
0x58, 0x4e, 0xfb, 0x6b, 0xa8, 0xfe, 0x57, 0xce, 0x44, 0x40, 0xfa, 0xfe, 0x1b, 0xc2, 0x98, 0x7b,
|
||||
0x49, 0x8a, 0x1e, 0xb5, 0x70, 0x23, 0x47, 0x0c, 0x7f, 0x55, 0x45, 0x95, 0x7b, 0x2a, 0xd2, 0xfe,
|
||||
0x91, 0x41, 0x79, 0x98, 0xfc, 0x39, 0xcc, 0xbc, 0x80, 0x9a, 0x58, 0x5c, 0xcb, 0x6a, 0xdb, 0xa9,
|
||||
0xf9, 0x34, 0x13, 0x25, 0x8c, 0x56, 0x4b, 0x19, 0x55, 0xa1, 0x96, 0xdf, 0x3f, 0xa7, 0xa2, 0x30,
|
||||
0xd1, 0x00, 0xaa, 0xe2, 0x9b, 0xb2, 0x2d, 0x74, 0xff, 0xd5, 0xe3, 0x4d, 0x5a, 0x03, 0x84, 0xdc,
|
||||
0x45, 0xb0, 0x66, 0xc3, 0x5e, 0x99, 0x17, 0x69, 0xf0, 0xaa, 0x10, 0xf6, 0xf8, 0x62, 0xf2, 0xd6,
|
||||
0x31, 0x2d, 0xdb, 0x18, 0x1a, 0x83, 0xbe, 0x9d, 0x6a, 0x37, 0x17, 0x79, 0x13, 0x6a, 0x77, 0xd2,
|
||||
0x16, 0x86, 0x99, 0xba, 0x15, 0x59, 0x8b, 0xe1, 0xc5, 0xfa, 0xf2, 0x11, 0x1b, 0x04, 0x7d, 0x0b,
|
||||
0xf5, 0x7c, 0x99, 0xb0, 0x9c, 0xde, 0x97, 0x1b, 0x36, 0xd6, 0xf2, 0xec, 0x13, 0xcc, 0x6a, 0x7f,
|
||||
0xca, 0x70, 0xb0, 0x5e, 0x32, 0xa6, 0x09, 0xdf, 0xb0, 0x3a, 0xbf, 0xbf, 0xbf, 0x3a, 0x8f, 0x36,
|
||||
0xad, 0xce, 0x34, 0x55, 0xe9, 0xb2, 0xfc, 0x3f, 0x58, 0xd6, 0x7e, 0x7e, 0xce, 0x52, 0xdd, 0x81,
|
||||
0xe6, 0x3b, 0x6c, 0x99, 0xa7, 0xab, 0x5f, 0x94, 0x07, 0xcb, 0x51, 0x4e, 0x31, 0xd3, 0xb2, 0x1d,
|
||||
0xac, 0x9f, 0x1a, 0x13, 0x5b, 0xc7, 0xfa, 0x89, 0x52, 0x49, 0x17, 0xe6, 0xfa, 0x83, 0x72, 0xa9,
|
||||
0xdd, 0xef, 0xab, 0xf4, 0x50, 0x31, 0xdf, 0x41, 0x2d, 0x11, 0x6f, 0x67, 0xaa, 0x2c, 0xd8, 0xea,
|
||||
0x3c, 0xd5, 0x24, 0x5c, 0x04, 0x4c, 0xb7, 0xc5, 0xc9, 0x6f, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0x42, 0x7f, 0xee, 0x48, 0x09, 0x00, 0x00,
|
||||
// 1002 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0xdd, 0x6e, 0xe3, 0x44,
|
||||
0x14, 0xc6, 0x4e, 0xda, 0x24, 0x27, 0x69, 0x9a, 0x8e, 0xfa, 0x63, 0x0a, 0x5d, 0x82, 0x01, 0x11,
|
||||
0xf5, 0xa2, 0xa0, 0x22, 0xb1, 0x2b, 0xb8, 0x21, 0xa4, 0x6e, 0xd7, 0x6a, 0x63, 0x87, 0x89, 0xcb,
|
||||
0x6a, 0x25, 0xa4, 0x91, 0x9b, 0x4c, 0x5b, 0xab, 0xae, 0xc7, 0x78, 0xc6, 0x45, 0xb9, 0xe3, 0x01,
|
||||
0xb8, 0xe1, 0x96, 0x2b, 0x9e, 0x81, 0x57, 0xe2, 0x45, 0x90, 0xc7, 0x76, 0xd6, 0x6d, 0xdc, 0xb4,
|
||||
0x48, 0x7b, 0x95, 0x9c, 0x6f, 0xce, 0x39, 0x33, 0xe7, 0xe7, 0xfb, 0x0c, 0x5a, 0x18, 0xf3, 0x6b,
|
||||
0x12, 0x30, 0xe1, 0x5d, 0x7a, 0x13, 0x57, 0x78, 0x2c, 0xe0, 0x07, 0x61, 0xc4, 0x04, 0x43, 0x75,
|
||||
0xf9, 0x73, 0x11, 0x5f, 0xea, 0x7f, 0xaf, 0xc0, 0xc7, 0xa3, 0x98, 0x5f, 0x5b, 0x05, 0x2f, 0x4c,
|
||||
0xaf, 0x3c, 0x2e, 0x22, 0xf9, 0x1f, 0xd9, 0x00, 0x82, 0xdd, 0xd0, 0x80, 0x88, 0x59, 0x48, 0x35,
|
||||
0xa5, 0xab, 0xf4, 0xda, 0x87, 0x5f, 0x1f, 0xe4, 0xf1, 0x07, 0xcb, 0x62, 0x0f, 0x9c, 0x24, 0xd0,
|
||||
0x99, 0x85, 0x14, 0x37, 0x44, 0xfe, 0x17, 0x7d, 0x0a, 0xad, 0x29, 0xbd, 0xf3, 0x26, 0x94, 0x48,
|
||||
0x4c, 0x53, 0xbb, 0x4a, 0xaf, 0x81, 0x9b, 0x29, 0x26, 0x23, 0xd0, 0x97, 0xb0, 0xee, 0x05, 0x5c,
|
||||
0xb8, 0xbe, 0x2f, 0xf3, 0x10, 0x6f, 0xaa, 0x55, 0xa4, 0x57, 0xbb, 0x08, 0x9b, 0xd3, 0x24, 0x97,
|
||||
0x3b, 0x99, 0x50, 0xce, 0xb3, 0x5c, 0xd5, 0x34, 0x57, 0x8a, 0xa5, 0xb9, 0x34, 0xa8, 0xd1, 0xc0,
|
||||
0xbd, 0xf0, 0xe9, 0x54, 0x5b, 0xe9, 0x2a, 0xbd, 0x3a, 0xce, 0xcd, 0xe4, 0xe4, 0x8e, 0x46, 0xdc,
|
||||
0x63, 0x81, 0xb6, 0xda, 0x55, 0x7a, 0x55, 0x9c, 0x9b, 0xa8, 0x07, 0x1d, 0xd7, 0xf7, 0xd9, 0x6f,
|
||||
0x74, 0x4a, 0x6e, 0xe8, 0x8c, 0xf8, 0x1e, 0x17, 0x5a, 0xad, 0x5b, 0xe9, 0xb5, 0x70, 0x3b, 0xc3,
|
||||
0x4f, 0xe9, 0xec, 0xcc, 0xe3, 0x02, 0xed, 0xc3, 0xc6, 0x85, 0xcf, 0x26, 0x37, 0x74, 0x4a, 0x26,
|
||||
0xd7, 0xae, 0x48, 0x5d, 0xeb, 0xd2, 0x75, 0x3d, 0x3b, 0x18, 0x5c, 0xbb, 0x42, 0xfa, 0xbe, 0x00,
|
||||
0x88, 0x83, 0x48, 0xf6, 0x87, 0x46, 0x5a, 0x43, 0x3e, 0xa6, 0x80, 0xa0, 0x4d, 0x58, 0xb9, 0x8a,
|
||||
0xdc, 0x40, 0x68, 0xd0, 0x55, 0x7a, 0x2d, 0x9c, 0x1a, 0xe8, 0x25, 0x68, 0xf2, 0x4e, 0x72, 0x19,
|
||||
0xb1, 0x5b, 0x32, 0x61, 0x81, 0x70, 0x27, 0x82, 0x13, 0x16, 0xf8, 0x33, 0xad, 0x29, 0x73, 0x6c,
|
||||
0xc9, 0xf3, 0xe3, 0x88, 0xdd, 0x0e, 0xb2, 0x53, 0x3b, 0xf0, 0x67, 0xe8, 0x23, 0x68, 0xb8, 0x61,
|
||||
0x40, 0x04, 0x0b, 0xbd, 0x89, 0xd6, 0x92, 0x8d, 0xa9, 0xbb, 0x61, 0xe0, 0x24, 0x36, 0xfa, 0x02,
|
||||
0xda, 0xf2, 0x79, 0xe4, 0x96, 0x06, 0x72, 0x31, 0xb4, 0x35, 0x99, 0x6b, 0x4d, 0xa2, 0xc3, 0x0c,
|
||||
0x44, 0xdf, 0xc3, 0x6e, 0xde, 0x88, 0xdc, 0xb1, 0x50, 0x67, 0x5b, 0xd6, 0xb9, 0x93, 0x79, 0xe4,
|
||||
0x41, 0x79, 0xbd, 0xfa, 0x31, 0x34, 0xe6, 0x0b, 0x80, 0xb6, 0x01, 0x9d, 0x5b, 0xa7, 0x96, 0xfd,
|
||||
0xc6, 0x22, 0x8e, 0x7d, 0x6a, 0x58, 0xc4, 0x79, 0x3b, 0x32, 0x3a, 0x1f, 0xa0, 0x35, 0x68, 0xf4,
|
||||
0x47, 0x19, 0xd6, 0x51, 0x10, 0x82, 0xf6, 0xb1, 0x89, 0x8d, 0x1f, 0xfb, 0x63, 0x23, 0xc3, 0x54,
|
||||
0xfd, 0x1f, 0x15, 0x3e, 0x5f, 0xb6, 0x66, 0x98, 0xf2, 0x90, 0x05, 0x9c, 0x26, 0x03, 0xe5, 0xb1,
|
||||
0x1c, 0xbd, 0xdc, 0xd3, 0x3a, 0xce, 0x4d, 0x64, 0xc1, 0x0a, 0x8d, 0x22, 0x16, 0xc9, 0x65, 0x6b,
|
||||
0x1f, 0xbe, 0x7a, 0xde, 0xfe, 0xe6, 0x89, 0x0f, 0x8c, 0x24, 0x56, 0xee, 0x71, 0x9a, 0x06, 0xed,
|
||||
0x01, 0x44, 0xf4, 0xd7, 0x98, 0x72, 0x91, 0xef, 0x66, 0x0b, 0x37, 0x32, 0xc4, 0x9c, 0xea, 0xbf,
|
||||
0x2b, 0xd0, 0x98, 0xc7, 0x14, 0x4b, 0x37, 0x30, 0xb6, 0x71, 0x5e, 0xfa, 0x16, 0x6c, 0x0c, 0xfb,
|
||||
0x67, 0xc7, 0x36, 0x1e, 0x1a, 0x47, 0x64, 0x68, 0x8c, 0xc7, 0xfd, 0x13, 0xa3, 0xa3, 0xa0, 0x4d,
|
||||
0xe8, 0xfc, 0x6c, 0xe0, 0xb1, 0x69, 0x5b, 0x64, 0x68, 0x8e, 0x87, 0x7d, 0x67, 0xf0, 0xba, 0xa3,
|
||||
0xa2, 0x5d, 0xd8, 0x3e, 0xb7, 0xc6, 0xe7, 0xa3, 0x91, 0x8d, 0x1d, 0xe3, 0xa8, 0xd8, 0xc3, 0x4a,
|
||||
0xd2, 0x34, 0xd3, 0x72, 0x0c, 0x6c, 0xf5, 0xcf, 0xd2, 0x1b, 0x3a, 0x55, 0x3d, 0x06, 0x2d, 0xdb,
|
||||
0x86, 0x01, 0x9b, 0xd2, 0xfe, 0xf4, 0x8e, 0x46, 0xc2, 0xe3, 0x34, 0x99, 0x22, 0x7a, 0x0b, 0xdb,
|
||||
0x0b, 0xca, 0x40, 0xbc, 0xe0, 0x92, 0x69, 0x4a, 0xb7, 0xd2, 0x6b, 0x1e, 0x7e, 0xf6, 0x78, 0x7b,
|
||||
0x7e, 0x8a, 0x69, 0x34, 0x33, 0x83, 0x4b, 0x86, 0x37, 0xc3, 0x07, 0x47, 0x09, 0xaa, 0xbf, 0x82,
|
||||
0xad, 0xd2, 0x10, 0xf4, 0x09, 0x34, 0xc3, 0xf8, 0xc2, 0xf7, 0x26, 0x09, 0xa3, 0xb8, 0xbc, 0xa8,
|
||||
0x85, 0x21, 0x85, 0x4e, 0xe9, 0x8c, 0xeb, 0x7f, 0xa8, 0xf0, 0xe1, 0xa3, 0xb7, 0x2d, 0x10, 0x5d,
|
||||
0x59, 0x24, 0x7a, 0x89, 0x68, 0xa8, 0xa5, 0xa2, 0xb1, 0x07, 0xf0, 0xee, 0x29, 0xf9, 0xf0, 0xe6,
|
||||
0x2f, 0x29, 0x25, 0x7f, 0xb5, 0x94, 0xfc, 0x73, 0xc2, 0xae, 0x14, 0x09, 0xfb, 0xb8, 0xac, 0xec,
|
||||
0xc3, 0x06, 0xa7, 0xd1, 0x1d, 0x8d, 0x48, 0xe1, 0xfe, 0x9a, 0x8c, 0x5d, 0x4f, 0x0f, 0x46, 0xf9,
|
||||
0x2b, 0xf4, 0x3f, 0x15, 0xd8, 0x2b, 0x6d, 0xc7, 0x7c, 0xdb, 0x5f, 0x42, 0xf5, 0xff, 0xce, 0x4c,
|
||||
0x06, 0x24, 0xf5, 0xdf, 0x52, 0xce, 0xdd, 0x2b, 0x9a, 0xf7, 0xa8, 0x85, 0x1b, 0x19, 0x62, 0x4e,
|
||||
0x8b, 0x2c, 0xaa, 0xdc, 0x63, 0x91, 0xfe, 0xaf, 0x0a, 0x9d, 0x87, 0xc9, 0x9f, 0x33, 0x99, 0x1d,
|
||||
0xa8, 0x49, 0xd1, 0x98, 0xdf, 0xb6, 0x9a, 0x98, 0x4f, 0x4f, 0xa2, 0x64, 0xa2, 0xd5, 0xd2, 0x89,
|
||||
0x6a, 0x50, 0xcb, 0xde, 0x9f, 0x8d, 0x22, 0x37, 0xd1, 0x00, 0xaa, 0xf2, 0xbb, 0xb5, 0x2a, 0x79,
|
||||
0xff, 0xd5, 0xe3, 0x4d, 0x5a, 0x00, 0x24, 0xdd, 0x65, 0x30, 0xda, 0x86, 0x55, 0x37, 0x16, 0xd7,
|
||||
0x2c, 0xca, 0x86, 0x95, 0x59, 0xba, 0x03, 0x9b, 0x65, 0x51, 0x48, 0x87, 0x17, 0x39, 0xe1, 0x47,
|
||||
0xe7, 0xe3, 0xd7, 0xc4, 0xb2, 0x1d, 0xf3, 0xd8, 0x1c, 0xf4, 0x9d, 0x84, 0xd3, 0x19, 0xf9, 0x9b,
|
||||
0x50, 0x7b, 0x47, 0x79, 0x69, 0x58, 0xc9, 0x71, 0x47, 0xd5, 0x43, 0xd8, 0x59, 0x14, 0x25, 0xa9,
|
||||
0x2c, 0xe8, 0x5b, 0xa8, 0x67, 0x22, 0xc3, 0xb3, 0xb1, 0xef, 0x2e, 0x51, 0xb2, 0xb9, 0xef, 0x13,
|
||||
0x13, 0xd7, 0xff, 0x52, 0x61, 0x7b, 0xf1, 0xca, 0x90, 0x45, 0x62, 0x89, 0xa4, 0xfe, 0x70, 0x5f,
|
||||
0x52, 0xf7, 0x97, 0x49, 0x6a, 0x92, 0xaa, 0x54, 0x44, 0xdf, 0xc7, 0xf4, 0xf5, 0x5f, 0x9e, 0x23,
|
||||
0xb6, 0xeb, 0xd0, 0x7c, 0x83, 0x6d, 0xeb, 0xa4, 0xf8, 0xa5, 0x79, 0x20, 0x9a, 0x6a, 0x82, 0x59,
|
||||
0xb6, 0x43, 0xb0, 0x71, 0x62, 0x8e, 0x1d, 0x03, 0x1b, 0x47, 0x9d, 0x4a, 0x22, 0xa4, 0x8b, 0x05,
|
||||
0x65, 0x14, 0xbc, 0xdf, 0x57, 0xe5, 0x21, 0x93, 0xbe, 0x83, 0x5a, 0x24, 0x6b, 0xe7, 0x9a, 0x2a,
|
||||
0xa7, 0xd5, 0x7d, 0xaa, 0x49, 0x38, 0x0f, 0xb8, 0x58, 0x95, 0x9e, 0xdf, 0xfc, 0x17, 0x00, 0x00,
|
||||
0xff, 0xff, 0xd4, 0x90, 0x1f, 0x72, 0xc4, 0x09, 0x00, 0x00,
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ message PushNotificationRegistration {
|
|||
bytes grant = 10;
|
||||
bool allow_from_contacts_only = 11;
|
||||
string apn_topic = 12;
|
||||
bool block_mentions = 13;
|
||||
repeated bytes allowed_mentions_chat_list = 14;
|
||||
}
|
||||
|
||||
message PushNotificationRegistrationResponse {
|
||||
|
@ -72,6 +74,7 @@ message PushNotification {
|
|||
MESSAGE = 1;
|
||||
MENTION = 2;
|
||||
}
|
||||
bytes author = 7;
|
||||
}
|
||||
|
||||
message PushNotificationRequest {
|
||||
|
|
|
@ -641,168 +641,6 @@ func (s *MessengerPushNotificationSuite) TestReceivePushNotificationRetries() {
|
|||
s.Require().NoError(server.Shutdown())
|
||||
}
|
||||
|
||||
// Here bob acts as his own server
|
||||
func (s *MessengerPushNotificationSuite) TestActAsYourOwnPushNotificationServer() {
|
||||
bob1 := s.m
|
||||
server := s.newPushNotificationServer(s.shh, s.m.identity)
|
||||
bob2 := server
|
||||
alice := s.newMessenger(s.shh)
|
||||
// start alice and enable sending push notifications
|
||||
s.Require().NoError(alice.Start())
|
||||
s.Require().NoError(alice.EnableSendingPushNotifications())
|
||||
bobInstallationIDs := []string{bob1.installationID, bob2.installationID}
|
||||
|
||||
// Register bob1
|
||||
err := bob1.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom)
|
||||
s.Require().NoError(err)
|
||||
|
||||
err = bob1.RegisterForPushNotifications(context.Background(), bob1DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN)
|
||||
|
||||
// Pull servers and check we registered
|
||||
err = tt.RetryWithBackOff(func() error {
|
||||
_, err = server.RetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = bob1.RetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
registered, err := bob1.RegisteredForPushNotifications()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !registered {
|
||||
return errors.New("not registered")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
// Make sure we receive it
|
||||
s.Require().NoError(err)
|
||||
bob1Servers, err := bob1.GetPushNotificationsServers()
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Register bob2
|
||||
err = bob2.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom)
|
||||
s.Require().NoError(err)
|
||||
|
||||
err = bob2.RegisterForPushNotifications(context.Background(), bob2DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN)
|
||||
s.Require().NoError(err)
|
||||
|
||||
err = tt.RetryWithBackOff(func() error {
|
||||
_, err = server.RetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = bob2.RetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
registered, err := bob2.RegisteredForPushNotifications()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !registered {
|
||||
return errors.New("not registered")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
// Make sure we receive it
|
||||
s.Require().NoError(err)
|
||||
bob2Servers, err := bob2.GetPushNotificationsServers()
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Create one to one chat & send message
|
||||
pkString := hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey))
|
||||
chat := CreateOneToOneChat(pkString, &s.m.identity.PublicKey, alice.transport)
|
||||
s.Require().NoError(alice.SaveChat(&chat))
|
||||
inputMessage := buildTestMessage(chat)
|
||||
response, err := alice.SendChatMessage(context.Background(), inputMessage)
|
||||
s.Require().NoError(err)
|
||||
messageIDString := response.Messages[0].ID
|
||||
messageID, err := hex.DecodeString(messageIDString[2:])
|
||||
s.Require().NoError(err)
|
||||
|
||||
var info []*pushnotificationclient.PushNotificationInfo
|
||||
err = tt.RetryWithBackOff(func() error {
|
||||
_, err = server.RetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = alice.RetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info, err = alice.pushNotificationClient.GetPushNotificationInfo(&bob1.identity.PublicKey, bobInstallationIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Check we have replies for both bob1 and bob2
|
||||
if len(info) != 2 {
|
||||
return errors.New("info not fetched")
|
||||
}
|
||||
return nil
|
||||
|
||||
})
|
||||
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Check we have replies for both bob1 and bob2
|
||||
var bob1Info, bob2Info *pushnotificationclient.PushNotificationInfo
|
||||
|
||||
if info[0].AccessToken == bob1Servers[0].AccessToken {
|
||||
bob1Info = info[0]
|
||||
bob2Info = info[1]
|
||||
} else {
|
||||
bob2Info = info[0]
|
||||
bob1Info = info[1]
|
||||
}
|
||||
|
||||
s.Require().NotNil(bob1Info)
|
||||
s.Require().Equal(bob1.installationID, bob1Info.InstallationID)
|
||||
s.Require().Equal(bob1Servers[0].AccessToken, bob1Info.AccessToken)
|
||||
s.Require().Equal(&bob1.identity.PublicKey, bob1Info.PublicKey)
|
||||
|
||||
s.Require().NotNil(bob2Info)
|
||||
s.Require().Equal(bob2.installationID, bob2Info.InstallationID)
|
||||
s.Require().Equal(bob2Servers[0].AccessToken, bob2Info.AccessToken)
|
||||
s.Require().Equal(&bob2.identity.PublicKey, bob2Info.PublicKey)
|
||||
|
||||
retrievedNotificationInfo, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob1.identity.PublicKey, bobInstallationIDs)
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(retrievedNotificationInfo)
|
||||
s.Require().Len(retrievedNotificationInfo, 2)
|
||||
|
||||
var sentNotification *pushnotificationclient.SentNotification
|
||||
err = tt.RetryWithBackOff(func() error {
|
||||
_, err = server.RetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = alice.RetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sentNotification, err = alice.pushNotificationClient.GetSentNotification(common.HashPublicKey(&bob1.identity.PublicKey), bob1.installationID, messageID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if sentNotification == nil {
|
||||
return errors.New("sent notification not found")
|
||||
}
|
||||
if !sentNotification.Success {
|
||||
return errors.New("sent notification not successul")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(bob2.Shutdown())
|
||||
s.Require().NoError(alice.Shutdown())
|
||||
}
|
||||
|
||||
func (s *MessengerPushNotificationSuite) TestContactCode() {
|
||||
|
||||
bob1 := s.m
|
||||
|
@ -853,3 +691,133 @@ func (s *MessengerPushNotificationSuite) TestContactCode() {
|
|||
s.Require().NoError(alice.Shutdown())
|
||||
s.Require().NoError(server.Shutdown())
|
||||
}
|
||||
|
||||
func (s *MessengerPushNotificationSuite) TestReceivePushNotificationMention() {
|
||||
|
||||
bob := s.m
|
||||
|
||||
serverKey, err := crypto.GenerateKey()
|
||||
s.Require().NoError(err)
|
||||
server := s.newPushNotificationServer(s.shh, serverKey)
|
||||
|
||||
alice := s.newMessenger(s.shh)
|
||||
// start alice and enable sending push notifications
|
||||
s.Require().NoError(alice.Start())
|
||||
s.Require().NoError(alice.EnableSendingPushNotifications())
|
||||
bobInstallationIDs := []string{bob.installationID}
|
||||
|
||||
// Create public chat and join for both alice and bob
|
||||
chat := CreatePublicChat("status", s.m.transport)
|
||||
err = bob.SaveChat(&chat)
|
||||
s.Require().NoError(err)
|
||||
|
||||
err = bob.Join(chat)
|
||||
s.Require().NoError(err)
|
||||
|
||||
err = alice.SaveChat(&chat)
|
||||
s.Require().NoError(err)
|
||||
|
||||
err = alice.Join(chat)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Register bob
|
||||
err = bob.AddPushNotificationsServer(context.Background(), &server.identity.PublicKey, pushnotificationclient.ServerTypeCustom)
|
||||
s.Require().NoError(err)
|
||||
|
||||
err = bob.RegisterForPushNotifications(context.Background(), bob1DeviceToken, testAPNTopic, protobuf.PushNotificationRegistration_APN_TOKEN)
|
||||
|
||||
// Pull servers and check we registered
|
||||
err = tt.RetryWithBackOff(func() error {
|
||||
_, err = server.RetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = bob.RetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
registered, err := bob.RegisteredForPushNotifications()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !registered {
|
||||
return errors.New("not registered")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
// Make sure we receive it
|
||||
s.Require().NoError(err)
|
||||
bobServers, err := bob.GetPushNotificationsServers()
|
||||
s.Require().NoError(err)
|
||||
|
||||
inputMessage := buildTestMessage(chat)
|
||||
// message contains a mention
|
||||
inputMessage.Text = "Hey @" + types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey))
|
||||
response, err := alice.SendChatMessage(context.Background(), inputMessage)
|
||||
s.Require().NoError(err)
|
||||
messageIDString := response.Messages[0].ID
|
||||
messageID, err := hex.DecodeString(messageIDString[2:])
|
||||
s.Require().NoError(err)
|
||||
|
||||
var bobInfo []*pushnotificationclient.PushNotificationInfo
|
||||
err = tt.RetryWithBackOff(func() error {
|
||||
_, err = server.RetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = alice.RetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bobInfo, err = alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Check we have replies for bob
|
||||
if len(bobInfo) != 1 {
|
||||
return errors.New("info not fetched")
|
||||
}
|
||||
return nil
|
||||
|
||||
})
|
||||
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.Require().NotEmpty(bobInfo)
|
||||
s.Require().Equal(bob.installationID, bobInfo[0].InstallationID)
|
||||
s.Require().Equal(bobServers[0].AccessToken, bobInfo[0].AccessToken)
|
||||
s.Require().Equal(&bob.identity.PublicKey, bobInfo[0].PublicKey)
|
||||
|
||||
retrievedNotificationInfo, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob.identity.PublicKey, bobInstallationIDs)
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(retrievedNotificationInfo)
|
||||
s.Require().Len(retrievedNotificationInfo, 1)
|
||||
|
||||
var sentNotification *pushnotificationclient.SentNotification
|
||||
err = tt.RetryWithBackOff(func() error {
|
||||
_, err = server.RetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = alice.RetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sentNotification, err = alice.pushNotificationClient.GetSentNotification(common.HashPublicKey(&bob.identity.PublicKey), bob.installationID, messageID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if sentNotification == nil {
|
||||
return errors.New("sent notification not found")
|
||||
}
|
||||
if !sentNotification.Success {
|
||||
return errors.New("sent notification not successul")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(alice.Shutdown())
|
||||
s.Require().NoError(server.Shutdown())
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"crypto/cipher"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
@ -47,6 +48,8 @@ import (
|
|||
const encryptedPayloadKeyLength = 16
|
||||
const accessTokenKeyLength = 16
|
||||
const staleQueryTimeInSeconds = 86400
|
||||
const mentionInstallationID = "mention"
|
||||
const oneToOneChatIDLength = 132
|
||||
|
||||
// maxRegistrationRetries is the maximum number of attempts we do before giving up registering with a server
|
||||
const maxRegistrationRetries int64 = 12
|
||||
|
@ -103,13 +106,21 @@ type PushNotificationInfo struct {
|
|||
}
|
||||
|
||||
type SentNotification struct {
|
||||
PublicKey *ecdsa.PublicKey
|
||||
InstallationID string
|
||||
LastTriedAt int64
|
||||
RetryCount int64
|
||||
MessageID []byte
|
||||
Success bool
|
||||
Error protobuf.PushNotificationReport_ErrorType
|
||||
PublicKey *ecdsa.PublicKey
|
||||
InstallationID string
|
||||
LastTriedAt int64
|
||||
RetryCount int64
|
||||
MessageID []byte
|
||||
ChatID string
|
||||
NotificationType protobuf.PushNotification_PushNotificationType
|
||||
Success bool
|
||||
Error protobuf.PushNotificationReport_ErrorType
|
||||
}
|
||||
|
||||
type RegistrationOptions struct {
|
||||
PublicChatIDs []string
|
||||
MutedChatIDs []string
|
||||
ContactIDs []*ecdsa.PublicKey
|
||||
}
|
||||
|
||||
func (s *SentNotification) HashedPublicKey() []byte {
|
||||
|
@ -128,6 +139,9 @@ type Config struct {
|
|||
// only from contacts
|
||||
AllowFromContactsOnly bool
|
||||
|
||||
// BlockMentions indicates whether we should not receive notification for mentions
|
||||
BlockMentions bool
|
||||
|
||||
// InstallationID is the installation-id for this device
|
||||
InstallationID string
|
||||
|
||||
|
@ -138,8 +152,13 @@ type Config struct {
|
|||
DefaultServers []*ecdsa.PublicKey
|
||||
}
|
||||
|
||||
type MessagePersistence interface {
|
||||
MessageByID(string) (*common.Message, error)
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
persistence *Persistence
|
||||
persistence *Persistence
|
||||
messagePersistence MessagePersistence
|
||||
|
||||
config *Config
|
||||
|
||||
|
@ -176,13 +195,14 @@ type Client struct {
|
|||
registrationSubscriptions []chan struct{}
|
||||
}
|
||||
|
||||
func New(persistence *Persistence, config *Config, processor *common.MessageProcessor) *Client {
|
||||
func New(persistence *Persistence, config *Config, processor *common.MessageProcessor, messagePersistence MessagePersistence) *Client {
|
||||
return &Client{
|
||||
quit: make(chan struct{}),
|
||||
config: config,
|
||||
messageProcessor: processor,
|
||||
persistence: persistence,
|
||||
reader: rand.Reader,
|
||||
quit: make(chan struct{}),
|
||||
config: config,
|
||||
messageProcessor: processor,
|
||||
messagePersistence: messagePersistence,
|
||||
persistence: persistence,
|
||||
reader: rand.Reader,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,15 +211,12 @@ func (c *Client) Start() error {
|
|||
return errors.New("can't start, missing message processor")
|
||||
}
|
||||
|
||||
c.config.Logger.Debug("starting push notification client", zap.Any("config", c.config))
|
||||
|
||||
err := c.loadLastPushNotificationRegistration()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.subscribeForSentMessages()
|
||||
c.subscribeForScheduledMessages()
|
||||
c.subscribeForMessageEvents()
|
||||
|
||||
// We start even if push notifications are disabled, as we might
|
||||
// actually be sending an unregister message
|
||||
|
@ -299,7 +316,7 @@ func (c *Client) GetServers() ([]*PushNotificationServer, error) {
|
|||
return c.persistence.GetServers()
|
||||
}
|
||||
|
||||
func (c *Client) Reregister(contactIDs []*ecdsa.PublicKey, mutedChatIDs []string) error {
|
||||
func (c *Client) Reregister(options *RegistrationOptions) error {
|
||||
c.config.Logger.Debug("re-registering")
|
||||
if len(c.deviceToken) == 0 {
|
||||
c.config.Logger.Info("no device token, not registering")
|
||||
|
@ -311,7 +328,7 @@ func (c *Client) Reregister(contactIDs []*ecdsa.PublicKey, mutedChatIDs []string
|
|||
return nil
|
||||
}
|
||||
|
||||
return c.Register(c.deviceToken, c.apnTopic, c.tokenType, contactIDs, mutedChatIDs)
|
||||
return c.Register(c.deviceToken, c.apnTopic, c.tokenType, options)
|
||||
}
|
||||
|
||||
// pickDefaultServesr picks n servers at random
|
||||
|
@ -333,7 +350,7 @@ func (c *Client) pickDefaultServers(servers []*ecdsa.PublicKey) []*ecdsa.PublicK
|
|||
}
|
||||
|
||||
// Register registers with all the servers
|
||||
func (c *Client) Register(deviceToken, apnTopic string, tokenType protobuf.PushNotificationRegistration_TokenType, contactIDs []*ecdsa.PublicKey, mutedChatIDs []string) error {
|
||||
func (c *Client) Register(deviceToken, apnTopic string, tokenType protobuf.PushNotificationRegistration_TokenType, options *RegistrationOptions) error {
|
||||
// stop registration loop
|
||||
c.stopRegistrationLoop()
|
||||
|
||||
|
@ -364,12 +381,12 @@ func (c *Client) Register(deviceToken, apnTopic string, tokenType protobuf.PushN
|
|||
c.apnTopic = apnTopic
|
||||
c.tokenType = tokenType
|
||||
|
||||
registration, err := c.buildPushNotificationRegistrationMessage(contactIDs, mutedChatIDs)
|
||||
registration, err := c.buildPushNotificationRegistrationMessage(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.saveLastPushNotificationRegistration(registration, contactIDs)
|
||||
err = c.saveLastPushNotificationRegistration(registration, options.ContactIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -588,22 +605,42 @@ func (c *Client) DisableSending() {
|
|||
c.config.SendEnabled = false
|
||||
}
|
||||
|
||||
func (c *Client) EnablePushNotificationsFromContactsOnly(contactIDs []*ecdsa.PublicKey, mutedChatIDs []string) error {
|
||||
func (c *Client) EnablePushNotificationsFromContactsOnly(options *RegistrationOptions) error {
|
||||
c.config.Logger.Debug("enabling push notification from contacts only")
|
||||
c.config.AllowFromContactsOnly = true
|
||||
if c.lastPushNotificationRegistration != nil && c.config.RemoteNotificationsEnabled {
|
||||
c.config.Logger.Debug("re-registering after enabling push notifications from contacts only")
|
||||
return c.Register(c.deviceToken, c.apnTopic, c.tokenType, contactIDs, mutedChatIDs)
|
||||
return c.Register(c.deviceToken, c.apnTopic, c.tokenType, options)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) DisablePushNotificationsFromContactsOnly(contactIDs []*ecdsa.PublicKey, mutedChatIDs []string) error {
|
||||
func (c *Client) DisablePushNotificationsFromContactsOnly(options *RegistrationOptions) error {
|
||||
c.config.Logger.Debug("disabling push notification from contacts only")
|
||||
c.config.AllowFromContactsOnly = false
|
||||
if c.lastPushNotificationRegistration != nil && c.config.RemoteNotificationsEnabled {
|
||||
c.config.Logger.Debug("re-registering after disabling push notifications from contacts only")
|
||||
return c.Register(c.deviceToken, c.apnTopic, c.tokenType, contactIDs, mutedChatIDs)
|
||||
return c.Register(c.deviceToken, c.apnTopic, c.tokenType, options)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) EnablePushNotificationsBlockMentions(options *RegistrationOptions) error {
|
||||
c.config.Logger.Debug("disabling push notifications for mentions")
|
||||
c.config.BlockMentions = true
|
||||
if c.lastPushNotificationRegistration != nil && c.config.RemoteNotificationsEnabled {
|
||||
c.config.Logger.Debug("re-registering after disabling push notifications for mentions")
|
||||
return c.Register(c.deviceToken, c.apnTopic, c.tokenType, options)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) DisablePushNotificationsBlockMentions(options *RegistrationOptions) error {
|
||||
c.config.Logger.Debug("enabling push notifications for mentions")
|
||||
c.config.BlockMentions = false
|
||||
if c.lastPushNotificationRegistration != nil && c.config.RemoteNotificationsEnabled {
|
||||
c.config.Logger.Debug("re-registering after enabling push notifications for mentions")
|
||||
return c.Register(c.deviceToken, c.apnTopic, c.tokenType, options)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -644,37 +681,21 @@ func (c *Client) generateSharedKey(publicKey *ecdsa.PublicKey) ([]byte, error) {
|
|||
)
|
||||
}
|
||||
|
||||
// subscribeForSentMessages subscribes for newly sent messages so we can check if we need to send a push notification
|
||||
func (c *Client) subscribeForSentMessages() {
|
||||
// subscribeForMessageEvents subscribes for newly sent/scheduled messages so we can check if we need to send a push notification
|
||||
func (c *Client) subscribeForMessageEvents() {
|
||||
go func() {
|
||||
c.config.Logger.Debug("subscribing for sent messages")
|
||||
subscription := c.messageProcessor.SubscribeToSentMessages()
|
||||
c.config.Logger.Debug("subscribing for message events")
|
||||
sentMessagesSubscription := c.messageProcessor.SubscribeToSentMessages()
|
||||
scheduledMessagesSubscription := c.messageProcessor.SubscribeToScheduledMessages()
|
||||
for {
|
||||
select {
|
||||
case m, more := <-subscription:
|
||||
if !more {
|
||||
c.config.Logger.Debug("no more sent messages, quitting")
|
||||
return
|
||||
}
|
||||
c.config.Logger.Debug("handling message sent")
|
||||
if err := c.handleMessageSent(m); err != nil {
|
||||
c.config.Logger.Error("failed to handle message", zap.Error(err))
|
||||
}
|
||||
case <-c.quit:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// subscribeForScheduledMessages subscribes for messages scheduler for dispatch
|
||||
func (c *Client) subscribeForScheduledMessages() {
|
||||
go func() {
|
||||
c.config.Logger.Debug("subscribing for scheduled messages")
|
||||
subscription := c.messageProcessor.SubscribeToScheduledMessages()
|
||||
for {
|
||||
select {
|
||||
case m, more := <-subscription:
|
||||
// order is important, since both are asynchronous, we want to process
|
||||
// first scheduled messages, and after sent messages, otherwise we might
|
||||
// have some race conditions.
|
||||
// This does not completely rules them out, but reduced the window
|
||||
// where it might happen, a single channel should be used
|
||||
// if this actually happens.
|
||||
case m, more := <-scheduledMessagesSubscription:
|
||||
if !more {
|
||||
c.config.Logger.Debug("no more scheduled messages, quitting")
|
||||
return
|
||||
|
@ -683,6 +704,16 @@ func (c *Client) subscribeForScheduledMessages() {
|
|||
if err := c.handleMessageScheduled(m); err != nil {
|
||||
c.config.Logger.Error("failed to handle message", zap.Error(err))
|
||||
}
|
||||
|
||||
case m, more := <-sentMessagesSubscription:
|
||||
if !more {
|
||||
c.config.Logger.Debug("no more sent messages, quitting")
|
||||
return
|
||||
}
|
||||
c.config.Logger.Debug("handling message sent")
|
||||
if err := c.handleMessageSent(m); err != nil {
|
||||
c.config.Logger.Error("failed to handle message", zap.Error(err))
|
||||
}
|
||||
case <-c.quit:
|
||||
return
|
||||
}
|
||||
|
@ -785,10 +816,9 @@ func (c *Client) queryNotificationInfo(publicKey *ecdsa.PublicKey, force bool) e
|
|||
return nil
|
||||
}
|
||||
|
||||
// handleMessageSent is called every time a message is sent. It will check if
|
||||
// we need to notify on the message, and if so it will try to dispatch a push notification
|
||||
// messages might be batched, if coming from datasync for example.
|
||||
// handleMessageSent is called every time a message is sent
|
||||
func (c *Client) handleMessageSent(sentMessage *common.SentMessage) error {
|
||||
|
||||
c.config.Logger.Debug("sent messages", zap.Any("messageIDs", sentMessage.MessageIDs))
|
||||
|
||||
// Ignore if we are not sending notifications
|
||||
|
@ -797,6 +827,109 @@ func (c *Client) handleMessageSent(sentMessage *common.SentMessage) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
if sentMessage.PublicKey == nil {
|
||||
return c.handlePublicMessageSent(sentMessage)
|
||||
}
|
||||
return c.handleDirectMessageSent(sentMessage)
|
||||
}
|
||||
|
||||
// saving to the database might happen after we fetch the message, so we retry
|
||||
// for a reasonable amount of time before giving up
|
||||
func (c *Client) getMessage(messageID string) (*common.Message, error) {
|
||||
retries := 0
|
||||
for retries < 10 {
|
||||
message, err := c.messagePersistence.MessageByID(messageID)
|
||||
if err == sql.ErrNoRows {
|
||||
retries++
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
continue
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return message, nil
|
||||
}
|
||||
return nil, sql.ErrNoRows
|
||||
}
|
||||
|
||||
// handlePublicMessageSent handles public messages, we notify only on mentions
|
||||
func (c *Client) handlePublicMessageSent(sentMessage *common.SentMessage) error {
|
||||
// We always expect a single message, as we never batch them
|
||||
if len(sentMessage.MessageIDs) != 1 {
|
||||
return errors.New("batched public messages not handled")
|
||||
}
|
||||
|
||||
messageID := sentMessage.MessageIDs[0]
|
||||
c.config.Logger.Debug("handling public messages", zap.Binary("messageID", messageID))
|
||||
tracked, err := c.persistence.TrackedMessage(messageID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !tracked {
|
||||
c.config.Logger.Debug("messageID not tracked, nothing to do", zap.Binary("messageID", messageID))
|
||||
}
|
||||
|
||||
c.config.Logger.Debug("messageID tracked", zap.Binary("messageID", messageID))
|
||||
|
||||
message, err := c.getMessage(types.EncodeHex(messageID))
|
||||
if err != nil {
|
||||
c.config.Logger.Error("could not retrieve message", zap.Error(err))
|
||||
}
|
||||
|
||||
// This might happen if the user deleted their messages for example
|
||||
if message == nil {
|
||||
c.config.Logger.Warn("message not retrieved")
|
||||
return nil
|
||||
}
|
||||
|
||||
c.config.Logger.Debug("message found", zap.Binary("messageID", messageID))
|
||||
for _, pkString := range message.Mentions {
|
||||
c.config.Logger.Debug("handling mention", zap.String("publickey", pkString))
|
||||
pubkeyBytes, err := types.DecodeHex(pkString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
publicKey, err := crypto.UnmarshalPubkey(pubkeyBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// we use a synthetic installationID for mentions, as all devices need to be notified
|
||||
shouldNotify, err := c.shouldNotifyOn(publicKey, mentionInstallationID, messageID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.config.Logger.Debug("should no mention", zap.Any("publickey", shouldNotify))
|
||||
// we send the notifications and return the info of the devices notified
|
||||
infos, err := c.sendNotification(publicKey, nil, messageID, message.LocalChatID, protobuf.PushNotification_MENTION)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// mark message as sent so we don't notify again
|
||||
for _, i := range infos {
|
||||
c.config.Logger.Debug("marking as sent ", zap.Binary("mid", messageID), zap.String("id", i.InstallationID))
|
||||
if err := c.notifiedOn(publicKey, i.InstallationID, messageID, message.LocalChatID, protobuf.PushNotification_MESSAGE); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// handleDirectMessageSent handles one to ones and private group chat messages
|
||||
// It will check if we need to notify on the message, and if so it will try to
|
||||
// dispatch a push notification messages might be batched, if coming
|
||||
// from datasync for example.
|
||||
func (c *Client) handleDirectMessageSent(sentMessage *common.SentMessage) error {
|
||||
c.config.Logger.Debug("handling direct messages", zap.Any("messageIDs", sentMessage.MessageIDs))
|
||||
|
||||
publicKey := sentMessage.PublicKey
|
||||
|
||||
// Collect the messageIDs we want to notify on
|
||||
|
@ -849,8 +982,27 @@ func (c *Client) handleMessageSent(sentMessage *common.SentMessage) error {
|
|||
|
||||
c.config.Logger.Debug("actionable messages", zap.Any("message-ids", trackedMessageIDs), zap.Any("installation-ids", installationIDs))
|
||||
|
||||
// Get message to check chatID. Again we use the first message for simplicity, but we should send one for each chatID. Messages though are very rarely batched.
|
||||
message, err := c.getMessage(types.EncodeHex(trackedMessageIDs[0]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// This is not the prettiest.
|
||||
// because chatIDs are asymettric, we need to check if it's a one-to-one message or a group chat message.
|
||||
// to do that we fingerprint the chatID.
|
||||
// If it's a public key, we use our own public key as chatID, which correspond to the chatID used by the other peer
|
||||
// otherwise we use the group chat ID
|
||||
var chatID string
|
||||
if len(message.ChatId) == oneToOneChatIDLength {
|
||||
chatID = types.EncodeHex(crypto.FromECDSAPub(&c.config.Identity.PublicKey))
|
||||
} else {
|
||||
// this is a group chat
|
||||
chatID = message.ChatId
|
||||
}
|
||||
|
||||
// we send the notifications and return the info of the devices notified
|
||||
infos, err := c.sendNotification(publicKey, installationIDs, trackedMessageIDs[0])
|
||||
infos, err := c.sendNotification(publicKey, installationIDs, trackedMessageIDs[0], chatID, protobuf.PushNotification_MESSAGE)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -860,7 +1012,7 @@ func (c *Client) handleMessageSent(sentMessage *common.SentMessage) error {
|
|||
for _, messageID := range trackedMessageIDs {
|
||||
|
||||
c.config.Logger.Debug("marking as sent ", zap.Binary("mid", messageID), zap.String("id", i.InstallationID))
|
||||
if err := c.notifiedOn(publicKey, i.InstallationID, messageID); err != nil {
|
||||
if err := c.notifiedOn(publicKey, i.InstallationID, messageID, chatID, protobuf.PushNotification_MESSAGE); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -890,17 +1042,19 @@ func (c *Client) shouldNotifyOn(publicKey *ecdsa.PublicKey, installationID strin
|
|||
return c.persistence.ShouldSendNotificationFor(publicKey, installationID, messageID)
|
||||
}
|
||||
|
||||
// notifiedOn marks a combination of publickey/installationid/messageID as notified
|
||||
func (c *Client) notifiedOn(publicKey *ecdsa.PublicKey, installationID string, messageID []byte) error {
|
||||
// notifiedOn marks a combination of publickey/installationid/messageID/chatID/type as notified
|
||||
func (c *Client) notifiedOn(publicKey *ecdsa.PublicKey, installationID string, messageID []byte, chatID string, notificationType protobuf.PushNotification_PushNotificationType) error {
|
||||
return c.persistence.UpsertSentNotification(&SentNotification{
|
||||
PublicKey: publicKey,
|
||||
LastTriedAt: time.Now().Unix(),
|
||||
InstallationID: installationID,
|
||||
MessageID: messageID,
|
||||
PublicKey: publicKey,
|
||||
LastTriedAt: time.Now().Unix(),
|
||||
InstallationID: installationID,
|
||||
MessageID: messageID,
|
||||
ChatID: chatID,
|
||||
NotificationType: notificationType,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Client) mutedChatIDsHashes(chatIDs []string) [][]byte {
|
||||
func (c *Client) chatIDsHashes(chatIDs []string) [][]byte {
|
||||
var mutedChatListHashes [][]byte
|
||||
|
||||
for _, chatID := range chatIDs {
|
||||
|
@ -979,26 +1133,27 @@ func (c *Client) getVersion() uint64 {
|
|||
return c.lastPushNotificationRegistration.Version + 1
|
||||
}
|
||||
|
||||
func (c *Client) buildPushNotificationRegistrationMessage(contactIDs []*ecdsa.PublicKey, mutedChatIDs []string) (*protobuf.PushNotificationRegistration, error) {
|
||||
token := c.getToken(contactIDs)
|
||||
allowedKeyList, err := c.allowedKeyList([]byte(token), contactIDs)
|
||||
func (c *Client) buildPushNotificationRegistrationMessage(options *RegistrationOptions) (*protobuf.PushNotificationRegistration, error) {
|
||||
token := c.getToken(options.ContactIDs)
|
||||
allowedKeyList, err := c.allowedKeyList([]byte(token), options.ContactIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
options := &protobuf.PushNotificationRegistration{
|
||||
AccessToken: token,
|
||||
TokenType: c.tokenType,
|
||||
ApnTopic: c.apnTopic,
|
||||
Version: c.getVersion(),
|
||||
InstallationId: c.config.InstallationID,
|
||||
DeviceToken: c.deviceToken,
|
||||
AllowFromContactsOnly: c.config.AllowFromContactsOnly,
|
||||
Enabled: c.config.RemoteNotificationsEnabled,
|
||||
BlockedChatList: c.mutedChatIDsHashes(mutedChatIDs),
|
||||
AllowedKeyList: allowedKeyList,
|
||||
}
|
||||
return options, nil
|
||||
return &protobuf.PushNotificationRegistration{
|
||||
AccessToken: token,
|
||||
TokenType: c.tokenType,
|
||||
ApnTopic: c.apnTopic,
|
||||
Version: c.getVersion(),
|
||||
InstallationId: c.config.InstallationID,
|
||||
DeviceToken: c.deviceToken,
|
||||
AllowFromContactsOnly: c.config.AllowFromContactsOnly,
|
||||
Enabled: c.config.RemoteNotificationsEnabled,
|
||||
BlockedChatList: c.chatIDsHashes(options.MutedChatIDs),
|
||||
BlockMentions: c.config.BlockMentions,
|
||||
AllowedMentionsChatList: c.chatIDsHashes(options.PublicChatIDs),
|
||||
AllowedKeyList: allowedKeyList,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Client) buildPushNotificationUnregisterMessage() *protobuf.PushNotificationRegistration {
|
||||
|
@ -1128,7 +1283,8 @@ func (c *Client) registerWithServer(registration *protobuf.PushNotificationRegis
|
|||
|
||||
// sendNotification sends an actual notification to the push notification server.
|
||||
// the notification is sent using an ephemeral key to shield the real identity of the sender
|
||||
func (c *Client) sendNotification(publicKey *ecdsa.PublicKey, installationIDs []string, messageID []byte) ([]*PushNotificationInfo, error) {
|
||||
func (c *Client) sendNotification(publicKey *ecdsa.PublicKey, installationIDs []string, messageID []byte, chatID string, notificationType protobuf.PushNotification_PushNotificationType) ([]*PushNotificationInfo, error) {
|
||||
|
||||
// get latest push notification infos
|
||||
err := c.queryNotificationInfo(publicKey, false)
|
||||
if err != nil {
|
||||
|
@ -1187,12 +1343,12 @@ func (c *Client) sendNotification(publicKey *ecdsa.PublicKey, installationIDs []
|
|||
for _, infos := range actionableInfos {
|
||||
var pushNotifications []*protobuf.PushNotification
|
||||
for _, i := range infos {
|
||||
// TODO: Add group chat ChatID
|
||||
pushNotifications = append(pushNotifications, &protobuf.PushNotification{
|
||||
Type: protobuf.PushNotification_MESSAGE,
|
||||
Type: notificationType,
|
||||
// For now we set the ChatID to our own identity key, this will work fine for blocked users
|
||||
// and muted 1-to-1 chats, but not for group chats.
|
||||
ChatId: common.Shake256([]byte(types.EncodeHex(crypto.FromECDSAPub(&c.config.Identity.PublicKey)))),
|
||||
ChatId: common.Shake256([]byte(chatID)),
|
||||
Author: common.Shake256([]byte(types.EncodeHex(crypto.FromECDSAPub(&c.config.Identity.PublicKey)))),
|
||||
AccessToken: i.AccessToken,
|
||||
PublicKey: common.HashPublicKey(publicKey),
|
||||
InstallationId: i.InstallationID,
|
||||
|
@ -1251,7 +1407,7 @@ func (c *Client) resendNotification(pn *SentNotification) error {
|
|||
return err
|
||||
}
|
||||
|
||||
_, err = c.sendNotification(pn.PublicKey, []string{pn.InstallationID}, pn.MessageID)
|
||||
_, err = c.sendNotification(pn.PublicKey, []string{pn.InstallationID}, pn.MessageID, pn.ChatID, pn.NotificationType)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -1304,6 +1460,9 @@ func (c *Client) resendingLoop() error {
|
|||
|
||||
// registrationLoop is a loop that is running when we need to register with a push notification server, it only runs when needed, it will quit if no work is necessary.
|
||||
func (c *Client) registrationLoop() error {
|
||||
if c.lastPushNotificationRegistration == nil {
|
||||
return nil
|
||||
}
|
||||
for {
|
||||
c.config.Logger.Debug("running registration loop")
|
||||
servers, err := c.persistence.GetServers()
|
||||
|
|
|
@ -58,7 +58,7 @@ func (s *ClientSuite) SetupTest() {
|
|||
InstallationID: s.installationID,
|
||||
}
|
||||
|
||||
s.client = New(s.persistence, config, nil)
|
||||
s.client = New(s.persistence, config, nil, nil)
|
||||
}
|
||||
|
||||
func (s *ClientSuite) TestBuildPushNotificationRegisterMessage() {
|
||||
|
@ -74,6 +74,11 @@ func (s *ClientSuite) TestBuildPushNotificationRegisterMessage() {
|
|||
s.Require().NoError(err)
|
||||
contactIDs := []*ecdsa.PublicKey{&contactKey.PublicKey}
|
||||
|
||||
options := &RegistrationOptions{
|
||||
ContactIDs: contactIDs,
|
||||
MutedChatIDs: mutedChatList,
|
||||
}
|
||||
|
||||
// Set random generator for uuid
|
||||
var seed int64 = 1
|
||||
uuid.SetRand(rand.New(rand.NewSource(seed)))
|
||||
|
@ -88,7 +93,7 @@ func (s *ClientSuite) TestBuildPushNotificationRegisterMessage() {
|
|||
// Set reader
|
||||
s.client.reader = bytes.NewReader([]byte(expectedUUID))
|
||||
|
||||
options := &protobuf.PushNotificationRegistration{
|
||||
registration := &protobuf.PushNotificationRegistration{
|
||||
Version: 1,
|
||||
AccessToken: expectedUUID,
|
||||
DeviceToken: testDeviceToken,
|
||||
|
@ -97,24 +102,36 @@ func (s *ClientSuite) TestBuildPushNotificationRegisterMessage() {
|
|||
BlockedChatList: mutedChatListHashes,
|
||||
}
|
||||
|
||||
actualMessage, err := s.client.buildPushNotificationRegistrationMessage(contactIDs, mutedChatList)
|
||||
actualMessage, err := s.client.buildPushNotificationRegistrationMessage(options)
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.Require().Equal(options, actualMessage)
|
||||
s.Require().Equal(registration, actualMessage)
|
||||
}
|
||||
|
||||
func (s *ClientSuite) TestBuildPushNotificationRegisterMessageAllowFromContactsOnly() {
|
||||
mutedChatList := []string{"a", "b"}
|
||||
publicChatList := []string{"c", "d"}
|
||||
|
||||
// build chat lish hashes
|
||||
// build muted chat lish hashes
|
||||
var mutedChatListHashes [][]byte
|
||||
for _, chatID := range mutedChatList {
|
||||
mutedChatListHashes = append(mutedChatListHashes, common.Shake256([]byte(chatID)))
|
||||
}
|
||||
|
||||
// build public chat lish hashes
|
||||
var publicChatListHashes [][]byte
|
||||
for _, chatID := range publicChatList {
|
||||
publicChatListHashes = append(publicChatListHashes, common.Shake256([]byte(chatID)))
|
||||
}
|
||||
|
||||
contactKey, err := crypto.GenerateKey()
|
||||
s.Require().NoError(err)
|
||||
contactIDs := []*ecdsa.PublicKey{&contactKey.PublicKey}
|
||||
options := &RegistrationOptions{
|
||||
ContactIDs: contactIDs,
|
||||
MutedChatIDs: mutedChatList,
|
||||
PublicChatIDs: publicChatList,
|
||||
}
|
||||
|
||||
// Set random generator for uuid
|
||||
var seed int64 = 1
|
||||
|
@ -144,21 +161,22 @@ func (s *ClientSuite) TestBuildPushNotificationRegisterMessageAllowFromContactsO
|
|||
// Set reader
|
||||
s.client.reader = bytes.NewReader([]byte(expectedUUID))
|
||||
|
||||
options := &protobuf.PushNotificationRegistration{
|
||||
Version: 1,
|
||||
AccessToken: expectedUUID,
|
||||
DeviceToken: testDeviceToken,
|
||||
InstallationId: s.installationID,
|
||||
AllowFromContactsOnly: true,
|
||||
Enabled: true,
|
||||
BlockedChatList: mutedChatListHashes,
|
||||
AllowedKeyList: [][]byte{encryptedToken},
|
||||
registration := &protobuf.PushNotificationRegistration{
|
||||
Version: 1,
|
||||
AccessToken: expectedUUID,
|
||||
DeviceToken: testDeviceToken,
|
||||
InstallationId: s.installationID,
|
||||
AllowFromContactsOnly: true,
|
||||
Enabled: true,
|
||||
BlockedChatList: mutedChatListHashes,
|
||||
AllowedKeyList: [][]byte{encryptedToken},
|
||||
AllowedMentionsChatList: publicChatListHashes,
|
||||
}
|
||||
|
||||
actualMessage, err := s.client.buildPushNotificationRegistrationMessage(contactIDs, mutedChatList)
|
||||
actualMessage, err := s.client.buildPushNotificationRegistrationMessage(options)
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.Require().Equal(options, actualMessage)
|
||||
s.Require().Equal(registration, actualMessage)
|
||||
}
|
||||
|
||||
func (s *ClientSuite) TestHandleMessageScheduled() {
|
||||
|
@ -183,7 +201,7 @@ func (s *ClientSuite) TestHandleMessageScheduled() {
|
|||
s.Require().True(response)
|
||||
|
||||
// Save notification
|
||||
s.Require().NoError(s.client.notifiedOn(&key1.PublicKey, installationID1, messageID))
|
||||
s.Require().NoError(s.client.notifiedOn(&key1.PublicKey, installationID1, messageID, chatID, protobuf.PushNotification_MESSAGE))
|
||||
|
||||
// Second time, should not notify
|
||||
response, err = s.client.shouldNotifyOn(&key1.PublicKey, installationID1, messageID)
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
// 1593601729_initial_schema.up.sql (1.773kB)
|
||||
// 1597909626_add_server_type.down.sql (0)
|
||||
// 1597909626_add_server_type.up.sql (145B)
|
||||
// 1599053776_add_chat_id_and_type.down.sql (0)
|
||||
// 1599053776_add_chat_id_and_type.up.sql (264B)
|
||||
// doc.go (382B)
|
||||
|
||||
package migrations
|
||||
|
@ -128,7 +130,7 @@ func _1597909626_add_server_typeDownSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1597909626_add_server_type.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1597909727, 0)}
|
||||
info := bindataFileInfo{name: "1597909626_add_server_type.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1598949727, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -148,11 +150,51 @@ func _1597909626_add_server_typeUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1597909626_add_server_type.up.sql", size: 145, mode: os.FileMode(0644), modTime: time.Unix(1597909704, 0)}
|
||||
info := bindataFileInfo{name: "1597909626_add_server_type.up.sql", size: 145, mode: os.FileMode(0644), modTime: time.Unix(1598949727, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc8, 0x3f, 0xe0, 0xe7, 0x57, 0x0, 0x5d, 0x60, 0xf3, 0x55, 0x64, 0x71, 0x80, 0x3c, 0xca, 0x8, 0x61, 0xb5, 0x3c, 0xe, 0xa1, 0xe4, 0x61, 0xd1, 0x4e, 0xd8, 0xb2, 0x55, 0xdd, 0x87, 0x62, 0x9b}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __1599053776_add_chat_id_and_typeDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x01\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00")
|
||||
|
||||
func _1599053776_add_chat_id_and_typeDownSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1599053776_add_chat_id_and_typeDownSql,
|
||||
"1599053776_add_chat_id_and_type.down.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1599053776_add_chat_id_and_typeDownSql() (*asset, error) {
|
||||
bytes, err := _1599053776_add_chat_id_and_typeDownSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1599053776_add_chat_id_and_type.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1599053859, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __1599053776_add_chat_id_and_typeUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x28\x28\x2d\xce\x88\xcf\xcb\x2f\xc9\x4c\xcb\x4c\x4e\x2c\xc9\xcc\xcf\x8b\x4f\xce\xc9\x4c\xcd\x2b\x89\x2f\x06\x11\xc8\x12\xc5\x0a\x8e\x2e\x2e\x0a\xce\xfe\x3e\xa1\xbe\x7e\x0a\xc9\x19\x89\x25\xf1\x99\x29\x0a\x21\xae\x11\x21\xd6\x5c\x54\x30\x10\x45\x47\x49\x65\x41\xaa\x82\xa7\x5f\x88\x35\x17\x57\x68\x80\x8b\x63\x08\x69\xa6\x06\xbb\x86\xc0\xdd\x67\xab\xa0\xa4\xa4\x83\xc5\x70\x5b\x05\x43\x6b\x2e\x40\x00\x00\x00\xff\xff\x22\xaf\x2b\x87\x08\x01\x00\x00")
|
||||
|
||||
func _1599053776_add_chat_id_and_typeUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1599053776_add_chat_id_and_typeUpSql,
|
||||
"1599053776_add_chat_id_and_type.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1599053776_add_chat_id_and_typeUpSql() (*asset, error) {
|
||||
bytes, err := _1599053776_add_chat_id_and_typeUpSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1599053776_add_chat_id_and_type.up.sql", size: 264, mode: os.FileMode(0644), modTime: time.Unix(1599053853, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xea, 0x7a, 0xf9, 0xc4, 0xa2, 0x96, 0x2e, 0xf9, 0x8f, 0x7, 0xf1, 0x1e, 0x73, 0x8a, 0xa6, 0x3a, 0x13, 0x4, 0x73, 0x82, 0x83, 0xb, 0xe3, 0xb5, 0x3b, 0x7e, 0xd, 0x23, 0xce, 0x98, 0xd4, 0xdc}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x8f\x3d\x6e\xec\x30\x0c\x84\x7b\x9d\x62\xb0\xcd\x36\xcf\x52\xf3\xaa\x74\x29\xd3\xe7\x02\x5c\x89\x96\x88\xb5\x24\x43\xa4\xf7\xe7\xf6\x81\x37\x01\xe2\x2e\xed\x87\xf9\x86\xc3\x10\xf0\x59\x44\x31\xcb\xc2\x10\x45\xe3\xc8\xaa\x34\x9e\xb8\x70\xa4\x4d\x19\xa7\x2c\x56\xb6\x8b\x8f\xbd\x06\x35\xb2\x4d\x27\xa9\xa1\x4a\x1e\x64\x1c\x6e\xff\x4f\x2e\x04\x44\x6a\x67\x43\xa1\x96\x16\x7e\x75\x29\xd4\x68\x98\xb4\x8c\xbb\x58\x01\x61\x1d\x3c\xcb\xc3\xe3\xdd\xb0\x30\xa9\xc1\x0a\xd9\x59\x61\x85\x11\x49\x79\xaf\x99\xfb\x40\xee\xd3\x45\x5a\x22\x23\xbf\xa3\x8f\xf9\x40\xf6\x85\x91\x96\x85\x13\xe6\xd1\xeb\xcb\x55\xaa\x8c\x24\x83\xa3\xf5\xf1\xfc\x07\x52\x65\x43\xa3\xca\xba\xfb\x85\x6e\x8c\xd6\x7f\xce\x83\x5a\xfa\xfb\x23\xdc\xfb\xb8\x2a\x48\xc1\x8f\x95\xa3\x71\xf2\xce\xad\x14\xaf\x94\x19\xdf\x39\xe9\x4d\x9d\x0b\x21\xf7\xb7\xcc\x8d\x77\xf3\xb8\x73\x5a\xaf\xf9\x90\xc4\xd4\xe1\x7d\xf8\x05\x3e\x77\xf8\xe0\xbe\x02\x00\x00\xff\xff\x4d\x1d\x5d\x50\x7e\x01\x00\x00")
|
||||
|
||||
func docGoBytes() ([]byte, error) {
|
||||
|
@ -272,6 +314,10 @@ var _bindata = map[string]func() (*asset, error){
|
|||
|
||||
"1597909626_add_server_type.up.sql": _1597909626_add_server_typeUpSql,
|
||||
|
||||
"1599053776_add_chat_id_and_type.down.sql": _1599053776_add_chat_id_and_typeDownSql,
|
||||
|
||||
"1599053776_add_chat_id_and_type.up.sql": _1599053776_add_chat_id_and_typeUpSql,
|
||||
|
||||
"doc.go": docGo,
|
||||
}
|
||||
|
||||
|
@ -316,11 +362,13 @@ type bintree struct {
|
|||
}
|
||||
|
||||
var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"1593601729_initial_schema.down.sql": &bintree{_1593601729_initial_schemaDownSql, map[string]*bintree{}},
|
||||
"1593601729_initial_schema.up.sql": &bintree{_1593601729_initial_schemaUpSql, map[string]*bintree{}},
|
||||
"1597909626_add_server_type.down.sql": &bintree{_1597909626_add_server_typeDownSql, map[string]*bintree{}},
|
||||
"1597909626_add_server_type.up.sql": &bintree{_1597909626_add_server_typeUpSql, map[string]*bintree{}},
|
||||
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||
"1593601729_initial_schema.down.sql": &bintree{_1593601729_initial_schemaDownSql, map[string]*bintree{}},
|
||||
"1593601729_initial_schema.up.sql": &bintree{_1593601729_initial_schemaUpSql, map[string]*bintree{}},
|
||||
"1597909626_add_server_type.down.sql": &bintree{_1597909626_add_server_typeDownSql, map[string]*bintree{}},
|
||||
"1597909626_add_server_type.up.sql": &bintree{_1597909626_add_server_typeUpSql, map[string]*bintree{}},
|
||||
"1599053776_add_chat_id_and_type.down.sql": &bintree{_1599053776_add_chat_id_and_typeDownSql, map[string]*bintree{}},
|
||||
"1599053776_add_chat_id_and_type.up.sql": &bintree{_1599053776_add_chat_id_and_typeUpSql, map[string]*bintree{}},
|
||||
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||
}}
|
||||
|
||||
// RestoreAsset restores an asset under the given directory.
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
ALTER TABLE push_notification_client_sent_notifications ADD COLUMN chat_id TEXT;
|
||||
ALTER TABLE push_notification_client_sent_notifications ADD COLUMN notification_type INT;
|
||||
|
||||
UPDATE push_notification_client_sent_notifications SET chat_id = "", notification_type = 1;
|
|
@ -277,7 +277,7 @@ func (p *Persistence) ShouldSendNotificationToAllInstallationIDs(publicKey *ecds
|
|||
}
|
||||
|
||||
func (p *Persistence) UpsertSentNotification(n *SentNotification) error {
|
||||
_, err := p.db.Exec(`INSERT INTO push_notification_client_sent_notifications (public_key, installation_id, message_id, last_tried_at, retry_count, success, error, hashed_public_key) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, crypto.CompressPubkey(n.PublicKey), n.InstallationID, n.MessageID, n.LastTriedAt, n.RetryCount, n.Success, n.Error, n.HashedPublicKey())
|
||||
_, err := p.db.Exec(`INSERT INTO push_notification_client_sent_notifications (public_key, installation_id, message_id, last_tried_at, retry_count, success, error, hashed_public_key,chat_id, notification_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, crypto.CompressPubkey(n.PublicKey), n.InstallationID, n.MessageID, n.LastTriedAt, n.RetryCount, n.Success, n.Error, n.HashedPublicKey(), n.ChatID, n.NotificationType)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -287,7 +287,7 @@ func (p *Persistence) GetSentNotification(hashedPublicKey []byte, installationID
|
|||
InstallationID: installationID,
|
||||
MessageID: messageID,
|
||||
}
|
||||
err := p.db.QueryRow(`SELECT retry_count, last_tried_at, error, success, public_key FROM push_notification_client_sent_notifications WHERE hashed_public_key = ?`, hashedPublicKey).Scan(&sentNotification.RetryCount, &sentNotification.LastTriedAt, &sentNotification.Error, &sentNotification.Success, &publicKeyBytes)
|
||||
err := p.db.QueryRow(`SELECT retry_count, last_tried_at, error, success, public_key,chat_id,notification_type FROM push_notification_client_sent_notifications WHERE hashed_public_key = ?`, hashedPublicKey).Scan(&sentNotification.RetryCount, &sentNotification.LastTriedAt, &sentNotification.Error, &sentNotification.Success, &publicKeyBytes, &sentNotification.ChatID, &sentNotification.NotificationType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -309,7 +309,7 @@ func (p *Persistence) UpdateNotificationResponse(messageID []byte, response *pro
|
|||
|
||||
func (p *Persistence) GetRetriablePushNotifications() ([]*SentNotification, error) {
|
||||
var notifications []*SentNotification
|
||||
rows, err := p.db.Query(`SELECT retry_count, last_tried_at, error, success, public_key, installation_id, message_id FROM push_notification_client_sent_notifications WHERE NOT success AND error = ?`, protobuf.PushNotificationReport_WRONG_TOKEN)
|
||||
rows, err := p.db.Query(`SELECT retry_count, last_tried_at, error, success, public_key, installation_id, message_id,chat_id, notification_type FROM push_notification_client_sent_notifications WHERE NOT success AND error = ?`, protobuf.PushNotificationReport_WRONG_TOKEN)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -318,7 +318,7 @@ func (p *Persistence) GetRetriablePushNotifications() ([]*SentNotification, erro
|
|||
for rows.Next() {
|
||||
var publicKeyBytes []byte
|
||||
notification := &SentNotification{}
|
||||
err = rows.Scan(¬ification.RetryCount, ¬ification.LastTriedAt, ¬ification.Error, ¬ification.Success, &publicKeyBytes, ¬ification.InstallationID, ¬ification.MessageID)
|
||||
err = rows.Scan(¬ification.RetryCount, ¬ification.LastTriedAt, ¬ification.Error, ¬ification.Success, &publicKeyBytes, ¬ification.InstallationID, ¬ification.MessageID, ¬ification.ChatID, ¬ification.NotificationType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -12,7 +12,8 @@ import (
|
|||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
)
|
||||
|
||||
const defaultNotificationMessage = "You have a new message"
|
||||
const defaultNewMessageNotificationText = "You have a new message"
|
||||
const defaultMentionNotificationText = "Someone mentioned you"
|
||||
|
||||
type GoRushRequestData struct {
|
||||
EncryptedMessage string `json:"encryptedMessage"`
|
||||
|
@ -52,11 +53,17 @@ func PushNotificationRegistrationToGoRushRequest(requestAndRegistrations []*Requ
|
|||
for _, requestAndRegistration := range requestAndRegistrations {
|
||||
request := requestAndRegistration.Request
|
||||
registration := requestAndRegistration.Registration
|
||||
var text string
|
||||
if request.Type == protobuf.PushNotification_MESSAGE {
|
||||
text = defaultNewMessageNotificationText
|
||||
} else {
|
||||
text = defaultMentionNotificationText
|
||||
}
|
||||
goRushRequests.Notifications = append(goRushRequests.Notifications,
|
||||
&GoRushRequestNotification{
|
||||
Tokens: []string{registration.DeviceToken},
|
||||
Platform: tokenTypeToGoRushPlatform(registration.TokenType),
|
||||
Message: defaultNotificationMessage,
|
||||
Message: text,
|
||||
Topic: registration.ApnTopic,
|
||||
Data: &GoRushRequestData{
|
||||
EncryptedMessage: types.EncodeHex(request.Message),
|
||||
|
|
|
@ -33,6 +33,7 @@ func TestPushNotificationRegistrationToGoRushRequest(t *testing.T) {
|
|||
{
|
||||
Request: &protobuf.PushNotification{
|
||||
ChatId: chatID,
|
||||
Type: protobuf.PushNotification_MESSAGE,
|
||||
PublicKey: publicKey1,
|
||||
InstallationId: installationID1,
|
||||
Message: message1,
|
||||
|
@ -45,6 +46,7 @@ func TestPushNotificationRegistrationToGoRushRequest(t *testing.T) {
|
|||
{
|
||||
Request: &protobuf.PushNotification{
|
||||
ChatId: chatID,
|
||||
Type: protobuf.PushNotification_MESSAGE,
|
||||
PublicKey: publicKey1,
|
||||
InstallationId: installationID2,
|
||||
Message: message2,
|
||||
|
@ -57,6 +59,7 @@ func TestPushNotificationRegistrationToGoRushRequest(t *testing.T) {
|
|||
{
|
||||
Request: &protobuf.PushNotification{
|
||||
ChatId: chatID,
|
||||
Type: protobuf.PushNotification_MENTION,
|
||||
PublicKey: publicKey2,
|
||||
InstallationId: installationID3,
|
||||
Message: message3,
|
||||
|
@ -73,7 +76,7 @@ func TestPushNotificationRegistrationToGoRushRequest(t *testing.T) {
|
|||
{
|
||||
Tokens: []string{token1},
|
||||
Platform: platform1,
|
||||
Message: defaultNotificationMessage,
|
||||
Message: defaultNewMessageNotificationText,
|
||||
Data: &GoRushRequestData{
|
||||
EncryptedMessage: hexMessage1,
|
||||
ChatID: types.EncodeHex(chatID),
|
||||
|
@ -83,7 +86,7 @@ func TestPushNotificationRegistrationToGoRushRequest(t *testing.T) {
|
|||
{
|
||||
Tokens: []string{token2},
|
||||
Platform: platform2,
|
||||
Message: defaultNotificationMessage,
|
||||
Message: defaultNewMessageNotificationText,
|
||||
Data: &GoRushRequestData{
|
||||
EncryptedMessage: hexMessage2,
|
||||
ChatID: types.EncodeHex(chatID),
|
||||
|
@ -93,7 +96,7 @@ func TestPushNotificationRegistrationToGoRushRequest(t *testing.T) {
|
|||
{
|
||||
Tokens: []string{token3},
|
||||
Platform: platform3,
|
||||
Message: defaultNotificationMessage,
|
||||
Message: defaultMentionNotificationText,
|
||||
Data: &GoRushRequestData{
|
||||
EncryptedMessage: hexMessage3,
|
||||
ChatID: types.EncodeHex(chatID),
|
||||
|
|
|
@ -21,6 +21,8 @@ import (
|
|||
const encryptedPayloadKeyLength = 16
|
||||
const defaultGorushURL = "https://gorush.status.im"
|
||||
|
||||
var errUnhandledPushNotificationType = errors.New("unhandled push notification type")
|
||||
|
||||
type Config struct {
|
||||
Enabled bool
|
||||
// Identity is our identity key
|
||||
|
@ -56,7 +58,7 @@ func (s *Server) Start() error {
|
|||
|
||||
s.config.Logger.Info("starting push notification server")
|
||||
if s.config.Identity == nil {
|
||||
s.config.Logger.Info("Identity nil")
|
||||
s.config.Logger.Debug("Identity nil")
|
||||
// Pull identity from database
|
||||
identity, err := s.persistence.GetIdentity()
|
||||
if err != nil {
|
||||
|
@ -139,7 +141,7 @@ func (s *Server) HandlePushNotificationQuery(publicKey *ecdsa.PublicKey, message
|
|||
func (s *Server) HandlePushNotificationRequest(publicKey *ecdsa.PublicKey,
|
||||
messageID []byte,
|
||||
request protobuf.PushNotificationRequest) error {
|
||||
s.config.Logger.Info("handling pn request", zap.Binary("message-id", messageID))
|
||||
s.config.Logger.Debug("handling pn request", zap.Binary("message-id", messageID))
|
||||
|
||||
// This is at-most-once semantic for now
|
||||
exists, err := s.persistence.PushNotificationExists(messageID)
|
||||
|
@ -148,14 +150,20 @@ func (s *Server) HandlePushNotificationRequest(publicKey *ecdsa.PublicKey,
|
|||
}
|
||||
|
||||
if exists {
|
||||
s.config.Logger.Info("already handled")
|
||||
s.config.Logger.Debug("already handled")
|
||||
return nil
|
||||
}
|
||||
|
||||
response := s.buildPushNotificationRequestResponseAndSendNotification(&request)
|
||||
response, requestsAndRegistrations := s.buildPushNotificationRequestResponse(&request)
|
||||
//AndSendNotification(&request)
|
||||
if response == nil {
|
||||
return nil
|
||||
}
|
||||
err = s.sendPushNotification(requestsAndRegistrations)
|
||||
if err != nil {
|
||||
s.config.Logger.Error("failed to send go rush notification", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
encodedMessage, err := proto.Marshal(response)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -298,7 +306,7 @@ func (s *Server) validateRegistration(publicKey *ecdsa.PublicKey, payload []byte
|
|||
// buildPushNotificationQueryResponse check if we have the client information and send them back
|
||||
func (s *Server) buildPushNotificationQueryResponse(query *protobuf.PushNotificationQuery) *protobuf.PushNotificationQueryResponse {
|
||||
|
||||
s.config.Logger.Info("handling push notification query")
|
||||
s.config.Logger.Debug("handling push notification query")
|
||||
response := &protobuf.PushNotificationQueryResponse{}
|
||||
if query == nil || len(query.PublicKeys) == 0 {
|
||||
return response
|
||||
|
@ -334,23 +342,65 @@ func (s *Server) buildPushNotificationQueryResponse(query *protobuf.PushNotifica
|
|||
return response
|
||||
}
|
||||
|
||||
func (s *Server) blockedChatID(blockedChatIDs [][]byte, chatID []byte) bool {
|
||||
for _, blockedChatID := range blockedChatIDs {
|
||||
if bytes.Equal(blockedChatID, chatID) {
|
||||
func (s *Server) contains(list [][]byte, chatID []byte) bool {
|
||||
for _, list := range list {
|
||||
if bytes.Equal(list, chatID) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// buildPushNotificationRequestResponseAndSendNotification will build a response
|
||||
// and fire-and-forget send a query to the gorush instance
|
||||
func (s *Server) buildPushNotificationRequestResponseAndSendNotification(request *protobuf.PushNotificationRequest) *protobuf.PushNotificationResponse {
|
||||
type reportResult struct {
|
||||
sendNotification bool
|
||||
report *protobuf.PushNotificationReport
|
||||
}
|
||||
|
||||
// buildPushNotificationReport checks the request against the registration and
|
||||
// returns whether we should send the notification and what the response should be
|
||||
func (s *Server) buildPushNotificationReport(pn *protobuf.PushNotification, registration *protobuf.PushNotificationRegistration) (*reportResult, error) {
|
||||
response := &reportResult{}
|
||||
report := &protobuf.PushNotificationReport{
|
||||
PublicKey: pn.PublicKey,
|
||||
InstallationId: pn.InstallationId,
|
||||
}
|
||||
|
||||
if pn.Type == protobuf.PushNotification_UNKNOWN_PUSH_NOTIFICATION_TYPE {
|
||||
s.config.Logger.Warn("unhandled type")
|
||||
return nil, errUnhandledPushNotificationType
|
||||
}
|
||||
|
||||
if registration == nil {
|
||||
s.config.Logger.Warn("empty registration")
|
||||
report.Error = protobuf.PushNotificationReport_NOT_REGISTERED
|
||||
} else if registration.AccessToken != pn.AccessToken {
|
||||
s.config.Logger.Debug("invalid token")
|
||||
report.Error = protobuf.PushNotificationReport_WRONG_TOKEN
|
||||
} else if (s.isMessageNotification(pn) && !s.isValidMessageNotification(pn, registration)) || (s.isMentionNotification(pn) && !s.isValidMentionNotification(pn, registration)) {
|
||||
s.config.Logger.Debug("filtered notification")
|
||||
// We report as successful but don't send the notification
|
||||
// for privacy reasons, as otherwise we would disclose that
|
||||
// the sending client has been blocked or that the registering
|
||||
// client has not joined a given public chat
|
||||
report.Success = true
|
||||
} else {
|
||||
response.sendNotification = true
|
||||
s.config.Logger.Debug("sending push notification")
|
||||
report.Success = true
|
||||
}
|
||||
|
||||
response.report = report
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// buildPushNotificationRequestResponse will build a response
|
||||
func (s *Server) buildPushNotificationRequestResponse(request *protobuf.PushNotificationRequest) (*protobuf.PushNotificationResponse, []*RequestAndRegistration) {
|
||||
response := &protobuf.PushNotificationResponse{}
|
||||
// We don't even send a response in this case
|
||||
if request == nil || len(request.MessageId) == 0 {
|
||||
s.config.Logger.Warn("empty message id")
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
response.MessageId = request.MessageId
|
||||
|
@ -360,56 +410,48 @@ func (s *Server) buildPushNotificationRequestResponseAndSendNotification(request
|
|||
|
||||
for _, pn := range request.Requests {
|
||||
registration, err := s.persistence.GetPushNotificationRegistrationByPublicKeyAndInstallationID(pn.PublicKey, pn.InstallationId)
|
||||
report := &protobuf.PushNotificationReport{
|
||||
PublicKey: pn.PublicKey,
|
||||
InstallationId: pn.InstallationId,
|
||||
}
|
||||
|
||||
if pn.Type != protobuf.PushNotification_MESSAGE {
|
||||
s.config.Logger.Warn("unhandled type")
|
||||
continue
|
||||
}
|
||||
|
||||
var report *protobuf.PushNotificationReport
|
||||
if err != nil {
|
||||
s.config.Logger.Error("failed to retrieve registration", zap.Error(err))
|
||||
report.Error = protobuf.PushNotificationReport_UNKNOWN_ERROR_TYPE
|
||||
} else if registration == nil {
|
||||
s.config.Logger.Warn("empty registration")
|
||||
report.Error = protobuf.PushNotificationReport_NOT_REGISTERED
|
||||
} else if registration.AccessToken != pn.AccessToken {
|
||||
report.Error = protobuf.PushNotificationReport_WRONG_TOKEN
|
||||
} else if s.blockedChatID(registration.BlockedChatList, pn.ChatId) {
|
||||
// We report as successful but don't send the notification
|
||||
report.Success = true
|
||||
report = &protobuf.PushNotificationReport{
|
||||
PublicKey: pn.PublicKey,
|
||||
Error: protobuf.PushNotificationReport_UNKNOWN_ERROR_TYPE,
|
||||
InstallationId: pn.InstallationId,
|
||||
}
|
||||
} else {
|
||||
// For now we just assume that the notification will be successful
|
||||
requestAndRegistrations = append(requestAndRegistrations, &RequestAndRegistration{
|
||||
Request: pn,
|
||||
Registration: registration,
|
||||
})
|
||||
report.Success = true
|
||||
response, err := s.buildPushNotificationReport(pn, registration)
|
||||
if err != nil {
|
||||
s.config.Logger.Warn("unhandled type")
|
||||
continue
|
||||
}
|
||||
|
||||
if response.sendNotification {
|
||||
requestAndRegistrations = append(requestAndRegistrations, &RequestAndRegistration{
|
||||
Request: pn,
|
||||
Registration: registration,
|
||||
})
|
||||
}
|
||||
report = response.report
|
||||
|
||||
}
|
||||
|
||||
response.Reports = append(response.Reports, report)
|
||||
}
|
||||
|
||||
s.config.Logger.Info("built pn request")
|
||||
s.config.Logger.Debug("built pn request")
|
||||
if len(requestAndRegistrations) == 0 {
|
||||
s.config.Logger.Warn("no request and registration")
|
||||
return response
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// This can be done asynchronously
|
||||
return response, requestAndRegistrations
|
||||
}
|
||||
|
||||
func (s *Server) sendPushNotification(requestAndRegistrations []*RequestAndRegistration) error {
|
||||
if len(requestAndRegistrations) == 0 {
|
||||
return nil
|
||||
}
|
||||
goRushRequest := PushNotificationRegistrationToGoRushRequest(requestAndRegistrations)
|
||||
err := sendGoRushNotification(goRushRequest, s.config.GorushURL, s.config.Logger)
|
||||
if err != nil {
|
||||
s.config.Logger.Error("failed to send go rush notification", zap.Error(err))
|
||||
// TODO: handle this error?
|
||||
// GoRush will not let us know that the sending of the push notification has failed,
|
||||
// so this likely mean that the actual HTTP request has failed, or there was some unexpected error
|
||||
}
|
||||
|
||||
return response
|
||||
return sendGoRushNotification(goRushRequest, s.config.GorushURL, s.config.Logger)
|
||||
}
|
||||
|
||||
// listenToPublicKeyQueryTopic listen to a topic derived from the hashed public key
|
||||
|
@ -424,7 +466,7 @@ func (s *Server) listenToPublicKeyQueryTopic(hashedPublicKey []byte) error {
|
|||
// buildPushNotificationRegistrationResponse will check the registration is valid, save it, and listen to the topic for the queries
|
||||
func (s *Server) buildPushNotificationRegistrationResponse(publicKey *ecdsa.PublicKey, payload []byte) *protobuf.PushNotificationRegistrationResponse {
|
||||
|
||||
s.config.Logger.Info("handling push notification registration")
|
||||
s.config.Logger.Debug("handling push notification registration")
|
||||
response := &protobuf.PushNotificationRegistrationResponse{
|
||||
RequestId: common.Shake256(payload),
|
||||
}
|
||||
|
@ -442,7 +484,7 @@ func (s *Server) buildPushNotificationRegistrationResponse(publicKey *ecdsa.Publ
|
|||
}
|
||||
|
||||
if registration.Unregister {
|
||||
s.config.Logger.Info("unregistering client")
|
||||
s.config.Logger.Debug("unregistering client")
|
||||
// We save an empty registration, only keeping version and installation-id
|
||||
if err := s.persistence.UnregisterPushNotificationRegistration(common.HashPublicKey(publicKey), registration.InstallationId, registration.Version); err != nil {
|
||||
response.Error = protobuf.PushNotificationRegistrationResponse_INTERNAL_ERROR
|
||||
|
@ -464,7 +506,32 @@ func (s *Server) buildPushNotificationRegistrationResponse(publicKey *ecdsa.Publ
|
|||
}
|
||||
response.Success = true
|
||||
|
||||
s.config.Logger.Info("handled push notification registration successfully")
|
||||
s.config.Logger.Debug("handled push notification registration successfully")
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
func (s *Server) isMentionNotification(pn *protobuf.PushNotification) bool {
|
||||
return pn.Type == protobuf.PushNotification_MENTION
|
||||
}
|
||||
|
||||
// isValidMentionNotification checks:
|
||||
// this is a mention
|
||||
// mentions are enabled
|
||||
// the user joined the public chat
|
||||
// the author is not blocked
|
||||
func (s *Server) isValidMentionNotification(pn *protobuf.PushNotification, registration *protobuf.PushNotificationRegistration) bool {
|
||||
return s.isMentionNotification(pn) && !registration.BlockMentions && s.contains(registration.AllowedMentionsChatList, pn.ChatId) && !s.contains(registration.BlockedChatList, pn.Author)
|
||||
}
|
||||
|
||||
func (s *Server) isMessageNotification(pn *protobuf.PushNotification) bool {
|
||||
return pn.Type == protobuf.PushNotification_MESSAGE
|
||||
}
|
||||
|
||||
// isValidMentionNotification checks:
|
||||
// this is a message
|
||||
// the chat is not muted
|
||||
// the author is not blocked
|
||||
func (s *Server) isValidMessageNotification(pn *protobuf.PushNotification, registration *protobuf.PushNotificationRegistration) bool {
|
||||
return s.isMessageNotification(pn) && !s.contains(registration.BlockedChatList, pn.ChatId) && !s.contains(registration.BlockedChatList, pn.Author)
|
||||
}
|
||||
|
|
|
@ -582,3 +582,298 @@ func (s *ServerSuite) TestbuildPushNotificationQueryResponseWithFiltering() {
|
|||
s.Require().Equal(s.installationID, queryResponse.Info[0].InstallationId)
|
||||
s.Require().Equal(allowedKeyList, queryResponse.Info[0].AllowedKeyList)
|
||||
}
|
||||
|
||||
func (s *ServerSuite) TestPushNotificationMentions() {
|
||||
existingChatID := []byte("existing-chat-id")
|
||||
nonExistingChatID := []byte("non-existing-chat-id")
|
||||
registration := &protobuf.PushNotificationRegistration{
|
||||
DeviceToken: "abc",
|
||||
AccessToken: s.accessToken,
|
||||
Grant: s.grant,
|
||||
TokenType: protobuf.PushNotificationRegistration_APN_TOKEN,
|
||||
InstallationId: s.installationID,
|
||||
AllowedMentionsChatList: [][]byte{existingChatID},
|
||||
Version: 1,
|
||||
}
|
||||
payload, err := proto.Marshal(registration)
|
||||
s.Require().NoError(err)
|
||||
|
||||
cyphertext, err := common.Encrypt(payload, s.sharedKey, rand.Reader)
|
||||
s.Require().NoError(err)
|
||||
response := s.server.buildPushNotificationRegistrationResponse(&s.key.PublicKey, cyphertext)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().True(response.Success)
|
||||
|
||||
pushNotificationRequest := &protobuf.PushNotificationRequest{
|
||||
MessageId: []byte("message-id"),
|
||||
Requests: []*protobuf.PushNotification{
|
||||
{
|
||||
AccessToken: s.accessToken,
|
||||
PublicKey: common.HashPublicKey(&s.key.PublicKey),
|
||||
ChatId: existingChatID,
|
||||
InstallationId: s.installationID,
|
||||
Type: protobuf.PushNotification_MENTION,
|
||||
},
|
||||
{
|
||||
AccessToken: s.accessToken,
|
||||
PublicKey: common.HashPublicKey(&s.key.PublicKey),
|
||||
ChatId: nonExistingChatID,
|
||||
InstallationId: s.installationID,
|
||||
Type: protobuf.PushNotification_MENTION,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
pushNotificationResponse, requestAndRegistrations := s.server.buildPushNotificationRequestResponse(pushNotificationRequest)
|
||||
s.Require().NotNil(pushNotificationResponse)
|
||||
s.Require().NotNil(requestAndRegistrations)
|
||||
|
||||
// only one should succeed
|
||||
s.Require().Len(requestAndRegistrations, 1)
|
||||
}
|
||||
|
||||
func (s *ServerSuite) TestPushNotificationDisabledMentions() {
|
||||
existingChatID := []byte("existing-chat-id")
|
||||
registration := &protobuf.PushNotificationRegistration{
|
||||
DeviceToken: "abc",
|
||||
AccessToken: s.accessToken,
|
||||
Grant: s.grant,
|
||||
TokenType: protobuf.PushNotificationRegistration_APN_TOKEN,
|
||||
BlockMentions: true,
|
||||
InstallationId: s.installationID,
|
||||
AllowedMentionsChatList: [][]byte{existingChatID},
|
||||
Version: 1,
|
||||
}
|
||||
payload, err := proto.Marshal(registration)
|
||||
s.Require().NoError(err)
|
||||
|
||||
cyphertext, err := common.Encrypt(payload, s.sharedKey, rand.Reader)
|
||||
s.Require().NoError(err)
|
||||
response := s.server.buildPushNotificationRegistrationResponse(&s.key.PublicKey, cyphertext)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().True(response.Success)
|
||||
|
||||
pushNotificationRequest := &protobuf.PushNotificationRequest{
|
||||
MessageId: []byte("message-id"),
|
||||
Requests: []*protobuf.PushNotification{
|
||||
{
|
||||
AccessToken: s.accessToken,
|
||||
PublicKey: common.HashPublicKey(&s.key.PublicKey),
|
||||
ChatId: existingChatID,
|
||||
InstallationId: s.installationID,
|
||||
Type: protobuf.PushNotification_MENTION,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
pushNotificationResponse, requestAndRegistrations := s.server.buildPushNotificationRequestResponse(pushNotificationRequest)
|
||||
s.Require().NotNil(pushNotificationResponse)
|
||||
s.Require().Nil(requestAndRegistrations)
|
||||
}
|
||||
|
||||
func (s *ServerSuite) TestBuildPushNotificationReport() {
|
||||
accessToken := "a"
|
||||
chatID := []byte("chat-id")
|
||||
author := []byte("author")
|
||||
blockedAuthor := []byte("blocked-author")
|
||||
blockedChatID := []byte("blocked-chat-id")
|
||||
blockedChatList := [][]byte{blockedChatID, blockedAuthor}
|
||||
nonJoinedChatID := []byte("non-joined-chat-id")
|
||||
allowedMentionsChatList := [][]byte{chatID}
|
||||
validMessagePN := &protobuf.PushNotification{
|
||||
Type: protobuf.PushNotification_MESSAGE,
|
||||
ChatId: chatID,
|
||||
Author: author,
|
||||
AccessToken: accessToken,
|
||||
}
|
||||
validMentionPN := &protobuf.PushNotification{
|
||||
Type: protobuf.PushNotification_MENTION,
|
||||
ChatId: chatID,
|
||||
AccessToken: accessToken,
|
||||
}
|
||||
validRegistration := &protobuf.PushNotificationRegistration{
|
||||
AccessToken: accessToken,
|
||||
BlockedChatList: blockedChatList,
|
||||
AllowedMentionsChatList: allowedMentionsChatList,
|
||||
}
|
||||
blockedMentionsRegistration := &protobuf.PushNotificationRegistration{
|
||||
AccessToken: accessToken,
|
||||
BlockMentions: true,
|
||||
BlockedChatList: blockedChatList,
|
||||
AllowedMentionsChatList: allowedMentionsChatList,
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
pn *protobuf.PushNotification
|
||||
registration *protobuf.PushNotificationRegistration
|
||||
expectedError error
|
||||
expectedResponse *reportResult
|
||||
}{
|
||||
{
|
||||
name: "valid message",
|
||||
pn: validMessagePN,
|
||||
registration: validRegistration,
|
||||
expectedResponse: &reportResult{
|
||||
sendNotification: true,
|
||||
report: &protobuf.PushNotificationReport{
|
||||
Success: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid mention",
|
||||
pn: validMentionPN,
|
||||
registration: validRegistration,
|
||||
expectedResponse: &reportResult{
|
||||
sendNotification: true,
|
||||
report: &protobuf.PushNotificationReport{
|
||||
Success: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unknow push notification",
|
||||
pn: &protobuf.PushNotification{
|
||||
ChatId: chatID,
|
||||
AccessToken: accessToken,
|
||||
},
|
||||
registration: validRegistration,
|
||||
expectedError: errUnhandledPushNotificationType,
|
||||
},
|
||||
{
|
||||
name: "empty registration",
|
||||
pn: validMessagePN,
|
||||
registration: nil,
|
||||
expectedResponse: &reportResult{
|
||||
sendNotification: false,
|
||||
report: &protobuf.PushNotificationReport{
|
||||
Success: false,
|
||||
Error: protobuf.PushNotificationReport_NOT_REGISTERED,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid access token message",
|
||||
pn: &protobuf.PushNotification{
|
||||
Type: protobuf.PushNotification_MESSAGE,
|
||||
Author: author,
|
||||
ChatId: chatID,
|
||||
AccessToken: "invalid",
|
||||
},
|
||||
registration: validRegistration,
|
||||
expectedResponse: &reportResult{
|
||||
sendNotification: false,
|
||||
report: &protobuf.PushNotificationReport{
|
||||
Success: false,
|
||||
Error: protobuf.PushNotificationReport_WRONG_TOKEN,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid access token mention",
|
||||
pn: &protobuf.PushNotification{
|
||||
Type: protobuf.PushNotification_MENTION,
|
||||
Author: author,
|
||||
ChatId: chatID,
|
||||
AccessToken: "invalid",
|
||||
},
|
||||
registration: validRegistration,
|
||||
expectedResponse: &reportResult{
|
||||
sendNotification: false,
|
||||
report: &protobuf.PushNotificationReport{
|
||||
Success: false,
|
||||
Error: protobuf.PushNotificationReport_WRONG_TOKEN,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "blocked chat list message",
|
||||
pn: &protobuf.PushNotification{
|
||||
Type: protobuf.PushNotification_MESSAGE,
|
||||
ChatId: blockedChatID,
|
||||
Author: author,
|
||||
AccessToken: accessToken,
|
||||
},
|
||||
registration: validRegistration,
|
||||
expectedResponse: &reportResult{
|
||||
sendNotification: false,
|
||||
report: &protobuf.PushNotificationReport{
|
||||
Success: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "blocked group chat message",
|
||||
pn: &protobuf.PushNotification{
|
||||
Type: protobuf.PushNotification_MESSAGE,
|
||||
Author: blockedAuthor,
|
||||
ChatId: chatID,
|
||||
AccessToken: accessToken,
|
||||
},
|
||||
registration: validRegistration,
|
||||
expectedResponse: &reportResult{
|
||||
sendNotification: false,
|
||||
report: &protobuf.PushNotificationReport{
|
||||
Success: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "blocked chat list mention",
|
||||
pn: &protobuf.PushNotification{
|
||||
Type: protobuf.PushNotification_MENTION,
|
||||
Author: blockedAuthor,
|
||||
ChatId: chatID,
|
||||
AccessToken: accessToken,
|
||||
},
|
||||
registration: validRegistration,
|
||||
expectedResponse: &reportResult{
|
||||
sendNotification: false,
|
||||
report: &protobuf.PushNotificationReport{
|
||||
Success: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "blocked mentions",
|
||||
pn: &protobuf.PushNotification{
|
||||
Type: protobuf.PushNotification_MENTION,
|
||||
Author: author,
|
||||
ChatId: chatID,
|
||||
AccessToken: accessToken,
|
||||
},
|
||||
registration: blockedMentionsRegistration,
|
||||
expectedResponse: &reportResult{
|
||||
sendNotification: false,
|
||||
report: &protobuf.PushNotificationReport{
|
||||
Success: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "not in allowed mention chat list",
|
||||
pn: &protobuf.PushNotification{
|
||||
Type: protobuf.PushNotification_MENTION,
|
||||
Author: author,
|
||||
ChatId: nonJoinedChatID,
|
||||
AccessToken: accessToken,
|
||||
},
|
||||
registration: validRegistration,
|
||||
expectedResponse: &reportResult{
|
||||
sendNotification: false,
|
||||
report: &protobuf.PushNotificationReport{
|
||||
Success: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
response, err := s.server.buildPushNotificationReport(tc.pn, tc.registration)
|
||||
s.Require().Equal(tc.expectedError, err)
|
||||
s.Require().Equal(tc.expectedResponse, response)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
coretypes "github.com/status-im/status-go/eth-node/core/types"
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -92,7 +93,7 @@ func (t *TransactionValidator) verifyTransactionSignature(ctx context.Context, f
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *TransactionValidator) validateTokenTransfer(parameters *CommandParameters, transaction coretypes.Message) (*VerifyTransactionResponse, error) {
|
||||
func (t *TransactionValidator) validateTokenTransfer(parameters *common.CommandParameters, transaction coretypes.Message) (*VerifyTransactionResponse, error) {
|
||||
|
||||
data := transaction.Data()
|
||||
if len(data) != tokenTransferDataLength {
|
||||
|
@ -153,7 +154,7 @@ func (t *TransactionValidator) validateToAddress(specifiedTo, actualTo string) b
|
|||
return t.addresses[actualTo]
|
||||
}
|
||||
|
||||
func (t *TransactionValidator) validateEthereumTransfer(parameters *CommandParameters, transaction coretypes.Message) (*VerifyTransactionResponse, error) {
|
||||
func (t *TransactionValidator) validateEthereumTransfer(parameters *common.CommandParameters, transaction coretypes.Message) (*VerifyTransactionResponse, error) {
|
||||
toAddress := strings.ToLower(transaction.To().Hex())
|
||||
|
||||
if !t.validateToAddress(parameters.Address, toAddress) {
|
||||
|
@ -197,7 +198,7 @@ type VerifyTransactionResponse struct {
|
|||
// The address the transaction was actually sent
|
||||
Address string
|
||||
|
||||
Message *Message
|
||||
Message *common.Message
|
||||
Transaction *TransactionToValidate
|
||||
}
|
||||
|
||||
|
@ -205,7 +206,7 @@ type VerifyTransactionResponse struct {
|
|||
// If a negative response is returned, i.e `Valid` is false, it should
|
||||
// not be retried.
|
||||
// If an error is returned, validation can be retried.
|
||||
func (t *TransactionValidator) validateTransaction(ctx context.Context, message coretypes.Message, parameters *CommandParameters, from *ecdsa.PublicKey) (*VerifyTransactionResponse, error) {
|
||||
func (t *TransactionValidator) validateTransaction(ctx context.Context, message coretypes.Message, parameters *common.CommandParameters, from *ecdsa.PublicKey) (*VerifyTransactionResponse, error) {
|
||||
fromAddress := types.BytesToAddress(message.From().Bytes())
|
||||
|
||||
err := t.verifyTransactionSignature(ctx, from, fromAddress, parameters.TransactionHash, parameters.Signature)
|
||||
|
@ -268,7 +269,7 @@ func (t *TransactionValidator) ValidateTransactions(ctx context.Context) ([]*Ver
|
|||
}
|
||||
validationResult.Message = message
|
||||
} else {
|
||||
commandParameters := &CommandParameters{}
|
||||
commandParameters := &common.CommandParameters{}
|
||||
commandParameters.TransactionHash = transaction.TransactionHash
|
||||
commandParameters.Signature = transaction.Signature
|
||||
|
||||
|
@ -304,7 +305,7 @@ func (t *TransactionValidator) ValidateTransactions(ctx context.Context) ([]*Ver
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (t *TransactionValidator) ValidateTransaction(ctx context.Context, parameters *CommandParameters, from *ecdsa.PublicKey) (*VerifyTransactionResponse, error) {
|
||||
func (t *TransactionValidator) ValidateTransaction(ctx context.Context, parameters *common.CommandParameters, from *ecdsa.PublicKey) (*VerifyTransactionResponse, error) {
|
||||
t.logger.Debug("validating transaction", zap.Any("transaction", parameters), zap.Any("from", from))
|
||||
hash := parameters.TransactionHash
|
||||
c, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
coretypes "github.com/status-im/status-go/eth-node/core/types"
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
"github.com/status-im/status-go/protocol/tt"
|
||||
)
|
||||
|
||||
|
@ -105,7 +106,7 @@ func (s *TransactionValidatorSuite) TestValidateTransactions() {
|
|||
Transaction coretypes.Message
|
||||
OverrideSignatureChatKey *ecdsa.PublicKey
|
||||
OverrideTransactionHash string
|
||||
Parameters *CommandParameters
|
||||
Parameters *common.CommandParameters
|
||||
WalletKey *ecdsa.PrivateKey
|
||||
From *ecdsa.PublicKey
|
||||
}{
|
||||
|
@ -123,7 +124,7 @@ func (s *TransactionValidatorSuite) TestValidateTransactions() {
|
|||
nil,
|
||||
false,
|
||||
),
|
||||
Parameters: &CommandParameters{
|
||||
Parameters: &common.CommandParameters{
|
||||
Value: "23",
|
||||
},
|
||||
WalletKey: senderWalletKey,
|
||||
|
@ -143,7 +144,7 @@ func (s *TransactionValidatorSuite) TestValidateTransactions() {
|
|||
nil,
|
||||
false,
|
||||
),
|
||||
Parameters: &CommandParameters{
|
||||
Parameters: &common.CommandParameters{
|
||||
Value: "23",
|
||||
Address: strings.ToLower(myAddress1.Hex()),
|
||||
},
|
||||
|
@ -162,7 +163,7 @@ func (s *TransactionValidatorSuite) TestValidateTransactions() {
|
|||
nil,
|
||||
false,
|
||||
),
|
||||
Parameters: &CommandParameters{
|
||||
Parameters: &common.CommandParameters{
|
||||
Value: "23",
|
||||
Address: strings.ToLower(myAddress1.Hex()),
|
||||
},
|
||||
|
@ -182,7 +183,7 @@ func (s *TransactionValidatorSuite) TestValidateTransactions() {
|
|||
nil,
|
||||
false,
|
||||
),
|
||||
Parameters: &CommandParameters{
|
||||
Parameters: &common.CommandParameters{
|
||||
Value: "23",
|
||||
Address: strings.ToLower(myAddress1.Hex()),
|
||||
},
|
||||
|
@ -202,7 +203,7 @@ func (s *TransactionValidatorSuite) TestValidateTransactions() {
|
|||
false,
|
||||
),
|
||||
OverrideTransactionHash: "0xdd9202df5e2f3611b5b6b716aef2a3543cc0bdd7506f50926e0869b83c8383b9",
|
||||
Parameters: &CommandParameters{
|
||||
Parameters: &common.CommandParameters{
|
||||
Value: "23",
|
||||
},
|
||||
WalletKey: senderWalletKey,
|
||||
|
@ -221,7 +222,7 @@ func (s *TransactionValidatorSuite) TestValidateTransactions() {
|
|||
nil,
|
||||
false,
|
||||
),
|
||||
Parameters: &CommandParameters{
|
||||
Parameters: &common.CommandParameters{
|
||||
Value: "23",
|
||||
Address: strings.ToLower(myAddress2.Hex()),
|
||||
},
|
||||
|
@ -240,7 +241,7 @@ func (s *TransactionValidatorSuite) TestValidateTransactions() {
|
|||
nil,
|
||||
false,
|
||||
),
|
||||
Parameters: &CommandParameters{
|
||||
Parameters: &common.CommandParameters{
|
||||
Value: "23",
|
||||
},
|
||||
WalletKey: senderWalletKey,
|
||||
|
@ -259,7 +260,7 @@ func (s *TransactionValidatorSuite) TestValidateTransactions() {
|
|||
nil,
|
||||
false,
|
||||
),
|
||||
Parameters: &CommandParameters{
|
||||
Parameters: &common.CommandParameters{
|
||||
Value: "23",
|
||||
},
|
||||
WalletKey: senderWalletKey,
|
||||
|
@ -279,7 +280,7 @@ func (s *TransactionValidatorSuite) TestValidateTransactions() {
|
|||
buildData(transferFunction, myAddress1, big.NewInt(int64(23))),
|
||||
false,
|
||||
),
|
||||
Parameters: &CommandParameters{
|
||||
Parameters: &common.CommandParameters{
|
||||
Contract: contractString,
|
||||
Value: "23",
|
||||
},
|
||||
|
@ -300,7 +301,7 @@ func (s *TransactionValidatorSuite) TestValidateTransactions() {
|
|||
buildData(transferFunction, myAddress1, big.NewInt(int64(23))),
|
||||
false,
|
||||
),
|
||||
Parameters: &CommandParameters{
|
||||
Parameters: &common.CommandParameters{
|
||||
Contract: contractString,
|
||||
Address: strings.ToLower(myAddress1.Hex()),
|
||||
Value: "23",
|
||||
|
@ -322,7 +323,7 @@ func (s *TransactionValidatorSuite) TestValidateTransactions() {
|
|||
buildData(transferFunction, myAddress1, big.NewInt(int64(13))),
|
||||
false,
|
||||
),
|
||||
Parameters: &CommandParameters{
|
||||
Parameters: &common.CommandParameters{
|
||||
Contract: contractString,
|
||||
Value: "23",
|
||||
},
|
||||
|
@ -341,7 +342,7 @@ func (s *TransactionValidatorSuite) TestValidateTransactions() {
|
|||
buildData(transferFunction, myAddress1, big.NewInt(int64(23))),
|
||||
false,
|
||||
),
|
||||
Parameters: &CommandParameters{
|
||||
Parameters: &common.CommandParameters{
|
||||
Contract: contractString,
|
||||
Address: strings.ToLower(myAddress1.Hex()),
|
||||
Value: "23",
|
||||
|
@ -362,7 +363,7 @@ func (s *TransactionValidatorSuite) TestValidateTransactions() {
|
|||
buildData(transferFunction, myAddress1, big.NewInt(int64(23))),
|
||||
false,
|
||||
),
|
||||
Parameters: &CommandParameters{
|
||||
Parameters: &common.CommandParameters{
|
||||
Contract: contractString,
|
||||
Address: strings.ToLower(senderAddress.Hex()),
|
||||
Value: "23",
|
||||
|
@ -383,7 +384,7 @@ func (s *TransactionValidatorSuite) TestValidateTransactions() {
|
|||
buildData(transferFunction, myAddress2, big.NewInt(int64(23))),
|
||||
false,
|
||||
),
|
||||
Parameters: &CommandParameters{
|
||||
Parameters: &common.CommandParameters{
|
||||
Contract: contractString,
|
||||
Address: strings.ToLower(myAddress1.Hex()),
|
||||
Value: "23",
|
||||
|
@ -403,7 +404,7 @@ func (s *TransactionValidatorSuite) TestValidateTransactions() {
|
|||
buildData(notTransferFunction, myAddress1, big.NewInt(int64(23))),
|
||||
false,
|
||||
),
|
||||
Parameters: &CommandParameters{
|
||||
Parameters: &common.CommandParameters{
|
||||
Contract: contractString,
|
||||
Value: "23",
|
||||
},
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/mailserver"
|
||||
"github.com/status-im/status-go/protocol"
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
"github.com/status-im/status-go/protocol/encryption/multidevice"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
"github.com/status-im/status-go/protocol/pushnotificationclient"
|
||||
|
@ -315,8 +316,8 @@ func (api *PublicAPI) SetInstallationMetadata(installationID string, data *multi
|
|||
}
|
||||
|
||||
type ApplicationMessagesResponse struct {
|
||||
Messages []*protocol.Message `json:"messages"`
|
||||
Cursor string `json:"cursor"`
|
||||
Messages []*common.Message `json:"messages"`
|
||||
Cursor string `json:"cursor"`
|
||||
}
|
||||
|
||||
func (api *PublicAPI) ChatMessages(chatID, cursor string, limit int) (*ApplicationMessagesResponse, error) {
|
||||
|
@ -355,7 +356,7 @@ func (api *PublicAPI) UpdateMessageOutgoingStatus(id, newOutgoingStatus string)
|
|||
return api.service.messenger.UpdateMessageOutgoingStatus(id, newOutgoingStatus)
|
||||
}
|
||||
|
||||
func (api *PublicAPI) SendChatMessage(ctx context.Context, message *protocol.Message) (*protocol.MessengerResponse, error) {
|
||||
func (api *PublicAPI) SendChatMessage(ctx context.Context, message *common.Message) (*protocol.MessengerResponse, error) {
|
||||
return api.service.messenger.SendChatMessage(ctx, message)
|
||||
}
|
||||
|
||||
|
@ -505,6 +506,22 @@ func (api *PublicAPI) DisablePushNotificationsFromContactsOnly(ctx context.Conte
|
|||
return api.service.messenger.DisablePushNotificationsFromContactsOnly()
|
||||
}
|
||||
|
||||
func (api *PublicAPI) EnablePushNotificationsBlockMentions(ctx context.Context) error {
|
||||
err := api.service.accountsDB.SaveSetting("push-notifications-block-mentions?", true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return api.service.messenger.EnablePushNotificationsBlockMentions()
|
||||
}
|
||||
|
||||
func (api *PublicAPI) DisablePushNotificationsBlockMentions(ctx context.Context) error {
|
||||
err := api.service.accountsDB.SaveSetting("push-notifications-block-mentions?", false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return api.service.messenger.DisablePushNotificationsBlockMentions()
|
||||
}
|
||||
|
||||
func (api *PublicAPI) AddPushNotificationsServer(ctx context.Context, publicKeyBytes types.HexBytes) error {
|
||||
publicKey, err := crypto.UnmarshalPubkey(publicKeyBytes)
|
||||
if err != nil {
|
||||
|
|
|
@ -484,6 +484,7 @@ func buildMessengerOptions(
|
|||
|
||||
options = append(options, protocol.WithPushNotificationClientConfig(&pushnotificationclient.Config{
|
||||
DefaultServers: config.DefaultPushNotificationsServers,
|
||||
BlockMentions: settings.PushNotificationsBlockMentions,
|
||||
SendEnabled: settings.SendPushNotifications,
|
||||
AllowFromContactsOnly: settings.PushNotificationsFromContactsOnly,
|
||||
RemoteNotificationsEnabled: settings.RemotePushNotificationsEnabled,
|
||||
|
|
|
@ -4,6 +4,7 @@ package shhext
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
||||
|
@ -465,8 +466,8 @@ func (api *NimbusPublicAPI) VerifyENSNames(details []enstypes.ENSDetails) (map[s
|
|||
}
|
||||
|
||||
type ApplicationMessagesResponse struct {
|
||||
Messages []*protocol.Message `json:"messages"`
|
||||
Cursor string `json:"cursor"`
|
||||
Messages []*common.Message `json:"messages"`
|
||||
Cursor string `json:"cursor"`
|
||||
}
|
||||
|
||||
func (api *NimbusPublicAPI) ChatMessages(chatID, cursor string, limit int) (*ApplicationMessagesResponse, error) {
|
||||
|
@ -501,7 +502,7 @@ func (api *PublicAPI) StartMessenger() error {
|
|||
return api.service.StartMessenger()
|
||||
}
|
||||
|
||||
func (api *NimbusPublicAPI) SendChatMessage(ctx context.Context, message *protocol.Message) (*protocol.MessengerResponse, error) {
|
||||
func (api *NimbusPublicAPI) SendChatMessage(ctx context.Context, message *common.Message) (*protocol.MessengerResponse, error) {
|
||||
return api.service.messenger.SendChatMessage(ctx, message)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue