mirror of https://gitlab.com/bashrc2/epicyon
				
				
				
			
		
			
				
	
	
		
			1424 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			1424 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			Python
		
	
	
__filename__ = "daemon_get_post.py"
 | 
						|
__author__ = "Bob Mottram"
 | 
						|
__license__ = "AGPL3+"
 | 
						|
__version__ = "1.6.0"
 | 
						|
__maintainer__ = "Bob Mottram"
 | 
						|
__email__ = "bob@libreserver.org"
 | 
						|
__status__ = "Production"
 | 
						|
__module_group__ = "Daemon Timeline"
 | 
						|
 | 
						|
import os
 | 
						|
import json
 | 
						|
from webapp_conversation import html_conversation_view
 | 
						|
from flags import is_public_post_from_url
 | 
						|
from flags import is_public_post
 | 
						|
from flags import is_premium_account
 | 
						|
from utils import get_instance_url
 | 
						|
from utils import local_actor_url
 | 
						|
from utils import locate_post
 | 
						|
from utils import get_config_param
 | 
						|
from utils import can_reply_to
 | 
						|
from utils import get_nickname_from_actor
 | 
						|
from utils import get_new_post_endpoints
 | 
						|
from utils import acct_dir
 | 
						|
from utils import get_json_content_from_accept
 | 
						|
from utils import convert_domains
 | 
						|
from utils import has_object_dict
 | 
						|
from utils import load_json
 | 
						|
from utils import detect_mitm
 | 
						|
from session import establish_session
 | 
						|
from languages import get_understood_languages
 | 
						|
from languages import get_reply_language
 | 
						|
from httpcodes import write2
 | 
						|
from httpcodes import http_401
 | 
						|
from httpcodes import http_403
 | 
						|
from httpcodes import http_404
 | 
						|
from httpheaders import set_headers
 | 
						|
from httpheaders import set_html_post_headers
 | 
						|
from httpheaders import login_headers
 | 
						|
from httpheaders import redirect_headers
 | 
						|
from httprequests import request_http
 | 
						|
from posts import populate_replies_json
 | 
						|
from posts import remove_post_interactions
 | 
						|
from webapp_post import html_post_replies
 | 
						|
from webapp_post import html_individual_post
 | 
						|
from webapp_create_post import html_new_post
 | 
						|
from webapp_likers import html_likers_of_post
 | 
						|
from fitnessFunctions import fitness_performance
 | 
						|
from securemode import secure_mode
 | 
						|
from context import get_individual_post_context
 | 
						|
from conversation import convthread_id_to_conversation_tag
 | 
						|
 | 
						|
 | 
						|
def _show_post_from_file(self, post_filename: str, liked_by: str,
 | 
						|
                         react_by: str, react_emoji: str,
 | 
						|
                         authorized: bool,
 | 
						|
                         calling_domain: str, referer_domain: str,
 | 
						|
                         base_dir: str, http_prefix: str, nickname: str,
 | 
						|
                         domain: str, port: int,
 | 
						|
                         getreq_start_time,
 | 
						|
                         proxy_type: str, cookie: str,
 | 
						|
                         debug: str, include_create_wrapper: bool,
 | 
						|
                         curr_session, translate: {},
 | 
						|
                         account_timezone: {},
 | 
						|
                         bold_reading_nicknames: {},
 | 
						|
                         recent_posts_cache: {},
 | 
						|
                         max_recent_posts: int,
 | 
						|
                         cached_webfingers: {},
 | 
						|
                         person_cache: {},
 | 
						|
                         project_version: str,
 | 
						|
                         yt_replace_domain: str,
 | 
						|
                         twitter_replacement_domain: str,
 | 
						|
                         show_published_date_only: bool,
 | 
						|
                         peertube_instances: [],
 | 
						|
                         allow_local_network_access: bool,
 | 
						|
                         theme_name: str,
 | 
						|
                         system_language: str,
 | 
						|
                         max_like_count: int,
 | 
						|
                         signing_priv_key_pem: str,
 | 
						|
                         cw_lists: {},
 | 
						|
                         lists_enabled: {},
 | 
						|
                         dogwhistles: {},
 | 
						|
                         min_images_for_accounts: [],
 | 
						|
                         buy_sites: [],
 | 
						|
                         auto_cw_cache: {},
 | 
						|
                         fitness: {}, path: str,
 | 
						|
                         onion_domain: str,
 | 
						|
                         i2p_domain: str,
 | 
						|
                         mitm_servers: [],
 | 
						|
                         instance_software: {}) -> bool:
 | 
						|
    """Shows an individual post from its filename
 | 
						|
    """
 | 
						|
    if not os.path.isfile(post_filename):
 | 
						|
        http_404(self, 71)
 | 
						|
        self.server.getreq_busy = False
 | 
						|
        return True
 | 
						|
 | 
						|
    # if this is a premium account and the viewer is unauthorized
 | 
						|
    if not authorized:
 | 
						|
        if is_premium_account(base_dir, nickname, domain):
 | 
						|
            http_401(self, translate['Premium account'])
 | 
						|
            self.server.getreq_busy = False
 | 
						|
            return True
 | 
						|
 | 
						|
    post_json_object = load_json(post_filename)
 | 
						|
    if not post_json_object:
 | 
						|
        self.send_response(429)
 | 
						|
        self.end_headers()
 | 
						|
        self.server.getreq_busy = False
 | 
						|
        return True
 | 
						|
 | 
						|
    # Only authorized viewers get to see likes on posts
 | 
						|
    # Otherwize marketers could gain more social graph info
 | 
						|
    if not authorized:
 | 
						|
        pjo = post_json_object
 | 
						|
        if not is_public_post(pjo):
 | 
						|
            # only public posts may be viewed by unauthorized viewers
 | 
						|
            http_401(self, 'only public posts ' +
 | 
						|
                     'may be viewed by unauthorized viewers')
 | 
						|
            self.server.getreq_busy = False
 | 
						|
            return True
 | 
						|
        remove_post_interactions(pjo, True)
 | 
						|
    if request_http(self.headers, debug):
 | 
						|
        timezone = None
 | 
						|
        if account_timezone.get(nickname):
 | 
						|
            timezone = account_timezone.get(nickname)
 | 
						|
 | 
						|
        mitm = detect_mitm(self)
 | 
						|
        if not mitm:
 | 
						|
            mitm_filename = \
 | 
						|
                post_filename.replace('.json', '') + '.mitm'
 | 
						|
            if os.path.isfile(mitm_filename):
 | 
						|
                mitm = True
 | 
						|
 | 
						|
        bold_reading = False
 | 
						|
        if bold_reading_nicknames.get(nickname):
 | 
						|
            bold_reading = True
 | 
						|
 | 
						|
        msg = \
 | 
						|
            html_individual_post(recent_posts_cache,
 | 
						|
                                 max_recent_posts,
 | 
						|
                                 translate,
 | 
						|
                                 base_dir,
 | 
						|
                                 curr_session,
 | 
						|
                                 cached_webfingers,
 | 
						|
                                 person_cache,
 | 
						|
                                 nickname, domain, port,
 | 
						|
                                 authorized,
 | 
						|
                                 post_json_object,
 | 
						|
                                 http_prefix,
 | 
						|
                                 project_version,
 | 
						|
                                 liked_by, react_by, react_emoji,
 | 
						|
                                 yt_replace_domain,
 | 
						|
                                 twitter_replacement_domain,
 | 
						|
                                 show_published_date_only,
 | 
						|
                                 peertube_instances,
 | 
						|
                                 allow_local_network_access,
 | 
						|
                                 theme_name,
 | 
						|
                                 system_language,
 | 
						|
                                 max_like_count,
 | 
						|
                                 signing_priv_key_pem,
 | 
						|
                                 cw_lists,
 | 
						|
                                 lists_enabled,
 | 
						|
                                 timezone, mitm, bold_reading,
 | 
						|
                                 dogwhistles,
 | 
						|
                                 min_images_for_accounts,
 | 
						|
                                 buy_sites,
 | 
						|
                                 auto_cw_cache,
 | 
						|
                                 mitm_servers,
 | 
						|
                                 instance_software)
 | 
						|
        msg = msg.encode('utf-8')
 | 
						|
        msglen = len(msg)
 | 
						|
        set_html_post_headers(self, msglen,
 | 
						|
                              cookie, calling_domain, False,
 | 
						|
                              post_json_object)
 | 
						|
        write2(self, msg)
 | 
						|
        fitness_performance(getreq_start_time, fitness,
 | 
						|
                            '_GET', 'show_post_from_file',
 | 
						|
                            debug)
 | 
						|
    else:
 | 
						|
        if secure_mode(curr_session, proxy_type, False,
 | 
						|
                       self.server, self.headers, path):
 | 
						|
            if not include_create_wrapper and \
 | 
						|
               post_json_object['type'] == 'Create' and \
 | 
						|
               has_object_dict(post_json_object):
 | 
						|
                unwrapped_json = post_json_object['object']
 | 
						|
                unwrapped_json['@context'] = \
 | 
						|
                    get_individual_post_context()
 | 
						|
                msg_str = json.dumps(unwrapped_json,
 | 
						|
                                     ensure_ascii=False)
 | 
						|
            else:
 | 
						|
                msg_str = json.dumps(post_json_object,
 | 
						|
                                     ensure_ascii=False)
 | 
						|
            msg_str = convert_domains(calling_domain,
 | 
						|
                                      referer_domain,
 | 
						|
                                      msg_str, http_prefix,
 | 
						|
                                      domain,
 | 
						|
                                      onion_domain,
 | 
						|
                                      i2p_domain)
 | 
						|
            msg = msg_str.encode('utf-8')
 | 
						|
            msglen = len(msg)
 | 
						|
            protocol_str = \
 | 
						|
                get_json_content_from_accept(self.headers['Accept'])
 | 
						|
            set_headers(self, protocol_str, msglen,
 | 
						|
                        None, calling_domain, False)
 | 
						|
            write2(self, msg)
 | 
						|
            fitness_performance(getreq_start_time, fitness,
 | 
						|
                                '_GET', 'show_post_from_file json',
 | 
						|
                                debug)
 | 
						|
        else:
 | 
						|
            http_404(self, 73)
 | 
						|
    self.server.getreq_busy = False
 | 
						|
    return True
 | 
						|
 | 
						|
 | 
						|
