subscribe to public ban lists!
This commit is contained in:
@@ -82,3 +82,10 @@ censor_files: true
|
|||||||
censor_wordlist:
|
censor_wordlist:
|
||||||
- 'effword'
|
- 'effword'
|
||||||
- 'essword'
|
- 'essword'
|
||||||
|
|
||||||
|
# list of banlists that should be subscribed to, such as #community-moderation-effort-bl:neko.dev
|
||||||
|
# when users join any room managed by this bot, they are compared against these existing banlists
|
||||||
|
# if found, they will immediately be banned.
|
||||||
|
# your bot MUST be in the banlist room already!
|
||||||
|
banlists:
|
||||||
|
- '#community-moderation-effort-bl:neko.dev'
|
||||||
|
|||||||
+99
-32
@@ -4,6 +4,7 @@ from typing import Awaitable, Type, Optional, Tuple
|
|||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
import re
|
import re
|
||||||
|
import fnmatch
|
||||||
|
|
||||||
from mautrix.client import Client, InternalEventType, MembershipEventDispatcher, SyncStream
|
from mautrix.client import Client, InternalEventType, MembershipEventDispatcher, SyncStream
|
||||||
from mautrix.types import (Event, StateEvent, EventID, UserID, FileInfo, EventType,
|
from mautrix.types import (Event, StateEvent, EventID, UserID, FileInfo, EventType,
|
||||||
@@ -38,6 +39,7 @@ class Config(BaseProxyConfig):
|
|||||||
helper.copy("censor")
|
helper.copy("censor")
|
||||||
helper.copy("censor_wordlist")
|
helper.copy("censor_wordlist")
|
||||||
helper.copy("censor_files")
|
helper.copy("censor_files")
|
||||||
|
helper.copy("banlists")
|
||||||
|
|
||||||
|
|
||||||
class CommunityBot(Plugin):
|
class CommunityBot(Plugin):
|
||||||
@@ -126,7 +128,7 @@ class CommunityBot(Plugin):
|
|||||||
for w in self.config['censor_wordlist']:
|
for w in self.config['censor_wordlist']:
|
||||||
try:
|
try:
|
||||||
if bool(re.search(w, msg.content.body, re.IGNORECASE)):
|
if bool(re.search(w, msg.content.body, re.IGNORECASE)):
|
||||||
self.log.debug(f"DEBUG message flagged for censorship")
|
#self.log.debug(f"DEBUG message flagged for censorship")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
@@ -135,21 +137,105 @@ class CommunityBot(Plugin):
|
|||||||
|
|
||||||
def censor_room(self, msg):
|
def censor_room(self, msg):
|
||||||
if isinstance(self.config['censor'], bool):
|
if isinstance(self.config['censor'], bool):
|
||||||
self.log.debug(f"DEBUG message will be redacted because censoring is enabled")
|
#self.log.debug(f"DEBUG message will be redacted because censoring is enabled")
|
||||||
return self.config['censor']
|
return self.config['censor']
|
||||||
elif isinstance(self.config['censor'], list):
|
elif isinstance(self.config['censor'], list):
|
||||||
if msg.room_id in self.config['censor']:
|
if msg.room_id in self.config['censor']:
|
||||||
self.log.debug(f"DEBUG message will be redacted because censoring is enabled for THIS room")
|
#self.log.debug(f"DEBUG message will be redacted because censoring is enabled for THIS room")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
async def check_if_banned(self, userid):
|
||||||
|
# fetch banlist data
|
||||||
|
is_banned = False
|
||||||
|
myrooms = await self.client.get_joined_rooms()
|
||||||
|
for l in self.config['banlists']:
|
||||||
|
#self.log.debug(f"DEBUG getting banlist {l}")
|
||||||
|
if l.startswith('#'):
|
||||||
|
try:
|
||||||
|
l_id = await self.client.resolve_room_alias(l)
|
||||||
|
list_id = l_id["room_id"]
|
||||||
|
#self.log.debug(f"DEBUG banlist id resolves to: {list_id}")
|
||||||
|
except:
|
||||||
|
evt.reply("i don't recognize that list, sorry")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
list_id = l
|
||||||
|
|
||||||
|
if list_id not in myrooms:
|
||||||
|
self.log.error(f"Bot must be in {l} before attempting to use it as a banlist.")
|
||||||
|
pass
|
||||||
|
|
||||||
|
#self.log.debug(f"DEBUG looking up state in {list_id}")
|
||||||
|
list_state = await self.client.get_state(list_id)
|
||||||
|
#self.log.debug(f"DEBUG state found: {list_state}")
|
||||||
|
try:
|
||||||
|
user_policies = list(filter(lambda p : p.type.t=='m.policy.rule.user', list_state))
|
||||||
|
#self.log.debug(f"DEBUG user policies found: {user_policies}")
|
||||||
|
except Exception as e:
|
||||||
|
self.log.error(e)
|
||||||
|
|
||||||
|
for rule in user_policies:
|
||||||
|
#self.log.debug(f"Checking match of user {userid} in banlist {l} for {rule['content']}")
|
||||||
|
try:
|
||||||
|
if bool(fnmatch.fnmatch(userid, rule["content"]["entity"])) and \
|
||||||
|
bool(re.search('ban$', rule["content"]["recommendation"])):
|
||||||
|
#self.log.debug(f"DEBUG user {userid} matches ban rule {rule['content']['entity']}!")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
self.log.error(f"Found something funny in the banlist {l} for {rule['content']}: {e}")
|
||||||
|
pass
|
||||||
|
# if we haven't exited by now, we must not be banned!
|
||||||
|
return is_banned
|
||||||
|
|
||||||
|
async def ban_this_user(self, user):
|
||||||
|
#self.log.debug(f"DEBUG getting list of rooms")
|
||||||
|
roomlist = await self.get_space_roomlist()
|
||||||
|
# don't forget to kick from the space itself
|
||||||
|
roomlist.append(self.config["parent_room"])
|
||||||
|
#self.log.debug(f"DEBUG list of rooms acquired")
|
||||||
|
ban_event_map = {'ban_list':{}, 'error_list':{}}
|
||||||
|
|
||||||
|
ban_event_map['ban_list'][user] = []
|
||||||
|
#self.log.debug(f"DEBUG banning {user} from rooms...")
|
||||||
|
for room in roomlist:
|
||||||
|
try:
|
||||||
|
roomname = None
|
||||||
|
roomnamestate = await self.client.get_state_event(room, 'm.room.name')
|
||||||
|
roomname = roomnamestate['name']
|
||||||
|
|
||||||
|
# ban user even if they're not in the room!
|
||||||
|
#await self.client.get_state_event(room, EventType.ROOM_MEMBER, user)
|
||||||
|
await self.client.ban_user(room, user, reason='banned')
|
||||||
|
if roomname:
|
||||||
|
ban_event_map['ban_list'][user].append(roomname)
|
||||||
|
else:
|
||||||
|
ban_event_map['ban_list'][user].append(room)
|
||||||
|
time.sleep(0.5)
|
||||||
|
except MNotFound:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
self.log.warning(e)
|
||||||
|
ban_event_map['error_list'][user] = []
|
||||||
|
ban_event_map['error_list'][user].append(roomname or room)
|
||||||
|
|
||||||
|
return ban_event_map
|
||||||
|
|
||||||
|
|
||||||
@event.on(InternalEventType.JOIN)
|
@event.on(InternalEventType.JOIN)
|
||||||
async def newjoin(self, evt:StateEvent) -> None:
|
async def newjoin(self, evt:StateEvent) -> None:
|
||||||
if evt.source & SyncStream.STATE:
|
if evt.source & SyncStream.STATE:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
on_banlist = await self.check_if_banned(evt.sender)
|
||||||
|
if on_banlist:
|
||||||
|
#self.log.debug(f"DEBUG user is on banlist!")
|
||||||
|
# ban this account in managed rooms, don't bother with anything else
|
||||||
|
await self.ban_this_user(evt.sender)
|
||||||
|
return
|
||||||
# passive sync of tracking db
|
# passive sync of tracking db
|
||||||
if evt.room_id == self.config['parent_room']:
|
if evt.room_id == self.config['parent_room']:
|
||||||
await self.do_sync()
|
await self.do_sync()
|
||||||
@@ -213,6 +299,12 @@ class CommunityBot(Plugin):
|
|||||||
async def community(self) -> None:
|
async def community(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@community.subcommand("bancheck", help="check subscribed banlists for a user's mxid")
|
||||||
|
@command.argument("mxid", "full matrix ID", required=True)
|
||||||
|
async def check_banlists(self, evt: MessageEvent, mxid: UserID) -> None:
|
||||||
|
ban_status = await self.check_if_banned(mxid)
|
||||||
|
await evt.reply(f"user on banlist: {ban_status}")
|
||||||
|
|
||||||
|
|
||||||
@community.subcommand("sync", help="update the activity tracker with the current space members \
|
@community.subcommand("sync", help="update the activity tracker with the current space members \
|
||||||
in case they are missing")
|
in case they are missing")
|
||||||
@@ -388,37 +480,12 @@ class CommunityBot(Plugin):
|
|||||||
if evt.sender in self.config["admins"]:
|
if evt.sender in self.config["admins"]:
|
||||||
user = mxid
|
user = mxid
|
||||||
msg = await evt.respond("starting the ban...")
|
msg = await evt.respond("starting the ban...")
|
||||||
roomlist = await self.get_space_roomlist()
|
results_map = await self.ban_this_user(user)
|
||||||
# don't forget to kick from the space itself
|
|
||||||
roomlist.append(self.config["parent_room"])
|
|
||||||
ban_list = {}
|
|
||||||
error_list = {}
|
|
||||||
|
|
||||||
ban_list[user] = []
|
|
||||||
for room in roomlist:
|
|
||||||
try:
|
|
||||||
roomname = None
|
|
||||||
roomnamestate = await self.client.get_state_event(room, 'm.room.name')
|
|
||||||
roomname = roomnamestate['name']
|
|
||||||
|
|
||||||
# ban user even if they're not in the room!
|
|
||||||
#await self.client.get_state_event(room, EventType.ROOM_MEMBER, user)
|
|
||||||
await self.client.ban_user(room, user, reason='banned')
|
|
||||||
if roomname:
|
|
||||||
ban_list[user].append(roomname)
|
|
||||||
else:
|
|
||||||
ban_list[user].append(room)
|
|
||||||
time.sleep(0.5)
|
|
||||||
except MNotFound:
|
|
||||||
pass
|
|
||||||
except Exception as e:
|
|
||||||
self.log.warning(e)
|
|
||||||
error_list[user] = []
|
|
||||||
error_list[user].append(roomname or room)
|
|
||||||
|
|
||||||
|
|
||||||
results = "the following users were kicked and banned:<p><code>{ban_list}</code></p>the following errors were \
|
results = "the following users were kicked and banned:<p><code>{ban_list}</code></p>the following errors were \
|
||||||
recorded:<p><code>{error_list}</code></p>".format(ban_list=ban_list, error_list=error_list)
|
recorded:<p><code>{error_list}</code></p>".format(ban_list=results_map['ban_list'],
|
||||||
|
error_list=results_map['error_list'])
|
||||||
await evt.respond(results, allow_html=True, edits=msg)
|
await evt.respond(results, allow_html=True, edits=msg)
|
||||||
|
|
||||||
# sync our database after we've made changes to room memberships
|
# sync our database after we've made changes to room memberships
|
||||||
@@ -641,7 +708,7 @@ class CommunityBot(Plugin):
|
|||||||
new_pl = current_pl
|
new_pl = current_pl
|
||||||
new_pl['users'] = updated_user_map
|
new_pl['users'] = updated_user_map
|
||||||
try:
|
try:
|
||||||
self.log.debug(f"DEBUG sending finalized PL map to room {room}: {updated_user_map}")
|
#self.log.debug(f"DEBUG sending finalized PL map to room {room}: {updated_user_map}")
|
||||||
await self.client.send_state_event(room, 'm.room.power_levels', new_pl)
|
await self.client.send_state_event(room, 'm.room.power_levels', new_pl)
|
||||||
success_list.append(roomname or room)
|
success_list.append(roomname or room)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
maubot: 0.1.0
|
maubot: 0.1.0
|
||||||
id: org.jobmachine.communitybot
|
id: org.jobmachine.communitybot
|
||||||
version: 0.1.8
|
version: 0.1.9
|
||||||
license: MIT
|
license: MIT
|
||||||
modules:
|
modules:
|
||||||
- community
|
- community
|
||||||
|
|||||||
Reference in New Issue
Block a user