From 815ce4098985d1ccaed5b15603721cc05b642ac3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 14 Apr 2023 14:12:01 +0300 Subject: [PATCH] Add option to not set room meta in encrypted rooms --- mautrix_telegram/__main__.py | 1 + mautrix_telegram/config.py | 9 ++++- mautrix_telegram/example-config.yaml | 8 +++-- mautrix_telegram/portal.py | 54 +++++++++++++++++----------- mautrix_telegram/puppet.py | 2 +- 5 files changed, 49 insertions(+), 25 deletions(-) diff --git a/mautrix_telegram/__main__.py b/mautrix_telegram/__main__.py index 7b8881d9..a788b662 100644 --- a/mautrix_telegram/__main__.py +++ b/mautrix_telegram/__main__.py @@ -50,6 +50,7 @@ class TelegramBridge(Bridge): config: Config bot: Bot | None + matrix: MatrixHandler public_website: PublicBridgeWebsite | None provisioning_api: ProvisioningAPI | None diff --git a/mautrix_telegram/config.py b/mautrix_telegram/config.py index 492bbe07..2e16b962 100644 --- a/mautrix_telegram/config.py +++ b/mautrix_telegram/config.py @@ -148,7 +148,14 @@ class Config(BaseBridgeConfig): copy("bridge.animated_emoji.args.width") copy("bridge.animated_emoji.args.height") copy("bridge.animated_emoji.args.fps") - copy("bridge.private_chat_portal_meta") + if isinstance(self.get("bridge.private_chat_portal_meta", "default"), bool): + base["bridge.private_chat_portal_meta"] = ( + "always" if self["bridge.private_chat_portal_meta"] else "default" + ) + else: + copy("bridge.private_chat_portal_meta") + if base["bridge.private_chat_portal_meta"] not in ("default", "always", "never"): + base["bridge.private_chat_portal_meta"] = "default" copy("bridge.delivery_receipts") copy("bridge.delivery_error_reports") copy("bridge.incoming_bridge_error_reports") diff --git a/mautrix_telegram/example-config.yaml b/mautrix_telegram/example-config.yaml index d94012eb..9d8f6263 100644 --- a/mautrix_telegram/example-config.yaml +++ b/mautrix_telegram/example-config.yaml @@ -326,9 +326,11 @@ bridge: # default. messages: 100 - # Whether or not to explicitly set the avatar and room name for private - # chat portal rooms. This will be implicitly enabled if encryption.default is true. - private_chat_portal_meta: false + # Whether to explicitly set the avatar and room name for private chat portal rooms. + # If set to `default`, this will be enabled in encrypted rooms and disabled in unencrypted rooms. + # If set to `always`, all DM rooms will have explicit names and avatars set. + # If set to `never`, DM rooms will never have names and avatars set. + private_chat_portal_meta: default # Whether or not the bridge should send a read receipt from the bridge bot when a message has # been sent to Telegram. delivery_receipts: false diff --git a/mautrix_telegram/portal.py b/mautrix_telegram/portal.py index 1351cbb2..e67a9c88 100644 --- a/mautrix_telegram/portal.py +++ b/mautrix_telegram/portal.py @@ -1,5 +1,5 @@ # mautrix-telegram - A Matrix-Telegram puppeting bridge -# Copyright (C) 2022 Tulir Asokan +# Copyright (C) 2023 Tulir Asokan # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by @@ -15,7 +15,17 @@ # along with this program. If not, see . from __future__ import annotations -from typing import TYPE_CHECKING, Any, AsyncGenerator, Awaitable, Callable, List, Union, cast +from typing import ( + TYPE_CHECKING, + Any, + AsyncGenerator, + Awaitable, + Callable, + List, + Literal, + Union, + cast, +) from collections import defaultdict from datetime import datetime from html import escape as escape_html @@ -263,7 +273,7 @@ class Portal(DBPortal, BasePortal): sync_channel_members: bool sync_matrix_state: bool public_portals: bool - private_chat_portal_meta: bool + private_chat_portal_meta: Literal["default", "always", "never"] alias_template: SimpleTemplate[str] hs_domain: str @@ -440,6 +450,14 @@ class Portal(DBPortal, BasePortal): return self.tgid not in self.filter_list return True + @property + def set_dm_room_metadata(self) -> bool: + return ( + not self.is_direct + or self.private_chat_portal_meta == "always" + or (self.encrypted and self.private_chat_portal_meta != "never") + ) + @classmethod def init_cls(cls, bridge: "TelegramBridge") -> None: BasePortal.bridge = bridge @@ -714,12 +732,8 @@ class Portal(DBPortal, BasePortal): source: au.AbstractUser | None = None, photo: UserProfilePhoto | None = None, ) -> None: - if not self.encrypted and not self.private_chat_portal_meta: - return if puppet is None: puppet = await self.get_dm_puppet() - # The bridge bot needs to join for e2ee, but that messes up the default name - # generation. If/when canonical DMs happen, this might not be necessary anymore. changed = await self._update_avatar_from_puppet(puppet, source, photo) changed = await self._update_title(puppet.displayname) or changed if changed: @@ -951,7 +965,7 @@ class Portal(DBPortal, BasePortal): ) if self.is_direct: create_invites.add(self.az.bot_mxid) - if self.is_direct and (self.encrypted or self.private_chat_portal_meta): + if self.is_direct: assert puppet is not None self.title = puppet.displayname self.avatar_url = puppet.avatar_url @@ -959,7 +973,7 @@ class Portal(DBPortal, BasePortal): creation_content = {} if not self.config["bridge.federate_rooms"]: creation_content["m.federate"] = False - if self.avatar_url: + if self.avatar_url and self.set_dm_room_metadata: initial_state.append( { "type": str(EventType.ROOM_AVATAR), @@ -971,14 +985,14 @@ class Portal(DBPortal, BasePortal): self.log.debug( f"Creating room with parameters invite={create_invites}, {autojoin_invites=}, " f"{preset=}, {alias=!r}, name={self.title!r}, topic={self.about!r}, " - f"{creation_content=}, is_direct={self.is_direct}" + f"{creation_content=}, is_direct={self.is_direct}, {self.set_dm_room_metadata=}" ) room_id = await self.main_intent.create_room( alias_localpart=alias, preset=preset, is_direct=self.is_direct, invitees=list(create_invites), - name=self.title, + name=self.title if self.set_dm_room_metadata else None, topic=self.about, initial_state=initial_state, creation_content=creation_content, @@ -986,8 +1000,8 @@ class Portal(DBPortal, BasePortal): ) if not room_id: raise Exception(f"Failed to create room") - self.name_set = bool(self.title) - self.avatar_set = bool(self.avatar_url) + self.name_set = bool(self.title) and self.set_dm_room_metadata + self.avatar_set = bool(self.avatar_url) and self.set_dm_room_metadata if not autojoin_invites and self.encrypted and self.matrix.e2ee and self.is_direct: try: @@ -1301,11 +1315,12 @@ class Portal(DBPortal, BasePortal): async def _update_title( self, title: str, sender: p.Puppet | None = None, save: bool = False ) -> bool: - if self.title == title and self.name_set: + if self.title == title and (self.name_set or not self.set_dm_room_metadata): return False self.title = title - if self.mxid: + self.name_set = False + if self.mxid and self.set_dm_room_metadata: try: await self._try_set_state( sender, EventType.ROOM_NAME, RoomNameStateEventContent(name=self.title) @@ -1313,7 +1328,6 @@ class Portal(DBPortal, BasePortal): self.name_set = True except Exception as e: self.log.warning(f"Failed to set room name: {e}") - self.name_set = False if save: await self.save() return True @@ -1321,12 +1335,13 @@ class Portal(DBPortal, BasePortal): async def _update_avatar_from_puppet( self, puppet: p.Puppet, user: au.AbstractUser | None, photo: UserProfilePhoto | None ) -> bool: - if self.photo_id == puppet.photo_id and self.avatar_set: + if self.photo_id == puppet.photo_id and (self.avatar_set or not self.set_dm_room_metadata): return False if puppet.avatar_url: self.photo_id = puppet.photo_id self.avatar_url = puppet.avatar_url - if self.mxid: + self.avatar_set = False + if self.mxid and self.set_dm_room_metadata: try: await self._try_set_state( None, @@ -1336,9 +1351,8 @@ class Portal(DBPortal, BasePortal): self.avatar_set = True except Exception as e: self.log.warning(f"Failed to set room avatar: {e}") - self.avatar_set = False return True - elif photo is not None and user is not None: + elif photo is not None and user is not None and self.set_dm_room_metadata: return await self._update_avatar(user, photo=photo) else: return False diff --git a/mautrix_telegram/puppet.py b/mautrix_telegram/puppet.py index 1423a177..a3d841a5 100644 --- a/mautrix_telegram/puppet.py +++ b/mautrix_telegram/puppet.py @@ -297,7 +297,7 @@ class Puppet(DBPuppet, BasePuppet): await self.save() async def update_portals_meta(self) -> None: - if not p.Portal.private_chat_portal_meta and not self.mx.e2ee: + if p.Portal.private_chat_portal_meta != "always" and not self.mx.e2ee: return async for portal in p.Portal.find_private_chats_with(self.tgid): await portal.update_info_from_puppet(self)