def show_individual_post(self, ssml_getreq: bool, authorized: bool,
 | 
						|
                         calling_domain: str, referer_domain: str,
 | 
						|
                         path: str,
 | 
						|
                         base_dir: str, http_prefix: str,
 | 
						|
                         domain: str, domain_full: str, port: int,
 | 
						|
                         getreq_start_time,
 | 
						|
                         proxy_type: str, cookie: str,
 | 
						|
                         debug: str,
 | 
						|
                         curr_session, translate: {},
 | 
						|
                         account_timezone: {},
 | 
						|
                         fitness: {},
 | 
						|
                         bold_reading_nicknames: {},
 | 
						|
                         recent_posts_cache: {},
 | 
						|
                         max_recent_posts: int,
 | 
						|
                         cached_webfingers: {},
 | 
						|
                         person_cache: {},
 | 
						|
                         project_version: str,
 | 
						|
                         yt_replace_domain: str,
 | 
						|
                         twitter_replacement_domain: str,
 | 
						|
                         show_published_date_only: bool,
 | 
						|
                         peertube_instances: [],
 | 
						|
                         allow_local_network_access: bool,
 | 
						|
                         theme_name: str,
 | 
						|
                         system_language: str,
 | 
						|
                         max_like_count: int,
 | 
						|
                         signing_priv_key_pem: str,
 | 
						|
                         cw_lists: {},
 | 
						|
                         lists_enabled: {},
 | 
						|
                         dogwhistles: {},
 | 
						|
                         min_images_for_accounts: [],
 | 
						|
                         buy_sites: [],
 | 
						|
                         auto_cw_cache: {},
 | 
						|
                         onion_domain: str,
 | 
						|
                         i2p_domain: str,
 | 
						|
                         mitm_servers: [],
 | 
						|
                         instance_software: {}) -> bool:
 | 
						|
    """Shows an individual post
 | 
						|
    """
 | 
						|
    liked_by = None
 | 
						|
    if '?likedBy=' in path:
 | 
						|
        liked_by = path.split('?likedBy=')[1].strip()
 | 
						|
        if '?' in liked_by:
 | 
						|
            liked_by = liked_by.split('?')[0]
 | 
						|
        path = path.split('?likedBy=')[0]
 | 
						|
 | 
						|
    react_by = None
 | 
						|
    react_emoji = None
 | 
						|
    if '?reactBy=' in path:
 | 
						|
        react_by = path.split('?reactBy=')[1].strip()
 | 
						|
        if ';' in react_by:
 | 
						|
            react_by = react_by.split(';')[0]
 | 
						|
        if ';emoj=' in path:
 | 
						|
            react_emoji = path.split(';emoj=')[1].strip()
 | 
						|
            if ';' in react_emoji:
 | 
						|
                react_emoji = react_emoji.split(';')[0]
 | 
						|
        path = path.split('?reactBy=')[0]
 | 
						|
 | 
						|
    named_status = path.split('/users/')[1]
 | 
						|
    if '/' not in named_status:
 | 
						|
        return False
 | 
						|
    post_sections = named_status.split('/')
 | 
						|
    if len(post_sections) < 3:
 | 
						|
        return False
 | 
						|
    nickname = post_sections[0]
 | 
						|
    status_number = post_sections[2]
 | 
						|
    if len(status_number) <= 10 or (not status_number.isdigit()):
 | 
						|
        return False
 | 
						|
 | 
						|
    if ssml_getreq:
 | 
						|
        ssml_filename = \
 | 
						|
            acct_dir(base_dir, nickname, domain) + '/outbox/' + \
 | 
						|
            http_prefix + ':##' + domain_full + '#users#' + nickname + \
 | 
						|
            '#statuses#' + status_number + '.ssml'
 | 
						|
        if not os.path.isfile(ssml_filename):
 | 
						|
            ssml_filename = \
 | 
						|
                acct_dir(base_dir, nickname, domain) + '/postcache/' + \
 | 
						|
                http_prefix + ':##' + domain_full + '#users#' + \
 | 
						|
                nickname + '#statuses#' + status_number + '.ssml'
 | 
						|
        if not os.path.isfile(ssml_filename):
 | 
						|
            http_404(self, 74)
 | 
						|
            return True
 | 
						|
        ssml_str = None
 | 
						|
        try:
 | 
						|
            with open(ssml_filename, 'r', encoding='utf-8') as fp_ssml:
 | 
						|
                ssml_str = fp_ssml.read()
 | 
						|
        except OSError:
 | 
						|
            print('EX: unable to read ssml file ' + ssml_filename)
 | 
						|
        if ssml_str:
 | 
						|
            msg = ssml_str.encode('utf-8')
 | 
						|
            msglen = len(msg)
 | 
						|
            set_headers(self, 'application/ssml+xml', msglen,
 | 
						|
                        cookie, calling_domain, False)
 | 
						|
            write2(self, msg)
 | 
						|
            return True
 | 
						|
        http_404(self, 75)
 | 
						|
        return True
 | 
						|
 | 
						|
    post_filename = \
 | 
						|
        acct_dir(base_dir, nickname, domain) + '/outbox/' + \
 | 
						|
        http_prefix + ':##' + domain_full + '#users#' + nickname + \
 | 
						|
        '#statuses#' + status_number + '.json'
 | 
						|
 | 
						|
    include_create_wrapper = False
 | 
						|
    if post_sections[-1] == 'activity':
 | 
						|
        include_create_wrapper = True
 | 
						|
 | 
						|
    result = _show_post_from_file(self, post_filename, liked_by,
 | 
						|
                                  react_by, react_emoji,
 | 
						|
                                  authorized, calling_domain,
 | 
						|
                                  referer_domain,
 | 
						|
                                  base_dir, http_prefix, nickname,
 | 
						|
                                  domain, port,
 | 
						|
                                  getreq_start_time,
 | 
						|
                                  proxy_type, cookie, debug,
 | 
						|
                                  include_create_wrapper,
 | 
						|
                                  curr_session, translate,
 | 
						|
                                  account_timezone,
 | 
						|
                                  bold_reading_nicknames,
 | 
						|
                                  recent_posts_cache,
 | 
						|
                                  max_recent_posts,
 | 
						|
                                  cached_webfingers,
 | 
						|
                                  person_cache,
 | 
						|
                                  project_version,
 | 
						|
                                  yt_replace_domain,
 | 
						|
                                  twitter_replacement_domain,
 | 
						|
                                  show_published_date_only,
 | 
						|
                                  peertube_instances,
 | 
						|
                                  allow_local_network_access,
 | 
						|
                                  theme_name,
 | 
						|
                                  system_language,
 | 
						|
                                  max_like_count,
 | 
						|
                                  signing_priv_key_pem,
 | 
						|
                                  cw_lists,
 | 
						|
                                  lists_enabled,
 | 
						|
                                  dogwhistles,
 | 
						|
                                  min_images_for_accounts,
 | 
						|
                                  buy_sites,
 | 
						|
                                  auto_cw_cache,
 | 
						|
                                  fitness, path,
 | 
						|
                                  onion_domain,
 | 
						|
                                  i2p_domain,
 | 
						|
                                  mitm_servers,
 | 
						|
                                  instance_software)
 | 
						|
 | 
						|
    fitness_performance(getreq_start_time, fitness,
 | 
						|
                        '_GET', 'show_individual_post',
 | 
						|
                        debug)
 | 
						|
    return result
 | 
						|
 | 
						|
 | 
						|
