diff --git a/announce.py b/announce.py index f4c041f93..228295042 100644 --- a/announce.py +++ b/announce.py @@ -187,13 +187,14 @@ def create_announce(session, base_dir: str, federation_list: [], group_account = False if has_users_path(object_url): announce_nickname = get_nickname_from_actor(object_url) - announce_domain, announce_port = get_domain_from_actor(object_url) - if '/' + str(announce_nickname) + '/' in object_url: - announce_actor = \ - object_url.split('/' + announce_nickname + '/')[0] + \ - '/' + announce_nickname - if has_group_type(base_dir, announce_actor, person_cache): - group_account = True + if announce_nickname: + announce_domain, announce_port = get_domain_from_actor(object_url) + if '/' + str(announce_nickname) + '/' in object_url: + announce_actor = \ + object_url.split('/' + announce_nickname + '/')[0] + \ + '/' + announce_nickname + if has_group_type(base_dir, announce_actor, person_cache): + group_account = True if announce_nickname and announce_domain: send_signed_json(new_announce, session, base_dir, diff --git a/availability.py b/availability.py index 4c2528505..fdb913749 100644 --- a/availability.py +++ b/availability.py @@ -68,6 +68,8 @@ def outbox_availability(base_dir: str, nickname: str, message_json: {}, return False actor_nickname = get_nickname_from_actor(message_json['actor']) + if not actor_nickname: + return False if actor_nickname != nickname: return False domain, _ = get_domain_from_actor(message_json['actor']) diff --git a/bookmarks.py b/bookmarks.py index b2399c8d2..5ee5478d9 100644 --- a/bookmarks.py +++ b/bookmarks.py @@ -46,6 +46,8 @@ def undo_bookmarks_collection_entry(recent_posts_cache: {}, # remove any cached version of this post so that the # bookmark icon is changed nickname = get_nickname_from_actor(actor) + if not nickname: + return cached_post_filename = \ get_cached_post_filename(base_dir, nickname, domain, post_json_object) @@ -166,6 +168,8 @@ def update_bookmarks_collection(recent_posts_cache: {}, # remove any cached version of this post so that the # bookmark icon is changed nickname = get_nickname_from_actor(actor) + if not nickname: + return cached_post_filename = \ get_cached_post_filename(base_dir, nickname, domain, post_json_object) diff --git a/content.py b/content.py index 5bebdb0de..134d32619 100644 --- a/content.py +++ b/content.py @@ -7,6 +7,8 @@ __email__ = "bob@libreserver.org" __status__ = "Production" __module_group__ = "Core" +import math +import html import os import email.parser import urllib.parse @@ -701,7 +703,7 @@ def replace_content_duplicates(content: str) -> str: return content -def remove_text_formatting(content: str) -> str: +def remove_text_formatting(content: str, bold_reading: bool) -> str: """Removes markup for bold, italics, etc """ if is_pgp_encrypted(content) or contains_pgp_public_key(content): @@ -709,6 +711,9 @@ def remove_text_formatting(content: str) -> str: if '<' not in content: return content for markup in REMOVE_MARKUP: + if bold_reading: + if markup == 'b': + continue content = content.replace('<' + markup + '>', '') content = content.replace('', '') content = content.replace('<' + markup.upper() + '>', '') @@ -1323,3 +1328,62 @@ def contains_invalid_local_links(content: str) -> bool: if '?' + inv_str + '=' in content: return True return False + + +def bold_reading_string(text: str) -> str: + """Returns bold reading formatted text + """ + text = html.unescape(text) + add_paragraph_markup = False + if '

' in text: + text = text.replace('

', '\n').replace('

', '') + add_paragraph_markup = True + paragraphs = text.split('\n') + parag_ctr = 0 + new_text = '' + for parag in paragraphs: + words = parag.split(' ') + new_parag = '' + reading_markup = False + for wrd in words: + if '<' in wrd: + reading_markup = True + if reading_markup and '>' in wrd: + reading_markup = False + wrd_len = len(wrd) + if not reading_markup and wrd_len > 1 and \ + '<' not in wrd and '>' not in wrd and \ + '&' not in wrd and '=' not in wrd and \ + not wrd.startswith(':'): + + prefix = '' + postfix = '' + if wrd.startswith('"'): + prefix = '"' + wrd = wrd[1:] + if wrd.endswith('"'): + postfix = '"' + wrd = wrd[:wrd_len - 1] + + initial_chars = int(math.ceil(wrd_len / 2.0)) + new_parag += \ + prefix + '' + wrd[:initial_chars] + '' + \ + wrd[initial_chars:] + postfix + ' ' + else: + new_parag += wrd + ' ' + parag_ctr += 1 + new_parag = new_parag.strip() + if not new_parag: + continue + if parag_ctr < len(paragraphs): + if not add_paragraph_markup: + new_text += new_parag + '\n' + else: + new_text += '

' + new_parag + '

' + else: + if not add_paragraph_markup: + new_text += new_parag + else: + new_text += '

' + new_parag + '

' + + return new_text diff --git a/daemon.py b/daemon.py index 1c3d22acb..018dd4a3a 100644 --- a/daemon.py +++ b/daemon.py @@ -283,6 +283,7 @@ from utils import get_occupation_skills from utils import get_occupation_name from utils import set_occupation_name from utils import load_translations_from_file +from utils import load_bold_reading from utils import get_local_network_addresses from utils import decoded_host from utils import is_public_post @@ -2195,18 +2196,24 @@ class PubServer(BaseHTTPRequestHandler): if '/@' in search_handle: search_nickname = \ get_nickname_from_actor(search_handle) - search_domain, _ = \ - get_domain_from_actor(search_handle) - search_handle = \ - search_nickname + '@' + search_domain - if '@' not in search_handle: - if search_handle.startswith('http'): - search_nickname = \ - get_nickname_from_actor(search_handle) + if search_nickname: search_domain, _ = \ get_domain_from_actor(search_handle) search_handle = \ search_nickname + '@' + search_domain + else: + search_handle = None + if '@' not in search_handle: + if search_handle.startswith('http'): + search_nickname = \ + get_nickname_from_actor(search_handle) + if search_nickname: + search_domain, _ = \ + get_domain_from_actor(search_handle) + search_handle = \ + search_nickname + '@' + search_domain + else: + search_handle = None if '@' not in search_handle: # is this a local nickname on this instance? local_handle = \ @@ -2234,11 +2241,12 @@ class PubServer(BaseHTTPRequestHandler): self.server.translate, base_dir, http_prefix, nickname) - msg = msg.encode('utf-8') - msglen = len(msg) - self._login_headers('text/html', - msglen, calling_domain) - self._write(msg) + if msg: + msg = msg.encode('utf-8') + msglen = len(msg) + self._login_headers('text/html', + msglen, calling_domain) + self._write(msg) self.server.postreq_busy = False return elif moderation_str.startswith('submitBlock'): @@ -3027,6 +3035,11 @@ class PubServer(BaseHTTPRequestHandler): custom_submit_text = get_config_param(base_dir, 'customSubmitText') conversation_id = None reply_is_chat = False + + bold_reading = False + if self.server.bold_reading.get(chooser_nickname): + bold_reading = True + msg = html_new_post(self.server.css_cache, False, self.server.translate, base_dir, @@ -3062,7 +3075,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.cw_lists, self.server.lists_enabled, self.server.default_timeline, - reply_is_chat).encode('utf-8') + reply_is_chat, + bold_reading).encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, cookie, calling_domain, False) @@ -3088,11 +3102,13 @@ class PubServer(BaseHTTPRequestHandler): options_actor, self.server.debug, self.server.system_language, - signing_priv_key_pem).encode('utf-8') - msglen = len(msg) - self._set_headers('text/html', msglen, - cookie, calling_domain, False) - self._write(msg) + signing_priv_key_pem) + if msg: + msg = msg.encode('utf-8') + msglen = len(msg) + self._set_headers('text/html', msglen, + cookie, calling_domain, False) + self._write(msg) self.server.postreq_busy = False return else: @@ -3164,6 +3180,11 @@ class PubServer(BaseHTTPRequestHandler): custom_submit_text = get_config_param(base_dir, 'customSubmitText') conversation_id = None reply_is_chat = False + + bold_reading = False + if self.server.bold_reading.get(chooser_nickname): + bold_reading = True + msg = html_new_post(self.server.css_cache, False, self.server.translate, base_dir, @@ -3198,7 +3219,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.cw_lists, self.server.lists_enabled, self.server.default_timeline, - reply_is_chat).encode('utf-8') + reply_is_chat, + bold_reading).encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, cookie, calling_domain, False) @@ -3227,6 +3249,11 @@ class PubServer(BaseHTTPRequestHandler): users_path = path.split('/unfollowconfirm')[0] origin_path_str = http_prefix + '://' + domain_full + users_path follower_nickname = get_nickname_from_actor(origin_path_str) + if not follower_nickname: + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return length = int(self.headers['Content-length']) @@ -3257,6 +3284,11 @@ class PubServer(BaseHTTPRequestHandler): if '&' in following_actor: following_actor = following_actor.split('&')[0] following_nickname = get_nickname_from_actor(following_actor) + if not following_nickname: + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return following_domain, following_port = \ get_domain_from_actor(following_actor) following_domain_full = \ @@ -3318,6 +3350,11 @@ class PubServer(BaseHTTPRequestHandler): users_path = path.split('/followconfirm')[0] origin_path_str = http_prefix + '://' + domain_full + users_path follower_nickname = get_nickname_from_actor(origin_path_str) + if not follower_nickname: + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return length = int(self.headers['Content-length']) @@ -3358,6 +3395,11 @@ class PubServer(BaseHTTPRequestHandler): if '&' in following_actor: following_actor = following_actor.split('&')[0] following_nickname = get_nickname_from_actor(following_actor) + if not following_nickname: + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return following_domain, following_port = \ get_domain_from_actor(following_actor) if follower_nickname == following_nickname and \ @@ -3664,11 +3706,20 @@ class PubServer(BaseHTTPRequestHandler): search_str = ':' + search_str + ':' if search_str.startswith('#'): nickname = get_nickname_from_actor(actor_str) + if not nickname: + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return + # hashtag search timezone = None if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True hashtag_str = \ html_hashtag_search(self.server.css_cache, nickname, domain, port, @@ -3694,7 +3745,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) if hashtag_str: msg = hashtag_str.encode('utf-8') msglen = len(msg) @@ -3761,11 +3812,19 @@ class PubServer(BaseHTTPRequestHandler): break # your post history search nickname = get_nickname_from_actor(actor_str) + if not nickname: + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return search_str = search_str.replace("'", '', 1).strip() timezone = None if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True history_str = \ html_history_search(self.server.css_cache, self.server.translate, @@ -3794,7 +3853,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) if history_str: msg = history_str.encode('utf-8') msglen = len(msg) @@ -3834,11 +3893,19 @@ class PubServer(BaseHTTPRequestHandler): break # bookmark search nickname = get_nickname_from_actor(actor_str) + if not nickname: + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return search_str = search_str.replace('-', '', 1).strip() timezone = None if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True bookmarks_str = \ html_history_search(self.server.css_cache, self.server.translate, @@ -3867,7 +3934,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) if bookmarks_str: msg = bookmarks_str.encode('utf-8') msglen = len(msg) @@ -3890,6 +3957,11 @@ class PubServer(BaseHTTPRequestHandler): return # profile search nickname = get_nickname_from_actor(actor_str) + if not nickname: + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return profile_path_str = path.replace('/searchhandle', '') # are we already following the searched for handle? @@ -3897,6 +3969,11 @@ class PubServer(BaseHTTPRequestHandler): # get the actor if not has_users_path(search_str): search_nickname = get_nickname_from_actor(search_str) + if not search_nickname: + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return search_domain, search_port = \ get_domain_from_actor(search_str) search_domain_full = \ @@ -3991,6 +4068,10 @@ class PubServer(BaseHTTPRequestHandler): self.server.postreq_busy = False return + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True + profile_str = \ html_profile_after_search(self.server.css_cache, recent_posts_cache, @@ -4023,7 +4104,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.lists_enabled, timezone, self.server.onion_domain, - self.server.i2p_domain) + self.server.i2p_domain, + bold_reading) if profile_str: msg = profile_str.encode('utf-8') msglen = len(msg) @@ -4310,6 +4392,11 @@ class PubServer(BaseHTTPRequestHandler): local_actor_url(http_prefix, admin_nickname, domain_full) actor = origin_path_str actor_nickname = get_nickname_from_actor(actor) + if not actor_nickname: + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return if actor == share_actor or actor == admin_actor or \ is_moderator(base_dir, actor_nickname): item_id = remove_share_confirm_params.split('itemID=')[1] @@ -4378,6 +4465,11 @@ class PubServer(BaseHTTPRequestHandler): local_actor_url(http_prefix, admin_nickname, domain_full) actor = origin_path_str actor_nickname = get_nickname_from_actor(actor) + if not actor_nickname: + self.send_response(400) + self.end_headers() + self.server.postreq_busy = False + return if actor == share_actor or actor == admin_actor or \ is_moderator(base_dir, actor_nickname): item_id = remove_share_confirm_params.split('itemID=')[1] @@ -4921,6 +5013,9 @@ class PubServer(BaseHTTPRequestHandler): users_path = path.replace('/citationsdata', '') actor_str = self._get_instance_url(calling_domain) + users_path nickname = get_nickname_from_actor(actor_str) + if not nickname: + self.server.postreq_busy = False + return citations_filename = \ acct_dir(base_dir, nickname, domain) + '/.citations.txt' @@ -6587,6 +6682,33 @@ class PubServer(BaseHTTPRequestHandler): 'unable to delete ' + hide_reaction_button_file) + # bold reading checkbox + bold_reading_filename = \ + acct_dir(base_dir, nickname, domain) + \ + '/.boldReading' + bold_reading = False + if fields.get('boldReading'): + if fields['boldReading'] == 'on': + bold_reading = True + self.server.bold_reading[nickname] = True + try: + with open(bold_reading_filename, + 'w+') as rfile: + rfile.write('\n') + except OSError: + print('EX: unable to write bold reading ' + + bold_reading_filename) + if not bold_reading: + if self.server.bold_reading.get(nickname): + del self.server.bold_reading[nickname] + if os.path.isfile(bold_reading_filename): + try: + os.remove(bold_reading_filename) + except OSError: + print('EX: _profile_edit ' + + 'unable to delete ' + + bold_reading_filename) + # notify about new Likes if on_final_welcome_screen: # default setting from welcome screen @@ -7764,13 +7886,17 @@ class PubServer(BaseHTTPRequestHandler): self.server.text_mode_banner, self.server.news_instance, authorized, - access_keys, is_group).encode('utf-8') - msglen = len(msg) - self._set_headers('text/html', msglen, - cookie, calling_domain, False) - self._write(msg) - fitness_performance(getreq_start_time, self.server.fitness, - '_GET', '_show_person_options', debug) + access_keys, is_group) + if msg: + msg = msg.encode('utf-8') + msglen = len(msg) + self._set_headers('text/html', msglen, + cookie, calling_domain, False) + self._write(msg) + fitness_performance(getreq_start_time, self.server.fitness, + '_GET', '_show_person_options', debug) + else: + self._404() return if '/users/news/' in path: @@ -8132,6 +8258,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True hashtag_str = \ html_hashtag_search(self.server.css_cache, nickname, domain, port, @@ -8156,7 +8285,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) if hashtag_str: msg = hashtag_str.encode('utf-8') msglen = len(msg) @@ -8373,6 +8502,9 @@ class PubServer(BaseHTTPRequestHandler): if os.path.isfile(announce_filename.replace('.json', '') + '.mitm'): mitm = True + bold_reading = False + if self.server.bold_reading.get(self.post_to_nickname): + bold_reading = True individual_post_as_html(self.server.signing_priv_key_pem, False, self.server.recent_posts_cache, self.server.max_recent_posts, @@ -8401,7 +8533,7 @@ class PubServer(BaseHTTPRequestHandler): False, True, False, self.server.cw_lists, self.server.lists_enabled, - timezone, mitm) + timezone, mitm, bold_reading) actor_absolute = self._get_instance_url(calling_domain) + actor actor_path_str = \ @@ -8544,6 +8676,9 @@ class PubServer(BaseHTTPRequestHandler): following_handle = path.split('/followapprove=')[1] if '://' in following_handle: handle_nickname = get_nickname_from_actor(following_handle) + if not handle_nickname: + self._404() + return handle_domain, handle_port = \ get_domain_from_actor(following_handle) following_handle = \ @@ -8730,6 +8865,9 @@ class PubServer(BaseHTTPRequestHandler): following_handle = path.split('/followdeny=')[1] if '://' in following_handle: handle_nickname = get_nickname_from_actor(following_handle) + if not handle_nickname: + self._404() + return handle_domain, handle_port = \ get_domain_from_actor(following_handle) following_handle = \ @@ -8908,6 +9046,9 @@ class PubServer(BaseHTTPRequestHandler): if os.path.isfile(liked_post_filename.replace('.json', '') + '.mitm'): mitm = True + bold_reading = False + if self.server.bold_reading.get(self.post_to_nickname): + bold_reading = True individual_post_as_html(self.server.signing_priv_key_pem, False, self.server.recent_posts_cache, @@ -8938,7 +9079,7 @@ class PubServer(BaseHTTPRequestHandler): False, True, False, self.server.cw_lists, self.server.lists_enabled, - timezone, mitm) + timezone, mitm, bold_reading) else: print('WARN: Liked post not found: ' + liked_post_filename) # clear the icon from the cache so that it gets updated @@ -9090,6 +9231,9 @@ class PubServer(BaseHTTPRequestHandler): if os.path.isfile(liked_post_filename.replace('.json', '') + '.mitm'): mitm = True + bold_reading = False + if self.server.bold_reading.get(self.post_to_nickname): + bold_reading = True individual_post_as_html(self.server.signing_priv_key_pem, False, self.server.recent_posts_cache, @@ -9120,7 +9264,7 @@ class PubServer(BaseHTTPRequestHandler): False, True, False, self.server.cw_lists, self.server.lists_enabled, - timezone, mitm) + timezone, mitm, bold_reading) else: print('WARN: Unliked post not found: ' + liked_post_filename) # clear the icon from the cache so that it gets updated @@ -9301,6 +9445,9 @@ class PubServer(BaseHTTPRequestHandler): if os.path.isfile(reaction_post_filename.replace('.json', '') + '.mitm'): mitm = True + bold_reading = False + if self.server.bold_reading.get(self.post_to_nickname): + bold_reading = True individual_post_as_html(self.server.signing_priv_key_pem, False, self.server.recent_posts_cache, @@ -9331,7 +9478,7 @@ class PubServer(BaseHTTPRequestHandler): False, True, False, self.server.cw_lists, self.server.lists_enabled, - timezone, mitm) + timezone, mitm, bold_reading) else: print('WARN: Emoji reaction post not found: ' + reaction_post_filename) @@ -9502,6 +9649,9 @@ class PubServer(BaseHTTPRequestHandler): if os.path.isfile(reaction_post_filename.replace('.json', '') + '.mitm'): mitm = True + bold_reading = False + if self.server.bold_reading.get(self.post_to_nickname): + bold_reading = True individual_post_as_html(self.server.signing_priv_key_pem, False, self.server.recent_posts_cache, @@ -9532,7 +9682,7 @@ class PubServer(BaseHTTPRequestHandler): False, True, False, self.server.cw_lists, self.server.lists_enabled, - timezone, mitm) + timezone, mitm, bold_reading) else: print('WARN: Unreaction post not found: ' + reaction_post_filename) @@ -9609,6 +9759,11 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(self.post_to_nickname): timezone = \ self.server.account_timezone.get(self.post_to_nickname) + + bold_reading = False + if self.server.bold_reading.get(self.post_to_nickname): + bold_reading = True + msg = \ html_emoji_reaction_picker(self.server.css_cache, self.server.recent_posts_cache, @@ -9634,7 +9789,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.cw_lists, self.server.lists_enabled, timeline_str, page_number, - timezone) + timezone, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -9753,6 +9908,9 @@ class PubServer(BaseHTTPRequestHandler): if os.path.isfile(bookmark_filename.replace('.json', '') + '.mitm'): mitm = True + bold_reading = False + if self.server.bold_reading.get(self.post_to_nickname): + bold_reading = True individual_post_as_html(self.server.signing_priv_key_pem, False, self.server.recent_posts_cache, @@ -9783,7 +9941,7 @@ class PubServer(BaseHTTPRequestHandler): False, True, False, self.server.cw_lists, self.server.lists_enabled, - timezone, mitm) + timezone, mitm, bold_reading) else: print('WARN: Bookmarked post not found: ' + bookmark_filename) # self._post_to_outbox(bookmark_json, @@ -9909,6 +10067,9 @@ class PubServer(BaseHTTPRequestHandler): if os.path.isfile(bookmark_filename.replace('.json', '') + '.mitm'): mitm = True + bold_reading = False + if self.server.bold_reading.get(self.post_to_nickname): + bold_reading = True individual_post_as_html(self.server.signing_priv_key_pem, False, self.server.recent_posts_cache, @@ -9939,7 +10100,7 @@ class PubServer(BaseHTTPRequestHandler): False, True, False, self.server.cw_lists, self.server.lists_enabled, - timezone, mitm) + timezone, mitm, bold_reading) else: print('WARN: Unbookmarked post not found: ' + bookmark_filename) @@ -10029,7 +10190,8 @@ class PubServer(BaseHTTPRequestHandler): return delete_str = \ - html_confirm_delete(self.server.css_cache, + html_confirm_delete(self.server, + self.server.css_cache, self.server.recent_posts_cache, self.server.max_recent_posts, self.server.translate, page_number, @@ -10102,6 +10264,9 @@ class PubServer(BaseHTTPRequestHandler): actor = \ http_prefix + '://' + domain_full + path.split('?mute=')[0] nickname = get_nickname_from_actor(actor) + if not nickname: + self._404() + return mute_post(base_dir, nickname, domain, port, http_prefix, mute_url, self.server.recent_posts_cache, debug) @@ -10138,6 +10303,9 @@ class PubServer(BaseHTTPRequestHandler): if os.path.isfile(mute_filename.replace('.json', '') + '.mitm'): mitm = True + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True individual_post_as_html(self.server.signing_priv_key_pem, allow_downloads, self.server.recent_posts_cache, @@ -10169,7 +10337,7 @@ class PubServer(BaseHTTPRequestHandler): use_cache_only, self.server.cw_lists, self.server.lists_enabled, - timezone, mitm) + timezone, mitm, bold_reading) else: print('WARN: Muted post not found: ' + mute_filename) @@ -10223,6 +10391,9 @@ class PubServer(BaseHTTPRequestHandler): actor = \ http_prefix + '://' + domain_full + path.split('?unmute=')[0] nickname = get_nickname_from_actor(actor) + if not nickname: + self._404() + return unmute_post(base_dir, nickname, domain, port, http_prefix, mute_url, self.server.recent_posts_cache, debug) @@ -10259,6 +10430,9 @@ class PubServer(BaseHTTPRequestHandler): if os.path.isfile(mute_filename.replace('.json', '') + '.mitm'): mitm = True + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True individual_post_as_html(self.server.signing_priv_key_pem, allow_downloads, self.server.recent_posts_cache, @@ -10290,7 +10464,7 @@ class PubServer(BaseHTTPRequestHandler): use_cache_only, self.server.cw_lists, self.server.lists_enabled, - timezone, mitm) + timezone, mitm, bold_reading) else: print('WARN: Unmuted post not found: ' + mute_filename) if calling_domain.endswith('.onion') and onion_domain: @@ -10391,6 +10565,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_post_replies(self.server.css_cache, recent_posts_cache, @@ -10417,7 +10594,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -10493,6 +10670,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_post_replies(self.server.css_cache, recent_posts_cache, @@ -10519,7 +10699,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -10608,6 +10788,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_profile(self.server.signing_priv_key_pem, self.server.rss_icon_at_top, @@ -10641,7 +10824,7 @@ class PubServer(BaseHTTPRequestHandler): None, None, self.server.cw_lists, self.server.lists_enabled, self.server.content_license_url, - timezone) + timezone, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -10737,6 +10920,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nick): timezone = \ self.server.account_timezone.get(nick) + bold_reading = False + if self.server.bold_reading.get(nick): + bold_reading = True msg = \ html_profile(signing_priv_key_pem, self.server.rss_icon_at_top, @@ -10771,7 +10957,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.cw_lists, self.server.lists_enabled, content_license_url, - timezone) + timezone, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -10911,6 +11097,10 @@ class PubServer(BaseHTTPRequestHandler): post_url = post_url.split('?')[0] post_url = post_url.replace('--', '/') + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True + msg = \ html_likers_of_post(base_dir, nickname, domain, port, post_url, self.server.translate, @@ -10933,7 +11123,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - 'inbox', self.server.default_timeline) + 'inbox', self.server.default_timeline, + bold_reading) if not msg: self._404() return True @@ -10972,6 +11163,10 @@ class PubServer(BaseHTTPRequestHandler): post_url = post_url.split('?')[0] post_url = post_url.replace('--', '/') + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True + # note that the likers function is reused, but with 'shares' msg = \ html_likers_of_post(base_dir, nickname, domain, port, @@ -10996,7 +11191,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.cw_lists, self.server.lists_enabled, 'inbox', self.server.default_timeline, - 'shares') + bold_reading, 'shares') if not msg: self._404() return True @@ -11050,10 +11245,16 @@ 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 + + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True + msg = \ html_individual_post(self.server.css_cache, self.server.recent_posts_cache, @@ -11080,7 +11281,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone, mitm) + timezone, mitm, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -11324,6 +11525,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = html_inbox(self.server.css_cache, default_timeline, recent_posts_cache, @@ -11364,7 +11568,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) if getreq_start_time: fitness_performance(getreq_start_time, self.server.fitness, @@ -11492,6 +11696,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_inbox_dms(self.server.css_cache, self.server.default_timeline, @@ -11532,7 +11739,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -11649,6 +11856,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_inbox_replies(self.server.css_cache, self.server.default_timeline, @@ -11689,7 +11899,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -11803,6 +12013,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_inbox_media(self.server.css_cache, self.server.default_timeline, @@ -11844,7 +12057,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -11958,6 +12171,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_inbox_blogs(self.server.css_cache, self.server.default_timeline, @@ -11999,7 +12215,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -12121,6 +12337,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_inbox_news(self.server.css_cache, self.server.default_timeline, @@ -12163,7 +12382,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -12288,6 +12507,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_inbox_features(self.server.css_cache, self.server.default_timeline, @@ -12330,7 +12552,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -12409,6 +12631,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_shares(self.server.css_cache, self.server.default_timeline, @@ -12446,7 +12671,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.shared_items_federated_domains, self.server.signing_priv_key_pem, self.server.cw_lists, - self.server.lists_enabled, timezone) + self.server.lists_enabled, timezone, + bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -12499,6 +12725,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_wanted(self.server.css_cache, self.server.default_timeline, @@ -12537,7 +12766,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -12630,6 +12859,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_bookmarks(self.server.css_cache, self.server.default_timeline, @@ -12671,7 +12903,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -12780,6 +13012,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_outbox(self.server.css_cache, self.server.default_timeline, @@ -12819,7 +13054,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -12924,6 +13159,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_moderation(self.server.css_cache, self.server.default_timeline, @@ -12964,7 +13202,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - timezone) + timezone, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -13067,6 +13305,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_profile(self.server.signing_priv_key_pem, self.server.rss_icon_at_top, @@ -13102,7 +13343,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.cw_lists, self.server.lists_enabled, self.server.content_license_url, - timezone) + timezone, bold_reading) msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, @@ -13203,6 +13444,9 @@ class PubServer(BaseHTTPRequestHandler): self.server.content_license_url shared_items_federated_domains = \ self.server.shared_items_federated_domains + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_profile(self.server.signing_priv_key_pem, self.server.rss_icon_at_top, @@ -13239,7 +13483,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.cw_lists, self.server.lists_enabled, content_license_url, - timezone).encode('utf-8') + timezone, bold_reading).encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, cookie, calling_domain, False) @@ -13338,6 +13582,9 @@ class PubServer(BaseHTTPRequestHandler): self.server.content_license_url shared_items_federated_domains = \ self.server.shared_items_federated_domains + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_profile(self.server.signing_priv_key_pem, self.server.rss_icon_at_top, @@ -13375,7 +13622,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.cw_lists, self.server.lists_enabled, content_license_url, - timezone).encode('utf-8') + timezone, bold_reading).encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, cookie, calling_domain, False) @@ -13499,6 +13746,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.account_timezone.get(nickname): timezone = \ self.server.account_timezone.get(nickname) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True msg = \ html_profile(self.server.signing_priv_key_pem, self.server.rss_icon_at_top, @@ -13531,7 +13781,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.cw_lists, self.server.lists_enabled, self.server.content_license_url, - timezone).encode('utf-8') + timezone, bold_reading).encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, cookie, calling_domain, False) @@ -13814,6 +14064,9 @@ class PubServer(BaseHTTPRequestHandler): """Shows a QR code for an account """ nickname = get_nickname_from_actor(path) + if not nickname: + self._404() + return True if onion_domain: qrcode_domain = onion_domain port = 80 @@ -13863,6 +14116,9 @@ class PubServer(BaseHTTPRequestHandler): """Shows a banner image on the search screen """ nickname = get_nickname_from_actor(path) + if not nickname: + self._404() + return True banner_filename = \ acct_dir(base_dir, nickname, domain) + '/search_banner.png' if not os.path.isfile(banner_filename): @@ -14253,7 +14509,9 @@ class PubServer(BaseHTTPRequestHandler): break if is_new_post_endpoint: nickname = get_nickname_from_actor(path) - + if not nickname: + self._404() + return True if in_reply_to_url: reply_interval_hours = self.server.default_reply_interval_hrs if not can_reply_to(base_dir, nickname, domain, @@ -14279,6 +14537,10 @@ class PubServer(BaseHTTPRequestHandler): if reply_post_filename: post_json_object = load_json(reply_post_filename) + bold_reading = False + if self.server.bold_reading.get(nickname): + bold_reading = True + msg = html_new_post(self.server.css_cache, media_instance, translate, @@ -14316,7 +14578,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.cw_lists, self.server.lists_enabled, self.server.default_timeline, - reply_is_chat).encode('utf-8') + reply_is_chat, + bold_reading).encode('utf-8') if not msg: print('Error replying to ' + in_reply_to_url) self._404() @@ -14384,7 +14647,7 @@ class PubServer(BaseHTTPRequestHandler): access_keys = self.server.key_shortcuts[nickname] default_reply_interval_hrs = self.server.default_reply_interval_hrs - msg = html_edit_profile(self.server.css_cache, + msg = html_edit_profile(self.server, self.server.css_cache, translate, base_dir, path, domain, @@ -14400,8 +14663,9 @@ class PubServer(BaseHTTPRequestHandler): access_keys, default_reply_interval_hrs, self.server.cw_lists, - self.server.lists_enabled).encode('utf-8') + self.server.lists_enabled) if msg: + msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, cookie, calling_domain, False) @@ -14433,8 +14697,9 @@ class PubServer(BaseHTTPRequestHandler): port, http_prefix, self.server.default_timeline, - theme, access_keys).encode('utf-8') + theme, access_keys) if msg: + msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, cookie, calling_domain, False) @@ -14467,8 +14732,9 @@ class PubServer(BaseHTTPRequestHandler): http_prefix, self.server.default_timeline, self.server.theme_name, - access_keys).encode('utf-8') + access_keys) if msg: + msg = msg.encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, cookie, calling_domain, False) @@ -15807,6 +16073,9 @@ class PubServer(BaseHTTPRequestHandler): if html_getreq and authorized and users_in_path and \ self.path.endswith('/followingaccounts'): nickname = get_nickname_from_actor(self.path) + if not nickname: + self._404() + return following_filename = \ acct_dir(self.server.base_dir, nickname, self.server.domain) + '/following.txt' @@ -16571,14 +16840,16 @@ class PubServer(BaseHTTPRequestHandler): self.server.default_timeline, self.server.theme_name, self.server.text_mode_banner, - access_keys).encode('utf-8') - msglen = len(msg) - self._set_headers('text/html', msglen, cookie, calling_domain, - False) - self._write(msg) - fitness_performance(getreq_start_time, self.server.fitness, - '_GET', 'search screen shown', - self.server.debug) + access_keys) + if msg: + msg = msg.encode('utf-8') + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, + calling_domain, False) + self._write(msg) + fitness_performance(getreq_start_time, self.server.fitness, + '_GET', 'search screen shown', + self.server.debug) self.server.getreq_busy = False return @@ -16625,20 +16896,24 @@ class PubServer(BaseHTTPRequestHandler): self.server.domain_full, self.server.text_mode_banner, access_keys, - False).encode('utf-8') - msglen = len(msg) - if 'ical=true' in self.path: - self._set_headers('text/calendar', - msglen, cookie, calling_domain, - False) + False) + if msg: + msg = msg.encode('utf-8') + msglen = len(msg) + if 'ical=true' in self.path: + self._set_headers('text/calendar', + msglen, cookie, calling_domain, + False) + else: + self._set_headers('text/html', + msglen, cookie, calling_domain, + False) + self._write(msg) + fitness_performance(getreq_start_time, self.server.fitness, + '_GET', 'calendar shown', + self.server.debug) else: - self._set_headers('text/html', - msglen, cookie, calling_domain, - False) - self._write(msg) - fitness_performance(getreq_start_time, self.server.fitness, - '_GET', 'calendar shown', - self.server.debug) + self._404() self.server.getreq_busy = False return @@ -17210,6 +17485,10 @@ class PubServer(BaseHTTPRequestHandler): if ';' in actor: actor = actor.split(';')[0] nickname = get_nickname_from_actor(self.path.split('?')[0]) + if not nickname: + self._404() + self.server.getreq_busy = False + return if nickname == actor: post_url = \ local_actor_url(self.server.http_prefix, nickname, @@ -17712,11 +17991,12 @@ class PubServer(BaseHTTPRequestHandler): self.server.debug, self.server.system_language, self.server.signing_priv_key_pem) - msg = msg.encode('utf-8') - msglen = len(msg) - self._login_headers('text/html', - msglen, calling_domain) - self._write(msg) + if msg: + msg = msg.encode('utf-8') + msglen = len(msg) + self._login_headers('text/html', + msglen, calling_domain) + self._write(msg) self.server.getreq_busy = False return @@ -17749,11 +18029,12 @@ class PubServer(BaseHTTPRequestHandler): self.server.debug, self.server.system_language, self.server.signing_priv_key_pem) - msg = msg.encode('utf-8') - msglen = len(msg) - self._login_headers('text/html', - msglen, calling_domain) - self._write(msg) + if msg: + msg = msg.encode('utf-8') + msglen = len(msg) + self._login_headers('text/html', + msglen, calling_domain) + self._write(msg) self.server.getreq_busy = False return @@ -20413,6 +20694,9 @@ def run_daemon(crawlers_allowed: [], # scan the theme directory for any svg files containing scripts assert not scan_themes_for_scripts(base_dir) + # for each account, whether bold reading is enabled + httpd.bold_reading = load_bold_reading(base_dir) + httpd.account_timezone = load_account_timezones(base_dir) httpd.post_to_nickname = None diff --git a/desktop_client.py b/desktop_client.py index 35d83f535..acd8dc95d 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -683,7 +683,7 @@ def _read_local_box_post(session, nickname: str, domain: str, translate: {}, your_actor: str, domain_full: str, person_cache: {}, signing_priv_key_pem: str, - blocked_cache: {}) -> {}: + blocked_cache: {}, bold_reading: bool) -> {}: """Reads a post from the given timeline Returns the post json """ @@ -724,7 +724,7 @@ def _read_local_box_post(session, nickname: str, domain: str, system_language, domain_full, person_cache, signing_priv_key_pem, - blocked_cache) + blocked_cache, bold_reading) if post_json_object2: if has_object_dict(post_json_object2): if post_json_object2['object'].get('attributedTo') and \ @@ -1356,6 +1356,8 @@ def run_desktop_client(base_dir: str, proxy_type: str, http_prefix: str, """Runs the desktop and screen reader client, which announces new inbox items """ + bold_reading = False + # TODO: this should probably be retrieved somehow from the server signing_priv_key_pem = None @@ -1674,7 +1676,7 @@ def run_desktop_client(base_dir: str, proxy_type: str, http_prefix: str, espeak, translate, your_actor, domain_full, person_cache, signing_priv_key_pem, - blocked_cache) + blocked_cache, bold_reading) print('') say_str = 'Press Enter to continue...' say_str2 = _highlight_text(say_str) @@ -2464,7 +2466,8 @@ def run_desktop_client(base_dir: str, proxy_type: str, http_prefix: str, system_language, domain_full, person_cache, signing_priv_key_pem, - blocked_cache) + blocked_cache, + bold_reading) if post_json_object2: post_json_object = post_json_object2 if post_json_object: diff --git a/inbox.py b/inbox.py index 2aeb4df21..87a6f16f3 100644 --- a/inbox.py +++ b/inbox.py @@ -297,7 +297,8 @@ def _inbox_store_post_to_html_cache(recent_posts_cache: {}, cw_lists: {}, lists_enabled: str, timezone: str, - mitm: bool) -> None: + mitm: bool, + bold_reading: bool) -> None: """Converts the json post into html and stores it in a cache This enables the post to be quickly displayed later """ @@ -322,7 +323,8 @@ 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, mitm) + cw_lists, lists_enabled, timezone, mitm, + bold_reading) def valid_inbox(base_dir: str, nickname: str, domain: str) -> bool: @@ -1047,7 +1049,8 @@ def _receive_like(recent_posts_cache: {}, allow_local_network_access: bool, theme_name: str, system_language: str, max_like_count: int, cw_lists: {}, - lists_enabled: str) -> bool: + lists_enabled: str, + bold_reading: bool) -> bool: """Receives a Like activity within the POST section of HTTPServer """ if message_json['type'] != 'Like': @@ -1155,7 +1158,8 @@ def _receive_like(recent_posts_cache: {}, show_individual_post_icons, manually_approve_followers, False, True, False, cw_lists, - lists_enabled, timezone, mitm) + lists_enabled, timezone, mitm, + bold_reading) return True @@ -1174,7 +1178,8 @@ def _receive_undo_like(recent_posts_cache: {}, allow_local_network_access: bool, theme_name: str, system_language: str, max_like_count: int, cw_lists: {}, - lists_enabled: str) -> bool: + lists_enabled: str, + bold_reading: bool) -> bool: """Receives an undo like activity within the POST section of HTTPServer """ if message_json['type'] != 'Undo': @@ -1272,7 +1277,8 @@ def _receive_undo_like(recent_posts_cache: {}, show_individual_post_icons, manually_approve_followers, False, True, False, cw_lists, - lists_enabled, timezone, mitm) + lists_enabled, timezone, mitm, + bold_reading) return True @@ -1292,7 +1298,7 @@ def _receive_reaction(recent_posts_cache: {}, allow_local_network_access: bool, theme_name: str, system_language: str, max_like_count: int, cw_lists: {}, - lists_enabled: str) -> bool: + lists_enabled: str, bold_reading: bool) -> bool: """Receives an emoji reaction within the POST section of HTTPServer """ if message_json['type'] != 'EmojiReact': @@ -1422,7 +1428,8 @@ def _receive_reaction(recent_posts_cache: {}, show_individual_post_icons, manually_approve_followers, False, True, False, cw_lists, - lists_enabled, timezone, mitm) + lists_enabled, timezone, mitm, + bold_reading) return True @@ -1443,7 +1450,8 @@ def _receive_undo_reaction(recent_posts_cache: {}, allow_local_network_access: bool, theme_name: str, system_language: str, max_like_count: int, cw_lists: {}, - lists_enabled: str) -> bool: + lists_enabled: str, + bold_reading: bool) -> bool: """Receives an undo emoji reaction within the POST section of HTTPServer """ if message_json['type'] != 'Undo': @@ -1559,7 +1567,8 @@ def _receive_undo_reaction(recent_posts_cache: {}, show_individual_post_icons, manually_approve_followers, False, True, False, cw_lists, - lists_enabled, timezone, mitm) + lists_enabled, timezone, mitm, + bold_reading) return True @@ -1577,7 +1586,7 @@ def _receive_bookmark(recent_posts_cache: {}, allow_local_network_access: bool, theme_name: str, system_language: str, max_like_count: int, cw_lists: {}, - lists_enabled: {}) -> bool: + lists_enabled: {}, bold_reading: bool) -> bool: """Receives a bookmark activity within the POST section of HTTPServer """ if not message_json.get('type'): @@ -1673,7 +1682,8 @@ def _receive_bookmark(recent_posts_cache: {}, show_individual_post_icons, manually_approve_followers, False, True, False, cw_lists, - lists_enabled, timezone, mitm) + lists_enabled, timezone, mitm, + bold_reading) return True @@ -1693,7 +1703,7 @@ def _receive_undo_bookmark(recent_posts_cache: {}, allow_local_network_access: bool, theme_name: str, system_language: str, max_like_count: int, cw_lists: {}, - lists_enabled: str) -> bool: + lists_enabled: str, bold_reading: bool) -> bool: """Receives an undo bookmark activity within the POST section of HTTPServer """ if not message_json.get('type'): @@ -1791,7 +1801,7 @@ def _receive_undo_bookmark(recent_posts_cache: {}, show_individual_post_icons, manually_approve_followers, False, True, False, cw_lists, lists_enabled, - timezone, mitm) + timezone, mitm, bold_reading) return True @@ -1887,7 +1897,7 @@ def _receive_announce(recent_posts_cache: {}, allow_deletion: bool, peertube_instances: [], max_like_count: int, cw_lists: {}, - lists_enabled: str) -> bool: + lists_enabled: str, bold_reading: bool) -> bool: """Receives an announce activity within the POST section of HTTPServer """ if message_json['type'] != 'Announce': @@ -1941,6 +1951,9 @@ def _receive_announce(recent_posts_cache: {}, # is the announce actor blocked? nickname = handle.split('@')[0] actor_nickname = get_nickname_from_actor(message_json['actor']) + if not actor_nickname: + print('WARN: _receive_announce no actor_nickname') + return False actor_domain, _ = get_domain_from_actor(message_json['actor']) if is_blocked(base_dir, nickname, domain, actor_nickname, actor_domain): print('Receive announce blocked for actor: ' + @@ -1948,13 +1961,16 @@ def _receive_announce(recent_posts_cache: {}, return False # also check the actor for the url being announced - announcedActorNickname = get_nickname_from_actor(message_json['object']) + announced_actor_nickname = get_nickname_from_actor(message_json['object']) + if not announced_actor_nickname: + print('WARN: _receive_announce no announced_actor_nickname') + return False announcedActorDomain, announcedActorPort = \ get_domain_from_actor(message_json['object']) if is_blocked(base_dir, nickname, domain, - announcedActorNickname, announcedActorDomain): + announced_actor_nickname, announcedActorDomain): print('Receive announce object blocked for actor: ' + - announcedActorNickname + '@' + announcedActorDomain) + announced_actor_nickname + '@' + announcedActorDomain) return False # is this post in the outbox of the person? @@ -2004,7 +2020,8 @@ def _receive_announce(recent_posts_cache: {}, show_individual_post_icons, manually_approve_followers, False, True, False, cw_lists, - lists_enabled, timezone, mitm) + lists_enabled, timezone, mitm, + bold_reading) if not announce_html: print('WARN: Unable to generate html for announce ' + str(message_json)) @@ -2024,7 +2041,7 @@ def _receive_announce(recent_posts_cache: {}, system_language, domain_full, person_cache, signing_priv_key_pem, - blocked_cache) + blocked_cache, bold_reading) if not post_json_object: print('WARN: unable to download announce: ' + str(message_json)) not_in_onion = True @@ -2788,6 +2805,8 @@ def _inbox_update_calendar(base_dir: str, handle: str, actor = post_json_object['actor'] actor_nickname = get_nickname_from_actor(actor) + if not actor_nickname: + return actor_domain, _ = get_domain_from_actor(actor) handle_nickname = handle.split('@')[0] handle_domain = handle.split('@')[1] @@ -3103,7 +3122,8 @@ def _receive_question_vote(server, base_dir: str, nickname: str, domain: str, allow_local_network_access: bool, theme_name: str, system_language: str, max_like_count: int, - cw_lists: {}, lists_enabled: bool) -> None: + cw_lists: {}, lists_enabled: bool, + bold_reading: bool) -> None: """Updates the votes on a Question/poll """ # if this is a reply to a question then update the votes @@ -3155,7 +3175,8 @@ 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, mitm) + lists_enabled, timezone, mitm, + bold_reading) # add id to inbox index inbox_update_index('inbox', base_dir, handle, @@ -3254,6 +3275,8 @@ def _low_frequency_post_notification(base_dir: str, http_prefix: str, if not isinstance(attributed_to, str): return from_nickname = get_nickname_from_actor(attributed_to) + if not from_nickname: + return from_domain, from_port = get_domain_from_actor(attributed_to) from_domain_full = get_full_domain(from_domain, from_port) if notify_when_person_posts(base_dir, nickname, domain, @@ -3282,6 +3305,8 @@ def _check_for_git_patches(base_dir: str, nickname: str, domain: str, if not isinstance(attributed_to, str): return 0 from_nickname = get_nickname_from_actor(attributed_to) + if not from_nickname: + return 0 from_domain, from_port = get_domain_from_actor(attributed_to) from_domain_full = get_full_domain(from_domain, from_port) if receive_git_patch(base_dir, nickname, domain, @@ -3325,7 +3350,7 @@ def _inbox_after_initial(server, cw_lists: {}, lists_enabled: str, content_license_url: str, languages_understood: [], - mitm: bool) -> bool: + mitm: bool, bold_reading: bool) -> bool: """ Anything which needs to be done after initial checks have passed """ # if this is a clearnet instance then replace any onion/i2p @@ -3350,6 +3375,8 @@ def _inbox_after_initial(server, post_is_dm = False is_group = _group_handle(base_dir, handle) + handle_name = handle.split('@')[0] + if _receive_like(recent_posts_cache, session, handle, is_group, base_dir, http_prefix, @@ -3368,7 +3395,8 @@ def _inbox_after_initial(server, peertube_instances, allow_local_network_access, theme_name, system_language, - max_like_count, cw_lists, lists_enabled): + max_like_count, cw_lists, lists_enabled, + bold_reading): if debug: print('DEBUG: Like accepted from ' + actor) return False @@ -3390,7 +3418,8 @@ def _inbox_after_initial(server, peertube_instances, allow_local_network_access, theme_name, system_language, - max_like_count, cw_lists, lists_enabled): + max_like_count, cw_lists, lists_enabled, + bold_reading): if debug: print('DEBUG: Undo like accepted from ' + actor) return False @@ -3413,7 +3442,8 @@ def _inbox_after_initial(server, peertube_instances, allow_local_network_access, theme_name, system_language, - max_like_count, cw_lists, lists_enabled): + max_like_count, cw_lists, lists_enabled, + bold_reading): if debug: print('DEBUG: Reaction accepted from ' + actor) return False @@ -3435,7 +3465,8 @@ def _inbox_after_initial(server, peertube_instances, allow_local_network_access, theme_name, system_language, - max_like_count, cw_lists, lists_enabled): + max_like_count, cw_lists, lists_enabled, + bold_reading): if debug: print('DEBUG: Undo reaction accepted from ' + actor) return False @@ -3457,7 +3488,8 @@ def _inbox_after_initial(server, peertube_instances, allow_local_network_access, theme_name, system_language, - max_like_count, cw_lists, lists_enabled): + max_like_count, cw_lists, lists_enabled, + bold_reading): if debug: print('DEBUG: Bookmark accepted from ' + actor) return False @@ -3479,7 +3511,8 @@ def _inbox_after_initial(server, peertube_instances, allow_local_network_access, theme_name, system_language, - max_like_count, cw_lists, lists_enabled): + max_like_count, cw_lists, lists_enabled, + bold_reading): if debug: print('DEBUG: Undo bookmark accepted from ' + actor) return False @@ -3505,7 +3538,8 @@ def _inbox_after_initial(server, max_recent_posts, allow_deletion, peertube_instances, - max_like_count, cw_lists, lists_enabled): + max_like_count, cw_lists, lists_enabled, + bold_reading): if debug: print('DEBUG: Announce accepted from ' + actor) @@ -3603,7 +3637,8 @@ def _inbox_after_initial(server, allow_local_network_access, theme_name, system_language, max_like_count, - cw_lists, lists_enabled) + cw_lists, lists_enabled, + bold_reading) is_reply_to_muted_post = False @@ -3646,7 +3681,8 @@ def _inbox_after_initial(server, twitter_replacement_domain, allow_local_network_access, recent_posts_cache, debug, system_language, - domain_full, person_cache, signing_priv_key_pem): + domain_full, person_cache, signing_priv_key_pem, + bold_reading): # media index will be updated update_index_list.append('tlmedia') if is_blog_post(post_json_object): @@ -3706,11 +3742,10 @@ def _inbox_after_initial(server, print('Saving inbox post as html to cache') html_cache_start_time = time.time() - handle_name = handle.split('@')[0] allow_local_net_access = allow_local_network_access show_pub_date_only = show_published_date_only - timezone = get_account_timezone(base_dir, - handle_name, domain) + timezone = \ + get_account_timezone(base_dir, handle_name, domain) _inbox_store_post_to_html_cache(recent_posts_cache, max_recent_posts, translate, base_dir, @@ -3732,7 +3767,8 @@ def _inbox_after_initial(server, signing_priv_key_pem, cw_lists, lists_enabled, - timezone, mitm) + timezone, mitm, + bold_reading) if debug: time_diff = \ str(int((time.time() - html_cache_start_time) * @@ -3741,8 +3777,6 @@ def _inbox_after_initial(server, boxname + ' post as html to cache in ' + time_diff + ' mS') - handle_name = handle.split('@')[0] - # is this an edit of a previous post? # in Mastodon "delete and redraft" # NOTE: this must be done before update_conversation is called @@ -4770,6 +4804,11 @@ def run_inbox_queue(server, mitm = False if queue_json.get('mitm'): mitm = True + bold_reading = False + bold_reading_filename = \ + base_dir + '/accounts/' + handle + '/.boldReading' + if os.path.isfile(bold_reading_filename): + bold_reading = True _inbox_after_initial(server, recent_posts_cache, max_recent_posts, @@ -4801,7 +4840,8 @@ def run_inbox_queue(server, default_reply_interval_hrs, cw_lists, lists_enabled, content_license_url, - languages_understood, mitm) + languages_understood, mitm, + bold_reading) if debug: pprint(queue_json['post']) print('Queue: Queue post accepted') diff --git a/outbox.py b/outbox.py index 3b8215d52..db2f8877e 100644 --- a/outbox.py +++ b/outbox.py @@ -219,6 +219,10 @@ def post_message_to_outbox(session, translate: {}, domain, port, message_json) + bold_reading = False + if server.bold_reading.get(post_to_nickname): + bold_reading = True + # check that the outgoing post doesn't contain any markup # which can be used to implement exploits if has_object_dict(message_json): @@ -430,7 +434,8 @@ def post_message_to_outbox(session, translate: {}, recent_posts_cache, debug, system_language, domain_full, person_cache, - signing_priv_key_pem): + signing_priv_key_pem, + bold_reading): inbox_update_index('tlmedia', base_dir, post_to_nickname + '@' + domain, saved_filename, debug) @@ -485,7 +490,8 @@ def post_message_to_outbox(session, translate: {}, manually_approve_followers, False, True, use_cache_only, cw_lists, lists_enabled, - timezone, mitm) + timezone, mitm, + bold_reading) if outbox_announce(recent_posts_cache, base_dir, message_json, debug): diff --git a/posts.py b/posts.py index 9d43ae88a..f587f5d3d 100644 --- a/posts.py +++ b/posts.py @@ -3683,7 +3683,8 @@ def is_image_media(session, base_dir: str, http_prefix: str, recent_posts_cache: {}, debug: bool, system_language: str, domain_full: str, person_cache: {}, - signing_priv_key_pem: str) -> bool: + signing_priv_key_pem: str, + bold_reading: bool) -> bool: """Returns true if the given post has attached image media """ if post_json_object['type'] == 'Announce': @@ -3699,7 +3700,7 @@ def is_image_media(session, base_dir: str, http_prefix: str, system_language, domain_full, person_cache, signing_priv_key_pem, - blocked_cache) + blocked_cache, bold_reading) if post_json_announce: post_json_object = post_json_announce if post_json_object['type'] != 'Create': @@ -4765,7 +4766,7 @@ def download_announce(session, base_dir: str, http_prefix: str, system_language: str, domain_full: str, person_cache: {}, signing_priv_key_pem: str, - blocked_cache: {}) -> {}: + blocked_cache: {}, bold_reading: bool) -> {}: """Download the post referenced by an announce """ if not post_json_object.get('object'): @@ -4815,6 +4816,9 @@ def download_announce(session, base_dir: str, http_prefix: str, 'Accept': accept_str } actor_nickname = get_nickname_from_actor(post_json_object['actor']) + if not actor_nickname: + print('WARN: download_announce no actor_nickname') + return None actor_domain, actor_port = \ get_domain_from_actor(post_json_object['actor']) if not actor_domain: @@ -4969,7 +4973,7 @@ def download_announce(session, base_dir: str, http_prefix: str, content_str = limit_repeated_words(content_str, 6) # remove text formatting, such as bold/italics - content_str = remove_text_formatting(content_str) + content_str = remove_text_formatting(content_str, bold_reading) # set the content after santitization announced_json['content'] = content_str diff --git a/reaction.py b/reaction.py index e2804c61f..7dc2439b1 100644 --- a/reaction.py +++ b/reaction.py @@ -541,6 +541,8 @@ def html_emoji_reactions(post_json_object: {}, interactive: bool, emoji_content = item['content'] emoji_actor = item['actor'] emoji_nickname = get_nickname_from_actor(emoji_actor) + if not emoji_nickname: + return '' emoji_domain, _ = get_domain_from_actor(emoji_actor) emoji_handle = emoji_nickname + '@' + emoji_domain if emoji_actor == actor: diff --git a/skills.py b/skills.py index b1ac666b1..f7ce6e14e 100644 --- a/skills.py +++ b/skills.py @@ -158,6 +158,8 @@ def outbox_skills(base_dir: str, nickname: str, message_json: {}, return False actor_nickname = get_nickname_from_actor(message_json['actor']) + if not actor_nickname: + return False if actor_nickname != nickname: return False domain, _ = get_domain_from_actor(message_json['actor']) diff --git a/tests.py b/tests.py index d23461a08..53f197d1c 100644 --- a/tests.py +++ b/tests.py @@ -129,6 +129,7 @@ from inbox import json_post_allows_comments from inbox import valid_inbox from inbox import valid_inbox_filenames from categories import guess_hashtag_category +from content import bold_reading_string from content import safe_web_text from content import words_similarity from content import get_price_from_string @@ -3727,10 +3728,10 @@ def _test_recent_posts_cache(): def _test_remove_txt_formatting(): print('test_remove_txt_formatting') test_str = '

Text without formatting

' - result_str = remove_text_formatting(test_str) + result_str = remove_text_formatting(test_str, False) assert result_str == test_str test_str = '

Text with

formatting

' - result_str = remove_text_formatting(test_str) + result_str = remove_text_formatting(test_str, False) assert result_str == '

Text with formatting

' @@ -6687,6 +6688,72 @@ def _test_published_to_local_timezone() -> None: assert local_time_str == 'Sat Feb 26, 05:15' +def _test_bold_reading() -> None: + print('bold_reading') + text = "This is a test of emboldening." + text_bold = bold_reading_string(text) + expected = \ + "This is a test of " + \ + "emboldening." + if text_bold != expected: + print(text_bold) + assert text_bold == expected + + text = "

This is a test of emboldening with paragraph.

" + text_bold = bold_reading_string(text) + expected = \ + "

This is a test of " + \ + "emboldening with paragraph.

" + if text_bold != expected: + print(text_bold) + assert text_bold == expected + + text = \ + "

This is a test of emboldening

" + \ + "

With more than one paragraph.

" + text_bold = bold_reading_string(text) + expected = \ + "

This is a test of " + \ + "emboldening

With more " + \ + "than one paragraph.

" + if text_bold != expected: + print(text_bold) + assert text_bold == expected + + text = '

This is a test

' + text_bold = bold_reading_string(text) + expected = \ + '

This is a test ' + \ + '

' + if text_bold != expected: + print(text_bold) + assert text_bold == expected + + text = "There's the quoted text here" + text_bold = bold_reading_string(text) + expected = \ + "There's the quoted text here" + if text_bold != expected: + print(text_bold) + assert text_bold == expected + + text = '

@Someone or other' + \ + ' some text

' + text_bold = bold_reading_string(text) + expected = \ + '

' + \ + '@Someone or other' + \ + ' some text

' + if text_bold != expected: + print(text_bold) + assert text_bold == expected + + def run_all_tests(): base_dir = os.getcwd() print('Running tests...') @@ -6703,6 +6770,7 @@ def run_all_tests(): 'message_json', 'liked_post_json']) _test_checkbox_names() _test_functions() + _test_bold_reading() _test_published_to_local_timezone() _test_safe_webtext() _test_get_link_from_rss_item() diff --git a/translations/ar.json b/translations/ar.json index 8a4d3c7ee..6f6f4ce23 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -518,5 +518,6 @@ "Register": "يسجل", "Web Bots Allowed": "مسموح روبوتات الويب", "Known Search Bots": "روبوتات بحث الويب المعروفة", - "mitm": "يمكن قراءة الرسالة أو تعديلها من قبل طرف ثالث" + "mitm": "يمكن قراءة الرسالة أو تعديلها من قبل طرف ثالث", + "Bold reading": "قراءة جريئة" } diff --git a/translations/ca.json b/translations/ca.json index 10dd483f7..86651c8ae 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -518,5 +518,6 @@ "Register": "Registra't", "Web Bots Allowed": "Bots web permesos", "Known Search Bots": "Bots de cerca web coneguts", - "mitm": "El missatge podria haver estat llegit o modificat per un tercer" + "mitm": "El missatge podria haver estat llegit o modificat per un tercer", + "Bold reading": "Lectura atrevida" } diff --git a/translations/cy.json b/translations/cy.json index eef7ecbd4..8bc01bdec 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -518,5 +518,6 @@ "Register": "Cofrestrwch", "Web Bots Allowed": "Web Bots a Ganiateir", "Known Search Bots": "Bots Chwilio Gwe Hysbys", - "mitm": "Gallai'r neges fod wedi cael ei darllen neu ei haddasu gan drydydd parti" + "mitm": "Gallai'r neges fod wedi cael ei darllen neu ei haddasu gan drydydd parti", + "Bold reading": "Darllen beiddgar" } diff --git a/translations/de.json b/translations/de.json index a33f20caf..c2fe3ff2d 100644 --- a/translations/de.json +++ b/translations/de.json @@ -518,5 +518,6 @@ "Register": "Registrieren", "Web Bots Allowed": "Webbots erlaubt", "Known Search Bots": "Bekannte Bots für die Websuche", - "mitm": "Die Nachricht könnte von einem Dritten gelesen oder geändert worden sein" + "mitm": "Die Nachricht könnte von einem Dritten gelesen oder geändert worden sein", + "Bold reading": "Mutige Lektüre" } diff --git a/translations/en.json b/translations/en.json index 848aeb093..d70f59477 100644 --- a/translations/en.json +++ b/translations/en.json @@ -518,5 +518,6 @@ "Register": "Register", "Web Bots Allowed": "Web Search Bots Allowed", "Known Search Bots": "Known Web Search Bots", - "mitm": "Message could have been read or modified by a third party" + "mitm": "Message could have been read or modified by a third party", + "Bold reading": "Bold reading" } diff --git a/translations/es.json b/translations/es.json index b611d7366..3c3673ee3 100644 --- a/translations/es.json +++ b/translations/es.json @@ -518,5 +518,6 @@ "Register": "Registrarse", "Web Bots Allowed": "Bots web permitidos", "Known Search Bots": "Bots de búsqueda web conocidos", - "mitm": "El mensaje podría haber sido leído o modificado por un tercero" + "mitm": "El mensaje podría haber sido leído o modificado por un tercero", + "Bold reading": "Lectura en negrita" } diff --git a/translations/fr.json b/translations/fr.json index f50d7a4d4..a553b49b8 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -518,5 +518,6 @@ "Register": "S'inscrire", "Web Bots Allowed": "Robots Web autorisés", "Known Search Bots": "Robots de recherche Web connus", - "mitm": "Le message a pu être lu ou modifié par un tiers" + "mitm": "Le message a pu être lu ou modifié par un tiers", + "Bold reading": "Lecture audacieuse" } diff --git a/translations/ga.json b/translations/ga.json index 7fdcece92..c1f065901 100644 --- a/translations/ga.json +++ b/translations/ga.json @@ -518,5 +518,6 @@ "Register": "Clár", "Web Bots Allowed": "Róbónna Gréasáin Ceadaithe", "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ú" + "mitm": "D'fhéadfadh tríú páirtí an teachtaireacht a léamh nó a mhodhnú", + "Bold reading": "Léamh trom" } diff --git a/translations/hi.json b/translations/hi.json index 668b8aab6..6845d4d27 100644 --- a/translations/hi.json +++ b/translations/hi.json @@ -518,5 +518,6 @@ "Register": "रजिस्टर करें", "Web Bots Allowed": "वेब बॉट्स की अनुमति है", "Known Search Bots": "ज्ञात वेब खोज बॉट्स", - "mitm": "संदेश किसी तीसरे पक्ष द्वारा पढ़ा या संशोधित किया जा सकता था" + "mitm": "संदेश किसी तीसरे पक्ष द्वारा पढ़ा या संशोधित किया जा सकता था", + "Bold reading": "बोल्ड रीडिंग" } diff --git a/translations/it.json b/translations/it.json index 23e96d921..d6bd3418f 100644 --- a/translations/it.json +++ b/translations/it.json @@ -518,5 +518,6 @@ "Register": "Registrati", "Web Bots Allowed": "Web bot consentiti", "Known Search Bots": "Bot di ricerca Web noti", - "mitm": "Il messaggio potrebbe essere stato letto o modificato da terzi" + "mitm": "Il messaggio potrebbe essere stato letto o modificato da terzi", + "Bold reading": "Lettura audace" } diff --git a/translations/ja.json b/translations/ja.json index e722405f8..0d6fe2b7e 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -518,5 +518,6 @@ "Register": "登録", "Web Bots Allowed": "許可されたWebボット", "Known Search Bots": "既知のWeb検索ボット", - "mitm": "メッセージが第三者によって読み取られたり変更されたりした可能性があります" + "mitm": "メッセージが第三者によって読み取られたり変更されたりした可能性があります", + "Bold reading": "大胆な読書" } diff --git a/translations/ko.json b/translations/ko.json index e9bdb5d38..96b6e038a 100644 --- a/translations/ko.json +++ b/translations/ko.json @@ -518,5 +518,6 @@ "Register": "등록", "Web Bots Allowed": "웹 봇 허용", "Known Search Bots": "알려진 웹 검색 봇", - "mitm": "제3자가 메시지를 읽거나 수정했을 수 있습니다." + "mitm": "제3자가 메시지를 읽거나 수정했을 수 있습니다.", + "Bold reading": "굵은 글씨" } diff --git a/translations/ku.json b/translations/ku.json index e491e585c..2aa459238 100644 --- a/translations/ku.json +++ b/translations/ku.json @@ -518,5 +518,6 @@ "Register": "Fêhrist", "Web Bots Allowed": "Web Bots Destûrdar in", "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" + "mitm": "Peyam dikaribû ji hêla aliyek sêyemîn ve were xwendin an guhertin", + "Bold reading": "Xwendina qelew" } diff --git a/translations/oc.json b/translations/oc.json index 5c0858299..c6e69765c 100644 --- a/translations/oc.json +++ b/translations/oc.json @@ -514,5 +514,6 @@ "Register": "Register", "Web Bots Allowed": "Web Search Bots Allowed", "Known Search Bots": "Known Web Search Bots", - "mitm": "Message could have been read or modified by a third party" + "mitm": "Message could have been read or modified by a third party", + "Bold reading": "Bold reading" } diff --git a/translations/pl.json b/translations/pl.json index 3184a3a52..fb6e675b1 100644 --- a/translations/pl.json +++ b/translations/pl.json @@ -518,5 +518,6 @@ "Register": "Zarejestrować", "Web Bots Allowed": "Dozwolone boty internetowe", "Known Search Bots": "Znane boty wyszukiwania w sieci", - "mitm": "Wiadomość mogła zostać przeczytana lub zmodyfikowana przez osobę trzecią" + "mitm": "Wiadomość mogła zostać przeczytana lub zmodyfikowana przez osobę trzecią", + "Bold reading": "Odważne czytanie" } diff --git a/translations/pt.json b/translations/pt.json index 5a543440b..98a6db584 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -518,5 +518,6 @@ "Register": "Registro", "Web Bots Allowed": "Webbots permitidos", "Known Search Bots": "Bots de pesquisa na Web conhecidos", - "mitm": "A mensagem pode ter sido lida ou modificada por terceiros" + "mitm": "A mensagem pode ter sido lida ou modificada por terceiros", + "Bold reading": "Leitura em negrito" } diff --git a/translations/ru.json b/translations/ru.json index b9540fc12..e8d906959 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -518,5 +518,6 @@ "Register": "регистр", "Web Bots Allowed": "Веб-боты разрешены", "Known Search Bots": "Известные боты веб-поиска", - "mitm": "Сообщение могло быть прочитано или изменено третьим лицом" + "mitm": "Сообщение могло быть прочитано или изменено третьим лицом", + "Bold reading": "Смелое чтение" } diff --git a/translations/sw.json b/translations/sw.json index 9f047b434..39e466044 100644 --- a/translations/sw.json +++ b/translations/sw.json @@ -518,5 +518,6 @@ "Register": "Sajili", "Web Bots Allowed": "Mtandao wa Boti Unaruhusiwa", "Known Search Bots": "Vijibu vya Utafutaji wa Wavuti vinavyojulikana", - "mitm": "Ujumbe ungeweza kusomwa au kurekebishwa na mtu mwingine" + "mitm": "Ujumbe ungeweza kusomwa au kurekebishwa na mtu mwingine", + "Bold reading": "Kusoma kwa ujasiri" } diff --git a/translations/uk.json b/translations/uk.json index 89e9273bd..009245795 100644 --- a/translations/uk.json +++ b/translations/uk.json @@ -518,5 +518,6 @@ "Register": "Реєстрація", "Web Bots Allowed": "Веб-боти дозволені", "Known Search Bots": "Відомі пошукові роботи в Інтернеті", - "mitm": "Повідомлення могло бути прочитане або змінене третьою стороною" + "mitm": "Повідомлення могло бути прочитане або змінене третьою стороною", + "Bold reading": "Сміливе читання" } diff --git a/translations/zh.json b/translations/zh.json index b0acdfbde..c9624fce1 100644 --- a/translations/zh.json +++ b/translations/zh.json @@ -518,5 +518,6 @@ "Register": "登记", "Web Bots Allowed": "允许网络机器人", "Known Search Bots": "已知的网络搜索机器人", - "mitm": "消息可能已被第三方阅读或修改" + "mitm": "消息可能已被第三方阅读或修改", + "Bold reading": "大胆阅读" } diff --git a/utils.py b/utils.py index 5158ae9b1..e65cb083e 100644 --- a/utils.py +++ b/utils.py @@ -2343,6 +2343,8 @@ def undo_likes_collection_entry(recent_posts_cache: {}, # remove any cached version of this post so that the # like icon is changed nickname = get_nickname_from_actor(actor) + if not nickname: + return cached_post_filename = \ get_cached_post_filename(base_dir, nickname, domain, post_json_object) @@ -2409,6 +2411,8 @@ def undo_reaction_collection_entry(recent_posts_cache: {}, # remove any cached version of this post so that the # like icon is changed nickname = get_nickname_from_actor(actor) + if not nickname: + return cached_post_filename = \ get_cached_post_filename(base_dir, nickname, domain, post_json_object) @@ -2476,6 +2480,8 @@ def undo_announce_collection_entry(recent_posts_cache: {}, # remove any cached version of this announce so that the announce # icon is changed nickname = get_nickname_from_actor(actor) + if not nickname: + return cached_post_filename = \ get_cached_post_filename(base_dir, nickname, domain, post_json_object) @@ -3474,6 +3480,24 @@ def load_account_timezones(base_dir: str) -> {}: return account_timezone +def load_bold_reading(base_dir: str) -> {}: + """Returns a dictionary containing the bold reading status for each account + """ + bold_reading = {} + for subdir, dirs, files in os.walk(base_dir + '/accounts'): + for acct in dirs: + if '@' not in acct: + continue + if acct.startswith('inbox@') or acct.startswith('Actor@'): + continue + bold_reading_filename = \ + base_dir + '/accounts/' + acct + '/.boldReading' + if os.path.isfile(bold_reading_filename): + nickname = acct.split('@')[0] + bold_reading[nickname] = True + return bold_reading + + def get_account_timezone(base_dir: str, nickname: str, domain: str) -> str: """Returns the timezone for the given account """ diff --git a/webapp_calendar.py b/webapp_calendar.py index 576fae8e3..d0901bad9 100644 --- a/webapp_calendar.py +++ b/webapp_calendar.py @@ -42,6 +42,8 @@ def html_calendar_delete_confirm(css_cache: {}, translate: {}, base_dir: str, """Shows a screen asking to confirm the deletion of a calendar event """ nickname = get_nickname_from_actor(path) + if not nickname: + return None actor = local_actor_url(http_prefix, nickname, domain_full) domain, _ = get_domain_from_actor(actor) message_id = actor + '/statuses/' + post_id @@ -304,6 +306,8 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {}, month_number = curr_date.month nickname = get_nickname_from_actor(actor) + if not nickname: + return '' set_custom_background(base_dir, 'calendar-background', 'calendar-background') diff --git a/webapp_confirm.py b/webapp_confirm.py index 12e32c64e..d0bcedc6d 100644 --- a/webapp_confirm.py +++ b/webapp_confirm.py @@ -24,7 +24,7 @@ from webapp_utils import html_footer from webapp_post import individual_post_as_html -def html_confirm_delete(css_cache: {}, +def html_confirm_delete(server, css_cache: {}, recent_posts_cache: {}, max_recent_posts: int, translate, page_number: int, session, base_dir: str, message_id: str, @@ -45,6 +45,8 @@ def html_confirm_delete(css_cache: {}, return None actor = message_id.split('/statuses/')[0] nickname = get_nickname_from_actor(actor) + if not nickname: + return None domain, port = get_domain_from_actor(actor) domain_full = get_full_domain(domain, port) @@ -69,6 +71,9 @@ def html_confirm_delete(css_cache: {}, mitm = False if os.path.isfile(post_filename.replace('.json', '') + '.mitm'): mitm = True + bold_reading = False + if server.bold_reading.get(nickname): + bold_reading = True delete_post_str += \ individual_post_as_html(signing_priv_key_pem, True, recent_posts_cache, max_recent_posts, @@ -84,7 +89,8 @@ 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, mitm) + cw_lists, lists_enabled, timezone, mitm, + bold_reading) delete_post_str += '
' delete_post_str += \ '

' + \ @@ -119,6 +125,8 @@ def html_confirm_remove_shared_item(css_cache: {}, translate: {}, """Shows a screen asking to confirm the removal of a shared item """ nickname = get_nickname_from_actor(actor) + if not nickname: + return None domain, port = get_domain_from_actor(actor) domain_full = get_full_domain(domain, port) shares_file = \ @@ -207,10 +215,11 @@ def html_confirm_follow(css_cache: {}, translate: {}, base_dir: str, follow_str += ' \n' follow_str += \ ' \n' - follow_str += \ - '

' + translate['Follow'] + ' ' + \ - get_nickname_from_actor(follow_actor) + \ - '@' + follow_domain + ' ?

\n' + follow_actor_nick = get_nickname_from_actor(follow_actor) + if follow_actor_nick: + follow_str += \ + '

' + translate['Follow'] + ' ' + \ + follow_actor_nick + '@' + follow_domain + ' ?

\n' follow_str += '
\n' follow_str += ' \n' follow_str += \ ' \n' - follow_str += \ - '

' + translate['Stop following'] + \ - ' ' + get_nickname_from_actor(follow_actor) + \ - '@' + follow_domain + ' ?

\n' + follow_actor_nick = get_nickname_from_actor(follow_actor) + if follow_actor_nick: + follow_str += \ + '

' + translate['Stop following'] + \ + ' ' + follow_actor_nick + '@' + follow_domain + ' ?

\n' follow_str += ' \n' follow_str += ' \n' block_str += \ ' \n' - block_str += \ - '

' + translate['Stop blocking'] + ' ' + \ - get_nickname_from_actor(block_actor) + '@' + block_domain + ' ?

\n' + block_actor_nick = get_nickname_from_actor(block_actor) + if block_actor_nick: + block_str += \ + '

' + translate['Stop blocking'] + ' ' + \ + block_actor_nick + '@' + block_domain + ' ?

\n' block_str += ' \n' block_str += ' \n' diff --git a/webapp_frontscreen.py b/webapp_frontscreen.py index 68df1b6de..791dd1dc2 100644 --- a/webapp_frontscreen.py +++ b/webapp_frontscreen.py @@ -37,7 +37,8 @@ def _html_front_screen_posts(recent_posts_cache: {}, max_recent_posts: int, theme_name: str, system_language: str, max_like_count: int, signing_priv_key_pem: str, cw_lists: {}, - lists_enabled: str) -> str: + lists_enabled: str, + bold_reading: bool) -> str: """Shows posts on the front screen of a news instance These should only be public blog posts from the features timeline which is the blog timeline of the news actor @@ -87,7 +88,8 @@ def _html_front_screen_posts(recent_posts_cache: {}, max_recent_posts: int, False, False, False, True, False, False, cw_lists, lists_enabled, - timezone, False) + timezone, False, + bold_reading) if post_str: profile_str += post_str + separator_str ctr += 1 @@ -121,6 +123,7 @@ def html_front_screen(signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str) -> str: """Show the news instance front screen """ + bold_reading = False nickname = profile_json['preferredUsername'] if not nickname: return "" @@ -191,7 +194,8 @@ def html_front_screen(signing_priv_key_pem: str, theme, system_language, max_like_count, signing_priv_key_pem, - cw_lists, lists_enabled) + license_str + cw_lists, lists_enabled, + bold_reading) + license_str # Footer which is only used for system accounts profile_footer_str = ' \n' diff --git a/webapp_hashtagswarm.py b/webapp_hashtagswarm.py index 1cec4180d..6ddab1486 100644 --- a/webapp_hashtagswarm.py +++ b/webapp_hashtagswarm.py @@ -200,6 +200,8 @@ def html_search_hashtag_category(css_cache: {}, translate: {}, actor = path.split('/category/')[0] category_str = path.split('/category/')[1].strip() search_nickname = get_nickname_from_actor(actor) + if not search_nickname: + return '' set_custom_background(base_dir, 'search-background', 'follow-background') diff --git a/webapp_likers.py b/webapp_likers.py index 0625f151e..563b77d54 100644 --- a/webapp_likers.py +++ b/webapp_likers.py @@ -41,6 +41,7 @@ def html_likers_of_post(base_dir: str, nickname: str, max_like_count: int, signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, boxName: str, default_timeline: str, + bold_reading: bool, dict_name: str = 'likes') -> str: """Returns html for a screen showing who liked a post """ @@ -105,7 +106,7 @@ def html_likers_of_post(base_dir: str, nickname: str, False, False, False, False, False, False, cw_lists, lists_enabled, - timezone, mitm) + timezone, mitm, bold_reading) # show likers beneath the post obj = post_json_object @@ -142,6 +143,8 @@ def html_likers_of_post(base_dir: str, nickname: str, liker_name, False) else: liker_name = get_nickname_from_actor(liker_actor) + if not liker_name: + liker_name = 'unknown' if likers_list: likers_list += ' ' liker_avatar_url = \ diff --git a/webapp_moderation.py b/webapp_moderation.py index 596426636..490772f7f 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -55,7 +55,7 @@ def html_moderation(css_cache: {}, default_timeline: str, shared_items_federated_domains: [], signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show the moderation feed as html This is what you see when selecting the "mod" timeline """ @@ -81,7 +81,7 @@ def html_moderation(css_cache: {}, default_timeline: str, text_mode_banner, access_keys, system_language, max_like_count, shared_items_federated_domains, signing_priv_key_pem, cw_lists, lists_enabled, - timezone) + timezone, bold_reading) def html_account_info(css_cache: {}, translate: {}, @@ -107,6 +107,8 @@ def html_account_info(css_cache: {}, translate: {}, html_header_with_external_style(css_filename, instance_title, None) search_nickname = get_nickname_from_actor(search_handle) + if not search_nickname: + return '' search_domain, search_port = get_domain_from_actor(search_handle) search_handle = search_nickname + '@' + search_domain @@ -146,6 +148,8 @@ def html_account_info(css_cache: {}, translate: {}, blocked_followers = [] for follower_actor in followers_list: follower_nickname = get_nickname_from_actor(follower_actor) + if not follower_nickname: + return '' follower_domain, follower_port = get_domain_from_actor(follower_actor) follower_domain_full = get_full_domain(follower_domain, follower_port) if is_blocked(base_dir, nickname, domain, @@ -160,6 +164,8 @@ def html_account_info(css_cache: {}, translate: {}, blocked_following = [] for following_actor in following_list: following_nickname = get_nickname_from_actor(following_actor) + if not following_nickname: + return '' following_domain, following_port = \ get_domain_from_actor(following_actor) following_domain_full = \ @@ -224,6 +230,8 @@ def html_account_info(css_cache: {}, translate: {}, ':

\n' for actor in blocked_following: following_nickname = get_nickname_from_actor(actor) + if not following_nickname: + return '' following_domain, following_port = get_domain_from_actor(actor) following_domain_full = \ get_full_domain(following_domain, following_port) @@ -243,6 +251,8 @@ def html_account_info(css_cache: {}, translate: {}, ':

\n' for actor in blocked_followers: follower_nickname = get_nickname_from_actor(actor) + if not follower_nickname: + return '' follower_domain, follower_port = get_domain_from_actor(actor) follower_domain_full = \ get_full_domain(follower_domain, follower_port) diff --git a/webapp_person_options.py b/webapp_person_options.py index 90867b033..61b8c029b 100644 --- a/webapp_person_options.py +++ b/webapp_person_options.py @@ -66,6 +66,8 @@ def html_person_options(default_timeline: str, """Show options for a person: view/follow/block/report """ options_domain, options_port = get_domain_from_actor(options_actor) + if not options_domain: + return None options_domain_full = get_full_domain(options_domain, options_port) if os.path.isfile(base_dir + '/accounts/options-background-custom.jpg'): @@ -97,6 +99,8 @@ def html_person_options(default_timeline: str, dormant_months) options_nickname = get_nickname_from_actor(options_actor) + if not options_nickname: + return None options_domain_full = get_full_domain(options_domain, options_port) follows_you = \ is_follower_of_person(base_dir, @@ -140,7 +144,10 @@ def html_person_options(default_timeline: str, options_str += ' \n' options_str += ' \n' - handle = get_nickname_from_actor(options_actor) + '@' + options_domain + handle_nick = get_nickname_from_actor(options_actor) + if not handle_nick: + return None + handle = handle_nick + '@' + options_domain handle_shown = handle if locked_account: handle_shown += '🔒' @@ -151,7 +158,7 @@ def html_person_options(default_timeline: str, options_str += \ '

' + translate['Options for'] + \ ' @' + handle_shown + '

\n' - if follows_you: + if follows_you and authorized: options_str += \ '

' + translate['Follows you'] + '

\n' if moved_to: diff --git a/webapp_post.py b/webapp_post.py index 7c69692a3..567bdf322 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -58,6 +58,7 @@ from utils import get_domain_from_actor from utils import acct_dir from utils import local_actor_url from utils import is_unlisted_post +from content import bold_reading_string from content import limit_repeated_words from content import replace_emoji_from_tags from content import html_replace_quote_marks @@ -104,11 +105,12 @@ def _html_post_metadata_open_graph(domain: str, post_json_object: {}) -> str: if isinstance(obj_json['attributedTo'], str): attrib = obj_json['attributedTo'] actor_nick = get_nickname_from_actor(attrib) - actor_domain, _ = get_domain_from_actor(attrib) - actor_handle = actor_nick + '@' + actor_domain - metadata += \ - " \n" + if actor_nick: + actor_domain, _ = get_domain_from_actor(attrib) + actor_handle = actor_nick + '@' + actor_domain + metadata += \ + " \n" if obj_json.get('url'): metadata += \ " str: + mitm: bool, bold_reading: bool) -> str: """ Shows a single post as html """ if not post_json_object: @@ -1516,6 +1520,8 @@ def individual_post_as_html(signing_priv_key_pem: str, if domain_full not in post_actor: # lookup the correct webfinger for the post_actor post_actor_nickname = get_nickname_from_actor(post_actor) + if not post_actor_nickname: + return '' post_actor_domain, post_actor_port = get_domain_from_actor(post_actor) post_actor_domain_full = \ get_full_domain(post_actor_domain, post_actor_port) @@ -1598,7 +1604,7 @@ def individual_post_as_html(signing_priv_key_pem: str, system_language, domain_full, person_cache, signing_priv_key_pem, - blocked_cache) + blocked_cache, bold_reading) if not post_json_announce: # if the announce could not be downloaded then mark it as rejected announced_post_id = remove_id_ending(post_json_object['id']) @@ -1884,7 +1890,9 @@ def individual_post_as_html(signing_priv_key_pem: str, published_link = message_id # blog posts should have no /statuses/ in their link + post_is_blog = False if is_blog_post(post_json_object): + post_is_blog = True # is this a post to the local domain? if '://' + domain in message_id: published_link = message_id.replace('/statuses/', '/') @@ -1947,7 +1955,9 @@ def individual_post_as_html(signing_priv_key_pem: str, system_language: '' } + displaying_ciphertext = False if post_json_object['object'].get('cipherText'): + displaying_ciphertext = True post_json_object['object']['content'] = \ e2e_edecrypt_message_from_device(post_json_object['object']) post_json_object['object']['contentMap'][system_language] = \ @@ -1979,9 +1989,16 @@ def individual_post_as_html(signing_priv_key_pem: str, if not is_pgp_encrypted(content_str): if not is_patch: + # Add bold text + if bold_reading and \ + not displaying_ciphertext and \ + not post_is_blog: + content_str = bold_reading_string(content_str) + object_content = \ remove_long_words(content_str, 40, []) - object_content = remove_text_formatting(object_content) + object_content = \ + remove_text_formatting(object_content, bold_reading) object_content = limit_repeated_words(object_content, 6) object_content = \ switch_words(base_dir, nickname, domain, object_content) @@ -2114,7 +2131,8 @@ 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, mitm: bool) -> str: + timezone: str, mitm: bool, + bold_reading: bool) -> str: """Show an individual post as html """ original_post_json = post_json_object @@ -2132,6 +2150,8 @@ def html_individual_post(css_cache: {}, if by_str: by_str_nickname = get_nickname_from_actor(by_str) + if not by_str_nickname: + return '' by_str_domain, by_str_port = get_domain_from_actor(by_str) by_str_domain = get_full_domain(by_str_domain, by_str_port) by_str_handle = by_str_nickname + '@' + by_str_domain @@ -2180,7 +2200,8 @@ 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, mitm) + cw_lists, lists_enabled, timezone, mitm, + bold_reading) message_id = remove_id_ending(post_json_object['id']) # show the previous posts @@ -2220,7 +2241,8 @@ def html_individual_post(css_cache: {}, False, authorized, False, False, False, False, cw_lists, lists_enabled, - timezone, mitm) + post_str + timezone, mitm, + bold_reading) + post_str # show the following posts post_filename = locate_post(base_dir, nickname, domain, message_id) @@ -2258,7 +2280,8 @@ def html_individual_post(css_cache: {}, False, authorized, False, False, False, False, cw_lists, lists_enabled, - timezone, False) + timezone, False, + bold_reading) css_filename = base_dir + '/epicyon-profile.css' if os.path.isfile(base_dir + '/epicyon.css'): css_filename = base_dir + '/epicyon.css' @@ -2286,7 +2309,7 @@ def html_post_replies(css_cache: {}, max_like_count: int, signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show the replies to an individual post as html """ replies_str = '' @@ -2312,7 +2335,8 @@ def html_post_replies(css_cache: {}, False, False, False, False, False, False, cw_lists, lists_enabled, - timezone, False) + timezone, False, + bold_reading) css_filename = base_dir + '/epicyon-profile.css' if os.path.isfile(base_dir + '/epicyon.css'): @@ -2342,7 +2366,7 @@ def html_emoji_reaction_picker(css_cache: {}, max_like_count: int, signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, box_name: str, page_number: int, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Returns the emoji picker screen """ reacted_to_post_str = \ @@ -2365,7 +2389,8 @@ 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, False) + cw_lists, lists_enabled, timezone, False, + bold_reading) 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 505c43cd2..62579c754 100644 --- a/webapp_profile.py +++ b/webapp_profile.py @@ -75,6 +75,7 @@ from blog import get_blog_address from webapp_post import individual_post_as_html from webapp_timeline import html_individual_share from blocking import get_cw_list_variable +from content import bold_reading_string THEME_FORMATS = '.zip, .gz' @@ -146,7 +147,8 @@ def html_profile_after_search(css_cache: {}, signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, timezone: str, - onion_domain: str, i2p_domain: str) -> str: + onion_domain: str, i2p_domain: str, + bold_reading: bool) -> str: """Show a profile page after a search for a fediverse address """ http = False @@ -368,7 +370,8 @@ def html_profile_after_search(css_cache: {}, False, False, False, False, False, False, cw_lists, lists_enabled, - timezone, False) + timezone, False, + bold_reading) i += 1 if i >= 8: break @@ -591,7 +594,7 @@ def html_profile(signing_priv_key_pem: str, max_items_per_page: int, cw_lists: {}, lists_enabled: str, content_license_url: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show the profile page as html """ nickname = profile_json['preferredUsername'] @@ -1002,7 +1005,7 @@ def html_profile(signing_priv_key_pem: str, max_like_count, signing_priv_key_pem, cw_lists, lists_enabled, - timezone) + license_str + timezone, bold_reading) + license_str if not is_group: if selected == 'following': profile_str += \ @@ -1076,7 +1079,7 @@ def _html_profile_posts(recent_posts_cache: {}, max_recent_posts: int, max_like_count: int, signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Shows posts on the profile screen These should only be public posts """ @@ -1125,7 +1128,8 @@ def _html_profile_posts(recent_posts_cache: {}, max_recent_posts: int, False, False, False, True, False, False, cw_lists, lists_enabled, - timezone, False) + timezone, False, + bold_reading) if post_str: profile_str += post_str + separator_str ctr += 1 @@ -1993,7 +1997,7 @@ def _html_edit_profile_options(is_admin: bool, notify_likes: str, notify_reactions: str, hide_like_button: str, hide_reaction_button: str, - translate: {}) -> str: + translate: {}, bold_reading: bool) -> str: """option checkboxes section of edit profile screen """ edit_profile_form = '
\n' @@ -2025,6 +2029,9 @@ def _html_edit_profile_options(is_admin: bool, edit_profile_form += \ edit_check_box(translate["Don't show the Reaction button"], 'hideReactionButton', hide_reaction_button) + bold_str = bold_reading_string(translate['Bold reading']) + edit_profile_form += \ + edit_check_box(bold_str, 'boldReading', bold_reading) edit_profile_form += '
\n' return edit_profile_form @@ -2158,7 +2165,8 @@ def _html_edit_profile_top_banner(base_dir: str, return edit_profile_form -def html_edit_profile(css_cache: {}, translate: {}, base_dir: str, path: str, +def html_edit_profile(server, css_cache: {}, translate: {}, + base_dir: str, path: str, domain: str, port: int, http_prefix: str, default_timeline: str, theme: str, peertube_instances: [], @@ -2177,6 +2185,10 @@ def html_edit_profile(css_cache: {}, translate: {}, base_dir: str, path: str, return '' domain_full = get_full_domain(domain, port) + bold_reading = False + if server.bold_reading.get(nickname): + bold_reading = True + actor_filename = acct_dir(base_dir, nickname, domain) + '.json' if not os.path.isfile(actor_filename): return '' @@ -2346,7 +2358,7 @@ def html_edit_profile(css_cache: {}, translate: {}, base_dir: str, path: str, remove_twitter, notify_likes, notify_reactions, hide_like_button, hide_reaction_button, - translate) + translate, bold_reading) # Contact information edit_profile_form += \ @@ -2429,6 +2441,8 @@ def _individual_follow_as_html(signing_priv_key_pem: str, """An individual follow entry on the profile screen """ follow_url_nickname = get_nickname_from_actor(followUrl) + if not follow_url_nickname: + return '' follow_url_domain, follow_url_port = get_domain_from_actor(followUrl) follow_url_domain_full = \ get_full_domain(follow_url_domain, follow_url_port) diff --git a/webapp_search.py b/webapp_search.py index 33b9bca3e..5d543e733 100644 --- a/webapp_search.py +++ b/webapp_search.py @@ -380,6 +380,8 @@ def html_search(css_cache: {}, translate: {}, """ actor = path.replace('/search', '') search_nickname = get_nickname_from_actor(actor) + if not search_nickname: + return '' set_custom_background(base_dir, 'search-background', 'follow-background') @@ -611,7 +613,7 @@ def html_history_search(css_cache: {}, translate: {}, base_dir: str, signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show a page containing search results for your post history """ if historysearch.startswith("'"): @@ -699,7 +701,7 @@ def html_history_search(css_cache: {}, translate: {}, base_dir: str, show_individual_post_icons, False, False, False, False, cw_lists, lists_enabled, - timezone, False) + timezone, False, bold_reading) if post_str: history_search_form += separator_str + post_str index += 1 @@ -725,7 +727,7 @@ def html_hashtag_search(css_cache: {}, max_like_count: int, signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show a page containing search results for a hashtag or after selecting a hashtag from the swarm """ @@ -885,7 +887,8 @@ def html_hashtag_search(css_cache: {}, manually_approves_followers, show_public_only, store_to_sache, False, cw_lists, - lists_enabled, timezone, False) + lists_enabled, timezone, False, + bold_reading) if post_str: hashtag_search_form += separator_str + post_str index += 1 diff --git a/webapp_timeline.py b/webapp_timeline.py index 6da01cf05..ccabb2f73 100644 --- a/webapp_timeline.py +++ b/webapp_timeline.py @@ -455,7 +455,7 @@ def html_timeline(css_cache: {}, default_timeline: str, shared_items_federated_domains: [], signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show the timeline as html """ enable_timing_log = False @@ -935,7 +935,8 @@ def html_timeline(css_cache: {}, default_timeline: str, manually_approve_followers, False, True, use_cache_only, cw_lists, lists_enabled, - timezone, mitm) + timezone, mitm, + bold_reading) _log_timeline_timing(enable_timing_log, timeline_start_time, box_name, '12') @@ -1164,7 +1165,7 @@ def html_shares(css_cache: {}, default_timeline: str, shared_items_federated_domains: [], signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show the shares timeline as html """ manually_approve_followers = \ @@ -1194,7 +1195,8 @@ def html_shares(css_cache: {}, default_timeline: str, access_keys, system_language, max_like_count, shared_items_federated_domains, signing_priv_key_pem, - cw_lists, lists_enabled, timezone) + cw_lists, lists_enabled, timezone, + bold_reading) def html_wanted(css_cache: {}, default_timeline: str, @@ -1223,7 +1225,7 @@ def html_wanted(css_cache: {}, default_timeline: str, shared_items_federated_domains: [], signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show the wanted timeline as html """ manually_approve_followers = \ @@ -1253,7 +1255,8 @@ def html_wanted(css_cache: {}, default_timeline: str, access_keys, system_language, max_like_count, shared_items_federated_domains, signing_priv_key_pem, - cw_lists, lists_enabled, timezone) + cw_lists, lists_enabled, timezone, + bold_reading) def html_inbox(css_cache: {}, default_timeline: str, @@ -1283,7 +1286,7 @@ def html_inbox(css_cache: {}, default_timeline: str, shared_items_federated_domains: [], signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show the inbox as html """ manually_approve_followers = \ @@ -1313,7 +1316,8 @@ def html_inbox(css_cache: {}, default_timeline: str, access_keys, system_language, max_like_count, shared_items_federated_domains, signing_priv_key_pem, - cw_lists, lists_enabled, timezone) + cw_lists, lists_enabled, timezone, + bold_reading) def html_bookmarks(css_cache: {}, default_timeline: str, @@ -1343,7 +1347,7 @@ def html_bookmarks(css_cache: {}, default_timeline: str, shared_items_federated_domains: [], signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show the bookmarks as html """ manually_approve_followers = \ @@ -1372,7 +1376,8 @@ def html_bookmarks(css_cache: {}, default_timeline: str, allow_local_network_access, text_mode_banner, access_keys, system_language, max_like_count, shared_items_federated_domains, signing_priv_key_pem, - cw_lists, lists_enabled, timezone) + cw_lists, lists_enabled, timezone, + bold_reading) def html_inbox_dms(css_cache: {}, default_timeline: str, @@ -1402,7 +1407,7 @@ def html_inbox_dms(css_cache: {}, default_timeline: str, shared_items_federated_domains: [], signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show the DM timeline as html """ artist = is_artist(base_dir, nickname) @@ -1427,7 +1432,8 @@ def html_inbox_dms(css_cache: {}, default_timeline: str, access_keys, system_language, max_like_count, shared_items_federated_domains, signing_priv_key_pem, - cw_lists, lists_enabled, timezone) + cw_lists, lists_enabled, timezone, + bold_reading) def html_inbox_replies(css_cache: {}, default_timeline: str, @@ -1457,7 +1463,7 @@ def html_inbox_replies(css_cache: {}, default_timeline: str, shared_items_federated_domains: [], signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show the replies timeline as html """ artist = is_artist(base_dir, nickname) @@ -1481,7 +1487,7 @@ def html_inbox_replies(css_cache: {}, default_timeline: str, allow_local_network_access, text_mode_banner, access_keys, system_language, max_like_count, shared_items_federated_domains, signing_priv_key_pem, - cw_lists, lists_enabled, timezone) + cw_lists, lists_enabled, timezone, bold_reading) def html_inbox_media(css_cache: {}, default_timeline: str, @@ -1511,7 +1517,7 @@ def html_inbox_media(css_cache: {}, default_timeline: str, shared_items_federated_domains: [], signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show the media timeline as html """ artist = is_artist(base_dir, nickname) @@ -1535,7 +1541,7 @@ def html_inbox_media(css_cache: {}, default_timeline: str, allow_local_network_access, text_mode_banner, access_keys, system_language, max_like_count, shared_items_federated_domains, signing_priv_key_pem, - cw_lists, lists_enabled, timezone) + cw_lists, lists_enabled, timezone, bold_reading) def html_inbox_blogs(css_cache: {}, default_timeline: str, @@ -1565,7 +1571,7 @@ def html_inbox_blogs(css_cache: {}, default_timeline: str, shared_items_federated_domains: [], signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show the blogs timeline as html """ artist = is_artist(base_dir, nickname) @@ -1589,7 +1595,7 @@ def html_inbox_blogs(css_cache: {}, default_timeline: str, allow_local_network_access, text_mode_banner, access_keys, system_language, max_like_count, shared_items_federated_domains, signing_priv_key_pem, - cw_lists, lists_enabled, timezone) + cw_lists, lists_enabled, timezone, bold_reading) def html_inbox_features(css_cache: {}, default_timeline: str, @@ -1620,7 +1626,7 @@ def html_inbox_features(css_cache: {}, default_timeline: str, shared_items_federated_domains: [], signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show the features timeline as html """ return html_timeline(css_cache, default_timeline, @@ -1643,7 +1649,7 @@ def html_inbox_features(css_cache: {}, default_timeline: str, allow_local_network_access, text_mode_banner, access_keys, system_language, max_like_count, shared_items_federated_domains, signing_priv_key_pem, - cw_lists, lists_enabled, timezone) + cw_lists, lists_enabled, timezone, bold_reading) def html_inbox_news(css_cache: {}, default_timeline: str, @@ -1673,7 +1679,7 @@ def html_inbox_news(css_cache: {}, default_timeline: str, shared_items_federated_domains: [], signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show the news timeline as html """ return html_timeline(css_cache, default_timeline, @@ -1696,7 +1702,7 @@ def html_inbox_news(css_cache: {}, default_timeline: str, allow_local_network_access, text_mode_banner, access_keys, system_language, max_like_count, shared_items_federated_domains, signing_priv_key_pem, - cw_lists, lists_enabled, timezone) + cw_lists, lists_enabled, timezone, bold_reading) def html_outbox(css_cache: {}, default_timeline: str, @@ -1726,7 +1732,7 @@ def html_outbox(css_cache: {}, default_timeline: str, shared_items_federated_domains: [], signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - timezone: str) -> str: + timezone: str, bold_reading: bool) -> str: """Show the Outbox as html """ manually_approve_followers = \ @@ -1752,4 +1758,4 @@ def html_outbox(css_cache: {}, default_timeline: str, allow_local_network_access, text_mode_banner, access_keys, system_language, max_like_count, shared_items_federated_domains, signing_priv_key_pem, - cw_lists, lists_enabled, timezone) + cw_lists, lists_enabled, timezone, bold_reading) diff --git a/webapp_utils.py b/webapp_utils.py index 47014e269..f4e38f80b 100644 --- a/webapp_utils.py +++ b/webapp_utils.py @@ -418,6 +418,8 @@ def shares_timeline_json(actor: str, pageNumber: int, items_per_page: int, share_actor = share_actor.replace('___', '://') share_actor = share_actor.replace('--', '/') share_nickname = get_nickname_from_actor(share_actor) + if not share_nickname: + continue if is_blocked(base_dir, nickname, domain, share_nickname, federated_domain, None): continue @@ -1538,6 +1540,8 @@ def html_search_result_share(base_dir: str, shared_item: {}, translate: {}, # should the remove button be shown? show_remove_button = False nickname = get_nickname_from_actor(actor) + if not nickname: + return '' if actor.endswith('/users/' + contact_nickname): show_remove_button = True elif is_moderator(base_dir, nickname):