Added ChatEntity interface and made required changes for its use
This commit is contained in:
parent
ceed618102
commit
6ffe67deec
|
@ -0,0 +1,13 @@
|
|||
package protocol
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
)
|
||||
|
||||
type ChatEntity interface {
|
||||
GetChatId() string
|
||||
GetMessageType() protobuf.MessageType
|
||||
GetSigPubKey() *ecdsa.PublicKey
|
||||
}
|
|
@ -1,29 +1,31 @@
|
|||
package protocol
|
||||
|
||||
import "github.com/status-im/status-go/protocol/protobuf"
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
)
|
||||
|
||||
// EmojiReaction represents an emoji reaction from a user in the application layer, used for persistence, querying and
|
||||
// signaling
|
||||
type EmojiReaction struct {
|
||||
protobuf.EmojiReaction
|
||||
|
||||
// ID calculated as keccak256(compressedAuthorPubKey, data) where data is unencrypted payload.
|
||||
ID string
|
||||
|
||||
// Clock Lamport timestamp of the chat message
|
||||
Clock uint64
|
||||
|
||||
// MessageID the ID of the target message that the user wishes to react to
|
||||
MessageID string
|
||||
|
||||
// ChatID the ID of the chat the message belongs to, for query efficiency the ChatID is stored in the db even though the
|
||||
// target message also stores the ChatID
|
||||
ChatID string
|
||||
|
||||
// EmojiID the ID of the emoji the user wishes to react with
|
||||
EmojiID protobuf.EmojiReaction_Type
|
||||
|
||||
// From is a public key of the author of the emoji reaction.
|
||||
From string
|
||||
|
||||
// Retracted represents whether the user has chosen to remove a previously given reaction
|
||||
Retracted bool
|
||||
|
||||
// SigPubKey is the ecdsa encoded public key of the emoji reaction author
|
||||
SigPubKey *ecdsa.PublicKey `json:"-"`
|
||||
}
|
||||
|
||||
// GetSigPubKey returns an ecdsa encoded public key
|
||||
// this function is also required to implement the ChatEntity interface
|
||||
func (e EmojiReaction) GetSigPubKey() *ecdsa.PublicKey {
|
||||
return e.SigPubKey
|
||||
}
|
||||
|
|
|
@ -332,3 +332,9 @@ func getAudioMessageMIME(i *protobuf.AudioMessage) (string, error) {
|
|||
|
||||
return "", errors.New("audio format not supported")
|
||||
}
|
||||
|
||||
// GetSigPubKey returns an ecdsa encoded public key
|
||||
// this function is also required to implement the ChatEntity interface
|
||||
func (m Message) GetSigPubKey() *ecdsa.PublicKey {
|
||||
return m.SigPubKey
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ func (m *MessageHandler) handleCommandMessage(state *ReceivedMessageState, messa
|
|||
if err := message.PrepareContent(); err != nil {
|
||||
return fmt.Errorf("failed to prepare content: %v", err)
|
||||
}
|
||||
chat, err := m.matchMessage(message, state.AllChats, state.Timesource)
|
||||
chat, err := m.matchChatEntity(message, state.AllChats, state.Timesource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -312,9 +312,9 @@ func (m *MessageHandler) HandleChatMessage(state *ReceivedMessageState) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("failed to prepare message content: %v", err)
|
||||
}
|
||||
chat, err := m.matchMessage(receivedMessage, state.AllChats, state.Timesource)
|
||||
chat, err := m.matchChatEntity(receivedMessage, state.AllChats, state.Timesource)
|
||||
if err != nil {
|
||||
return err // matchMessage returns a descriptive error message
|
||||
return err // matchChatEntity returns a descriptive error message
|
||||
}
|
||||
|
||||
// If deleted-at is greater, ignore message
|
||||
|
@ -359,9 +359,7 @@ func (m *MessageHandler) HandleChatMessage(state *ReceivedMessageState) error {
|
|||
}
|
||||
|
||||
// Add to response
|
||||
if receivedMessage != nil {
|
||||
state.Response.Messages = append(state.Response.Messages, receivedMessage)
|
||||
}
|
||||
state.Response.Messages = append(state.Response.Messages, receivedMessage)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -567,26 +565,26 @@ func (m *MessageHandler) HandleDeclineRequestTransaction(messageState *ReceivedM
|
|||
return m.handleCommandMessage(messageState, oldMessage)
|
||||
}
|
||||
|
||||
func (m *MessageHandler) matchMessage(message *Message, chats map[string]*Chat, timesource TimeSource) (*Chat, error) {
|
||||
if message.SigPubKey == nil {
|
||||
func (m *MessageHandler) matchChatEntity(chatEntity ChatEntity, chats map[string]*Chat, timesource TimeSource) (*Chat, error) {
|
||||
if chatEntity.GetSigPubKey() == nil {
|
||||
m.logger.Error("public key can't be empty")
|
||||
return nil, errors.New("received a message with empty public key")
|
||||
return nil, errors.New("received a chatEntity with empty public key")
|
||||
}
|
||||
|
||||
switch {
|
||||
case message.MessageType == protobuf.MessageType_PUBLIC_GROUP:
|
||||
case chatEntity.GetMessageType() == protobuf.MessageType_PUBLIC_GROUP:
|
||||
// For public messages, all outgoing and incoming messages have the same chatID
|
||||
// equal to a public chat name.
|
||||
chatID := message.ChatId
|
||||
chatID := chatEntity.GetChatId()
|
||||
chat := chats[chatID]
|
||||
if chat == nil {
|
||||
return nil, errors.New("received a public message from non-existing chat")
|
||||
return nil, errors.New("received a public chatEntity from non-existing chat")
|
||||
}
|
||||
return chat, nil
|
||||
case message.MessageType == protobuf.MessageType_ONE_TO_ONE && common.IsPubKeyEqual(message.SigPubKey, &m.identity.PublicKey):
|
||||
case chatEntity.GetMessageType() == protobuf.MessageType_ONE_TO_ONE && common.IsPubKeyEqual(message.SigPubKey, &m.identity.PublicKey):
|
||||
// It's a private message coming from us so we rely on Message.ChatID
|
||||
// If chat does not exist, it should be created to support multidevice synchronization.
|
||||
chatID := message.ChatId
|
||||
chatID := chatEntity.GetChatId()
|
||||
chat := chats[chatID]
|
||||
if chat == nil {
|
||||
if len(chatID) != PubKeyStringLength {
|
||||
|
@ -606,27 +604,27 @@ func (m *MessageHandler) matchMessage(message *Message, chats map[string]*Chat,
|
|||
chat = &newChat
|
||||
}
|
||||
return chat, nil
|
||||
case message.MessageType == protobuf.MessageType_ONE_TO_ONE:
|
||||
// It's an incoming private message. ChatID is calculated from the signature.
|
||||
case chatEntity.GetMessageType() == protobuf.MessageType_ONE_TO_ONE:
|
||||
// It's an incoming private chatEntity. ChatID is calculated from the signature.
|
||||
// If a chat does not exist, a new one is created and saved.
|
||||
chatID := contactIDFromPublicKey(message.SigPubKey)
|
||||
chatID := contactIDFromPublicKey(chatEntity.GetSigPubKey())
|
||||
chat := chats[chatID]
|
||||
if chat == nil {
|
||||
// TODO: this should be a three-word name used in the mobile client
|
||||
newChat := CreateOneToOneChat(chatID[:8], message.SigPubKey, timesource)
|
||||
newChat := CreateOneToOneChat(chatID[:8], chatEntity.GetSigPubKey(), timesource)
|
||||
chat = &newChat
|
||||
}
|
||||
return chat, nil
|
||||
case message.MessageType == protobuf.MessageType_PRIVATE_GROUP:
|
||||
// In the case of a group message, ChatID is the same for all messages belonging to a group.
|
||||
case chatEntity.GetMessageType() == protobuf.MessageType_PRIVATE_GROUP:
|
||||
// In the case of a group chatEntity, ChatID is the same for all messages belonging to a group.
|
||||
// It needs to be verified if the signature public key belongs to the chat.
|
||||
chatID := message.ChatId
|
||||
chatID := chatEntity.GetChatId()
|
||||
chat := chats[chatID]
|
||||
if chat == nil {
|
||||
return nil, errors.New("received group chat message for non-existing chat")
|
||||
return nil, errors.New("received group chat chatEntity for non-existing chat")
|
||||
}
|
||||
|
||||
theirKeyHex := contactIDFromPublicKey(message.SigPubKey)
|
||||
theirKeyHex := contactIDFromPublicKey(chatEntity.GetSigPubKey())
|
||||
myKeyHex := contactIDFromPublicKey(&m.identity.PublicKey)
|
||||
var theyJoined bool
|
||||
var iJoined bool
|
||||
|
@ -670,21 +668,23 @@ func (m *MessageHandler) messageExists(messageID string, existingMessagesMap map
|
|||
return false, nil
|
||||
}
|
||||
|
||||
func (m *MessageHandler) HandleEmojiReaction(state *ReceivedMessageState, message protobuf.EmojiReaction) error {
|
||||
func (m *MessageHandler) HandleEmojiReaction(state *ReceivedMessageState, pbEmojiR protobuf.EmojiReaction) error {
|
||||
logger := m.logger.With(zap.String("site", "HandleEmojiReaction"))
|
||||
// TODO change this to chat id directly from the protobuf once it is updated
|
||||
contact := state.CurrentMessageState.Contact
|
||||
chat, ok := state.AllChats[contact.ID]
|
||||
if !ok {
|
||||
chat = OneToOneFromPublicKey(state.CurrentMessageState.PublicKey, state.Timesource)
|
||||
// We don't want to show the chat to the user
|
||||
chat.Active = false
|
||||
emojiReaction := &EmojiReaction{
|
||||
EmojiReaction: pbEmojiR,
|
||||
ID: state.CurrentMessageState.MessageID,
|
||||
From: state.CurrentMessageState.Contact.ID,
|
||||
SigPubKey: state.CurrentMessageState.PublicKey,
|
||||
}
|
||||
chat, err := m.matchChatEntity(emojiReaction, state.AllChats, state.Timesource)
|
||||
if err != nil {
|
||||
return err // matchChatEntity returns a descriptive error message
|
||||
}
|
||||
|
||||
logger.Info("Handling emoji reaction")
|
||||
|
||||
if chat.LastClockValue < message.Clock {
|
||||
chat.LastClockValue = message.Clock
|
||||
if chat.LastClockValue < pbEmojiR.Clock {
|
||||
chat.LastClockValue = pbEmojiR.Clock
|
||||
}
|
||||
|
||||
state.ModifiedChats[chat.ID] = true
|
||||
|
|
|
@ -2254,7 +2254,7 @@ func (s *MessageHandlerSuite) TestRun() {
|
|||
s.Empty(message.LocalChatID)
|
||||
|
||||
message.ID = strconv.Itoa(idx) // manually set the ID because messages does not go through messageProcessor
|
||||
chat, err := s.messageHandler.matchMessage(&message, chatsMap, &testTimeSource{})
|
||||
chat, err := s.messageHandler.matchChatEntity(&message, chatsMap, &testTimeSource{})
|
||||
if tc.Error {
|
||||
s.Require().Error(err)
|
||||
} else {
|
||||
|
|
|
@ -5,10 +5,20 @@ package protobuf;
|
|||
import "enums.proto";
|
||||
|
||||
message EmojiReaction {
|
||||
// clock Lamport timestamp of the chat message
|
||||
uint64 clock = 1;
|
||||
|
||||
// chat_id the ID of the chat the message belongs to, for query efficiency the chat_id is stored in the db even though the
|
||||
// target message also stores the chat_id
|
||||
string chat_id = 2;
|
||||
|
||||
// message_id the ID of the target message that the user wishes to react to
|
||||
string message_id = 3;
|
||||
|
||||
// message_type is (somewhat confusingly) the ID of the type of chat the message belongs to
|
||||
MessageType message_type = 4;
|
||||
|
||||
// type the ID of the emoji the user wishes to react with
|
||||
Type type = 5;
|
||||
|
||||
enum Type {
|
||||
|
|
Loading…
Reference in New Issue