From e81f3087924038ff23d7ee15e9b992631ea593d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20B=C3=BCchner?= Date: Wed, 18 Sep 2024 22:48:26 +0200 Subject: [PATCH] proxy support fixes --- synapse_invite_checker/invite_checker.py | 113 +++++++++++------------ 1 file changed, 54 insertions(+), 59 deletions(-) diff --git a/synapse_invite_checker/invite_checker.py b/synapse_invite_checker/invite_checker.py index 05228b7..32e3502 100644 --- a/synapse_invite_checker/invite_checker.py +++ b/synapse_invite_checker/invite_checker.py @@ -1,4 +1,4 @@ -import treq +import requests import json import time import os @@ -49,61 +49,45 @@ class InviteChecker: self.api.register_spam_checker_callbacks(user_may_invite=self.user_may_invite) logger.info("InviteChecker initialized") - @inlineCallbacks def fetch_json(self, url): logger.info(f"Fetching JSON data from: {url}") - # Fetch proxy from the environment variable - https_proxy = os.getenv('https_proxy') - headers = None # Initialize headers to None + # Read proxy configuration from the environment variable 'https_proxy', if set + https_proxy = os.getenv('https_proxy', None) + proxies = {} if https_proxy: - logger.info(f"Using HTTPS proxy: {https_proxy}") - - # Parse the proxy URL with optional username and password - if '@' in https_proxy: # Check if authentication info is present - credentials, proxy_hostport = https_proxy.split('@') - username, password = credentials.split(':') - proxy_host, proxy_port = proxy_hostport.split(':') - - # Create basic authentication header - auth_string = f'{username}:{password}' - auth_bytes = base64.b64encode(auth_string.encode('utf-8')).decode('utf-8') - headers = Headers({ - 'Proxy-Authorization': [f'Basic {auth_bytes}'] - }) + # Mask credentials in the proxy URL + if '@' in https_proxy: + masked_proxy = '****:****@' + https_proxy.split('@')[1] else: - headers = None - proxy_host, proxy_port = https_proxy.split(':') + masked_proxy = https_proxy - proxy_endpoint = TCP4ClientEndpoint(reactor, proxy_host, int(proxy_port)) - - # Create a ProxyAgent with authentication if needed - agent = ProxyAgent(proxy_endpoint) + proxies = { + "https": https_proxy + } + logger.info(f"Using HTTPS proxy: {masked_proxy}") else: - # If no proxy is set, use the default agent - agent = Agent(reactor) + logger.info("No proxy configured, making direct request") try: - # Pass headers to the request if authentication is required - if headers: - response = yield treq.get(url, agent=agent, headers=headers) - else: - response = yield treq.get(url, agent=agent) + # Make the request with the proxy if set, otherwise direct + response = requests.get(url, proxies=proxies, timeout=10) - if response.code == 200: - content = yield response.content() - data = json.loads(content.decode('utf-8')) + # Log the response status code + logger.info(f"Received response with status code: {response.status_code}") + + # Check for a successful response + if response.status_code == 200: + data = response.json() # Parse the JSON data logger.debug(f"Received JSON data: {data}") - returnValue(data) + return data else: - logger.error(f"Failed to fetch JSON data. Status code: {response.code}") - returnValue(None) + logger.error(f"Non-200 response code: {response.status_code}, Response body: {response.text}") + return None except Exception as e: - logger.error(f"Error while fetching JSON: {str(e)}") - returnValue(None) - - + logger.error(f"Error while fetching JSON: {str(e)} - {type(e).__name__}") + return None @inlineCallbacks def fetch_policy_room_banlist(self): @@ -153,17 +137,22 @@ class InviteChecker: """Fetch and update the blocklist, allowlist, and blocklisted room IDs.""" logger.info("Updating blocklist, allowlist, and room blocklist") - json_data = yield self.fetch_json(self.config.blocklist_allowlist_url) + json_data = self.fetch_json(self.config.blocklist_allowlist_url) if json_data: + logger.debug(f"Fetched JSON data: {json_data}") # Log the full JSON data for verification self.allow_all_invites_on_error = False self.use_allowlist = json_data.get('use_allowlist', True) self.use_blocklist = json_data.get('use_blocklist', True) self.blocklist = set(json_data.get('blocklist', [])) self.allowlist = set(json_data.get('allowlist', [])) + + logger.debug(f"Blocklist: {self.blocklist}") + logger.debug(f"Allowlist: {self.allowlist}") # Fetch and cache the policy room ban lists policy_banlist = yield self.fetch_policy_room_banlist() + logger.debug(f"Fetched policy banlist: {policy_banlist}") self.blocklist.update(policy_banlist) # Merge policy bans into blocklist self.blocklist_room_ids = set() @@ -233,24 +222,30 @@ class InviteChecker: logger.info(f"Allowing invite from {inviter} to {invitee} due to previous JSON fetch failure.") returnValue("NOT_SPAM") - blocklist, allowlist, blocklist_room_ids = yield self.get_blocklist_allowlist() - inviter_domain = UserID.from_string(inviter).domain + try: + blocklist, allowlist, blocklist_room_ids = yield self.get_blocklist_allowlist() + inviter_domain = UserID.from_string(inviter).domain - if self.use_allowlist and (inviter_domain in allowlist or inviter in allowlist): + logger.debug(f"Blocklist: {blocklist}, Allowlist: {allowlist}, Blocklist Room IDs: {blocklist_room_ids}") + + if self.use_allowlist and (inviter_domain in allowlist or inviter in allowlist): + returnValue("NOT_SPAM") + + if room_id in blocklist_room_ids: + logger.info(f"Invite blocked: room {room_id} is blocklisted") + yield self.send_message_to_room(f"Invite from {inviter} to {invitee} blocked in room {room_id}. Reason: Blocklisted room.") + returnValue(errors.Codes.FORBIDDEN) + + if self.use_blocklist and (inviter_domain in blocklist or inviter in blocklist): + logger.info(f"Invite blocked: {inviter} is blocklisted") + yield self.send_message_to_room(f"Invite from {inviter} to {invitee} blocked. Reason: Blocklisted.") + returnValue(errors.Codes.FORBIDDEN) + + logger.info(f"Invite allowed by {inviter} for {invitee} in room {room_id}") returnValue("NOT_SPAM") - - if room_id in blocklist_room_ids: - logger.info(f"Invite blocked: room {room_id} is blocklisted") - yield self.send_message_to_room(f"Invite from {inviter} to {invitee} blocked in room {room_id}. Reason: Blocklisted room.") - returnValue(errors.Codes.FORBIDDEN) - - if self.use_blocklist and (inviter_domain in blocklist or inviter in blocklist): - logger.info(f"Invite blocked: {inviter} is blocklisted") - yield self.send_message_to_room(f"Invite from {inviter} to {invitee} blocked. Reason: Blocklisted.") - returnValue(errors.Codes.FORBIDDEN) - - logger.info(f"Invite allowed by {inviter} for {invitee} in room {room_id}") - returnValue("NOT_SPAM") + except Exception as e: + logger.error(f"Error during invite check: {str(e)} - {type(e).__name__}") + returnValue("NOT_SPAM") # Fallback to allow the invite if an error occurs @inlineCallbacks def get_blocklist_allowlist(self):