From 1b91fbc8064af5c9aeddf319506f2566f01269e9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 30 Oct 2020 20:16:02 +0200 Subject: [PATCH] Check room encryption status when bridging portal --- mautrix_telegram/commands/portal/bridge.py | 7 ++- .../commands/portal/create_chat.py | 6 +- mautrix_telegram/commands/portal/util.py | 7 ++- mautrix_telegram/portal/base.py | 1 + mautrix_telegram/web/provisioning/__init__.py | 56 ++++++++++--------- 5 files changed, 43 insertions(+), 34 deletions(-) diff --git a/mautrix_telegram/commands/portal/bridge.py b/mautrix_telegram/commands/portal/bridge.py index 1cf38808..833bdc4a 100644 --- a/mautrix_telegram/commands/portal/bridge.py +++ b/mautrix_telegram/commands/portal/bridge.py @@ -136,6 +136,9 @@ async def confirm_bridge(evt: CommandEvent) -> Optional[EventID]: return await evt.reply("Fatal error: tgid or peer_type missing from command_status. " "This shouldn't happen unless you're messing with the command " "handler code.") + + is_logged_in = await evt.sender.is_logged_in() and not status["force_use_bot"] + if "mxid" in status: ok, coro = await cleanup_old_portal_while_bridging(evt, portal) if not ok: @@ -153,7 +156,6 @@ async def confirm_bridge(evt: CommandEvent) -> Optional[EventID]: "`$cmdprefix+sp cancel` to cancel.") evt.sender.command_status = None - is_logged_in = await evt.sender.is_logged_in() and not status["force_use_bot"] async with portal._room_create_lock: await _locked_confirm_bridge(evt, portal=portal, room_id=bridge_to_mxid, is_logged_in=is_logged_in) @@ -180,7 +182,8 @@ async def _locked_confirm_bridge(evt: CommandEvent, portal: 'po.Portal', room_id portal.mxid = room_id portal.by_mxid[portal.mxid] = portal - portal.title, portal.about, levels = await get_initial_state(evt.az.intent, evt.room_id) + (portal.title, portal.about, levels, + portal.encrypted) = await get_initial_state(evt.az.intent, evt.room_id) portal.photo_id = "" await portal.save() diff --git a/mautrix_telegram/commands/portal/create_chat.py b/mautrix_telegram/commands/portal/create_chat.py index c26c49af..c2271b38 100644 --- a/mautrix_telegram/commands/portal/create_chat.py +++ b/mautrix_telegram/commands/portal/create_chat.py @@ -38,7 +38,7 @@ async def create(evt: CommandEvent) -> EventID: if not await user_has_power_level(evt.room_id, evt.az.intent, evt.sender, "bridge"): return await evt.reply("You do not have the permissions to bridge this room.") - title, about, levels = await get_initial_state(evt.az.intent, evt.room_id) + title, about, levels, encrypted = await get_initial_state(evt.az.intent, evt.room_id) if not title: return await evt.reply("Please set a title before creating a Telegram chat.") @@ -50,8 +50,8 @@ async def create(evt: CommandEvent) -> EventID: "group": "chat", }[type] - portal = po.Portal(tgid=TelegramID(0), peer_type=type, - mxid=evt.room_id, title=title, about=about) + portal = po.Portal(tgid=TelegramID(0), peer_type=type, mxid=evt.room_id, + title=title, about=about, encrypted=encrypted) try: await portal.create_telegram_chat(evt.sender, supergroup=supergroup) except ValueError as e: diff --git a/mautrix_telegram/commands/portal/util.py b/mautrix_telegram/commands/portal/util.py index 67ca5482..c3db1a01 100644 --- a/mautrix_telegram/commands/portal/util.py +++ b/mautrix_telegram/commands/portal/util.py @@ -25,11 +25,12 @@ OptStr = Optional[str] async def get_initial_state(intent: IntentAPI, room_id: RoomID - ) -> Tuple[OptStr, OptStr, Optional[PowerLevelStateEventContent]]: + ) -> Tuple[OptStr, OptStr, Optional[PowerLevelStateEventContent], bool]: state = await intent.get_state(room_id) title: OptStr = None about: OptStr = None levels: Optional[PowerLevelStateEventContent] = None + encrypted: bool = False for event in state: try: if event.type == EventType.ROOM_NAME: @@ -40,10 +41,12 @@ async def get_initial_state(intent: IntentAPI, room_id: RoomID levels = event.content elif event.type == EventType.ROOM_CANONICAL_ALIAS: title = title or event.content.canonical_alias + elif event.type == EventType.ROOM_ENCRYPTION: + encrypted = True except KeyError: # Some state event probably has empty content pass - return title, about, levels + return title, about, levels, encrypted async def user_has_power_level(room_id: RoomID, intent: IntentAPI, sender: u.User, diff --git a/mautrix_telegram/portal/base.py b/mautrix_telegram/portal/base.py index 00067e54..3f3d5106 100644 --- a/mautrix_telegram/portal/base.py +++ b/mautrix_telegram/portal/base.py @@ -107,6 +107,7 @@ class BasePortal(MautrixBasePortal, ABC): _db_instance: DBPortal _main_intent: Optional[IntentAPI] + _room_create_lock: asyncio.Lock def __init__(self, tgid: TelegramID, peer_type: str, tg_receiver: Optional[TelegramID] = None, mxid: Optional[RoomID] = None, username: Optional[str] = None, diff --git a/mautrix_telegram/web/provisioning/__init__.py b/mautrix_telegram/web/provisioning/__init__.py index 10037927..2ec4cae0 100644 --- a/mautrix_telegram/web/provisioning/__init__.py +++ b/mautrix_telegram/web/provisioning/__init__.py @@ -141,6 +141,12 @@ class ProvisioningAPI(AuthAPI): return self.get_error_response(403, "not_enough_permissions", "You do not have the permissions to bridge that room.") + is_logged_in = user is not None and await user.is_logged_in() + acting_user = user if is_logged_in else self.context.bot + if not acting_user: + return self.get_login_response(status=403, errcode="not_logged_in", + error="You are not logged in and there is no relay bot.") + portal = Portal.get_by_tgid(tgid, peer_type=peer_type) if portal.mxid == room_id: return self.get_error_response(200, "bridge_exists", @@ -157,35 +163,30 @@ class ProvisioningAPI(AuthAPI): "Telegram chat is already bridged to another " "Matrix room.") - is_logged_in = user is not None and await user.is_logged_in() - acting_user = user if is_logged_in else self.context.bot - if not acting_user: - return self.get_login_response(status=403, errcode="not_logged_in", - error="You are not logged in and there is no relay bot.") + async with portal._room_create_lock: + entity: Optional[TypeChat] = None + try: + entity = await acting_user.client.get_entity(portal.peer) + except Exception: + self.log.exception("Failed to get_entity(%s) for manual bridging.", portal.peer) - entity: Optional[TypeChat] = None - try: - entity = await acting_user.client.get_entity(portal.peer) - except Exception: - self.log.exception("Failed to get_entity(%s) for manual bridging.", portal.peer) - - if not entity or isinstance(entity, (ChatForbidden, ChannelForbidden)): - if is_logged_in: - return self.get_error_response(403, "user_not_in_chat", + if not entity or isinstance(entity, (ChatForbidden, ChannelForbidden)): + if is_logged_in: + return self.get_error_response(403, "user_not_in_chat", + "Failed to get info of Telegram chat. " + "Are you in the chat?") + return self.get_error_response(403, "bot_not_in_chat", "Failed to get info of Telegram chat. " - "Are you in the chat?") - return self.get_error_response(403, "bot_not_in_chat", - "Failed to get info of Telegram chat. " - "Is the relay bot in the chat?") + "Is the relay bot in the chat?") - direct = False + portal.mxid = room_id + portal.by_mxid[portal.mxid] = portal + (portal.title, portal.about, levels, + portal.encrypted) = await get_initial_state(self.az.intent, room_id) + portal.photo_id = "" + await portal.save() - portal.mxid = room_id - portal.title, portal.about, levels = await get_initial_state(self.az.intent, room_id) - portal.photo_id = "" - await portal.save() - - asyncio.ensure_future(portal.update_matrix_room(user, entity, direct, levels=levels), + asyncio.ensure_future(portal.update_matrix_room(user, entity, direct=False, levels=levels), loop=self.loop) return web.Response(status=202, body="{}") @@ -216,7 +217,7 @@ class ProvisioningAPI(AuthAPI): "You do not have the permissions to bridge that room.") try: - title, about, _ = await get_initial_state(self.az.intent, room_id) + title, about, _, encrypted = await get_initial_state(self.az.intent, room_id) except (MatrixRequestError, IntentError): return self.get_error_response(403, "bot_not_in_room", "The bridge bot is not in the given room.") @@ -240,7 +241,8 @@ class ProvisioningAPI(AuthAPI): "group": "chat", }[type] - portal = Portal(tgid=TelegramID(0), mxid=room_id, title=title, about=about, peer_type=type) + portal = Portal(tgid=TelegramID(0), mxid=room_id, title=title, about=about, peer_type=type, + encrypted=encrypted) try: await portal.create_telegram_chat(user, supergroup=supergroup) except ValueError as e: