basic wordlist message redaction
add file and image redaction update readme, version bump
This commit is contained in:
@@ -80,6 +80,18 @@ easy (or possible) to find. this subcommand (`!community roomid`) can be used to
|
|||||||
points to. with no argument passed, it will return the current room's ID, or you can pass it an alias (e.g. `!community
|
points to. with no argument passed, it will return the current room's ID, or you can pass it an alias (e.g. `!community
|
||||||
roomid #whatisthisroom:myserver.tld`).
|
roomid #whatisthisroom:myserver.tld`).
|
||||||
|
|
||||||
|
## message redaction
|
||||||
|
|
||||||
|
the bot can be configured to redact messages automatically to protect your users. set `censor` to either `true`,
|
||||||
|
`false`, or a list of room IDs to enable censorship in.
|
||||||
|
|
||||||
|
set `censor_files` to have the bot immediately redact file uploads in the censored rooms. define trigger words in
|
||||||
|
`censor_wordlist` to flag messages for automatic redaction.
|
||||||
|
|
||||||
|
please keep in mind that wordlist-based censorship is problematic and may redact false positives. writing a matching
|
||||||
|
algorithm that is perfect is impossible. consider configuring your community such that censorship need only be applied
|
||||||
|
in a limited subset of rooms.
|
||||||
|
|
||||||
# installation
|
# installation
|
||||||
|
|
||||||
install this like any other maubot plugin: zip the contents of this repo into a file and upload via the web interface,
|
install this like any other maubot plugin: zip the contents of this repo into a file and upload via the web interface,
|
||||||
|
|||||||
@@ -62,3 +62,19 @@ notification_room:
|
|||||||
# message to send to the notification room when someone joins one of the above rooms:
|
# message to send to the notification room when someone joins one of the above rooms:
|
||||||
join_notification_message: |
|
join_notification_message: |
|
||||||
User <code>{user}</code> has joined <code>{room}</code>.
|
User <code>{user}</code> has joined <code>{room}</code>.
|
||||||
|
|
||||||
|
# whether to censor files/messages
|
||||||
|
# can be boolean (true/false) for all-or-nothing behavior,
|
||||||
|
# or pass a list of room IDs to only censor certain rooms. this may be helpful
|
||||||
|
# if certain rooms are publicly facing while others are more trustworthy.
|
||||||
|
# this bot, bot admins and bot moderators are immune to censorship.
|
||||||
|
censor: false
|
||||||
|
|
||||||
|
# whether to redact file and image uploads. this will apply to all rooms defined
|
||||||
|
# in the censor variable (either boolean or a list of room IDs).
|
||||||
|
censor_files: true
|
||||||
|
|
||||||
|
# what words should trigger message redaction if censorship is enabled?
|
||||||
|
censor_wordlist:
|
||||||
|
- 'effword'
|
||||||
|
- 'essword'
|
||||||
|
|||||||
+41
-1
@@ -8,7 +8,7 @@ import re
|
|||||||
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,
|
||||||
MediaMessageEventContent, ReactionEvent, RedactionEvent, RoomID,
|
MediaMessageEventContent, ReactionEvent, RedactionEvent, RoomID,
|
||||||
RoomAlias, PowerLevelStateEventContent)
|
RoomAlias, PowerLevelStateEventContent, MessageType)
|
||||||
from mautrix.errors import MNotFound
|
from mautrix.errors import MNotFound
|
||||||
from mautrix.util.config import BaseProxyConfig, ConfigUpdateHelper
|
from mautrix.util.config import BaseProxyConfig, ConfigUpdateHelper
|
||||||
from maubot import Plugin, MessageEvent
|
from maubot import Plugin, MessageEvent
|
||||||
@@ -34,6 +34,9 @@ class Config(BaseProxyConfig):
|
|||||||
helper.copy("join_notification_message")
|
helper.copy("join_notification_message")
|
||||||
helper.copy_dict("greeting_rooms")
|
helper.copy_dict("greeting_rooms")
|
||||||
helper.copy_dict("greetings")
|
helper.copy_dict("greetings")
|
||||||
|
helper.copy("censor")
|
||||||
|
helper.copy("censor_wordlist")
|
||||||
|
helper.copy("censor_files")
|
||||||
|
|
||||||
|
|
||||||
class CommunityBot(Plugin):
|
class CommunityBot(Plugin):
|
||||||
@@ -112,6 +115,32 @@ class CommunityBot(Plugin):
|
|||||||
|
|
||||||
return report
|
return report
|
||||||
|
|
||||||
|
def flag_message(self, msg):
|
||||||
|
if msg.content.msgtype in [MessageType.FILE, MessageType.IMAGE]:
|
||||||
|
return self.config['censor_files']
|
||||||
|
|
||||||
|
for w in self.config['censor_wordlist']:
|
||||||
|
try:
|
||||||
|
if bool(re.search(w, msg.content.body, re.IGNORECASE)):
|
||||||
|
self.log.debug(f"DEBUG message flagged for censorship")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
self.log.error(f"Could not parse message for flagging: {e}")
|
||||||
|
|
||||||
|
def censor_room(self, msg):
|
||||||
|
if isinstance(self.config['censor'], bool):
|
||||||
|
self.log.debug(f"DEBUG message will be redacted because censoring is enabled")
|
||||||
|
return self.config['censor']
|
||||||
|
elif isinstance(self.config['censor'], list):
|
||||||
|
if msg.room_id in self.config['censor']:
|
||||||
|
self.log.debug(f"DEBUG message will be redacted because censoring is enabled for THIS room")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
@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:
|
||||||
@@ -141,6 +170,17 @@ class CommunityBot(Plugin):
|
|||||||
|
|
||||||
@event.on(EventType.ROOM_MESSAGE)
|
@event.on(EventType.ROOM_MESSAGE)
|
||||||
async def update_message_timestamp(self, evt: MessageEvent) -> None:
|
async def update_message_timestamp(self, evt: MessageEvent) -> None:
|
||||||
|
if self.flag_message(evt):
|
||||||
|
# do we need to redact?
|
||||||
|
if evt.sender not in self.config['admins'] and \
|
||||||
|
evt.sender not in self.config['moderators'] and \
|
||||||
|
evt.sender != self.client.mxid and \
|
||||||
|
self.censor_room(evt):
|
||||||
|
try:
|
||||||
|
await self.client.redact(evt.room_id, evt.event_id, reason="message flagged")
|
||||||
|
except Exception as e:
|
||||||
|
self.log.error(f"Flagged message could not be redacted: {e}")
|
||||||
|
|
||||||
if not self.config["track_messages"]:
|
if not self.config["track_messages"]:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
|||||||
+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.6
|
version: 0.1.7
|
||||||
license: MIT
|
license: MIT
|
||||||
modules:
|
modules:
|
||||||
- community
|
- community
|
||||||
|
|||||||
Reference in New Issue
Block a user