def show_new_post(self, edit_post_params: {},
 | 
						|
                  calling_domain: str, path: str,
 | 
						|
                  media_instance: bool, translate: {},
 | 
						|
                  base_dir: str, http_prefix: str,
 | 
						|
                  in_reply_to_url: str, reply_to_list: [],
 | 
						|
                  reply_is_chat: bool,
 | 
						|
                  share_description: str, reply_page_number: int,
 | 
						|
                  reply_category: str,
 | 
						|
                  domain: str, domain_full: str,
 | 
						|
                  getreq_start_time, cookie,
 | 
						|
                  no_drop_down: bool, conversation_id: str,
 | 
						|
                  convthread_id: str,
 | 
						|
                  curr_session, default_reply_interval_hrs: int,
 | 
						|
                  debug: bool, access_keys: {},
 | 
						|
                  key_shortcuts: {}, system_language: str,
 | 
						|
                  default_post_language: {},
 | 
						|
                  bold_reading_nicknames: {},
 | 
						|
                  person_cache: {},
 | 
						|
                  fitness: {},
 | 
						|
                  default_timeline: str,
 | 
						|
                  newswire: {},
 | 
						|
                  theme_name: str,
 | 
						|
                  recent_posts_cache: {},
 | 
						|
                  max_recent_posts: int,
 | 
						|
                  cached_webfingers: {},
 | 
						|
                  port: int,
 | 
						|
                  project_version: str,
 | 
						|
                  yt_replace_domain: str,
 | 
						|
                  twitter_replacement_domain: str,
 | 
						|
                  show_published_date_only: bool,
 | 
						|
                  peertube_instances: [],
 | 
						|
                  allow_local_network_access: bool,
 | 
						|
                  max_like_count: int,
 | 
						|
                  signing_priv_key_pem: str,
 | 
						|
                  cw_lists: {},
 | 
						|
                  lists_enabled: {},
 | 
						|
                  dogwhistles: {},
 | 
						|
                  min_images_for_accounts: [],
 | 
						|
                  buy_sites: [],
 | 
						|
                  auto_cw_cache: {},
 | 
						|
                  searchable_by_default_dict: [],
 | 
						|
                  mitm_servers: [],
 | 
						|
                  instance_software: {}) -> bool:
 | 
						|
    """Shows the new post screen
 | 
						|
    """
 | 
						|
    searchable_by_default = 'yourself'
 | 
						|
    is_new_post_endpoint = False
 | 
						|
    new_post_month = None
 | 
						|
    new_post_year = None
 | 
						|
    if '/users/' in path and '/new' in path:
 | 
						|
        if '?month=' in path:
 | 
						|
            month_str = path.split('?month=')[1]
 | 
						|
            if ';' in month_str:
 | 
						|
                month_str = month_str.split(';')[0]
 | 
						|
            if month_str.isdigit():
 | 
						|
                new_post_month = int(month_str)
 | 
						|
        if new_post_month and ';year=' in path:
 | 
						|
            year_str = path.split(';year=')[1]
 | 
						|
            if ';' in year_str:
 | 
						|
                year_str = year_str.split(';')[0]
 | 
						|
            if year_str.isdigit():
 | 
						|
                new_post_year = int(year_str)
 | 
						|
            if new_post_year:
 | 
						|
                path = path.split('?month=')[0]
 | 
						|
        # Various types of new post in the web interface
 | 
						|
        new_post_endpoints = get_new_post_endpoints()
 | 
						|
        for curr_post_type in new_post_endpoints:
 | 
						|
            if path.endswith('/' + curr_post_type):
 | 
						|
                is_new_post_endpoint = True
 | 
						|
                break
 | 
						|
    if is_new_post_endpoint:
 | 
						|
        nickname = get_nickname_from_actor(path)
 | 
						|
        if not nickname:
 | 
						|
            http_404(self, 103)
 | 
						|
            return True
 | 
						|
        if searchable_by_default_dict.get(nickname):
 | 
						|
            searchable_by_default = searchable_by_default_dict[nickname]
 | 
						|
        if in_reply_to_url:
 | 
						|
            reply_interval_hours = default_reply_interval_hrs
 | 
						|
            if not can_reply_to(base_dir, nickname, domain,
 | 
						|
                                in_reply_to_url, reply_interval_hours):
 | 
						|
                print('Reply outside of time window ' + in_reply_to_url +
 | 
						|
                      ' ' + str(reply_interval_hours) + ' hours')
 | 
						|
                http_403(self)
 | 
						|
                return True
 | 
						|
            if debug:
 | 
						|
                print('Reply is within time interval: ' +
 | 
						|
                      str(reply_interval_hours) + ' hours')
 | 
						|
 | 
						|
        if key_shortcuts.get(nickname):
 | 
						|
            access_keys = key_shortcuts[nickname]
 | 
						|
 | 
						|
        custom_submit_text = get_config_param(base_dir, 'customSubmitText')
 | 
						|
 | 
						|
        default_post_language2 = system_language
 | 
						|
        if default_post_language.get(nickname):
 | 
						|
            default_post_language2 = default_post_language[nickname]
 | 
						|
 | 
						|
        post_json_object = None
 | 
						|
        if in_reply_to_url:
 | 
						|
            reply_post_filename = \
 | 
						|
                locate_post(base_dir, nickname, domain, in_reply_to_url)
 | 
						|
            if reply_post_filename:
 | 
						|
                post_json_object = load_json(reply_post_filename)
 | 
						|
                if post_json_object:
 | 
						|
                    reply_language = \
 | 
						|
                        get_reply_language(base_dir, post_json_object)
 | 
						|
                    if reply_language:
 | 
						|
                        default_post_language2 = reply_language
 | 
						|
 | 
						|
        bold_reading = False
 | 
						|
        if bold_reading_nicknames.get(nickname):
 | 
						|
            bold_reading = True
 | 
						|
 | 
						|
        languages_understood = \
 | 
						|
            get_understood_languages(base_dir,
 | 
						|
                                     http_prefix,
 | 
						|
                                     nickname,
 | 
						|
                                     domain_full,
 | 
						|
                                     person_cache)
 | 
						|
        default_buy_site = ''
 | 
						|
        msg = \
 | 
						|
            html_new_post(edit_post_params, media_instance,
 | 
						|
                          translate,
 | 
						|
                          base_dir,
 | 
						|
                          http_prefix,
 | 
						|
                          path, in_reply_to_url,
 | 
						|
                          reply_to_list,
 | 
						|
                          share_description, None,
 | 
						|
                          reply_page_number,
 | 
						|
                          reply_category,
 | 
						|
                          nickname, domain,
 | 
						|
                          domain_full,
 | 
						|
                          default_timeline,
 | 
						|
                          newswire,
 | 
						|
                          theme_name,
 | 
						|
                          no_drop_down, access_keys,
 | 
						|
                          custom_submit_text,
 | 
						|
                          conversation_id, convthread_id,
 | 
						|
                          recent_posts_cache,
 | 
						|
                          max_recent_posts,
 | 
						|
                          curr_session,
 | 
						|
                          cached_webfingers,
 | 
						|
                          person_cache,
 | 
						|
                          port,
 | 
						|
                          post_json_object,
 | 
						|
                          project_version,
 | 
						|
                          yt_replace_domain,
 | 
						|
                          twitter_replacement_domain,
 | 
						|
                          show_published_date_only,
 | 
						|
                          peertube_instances,
 | 
						|
                          allow_local_network_access,
 | 
						|
                          system_language,
 | 
						|
                          languages_understood,
 | 
						|
                          max_like_count,
 | 
						|
                          signing_priv_key_pem,
 | 
						|
                          cw_lists,
 | 
						|
                          lists_enabled,
 | 
						|
                          default_timeline,
 | 
						|
                          reply_is_chat,
 | 
						|
                          bold_reading,
 | 
						|
                          dogwhistles,
 | 
						|
                          min_images_for_accounts,
 | 
						|
                          new_post_month, new_post_year,
 | 
						|
                          default_post_language2,
 | 
						|
                          buy_sites,
 | 
						|
                          default_buy_site,
 | 
						|
                          auto_cw_cache,
 | 
						|
                          searchable_by_default,
 | 
						|
                          mitm_servers,
 | 
						|
                          instance_software)
 | 
						|
        if not msg:
 | 
						|
            print('Error replying to ' + in_reply_to_url)
 | 
						|
            http_404(self, 104)
 | 
						|
            return True
 | 
						|
        msg = msg.encode('utf-8')
 | 
						|
        msglen = len(msg)
 | 
						|
        set_headers(self, 'text/html', msglen,
 | 
						|
                    cookie, calling_domain, False)
 | 
						|
        write2(self, msg)
 | 
						|
        fitness_performance(getreq_start_time, fitness,
 | 
						|
                            '_GET', 'show_new_post',
 | 
						|
                            debug)
 | 
						|
        return True
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def show_individual_at_post(self, ssml_getreq: bool, authorized: bool,
 | 
						|
                            calling_domain: str, referer_domain: str,
 | 
						|
                            path: str,
 | 
						|
                            base_dir: str, http_prefix: str,
 | 
						|
                            domain: str, domain_full: str, port: int,
 | 
						|
                            getreq_start_time,
 | 
						|
                            proxy_type: str, cookie: str,
 | 
						|
                            debug: str,
 | 
						|
                            curr_session, translate: {},
 | 
						|
                            account_timezone: {},
 | 
						|
                            fitness: {},
 | 
						|
                            recent_posts_cache: {},
 | 
						|
                            max_recent_posts: int,
 | 
						|
                            cached_webfingers: {},
 | 
						|
                            person_cache: {},
 | 
						|
                            project_version: str,
 | 
						|
                            yt_replace_domain: str,
 | 
						|
                            twitter_replacement_domain: str,
 | 
						|
                            show_published_date_only: bool,
 | 
						|
                            peertube_instances: [],
 | 
						|
                            allow_local_network_access: bool,
 | 
						|
                            theme_name: str,
 | 
						|
                            system_language: str,
 | 
						|
                            max_like_count: int,
 | 
						|
                            signing_priv_key_pem: str,
 | 
						|
                            cw_lists: {},
 | 
						|
                            lists_enabled: {},
 | 
						|
                            dogwhistles: {},
 | 
						|
                            min_images_for_accounts: [],
 | 
						|
                            buy_sites: [],
 | 
						|
                            auto_cw_cache: {},
 | 
						|
                            onion_domain: str,
 | 
						|
                            i2p_domain: str,
 | 
						|
                            bold_reading_nicknames: {},
 | 
						|
                            mitm_servers: [],
 | 
						|
                            instance_software: {}) -> bool:
 | 
						|
    """get an individual post from the path /@nickname/statusnumber
 | 
						|
    """
 | 
						|
    if '/@' not in path:
 | 
						|
        return False
 | 
						|
 | 
						|
    liked_by = None
 | 
						|
    if '?likedBy=' in path:
 | 
						|
        liked_by = path.split('?likedBy=')[1].strip()
 | 
						|
        if '?' in liked_by:
 | 
						|
            liked_by = liked_by.split('?')[0]
 | 
						|
        path = path.split('?likedBy=')[0]
 | 
						|
 | 
						|
    react_by = None
 | 
						|
    react_emoji = None
 | 
						|
    if '?reactBy=' in path:
 | 
						|
        react_by = path.split('?reactBy=')[1].strip()
 | 
						|
        if ';' in react_by:
 | 
						|
            react_by = react_by.split(';')[0]
 | 
						|
        if ';emoj=' in path:
 | 
						|
            react_emoji = path.split(';emoj=')[1].strip()
 | 
						|
            if ';' in react_emoji:
 | 
						|
                react_emoji = react_emoji.split(';')[0]
 | 
						|
        path = path.split('?reactBy=')[0]
 | 
						|
 | 
						|
    named_status = path.split('/@')[1]
 | 
						|
    if '/' not in named_status:
 | 
						|
        # show actor
 | 
						|
        nickname = named_status
 | 
						|
        return False
 | 
						|
 | 
						|
    post_sections = named_status.split('/')
 | 
						|
    if len(post_sections) != 2:
 | 
						|
        return False
 | 
						|
    nickname = post_sections[0]
 | 
						|
    status_number = post_sections[1]
 | 
						|
    if len(status_number) <= 10 or not status_number.isdigit():
 | 
						|
        return False
 | 
						|
 | 
						|
    if ssml_getreq:
 | 
						|
        ssml_filename = \
 | 
						|
            acct_dir(base_dir, nickname, domain) + '/outbox/' + \
 | 
						|
            http_prefix + ':##' + domain_full + '#users#' + nickname + \
 | 
						|
            '#statuses#' + status_number + '.ssml'
 | 
						|
        if not os.path.isfile(ssml_filename):
 | 
						|
            ssml_filename = \
 | 
						|
                acct_dir(base_dir, nickname, domain) + '/postcache/' + \
 | 
						|
                http_prefix + ':##' + domain_full + '#users#' + \
 | 
						|
                nickname + '#statuses#' + status_number + '.ssml'
 | 
						|
        if not os.path.isfile(ssml_filename):
 | 
						|
            http_404(self, 67)
 | 
						|
            return True
 | 
						|
        ssml_str = None
 | 
						|
        try:
 | 
						|
            with open(ssml_filename, 'r', encoding='utf-8') as fp_ssml:
 | 
						|
                ssml_str = fp_ssml.read()
 | 
						|
        except OSError:
 | 
						|
            print('EX: unable to read ssml file 2 ' + ssml_filename)
 | 
						|
        if ssml_str:
 | 
						|
            msg = ssml_str.encode('utf-8')
 | 
						|
            msglen = len(msg)
 | 
						|
            set_headers(self, 'application/ssml+xml', msglen,
 | 
						|
                        cookie, calling_domain, False)
 | 
						|
            write2(self, msg)
 | 
						|
            return True
 | 
						|
        http_404(self, 68)
 | 
						|
        return True
 | 
						|
 | 
						|
    post_filename = \
 | 
						|
        acct_dir(base_dir, nickname, domain) + '/outbox/' + \
 | 
						|
        http_prefix + ':##' + domain_full + '#users#' + nickname + \
 | 
						|
        '#statuses#' + status_number + '.json'
 | 
						|
 | 
						|
    include_create_wrapper = False
 | 
						|
    if post_sections[-1] == 'activity':
 | 
						|
        include_create_wrapper = True
 | 
						|
 | 
						|
    result = _show_post_from_file(self, post_filename, liked_by,
 | 
						|
                                  react_by, react_emoji,
 | 
						|
                                  authorized, calling_domain,
 | 
						|
                                  referer_domain,
 | 
						|
                                  base_dir, http_prefix, nickname,
 | 
						|
                                  domain, port,
 | 
						|
                                  getreq_start_time,
 | 
						|
                                  proxy_type, cookie, debug,
 | 
						|
                                  include_create_wrapper,
 | 
						|
                                  curr_session, translate,
 | 
						|
                                  account_timezone,
 | 
						|
                                  bold_reading_nicknames,
 | 
						|
                                  recent_posts_cache,
 | 
						|
                                  max_recent_posts,
 | 
						|
                                  cached_webfingers,
 | 
						|
                                  person_cache,
 | 
						|
                                  project_version,
 | 
						|
                                  yt_replace_domain,
 | 
						|
                                  twitter_replacement_domain,
 | 
						|
                                  show_published_date_only,
 | 
						|
                                  peertube_instances,
 | 
						|
                                  allow_local_network_access,
 | 
						|
                                  theme_name,
 | 
						|
                                  system_language,
 | 
						|
                                  max_like_count,
 | 
						|
                                  signing_priv_key_pem,
 | 
						|
                                  cw_lists,
 | 
						|
                                  lists_enabled,
 | 
						|
                                  dogwhistles,
 | 
						|
                                  min_images_for_accounts,
 | 
						|
                                  buy_sites,
 | 
						|
                                  auto_cw_cache,
 | 
						|
                                  fitness, path,
 | 
						|
                                  onion_domain,
 | 
						|
                                  i2p_domain,
 | 
						|
                                  mitm_servers,
 | 
						|
                                  instance_software)
 | 
						|
 | 
						|
    fitness_performance(getreq_start_time, fitness,
 | 
						|
                        '_GET', 'show_individual_at_post',
 | 
						|
                        debug)
 | 
						|
    return result
 | 
						|
 | 
						|
 | 
						|
