diff --git a/example-config.yaml b/example-config.yaml index 9c32844a..82077df0 100644 --- a/example-config.yaml +++ b/example-config.yaml @@ -177,8 +177,9 @@ bridge: # Permissions for using the bridge. # Permitted values: # relaybot - Only use the bridge via the relaybot, no access to commands. - # user - Relaybot level + access to commands to create bridges (no puppeting) - # full - Full access to use the bridge via relaybot or logging in with Telegram account. + # user - Relaybot level + access to commands to create bridges. + # puppeting - User level + logging in with a Telegram account. + # full - Full access to use the bridge, i.e. previous levels + Matrix login. # admin - Full access to use the bridge and some extra administration commands. # Permitted keys: # * - All Matrix users diff --git a/mautrix_telegram/abstract_user.py b/mautrix_telegram/abstract_user.py index 249a8d77..f1a72db4 100644 --- a/mautrix_telegram/abstract_user.py +++ b/mautrix_telegram/abstract_user.py @@ -61,10 +61,11 @@ class AbstractUser(ABC): ignore_incoming_bot_events = True # type: bool def __init__(self): + self.is_admin = False # type: bool + self.matrix_puppet_whitelisted = False # type: bool self.puppet_whitelisted = False # type: bool self.whitelisted = False # type: bool self.relaybot_whitelisted = False # type: bool - self.is_admin = False # type: bool self.client = None # type: MautrixTelegramClient self.tgid = None # type: int self.mxid = None # type: str diff --git a/mautrix_telegram/commands/auth.py b/mautrix_telegram/commands/auth.py index 9d52ab0d..38b1fbe2 100644 --- a/mautrix_telegram/commands/auth.py +++ b/mautrix_telegram/commands/auth.py @@ -49,7 +49,7 @@ async def ping_bot(evt: CommandEvent): "To use the bot, simply invite it to a portal room.") -@command_handler(needs_auth=True, +@command_handler(needs_auth=True, needs_matrix_puppeting=True, help_section=SECTION_AUTH, help_text="Revert your Telegram account's Matrix puppet to use the default Matrix " "account.") @@ -61,7 +61,7 @@ async def logout_matrix(evt: CommandEvent): await evt.reply("Reverted your Telegram account's Matrix puppet back to the default.") -@command_handler(needs_auth=True, management_only=True, +@command_handler(needs_auth=True, management_only=True, needs_matrix_puppeting=True, help_section=SECTION_AUTH, help_text="Replace your Telegram account's Matrix puppet with your own Matrix " "account") diff --git a/mautrix_telegram/commands/handler.py b/mautrix_telegram/commands/handler.py index 53a71a4b..c7d2b1c2 100644 --- a/mautrix_telegram/commands/handler.py +++ b/mautrix_telegram/commands/handler.py @@ -66,12 +66,14 @@ class CommandEvent: class CommandHandler: - def __init__(self, handler: Callable[[CommandEvent], None], - needs_auth: bool, needs_puppeting: bool, needs_admin: bool, management_only: bool, - name: str, help_text: str, help_args: str, help_section: HelpSection): + def __init__(self, handler: Callable[[CommandEvent], None], needs_auth: bool, + needs_puppeting: bool, needs_matrix_puppeting: bool, needs_admin: bool, + management_only: bool, name: str, help_text: str, help_args: str, + help_section: HelpSection): self._handler = handler self.needs_auth = needs_auth self.needs_puppeting = needs_puppeting + self.needs_matrix_puppeting = needs_matrix_puppeting self.needs_admin = needs_admin self.management_only = management_only self.name = name @@ -85,16 +87,19 @@ class CommandHandler: "you may only run it in management rooms.") elif self.needs_puppeting and not evt.sender.puppet_whitelisted: return "This command requires puppeting privileges." + elif self.needs_matrix_puppeting and not evt.sender.matrix_puppet_whitelisted: + return "This command requires Matrix puppeting privileges." elif self.needs_admin and not evt.sender.is_admin: return "This command requires administrator privileges." elif self.needs_auth and not await evt.sender.is_logged_in(): return "This command requires you to be logged in." return None - def has_permission(self, is_management: bool, puppet_whitelisted: bool, is_admin: bool, - is_logged_in: bool) -> bool: + def has_permission(self, is_management: bool, puppet_whitelisted: bool, + matrix_puppet_whitelisted: bool, is_admin: bool, is_logged_in: bool) -> bool: return ((not self.management_only or is_management) and (not self.needs_puppeting or puppet_whitelisted) and + (not self.needs_matrix_puppeting or matrix_puppet_whitelisted) and (not self.needs_admin or is_admin) and (not self.needs_auth or is_logged_in)) @@ -114,14 +119,16 @@ class CommandHandler: def command_handler(_func: Optional[Callable[[CommandEvent], None]] = None, *, needs_auth=True, - needs_puppeting=True, needs_admin=False, management_only=False, - name=None, help_text="", help_args="", help_section=None): + needs_puppeting=True, needs_matrix_puppeting=False, needs_admin=False, + management_only=False, name=None, help_text="", help_args="", + help_section=None): input_name = name def decorator(func: Callable[[CommandEvent], None]): name = input_name or func.__name__.replace("_", "-") - handler = CommandHandler(func, needs_auth, needs_puppeting, needs_admin, management_only, - name, help_text, help_args, help_section) + handler = CommandHandler(func, needs_auth, needs_puppeting, needs_matrix_puppeting, + needs_admin, management_only, name, help_text, help_args, + help_section) command_handlers[handler.name] = handler return handler diff --git a/mautrix_telegram/commands/meta.py b/mautrix_telegram/commands/meta.py index a3d36a4b..f50a83e0 100644 --- a/mautrix_telegram/commands/meta.py +++ b/mautrix_telegram/commands/meta.py @@ -38,7 +38,8 @@ help_cache = {} async def _get_help_text(evt: CommandEvent): - cache_key = (evt.is_management, evt.sender.puppet_whitelisted, evt.sender.is_admin, + cache_key = (evt.is_management, evt.sender.puppet_whitelisted, + evt.sender.matrix_puppet_whitelisted, evt.sender.is_admin, await evt.sender.is_logged_in()) if cache_key not in help_cache: help = {} diff --git a/mautrix_telegram/config.py b/mautrix_telegram/config.py index 8a68b2f8..49573784 100644 --- a/mautrix_telegram/config.py +++ b/mautrix_telegram/config.py @@ -248,15 +248,16 @@ class Config(DictWithRecursion): self._data = base._data self.save() - def _get_permissions(self, key: str) -> Tuple[bool, bool, bool, bool, bool]: + def _get_permissions(self, key: str) -> Tuple[bool, bool, bool, bool, bool, bool]: level = self["bridge.permissions"].get(key, "") admin = level == "admin" - puppeting = level == "full" or admin + matrix_puppeting = level == "full" or admin + puppeting = level == "puppeting" or matrix_puppeting user = level == "user" or puppeting relaybot = level == "relaybot" or user - return relaybot, user, puppeting, admin, level + return relaybot, user, puppeting, matrix_puppeting, admin, level - def get_permissions(self, mxid: str) -> Tuple[bool, bool, bool, bool, bool]: + def get_permissions(self, mxid: str) -> Tuple[bool, bool, bool, bool, bool, bool]: permissions = self["bridge.permissions"] or {} if mxid in permissions: return self._get_permissions(mxid) diff --git a/mautrix_telegram/user.py b/mautrix_telegram/user.py index c2bdf780..e42e1071 100644 --- a/mautrix_telegram/user.py +++ b/mautrix_telegram/user.py @@ -65,6 +65,7 @@ class User(AbstractUser): (self.relaybot_whitelisted, self.whitelisted, self.puppet_whitelisted, + self.matrix_puppet_whitelisted, self.is_admin, self.permissions) = config.get_permissions(self.mxid)