Tighten up puppet DM invites

This commit is contained in:
Andrew Ferrazzutti 2021-07-22 03:20:58 -04:00
parent 0dd2cf60b1
commit 3868c19b71
5 changed files with 85 additions and 15 deletions

View File

@ -16,12 +16,12 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from mautrix.bridge import BaseMatrixHandler from mautrix.bridge import BaseMatrixHandler
from mautrix.types import (Event, ReactionEvent, MessageEvent, StateEvent, EncryptedEvent, RedactionEvent, from mautrix.types import (Event, EventType, MessageEvent, StateEvent, EncryptedEvent,
ReceiptEvent, SingleReceiptEventContent, ReceiptEvent, SingleReceiptEventContent, TextMessageEventContent,
EventID, RoomID, UserID) EventID, RoomID, UserID)
from mautrix.errors import MatrixError
from . import portal as po, puppet as pu, user as u from . import portal as po, puppet as pu, user as u
from .db import Message as DBMessage
if TYPE_CHECKING: if TYPE_CHECKING:
from .__main__ import MessagesBridge from .__main__ import MessagesBridge
@ -54,17 +54,78 @@ class MatrixHandler(BaseMatrixHandler):
async def handle_puppet_invite(self, room_id: RoomID, puppet: 'pu.Puppet', async def handle_puppet_invite(self, room_id: RoomID, puppet: 'pu.Puppet',
invited_by: 'u.User', _: EventID) -> None: invited_by: 'u.User', _: EventID) -> None:
chat_id = puppet.mid intent = puppet.intent
portal = await po.Portal.get_by_chat_id(chat_id, create=True) self.log.debug(f"{invited_by.mxid} invited puppet for {puppet.mid} to {room_id}")
if portal.mxid: if not await invited_by.is_logged_in():
# TODO Allow creating a LINE group/room from a Matrix invite await intent.error_and_leave(room_id, text="Please log in before inviting "
await portal.main_intent.error_and_leave(room_id, "You already have an existing chat with me!") "LINE puppets to private chats.")
return return
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.")
else:
# 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.")
return
await intent.join_room(room_id)
try:
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)
return
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)
return
portal = await po.Portal.get_by_chat_id(puppet.mid, create=True)
if portal.mxid:
try:
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"
"</a>"))
await intent.leave_room(room_id)
return
except MatrixError:
pass
portal.mxid = room_id 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,
TextMessageEventContent(msgtype=MessageType.NOTICE,
body="Portal to private chat created and end-to-bridge"
" encryption enabled."))
await intent.send_message_event(room_id, evt_type, content)
else:
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 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() await invited_by.client.pause()
try: try:
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 portal.update_matrix_room(invited_by, chat_info)
finally: finally:
await invited_by.client.resume() await invited_by.client.resume()

View File

@ -189,7 +189,8 @@ class Portal(DBPortal, BasePortal):
async def handle_matrix_leave(self, user: 'u.User') -> None: async def handle_matrix_leave(self, user: 'u.User') -> None:
self.log.info(f"{user.mxid} left portal to {self.chat_id}, " self.log.info(f"{user.mxid} left portal to {self.chat_id}, "
f"cleaning up and deleting...") 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() await self.cleanup_and_delete()
async def _bridge_own_message_pm(self, source: 'u.User', puppet: Optional['p.Puppet'], mid: str, 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)) return MediaInfo(mxc, decryption_info, mime_type, file_name, len(data))
async def update_info(self, conv: ChatInfo, client: Optional[Client]) -> None: 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: for participant in conv.participants:
# REMINDER: multi-user chats include your own LINE user in the participant list # REMINDER: multi-user chats include your own LINE user in the participant list
if participant.id != None: if participant.id != None:
@ -806,7 +803,8 @@ class Portal(DBPortal, BasePortal):
self.by_chat_id[self.chat_id] = self self.by_chat_id[self.chat_id] = self
if self.mxid: if self.mxid:
self.by_mxid[self.mxid] = self 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 = (await p.Puppet.get_by_mid(self.other_user)).intent
else: else:
self._main_intent = self.az.intent self._main_intent = self.az.intent

View File

@ -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: 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) 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 on_message(self, func: Callable[[Message], Awaitable[None]]) -> None:
async def wrapper(data: Dict[str, Any]) -> None: async def wrapper(data: Dict[str, Any]) -> None:
await func(Message.deserialize(data["message"])) await func(Message.deserialize(data["message"]))

View File

@ -258,6 +258,7 @@ export default class Client {
send: req => this.puppet.sendMessage(req.chat_id, req.text), send: req => this.puppet.sendMessage(req.chat_id, req.text),
send_file: req => this.puppet.sendFile(req.chat_id, req.file_path), 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), 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(), pause: () => this.puppet.stopObserving(),
resume: () => this.puppet.startObserving(), resume: () => this.puppet.startObserving(),
get_own_profile: () => this.puppet.getOwnProfile(), get_own_profile: () => this.puppet.getOwnProfile(),

View File

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