def show_likers_of_post(self, authorized: bool,
 | 
						|
                        calling_domain: str, path: str,
 | 
						|
                        base_dir: str, http_prefix: str,
 | 
						|
                        domain: str, port: int,
 | 
						|
                        getreq_start_time, cookie: str,
 | 
						|
                        debug: str, curr_session,
 | 
						|
                        bold_reading_nicknames: {},
 | 
						|
                        translate: {},
 | 
						|
                        theme_name: str,
 | 
						|
                        access_keys: {},
 | 
						|
                        recent_posts_cache: {},
 | 
						|
                        max_recent_posts: int,
 | 
						|
                        cached_webfingers: {},
 | 
						|
                        person_cache: {},
 | 
						|
                        project_version: str,
 | 
						|
                        yt_replace_domain: str,
 | 
						|
                        twitter_replacement_domain: str,
 | 
						|
                        show_published_date_only: bool,
 | 
						|
                        peertube_instances: [],
 | 
						|
                        allow_local_network_access: bool,
 | 
						|
                        system_language: str,
 | 
						|
                        max_like_count: int,
 | 
						|
                        signing_priv_key_pem: str,
 | 
						|
                        cw_lists: {},
 | 
						|
                        lists_enabled: {},
 | 
						|
                        default_timeline: str,
 | 
						|
                        dogwhistles: {},
 | 
						|
                        min_images_for_accounts: [],
 | 
						|
                        buy_sites: [],
 | 
						|
                        auto_cw_cache: {},
 | 
						|
                        fitness: {},
 | 
						|
                        mitm_servers: [],
 | 
						|
                        instance_software: {}) -> bool:
 | 
						|
    """Show the likers of a post
 | 
						|
    """
 | 
						|
    if not authorized:
 | 
						|
        return False
 | 
						|
    if '?likers=' not in path:
 | 
						|
        return False
 | 
						|
    if '/users/' not in path:
 | 
						|
        return False
 | 
						|
    nickname = path.split('/users/')[1]
 | 
						|
    if '?' in nickname:
 | 
						|
        nickname = nickname.split('?')[0]
 | 
						|
    post_url = path.split('?likers=')[1]
 | 
						|
    if '?' in post_url:
 | 
						|
        post_url = post_url.split('?')[0]
 | 
						|
    post_url = post_url.replace('--', '/')
 | 
						|
 | 
						|
    bold_reading = False
 | 
						|
    if bold_reading_nicknames.get(nickname):
 | 
						|
        bold_reading = True
 | 
						|
 | 
						|
    msg = \
 | 
						|
        html_likers_of_post(base_dir, nickname, domain, port,
 | 
						|
                            post_url, translate,
 | 
						|
                            http_prefix,
 | 
						|
                            theme_name,
 | 
						|
                            access_keys,
 | 
						|
                            recent_posts_cache,
 | 
						|
                            max_recent_posts,
 | 
						|
                            curr_session,
 | 
						|
                            cached_webfingers,
 | 
						|
                            person_cache,
 | 
						|
                            project_version,
 | 
						|
                            yt_replace_domain,
 | 
						|
                            twitter_replacement_domain,
 | 
						|
                            show_published_date_only,
 | 
						|
                            peertube_instances,
 | 
						|
                            allow_local_network_access,
 | 
						|
                            system_language,
 | 
						|
                            max_like_count,
 | 
						|
                            signing_priv_key_pem,
 | 
						|
                            cw_lists,
 | 
						|
                            lists_enabled,
 | 
						|
                            'inbox', default_timeline,
 | 
						|
                            bold_reading,
 | 
						|
                            dogwhistles,
 | 
						|
                            min_images_for_accounts,
 | 
						|
                            buy_sites,
 | 
						|
                            auto_cw_cache, 'likes',
 | 
						|
                            mitm_servers,
 | 
						|
                            instance_software)
 | 
						|
    if not msg:
 | 
						|
        http_404(self, 69)
 | 
						|
        return True
 | 
						|
    msg = msg.encode('utf-8')
 | 
						|
    msglen = len(msg)
 | 
						|
    set_headers(self, 'text/html', msglen,
 | 
						|
                cookie, calling_domain, False)
 | 
						|
    write2(self, msg)
 | 
						|
    fitness_performance(getreq_start_time, fitness,
 | 
						|
                        '_GET', 'show_likers_of_post',
 | 
						|
                        debug)
 | 
						|
    return True
 | 
						|
 | 
						|
 | 
						|
