Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2f691bf1b8 | |||
| 50984dab14 | |||
| 6f6ce4bcc7 | |||
| 119729393c | |||
| 9f3869e878 | |||
| 9fb2a73ec5 | |||
| 64b3699b3c | |||
| 76ad31a3bc | |||
| 71cdee5a4d | |||
| 2ae4b23528 | |||
| 39927ac6c0 | |||
| 3e6e59db29 |
+4
-2
@@ -18,7 +18,7 @@ RUN apk add --no-cache libpng libpng-dev zlib zlib-dev \
|
||||
&& git checkout 543c1d23ac9322f4f03c7fb6612ea7d026d44ac0 \
|
||||
&& make
|
||||
|
||||
FROM docker.io/alpine:3.10
|
||||
FROM docker.io/alpine:3.11
|
||||
|
||||
ENV UID=1337 \
|
||||
GID=1337 \
|
||||
@@ -52,7 +52,7 @@ RUN apk add --no-cache --virtual .build-deps \
|
||||
py3-markupsafe \
|
||||
#moviepy
|
||||
py3-decorator \
|
||||
#py3-tqdm \
|
||||
py3-tqdm \
|
||||
py3-requests \
|
||||
#imageio
|
||||
py3-numpy \
|
||||
@@ -68,6 +68,8 @@ RUN apk add --no-cache --virtual .build-deps \
|
||||
# lottieconverter
|
||||
zlib libpng \
|
||||
&& pip3 install .[speedups,hq_thumbnails,metrics] \
|
||||
# pip installs the sources to /usr/lib/python3.8/site-packages, so we don't need them here
|
||||
&& rm -rf /opt/mautrix-telegram/mautrix_telegram \
|
||||
&& apk del .build-deps
|
||||
|
||||
VOLUME /data
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -35,6 +35,7 @@ affinity: {}
|
||||
postgresql:
|
||||
enabled: true
|
||||
postgresqlDatabase: mxtg
|
||||
postgresqlPassword: SET TO RANDOM STRING
|
||||
persistence:
|
||||
size: 2Gi
|
||||
resources:
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
__version__ = "0.7.0rc2"
|
||||
__version__ = "0.7.0rc3"
|
||||
__author__ = "Tulir Asokan <tulir@maunium.net>"
|
||||
|
||||
@@ -169,7 +169,7 @@ async def execute_room_cleanup(evt, rooms_to_clean: List[Union[po.Portal, RoomID
|
||||
await room.cleanup_and_delete()
|
||||
cleaned += 1
|
||||
else:
|
||||
await po.Portal.cleanup_room(evt.az.intent, room, message="Room deleted")
|
||||
await po.Portal.cleanup_room(evt.az.intent, room, "Room deleted")
|
||||
cleaned += 1
|
||||
evt.sender.command_status = None
|
||||
await evt.reply(f"{cleaned} rooms cleaned up successfully.")
|
||||
|
||||
@@ -51,6 +51,10 @@ class CommandEvent(BaseCommandEvent):
|
||||
self.config = processor.config
|
||||
self.public_website = processor.public_website
|
||||
|
||||
@property
|
||||
def print_error_traceback(self) -> bool:
|
||||
return self.sender.is_admin
|
||||
|
||||
async def get_help_key(self) -> HelpCacheKey:
|
||||
return HelpCacheKey(self.is_management, self.is_portal, self.sender.puppet_whitelisted,
|
||||
self.sender.matrix_puppet_whitelisted, self.sender.is_admin,
|
||||
|
||||
@@ -113,12 +113,10 @@ async def cleanup_old_portal_while_bridging(evt: CommandEvent, portal: "po.Porta
|
||||
"Continuing without touching previous Matrix room...")
|
||||
return True, None
|
||||
elif evt.args[0] == "delete-and-continue":
|
||||
return True, portal.cleanup_room(portal.main_intent, portal.mxid,
|
||||
message="Portal deleted (moving to another room)")
|
||||
return True, portal.cleanup_portal("Portal deleted (moving to another room)")
|
||||
elif evt.args[0] == "unbridge-and-continue":
|
||||
return True, portal.cleanup_room(portal.main_intent, portal.mxid,
|
||||
message="Room unbridged (portal moving to another room)",
|
||||
puppets_only=True)
|
||||
return True, portal.cleanup_portal("Room unbridged (portal moving to another room)",
|
||||
puppets_only=True)
|
||||
else:
|
||||
await evt.reply(
|
||||
"The chat you were trying to bridge already has a Matrix portal room.\n\n"
|
||||
|
||||
@@ -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 <phone>`.")
|
||||
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}")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import subprocess
|
||||
import shutil
|
||||
import os
|
||||
|
||||
from . import __version__
|
||||
@@ -14,8 +15,7 @@ cmd_env = {
|
||||
def run(cmd):
|
||||
return subprocess.check_output(cmd, stderr=subprocess.DEVNULL, env=cmd_env)
|
||||
|
||||
|
||||
if os.path.exists(".git"):
|
||||
if os.path.exists(".git") and shutil.which("git"):
|
||||
try:
|
||||
git_revision = run(["git", "rev-parse", "HEAD"]).strip().decode("ascii")
|
||||
git_revision_url = f"https://github.com/tulir/mautrix-telegram/commit/{git_revision}"
|
||||
@@ -26,15 +26,15 @@ if os.path.exists(".git"):
|
||||
|
||||
try:
|
||||
git_tag = run(["git", "describe", "--exact-match", "--tags"]).strip().decode("ascii")
|
||||
git_tag_url = f"https://github.com/tulir/mautrix-telegram/releases/tag/{git_tag}"
|
||||
except (subprocess.SubprocessError, OSError):
|
||||
git_tag = None
|
||||
git_tag_url = None
|
||||
else:
|
||||
git_revision = "unknown"
|
||||
git_revision_url = None
|
||||
git_tag = None
|
||||
git_tag_url = None
|
||||
|
||||
git_tag_url = (f"https://github.com/tulir/mautrix-telegram/releases/tag/{git_tag}"
|
||||
if git_tag else None)
|
||||
|
||||
if git_tag and __version__ == git_tag[1:].replace("-", ""):
|
||||
version = __version__
|
||||
|
||||
@@ -215,6 +215,11 @@ class MatrixHandler(BaseMatrixHandler):
|
||||
event_id: EventID) -> None:
|
||||
await self.handle_kick_ban(False, room_id, user_id, kicked_by, reason, event_id)
|
||||
|
||||
async def handle_unban(self, room_id: RoomID, user_id: UserID, unbanned_by: UserID,
|
||||
reason: str, event_id: EventID) -> None:
|
||||
# TODO handle unbans properly instead of handling it as a kick
|
||||
await self.handle_kick_ban(False, room_id, user_id, unbanned_by, reason, event_id)
|
||||
|
||||
async def handle_ban(self, room_id: RoomID, user_id: UserID, banned_by: UserID, reason: str,
|
||||
event_id: EventID) -> None:
|
||||
await self.handle_kick_ban(True, room_id, user_id, banned_by, reason, event_id)
|
||||
|
||||
@@ -273,17 +273,13 @@ class BasePortal(ABC):
|
||||
authenticated.append(user)
|
||||
return authenticated
|
||||
|
||||
async def cleanup_room(self, intent: IntentAPI, room_id: RoomID,
|
||||
message: str = "Portal deleted", puppets_only: bool = False) -> None:
|
||||
@staticmethod
|
||||
async def cleanup_room(intent: IntentAPI, room_id: RoomID, message: str,
|
||||
puppets_only: bool = False) -> None:
|
||||
try:
|
||||
members = await intent.get_room_members(room_id)
|
||||
except MatrixRequestError:
|
||||
members = []
|
||||
if self.username:
|
||||
try:
|
||||
await intent.remove_room_alias(self.alias_localpart)
|
||||
except (MatrixRequestError, IntentError):
|
||||
self.log.warning("Failed to remove alias when cleaning up room", exc_info=True)
|
||||
for user in members:
|
||||
puppet = p.Puppet.get_by_mxid(UserID(user), create=False)
|
||||
if user != intent.mxid and (not puppets_only or puppet):
|
||||
@@ -299,12 +295,20 @@ class BasePortal(ABC):
|
||||
except (MatrixRequestError, IntentError):
|
||||
self.log.warning("Failed to leave room when cleaning up room", exc_info=True)
|
||||
|
||||
async def cleanup_portal(self, message: str, puppets_only: bool = False) -> None:
|
||||
if self.username:
|
||||
try:
|
||||
await self.main_intent.remove_room_alias(self.alias_localpart)
|
||||
except (MatrixRequestError, IntentError):
|
||||
self.log.warning("Failed to remove alias when cleaning up room", exc_info=True)
|
||||
await self.cleanup_room(self.main_intent, self.mxid, message, puppets_only)
|
||||
|
||||
async def unbridge(self) -> None:
|
||||
await self.cleanup_room(self.main_intent, self.mxid, "Room unbridged", puppets_only=True)
|
||||
await self.cleanup_portal("Room unbridged", puppets_only=True)
|
||||
self.delete()
|
||||
|
||||
async def cleanup_and_delete(self) -> None:
|
||||
await self.cleanup_room(self.main_intent, self.mxid)
|
||||
await self.cleanup_portal("Portal deleted")
|
||||
self.delete()
|
||||
|
||||
# endregion
|
||||
|
||||
@@ -258,6 +258,8 @@ class Puppet(CustomPuppetMixin):
|
||||
return False
|
||||
allow_source = (source.is_relaybot
|
||||
or self.displayname_source == source.tgid
|
||||
# User is not a contact, so there's no custom name
|
||||
or not info.contact
|
||||
# No displayname source, so just trust anything
|
||||
or self.displayname_source is None)
|
||||
if not allow_source:
|
||||
@@ -424,4 +426,8 @@ def init(context: 'Context') -> Iterable[Awaitable[Any]]:
|
||||
Puppet.displayname_template = SimpleTemplate(config["bridge.displayname_template"],
|
||||
"displayname")
|
||||
|
||||
secret = config["bridge.login_shared_secret"]
|
||||
Puppet.login_shared_secret = secret.encode("utf-8") if secret else None
|
||||
Puppet.login_device_name = "Telegram Bridge"
|
||||
|
||||
return (puppet.try_start() for puppet in Puppet.all_with_custom_mxid())
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -149,11 +149,9 @@ class ProvisioningAPI(AuthAPI):
|
||||
force = request.query.get("force", None)
|
||||
if force in ("delete", "unbridge"):
|
||||
delete = force == "delete"
|
||||
await portal.cleanup_room(portal.main_intent, portal.mxid, puppets_only=not delete,
|
||||
message=("Portal deleted (moving to another room)"
|
||||
if delete
|
||||
else "Room unbridged (portal moving to another "
|
||||
"room)"))
|
||||
await portal.cleanup_portal("Portal deleted (moving to another room)" if delete
|
||||
else "Room unbridged (portal moving to another room)",
|
||||
puppets_only=not delete)
|
||||
else:
|
||||
return self.get_error_response(409, "chat_already_bridged",
|
||||
"Telegram chat is already bridged to another "
|
||||
|
||||
Reference in New Issue
Block a user