Avoid webpage preview updates being sent as message edits (by hash matching)

This commit is contained in:
Bohdan Horbeshko 2023-07-22 10:46:35 -04:00
parent eadef987be
commit 748366ad6a
3 changed files with 69 additions and 1 deletions

View file

@ -2,6 +2,7 @@ package telegram
import ( import (
"github.com/pkg/errors" "github.com/pkg/errors"
"hash/maphash"
"path/filepath" "path/filepath"
"strconv" "strconv"
"sync" "sync"
@ -60,6 +61,9 @@ type Client struct {
DelayedStatuses map[int64]*DelayedStatus DelayedStatuses map[int64]*DelayedStatus
DelayedStatusesLock sync.Mutex DelayedStatusesLock sync.Mutex
lastMsgHashes map[int64]uint64
msgHashSeed maphash.Seed
locks clientLocks locks clientLocks
SendMessageLock sync.Mutex SendMessageLock sync.Mutex
} }
@ -69,6 +73,7 @@ type clientLocks struct {
chatMessageLocks map[int64]*sync.Mutex chatMessageLocks map[int64]*sync.Mutex
resourcesLock sync.Mutex resourcesLock sync.Mutex
outboxLock sync.Mutex outboxLock sync.Mutex
lastMsgHashesLock sync.Mutex
} }
// NewClient instantiates a Telegram App // NewClient instantiates a Telegram App
@ -129,6 +134,8 @@ func NewClient(conf config.TelegramConfig, jid string, component *xmpp.Component
cache: cache.NewCache(), cache: cache.NewCache(),
options: options, options: options,
DelayedStatuses: make(map[int64]*DelayedStatus), DelayedStatuses: make(map[int64]*DelayedStatus),
lastMsgHashes: make(map[int64]uint64),
msgHashSeed: maphash.MakeSeed(),
locks: clientLocks{ locks: clientLocks{
chatMessageLocks: make(map[int64]*sync.Mutex), chatMessageLocks: make(map[int64]*sync.Mutex),
}, },

View file

@ -226,6 +226,8 @@ func (c *Client) updateNewMessage(update *client.UpdateNewMessage) {
}).Warn("New message from chat") }).Warn("New message from chat")
c.ProcessIncomingMessage(chatId, update.Message, ignoredResource) c.ProcessIncomingMessage(chatId, update.Message, ignoredResource)
c.updateLastMessageHash(update.Message.ChatId, update.Message.Id, update.Message.Content)
}() }()
} }
@ -233,6 +235,8 @@ func (c *Client) updateNewMessage(update *client.UpdateNewMessage) {
func (c *Client) updateMessageContent(update *client.UpdateMessageContent) { func (c *Client) updateMessageContent(update *client.UpdateMessageContent) {
markupFunction := formatter.EntityToXEP0393 markupFunction := formatter.EntityToXEP0393
defer c.updateLastMessageHash(update.ChatId, update.MessageId, update.NewContent)
c.SendMessageLock.Lock() c.SendMessageLock.Lock()
c.SendMessageLock.Unlock() c.SendMessageLock.Unlock()
xmppId, err := gateway.IdsDB.GetByTgIds(c.Session.Login, c.jid, update.ChatId, update.MessageId) xmppId, err := gateway.IdsDB.GetByTgIds(c.Session.Login, c.jid, update.ChatId, update.MessageId)
@ -250,7 +254,7 @@ func (c *Client) updateMessageContent(update *client.UpdateMessageContent) {
return return
} }
if update.NewContent.MessageContentType() == client.TypeMessageText { if update.NewContent.MessageContentType() == client.TypeMessageText && c.hasLastMessageHashChanged(update.ChatId, update.MessageId, update.NewContent) {
textContent := update.NewContent.(*client.MessageText) textContent := update.NewContent.(*client.MessageText)
var editChar string var editChar string
if c.Session.AsciiArrows { if c.Session.AsciiArrows {

View file

@ -2,8 +2,10 @@ package telegram
import ( import (
"crypto/sha1" "crypto/sha1"
"encoding/binary"
"fmt" "fmt"
"github.com/pkg/errors" "github.com/pkg/errors"
"hash/maphash"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
@ -1384,3 +1386,58 @@ func (c *Client) getCarbonFullJids(isOutgoing bool, ignoredResource string) []st
} }
return jids return jids
} }
func (c *Client) calculateMessageHash(messageId int64, content client.MessageContent) uint64 {
var h maphash.Hash
h.SetSeed(c.msgHashSeed)
buf8 := make([]byte, 8)
binary.BigEndian.PutUint64(buf8, uint64(messageId))
h.Write(buf8)
if content != nil && content.MessageContentType() == client.TypeMessageText {
textContent, ok := content.(*client.MessageText)
if !ok {
uhOh()
}
if textContent.Text != nil {
h.WriteString(textContent.Text.Text)
for _, entity := range textContent.Text.Entities {
buf4 := make([]byte, 4)
binary.BigEndian.PutUint32(buf4, uint32(entity.Offset))
h.Write(buf4)
binary.BigEndian.PutUint32(buf4, uint32(entity.Length))
h.Write(buf4)
h.WriteString(entity.Type.TextEntityTypeType())
}
}
}
return h.Sum64()
}
func (c *Client) updateLastMessageHash(chatId, messageId int64, content client.MessageContent) {
c.locks.lastMsgHashesLock.Lock()
defer c.locks.lastMsgHashesLock.Unlock()
c.lastMsgHashes[chatId] = c.calculateMessageHash(messageId, content)
}
func (c *Client) hasLastMessageHashChanged(chatId, messageId int64, content client.MessageContent) bool {
c.locks.lastMsgHashesLock.Lock()
defer c.locks.lastMsgHashesLock.Unlock()
oldHash, ok := c.lastMsgHashes[chatId]
newHash := c.calculateMessageHash(messageId, content)
if !ok {
log.Warnf("Last message hash for chat %v does not exist", chatId)
}
log.WithFields(log.Fields{
"old hash": oldHash,
"new hash": newHash,
}).Info("Message hashes")
return !ok || oldHash != newHash
}