def show_announcers_of_post(self, authorized: bool,
 | 
						|
                            calling_domain: str, path: str,
 | 
						|
                            base_dir: str, http_prefix: str,
 | 
						|
                            domain: str, port: int,
 | 
						|
                            getreq_start_time, cookie: str,
 | 
						|
                            debug: str, curr_session,
 | 
						|
                            bold_reading_nicknames: {},
 | 
						|
                            translate: {},
 | 
						|
                            theme_name: str,
 | 
						|
                            access_keys: {},
 | 
						|
                            recent_posts_cache: {},
 | 
						|
                            max_recent_posts: int,
 | 
						|
                            cached_webfingers: {},
 | 
						|
                            person_cache: {},
 | 
						|
                            project_version: str,
 | 
						|
                            yt_replace_domain: str,
 | 
						|
                            twitter_replacement_domain: str,
 | 
						|
                            show_published_date_only: bool,
 | 
						|
                            peertube_instances: [],
 | 
						|
                            allow_local_network_access: bool,
 | 
						|
                            system_language: str,
 | 
						|
                            max_like_count: int,
 | 
						|
                            signing_priv_key_pem: str,
 | 
						|
                            cw_lists: {},
 | 
						|
                            lists_enabled: {},
 | 
						|
                            default_timeline: str,
 | 
						|
                            dogwhistles: {},
 | 
						|
                            min_images_for_accounts: [],
 | 
						|
                            buy_sites: [],
 | 
						|
                            auto_cw_cache: {},
 | 
						|
                            fitness: {},
 | 
						|
                            mitm_servers: [],
 | 
						|
                            instance_software: {}) -> bool:
 | 
						|
    """Show the announcers of a post
 | 
						|
    """
 | 
						|
    if not authorized:
 | 
						|
        return False
 | 
						|
    if '?announcers=' not in path:
 | 
						|
        return False
 | 
						|
    if '/users/' not in path:
 | 
						|
        return False
 | 
						|
    nickname = path.split('/users/')[1]
 | 
						|
    if '?' in nickname:
 | 
						|
        nickname = nickname.split('?')[0]
 | 
						|
    post_url = path.split('?announcers=')[1]
 | 
						|
    if '?' in post_url:
 | 
						|
        post_url = post_url.split('?')[0]
 | 
						|
    post_url = post_url.replace('--', '/')
 | 
						|
 | 
						|
    bold_reading = False
 | 
						|
    if bold_reading_nicknames.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,
 | 
						|
                            post_url, translate,
 | 
						|
                            http_prefix,
 | 
						|
                            theme_name,
 | 
						|
                            access_keys,
 | 
						|
                            recent_posts_cache,
 | 
						|
                            max_recent_posts,
 | 
						|
                            curr_session,
 | 
						|
                            cached_webfingers,
 | 
						|
                            person_cache,
 | 
						|
                            project_version,
 | 
						|
                            yt_replace_domain,
 | 
						|
                            twitter_replacement_domain,
 | 
						|
                            show_published_date_only,
 | 
						|
                            peertube_instances,
 | 
						|
                            allow_local_network_access,
 | 
						|
                            system_language,
 | 
						|
                            max_like_count,
 | 
						|
                            signing_priv_key_pem,
 | 
						|
                            cw_lists,
 | 
						|
                            lists_enabled,
 | 
						|
                            'inbox', default_timeline,
 | 
						|
                            bold_reading, dogwhistles,
 | 
						|
                            min_images_for_accounts,
 | 
						|
                            buy_sites,
 | 
						|
                            auto_cw_cache,
 | 
						|
                            'shares', mitm_servers,
 | 
						|
                            instance_software)
 | 
						|
    if not msg:
 | 
						|
        http_404(self, 70)
 | 
						|
        return True
 | 
						|
    msg = msg.encode('utf-8')
 | 
						|
    msglen = len(msg)
 | 
						|
    set_headers(self, 'text/html', msglen,
 | 
						|
                cookie, calling_domain, False)
 | 
						|
    write2(self, msg)
 | 
						|
    fitness_performance(getreq_start_time, fitness,
 | 
						|
                        '_GET', 'show_announcers_of_post',
 | 
						|
                        debug)
 | 
						|
    return True
 | 
						|
 | 
						|
 | 
						|
