diff --git a/protocol/common/message_processor_test.go b/protocol/common/message_processor_test.go index c32c8f0e1..59705a6f6 100644 --- a/protocol/common/message_processor_test.go +++ b/protocol/common/message_processor_test.go @@ -129,7 +129,7 @@ func (s *MessageProcessorSuite) TestHandleDecodedMessagesWrapped() { s.Require().Equal(1, len(decodedMessages)) s.Require().Equal(&authorKey.PublicKey, decodedMessages[0].SigPubKey()) s.Require().Equal(v1protocol.MessageID(&authorKey.PublicKey, wrappedPayload), decodedMessages[0].ID) - parsedMessage := decodedMessages[0].ParsedMessage.(protobuf.ChatMessage) + parsedMessage := decodedMessages[0].ParsedMessage.Interface().(protobuf.ChatMessage) s.Require().Equal(encodedPayload, decodedMessages[0].DecryptedPayload) s.Require().True(proto.Equal(&s.testMessage, &parsedMessage)) s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].Type) @@ -167,7 +167,7 @@ func (s *MessageProcessorSuite) TestHandleDecodedMessagesDatasync() { s.Require().Equal(&authorKey.PublicKey, decodedMessages[0].SigPubKey()) s.Require().Equal(v1protocol.MessageID(&authorKey.PublicKey, wrappedPayload), decodedMessages[0].ID) s.Require().Equal(encodedPayload, decodedMessages[0].DecryptedPayload) - parsedMessage := decodedMessages[0].ParsedMessage.(protobuf.ChatMessage) + parsedMessage := decodedMessages[0].ParsedMessage.Interface().(protobuf.ChatMessage) s.Require().True(proto.Equal(&s.testMessage, &parsedMessage)) s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].Type) } @@ -235,7 +235,7 @@ func (s *MessageProcessorSuite) TestHandleDecodedMessagesDatasyncEncrypted() { s.Require().Equal(&authorKey.PublicKey, decodedMessages[0].SigPubKey()) s.Require().Equal(v1protocol.MessageID(&authorKey.PublicKey, wrappedPayload), decodedMessages[0].ID) s.Require().Equal(encodedPayload, decodedMessages[0].DecryptedPayload) - parsedMessage := decodedMessages[0].ParsedMessage.(protobuf.ChatMessage) + parsedMessage := decodedMessages[0].ParsedMessage.Interface().(protobuf.ChatMessage) s.Require().True(proto.Equal(&s.testMessage, &parsedMessage)) s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].Type) } diff --git a/protocol/emoji_reaction.go b/protocol/emoji_reaction.go index e32b79cb6..cb43a7243 100644 --- a/protocol/emoji_reaction.go +++ b/protocol/emoji_reaction.go @@ -22,11 +22,14 @@ type EmojiReaction struct { // SigPubKey is the ecdsa encoded public key of the emoji reaction author SigPubKey *ecdsa.PublicKey `json:"-"` + + // LocalChatID is the chatID of the local chat (one-to-one are not symmetric) + LocalChatID string `json:"localChatId"` } -// ID is the Keccak256() contatenation of From-ChatID-MessageID-EmojiType +// ID is the Keccak256() contatenation of From-MessageID-EmojiType func (e EmojiReaction) ID() string { - return types.EncodeHex(crypto.Keccak256([]byte(fmt.Sprintf("%s%s%s%d", e.From, e.ChatId, e.MessageId, e.Type)))) + return types.EncodeHex(crypto.Keccak256([]byte(fmt.Sprintf("%s%s%d", e.From, e.MessageId, e.Type)))) } // GetSigPubKey returns an ecdsa encoded public key diff --git a/protocol/message_handler.go b/protocol/message_handler.go index afc8506f0..86cee9b09 100644 --- a/protocol/message_handler.go +++ b/protocol/message_handler.go @@ -670,10 +670,20 @@ func (m *MessageHandler) messageExists(messageID string, existingMessagesMap map func (m *MessageHandler) HandleEmojiReaction(state *ReceivedMessageState, pbEmojiR protobuf.EmojiReaction) error { logger := m.logger.With(zap.String("site", "HandleEmojiReaction")) + if err := ValidateReceivedEmojiReaction(&pbEmojiR, state.Timesource.GetCurrentTime()); err != nil { + logger.Error("invalid emoji reaction", zap.Error(err)) + return err + } + from := state.CurrentMessageState.Contact.ID - // check that the user can actually send an emoji for this message - existingEmoji, err := m.persistence.EmojiReactionByFromMessageIDAndType(from, pbEmojiR.MessageId, pbEmojiR.Type) + emojiReaction := &EmojiReaction{ + EmojiReaction: pbEmojiR, + From: from, + SigPubKey: state.CurrentMessageState.PublicKey, + } + + existingEmoji, err := m.persistence.EmojiReactionByID(emojiReaction.ID()) if err != errRecordNotFound && err != nil { return err } @@ -683,18 +693,15 @@ func (m *MessageHandler) HandleEmojiReaction(state *ReceivedMessageState, pbEmoj return nil } - emojiReaction := &EmojiReaction{ - EmojiReaction: pbEmojiR, - From: from, - SigPubKey: state.CurrentMessageState.PublicKey, - } chat, err := m.matchChatEntity(emojiReaction, state.AllChats, state.Timesource) if err != nil { return err // matchChatEntity returns a descriptive error message } - // TODO: make sure the user can actualy send an emoji for this chat. - logger.Info("Handling emoji reaction") + // Set local chat id + emojiReaction.LocalChatID = chat.ID + + logger.Debug("Handling emoji reaction") if chat.LastClockValue < pbEmojiR.Clock { chat.LastClockValue = pbEmojiR.Clock diff --git a/protocol/message_persistence.go b/protocol/message_persistence.go index a0aa39cac..3019961d3 100644 --- a/protocol/message_persistence.go +++ b/protocol/message_persistence.go @@ -408,6 +408,7 @@ func (db sqlitePersistence) MessagesByIDs(ids []string) ([]*Message, error) { return nil, err } defer rows.Close() + var result []*Message for rows.Next() { var message Message @@ -496,14 +497,14 @@ func (db sqlitePersistence) EmojiReactionsByChatID(chatID string, currCursor str if currCursor != "" { cursorWhere = "AND substr('0000000000000000000000000000000000000000000000000000000000000000' || m.clock_value, -64, 64) || m.id <= ?" } - args := []interface{}{chatID} + args := []interface{}{chatID, chatID} if currCursor != "" { args = append(args, currCursor) } args = append(args, limit) - // Build a new column `cursor` at the query time by having a fixed-sized clock value at the beginning - // concatenated with message ID. Results are sorted using this new column. - // This new column values can also be returned as a cursor for subsequent requests. + // NOTE: We match against local_chat_id for security reasons. + // As a user could potentially send an emoji reaction for a one to + // one/group chat that has no access to. query := fmt.Sprintf(` SELECT e.clock_value, @@ -511,11 +512,14 @@ func (db sqlitePersistence) EmojiReactionsByChatID(chatID string, currCursor str e.emoji_id, e.message_id, e.chat_id, + e.local_chat_id, e.retracted FROM emoji_reactions e WHERE NOT(e.retracted) AND + e.local_chat_id = ? + AND e.message_id IN (SELECT id FROM user_messages m WHERE NOT(m.hide) AND m.local_chat_id = ? %s ORDER BY substr('0000000000000000000000000000000000000000000000000000000000000000' || m.clock_value, -64, 64) || m.id DESC LIMIT ?) @@ -539,6 +543,7 @@ func (db sqlitePersistence) EmojiReactionsByChatID(chatID string, currCursor str &emojiReaction.Type, &emojiReaction.MessageId, &emojiReaction.ChatId, + &emojiReaction.LocalChatID, &emojiReaction.Retracted) if err != nil { return nil, err @@ -768,7 +773,7 @@ func (db sqlitePersistence) BlockContact(contact *Contact) ([]*Chat, error) { } func (db sqlitePersistence) SaveEmojiReaction(emojiReaction *EmojiReaction) (err error) { - query := "INSERT INTO emoji_reactions(id,clock_value,source,emoji_id,message_id,chat_id,retracted) VALUES (?,?,?,?,?,?,?)" + query := "INSERT INTO emoji_reactions(id,clock_value,source,emoji_id,message_id,chat_id,local_chat_id,retracted) VALUES (?,?,?,?,?,?,?,?)" stmt, err := db.db.Prepare(query) if err != nil { return @@ -781,6 +786,7 @@ func (db sqlitePersistence) SaveEmojiReaction(emojiReaction *EmojiReaction) (err emojiReaction.Type, emojiReaction.MessageId, emojiReaction.ChatId, + emojiReaction.LocalChatID, emojiReaction.Retracted, ) @@ -788,26 +794,14 @@ func (db sqlitePersistence) SaveEmojiReaction(emojiReaction *EmojiReaction) (err } func (db sqlitePersistence) EmojiReactionByID(id string) (*EmojiReaction, error) { - tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{}) - if err != nil { - return nil, err - } - defer func() { - if err == nil { - err = tx.Commit() - return - } - // don't shadow original error - _ = tx.Rollback() - }() - - row := tx.QueryRow( + row := db.db.QueryRow( `SELECT clock_value, source, emoji_id, message_id, chat_id, + local_chat_id, retracted FROM emoji_reactions @@ -816,71 +810,15 @@ func (db sqlitePersistence) EmojiReactionByID(id string) (*EmojiReaction, error) `, id) emojiReaction := new(EmojiReaction) - args := []interface{}{ - &emojiReaction.Clock, + err := row.Scan(&emojiReaction.Clock, &emojiReaction.From, &emojiReaction.Type, &emojiReaction.MessageId, &emojiReaction.ChatId, + &emojiReaction.LocalChatID, &emojiReaction.Retracted, - } - err = row.Scan(args...) - - switch err { - case sql.ErrNoRows: - return nil, errRecordNotFound - case nil: - return emojiReaction, nil - default: - return nil, err - } -} - -func (db sqlitePersistence) EmojiReactionByFromMessageIDAndType(from string, messageID string, emojiType protobuf.EmojiReaction_Type) (*EmojiReaction, error) { - tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{}) - if err != nil { - return nil, err - } - defer func() { - if err == nil { - err = tx.Commit() - return - } - // don't shadow original error - _ = tx.Rollback() - }() - - row := tx.QueryRow( - `SELECT - clock_value, - source, - emoji_id, - message_id, - chat_id, - retracted - - FROM - emoji_reactions - WHERE - emoji_reactions.source = ? - AND - emoji_reactions.message_id = ? - AND - emoji_reactions.emoji_id = ? - `, - from, - messageID, - emojiType, ) - emojiReaction := new(EmojiReaction) - err = row.Scan(&emojiReaction.Clock, - &emojiReaction.From, - &emojiReaction.Type, - &emojiReaction.MessageId, - &emojiReaction.ChatId, - &emojiReaction.Retracted) - switch err { case sql.ErrNoRows: return nil, errRecordNotFound @@ -890,8 +828,3 @@ func (db sqlitePersistence) EmojiReactionByFromMessageIDAndType(from string, mes return nil, err } } - -func (db sqlitePersistence) RetractEmojiReaction(id string) error { - _, err := db.db.Exec(`UPDATE emoji_reactions SET retracted = 1 WHERE id = ?`, id) - return err -} diff --git a/protocol/message_validator.go b/protocol/message_validator.go index 8d206a03f..06ed8fa4b 100644 --- a/protocol/message_validator.go +++ b/protocol/message_validator.go @@ -225,3 +225,27 @@ func ValidateReceivedChatMessage(message *protobuf.ChatMessage, whisperTimestamp return nil } + +func ValidateReceivedEmojiReaction(emoji *protobuf.EmojiReaction, whisperTimestamp uint64) error { + if err := validateClockValue(emoji.Clock, whisperTimestamp); err != nil { + return err + } + + if len(emoji.MessageId) == 0 { + return errors.New("message-id can't be empty") + } + + if len(emoji.ChatId) == 0 { + return errors.New("chat-id can't be empty") + } + + if emoji.Type == protobuf.EmojiReaction_UNKNOWN_EMOJI_REACTION_TYPE { + return errors.New("unknown emoji reaction type") + } + + if emoji.MessageType == protobuf.MessageType_UNKNOWN_MESSAGE_TYPE { + return errors.New("unknown message type") + } + + return nil +} diff --git a/protocol/message_validator_test.go b/protocol/message_validator_test.go index 407d823b2..ad5dadba1 100644 --- a/protocol/message_validator_test.go +++ b/protocol/message_validator_test.go @@ -477,3 +477,105 @@ func (s *MessageValidatorSuite) TestValidatePlainTextMessage() { }) } } + +func (s *MessageValidatorSuite) TestValidateEmojiReaction() { + testCases := []struct { + Name string + Valid bool + WhisperTimestamp uint64 + Message protobuf.EmojiReaction + }{ + { + Name: "valid emoji reaction", + Valid: true, + WhisperTimestamp: 30, + Message: protobuf.EmojiReaction{ + Clock: 30, + ChatId: "chat-id", + MessageId: "message-id", + MessageType: protobuf.MessageType_ONE_TO_ONE, + Type: protobuf.EmojiReaction_LOVE, + }, + }, + { + Name: "valid emoji retraction", + Valid: true, + WhisperTimestamp: 30, + Message: protobuf.EmojiReaction{ + Clock: 30, + ChatId: "0.34", + MessageId: "message-id", + Type: protobuf.EmojiReaction_LOVE, + MessageType: protobuf.MessageType_ONE_TO_ONE, + Retracted: true, + }, + }, + { + Name: "missing chatID", + Valid: false, + WhisperTimestamp: 30, + Message: protobuf.EmojiReaction{ + Clock: 30, + MessageId: "message-id", + MessageType: protobuf.MessageType_ONE_TO_ONE, + Type: protobuf.EmojiReaction_LOVE, + }, + }, + { + Name: "missing messageID", + Valid: false, + WhisperTimestamp: 30, + Message: protobuf.EmojiReaction{ + Clock: 30, + ChatId: "chat-id", + MessageType: protobuf.MessageType_ONE_TO_ONE, + Type: protobuf.EmojiReaction_LOVE, + }, + }, + { + Name: "missing type", + Valid: false, + WhisperTimestamp: 30, + Message: protobuf.EmojiReaction{ + Clock: 30, + ChatId: "chat-id", + MessageId: "message-id", + MessageType: protobuf.MessageType_ONE_TO_ONE, + }, + }, + { + Name: "missing message type", + Valid: false, + WhisperTimestamp: 30, + Message: protobuf.EmojiReaction{ + Clock: 30, + ChatId: "chat-id", + MessageId: "message-id", + Type: protobuf.EmojiReaction_LOVE, + }, + }, + { + Name: "clock value too high", + Valid: false, + WhisperTimestamp: 30, + Message: protobuf.EmojiReaction{ + Clock: 900000, + ChatId: "chat-id", + MessageId: "message-id", + MessageType: protobuf.MessageType_ONE_TO_ONE, + Type: protobuf.EmojiReaction_LOVE, + }, + }, + } + for _, tc := range testCases { + s.Run(tc.Name, func() { + err := ValidateReceivedEmojiReaction(&tc.Message, tc.WhisperTimestamp) + if tc.Valid { + s.Nil(err) + } else { + s.NotNil(err) + } + }) + } + +} diff --git a/protocol/messenger.go b/protocol/messenger.go index 1d8d2b908..d97a1b6b9 100644 --- a/protocol/messenger.go +++ b/protocol/messenger.go @@ -3245,7 +3245,8 @@ func (m *Messenger) SendEmojiReaction(ctx context.Context, chatID, messageID str ChatId: chatID, Type: protobuf.EmojiReaction_Type(emojiID), }, - From: types.EncodeHex(crypto.FromECDSAPub(&m.identity.PublicKey)), + LocalChatID: chatID, + From: types.EncodeHex(crypto.FromECDSAPub(&m.identity.PublicKey)), } encodedMessage, err := m.encodeChatEntity(chat, emojiR) if err != nil { @@ -3334,7 +3335,7 @@ func (m *Messenger) SendEmojiReactionRetraction(ctx context.Context, emojiReacti response.Chats = []*Chat{chat} // Persist retraction state for emoji reaction - err = m.persistence.RetractEmojiReaction(emojiReactionID) + err = m.persistence.SaveEmojiReaction(emojiR) if err != nil { return nil, err } diff --git a/protocol/migrations/migrations.go b/protocol/migrations/migrations.go index 41aae374a..87e9cd76f 100644 --- a/protocol/migrations/migrations.go +++ b/protocol/migrations/migrations.go @@ -17,7 +17,7 @@ // 1595862781_add_audio_data.down.sql (0) // 1595862781_add_audio_data.up.sql (246B) // 1595865249_create_emoji_reactions_table.down.sql (27B) -// 1595865249_create_emoji_reactions_table.up.sql (265B) +// 1595865249_create_emoji_reactions_table.up.sql (300B) // doc.go (850B) package migrations @@ -427,7 +427,7 @@ func _1595865249_create_emoji_reactions_tableDownSql() (*asset, error) { return a, nil } -var __1595865249_create_emoji_reactions_tableUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x74\xce\xbf\x4e\xc3\x30\x10\xc7\xf1\x3d\x52\xde\xe1\x37\x82\xc4\xc0\xce\x64\xcc\x45\x58\x18\xa7\x72\xaf\xa8\x9d\x22\xcb\x3d\x81\xa1\xc5\x92\xed\xf0\xfc\x88\x64\xe1\x8f\x98\x3f\x77\xdf\x3b\xed\x49\x31\x81\xd5\xad\x25\x98\x01\x6e\x64\xd0\xde\x6c\x79\x0b\x39\xe7\xd7\x34\x15\x09\xb1\xa5\xfc\x5e\x71\xd1\x77\x40\x3a\xe2\x49\x79\x7d\xaf\x3c\x36\xde\x3c\x2a\x7f\xc0\x03\x1d\x30\x3a\xe8\xd1\x0d\xd6\x68\x86\xa7\x8d\x55\x9a\xae\xbe\xc6\xe3\x29\xc7\xb7\xe9\x23\x9c\x66\x81\x71\xbc\xe4\xdd\xce\xda\x05\x6b\x9e\x4b\x14\x30\xed\x7f\xc1\x7a\x39\x1d\xff\xae\x9c\xa5\xd6\xf0\x2c\xd3\xb7\x37\x7e\x78\x7c\x09\xed\x5f\x2c\xd2\x4a\x88\x4d\xd6\xee\x1d\x0d\x6a\x67\x19\xd7\x7d\x77\x79\xd3\x77\x9f\x01\x00\x00\xff\xff\xf2\xdf\x03\x4e\x09\x01\x00\x00") +var __1595865249_create_emoji_reactions_tableUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x7c\xce\xbd\x4e\x03\x31\x10\x04\xe0\xfe\xa4\x7b\x87\x29\x41\xa2\xa0\xa7\x32\x66\x4f\x58\x18\x5f\xe4\x6c\x50\x52\x9d\x2c\x67\x05\x07\x0e\x96\x6c\x87\xe7\x47\xe4\x1a\x7e\x44\xea\x6f\x76\x67\xb4\x27\xc5\x04\x56\xb7\x96\x60\x06\xb8\x91\x41\x5b\xb3\xe6\x35\xe4\x90\x5f\xe7\xa9\x48\x88\x6d\xce\xef\x15\x17\x7d\x07\xcc\x7b\x3c\x29\xaf\xef\x95\xc7\xca\x9b\x47\xe5\x77\x78\xa0\x1d\x46\x07\x3d\xba\xc1\x1a\xcd\xf0\xb4\xb2\x4a\xd3\xd5\x57\x3c\xa6\x1c\xdf\xa6\x8f\x90\x8e\x02\xe3\xf8\xf4\xde\x6d\xac\x3d\x61\xcd\xc7\x12\x05\x4c\xdb\x5f\xb0\x34\xcf\xfb\xbf\x27\x07\xa9\x35\x3c\xcb\xf4\x6d\xc6\x0f\x8f\x2f\xa1\xfd\x8b\x29\xc7\x90\xa6\xb3\x91\x22\xad\x84\xd8\x64\xa9\xbe\xa3\x41\x6d\x2c\xe3\xba\xef\x2e\x6f\xfa\xee\x33\x00\x00\xff\xff\xe4\x28\x05\xe0\x2c\x01\x00\x00") func _1595865249_create_emoji_reactions_tableUpSqlBytes() ([]byte, error) { return bindataRead( @@ -442,8 +442,8 @@ func _1595865249_create_emoji_reactions_tableUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1595865249_create_emoji_reactions_table.up.sql", size: 265, mode: os.FileMode(0644), modTime: time.Unix(1595865239, 0)} - a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x13, 0x28, 0xa4, 0x70, 0xf0, 0xfe, 0xd, 0xc2, 0x16, 0xc3, 0x1d, 0xbb, 0x3c, 0x1, 0xf6, 0x58, 0x69, 0x2a, 0x27, 0x21, 0xbc, 0x8b, 0xc8, 0x1a, 0xd, 0x36, 0x2d, 0x29, 0x0, 0xc3, 0xfa, 0xad}} + info := bindataFileInfo{name: "1595865249_create_emoji_reactions_table.up.sql", size: 300, mode: os.FileMode(0644), modTime: time.Unix(1595921491, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3e, 0xc5, 0x43, 0x5c, 0x3d, 0x53, 0x43, 0x2c, 0x1a, 0xa5, 0xb6, 0xbf, 0x7, 0x4, 0x5a, 0x3e, 0x40, 0x8b, 0xa4, 0x57, 0x12, 0x58, 0xbc, 0x42, 0xe2, 0xc3, 0xde, 0x76, 0x98, 0x80, 0xe2, 0xbe}} return a, nil } diff --git a/protocol/migrations/sqlite/1595865249_create_emoji_reactions_table.up.sql b/protocol/migrations/sqlite/1595865249_create_emoji_reactions_table.up.sql index b28b945a0..2436bd4ff 100644 --- a/protocol/migrations/sqlite/1595865249_create_emoji_reactions_table.up.sql +++ b/protocol/migrations/sqlite/1595865249_create_emoji_reactions_table.up.sql @@ -5,5 +5,6 @@ CREATE TABLE IF NOT EXISTS emoji_reactions ( emoji_id INT NOT NULL, message_id VARCHAR NOT NULL, chat_id VARCHAR NOT NULL, + local_chat_id VARCHAR NOT NULL, retracted INT DEFAULT 0 ); diff --git a/protocol/persistence_test.go b/protocol/persistence_test.go index d3e4968a8..1f7e8b588 100644 --- a/protocol/persistence_test.go +++ b/protocol/persistence_test.go @@ -407,7 +407,8 @@ func TestPersistenceEmojiReactions(t *testing.T) { ChatId: chatID, Type: protobuf.EmojiReaction_SAD, }, - From: from1, + LocalChatID: chatID, + From: from1, })) // Insert retracted emoji reaction @@ -419,7 +420,8 @@ func TestPersistenceEmojiReactions(t *testing.T) { Type: protobuf.EmojiReaction_SAD, Retracted: true, }, - From: from2, + LocalChatID: chatID, + From: from2, })) // Insert retracted emoji reaction out of pagination @@ -430,7 +432,8 @@ func TestPersistenceEmojiReactions(t *testing.T) { ChatId: chatID, Type: protobuf.EmojiReaction_SAD, }, - From: from2, + LocalChatID: chatID, + From: from2, })) // Insert retracted emoji reaction out of pagination @@ -441,7 +444,20 @@ func TestPersistenceEmojiReactions(t *testing.T) { ChatId: chatID, Type: protobuf.EmojiReaction_SAD, }, - From: from3, + LocalChatID: chatID, + From: from3, + })) + + // Wrong local chat id + require.NoError(t, p.SaveEmojiReaction(&EmojiReaction{ + EmojiReaction: protobuf.EmojiReaction{ + Clock: 1, + MessageId: id1, + ChatId: chatID, + Type: protobuf.EmojiReaction_LOVE, + }, + LocalChatID: "wrong-chat-id", + From: from3, })) reactions, err := p.EmojiReactionsByChatID(chatID, "", 1) diff --git a/protocol/v1/membership_update_message_test.go b/protocol/v1/membership_update_message_test.go index 7176b4e59..e952f5ac1 100644 --- a/protocol/v1/membership_update_message_test.go +++ b/protocol/v1/membership_update_message_test.go @@ -54,7 +54,8 @@ func TestSignMembershipUpdate(t *testing.T) { require.NoError(t, err) // Encode message - encodedMessage := testMembershipUpdateMessageStruct.ToProtobuf() + encodedMessage, err := testMembershipUpdateMessageStruct.ToProtobuf() + require.NoError(t, err) // Verify it verifiedMessage, err := MembershipUpdateMessageFromProtobuf(encodedMessage) require.NoError(t, err)