Add option to filter telegram chats from being bridged. Fixes #41
This commit is contained in:
+9
-1
@@ -109,13 +109,21 @@ bridge:
|
||||
public_portals: true
|
||||
# Whether to send stickers as the new native m.sticker type or normal m.images.
|
||||
# Old versions of Riot don't support the new type at all.
|
||||
#
|
||||
# Remember that proper sticker support always requires Pillow to convert webp into png.
|
||||
native_stickers: true
|
||||
# Whether or not to fetch and handle Telegram updates at startup from the time the bridge was down.
|
||||
# WARNING: Probably buggy, might get stuck in infinite loop.
|
||||
catch_up: false
|
||||
|
||||
filter:
|
||||
# Filter mode to use. Either "blacklist" or "whitelist".
|
||||
# If the mode is "blacklist", the listed chats will never be bridged. An empty blacklist disables the filter.
|
||||
# If the mode is "whitelist", only the listed chats can be bridged.
|
||||
# Direct chats are not affected.
|
||||
mode: blacklist
|
||||
# The list of group/channel IDs to filter.
|
||||
list: []
|
||||
|
||||
# The prefix for commands. Only required in non-management rooms.
|
||||
command_prefix: "!tg"
|
||||
|
||||
|
||||
@@ -145,6 +145,9 @@ class Bot(AbstractUser):
|
||||
if not config["bridge.relaybot.authless_portals"]:
|
||||
return await reply("This bridge doesn't allow portal creation from Telegram.")
|
||||
|
||||
if not portal.allow_bridging():
|
||||
return await reply("This bridge doesn't allow bridging this chat.")
|
||||
|
||||
await portal.create_matrix_room(self)
|
||||
if portal.mxid:
|
||||
if portal.username:
|
||||
|
||||
@@ -80,5 +80,9 @@ def help(evt):
|
||||
**group-name** <_name_|`-`> - Change the username of a supergroup/channel. To disable, use a dash
|
||||
(`-`) as the name.
|
||||
**clean-rooms** - Clean up unused portal/management rooms.
|
||||
|
||||
**filter** <`whitelist`|`blacklist`> <_chat ID_> - Allow or disallow bridging
|
||||
**filter-mode** <`whitelist`|`blacklist`> - Change whether the bridge will allow or disallow
|
||||
bridging rooms by default.
|
||||
"""
|
||||
return evt.reply(management_status + help)
|
||||
|
||||
@@ -161,6 +161,10 @@ async def bridge(evt: CommandEvent):
|
||||
"Bridging private chats to existing rooms is not allowed.")
|
||||
|
||||
portal = po.Portal.get_by_tgid(tgid, peer_type=peer_type)
|
||||
if not portal.allow_bridging():
|
||||
return await evt.reply("This bridge doesn't allow bridging that Telegram chat.\n"
|
||||
"If you're the bridge admin, try"
|
||||
"`$cmdprefix+sp whitelist <Telegram chat ID>` first.")
|
||||
if portal.mxid:
|
||||
has_portal_message = (
|
||||
"That Telegram chat already has a portal at "
|
||||
@@ -353,3 +357,70 @@ async def group_name(evt: CommandEvent):
|
||||
return await evt.reply("That username is already in use.")
|
||||
except UsernameInvalidError:
|
||||
return await evt.reply("Invalid username")
|
||||
|
||||
|
||||
@command_handler(needs_admin=True)
|
||||
async def filter_mode(evt: CommandEvent):
|
||||
try:
|
||||
mode = evt.args[0]
|
||||
if mode not in ("whitelist", "blacklist"):
|
||||
raise ValueError()
|
||||
except (IndexError, ValueError):
|
||||
return await evt.reply("**Usage:** `$cmdprefix+sp filter-mode <whitelist/blacklist>`")
|
||||
|
||||
evt.config["bridge.filter.mode"] = mode
|
||||
evt.config.save()
|
||||
po.Portal.filter_mode = mode
|
||||
if mode == "whitelist":
|
||||
return await evt.reply("The bridge will now disallow bridging chats by default.\n"
|
||||
"To allow bridging a specific chat, use"
|
||||
"`!filter whitelist <chat ID>`.")
|
||||
else:
|
||||
return await evt.reply("The bridge will now allow bridging chats by default.\n"
|
||||
"To disallow bridging a specific chat, use"
|
||||
"`!filter blacklist <chat ID>`.")
|
||||
|
||||
|
||||
@command_handler(needs_admin=True)
|
||||
async def filter(evt: CommandEvent):
|
||||
try:
|
||||
action = evt.args[0]
|
||||
if action not in ("whitelist", "blacklist", "add", "remove"):
|
||||
raise ValueError()
|
||||
|
||||
id = evt.args[1]
|
||||
if id.startswith("-100"):
|
||||
id = int(id[4:])
|
||||
elif id.startswith("-"):
|
||||
id = int(id[1:])
|
||||
else:
|
||||
id = int(id)
|
||||
except (IndexError, ValueError):
|
||||
return await evt.reply("**Usage:** `$cmdprefix+sp filter <whitelist/blacklist> <chat ID>`")
|
||||
|
||||
mode = evt.config["bridge.filter.mode"]
|
||||
if mode not in ("blacklist", "whitelist"):
|
||||
return await evt.reply(f"Unknown filter mode \"{mode}\". Please fix the bridge config.")
|
||||
|
||||
list = evt.config["bridge.filter.list"]
|
||||
|
||||
if action in ("blacklist", "whitelist"):
|
||||
action = "add" if mode == action else "remove"
|
||||
|
||||
def save():
|
||||
evt.config["bridge.filter.list"] = list
|
||||
evt.config.save()
|
||||
po.Portal.filter_list = list
|
||||
|
||||
if action == "add":
|
||||
if id in list:
|
||||
return await evt.reply(f"That chat is already {mode}ed.")
|
||||
list.append(id)
|
||||
save()
|
||||
return await evt.reply(f"Chat ID added to {mode}.")
|
||||
elif action == "remove":
|
||||
if id not in list:
|
||||
return await evt.reply(f"That chat is not {mode}ed.")
|
||||
list.remove(id)
|
||||
save()
|
||||
return await evt.reply(f"Chat ID removed from {mode}.")
|
||||
|
||||
@@ -181,6 +181,9 @@ class Config(DictWithRecursion):
|
||||
copy("bridge.native_stickers")
|
||||
copy("bridge.catch_up")
|
||||
|
||||
copy("bridge.filter.mode")
|
||||
copy("bridge.filter.list")
|
||||
|
||||
copy("bridge.command_prefix")
|
||||
|
||||
migrate_permissions = ("bridge.permissions" not in self
|
||||
|
||||
@@ -48,6 +48,8 @@ class Portal:
|
||||
az = None
|
||||
bot = None
|
||||
loop = None
|
||||
filter_mode = None
|
||||
filter_list = None
|
||||
bridge_notices = False
|
||||
alias_template = None
|
||||
mx_alias_regex = None
|
||||
@@ -117,6 +119,26 @@ class Portal:
|
||||
self._main_intent = puppet.intent if direct else self.az.intent
|
||||
return self._main_intent
|
||||
|
||||
# endregion
|
||||
# region Filtering
|
||||
|
||||
def allow_bridging(self, tgid=None):
|
||||
tgid = tgid or self.tgid
|
||||
if self.peer_type == "user":
|
||||
self.log.debug(f"!!!!!!!!!!!!!!!!!!!!!!!!!!!! allow_bridging(User {tgid}) -> True")
|
||||
return True
|
||||
elif self.filter_mode == "whitelist":
|
||||
self.log.debug(
|
||||
f"!!!!!!!!!!!!!!!!!!!!!!!!!!!! allow_bridging(Chat {tgid}) -> {tgid in self.filter_list} (whitelist={self.filter_list})")
|
||||
return tgid in self.filter_list
|
||||
elif self.filter_mode == "blacklist":
|
||||
self.log.debug(
|
||||
f"!!!!!!!!!!!!!!!!!!!!!!!!!!!! allow_bridging(Chat {tgid}) -> {tgid not in self.filter_list} (blacklist={self.filter_list})")
|
||||
return tgid not in self.filter_list
|
||||
else:
|
||||
self.log.debug("!!!!!!!!!!!!!!??????????????? Unknown filter mode", self.filter_mode)
|
||||
return True
|
||||
|
||||
# endregion
|
||||
# region Deduplication
|
||||
|
||||
@@ -233,6 +255,9 @@ class Portal:
|
||||
if self.mxid:
|
||||
return self.mxid
|
||||
|
||||
if not self.allow_bridging():
|
||||
return None
|
||||
|
||||
if not entity:
|
||||
entity = await user.client.get_entity(self.peer)
|
||||
self.log.debug("Fetched data: %s", entity)
|
||||
@@ -336,6 +361,10 @@ class Portal:
|
||||
await puppet.intent.ensure_joined(self.mxid)
|
||||
await puppet.update_info(source, entity)
|
||||
|
||||
user = u.User.get_by_tgid(entity.id)
|
||||
if user:
|
||||
await self.invite_to_matrix(user.mxid)
|
||||
|
||||
# We can't trust the member list if any of the following cases is true:
|
||||
# * There are close to 10 000 users, because Telegram might not be sending all members.
|
||||
# * The member sync count is limited, because then we might ignore some members.
|
||||
@@ -371,7 +400,7 @@ class Portal:
|
||||
user = u.User.get_by_tgid(user_id)
|
||||
if user:
|
||||
user.register_portal(self)
|
||||
await self.main_intent.invite(self.mxid, user.mxid)
|
||||
await self.invite_to_matrix(user.mxid)
|
||||
|
||||
async def delete_telegram_user(self, user_id, sender):
|
||||
puppet = p.Puppet.get(user_id)
|
||||
@@ -1592,7 +1621,9 @@ def init(context):
|
||||
global config
|
||||
Portal.az, Portal.db, config, Portal.loop, Portal.bot = context
|
||||
Portal.bridge_notices = config["bridge.bridge_notices"]
|
||||
Portal.filter_mode = config["bridge.filter.mode"]
|
||||
Portal.filter_list = config["bridge.filter.list"]
|
||||
Portal.alias_template = config.get("bridge.alias_template", "telegram_{groupname}")
|
||||
Portal.hs_domain = config["homeserver"]["domain"]
|
||||
Portal.hs_domain = config["homeserver.domain"]
|
||||
localpart = Portal.alias_template.format(groupname="(.+)")
|
||||
Portal.mx_alias_regex = re.compile(f"#{localpart}:{Portal.hs_domain}")
|
||||
|
||||
Reference in New Issue
Block a user