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 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
if TYPE_CHECKING:
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.")
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
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 Consider not backfilling on invite.
# To do so, must set the last-seen message ID appropriately
await invited_by.client.pause()
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)
finally:
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:
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
else:
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:
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"]))

View File

@ -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(),

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) {
return await this.taskQueue.push(() =>
this.page.evaluate(