From 2ae4b235281ef88cffdcee2e07fefd04f6a9ee3c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 15 Dec 2019 17:10:04 +0200 Subject: [PATCH] Add option to log in to custom puppet with shared secret --- example-config.yaml | 6 ++++++ mautrix_telegram/commands/telegram/auth.py | 9 ++++++--- mautrix_telegram/config.py | 1 + mautrix_telegram/puppet.py | 3 +++ mautrix_telegram/user.py | 21 +++++++++++++++++---- mautrix_telegram/web/common/auth_api.py | 2 +- setup.py | 2 +- 7 files changed, 35 insertions(+), 9 deletions(-) diff --git a/example-config.yaml b/example-config.yaml index 082674a6..2c2040a9 100644 --- a/example-config.yaml +++ b/example-config.yaml @@ -154,6 +154,12 @@ bridge: # Whether or not to use /sync to get presence, read receipts and typing notifications when using # your own Matrix account as the Matrix puppet for your Telegram account. sync_with_custom_puppets: true + # Shared secret for https://github.com/devture/matrix-synapse-shared-secret-auth + # + # If set, custom puppets will be enabled automatically for local users + # instead of users having to find an access token and run `login-matrix` + # manually. + login_shared_secret: null # Set to false to disable link previews in messages sent to Telegram. telegram_link_preview: true # Use inline images instead of a separate message for the caption. diff --git a/mautrix_telegram/commands/telegram/auth.py b/mautrix_telegram/commands/telegram/auth.py index a47b987a..d6adf1ce 100644 --- a/mautrix_telegram/commands/telegram/auth.py +++ b/mautrix_telegram/commands/telegram/auth.py @@ -20,7 +20,8 @@ from telethon.errors import ( # isort: skip AccessTokenExpiredError, AccessTokenInvalidError, FirstNameInvalidError, FloodWaitError, PasswordHashInvalidError, PhoneCodeExpiredError, PhoneCodeInvalidError, PhoneNumberAppSignupForbiddenError, PhoneNumberBannedError, PhoneNumberFloodError, - PhoneNumberOccupiedError, PhoneNumberUnoccupiedError, SessionPasswordNeededError) + PhoneNumberOccupiedError, PhoneNumberUnoccupiedError, SessionPasswordNeededError, + PhoneNumberInvalidError) from mautrix.types import EventID @@ -84,7 +85,7 @@ async def enter_code_register(evt: CommandEvent) -> EventID: await evt.sender.ensure_started(even_if_no_session=True) first_name, last_name = evt.sender.command_status["full_name"] user = await evt.sender.client.sign_up(evt.args[0], first_name, last_name) - asyncio.ensure_future(evt.sender.post_login(user), loop=evt.loop) + asyncio.ensure_future(evt.sender.post_login(user, first_login=True), loop=evt.loop) evt.sender.command_status = None return await evt.reply(f"Successfully registered to Telegram.") except PhoneNumberOccupiedError: @@ -166,6 +167,8 @@ async def _request_code(evt: CommandEvent, phone_number: str, next_status: Dict[ except PhoneNumberUnoccupiedError: return await evt.reply("That phone number has not been registered. " "Please register with `$cmdprefix+sp register `.") + except PhoneNumberInvalidError: + return await evt.reply("That phone number is not valid.") except Exception: evt.log.exception("Error requesting phone code") return await evt.reply("Unhandled exception while requesting code. " @@ -244,7 +247,7 @@ async def _sign_in(evt: CommandEvent, **sign_in_info) -> EventID: await evt.reply(f"[{existing_user.displayname}]" f"(https://matrix.to/#/{existing_user.mxid})" " was logged out from the account.") - asyncio.ensure_future(evt.sender.post_login(user), loop=evt.loop) + asyncio.ensure_future(evt.sender.post_login(user, first_login=True), loop=evt.loop) evt.sender.command_status = None name = f"@{user.username}" if user.username else f"+{user.phone}" return await evt.reply(f"Successfully logged in as {name}") diff --git a/mautrix_telegram/config.py b/mautrix_telegram/config.py index 849c315c..a1ca0182 100644 --- a/mautrix_telegram/config.py +++ b/mautrix_telegram/config.py @@ -109,6 +109,7 @@ class Config(BaseBridgeConfig): copy("bridge.plaintext_highlights") copy("bridge.public_portals") copy("bridge.sync_with_custom_puppets") + copy("bridge.login_shared_secret") copy("bridge.telegram_link_preview") copy("bridge.inline_images") copy("bridge.image_as_file_size") diff --git a/mautrix_telegram/puppet.py b/mautrix_telegram/puppet.py index cf9c478f..97ccac5e 100644 --- a/mautrix_telegram/puppet.py +++ b/mautrix_telegram/puppet.py @@ -424,4 +424,7 @@ def init(context: 'Context') -> Iterable[Awaitable[Any]]: Puppet.displayname_template = SimpleTemplate(config["bridge.displayname_template"], "displayname") + Puppet.login_shared_secret = config["bridge.login_shared_secret"].encode("utf-8") + Puppet.login_device_name = "Telegram Bridge" + return (puppet.try_start() for puppet in Puppet.all_with_custom_mxid()) diff --git a/mautrix_telegram/user.py b/mautrix_telegram/user.py index 6fa20385..73b28945 100644 --- a/mautrix_telegram/user.py +++ b/mautrix_telegram/user.py @@ -199,14 +199,27 @@ class User(AbstractUser, BaseUser): self.client.session.delete() return self - async def post_login(self, info: TLUser = None) -> None: + async def post_login(self, info: TLUser = None, first_login: bool = False) -> None: try: await self.update_info(info) - if not self.is_bot and config["bridge.startup_sync"]: + except Exception: + self.log.exception("Failed to update telegram account info") + return + + try: + puppet = pu.Puppet.get(self.tgid) + if puppet.custom_mxid != self.mxid and puppet.can_auto_login(self.mxid): + self.log.info(f"Automatically enabling custom puppet") + await puppet.switch_mxid(access_token="auto", mxid=self.mxid) + except Exception: + self.log.exception("Failed to automatically enable custom puppet") + + if not self.is_bot and config["bridge.startup_sync"]: + try: await self.sync_dialogs() await self.sync_contacts() - except Exception: - self.log.exception("Failed to run post-login functions for %s", self.mxid) + except Exception: + self.log.exception("Failed to run post-login sync") async def update(self, update: TypeUpdate) -> bool: if not self.is_bot: diff --git a/mautrix_telegram/web/common/auth_api.py b/mautrix_telegram/web/common/auth_api.py index 8e02a87e..8b1a2dc0 100644 --- a/mautrix_telegram/web/common/auth_api.py +++ b/mautrix_telegram/web/common/auth_api.py @@ -119,7 +119,7 @@ class AuthAPI(abc.ABC): existing_user = User.get_by_tgid(user_info.id) if existing_user and existing_user != user: await existing_user.log_out() - asyncio.ensure_future(user.post_login(user_info), loop=self.loop) + asyncio.ensure_future(user.post_login(user_info, first_login=True), loop=self.loop) if user.command_status and user.command_status["action"] == "Login": user.command_status = None diff --git a/setup.py b/setup.py index 9b920290..99a93c8a 100644 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ setuptools.setup( install_requires=[ "aiohttp>=3.0.1,<4", - "mautrix>=0.4.0rc2,<0.5", + "mautrix>=0.4.0rc4,<0.5", "SQLAlchemy>=1.2.3,<2", "alembic>=1.0.0,<2", "commonmark>=0.8.1,<0.10",