def show_replies_to_post(self, authorized: bool,
 | 
						|
                         calling_domain: str, referer_domain: str,
 | 
						|
                         path: str, base_dir: str, http_prefix: str,
 | 
						|
                         domain: str, domain_full: str, port: int,
 | 
						|
                         getreq_start_time,
 | 
						|
                         proxy_type: str, cookie: str,
 | 
						|
                         debug: str, curr_session,
 | 
						|
                         recent_posts_cache: {},
 | 
						|
                         max_recent_posts: int,
 | 
						|
                         translate: {},
 | 
						|
                         cached_webfingers: {},
 | 
						|
                         person_cache: {},
 | 
						|
                         project_version: str,
 | 
						|
                         yt_replace_domain: str,
 | 
						|
                         twitter_replacement_domain: str,
 | 
						|
                         peertube_instances: [],
 | 
						|
                         account_timezone: {},
 | 
						|
                         bold_reading_nicknames: {},
 | 
						|
                         show_published_date_only: bool,
 | 
						|
                         allow_local_network_access: bool,
 | 
						|
                         theme_name: str,
 | 
						|
                         system_language: str,
 | 
						|
                         max_like_count: int,
 | 
						|
                         signing_priv_key_pem: str,
 | 
						|
                         cw_lists: {},
 | 
						|
                         lists_enabled: {},
 | 
						|
                         dogwhistles: {},
 | 
						|
                         min_images_for_accounts: [],
 | 
						|
                         buy_sites: [],
 | 
						|
                         auto_cw_cache: {},
 | 
						|
                         fitness: {},
 | 
						|
                         onion_domain: str,
 | 
						|
                         i2p_domain: str,
 | 
						|
                         mitm_servers: [],
 | 
						|
                         instance_software: {}) -> bool:
 | 
						|
    """Shows the replies to a post
 | 
						|
    """
 | 
						|
    if not ('/statuses/' in path and '/users/' in path):
 | 
						|
        return False
 | 
						|
 | 
						|
    named_status = path.split('/users/')[1]
 | 
						|
    if '/' not in named_status:
 | 
						|
        return False
 | 
						|
 | 
						|
    post_sections = named_status.split('/')
 | 
						|
    if len(post_sections) < 4:
 | 
						|
        return False
 | 
						|
 | 
						|
    if not post_sections[3].startswith('replies'):
 | 
						|
        return False
 | 
						|
    nickname = post_sections[0]
 | 
						|
    status_number = post_sections[2]
 | 
						|
    if not (len(status_number) > 10 and status_number.isdigit()):
 | 
						|
        return False
 | 
						|
 | 
						|
    boxname = 'outbox'
 | 
						|
    # get the replies file
 | 
						|
    post_dir = \
 | 
						|
        acct_dir(base_dir, nickname, domain) + '/' + boxname
 | 
						|
    orig_post_url = http_prefix + ':##' + domain_full + '#users#' + \
 | 
						|
        nickname + '#statuses#' + status_number
 | 
						|
    post_replies_filename = \
 | 
						|
        post_dir + '/' + orig_post_url + '.replies'
 | 
						|
    if not os.path.isfile(post_replies_filename):
 | 
						|
        # There are no replies,
 | 
						|
        # so show empty collection
 | 
						|
        first_str = \
 | 
						|
            local_actor_url(http_prefix, nickname, domain_full) + \
 | 
						|
            '/statuses/' + status_number + '/replies?page=true'
 | 
						|
 | 
						|
        id_str = \
 | 
						|
            local_actor_url(http_prefix, nickname, domain_full) + \
 | 
						|
            '/statuses/' + status_number + '/replies'
 | 
						|
 | 
						|
        last_str = \
 | 
						|
            local_actor_url(http_prefix, nickname, domain_full) + \
 | 
						|
            '/statuses/' + status_number + '/replies?page=true'
 | 
						|
 | 
						|
        replies_json = {
 | 
						|
            "@context": [
 | 
						|
                'https://www.w3.org/ns/activitystreams',
 | 
						|
                'https://w3id.org/security/v1'
 | 
						|
            ],
 | 
						|
            'first': first_str,
 | 
						|
            'id': id_str,
 | 
						|
            'last': last_str,
 | 
						|
            'totalItems': 0,
 | 
						|
            'type': 'OrderedCollection'
 | 
						|
        }
 | 
						|
 | 
						|
        if request_http(self.headers, debug):
 | 
						|
            curr_session = \
 | 
						|
                establish_session("show_replies_to_post",
 | 
						|
                                  curr_session, proxy_type,
 | 
						|
                                  self.server)
 | 
						|
            if not curr_session:
 | 
						|
                http_404(self, 61)
 | 
						|
                return True
 | 
						|
            yt_domain = yt_replace_domain
 | 
						|
            timezone = None
 | 
						|
            if account_timezone.get(nickname):
 | 
						|
                timezone = account_timezone.get(nickname)
 | 
						|
            bold_reading = False
 | 
						|
            if bold_reading_nicknames.get(nickname):
 | 
						|
                bold_reading = True
 | 
						|
            msg = \
 | 
						|
                html_post_replies(recent_posts_cache,
 | 
						|
                                  max_recent_posts,
 | 
						|
                                  translate,
 | 
						|
                                  base_dir,
 | 
						|
                                  curr_session,
 | 
						|
                                  cached_webfingers,
 | 
						|
                                  person_cache,
 | 
						|
                                  nickname,
 | 
						|
                                  domain,
 | 
						|
                                  port,
 | 
						|
                                  replies_json,
 | 
						|
                                  http_prefix,
 | 
						|
                                  project_version,
 | 
						|
                                  yt_domain,
 | 
						|
                                  twitter_replacement_domain,
 | 
						|
                                  show_published_date_only,
 | 
						|
                                  peertube_instances,
 | 
						|
                                  allow_local_network_access,
 | 
						|
                                  theme_name,
 | 
						|
                                  system_language,
 | 
						|
                                  max_like_count,
 | 
						|
                                  signing_priv_key_pem,
 | 
						|
                                  cw_lists,
 | 
						|
                                  lists_enabled,
 | 
						|
                                  timezone, bold_reading,
 | 
						|
                                  dogwhistles,
 | 
						|
                                  min_images_for_accounts,
 | 
						|
                                  buy_sites,
 | 
						|
                                  auto_cw_cache,
 | 
						|
                                  mitm_servers,
 | 
						|
                                  instance_software)
 | 
						|
            msg = msg.encode('utf-8')
 | 
						|
            msglen = len(msg)
 | 
						|
            set_headers(self, 'text/html', msglen,
 | 
						|
                        cookie, calling_domain, False)
 | 
						|
            write2(self, msg)
 | 
						|
            fitness_performance(getreq_start_time, fitness,
 | 
						|
                                '_GET', 'show_replies_to_post',
 | 
						|
                                debug)
 | 
						|
        else:
 | 
						|
            if secure_mode(curr_session, proxy_type, False,
 | 
						|
                           self.server, self.headers, path):
 | 
						|
                msg_str = json.dumps(replies_json, ensure_ascii=False)
 | 
						|
                msg_str = convert_domains(calling_domain,
 | 
						|
                                          referer_domain,
 | 
						|
                                          msg_str, http_prefix,
 | 
						|
                                          domain,
 | 
						|
                                          onion_domain,
 | 
						|
                                          i2p_domain)
 | 
						|
                msg = msg_str.encode('utf-8')
 | 
						|
                protocol_str = \
 | 
						|
                    get_json_content_from_accept(self.headers['Accept'])
 | 
						|
                msglen = len(msg)
 | 
						|
                set_headers(self, protocol_str, msglen, None,
 | 
						|
                            calling_domain, False)
 | 
						|
                write2(self, msg)
 | 
						|
                fitness_performance(getreq_start_time, fitness,
 | 
						|
                                    '_GET', 'show_replies_to_post json',
 | 
						|
                                    debug)
 | 
						|
            else:
 | 
						|
                http_404(self, 62)
 | 
						|
        return True
 | 
						|
 | 
						|
    # replies exist. Itterate through the
 | 
						|
    # text file containing message ids
 | 
						|
    id_str = \
 | 
						|
        local_actor_url(http_prefix, nickname, domain_full) + \
 | 
						|
        '/statuses/' + status_number + '?page=true'
 | 
						|
 | 
						|
    part_of_str = \
 | 
						|
        local_actor_url(http_prefix, nickname, domain_full) + \
 | 
						|
        '/statuses/' + status_number
 | 
						|
 | 
						|
    replies_json = {
 | 
						|
        "@context": [
 | 
						|
            'https://www.w3.org/ns/activitystreams',
 | 
						|
            'https://w3id.org/security/v1'
 | 
						|
        ],
 | 
						|
        'id': id_str,
 | 
						|
        'orderedItems': [
 | 
						|
        ],
 | 
						|
        'partOf': part_of_str,
 | 
						|
        'type': 'OrderedCollectionPage'
 | 
						|
    }
 | 
						|
 | 
						|
    # if the original post is public then return the replies
 | 
						|
    replies_are_public = \
 | 
						|
        is_public_post_from_url(base_dir, nickname, domain,
 | 
						|
                                orig_post_url)
 | 
						|
    if replies_are_public:
 | 
						|
        authorized = True
 | 
						|
 | 
						|
    # populate the items list with replies
 | 
						|
    populate_replies_json(base_dir, nickname, domain,
 | 
						|
                          post_replies_filename,
 | 
						|
                          authorized, replies_json)
 | 
						|
 | 
						|
    # send the replies json
 | 
						|
    if request_http(self.headers, debug):
 | 
						|
        curr_session = \
 | 
						|
            establish_session("show_replies_to_post2",
 | 
						|
                              curr_session, proxy_type,
 | 
						|
                              self.server)
 | 
						|
        if not curr_session:
 | 
						|
            http_404(self, 63)
 | 
						|
            return True
 | 
						|
        yt_domain = yt_replace_domain
 | 
						|
        timezone = None
 | 
						|
        if account_timezone.get(nickname):
 | 
						|
            timezone = account_timezone.get(nickname)
 | 
						|
        bold_reading = False
 | 
						|
        if bold_reading_nicknames.get(nickname):
 | 
						|
            bold_reading = True
 | 
						|
        msg = \
 | 
						|
            html_post_replies(recent_posts_cache,
 | 
						|
                              max_recent_posts,
 | 
						|
                              translate,
 | 
						|
                              base_dir,
 | 
						|
                              curr_session,
 | 
						|
                              cached_webfingers,
 | 
						|
                              person_cache,
 | 
						|
                              nickname,
 | 
						|
                              domain,
 | 
						|
                              port,
 | 
						|
                              replies_json,
 | 
						|
                              http_prefix,
 | 
						|
                              project_version,
 | 
						|
                              yt_domain,
 | 
						|
                              twitter_replacement_domain,
 | 
						|
                              show_published_date_only,
 | 
						|
                              peertube_instances,
 | 
						|
                              allow_local_network_access,
 | 
						|
                              theme_name,
 | 
						|
                              system_language,
 | 
						|
                              max_like_count,
 | 
						|
                              signing_priv_key_pem,
 | 
						|
                              cw_lists,
 | 
						|
                              lists_enabled,
 | 
						|
                              timezone, bold_reading,
 | 
						|
                              dogwhistles,
 | 
						|
                              min_images_for_accounts,
 | 
						|
                              buy_sites,
 | 
						|
                              auto_cw_cache,
 | 
						|
                              mitm_servers,
 | 
						|
                              instance_software)
 | 
						|
        msg = msg.encode('utf-8')
 | 
						|
        msglen = len(msg)
 | 
						|
        set_headers(self, 'text/html', msglen,
 | 
						|
                    cookie, calling_domain, False)
 | 
						|
        write2(self, msg)
 | 
						|
        fitness_performance(getreq_start_time, fitness,
 | 
						|
                            '_GET', 'show_replies_to_post',
 | 
						|
                            debug)
 | 
						|
    else:
 | 
						|
        if secure_mode(curr_session, proxy_type, False,
 | 
						|
                       self.server, self.headers, path):
 | 
						|
            msg_str = json.dumps(replies_json, ensure_ascii=False)
 | 
						|
            msg_str = convert_domains(calling_domain,
 | 
						|
                                      referer_domain,
 | 
						|
                                      msg_str, http_prefix,
 | 
						|
                                      domain,
 | 
						|
                                      onion_domain,
 | 
						|
                                      i2p_domain)
 | 
						|
            msg = msg_str.encode('utf-8')
 | 
						|
            protocol_str = \
 | 
						|
                get_json_content_from_accept(self.headers['Accept'])
 | 
						|
            msglen = len(msg)
 | 
						|
            set_headers(self, protocol_str, msglen,
 | 
						|
                        None, calling_domain, False)
 | 
						|
            write2(self, msg)
 | 
						|
            fitness_performance(getreq_start_time, fitness,
 | 
						|
                                '_GET', 'show_replies_to_post json',
 | 
						|
                                debug)
 | 
						|
        else:
 | 
						|
            http_404(self, 64)
 | 
						|
    return True
 | 
						|
 | 
						|
 | 
						|
