forked from fair/matrix-puppeteer-line
Tighten up puppet DM invites
This commit is contained in:
parent
0dd2cf60b1
commit
3868c19b71
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"]))
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Reference in New Issue