From b0cfe7dd0af7b35d06bc8c78a1b790aaf7df3245 Mon Sep 17 00:00:00 2001 From: PC-Admin Date: Mon, 14 Aug 2023 22:32:38 +0800 Subject: [PATCH] add redlight alert bot, to send alerts to redlight client administrators --- redlight_bot.py | 38 ++++++++++++++++++++++++++++++++++++++ redlight_client_module.py | 29 ++++++++++++++++++++++++----- technical_spec.md | 2 ++ 3 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 redlight_bot.py diff --git a/redlight_bot.py b/redlight_bot.py new file mode 100644 index 0000000..4a1d6c8 --- /dev/null +++ b/redlight_bot.py @@ -0,0 +1,38 @@ +import logging +import requests + +# Setting up logging: +file_handler = logging.FileHandler('/var/log/matrix-synapse/redlight.log') +file_handler.setLevel(logging.INFO) +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +file_handler.setFormatter(formatter) + +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) +logger.addHandler(file_handler) + +# Prevent logger's messages from propagating to the root logger. +logger.propagate = False + +class RedlightBot: + def __init__(self, homeserver, access_token): + self.homeserver = homeserver + self.access_token = access_token + self.headers = { + "Authorization": f"Bearer {self.access_token}", + "Content-Type": "application/json" + } + + def send_alert_message(self, room_id, message): + endpoint = f"{self.homeserver}/_matrix/client/r0/rooms/{room_id}/send/m.room.message" + payload = { + "msgtype": "m.text", + "body": message + } + response = requests.post(endpoint, headers=self.headers, json=payload) + + # Check if the request was successful + if response.status_code == 200: + logger.info("Alert message sent successfully!") + else: + logger.info(f"Failed to send allert message. Status code: {response.status_code}, Response: {response.text}") diff --git a/redlight_client_module.py b/redlight_client_module.py index 9bec58c..624d371 100755 --- a/redlight_client_module.py +++ b/redlight_client_module.py @@ -1,6 +1,7 @@ import logging import hashlib import json +import asyncio from typing import Union from synapse.module_api import ModuleApi, NOT_SPAM from synapse.api.errors import AuthError @@ -11,6 +12,7 @@ from twisted.internet import reactor from twisted.internet import defer from twisted.web.iweb import IBodyProducer from zope.interface import implementer +from redlight_bot import RedlightBot # Setting up logging: file_handler = logging.FileHandler('/var/log/matrix-synapse/redlight.log') @@ -46,12 +48,23 @@ class _JsonProducer: class RedlightClientModule: def __init__(self, config: dict, api: ModuleApi): self._api = api - # URL where we'll check if the room/user combination is allowed. - self._redlight_url = config.get("redlight_url", "http://127.0.0.1:8008/_matrix/loj/v1/abuse_lookup") + # Your homeserver's URL + self._homeserver_url = "https://" + config.get("homeserver_url", "127.0.0.1:8008") + # The API token of your redlight bot user + self._redlight_bot_user = config.get("redlight_bot_token", "") + # The alert room your redlight bot will post too + self._redlight_alert_room = config.get("redlight_alert_room", "") + # Redlight server endpoint, where we'll check if the room/user combination is allowed. + self._redlight_endpoint = "https://" + config.get("redlight_server", "127.0.0.1:8008") + "/_matrix/loj/v1/abuse_lookup" self._agent = Agent(reactor) # Twisted agent for making HTTP requests. + # Create an instance of the RedlightBot + self.bot = RedlightBot(self._homeserver_url, self._redlight_bot_user) # Adjust the homeserver and token as required + logger.info("RedLightClientModule initialized.") - logger.info(f"Redlight Server URL set to: {self._redlight_url}") + logger.info(f"Redlight bot user token: {self._redlight_bot_user}") + logger.info(f"Redlight alert room: {self._redlight_alert_room}") + logger.info(f"Redlight server endpoint set to: {self._redlight_endpoint}") # Register the user_may_join_room function to be called by Synapse before a user joins a room. api.register_spam_checker_callbacks( @@ -84,7 +97,7 @@ class RedlightClientModule: # Make the HTTP request to our redlight server. response = await self._agent.request( b"PUT", - self._redlight_url.encode(), + self._redlight_endpoint.encode(), Headers({'Content-Type': [b'application/json']}), body ) @@ -105,7 +118,13 @@ class RedlightClientModule: # Handle the response based on its HTTP status code. if response.code == 200: logger.warn(f"User {user} not allowed to join room {room}.") - raise AuthError(403, "User not allowed to join this room.") + # Create the alert message + alert_message = f"WARNING: Incident detected! User {user} was attempting to access this restricted room: {room}" + # Start the synchronous send_alert_message method in a thread but don't await it + loop = asyncio.get_event_loop() + loop.run_in_executor(None, self.bot.send_alert_message, self._redlight_alert_room, alert_message) + # Throw a 403 error that the user will see + raise AuthError(403, "PERMISSION DENIED - This room violates server policy.") elif response.code == 204: logger.info(f"User {user} allowed to join room {room}.") return NOT_SPAM # Allow the user to join. diff --git a/technical_spec.md b/technical_spec.md index b983aec..9e1636a 100644 --- a/technical_spec.md +++ b/technical_spec.md @@ -117,4 +117,6 @@ More then 10 join requests in a minute might seem suspicious... (What about bots - What other methods (besides IP) could be used to restrict requests from redlight client homeservers? +API tokens, certificate-based authentication, or domain whitelisting? + - What other methods could be used to secure the source list and prevent interception/leaking?