def show_notify_post(self, authorized: bool,
 | 
						|
                     calling_domain: str, referer_domain: str,
 | 
						|
                     path: str,
 | 
						|
                     base_dir: str, http_prefix: str,
 | 
						|
                     domain: str, port: int,
 | 
						|
                     getreq_start_time,
 | 
						|
                     proxy_type: str, cookie: str,
 | 
						|
                     debug: str,
 | 
						|
                     curr_session, translate: {},
 | 
						|
                     account_timezone: {},
 | 
						|
                     fitness: {},
 | 
						|
                     recent_posts_cache: {},
 | 
						|
                     max_recent_posts: int,
 | 
						|
                     cached_webfingers: {},
 | 
						|
                     person_cache: {},
 | 
						|
                     project_version: str,
 | 
						|
                     yt_replace_domain: str,
 | 
						|
                     twitter_replacement_domain: str,
 | 
						|
                     show_published_date_only: bool,
 | 
						|
                     peertube_instances: [],
 | 
						|
                     allow_local_network_access: bool,
 | 
						|
                     theme_name: str,
 | 
						|
                     system_language: str,
 | 
						|
                     max_like_count: int,
 | 
						|
                     signing_priv_key_pem: str,
 | 
						|
                     cw_lists: {},
 | 
						|
                     lists_enabled: {},
 | 
						|
                     dogwhistles: {},
 | 
						|
                     min_images_for_accounts: [],
 | 
						|
                     buy_sites: [],
 | 
						|
                     auto_cw_cache: {},
 | 
						|
                     onion_domain: str,
 | 
						|
                     i2p_domain: str,
 | 
						|
                     bold_reading_nicknames: {},
 | 
						|
                     mitm_servers: [],
 | 
						|
                     instance_software: {}) -> bool:
 | 
						|
    """Shows an individual post from an account which you are following
 | 
						|
    and where you have the notify checkbox set on person options
 | 
						|
    """
 | 
						|
    liked_by = None
 | 
						|
    react_by = None
 | 
						|
    react_emoji = None
 | 
						|
    post_id = path.split('?notifypost=')[1].strip()
 | 
						|
    post_id = post_id.replace('-', '/')
 | 
						|
    path = path.split('?notifypost=')[0]
 | 
						|
    nickname = path.split('/users/')[1]
 | 
						|
    if '/' in nickname:
 | 
						|
        return False
 | 
						|
    replies = False
 | 
						|
 | 
						|
    post_filename = locate_post(base_dir, nickname, domain,
 | 
						|
                                post_id, replies)
 | 
						|
    if not post_filename:
 | 
						|
        return False
 | 
						|
 | 
						|
    include_create_wrapper = False
 | 
						|
    if path.endswith('/activity'):
 | 
						|
        include_create_wrapper = True
 | 
						|
 | 
						|
    result = _show_post_from_file(self, post_filename, liked_by,
 | 
						|
                                  react_by, react_emoji,
 | 
						|
                                  authorized, calling_domain,
 | 
						|
                                  referer_domain,
 | 
						|
                                  base_dir, http_prefix, nickname,
 | 
						|
                                  domain, port,
 | 
						|
                                  getreq_start_time,
 | 
						|
                                  proxy_type, cookie, debug,
 | 
						|
                                  include_create_wrapper,
 | 
						|
                                  curr_session, translate,
 | 
						|
                                  account_timezone,
 | 
						|
                                  bold_reading_nicknames,
 | 
						|
                                  recent_posts_cache,
 | 
						|
                                  max_recent_posts,
 | 
						|
                                  cached_webfingers,
 | 
						|
                                  person_cache,
 | 
						|
                                  project_version,
 | 
						|
                                  yt_replace_domain,
 | 
						|
                                  twitter_replacement_domain,
 | 
						|
                                  show_published_date_only,
 | 
						|
                                  peertube_instances,
 | 
						|
                                  allow_local_network_access,
 | 
						|
                                  theme_name,
 | 
						|
                                  system_language,
 | 
						|
                                  max_like_count,
 | 
						|
                                  signing_priv_key_pem,
 | 
						|
                                  cw_lists,
 | 
						|
                                  lists_enabled,
 | 
						|
                                  dogwhistles,
 | 
						|
                                  min_images_for_accounts,
 | 
						|
                                  buy_sites,
 | 
						|
                                  auto_cw_cache,
 | 
						|
                                  fitness, path,
 | 
						|
                                  onion_domain,
 | 
						|
                                  i2p_domain,
 | 
						|
                                  mitm_servers,
 | 
						|
                                  instance_software)
 | 
						|
    fitness_performance(getreq_start_time, fitness,
 | 
						|
                        '_GET', 'show_notify_post',
 | 
						|
                        debug)
 | 
						|
    return result
 | 
						|
 | 
						|
 | 
						|
