Tighten up puppet DM invites

Andrew Ferrazzutti 1 year ago
parent 0dd2cf60b1
commit 3868c19b71
  1. 79
  2. 10
  3. 3
  4. 1
  5. 7

@ -16,12 +16,12 @@
from typing import TYPE_CHECKING
from mautrix.bridge import BaseMatrixHandler
from mautrix.types import (Event, ReactionEvent, MessageEvent, StateEvent, EncryptedEvent, RedactionEvent,
ReceiptEvent, SingleReceiptEventContent,
from mautrix.types import (Event, EventType, MessageEvent, StateEvent, EncryptedEvent,
ReceiptEvent, SingleReceiptEventContent, TextMessageEventContent,
EventID, RoomID, UserID)
from mautrix.errors import MatrixError
from . import portal as po, puppet as pu, user as u
from .db import Message as DBMessage
from .__main__ import MessagesBridge
@ -54,17 +54,78 @@ class MatrixHandler(BaseMatrixHandler):
async def handle_puppet_invite(self, room_id: RoomID, puppet: 'pu.Puppet',
invited_by: 'u.User', _: EventID) -> None:
chat_id = puppet.mid
portal = await po.Portal.get_by_chat_id(chat_id, create=True)
if portal.mxid:
# TODO Allow creating a LINE group/room from a Matrix invite
await portal.main_intent.error_and_leave(room_id, "You already have an existing chat with me!")
intent = puppet.intent
self.log.debug(f"{invited_by.mxid} invited puppet for {puppet.mid} to {room_id}")
if not await invited_by.is_logged_in():
await intent.error_and_leave(room_id, text="Please log in before inviting "
"LINE puppets to private chats.")
portal = await po.Portal.get_by_mxid(room_id)
if portal:
if portal.is_direct:
await intent.error_and_leave(room_id, text="You can not invite additional users "
"to private chats.")
# TODO Send invite in LINE
await intent.error_and_leave(room_id, text="Inviting additional users to an existing "
"group chat is not yet supported.")
await intent.join_room(room_id)
members = await intent.get_room_members(room_id)
except MatrixError:
self.log.exception(f"Failed to get member list after joining {room_id}")
await intent.leave_room(room_id)
if len(members) > 2:
# TODO Add LINE group/room creating. Must also distinguish between the two!
await intent.send_notice(room_id, "You can not invite LINE puppets to "
"multi-user rooms.")
await intent.leave_room(room_id)
portal = await po.Portal.get_by_chat_id(puppet.mid, create=True)
if portal.mxid:
await intent.invite_user(portal.mxid, invited_by.mxid, check_cache=False)
await intent.send_notice(room_id,
text=("You already have a private chat with me "
f"in room {portal.mxid}"),
html=("You already have a private chat with me: "
f"<a href='https://matrix.to/#/{portal.mxid}'>"
"Link to room"
await intent.leave_room(room_id)
except MatrixError:
portal.mxid = room_id
e2be_ok = await portal.check_dm_encryption()
# TODO Consider setting other power levels that get set on portal creation,
# but they're of little use when the inviting user has an equal PL...
await portal.save()
if e2be_ok is True:
evt_type, content = await self.e2ee.encrypt(
room_id, EventType.ROOM_MESSAGE,
body="Portal to private chat created and end-to-bridge"
" encryption enabled."))
await intent.send_message_event(room_id, evt_type, content)
message = "Portal to private chat created."
if e2be_ok is False:
message += "\n\nWarning: Failed to enable end-to-bridge encryption"
await intent.send_notice(room_id, message)
# TODO Put pause/resume in portal methods, with a lock or something
# TODO Consider not backfilling on invite.
# To do so, must set the last-seen message ID appropriately
await invited_by.client.pause()
chat_info = await invited_by.client.get_chat(chat_id)
chat_info = await invited_by.client.get_chat(puppet.mid)
await portal.update_matrix_room(invited_by, chat_info)
await invited_by.client.resume()

@ -189,7 +189,8 @@ class Portal(DBPortal, BasePortal):
async def handle_matrix_leave(self, user: 'u.User') -> None:
self.log.info(f"{user.mxid} left portal to {self.chat_id}, "
f"cleaning up and deleting...")
# TODO Delete room history in LINE to prevent a re-sync from happening
if await user.is_logged_in():
await user.client.forget_chat(self.chat_id)
await self.cleanup_and_delete()
async def _bridge_own_message_pm(self, source: 'u.User', puppet: Optional['p.Puppet'], mid: str,
@ -501,10 +502,6 @@ class Portal(DBPortal, BasePortal):
return MediaInfo(mxc, decryption_info, mime_type, file_name, len(data))
async def update_info(self, conv: ChatInfo, client: Optional[Client]) -> None:
if self.is_direct:
self.other_user = conv.participants[0].id
if self._main_intent is self.az.intent:
self._main_intent = (await p.Puppet.get_by_mid(self.other_user)).intent
for participant in conv.participants:
# REMINDER: multi-user chats include your own LINE user in the participant list
if participant.id != None:
@ -806,7 +803,8 @@ class Portal(DBPortal, BasePortal):
self.by_chat_id[self.chat_id] = self
if self.mxid:
self.by_mxid[self.mxid] = self
if self.other_user:
if self.is_direct:
self.other_user = self.chat_id
self._main_intent = (await p.Puppet.get_by_mid(self.other_user)).intent
self._main_intent = self.az.intent

@ -88,6 +88,9 @@ class Client(RPCClient):
async def set_last_message_ids(self, msg_ids: Dict[str, int], own_msg_ids: Dict[str, int], rct_ids: Dict[str, Dict[int, int]]) -> None:
await self.request("set_last_message_ids", msg_ids=msg_ids, own_msg_ids=own_msg_ids, rct_ids=rct_ids)
async def forget_chat(self, chat_id: str) -> None:
await self.request("forget_chat", chat_id=chat_id)
async def on_message(self, func: Callable[[Message], Awaitable[None]]) -> None:
async def wrapper(data: Dict[str, Any]) -> None:
await func(Message.deserialize(data["message"]))

@ -258,6 +258,7 @@ export default class Client {
send: req => this.puppet.sendMessage(req.chat_id, req.text),
send_file: req => this.puppet.sendFile(req.chat_id, req.file_path),
set_last_message_ids: req => this.puppet.setLastMessageIDs(req.msg_ids, req.own_msg_ids, req.rct_ids),
forget_chat: req => this.puppet.forgetChat(req.chat_id),
pause: () => this.puppet.stopObserving(),
resume: () => this.puppet.startObserving(),
get_own_profile: () => this.puppet.getOwnProfile(),

@ -538,6 +538,13 @@ export default class MessagesPuppeteer {
forgetChat(chatID) {
// TODO Delete chat from recents list
async readImage(imageUrl) {
return await this.taskQueue.push(() =>