Add support for forwarding messages

This commit is contained in:
Tulir Asokan
2022-07-07 13:02:01 +03:00
parent f26973f46c
commit df9b7d343e
3 changed files with 79 additions and 0 deletions

View File

@@ -5,6 +5,9 @@
* Added option to not bridge chats with lots of members.
* Added option to include captions in the same message as the media to
implement [MSC2530].
* Added support for bridging forwarded messages as forwards on Telegram.
* If forwarding fails (e.g. due to it being blocked in the source chat), the
bridge will automatically fall back to sending it as a normal new message.
* Added options to make encryption more secure.
* The `encryption` -> `verification_levels` config options can be used to
make the bridge require encrypted messages to come from cross-signed

View File

@@ -1897,6 +1897,68 @@ class Portal(DBPortal, BasePortal):
message_type=content.msgtype,
)
async def _find_source_msg(
self, sender: u.User, content: MessageEventContent
) -> DBMessage | None:
try:
source = content["fi.mau.telegram.source"]
except KeyError:
return None
if not isinstance(source, dict):
return None
try:
msg_id = source["id"]
space = source["space"]
chat_id = source["chat_id"]
peer_type = source["peer_type"]
except KeyError:
return None
if (
not isinstance(msg_id, int)
or not isinstance(chat_id, int)
or not isinstance(space, int)
or not isinstance(peer_type, str)
):
return None
elif await sender.needs_relaybot(self):
return None
if peer_type == "user" and space != sender.tgid:
return
dbm = await DBMessage.get_one_by_tgid(TelegramID(msg_id), TelegramID(space))
if dbm and peer_type == "chat" and space != sender.tgid:
dbm = DBMessage.get_by_mxid(dbm.mxid, dbm.mx_room, sender.tgid)
return dbm
async def _handle_matrix_forward(
self,
sender: u.User,
msg: DBMessage,
event_id: EventID,
space: TelegramID,
msgtype: MessageType,
) -> bool:
source_portal = await Portal.get_by_mxid(msg.mx_room)
if not source_portal:
return False
async with self.send_lock(sender.tgid):
try:
response = await sender.client.forward_messages(
self.peer,
messages=[msg.tgid],
from_peer=source_portal.peer,
)
except Exception as e:
self.log.warning(
f"Failed to send {event_id} from {sender.mxid} as forward of {msg.tgid} "
f"from {source_portal.tgid}: {e}, falling back to normal message handling"
)
return False
else:
await self._mark_matrix_handled(
sender, EventType.ROOM_MESSAGE, event_id, space, 0, response[0], msgtype
)
return True
async def _handle_matrix_message(
self, sender: u.User, content: MessageEventContent, event_id: EventID
) -> None:
@@ -1912,6 +1974,11 @@ class Portal(DBPortal, BasePortal):
if self.peer_type == "channel" # Channels have their own ID space
else (sender.tgid if logged_in else self.bot.tgid)
)
source_msg = await self._find_source_msg(sender, content)
if source_msg and await self._handle_matrix_forward(
sender, source_msg, event_id, space, content.msgtype
):
return
reply_to = await formatter.matrix_reply_to_telegram(content, space, room_id=self.mxid)
media = (

View File

@@ -159,7 +159,16 @@ class TelegramMessageConverter:
return
if converted:
converted.content.external_url = self._get_external_url(evt)
converted.content["fi.mau.telegram.source"] = {
"space": self.portal.tgid if self.portal.peer_type == "channel" else source.tgid,
"chat_id": self.portal.tgid,
"peer_type": self.portal.peer_type,
"id": evt.id,
}
if converted.caption:
converted.caption["fi.mau.telegram.source"] = converted.content[
"fi.mau.telegram.source"
]
converted.caption.external_url = converted.content.external_url
if self.portal.get_config("caption_in_message"):
self._caption_to_message(converted)