diff --git a/daemon.py b/daemon.py index 110ced53f..6eb73c27b 100644 --- a/daemon.py +++ b/daemon.py @@ -60,6 +60,7 @@ from donate import get_donation_url from donate import set_donation_url from donate import get_website from donate import set_website +from person import add_alternate_domains from person import add_actor_update_timestamp from person import set_person_notes from person import get_default_person_context @@ -428,7 +429,7 @@ class PubServer(BaseHTTPRequestHandler): def _convert_domains(self, calling_domain, referer_domain, msg_str: str) -> str: - """Convert domains to onion or i2p + """Convert domains to onion or i2p, depending upon who is asking """ curr_http_prefix = self.server.http_prefix + '://' if is_onion_request(calling_domain, referer_domain, @@ -8363,6 +8364,10 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(self.post_to_nickname): timezone = \ self.server.account_timezone.get(self.post_to_nickname) + mitm = False + if os.path.isfile(announce_filename.replace('.json', '') + + '.mitm'): + mitm = True individual_post_as_html(self.server.signing_priv_key_pem, False, self.server.recent_posts_cache, self.server.max_recent_posts, @@ -8391,7 +8396,7 @@ class PubServer(BaseHTTPRequestHandler): False, True, False, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, mitm) actor_absolute = self._get_instance_url(calling_domain) + actor actor_path_str = \ @@ -8894,6 +8899,10 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(self.post_to_nickname): timezone = \ self.server.account_timezone.get(self.post_to_nickname) + mitm = False + if os.path.isfile(liked_post_filename.replace('.json', '') + + '.mitm'): + mitm = True individual_post_as_html(self.server.signing_priv_key_pem, False, self.server.recent_posts_cache, @@ -8924,7 +8933,7 @@ class PubServer(BaseHTTPRequestHandler): False, True, False, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, mitm) else: print('WARN: Liked post not found: ' + liked_post_filename) # clear the icon from the cache so that it gets updated @@ -9072,6 +9081,10 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(self.post_to_nickname): timezone = \ self.server.account_timezone.get(self.post_to_nickname) + mitm = False + if os.path.isfile(liked_post_filename.replace('.json', '') + + '.mitm'): + mitm = True individual_post_as_html(self.server.signing_priv_key_pem, False, self.server.recent_posts_cache, @@ -9102,7 +9115,7 @@ class PubServer(BaseHTTPRequestHandler): False, True, False, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, mitm) else: print('WARN: Unliked post not found: ' + liked_post_filename) # clear the icon from the cache so that it gets updated @@ -9279,6 +9292,10 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(self.post_to_nickname): timezone = \ self.server.account_timezone.get(self.post_to_nickname) + mitm = False + if os.path.isfile(reaction_post_filename.replace('.json', '') + + '.mitm'): + mitm = True individual_post_as_html(self.server.signing_priv_key_pem, False, self.server.recent_posts_cache, @@ -9309,7 +9326,7 @@ class PubServer(BaseHTTPRequestHandler): False, True, False, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, mitm) else: print('WARN: Emoji reaction post not found: ' + reaction_post_filename) @@ -9476,6 +9493,10 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(self.post_to_nickname): timezone = \ self.server.account_timezone.get(self.post_to_nickname) + mitm = False + if os.path.isfile(reaction_post_filename.replace('.json', '') + + '.mitm'): + mitm = True individual_post_as_html(self.server.signing_priv_key_pem, False, self.server.recent_posts_cache, @@ -9506,7 +9527,7 @@ class PubServer(BaseHTTPRequestHandler): False, True, False, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, mitm) else: print('WARN: Unreaction post not found: ' + reaction_post_filename) @@ -9723,6 +9744,10 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(self.post_to_nickname): timezone = \ self.server.account_timezone.get(self.post_to_nickname) + mitm = False + if os.path.isfile(bookmark_filename.replace('.json', '') + + '.mitm'): + mitm = True individual_post_as_html(self.server.signing_priv_key_pem, False, self.server.recent_posts_cache, @@ -9753,7 +9778,7 @@ class PubServer(BaseHTTPRequestHandler): False, True, False, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, mitm) else: print('WARN: Bookmarked post not found: ' + bookmark_filename) # self._post_to_outbox(bookmark_json, @@ -9875,6 +9900,10 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(self.post_to_nickname): timezone = \ self.server.account_timezone.get(self.post_to_nickname) + mitm = False + if os.path.isfile(bookmark_filename.replace('.json', '') + + '.mitm'): + mitm = True individual_post_as_html(self.server.signing_priv_key_pem, False, self.server.recent_posts_cache, @@ -9905,7 +9934,7 @@ class PubServer(BaseHTTPRequestHandler): False, True, False, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, mitm) else: print('WARN: Unbookmarked post not found: ' + bookmark_filename) @@ -10100,6 +10129,10 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + mitm = False + if os.path.isfile(mute_filename.replace('.json', '') + + '.mitm'): + mitm = True individual_post_as_html(self.server.signing_priv_key_pem, allow_downloads, self.server.recent_posts_cache, @@ -10131,7 +10164,7 @@ class PubServer(BaseHTTPRequestHandler): use_cache_only, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, mitm) else: print('WARN: Muted post not found: ' + mute_filename) @@ -10217,6 +10250,10 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + mitm = False + if os.path.isfile(mute_filename.replace('.json', '') + + '.mitm'): + mitm = True individual_post_as_html(self.server.signing_priv_key_pem, allow_downloads, self.server.recent_posts_cache, @@ -10248,7 +10285,7 @@ class PubServer(BaseHTTPRequestHandler): use_cache_only, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, mitm) else: print('WARN: Unmuted post not found: ' + mute_filename) if calling_domain.endswith('.onion') and onion_domain: @@ -11008,6 +11045,10 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + mitm = False + if os.path.isfile(post_filename.replace('.json', '') + + '.mitm'): + mitm = True msg = \ html_individual_post(self.server.css_cache, self.server.recent_posts_cache, @@ -11034,7 +11075,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, mitm) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -13428,6 +13469,7 @@ class PubServer(BaseHTTPRequestHandler): actor_json = person_lookup(domain, path, base_dir) if not actor_json: return False + add_alternate_domains(actor_json, domain, onion_domain, i2p_domain) if self._request_http(): curr_session = \ self._establish_session("showPersonProfile", diff --git a/inbox.py b/inbox.py index b3ba36255..7006a156d 100644 --- a/inbox.py +++ b/inbox.py @@ -296,7 +296,8 @@ def _inbox_store_post_to_html_cache(recent_posts_cache: {}, signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> None: + timezone: str, + mitm: bool) -> None: """Converts the json post into html and stores it in a cache This enables the post to be quickly displayed later """ @@ -321,7 +322,7 @@ def _inbox_store_post_to_html_cache(recent_posts_cache: {}, peertube_instances, allow_local_network_access, theme_name, system_language, max_like_count, not_dm, True, True, False, True, False, - cw_lists, lists_enabled, timezone) + cw_lists, lists_enabled, timezone, mitm) def valid_inbox(base_dir: str, nickname: str, domain: str) -> bool: @@ -1133,6 +1134,9 @@ def _receive_like(recent_posts_cache: {}, follower_approval_active(base_dir, handle_name, domain) not_dm = not is_dm(liked_post_json) timezone = get_account_timezone(base_dir, handle_name, domain) + mitm = False + if os.path.isfile(post_filename.replace('.json', '') + '.mitm'): + mitm = True individual_post_as_html(signing_priv_key_pem, False, recent_posts_cache, max_recent_posts, translate, page_number, base_dir, @@ -1151,7 +1155,7 @@ def _receive_like(recent_posts_cache: {}, show_individual_post_icons, manually_approve_followers, False, True, False, cw_lists, - lists_enabled, timezone) + lists_enabled, timezone, mitm) return True @@ -1247,6 +1251,9 @@ def _receive_undo_like(recent_posts_cache: {}, follower_approval_active(base_dir, handle_name, domain) not_dm = not is_dm(liked_post_json) timezone = get_account_timezone(base_dir, handle_name, domain) + mitm = False + if os.path.isfile(post_filename.replace('.json', '') + '.mitm'): + mitm = True individual_post_as_html(signing_priv_key_pem, False, recent_posts_cache, max_recent_posts, translate, page_number, base_dir, @@ -1265,7 +1272,7 @@ def _receive_undo_like(recent_posts_cache: {}, show_individual_post_icons, manually_approve_followers, False, True, False, cw_lists, - lists_enabled, timezone) + lists_enabled, timezone, mitm) return True @@ -1393,6 +1400,9 @@ def _receive_reaction(recent_posts_cache: {}, follower_approval_active(base_dir, handle_name, domain) not_dm = not is_dm(reaction_post_json) timezone = get_account_timezone(base_dir, handle_name, domain) + mitm = False + if os.path.isfile(post_filename.replace('.json', '') + '.mitm'): + mitm = True individual_post_as_html(signing_priv_key_pem, False, recent_posts_cache, max_recent_posts, translate, page_number, base_dir, @@ -1412,7 +1422,7 @@ def _receive_reaction(recent_posts_cache: {}, show_individual_post_icons, manually_approve_followers, False, True, False, cw_lists, - lists_enabled, timezone) + lists_enabled, timezone, mitm) return True @@ -1527,6 +1537,9 @@ def _receive_undo_reaction(recent_posts_cache: {}, follower_approval_active(base_dir, handle_name, domain) not_dm = not is_dm(reaction_post_json) timezone = get_account_timezone(base_dir, handle_name, domain) + mitm = False + if os.path.isfile(post_filename.replace('.json', '') + '.mitm'): + mitm = True individual_post_as_html(signing_priv_key_pem, False, recent_posts_cache, max_recent_posts, translate, page_number, base_dir, @@ -1546,7 +1559,7 @@ def _receive_undo_reaction(recent_posts_cache: {}, show_individual_post_icons, manually_approve_followers, False, True, False, cw_lists, - lists_enabled, timezone) + lists_enabled, timezone, mitm) return True @@ -1639,6 +1652,9 @@ def _receive_bookmark(recent_posts_cache: {}, follower_approval_active(base_dir, nickname, domain) not_dm = not is_dm(bookmarked_post_json) timezone = get_account_timezone(base_dir, nickname, domain) + mitm = False + if os.path.isfile(post_filename.replace('.json', '') + '.mitm'): + mitm = True individual_post_as_html(signing_priv_key_pem, False, recent_posts_cache, max_recent_posts, translate, page_number, base_dir, @@ -1657,7 +1673,7 @@ def _receive_bookmark(recent_posts_cache: {}, show_individual_post_icons, manually_approve_followers, False, True, False, cw_lists, - lists_enabled, timezone) + lists_enabled, timezone, mitm) return True @@ -1754,6 +1770,9 @@ def _receive_undo_bookmark(recent_posts_cache: {}, follower_approval_active(base_dir, nickname, domain) not_dm = not is_dm(bookmarked_post_json) timezone = get_account_timezone(base_dir, nickname, domain) + mitm = False + if os.path.isfile(post_filename.replace('.json', '') + '.mitm'): + mitm = True individual_post_as_html(signing_priv_key_pem, False, recent_posts_cache, max_recent_posts, translate, page_number, base_dir, @@ -1772,7 +1791,7 @@ def _receive_undo_bookmark(recent_posts_cache: {}, show_individual_post_icons, manually_approve_followers, False, True, False, cw_lists, lists_enabled, - timezone) + timezone, mitm) return True @@ -1963,6 +1982,9 @@ def _receive_announce(recent_posts_cache: {}, if debug: print('Generating html for announce ' + message_json['id']) timezone = get_account_timezone(base_dir, nickname, domain) + mitm = False + if os.path.isfile(post_filename.replace('.json', '') + '.mitm'): + mitm = True announce_html = \ individual_post_as_html(signing_priv_key_pem, True, recent_posts_cache, max_recent_posts, @@ -1982,7 +2004,7 @@ def _receive_announce(recent_posts_cache: {}, show_individual_post_icons, manually_approve_followers, False, True, False, cw_lists, - lists_enabled, timezone) + lists_enabled, timezone, mitm) if not announce_html: print('WARN: Unable to generate html for announce ' + str(message_json)) @@ -3110,6 +3132,9 @@ def _receive_question_vote(server, base_dir: str, nickname: str, domain: str, follower_approval_active(base_dir, nickname, domain) not_dm = not is_dm(question_json) timezone = get_account_timezone(base_dir, nickname, domain) + mitm = False + if os.path.isfile(question_post_filename.replace('.json', '') + '.mitm'): + mitm = True individual_post_as_html(signing_priv_key_pem, False, recent_posts_cache, max_recent_posts, translate, page_number, base_dir, @@ -3128,7 +3153,7 @@ def _receive_question_vote(server, base_dir: str, nickname: str, domain: str, show_individual_post_icons, manually_approve_followers, False, True, False, cw_lists, - lists_enabled, timezone) + lists_enabled, timezone, mitm) # add id to inbox index inbox_update_index('inbox', base_dir, handle, @@ -3297,7 +3322,8 @@ def _inbox_after_initial(server, default_reply_interval_hrs: int, cw_lists: {}, lists_enabled: str, content_license_url: str, - languages_understood: []) -> bool: + languages_understood: [], + mitm: bool) -> bool: """ Anything which needs to be done after initial checks have passed """ # if this is a clearnet instance then replace any onion/i2p @@ -3634,6 +3660,17 @@ def _inbox_after_initial(server, # save the post to file if save_json(post_json_object, destination_filename): + if mitm: + # write a file to indicate that this post was delivered + # via a third party + destination_filename_mitm = \ + destination_filename.replace('.json', '') + '.mitm' + try: + with open(destination_filename_mitm, 'w+') as mitm_file: + mitm_file.write('\n') + except OSError: + print('EX: unable to write ' + destination_filename_mitm) + _low_frequency_post_notification(base_dir, http_prefix, nickname, domain, port, handle, post_is_dm, json_obj) @@ -3693,7 +3730,7 @@ def _inbox_after_initial(server, signing_priv_key_pem, cw_lists, lists_enabled, - timezone) + timezone, mitm) if debug: time_diff = \ str(int((time.time() - html_cache_start_time) * @@ -4728,6 +4765,9 @@ def run_inbox_queue(server, destination = \ queue_json['destination'].replace(inbox_handle, handle) languages_understood = [] + mitm = False + if queue_json.get('mitm'): + mitm = True _inbox_after_initial(server, recent_posts_cache, max_recent_posts, @@ -4759,7 +4799,7 @@ def run_inbox_queue(server, default_reply_interval_hrs, cw_lists, lists_enabled, content_license_url, - languages_understood) + languages_understood, mitm) if debug: pprint(queue_json['post']) print('Queue: Queue post accepted') diff --git a/outbox.py b/outbox.py index 5e2943b8e..3b8215d52 100644 --- a/outbox.py +++ b/outbox.py @@ -457,6 +457,10 @@ def post_message_to_outbox(session, translate: {}, timezone = \ get_account_timezone(base_dir, post_to_nickname, domain) + mitm = False + if os.path.isfile(saved_filename.replace('.json', '') + + '.mitm'): + mitm = True individual_post_as_html(signing_priv_key_pem, False, recent_posts_cache, max_recent_posts, @@ -481,7 +485,7 @@ def post_message_to_outbox(session, translate: {}, manually_approve_followers, False, True, use_cache_only, cw_lists, lists_enabled, - timezone) + timezone, mitm) if outbox_announce(recent_posts_cache, base_dir, message_json, debug): diff --git a/person.py b/person.py index 69026c9fc..c6ddc773c 100644 --- a/person.py +++ b/person.py @@ -38,6 +38,7 @@ from roles import set_role from roles import set_rolesFromList from roles import get_actor_roles_list from media import process_meta_data +from utils import get_nickname_from_actor from utils import remove_html from utils import contains_invalid_chars from utils import replace_users_with_at @@ -861,6 +862,31 @@ def person_upgrade_actor(base_dir: str, person_json: {}, save_json(person_json, actor_cache_filename) +def add_alternate_domains(actor_json: {}, domain: str, + onion_domain: str, i2p_domain: str) -> None: + """Adds alternate onion and/or i2p domains to alsoKnownAs + """ + if not onion_domain and not i2p_domain: + return + if not actor_json.get('id'): + return + if domain not in actor_json['id']: + return + nickname = get_nickname_from_actor(actor_json['id']) + if not nickname: + return + if 'alsoKnownAs' not in actor_json: + actor_json['alsoKnownAs'] = [] + if onion_domain: + onion_actor = 'http://' + onion_domain + '/users/' + nickname + if onion_actor not in actor_json['alsoKnownAs']: + actor_json['alsoKnownAs'].append(onion_actor) + if i2p_domain: + i2p_actor = 'http://' + i2p_domain + '/users/' + nickname + if i2p_actor not in actor_json['alsoKnownAs']: + actor_json['alsoKnownAs'].append(i2p_actor) + + def person_lookup(domain: str, path: str, base_dir: str) -> {}: """Lookup the person for an given nickname """ diff --git a/posts.py b/posts.py index 5171b6422..9d43ae88a 100644 --- a/posts.py +++ b/posts.py @@ -3779,6 +3779,11 @@ def _add_post_to_timeline(file_path: str, boxname: str, # append a replies identifier, which will later be removed post_str += '' + mitm_filename = file_path.replace('.json', '.mitm') + if os.path.isfile(mitm_filename): + # append a mitm identifier, which will later be removed + post_str += '' + return _add_post_string_to_timeline(post_str, boxname, posts_in_box, box_actor) return False @@ -4078,6 +4083,13 @@ def _create_box_indexed(recent_posts_cache: {}, # remove the replies identifier post_str = post_str.replace('', '') + # Check if the post was delivered via a third party + mitm = False + if post_str.endswith(''): + mitm = True + # remove the mitm identifier + post_str = post_str.replace('', '') + pst = None try: pst = json.loads(post_str) @@ -4090,6 +4102,9 @@ def _create_box_indexed(recent_posts_cache: {}, # created by individual_post_as_html pst['hasReplies'] = has_replies + # was the post delivered via a third party? + pst['mitm'] = mitm + if not authorized: if not remove_post_interactions(pst, False): continue @@ -4842,18 +4857,22 @@ def download_announce(session, base_dir: str, http_prefix: str, return None if not isinstance(announced_json, dict): - print('WARN: announce json is not a dict - ' + + print('WARN: announced post json is not a dict - ' + post_json_object['object']) _reject_announce(announce_filename, base_dir, nickname, domain, post_id, recent_posts_cache) return None if not announced_json.get('id'): + print('WARN: announced post does not have an id ' + + str(announced_json)) _reject_announce(announce_filename, base_dir, nickname, domain, post_id, recent_posts_cache) return None if not announced_json.get('type'): + print('WARN: announced post does not have a type ' + + str(announced_json)) _reject_announce(announce_filename, base_dir, nickname, domain, post_id, recent_posts_cache) @@ -4866,11 +4885,15 @@ def download_announce(session, base_dir: str, http_prefix: str, if converted_json: announced_json = converted_json if '/statuses/' not in announced_json['id']: + print('WARN: announced post id does not contain /statuses/ ' + + str(announced_json)) _reject_announce(announce_filename, base_dir, nickname, domain, post_id, recent_posts_cache) return None if not has_users_path(announced_json['id']): + print('WARN: announced post id does not contain /users/ ' + + str(announced_json)) _reject_announce(announce_filename, base_dir, nickname, domain, post_id, recent_posts_cache) @@ -4878,22 +4901,30 @@ def download_announce(session, base_dir: str, http_prefix: str, if announced_json['type'] != 'Note' and \ announced_json['type'] != 'Page' and \ announced_json['type'] != 'Article': + print('WARN: announced post is not Note/Page/Article ' + + str(announced_json)) # You can only announce Note or Article types _reject_announce(announce_filename, base_dir, nickname, domain, post_id, recent_posts_cache) return None if not announced_json.get('content'): + print('WARN: announced post does not have content ' + + str(announced_json)) _reject_announce(announce_filename, base_dir, nickname, domain, post_id, recent_posts_cache) return None if not announced_json.get('published'): + print('WARN: announced post does not have published ' + + str(announced_json)) _reject_announce(announce_filename, base_dir, nickname, domain, post_id, recent_posts_cache) return None if not valid_post_date(announced_json['published'], 90, debug): + print('WARN: announced post is not recently published ' + + str(announced_json)) _reject_announce(announce_filename, base_dir, nickname, domain, post_id, recent_posts_cache) @@ -4906,18 +4937,24 @@ def download_announce(session, base_dir: str, http_prefix: str, # Check the content of the announce content_str = announced_json['content'] if dangerous_markup(content_str, allow_local_network_access): + print('WARN: announced post contains dangerous markup ' + + str(announced_json)) _reject_announce(announce_filename, base_dir, nickname, domain, post_id, recent_posts_cache) return None if is_filtered(base_dir, nickname, domain, content_str): + print('WARN: announced post has been filtered ' + + str(announced_json)) _reject_announce(announce_filename, base_dir, nickname, domain, post_id, recent_posts_cache) return None if invalid_ciphertext(content_str): + print('WARN: announced post contains invalid ciphertext ' + + str(announced_json)) _reject_announce(announce_filename, base_dir, nickname, domain, post_id, recent_posts_cache) @@ -4943,6 +4980,8 @@ def download_announce(session, base_dir: str, http_prefix: str, actor_nickname, actor_domain, actor_port, announced_json) if announced_json['type'] != 'Create': + print('WARN: announced post could not be wrapped in Create ' + + str(announced_json)) # Create wrap failed _reject_announce(announce_filename, base_dir, nickname, domain, post_id, @@ -4963,6 +5002,8 @@ def download_announce(session, base_dir: str, http_prefix: str, get_full_domain(attributed_domain, attributed_port) if is_blocked(base_dir, nickname, domain, attributed_nickname, attributed_domain): + print('WARN: announced post handle is blocked ' + + str(attributed_nickname) + '@' + attributed_domain) _reject_announce(announce_filename, base_dir, nickname, domain, post_id, recent_posts_cache) diff --git a/theme/blue/icons/mitm.png b/theme/blue/icons/mitm.png new file mode 100644 index 000000000..19bce88c3 Binary files /dev/null and b/theme/blue/icons/mitm.png differ diff --git a/theme/debian/icons/mitm.png b/theme/debian/icons/mitm.png new file mode 100644 index 000000000..19bce88c3 Binary files /dev/null and b/theme/debian/icons/mitm.png differ diff --git a/theme/default/icons/mitm.png b/theme/default/icons/mitm.png new file mode 100644 index 000000000..19bce88c3 Binary files /dev/null and b/theme/default/icons/mitm.png differ diff --git a/theme/hacker/icons/mitm.png b/theme/hacker/icons/mitm.png new file mode 100644 index 000000000..68f9b996b Binary files /dev/null and b/theme/hacker/icons/mitm.png differ diff --git a/theme/henge/icons/mitm.png b/theme/henge/icons/mitm.png new file mode 100644 index 000000000..e915838cc Binary files /dev/null and b/theme/henge/icons/mitm.png differ diff --git a/theme/indymediaclassic/icons/mitm.png b/theme/indymediaclassic/icons/mitm.png new file mode 100644 index 000000000..ccce2caae Binary files /dev/null and b/theme/indymediaclassic/icons/mitm.png differ diff --git a/theme/indymediamodern/icons/mitm.png b/theme/indymediamodern/icons/mitm.png new file mode 100644 index 000000000..8c1a044f8 Binary files /dev/null and b/theme/indymediamodern/icons/mitm.png differ diff --git a/theme/lcd/icons/mitm.png b/theme/lcd/icons/mitm.png new file mode 100644 index 000000000..acecff810 Binary files /dev/null and b/theme/lcd/icons/mitm.png differ diff --git a/theme/light/icons/mitm.png b/theme/light/icons/mitm.png new file mode 100644 index 000000000..8c1a044f8 Binary files /dev/null and b/theme/light/icons/mitm.png differ diff --git a/theme/night/icons/mitm.png b/theme/night/icons/mitm.png new file mode 100644 index 000000000..19bce88c3 Binary files /dev/null and b/theme/night/icons/mitm.png differ diff --git a/theme/pixel/icons/mitm.png b/theme/pixel/icons/mitm.png new file mode 100644 index 000000000..0a594a408 Binary files /dev/null and b/theme/pixel/icons/mitm.png differ diff --git a/theme/purple/icons/mitm.png b/theme/purple/icons/mitm.png new file mode 100644 index 000000000..aadad00a1 Binary files /dev/null and b/theme/purple/icons/mitm.png differ diff --git a/theme/rc3/icons/mitm.png b/theme/rc3/icons/mitm.png new file mode 100644 index 000000000..aea21612d Binary files /dev/null and b/theme/rc3/icons/mitm.png differ diff --git a/theme/solidaric/icons/mitm.png b/theme/solidaric/icons/mitm.png new file mode 100644 index 000000000..176f6b522 Binary files /dev/null and b/theme/solidaric/icons/mitm.png differ diff --git a/theme/starlight/icons/mitm.png b/theme/starlight/icons/mitm.png new file mode 100644 index 000000000..94c8a28fc Binary files /dev/null and b/theme/starlight/icons/mitm.png differ diff --git a/theme/zen/icons/mitm.png b/theme/zen/icons/mitm.png new file mode 100644 index 000000000..c04ad28c7 Binary files /dev/null and b/theme/zen/icons/mitm.png differ diff --git a/translations/ar.json b/translations/ar.json index 25d3a03c4..8a4d3c7ee 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -517,5 +517,6 @@ "Repeated by": "يتكرر بواسطة", "Register": "يسجل", "Web Bots Allowed": "مسموح روبوتات الويب", - "Known Search Bots": "روبوتات بحث الويب المعروفة" + "Known Search Bots": "روبوتات بحث الويب المعروفة", + "mitm": "يمكن قراءة الرسالة أو تعديلها من قبل طرف ثالث" } diff --git a/translations/ca.json b/translations/ca.json index 839c0035d..10dd483f7 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -517,5 +517,6 @@ "Repeated by": "Repetit per", "Register": "Registra't", "Web Bots Allowed": "Bots web permesos", - "Known Search Bots": "Bots de cerca web coneguts" + "Known Search Bots": "Bots de cerca web coneguts", + "mitm": "El missatge podria haver estat llegit o modificat per un tercer" } diff --git a/translations/cy.json b/translations/cy.json index 7567962b7..eef7ecbd4 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -517,5 +517,6 @@ "Repeated by": "Ailadrodd gan", "Register": "Cofrestrwch", "Web Bots Allowed": "Web Bots a Ganiateir", - "Known Search Bots": "Bots Chwilio Gwe Hysbys" + "Known Search Bots": "Bots Chwilio Gwe Hysbys", + "mitm": "Gallai'r neges fod wedi cael ei darllen neu ei haddasu gan drydydd parti" } diff --git a/translations/de.json b/translations/de.json index e8a88b053..a33f20caf 100644 --- a/translations/de.json +++ b/translations/de.json @@ -517,5 +517,6 @@ "Repeated by": "Wiederholt von", "Register": "Registrieren", "Web Bots Allowed": "Webbots erlaubt", - "Known Search Bots": "Bekannte Bots für die Websuche" + "Known Search Bots": "Bekannte Bots für die Websuche", + "mitm": "Die Nachricht könnte von einem Dritten gelesen oder geändert worden sein" } diff --git a/translations/en.json b/translations/en.json index 76758fb36..848aeb093 100644 --- a/translations/en.json +++ b/translations/en.json @@ -517,5 +517,6 @@ "Repeated by": "Repeated by", "Register": "Register", "Web Bots Allowed": "Web Search Bots Allowed", - "Known Search Bots": "Known Web Search Bots" + "Known Search Bots": "Known Web Search Bots", + "mitm": "Message could have been read or modified by a third party" } diff --git a/translations/es.json b/translations/es.json index aa88cfafd..b611d7366 100644 --- a/translations/es.json +++ b/translations/es.json @@ -517,5 +517,6 @@ "Repeated by": "Repetido por", "Register": "Registrarse", "Web Bots Allowed": "Bots web permitidos", - "Known Search Bots": "Bots de búsqueda web conocidos" + "Known Search Bots": "Bots de búsqueda web conocidos", + "mitm": "El mensaje podría haber sido leído o modificado por un tercero" } diff --git a/translations/fr.json b/translations/fr.json index 71ce41fb1..f50d7a4d4 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -517,5 +517,6 @@ "Repeated by": "Répété par", "Register": "S'inscrire", "Web Bots Allowed": "Robots Web autorisés", - "Known Search Bots": "Robots de recherche Web connus" + "Known Search Bots": "Robots de recherche Web connus", + "mitm": "Le message a pu être lu ou modifié par un tiers" } diff --git a/translations/ga.json b/translations/ga.json index 597385634..7fdcece92 100644 --- a/translations/ga.json +++ b/translations/ga.json @@ -517,5 +517,6 @@ "Repeated by": "Arís agus arís eile ag", "Register": "Clár", "Web Bots Allowed": "Róbónna Gréasáin Ceadaithe", - "Known Search Bots": "Róbónna Cuardach Gréasáin Aitheanta" + "Known Search Bots": "Róbónna Cuardach Gréasáin Aitheanta", + "mitm": "D'fhéadfadh tríú páirtí an teachtaireacht a léamh nó a mhodhnú" } diff --git a/translations/hi.json b/translations/hi.json index 348f31bdb..668b8aab6 100644 --- a/translations/hi.json +++ b/translations/hi.json @@ -517,5 +517,6 @@ "Repeated by": "द्वारा दोहराया गया", "Register": "रजिस्टर करें", "Web Bots Allowed": "वेब बॉट्स की अनुमति है", - "Known Search Bots": "ज्ञात वेब खोज बॉट्स" + "Known Search Bots": "ज्ञात वेब खोज बॉट्स", + "mitm": "संदेश किसी तीसरे पक्ष द्वारा पढ़ा या संशोधित किया जा सकता था" } diff --git a/translations/it.json b/translations/it.json index f66199075..23e96d921 100644 --- a/translations/it.json +++ b/translations/it.json @@ -517,5 +517,6 @@ "Repeated by": "Ripetuto da", "Register": "Registrati", "Web Bots Allowed": "Web bot consentiti", - "Known Search Bots": "Bot di ricerca Web noti" + "Known Search Bots": "Bot di ricerca Web noti", + "mitm": "Il messaggio potrebbe essere stato letto o modificato da terzi" } diff --git a/translations/ja.json b/translations/ja.json index b524984d9..e722405f8 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -517,5 +517,6 @@ "Repeated by": "によって繰り返される", "Register": "登録", "Web Bots Allowed": "許可されたWebボット", - "Known Search Bots": "既知のWeb検索ボット" + "Known Search Bots": "既知のWeb検索ボット", + "mitm": "メッセージが第三者によって読み取られたり変更されたりした可能性があります" } diff --git a/translations/ko.json b/translations/ko.json index 5df692faa..e9bdb5d38 100644 --- a/translations/ko.json +++ b/translations/ko.json @@ -517,5 +517,6 @@ "Repeated by": "반복한 사람", "Register": "등록", "Web Bots Allowed": "웹 봇 허용", - "Known Search Bots": "알려진 웹 검색 봇" + "Known Search Bots": "알려진 웹 검색 봇", + "mitm": "제3자가 메시지를 읽거나 수정했을 수 있습니다." } diff --git a/translations/ku.json b/translations/ku.json index 2a94f25de..e491e585c 100644 --- a/translations/ku.json +++ b/translations/ku.json @@ -517,5 +517,6 @@ "Repeated by": "Ji hêla dubare kirin", "Register": "Fêhrist", "Web Bots Allowed": "Web Bots Destûrdar in", - "Known Search Bots": "Botên Lêgerîna Webê yên naskirî" + "Known Search Bots": "Botên Lêgerîna Webê yên naskirî", + "mitm": "Peyam dikaribû ji hêla aliyek sêyemîn ve were xwendin an guhertin" } diff --git a/translations/oc.json b/translations/oc.json index fc4a357a6..5c0858299 100644 --- a/translations/oc.json +++ b/translations/oc.json @@ -513,5 +513,6 @@ "Repeated by": "Repeated by", "Register": "Register", "Web Bots Allowed": "Web Search Bots Allowed", - "Known Search Bots": "Known Web Search Bots" + "Known Search Bots": "Known Web Search Bots", + "mitm": "Message could have been read or modified by a third party" } diff --git a/translations/pl.json b/translations/pl.json index 301c70145..3184a3a52 100644 --- a/translations/pl.json +++ b/translations/pl.json @@ -517,5 +517,6 @@ "Repeated by": "Powtórzone przez", "Register": "Zarejestrować", "Web Bots Allowed": "Dozwolone boty internetowe", - "Known Search Bots": "Znane boty wyszukiwania w sieci" + "Known Search Bots": "Znane boty wyszukiwania w sieci", + "mitm": "Wiadomość mogła zostać przeczytana lub zmodyfikowana przez osobę trzecią" } diff --git a/translations/pt.json b/translations/pt.json index 4c8e848cc..5a543440b 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -517,5 +517,6 @@ "Repeated by": "Repetido por", "Register": "Registro", "Web Bots Allowed": "Webbots permitidos", - "Known Search Bots": "Bots de pesquisa na Web conhecidos" + "Known Search Bots": "Bots de pesquisa na Web conhecidos", + "mitm": "A mensagem pode ter sido lida ou modificada por terceiros" } diff --git a/translations/ru.json b/translations/ru.json index a5f545bcd..b9540fc12 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -517,5 +517,6 @@ "Repeated by": "Повторено", "Register": "регистр", "Web Bots Allowed": "Веб-боты разрешены", - "Known Search Bots": "Известные боты веб-поиска" + "Known Search Bots": "Известные боты веб-поиска", + "mitm": "Сообщение могло быть прочитано или изменено третьим лицом" } diff --git a/translations/sw.json b/translations/sw.json index bda0f5299..9f047b434 100644 --- a/translations/sw.json +++ b/translations/sw.json @@ -517,5 +517,6 @@ "Repeated by": "Imerudiwa na", "Register": "Sajili", "Web Bots Allowed": "Mtandao wa Boti Unaruhusiwa", - "Known Search Bots": "Vijibu vya Utafutaji wa Wavuti vinavyojulikana" + "Known Search Bots": "Vijibu vya Utafutaji wa Wavuti vinavyojulikana", + "mitm": "Ujumbe ungeweza kusomwa au kurekebishwa na mtu mwingine" } diff --git a/translations/uk.json b/translations/uk.json index 2f1d65fc4..89e9273bd 100644 --- a/translations/uk.json +++ b/translations/uk.json @@ -517,5 +517,6 @@ "Repeated by": "Повторюється за", "Register": "Реєстрація", "Web Bots Allowed": "Веб-боти дозволені", - "Known Search Bots": "Відомі пошукові роботи в Інтернеті" + "Known Search Bots": "Відомі пошукові роботи в Інтернеті", + "mitm": "Повідомлення могло бути прочитане або змінене третьою стороною" } diff --git a/translations/zh.json b/translations/zh.json index 280ce1fcf..b0acdfbde 100644 --- a/translations/zh.json +++ b/translations/zh.json @@ -517,5 +517,6 @@ "Repeated by": "重复", "Register": "登记", "Web Bots Allowed": "允许网络机器人", - "Known Search Bots": "已知的网络搜索机器人" + "Known Search Bots": "已知的网络搜索机器人", + "mitm": "消息可能已被第三方阅读或修改" } diff --git a/utils.py b/utils.py index a4b9b8396..e647e5680 100644 --- a/utils.py +++ b/utils.py @@ -1788,7 +1788,7 @@ def delete_post(base_dir: str, http_prefix: str, # remove any attachment _remove_attachment(base_dir, http_prefix, domain, post_json_object) - extensions = ('votes', 'arrived', 'muted', 'tts', 'reject') + extensions = ('votes', 'arrived', 'muted', 'tts', 'reject', 'mitm') for ext in extensions: ext_filename = post_filename + '.' + ext if os.path.isfile(ext_filename): diff --git a/webapp_confirm.py b/webapp_confirm.py index 7e64348de..12e32c64e 100644 --- a/webapp_confirm.py +++ b/webapp_confirm.py @@ -66,6 +66,9 @@ def html_confirm_delete(css_cache: {}, delete_post_str = \ html_header_with_external_style(css_filename, instance_title, None) timezone = get_account_timezone(base_dir, nickname, domain) + mitm = False + if os.path.isfile(post_filename.replace('.json', '') + '.mitm'): + mitm = True delete_post_str += \ individual_post_as_html(signing_priv_key_pem, True, recent_posts_cache, max_recent_posts, @@ -81,7 +84,7 @@ def html_confirm_delete(css_cache: {}, peertube_instances, allow_local_network_access, theme_name, system_language, max_like_count, False, False, False, False, False, False, - cw_lists, lists_enabled, timezone) + cw_lists, lists_enabled, timezone, mitm) delete_post_str += '
' delete_post_str += \ '

' + \ diff --git a/webapp_create_post.py b/webapp_create_post.py index 4dff64b43..0812ea207 100644 --- a/webapp_create_post.py +++ b/webapp_create_post.py @@ -286,7 +286,7 @@ def html_new_post(css_cache: {}, media_instance: bool, translate: {}, False, False, False, False, False, False, cw_lists, lists_enabled, - timezone) + timezone, False) reply_str = '\n' diff --git a/webapp_frontscreen.py b/webapp_frontscreen.py index 1d135d5eb..68df1b6de 100644 --- a/webapp_frontscreen.py +++ b/webapp_frontscreen.py @@ -87,7 +87,7 @@ def _html_front_screen_posts(recent_posts_cache: {}, max_recent_posts: int, False, False, False, True, False, False, cw_lists, lists_enabled, - timezone) + timezone, False) if post_str: profile_str += post_str + separator_str ctr += 1 diff --git a/webapp_likers.py b/webapp_likers.py index 7cfe6e8b0..0625f151e 100644 --- a/webapp_likers.py +++ b/webapp_likers.py @@ -78,6 +78,9 @@ def html_likers_of_post(base_dir: str, nickname: str, # show the post which was liked timezone = get_account_timezone(base_dir, nickname, domain) + mitm = False + if os.path.isfile(filename.replace('.json', '') + '.mitm'): + mitm = True html_str += \ individual_post_as_html(signing_priv_key_pem, True, recent_posts_cache, @@ -102,7 +105,7 @@ def html_likers_of_post(base_dir: str, nickname: str, False, False, False, False, False, False, cw_lists, lists_enabled, - timezone) + timezone, mitm) # show likers beneath the post obj = post_json_object diff --git a/webapp_post.py b/webapp_post.py index 5100eeb09..7c69692a3 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -1026,8 +1026,8 @@ def _get_post_title_announce_html(base_dir: str, page_number: int, message_id_str: str, container_class_icons: str, - container_class: str) -> (str, str, - str, str): + container_class: str, + mitm: bool) -> (str, str, str, str): """Returns the announce title of a post containing names of participants x announces y """ @@ -1081,6 +1081,10 @@ def _get_post_title_announce_html(base_dir: str, title_str += \ _announce_with_display_name_html(translate, post_json_object, announce_display_name) + + if mitm: + title_str += _mitm_warning_html(translate) + # show avatar of person replied to announce_actor = attributed_to announce_avatar_url = \ @@ -1141,6 +1145,16 @@ def _reply_to_unknown_html(translate: {}, '" class="announceOrReply">@unknown\n' +def _mitm_warning_html(translate: {}) -> str: + """Returns the html title for a reply to an unknown handle + """ + mitm_warning_str = translate['mitm'] + return ' ' + \
+        mitm_warning_str + '\n' + + def _reply_with_unknown_path_html(translate: {}, post_json_object: {}, post_domain: str) -> str: @@ -1196,7 +1210,8 @@ def _get_post_title_reply_html(base_dir: str, page_number: int, message_id_str: str, container_class_icons: str, - container_class: str) -> (str, str, str, str): + container_class: str, + mitm: bool) -> (str, str, str, str): """Returns the reply title of a post containing names of participants x replies to y """ @@ -1264,6 +1279,9 @@ def _get_post_title_reply_html(base_dir: str, title_str += _get_reply_html(translate, in_reply_to, reply_display_name) + if mitm: + title_str += _mitm_warning_html(translate) + _log_post_timing(enable_timing_log, post_start_time, '13.7') # show avatar of person replied to @@ -1309,7 +1327,8 @@ def _get_post_title_html(base_dir: str, page_number: int, message_id_str: str, container_class_icons: str, - container_class: str) -> (str, str, str, str): + container_class: str, + mitm: bool) -> (str, str, str, str): """Returns the title of a post containing names of participants x replies to y, x announces y, etc """ @@ -1337,7 +1356,7 @@ def _get_post_title_html(base_dir: str, page_number, message_id_str, container_class_icons, - container_class) + container_class, mitm) return _get_post_title_reply_html(base_dir, http_prefix, @@ -1356,7 +1375,7 @@ def _get_post_title_html(base_dir: str, page_number, message_id_str, container_class_icons, - container_class) + container_class, mitm) def _get_footer_with_icons(show_icons: bool, @@ -1416,7 +1435,8 @@ def individual_post_as_html(signing_priv_key_pem: str, use_cache_only: bool, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, + mitm: bool) -> str: """ Shows a single post as html """ if not post_json_object: @@ -1845,7 +1865,7 @@ def individual_post_as_html(signing_priv_key_pem: str, page_number, message_id_str, container_class_icons, - container_class) + container_class, mitm) title_str += title_str2 _log_post_timing(enable_timing_log, post_start_time, '14') @@ -2094,7 +2114,7 @@ def html_individual_post(css_cache: {}, theme_name: str, system_language: str, max_like_count: int, signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, mitm: bool) -> str: """Show an individual post as html """ original_post_json = post_json_object @@ -2160,7 +2180,7 @@ def html_individual_post(css_cache: {}, allow_local_network_access, theme_name, system_language, max_like_count, False, authorized, False, False, False, False, - cw_lists, lists_enabled, timezone) + cw_lists, lists_enabled, timezone, mitm) message_id = remove_id_ending(post_json_object['id']) # show the previous posts @@ -2173,6 +2193,10 @@ def html_individual_post(css_cache: {}, break post_json_object = load_json(post_filename) if post_json_object: + mitm = False + if os.path.isfile(post_filename.replace('.json', '') + + '.mitm'): + mitm = True post_str = \ individual_post_as_html(signing_priv_key_pem, True, recent_posts_cache, @@ -2196,7 +2220,7 @@ def html_individual_post(css_cache: {}, False, authorized, False, False, False, False, cw_lists, lists_enabled, - timezone) + post_str + timezone, mitm) + post_str # show the following posts post_filename = locate_post(base_dir, nickname, domain, message_id) @@ -2234,7 +2258,7 @@ def html_individual_post(css_cache: {}, False, authorized, False, False, False, False, cw_lists, lists_enabled, - timezone) + timezone, False) css_filename = base_dir + '/epicyon-profile.css' if os.path.isfile(base_dir + '/epicyon.css'): css_filename = base_dir + '/epicyon.css' @@ -2288,7 +2312,7 @@ def html_post_replies(css_cache: {}, False, False, False, False, False, False, cw_lists, lists_enabled, - timezone) + timezone, False) css_filename = base_dir + '/epicyon-profile.css' if os.path.isfile(base_dir + '/epicyon.css'): @@ -2341,7 +2365,7 @@ def html_emoji_reaction_picker(css_cache: {}, theme_name, system_language, max_like_count, False, False, False, False, False, False, - cw_lists, lists_enabled, timezone) + cw_lists, lists_enabled, timezone, False) reactions_filename = base_dir + '/emoji/reactions.json' if not os.path.isfile(reactions_filename): diff --git a/webapp_profile.py b/webapp_profile.py index e4a8d2de6..505c43cd2 100644 --- a/webapp_profile.py +++ b/webapp_profile.py @@ -368,7 +368,7 @@ def html_profile_after_search(css_cache: {}, False, False, False, False, False, False, cw_lists, lists_enabled, - timezone) + timezone, False) i += 1 if i >= 8: break @@ -1125,7 +1125,7 @@ def _html_profile_posts(recent_posts_cache: {}, max_recent_posts: int, False, False, False, True, False, False, cw_lists, lists_enabled, - timezone) + timezone, False) if post_str: profile_str += post_str + separator_str ctr += 1 diff --git a/webapp_search.py b/webapp_search.py index 712c0329c..33b9bca3e 100644 --- a/webapp_search.py +++ b/webapp_search.py @@ -699,7 +699,7 @@ def html_history_search(css_cache: {}, translate: {}, base_dir: str, show_individual_post_icons, False, False, False, False, cw_lists, lists_enabled, - timezone) + timezone, False) if post_str: history_search_form += separator_str + post_str index += 1 @@ -885,7 +885,7 @@ def html_hashtag_search(css_cache: {}, manually_approves_followers, show_public_only, store_to_sache, False, cw_lists, - lists_enabled, timezone) + lists_enabled, timezone, False) if post_str: hashtag_search_form += separator_str + post_str index += 1 diff --git a/webapp_timeline.py b/webapp_timeline.py index 47d18b765..6da01cf05 100644 --- a/webapp_timeline.py +++ b/webapp_timeline.py @@ -906,6 +906,9 @@ def html_timeline(css_cache: {}, default_timeline: str, timeline_start_time, box_name, '11') + mitm = False + if item.get('mitm'): + mitm = True # read the post from disk curr_tl_str = \ individual_post_as_html(signing_priv_key_pem, @@ -932,7 +935,7 @@ def html_timeline(css_cache: {}, default_timeline: str, manually_approve_followers, False, True, use_cache_only, cw_lists, lists_enabled, - timezone) + timezone, mitm) _log_timeline_timing(enable_timing_log, timeline_start_time, box_name, '12')