diff --git a/daemon.py b/daemon.py index b1158834d..9f495bdb3 100644 --- a/daemon.py +++ b/daemon.py @@ -65,8 +65,8 @@ from utils import get_full_domain from utils import set_config_param from utils import get_config_param from utils import load_json -from utils import load_mitm_servers from utils import load_instance_software +from mitm import load_mitm_servers from content import load_auto_cw_cache from content import load_dogwhistles from theme import scan_themes_for_scripts diff --git a/daemon_get.py b/daemon_get.py index 88d58eda8..4ae1ad76c 100644 --- a/daemon_get.py +++ b/daemon_get.py @@ -114,7 +114,7 @@ from utils import get_nickname_from_actor from utils import get_json_content_from_accept from utils import check_bad_path from utils import decoded_host -from utils import detect_mitm +from mitm import detect_mitm from person import get_person_notes_endpoint from person import get_account_pub_key from shares import actor_attached_shares diff --git a/daemon_get_buttons_announce.py b/daemon_get_buttons_announce.py index a85d8aa21..6a19a04f4 100644 --- a/daemon_get_buttons_announce.py +++ b/daemon_get_buttons_announce.py @@ -18,7 +18,7 @@ from utils import remove_id_ending from utils import local_actor_url from utils import get_nickname_from_actor from utils import get_instance_url -from utils import detect_mitm +from mitm import detect_mitm from httpheaders import redirect_headers from session import establish_session from httpcodes import http_404 diff --git a/daemon_get_buttons_bookmark.py b/daemon_get_buttons_bookmark.py index 6a1195bdd..037dc0903 100644 --- a/daemon_get_buttons_bookmark.py +++ b/daemon_get_buttons_bookmark.py @@ -17,7 +17,7 @@ from utils import is_dm from utils import get_nickname_from_actor from utils import get_instance_url from utils import local_actor_url -from utils import detect_mitm +from mitm import detect_mitm from session import establish_session from httpheaders import redirect_headers from httpcodes import http_404 diff --git a/daemon_get_buttons_like.py b/daemon_get_buttons_like.py index a6afe9c29..67586b0c5 100644 --- a/daemon_get_buttons_like.py +++ b/daemon_get_buttons_like.py @@ -18,7 +18,7 @@ from utils import locate_post from utils import local_actor_url from utils import get_nickname_from_actor from utils import get_instance_url -from utils import detect_mitm +from mitm import detect_mitm from daemon_utils import post_to_outbox from follow import follower_approval_active from httpheaders import redirect_headers diff --git a/daemon_get_buttons_mute.py b/daemon_get_buttons_mute.py index 6dc807bfe..4f1986503 100644 --- a/daemon_get_buttons_mute.py +++ b/daemon_get_buttons_mute.py @@ -15,7 +15,7 @@ from utils import get_cached_post_filename from utils import load_json from utils import locate_post from utils import get_nickname_from_actor -from utils import detect_mitm +from mitm import detect_mitm from httpcodes import http_404 from httpheaders import redirect_headers from blocking import unmute_post diff --git a/daemon_get_buttons_reaction.py b/daemon_get_buttons_reaction.py index ce28e1dd8..87eb6259b 100644 --- a/daemon_get_buttons_reaction.py +++ b/daemon_get_buttons_reaction.py @@ -19,7 +19,7 @@ from utils import is_dm from utils import local_actor_url from utils import get_instance_url from utils import get_nickname_from_actor -from utils import detect_mitm +from mitm import detect_mitm from httpheaders import redirect_headers from session import establish_session from httpcodes import http_404 diff --git a/daemon_get_post.py b/daemon_get_post.py index 143ef162d..1e5c92b2a 100644 --- a/daemon_get_post.py +++ b/daemon_get_post.py @@ -25,7 +25,7 @@ from utils import get_json_content_from_accept from utils import convert_domains from utils import has_object_dict from utils import load_json -from utils import detect_mitm +from mitm import detect_mitm from session import establish_session from languages import get_understood_languages from languages import get_reply_language diff --git a/daemon_post.py b/daemon_post.py index dcd4426f9..835a64557 100644 --- a/daemon_post.py +++ b/daemon_post.py @@ -21,7 +21,7 @@ from utils import local_actor_url from utils import contains_invalid_chars from utils import remove_id_ending from utils import check_bad_path -from utils import detect_mitm +from mitm import detect_mitm from blocking import contains_military_domain from blocking import contains_government_domain from blocking import contains_bluesky_domain diff --git a/daemon_utils.py b/daemon_utils.py index a4e48dca0..3068611be 100644 --- a/daemon_utils.py +++ b/daemon_utils.py @@ -28,7 +28,7 @@ from content import valid_url_lengths from posts import add_to_field from status import actor_status_expired from status import get_actor_status -from utils import detect_mitm +from mitm import detect_mitm from utils import data_dir from utils import load_json from utils import save_json diff --git a/inbox.py b/inbox.py index 3374c97dd..3066a9e87 100644 --- a/inbox.py +++ b/inbox.py @@ -23,7 +23,7 @@ from flags import has_group_type from flags import is_quote_toot from flags import url_permitted from quote import quote_toots_allowed -from utils import save_mitm_servers +from mitm import save_mitm_servers from utils import harmless_markup from utils import lines_in_file from utils import date_epoch diff --git a/mitm.py b/mitm.py new file mode 100644 index 000000000..6eb3d46ed --- /dev/null +++ b/mitm.py @@ -0,0 +1,81 @@ +__filename__ = "mitm.py" +__author__ = "Bob Mottram" +__license__ = "AGPL3+" +__version__ = "1.6.0" +__maintainer__ = "Bob Mottram" +__email__ = "bob@libreserver.org" +__status__ = "Production" +__module_group__ = "Core" + +# some posts are proxied through a third party server which removes transport +# layer security, breaking the end-to-end principle. Epicyon warns the +# user when it knows that this is happening. + +import os +from utils import data_dir + + +def detect_mitm(self) -> bool: + """Detect if a request contains a MiTM + """ + mitm_domains = ( + 'cloudflare', 'radware', 'imperva', 'akamai', 'azure', + 'fastly', 'google' + ) + # look for domains within these headers + check_headers = ( + 'Server', 'Report-To', 'Report-to', 'report-to', + 'Expect-CT', 'Expect-Ct', 'expect-ct' + ) + for interloper in mitm_domains: + for header_name in check_headers: + if not self.headers.get(header_name): + continue + if interloper in str(self.headers[header_name]).lower(): + return True + # The presence of these headers on their own indicates a MiTM + mitm_headers = ( + 'CF-Connecting-IP', 'CF-RAY', 'CF-IPCountry', 'CF-Visitor', + 'CDN-Loop', 'CF-Worker', 'CF-Cache-Status' + ) + for header_name in mitm_headers: + if self.headers.get(header_name): + return True + if self.headers.get(header_name.lower()): + return True + return False + + +def load_mitm_servers(base_dir: str) -> []: + """Loads a list of servers implementing insecure transport security + """ + mitm_servers_filename = data_dir(base_dir) + '/mitm_servers.txt' + mitm_servers: list[str] = [] + if os.path.isfile(mitm_servers_filename): + try: + with open(mitm_servers_filename, 'r', + encoding='utf-8') as fp_mitm: + mitm_servers = fp_mitm.read() + except OSError: + print('EX: error while reading mitm_servers.txt') + if not mitm_servers: + return [] + mitm_servers = mitm_servers.split('\n') + return mitm_servers + + +def save_mitm_servers(base_dir: str, mitm_servers: []) -> None: + """Saves a list of servers implementing insecure transport security + """ + mitm_servers_str = '' + for domain in mitm_servers: + if domain: + mitm_servers_str += domain + '\n' + + mitm_servers_filename = data_dir(base_dir) + '/mitm_servers.txt' + try: + with open(mitm_servers_filename, 'w+', + encoding='utf-8') as fp_mitm: + fp_mitm.write(mitm_servers_str) + except OSError: + print('EX: error while saving mitm_servers.txt') diff --git a/session.py b/session.py index e149f5c9e..c92042534 100644 --- a/session.py +++ b/session.py @@ -19,8 +19,8 @@ from utils import text_in_file from utils import acct_dir from utils import binary_is_image from utils import image_mime_types_dict -from utils import detect_mitm from utils import get_domain_from_actor +from mitm import detect_mitm from httpsig import create_signed_header diff --git a/utils.py b/utils.py index 128f062be..2b523fbd6 100644 --- a/utils.py +++ b/utils.py @@ -5106,55 +5106,6 @@ def browser_supports_download_filename(ua_str: str) -> bool: return False -def detect_mitm(self) -> bool: - """Detect if a request contains a MiTM - """ - mitm_domains = ( - 'cloudflare', 'radware', 'imperva', 'akamai', 'azure', - 'fastly', 'google' - ) - # look for domains within these headers - check_headers = ( - 'Server', 'Report-To', 'Report-to', 'report-to', - 'Expect-CT', 'Expect-Ct', 'expect-ct' - ) - for interloper in mitm_domains: - for header_name in check_headers: - if not self.headers.get(header_name): - continue - if interloper in str(self.headers[header_name]).lower(): - return True - # The presence of these headers on their own indicates a MiTM - mitm_headers = ( - 'CF-Connecting-IP', 'CF-RAY', 'CF-IPCountry', 'CF-Visitor', - 'CDN-Loop', 'CF-Worker', 'CF-Cache-Status' - ) - for header_name in mitm_headers: - if self.headers.get(header_name): - return True - if self.headers.get(header_name.lower()): - return True - return False - - -def load_mitm_servers(base_dir: str) -> []: - """Loads a list of servers implementing insecure transport security - """ - mitm_servers_filename = data_dir(base_dir) + '/mitm_servers.txt' - mitm_servers: list[str] = [] - if os.path.isfile(mitm_servers_filename): - try: - with open(mitm_servers_filename, 'r', - encoding='utf-8') as fp_mitm: - mitm_servers = fp_mitm.read() - except OSError: - print('EX: error while reading mitm_servers.txt') - if not mitm_servers: - return [] - mitm_servers = mitm_servers.split('\n') - return mitm_servers - - def load_instance_software(base_dir: str) -> []: """For each domain encountered this stores the instance type such as mastodon, epicyon, pixelfed, etc @@ -5167,23 +5118,6 @@ def load_instance_software(base_dir: str) -> []: return {} -def save_mitm_servers(base_dir: str, mitm_servers: []) -> None: - """Saves a list of servers implementing insecure transport security - """ - mitm_servers_str = '' - for domain in mitm_servers: - if domain: - mitm_servers_str += domain + '\n' - - mitm_servers_filename = data_dir(base_dir) + '/mitm_servers.txt' - try: - with open(mitm_servers_filename, 'w+', - encoding='utf-8') as fp_mitm: - fp_mitm.write(mitm_servers_str) - except OSError: - print('EX: error while saving mitm_servers.txt') - - def get_event_categories() -> []: """Returns event categories https://codeberg.org/fediverse/fep/src/branch/main/fep/8a8e/fep-8a8e.md