Merge branch 'feature/push-notification-mentions' into develop

This commit is contained in:
Andrea Maria Piana 2020-09-09 22:11:08 +02:00
commit 19a82f68ad
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
43 changed files with 1566 additions and 684 deletions

View File

@ -1 +1 @@
0.60.2
0.61.0

View File

@ -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.

View File

@ -0,0 +1 @@
ALTER settings ADD COLUMN push_notifications_block_mentions BOOLEAN DEFAULT FALSE;

View File

@ -0,0 +1 @@
ALTER TABLE settings ADD COLUMN push_notifications_block_mentions BOOLEAN DEFAULT FALSE;

View File

@ -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,

View File

@ -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},

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)
}

View File

@ -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))

View File

@ -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 {

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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{}},

View File

@ -0,0 +1 @@
ALTER TABLE user_messages ADD COLUMN mentions BLOB;

View File

@ -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
}

View File

@ -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)
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,
}

View File

@ -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 {

View File

@ -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())
}

View File

@ -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()

View File

@ -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)

View File

@ -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.

View File

@ -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;

View File

@ -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(&notification.RetryCount, &notification.LastTriedAt, &notification.Error, &notification.Success, &publicKeyBytes, &notification.InstallationID, &notification.MessageID)
err = rows.Scan(&notification.RetryCount, &notification.LastTriedAt, &notification.Error, &notification.Success, &publicKeyBytes, &notification.InstallationID, &notification.MessageID, &notification.ChatID, &notification.NotificationType)
if err != nil {
return nil, err
}

View File

@ -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),

View File

@ -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),

View File

@ -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)
}

View File

@ -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)
})
}
}

View File

@ -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)

View File

@ -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",
},

View File

@ -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 {

View File

@ -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,

View File

@ -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)
}