def show_conversation_thread(self, authorized: bool,
 | 
						|
                             calling_domain: str, path: str,
 | 
						|
                             base_dir: str, http_prefix: str,
 | 
						|
                             domain: str, port: int,
 | 
						|
                             debug: str, curr_session,
 | 
						|
                             cookie: str, ua_str: str,
 | 
						|
                             domain_full: str,
 | 
						|
                             onion_domain: str,
 | 
						|
                             i2p_domain: str,
 | 
						|
                             account_timezone: {},
 | 
						|
                             bold_reading_nicknames: {},
 | 
						|
                             translate: {},
 | 
						|
                             project_version: str,
 | 
						|
                             recent_posts_cache: {},
 | 
						|
                             max_recent_posts: int,
 | 
						|
                             cached_webfingers: {},
 | 
						|
                             person_cache: {},
 | 
						|
                             yt_replace_domain: str,
 | 
						|
                             twitter_replacement_domain: str,
 | 
						|
                             show_published_date_only: bool,
 | 
						|
                             peertube_instances: [],
 | 
						|
                             allow_local_network_access: bool,
 | 
						|
                             theme_name: str,
 | 
						|
                             system_language: str,
 | 
						|
                             max_like_count: int,
 | 
						|
                             signing_priv_key_pem: str,
 | 
						|
                             cw_lists: {},
 | 
						|
                             lists_enabled: {},
 | 
						|
                             dogwhistles: {},
 | 
						|
                             access_keys: {},
 | 
						|
                             min_images_for_accounts: [],
 | 
						|
                             buy_sites: [],
 | 
						|
                             blocked_cache: {},
 | 
						|
                             block_federated: {},
 | 
						|
                             auto_cw_cache: {},
 | 
						|
                             default_timeline: str,
 | 
						|
                             mitm_servers: [],
 | 
						|
                             instance_software: {}) -> bool:
 | 
						|
    """get conversation thread from the date link on a post
 | 
						|
    """
 | 
						|
    if not path.startswith('/users/'):
 | 
						|
        return False
 | 
						|
    conv_separator = '?convthread='
 | 
						|
    # https://codeberg.org/fediverse/fep/src/branch/main/fep/76ea/fep-76ea.md
 | 
						|
    if conv_separator not in path and \
 | 
						|
       '/thread/' in path and \
 | 
						|
       '?repeat' not in path and \
 | 
						|
       '?un' not in path and \
 | 
						|
       '?like' not in path and \
 | 
						|
       '?delete' not in path and \
 | 
						|
       '?postedit' not in path and \
 | 
						|
       '?bookmark' not in path and \
 | 
						|
       '?selreact' not in path and \
 | 
						|
       '?mute' not in path and \
 | 
						|
       '?reply' not in path:
 | 
						|
        convthread_id = path.split('/thread/', 1)[1].strip()
 | 
						|
        if convthread_id.isdigit():
 | 
						|
            new_tag = convthread_id_to_conversation_tag(domain_full,
 | 
						|
                                                        convthread_id)
 | 
						|
            if new_tag:
 | 
						|
                path = \
 | 
						|
                    path.split(conv_separator)[0] + conv_separator + new_tag
 | 
						|
    if conv_separator not in path:
 | 
						|
        return False
 | 
						|
    post_id = path.split(conv_separator)[1].strip()
 | 
						|
    post_id = post_id.replace('--', '/')
 | 
						|
    if post_id.startswith('/users/'):
 | 
						|
        instance_url = get_instance_url(calling_domain,
 | 
						|
                                        http_prefix,
 | 
						|
                                        domain_full,
 | 
						|
                                        onion_domain,
 | 
						|
                                        i2p_domain)
 | 
						|
        post_id = instance_url + post_id
 | 
						|
    nickname = path.split('/users/')[1]
 | 
						|
    if conv_separator in nickname:
 | 
						|
        nickname = nickname.split(conv_separator)[0]
 | 
						|
    if '/' in nickname:
 | 
						|
        nickname = nickname.split('/')[0]
 | 
						|
    timezone = None
 | 
						|
    if account_timezone.get(nickname):
 | 
						|
        timezone = account_timezone.get(nickname)
 | 
						|
    bold_reading = False
 | 
						|
    if bold_reading_nicknames.get(nickname):
 | 
						|
        bold_reading = True
 | 
						|
    conv_str = \
 | 
						|
        html_conversation_view(authorized,
 | 
						|
                               post_id, translate,
 | 
						|
                               base_dir,
 | 
						|
                               http_prefix,
 | 
						|
                               nickname,
 | 
						|
                               domain,
 | 
						|
                               project_version,
 | 
						|
                               recent_posts_cache,
 | 
						|
                               max_recent_posts,
 | 
						|
                               curr_session,
 | 
						|
                               cached_webfingers,
 | 
						|
                               person_cache,
 | 
						|
                               port,
 | 
						|
                               yt_replace_domain,
 | 
						|
                               twitter_replacement_domain,
 | 
						|
                               show_published_date_only,
 | 
						|
                               peertube_instances,
 | 
						|
                               allow_local_network_access,
 | 
						|
                               theme_name,
 | 
						|
                               system_language,
 | 
						|
                               max_like_count,
 | 
						|
                               signing_priv_key_pem,
 | 
						|
                               cw_lists,
 | 
						|
                               lists_enabled,
 | 
						|
                               timezone, bold_reading,
 | 
						|
                               dogwhistles,
 | 
						|
                               access_keys,
 | 
						|
                               min_images_for_accounts,
 | 
						|
                               debug,
 | 
						|
                               buy_sites,
 | 
						|
                               blocked_cache,
 | 
						|
                               block_federated,
 | 
						|
                               auto_cw_cache,
 | 
						|
                               ua_str,
 | 
						|
                               default_timeline,
 | 
						|
                               mitm_servers,
 | 
						|
                               instance_software)
 | 
						|
    if conv_str:
 | 
						|
        msg = conv_str.encode('utf-8')
 | 
						|
        msglen = len(msg)
 | 
						|
        login_headers(self, 'text/html', msglen, calling_domain)
 | 
						|
        write2(self, msg)
 | 
						|
        self.server.getreq_busy = False
 | 
						|
        return True
 | 
						|
    # redirect to the original site if there are no results
 | 
						|
    if '://' + domain_full + '/' in post_id:
 | 
						|
        redirect_headers(self, post_id, cookie, calling_domain, 303)
 | 
						|
    else:
 | 
						|
        redirect_headers(self, post_id, None, calling_domain, 303)
 | 
						|
    self.server.getreq_busy = False
 | 
						|
    return True
 |