mirror of https://gitlab.com/bashrc2/epicyon
8075 lines
341 KiB
Python
8075 lines
341 KiB
Python
__filename__ = "daemon_get.py"
|
|
__author__ = "Bob Mottram"
|
|
__license__ = "AGPL3+"
|
|
__version__ = "1.5.0"
|
|
__maintainer__ = "Bob Mottram"
|
|
__email__ = "bob@libreserver.org"
|
|
__status__ = "Production"
|
|
__module_group__ = "Core"
|
|
|
|
import os
|
|
import time
|
|
import json
|
|
import datetime
|
|
import urllib.parse
|
|
from shutil import copyfile
|
|
from skills import get_skills_from_list
|
|
from skills import no_of_actor_skills
|
|
from city import get_spoofed_city
|
|
from roles import get_actor_roles_list
|
|
from languages import get_understood_languages
|
|
from languages import get_reply_language
|
|
from webfinger import webfinger_lookup
|
|
from webfinger import webfinger_node_info
|
|
from webfinger import webfinger_meta
|
|
from webfinger import wellknown_protocol_handler
|
|
from media import path_is_video
|
|
from media import path_is_transcript
|
|
from media import path_is_audio
|
|
from context import get_individual_post_context
|
|
from newswire import rss2header
|
|
from newswire import get_rs_sfrom_dict
|
|
from newswire import rss2footer
|
|
from pgp import actor_to_vcard
|
|
from pgp import actor_to_vcard_xml
|
|
from siteactive import referer_is_active
|
|
from maps import map_format_from_tagmaps_path
|
|
from blog import html_blog_page
|
|
from blog import html_blog_page_rss2
|
|
from blog import html_blog_page_rss3
|
|
from blog import html_edit_blog
|
|
from blog import html_blog_post
|
|
from blog import path_contains_blog_link
|
|
from blog import html_blog_view
|
|
from speaker import get_ssml_box
|
|
from follow import pending_followers_timeline_json
|
|
from follow import get_following_feed
|
|
from blocking import broch_mode_is_active
|
|
from blocking import remove_global_block
|
|
from blocking import update_blocked_cache
|
|
from blocking import add_global_block
|
|
from blocking import blocked_timeline_json
|
|
from cache import get_person_from_cache
|
|
from webapp_create_post import html_new_post
|
|
from webapp_profile import html_profile
|
|
from webapp_profile import html_edit_profile
|
|
from webapp_conversation import html_conversation_view
|
|
from webapp_moderation import html_account_info
|
|
from webapp_calendar import html_calendar_delete_confirm
|
|
from webapp_calendar import html_calendar
|
|
from webapp_hashtagswarm import html_search_hashtag_category
|
|
from webapp_minimalbutton import set_minimal
|
|
from webapp_minimalbutton import is_minimal
|
|
from webapp_search import html_search_emoji_text_entry
|
|
from webapp_search import html_search
|
|
from webapp_search import html_hashtag_search_remote
|
|
from webapp_column_left import html_edit_links
|
|
from webapp_column_left import html_links_mobile
|
|
from webapp_column_right import html_edit_news_post
|
|
from webapp_column_right import html_edit_newswire
|
|
from webapp_column_right import html_newswire_mobile
|
|
from webapp_timeline import html_inbox
|
|
from webapp_theme_designer import html_theme_designer
|
|
from webapp_accesskeys import html_access_keys
|
|
from webapp_manual import html_manual
|
|
from webapp_specification import html_specification
|
|
from webapp_about import html_about
|
|
from webapp_tos import html_terms_of_service
|
|
from webapp_confirm import html_confirm_remove_shared_item
|
|
from webapp_welcome_profile import html_welcome_profile
|
|
from webapp_welcome_final import html_welcome_final
|
|
from webapp_welcome import html_welcome_screen
|
|
from webapp_welcome import is_welcome_screen_complete
|
|
from webapp_podcast import html_podcast_episode
|
|
from webapp_utils import get_default_path
|
|
from webapp_utils import csv_following_list
|
|
from webapp_utils import get_shares_collection
|
|
from webapp_utils import html_following_list
|
|
from webapp_utils import html_show_share
|
|
from webapp_likers import html_likers_of_post
|
|
from webapp_login import html_login
|
|
from webapp_post import html_individual_post
|
|
from webapp_post import html_post_replies
|
|
from webapp_post import html_emoji_reaction_picker
|
|
from followerSync import update_followers_sync_cache
|
|
from securemode import secure_mode
|
|
from fitnessFunctions import sorted_watch_points
|
|
from fitnessFunctions import fitness_performance
|
|
from fitnessFunctions import html_watch_points_graph
|
|
from session import establish_session
|
|
from session import get_session_for_domains
|
|
from crawlers import blocked_user_agent
|
|
from daemon_utils import etag_exists
|
|
from daemon_utils import has_accept
|
|
from daemon_utils import show_person_options
|
|
from daemon_utils import is_authorized
|
|
from daemon_utils import get_user_agent
|
|
from httpheaders import set_headers_etag
|
|
from httpheaders import login_headers
|
|
from httpheaders import redirect_headers
|
|
from httprequests import request_icalendar
|
|
from httprequests import request_ssml
|
|
from httprequests import request_csv
|
|
from httprequests import request_http
|
|
from httpheaders import set_headers
|
|
from httpheaders import logout_headers
|
|
from httpheaders import logout_redirect
|
|
from httpcodes import http_200
|
|
from httpcodes import http_401
|
|
from httpcodes import http_402
|
|
from httpcodes import http_403
|
|
from httpcodes import http_404
|
|
from httpcodes import http_304
|
|
from httpcodes import http_400
|
|
from httpcodes import http_503
|
|
from httpcodes import write2
|
|
from utils import is_public_post
|
|
from utils import get_occupation_skills
|
|
from utils import is_public_post_from_url
|
|
from utils import can_reply_to
|
|
from utils import get_new_post_endpoints
|
|
from utils import save_json
|
|
from utils import locate_post
|
|
from utils import get_image_mime_type
|
|
from utils import get_image_extensions
|
|
from utils import is_account_dir
|
|
from utils import get_config_param
|
|
from utils import user_agent_domain
|
|
from utils import local_network_host
|
|
from utils import permitted_dir
|
|
from utils import has_users_path
|
|
from utils import media_file_mime_type
|
|
from utils import is_image_file
|
|
from utils import is_artist
|
|
from utils import is_blog_post
|
|
from utils import replace_users_with_at
|
|
from utils import remove_id_ending
|
|
from utils import local_actor_url
|
|
from utils import load_json
|
|
from utils import acct_dir
|
|
from utils import get_instance_url
|
|
from utils import convert_domains
|
|
from utils import get_nickname_from_actor
|
|
from utils import get_json_content_from_accept
|
|
from utils import check_bad_path
|
|
from utils import corp_servers
|
|
from utils import decoded_host
|
|
from utils import has_object_dict
|
|
from person import add_alternate_domains
|
|
from person import person_box_json
|
|
from person import save_person_qrcode
|
|
from person import person_lookup
|
|
from person import get_account_pub_key
|
|
from shares import actor_attached_shares
|
|
from shares import get_share_category
|
|
from shares import vf_proposal_from_id
|
|
from shares import authorize_shared_items
|
|
from shares import shares_catalog_endpoint
|
|
from shares import shares_catalog_account_endpoint
|
|
from shares import shares_catalog_csv_endpoint
|
|
from posts import remove_post_interactions
|
|
from posts import populate_replies_json
|
|
from posts import json_pin_post
|
|
from posts import is_moderator
|
|
from posts import get_pinned_post_as_json
|
|
from posts import outbox_message_create_wrap
|
|
from daemon_get_masto_api import masto_api
|
|
from daemon_get_favicon import show_cached_favicon
|
|
from daemon_get_favicon import get_favicon
|
|
from daemon_get_exports import get_exported_blocks
|
|
from daemon_get_exports import get_exported_theme
|
|
from daemon_get_pwa import progressive_web_app_manifest
|
|
from daemon_get_css import get_fonts
|
|
from daemon_get_css import get_style_sheet
|
|
from daemon_get_nodeinfo import get_nodeinfo
|
|
from daemon_get_hashtag import hashtag_search_rss2
|
|
from daemon_get_hashtag import hashtag_search_json2
|
|
from daemon_get_hashtag import hashtag_search2
|
|
from daemon_get_hashtag import get_hashtag_categories_feed2
|
|
from daemon_get_timeline import show_media_timeline
|
|
from daemon_get_timeline import show_blogs_timeline
|
|
from daemon_get_timeline import show_news_timeline
|
|
from daemon_get_timeline import show_features_timeline
|
|
from daemon_get_timeline import show_shares_timeline
|
|
from daemon_get_timeline import show_wanted_timeline
|
|
from daemon_get_timeline import show_bookmarks_timeline
|
|
from daemon_get_timeline import show_outbox_timeline
|
|
from daemon_get_timeline import show_mod_timeline
|
|
from daemon_get_timeline import show_dms
|
|
from daemon_get_timeline import show_replies
|
|
from daemon_get_feeds import show_shares_feed
|
|
from daemon_get_feeds import show_following_feed
|
|
from daemon_get_feeds import show_moved_feed
|
|
from daemon_get_feeds import show_inactive_feed
|
|
from daemon_get_feeds import show_followers_feed
|
|
from daemon_get_buttons import announce_button
|
|
from daemon_get_buttons import announce_button_undo
|
|
from daemon_get_buttons import follow_approve_button
|
|
from daemon_get_buttons import follow_deny_button
|
|
from daemon_get_buttons import like_button
|
|
from daemon_get_buttons import like_button_undo
|
|
from daemon_get_buttons import reaction_button
|
|
from daemon_get_buttons import reaction_button_undo
|
|
from daemon_get_buttons import bookmark_button
|
|
from daemon_get_buttons import bookmark_button_undo
|
|
from daemon_get_buttons import delete_button
|
|
from daemon_get_buttons import mute_button
|
|
from daemon_get_buttons import mute_button_undo
|
|
|
|
# Blogs can be longer, so don't show many per page
|
|
MAX_POSTS_IN_BLOGS_FEED = 4
|
|
|
|
# maximum number of posts to list in outbox feed
|
|
MAX_POSTS_IN_FEED = 12
|
|
|
|
# Maximum number of entries in returned rss.xml
|
|
MAX_POSTS_IN_RSS_FEED = 10
|
|
|
|
# reduced posts for media feed because it can take a while
|
|
MAX_POSTS_IN_MEDIA_FEED = 6
|
|
|
|
MAX_POSTS_IN_NEWS_FEED = 10
|
|
|
|
# number of item shares per page
|
|
SHARES_PER_PAGE = 12
|
|
|
|
# number of follows/followers per page
|
|
FOLLOWS_PER_PAGE = 6
|
|
|
|
# maximum number of posts in a hashtag feed
|
|
MAX_POSTS_IN_HASHTAG_FEED = 6
|
|
|
|
|
|
def daemon_http_get(self) -> None:
|
|
"""daemon handler for http GET
|
|
"""
|
|
if self.server.starting_daemon:
|
|
return
|
|
if check_bad_path(self.path):
|
|
http_400(self)
|
|
return
|
|
|
|
calling_domain = self.server.domain_full
|
|
|
|
if self.headers.get('Server'):
|
|
if self.headers['Server'] in corp_servers():
|
|
if self.server.debug:
|
|
print('Corporate leech bounced: ' + self.headers['Server'])
|
|
http_402(self)
|
|
return
|
|
|
|
if self.headers.get('Host'):
|
|
calling_domain = decoded_host(self.headers['Host'])
|
|
if self.server.onion_domain:
|
|
if calling_domain not in (self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.onion_domain):
|
|
print('GET domain blocked: ' + calling_domain)
|
|
http_400(self)
|
|
return
|
|
elif self.server.i2p_domain:
|
|
if calling_domain not in (self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.i2p_domain):
|
|
print('GET domain blocked: ' + calling_domain)
|
|
http_400(self)
|
|
return
|
|
else:
|
|
if calling_domain not in (self.server.domain,
|
|
self.server.domain_full):
|
|
print('GET domain blocked: ' + calling_domain)
|
|
http_400(self)
|
|
return
|
|
|
|
ua_str = get_user_agent(self)
|
|
|
|
if not _permitted_crawler_path(self, self.path):
|
|
block, self.server.blocked_cache_last_updated = \
|
|
blocked_user_agent(calling_domain, ua_str,
|
|
self.server.news_instance,
|
|
self.server.debug,
|
|
self.server.user_agents_blocked,
|
|
self.server.blocked_cache_last_updated,
|
|
self.server.base_dir,
|
|
self.server.blocked_cache,
|
|
self.server.block_federated,
|
|
self.server.blocked_cache_update_secs,
|
|
self.server.crawlers_allowed,
|
|
self.server.known_bots,
|
|
self.path, self.server.block_military)
|
|
if block:
|
|
http_400(self)
|
|
return
|
|
|
|
referer_domain = _get_referer_domain(self, ua_str)
|
|
|
|
curr_session, proxy_type = \
|
|
get_session_for_domains(self.server,
|
|
calling_domain, referer_domain)
|
|
|
|
getreq_start_time = time.time()
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'start', self.server.debug)
|
|
|
|
if _show_vcard(self, self.server.base_dir,
|
|
self.path, calling_domain, referer_domain,
|
|
self.server.domain):
|
|
return
|
|
|
|
# getting the public key for an account
|
|
acct_pub_key_json = \
|
|
get_account_pub_key(self.path, self.server.person_cache,
|
|
self.server.base_dir,
|
|
self.server.domain, calling_domain,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
if acct_pub_key_json:
|
|
msg_str = json.dumps(acct_pub_key_json, ensure_ascii=False)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
accept_str = self.headers['Accept']
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
return
|
|
|
|
# Since fediverse crawlers are quite active,
|
|
# make returning info to them high priority
|
|
# get nodeinfo endpoint
|
|
if get_nodeinfo(self, ua_str, calling_domain, referer_domain,
|
|
self.server.http_prefix, 5, self.server.debug):
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_nodeinfo[calling_domain]',
|
|
self.server.debug)
|
|
|
|
if _security_txt(self, ua_str, calling_domain, referer_domain,
|
|
self.server.http_prefix, 5, self.server.debug):
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_security_txt[calling_domain]',
|
|
self.server.debug)
|
|
|
|
# followers synchronization request
|
|
# See https://github.com/mastodon/mastodon/pull/14510
|
|
# https://codeberg.org/fediverse/fep/src/branch/main/feps/fep-8fcf.md
|
|
if self.path.startswith('/users/') and \
|
|
self.path.endswith('/followers_synchronization'):
|
|
if self.server.followers_synchronization:
|
|
# only do one request at a time
|
|
http_503(self)
|
|
return
|
|
self.server.followers_synchronization = True
|
|
if self.server.debug:
|
|
print('DEBUG: followers synchronization request ' +
|
|
self.path + ' ' + calling_domain)
|
|
# check authorized fetch
|
|
if secure_mode(curr_session, proxy_type, False,
|
|
self.server, self.headers, self.path):
|
|
nickname = get_nickname_from_actor(self.path)
|
|
sync_cache = self.server.followers_sync_cache
|
|
sync_json, _ = \
|
|
update_followers_sync_cache(self.server.base_dir,
|
|
nickname,
|
|
self.server.domain,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
calling_domain,
|
|
sync_cache)
|
|
msg_str = json.dumps(sync_json, ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain, referer_domain,
|
|
msg_str,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'application/json', msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
self.server.followers_synchronization = False
|
|
return
|
|
else:
|
|
# request was not signed
|
|
result_json = {
|
|
"error": "Request not signed"
|
|
}
|
|
msg_str = json.dumps(result_json, ensure_ascii=False)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
accept_str = self.headers['Accept']
|
|
if 'json' in accept_str:
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
self.server.followers_synchronization = False
|
|
return
|
|
http_404(self, 110)
|
|
self.server.followers_synchronization = False
|
|
return
|
|
|
|
if self.path == '/logout':
|
|
if not self.server.news_instance:
|
|
msg = \
|
|
html_login(self.server.translate,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.system_language,
|
|
False, ua_str,
|
|
self.server.theme_name).encode('utf-8')
|
|
msglen = len(msg)
|
|
logout_headers(self, 'text/html', msglen, calling_domain)
|
|
write2(self, msg)
|
|
else:
|
|
news_url = \
|
|
get_instance_url(calling_domain,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain) + \
|
|
'/users/news'
|
|
logout_redirect(self, news_url, calling_domain)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'logout',
|
|
self.server.debug)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show logout',
|
|
self.server.debug)
|
|
|
|
# replace https://domain/@nick with https://domain/users/nick
|
|
if self.path.startswith('/@'):
|
|
self.path = self.path.replace('/@', '/users/')
|
|
# replace https://domain/@nick/statusnumber
|
|
# with https://domain/users/nick/statuses/statusnumber
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
status_number_str = nickname.split('/')[1]
|
|
if status_number_str.isdigit():
|
|
nickname = nickname.split('/')[0]
|
|
self.path = \
|
|
self.path.replace('/users/' + nickname + '/',
|
|
'/users/' + nickname + '/statuses/')
|
|
|
|
# instance actor
|
|
if self.path in ('/actor', '/users/instance.actor', '/users/actor',
|
|
'/Actor', '/users/Actor'):
|
|
self.path = '/users/inbox'
|
|
if _show_instance_actor(self, calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
None, self.server.debug,
|
|
self.server.enable_shared_inbox):
|
|
return
|
|
else:
|
|
http_404(self, 111)
|
|
return
|
|
|
|
# turn off dropdowns on new post screen
|
|
no_drop_down = False
|
|
if self.path.endswith('?nodropdown'):
|
|
no_drop_down = True
|
|
self.path = self.path.replace('?nodropdown', '')
|
|
|
|
# redirect music to #nowplaying list
|
|
if self.path == '/music' or self.path == '/NowPlaying':
|
|
self.path = '/tags/NowPlaying'
|
|
|
|
if self.server.debug:
|
|
print('DEBUG: GET from ' + self.server.base_dir +
|
|
' path: ' + self.path + ' busy: ' +
|
|
str(self.server.getreq_busy))
|
|
|
|
if self.server.debug:
|
|
print(str(self.headers))
|
|
|
|
cookie = None
|
|
if self.headers.get('Cookie'):
|
|
cookie = self.headers['Cookie']
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'get cookie',
|
|
self.server.debug)
|
|
|
|
if '/manifest.json' in self.path:
|
|
if has_accept(self, calling_domain):
|
|
if not request_http(self.headers, self.server.debug):
|
|
progressive_web_app_manifest(self, self.server.base_dir,
|
|
calling_domain,
|
|
referer_domain,
|
|
getreq_start_time)
|
|
return
|
|
else:
|
|
self.path = '/'
|
|
|
|
if '/browserconfig.xml' in self.path:
|
|
if has_accept(self, calling_domain):
|
|
_browser_config(self, calling_domain, referer_domain,
|
|
getreq_start_time)
|
|
return
|
|
|
|
# default newswire favicon, for links to sites which
|
|
# have no favicon
|
|
if not self.path.startswith('/favicons/'):
|
|
if 'newswire_favicon.ico' in self.path:
|
|
get_favicon(self, calling_domain, self.server.base_dir,
|
|
self.server.debug,
|
|
'newswire_favicon.ico')
|
|
return
|
|
|
|
# favicon image
|
|
if 'favicon.ico' in self.path:
|
|
get_favicon(self, calling_domain, self.server.base_dir,
|
|
self.server.debug, 'favicon.ico')
|
|
return
|
|
|
|
# check authorization
|
|
authorized = is_authorized(self)
|
|
if self.server.debug:
|
|
if authorized:
|
|
print('GET Authorization granted ' + self.path)
|
|
else:
|
|
print('GET Not authorized ' + self.path + ' ' +
|
|
str(self.headers))
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'isAuthorized',
|
|
self.server.debug)
|
|
|
|
if authorized and self.path.endswith('/bots.txt'):
|
|
known_bots_str = ''
|
|
for bot_name in self.server.known_bots:
|
|
known_bots_str += bot_name + '\n'
|
|
msg = known_bots_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/plain; charset=utf-8',
|
|
msglen, None, calling_domain, True)
|
|
write2(self, msg)
|
|
if self.server.debug:
|
|
print('Sent known bots: ' +
|
|
self.server.path + ' ' + calling_domain)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'get_known_bots',
|
|
self.server.debug)
|
|
return
|
|
|
|
if _show_conversation_thread(self, authorized,
|
|
calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
self.server.debug,
|
|
self.server.session,
|
|
cookie):
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_show_conversation_thread',
|
|
self.server.debug)
|
|
return
|
|
|
|
# show a shared item if it is listed within actor attachment
|
|
if self.path.startswith('/users/') and '/shareditems/' in self.path:
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
shared_item_display_name = self.path.split('/shareditems/')[1]
|
|
if not nickname or not shared_item_display_name:
|
|
http_404(self, 112)
|
|
return
|
|
if not has_accept(self, calling_domain):
|
|
print('DEBUG: shareditems 1')
|
|
http_404(self, 113)
|
|
return
|
|
# get the actor from the cache
|
|
actor = \
|
|
get_instance_url(calling_domain,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain) + \
|
|
'/users/' + nickname
|
|
actor_json = get_person_from_cache(self.server.base_dir, actor,
|
|
self.server.person_cache)
|
|
if not actor_json:
|
|
actor_filename = acct_dir(self.server.base_dir, nickname,
|
|
self.server.domain) + '.json'
|
|
if os.path.isfile(actor_filename):
|
|
actor_json = load_json(actor_filename, 1, 1)
|
|
if not actor_json:
|
|
print('DEBUG: shareditems 2 ' + actor)
|
|
http_404(self, 114)
|
|
return
|
|
attached_shares = actor_attached_shares(actor_json)
|
|
if not attached_shares:
|
|
print('DEBUG: shareditems 3 ' + str(actor_json['attachment']))
|
|
http_404(self, 115)
|
|
return
|
|
# is the given shared item in the list?
|
|
share_id = None
|
|
for share_href in attached_shares:
|
|
if not isinstance(share_href, str):
|
|
continue
|
|
if share_href.endswith(self.path):
|
|
share_id = share_href.replace('://', '___')
|
|
share_id = share_id.replace('/', '--')
|
|
break
|
|
if not share_id:
|
|
print('DEBUG: shareditems 4')
|
|
http_404(self, 116)
|
|
return
|
|
# show the shared item
|
|
print('DEBUG: shareditems 5 ' + share_id)
|
|
shares_file_type = 'shares'
|
|
if request_http(self.headers, self.server.debug):
|
|
# get the category for share_id
|
|
share_category = \
|
|
get_share_category(self.server.base_dir,
|
|
nickname, self.server.domain,
|
|
shares_file_type, share_id)
|
|
msg = \
|
|
html_show_share(self.server.base_dir,
|
|
self.server.domain, nickname,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
share_id, self.server.translate,
|
|
self.server.shared_items_federated_domains,
|
|
self.server.default_timeline,
|
|
self.server.theme_name, shares_file_type,
|
|
share_category, not authorized)
|
|
if msg:
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/html', msglen,
|
|
None, calling_domain, True)
|
|
write2(self, msg)
|
|
return
|
|
else:
|
|
print('DEBUG: shareditems 6 ' + share_id)
|
|
else:
|
|
# get json for the shared item in ValueFlows format
|
|
share_json = \
|
|
vf_proposal_from_id(self.server.base_dir,
|
|
nickname, self.server.domain,
|
|
shares_file_type, share_id,
|
|
actor)
|
|
if share_json:
|
|
msg_str = json.dumps(share_json)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'application/json', msglen,
|
|
None, calling_domain, True)
|
|
write2(self, msg)
|
|
return
|
|
else:
|
|
print('DEBUG: shareditems 7 ' + share_id)
|
|
http_404(self, 117)
|
|
return
|
|
|
|
# shared items offers collection for this instance
|
|
# this is only accessible to instance members or to
|
|
# other instances which present an authorization token
|
|
if self.path.startswith('/users/') and '/offers' in self.path:
|
|
offers_collection_authorized = authorized
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
page_number = 1
|
|
if '?page=' in self.path:
|
|
page_number_str = self.path.split('?page=')[1]
|
|
if ';' in page_number_str:
|
|
page_number_str = page_number_str.split(';')[0]
|
|
if page_number_str.isdigit():
|
|
page_number = int(page_number_str)
|
|
if not offers_collection_authorized:
|
|
if self.server.debug:
|
|
print('Offers collection access is not authorized. ' +
|
|
'Checking Authorization header')
|
|
# Check the authorization token
|
|
if self.headers.get('Origin') and \
|
|
self.headers.get('Authorization'):
|
|
permitted_domains = \
|
|
self.server.shared_items_federated_domains
|
|
shared_item_tokens = \
|
|
self.server.shared_item_federation_tokens
|
|
if authorize_shared_items(permitted_domains,
|
|
self.server.base_dir,
|
|
self.headers['Origin'],
|
|
calling_domain,
|
|
self.headers['Authorization'],
|
|
self.server.debug,
|
|
shared_item_tokens):
|
|
offers_collection_authorized = True
|
|
elif self.server.debug:
|
|
print('Authorization token refused for ' +
|
|
'offers collection federation')
|
|
# show offers collection for federation
|
|
offers_json = []
|
|
if has_accept(self, calling_domain) and \
|
|
offers_collection_authorized:
|
|
if self.server.debug:
|
|
print('Preparing offers collection')
|
|
|
|
domain_full = self.server.domain_full
|
|
http_prefix = self.server.http_prefix
|
|
if self.server.debug:
|
|
print('Offers collection for account: ' + nickname)
|
|
base_dir = self.server.base_dir
|
|
offers_items_per_page = 12
|
|
max_shares_per_account = offers_items_per_page
|
|
shared_items_federated_domains = \
|
|
self.server.shared_items_federated_domains
|
|
actor = \
|
|
local_actor_url(http_prefix, nickname, domain_full) + \
|
|
'/offers'
|
|
offers_json = \
|
|
get_shares_collection(actor, page_number,
|
|
offers_items_per_page, base_dir,
|
|
self.server.domain, nickname,
|
|
max_shares_per_account,
|
|
shared_items_federated_domains,
|
|
'shares')
|
|
msg_str = json.dumps(offers_json,
|
|
ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
accept_str = self.headers['Accept']
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
return
|
|
|
|
if self.path.startswith('/users/') and '/blocked' in self.path:
|
|
blocked_collection_authorized = authorized
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
page_number = 1
|
|
if '?page=' in self.path:
|
|
page_number_str = self.path.split('?page=')[1]
|
|
if ';' in page_number_str:
|
|
page_number_str = page_number_str.split(';')[0]
|
|
if page_number_str.isdigit():
|
|
page_number = int(page_number_str)
|
|
# show blocked collection for the nickname
|
|
actor = \
|
|
local_actor_url(self.server.http_prefix,
|
|
nickname, self.server.domain_full)
|
|
actor += '/blocked'
|
|
blocked_json = {
|
|
"@context": [
|
|
"https://www.w3.org/ns/activitystreams",
|
|
"https://purl.archive.org/socialweb/blocked"
|
|
],
|
|
"id": actor,
|
|
"type": "OrderedCollection",
|
|
"name": nickname + "'s Blocked Collection",
|
|
"orderedItems": []
|
|
}
|
|
if has_accept(self, calling_domain) and \
|
|
blocked_collection_authorized:
|
|
if self.server.debug:
|
|
print('Preparing blocked collection')
|
|
|
|
if self.server.debug:
|
|
print('Blocked collection for account: ' + nickname)
|
|
base_dir = self.server.base_dir
|
|
blocked_items_per_page = 12
|
|
blocked_json = \
|
|
blocked_timeline_json(actor, page_number,
|
|
blocked_items_per_page, base_dir,
|
|
nickname, self.server.domain)
|
|
msg_str = json.dumps(blocked_json,
|
|
ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
accept_str = self.headers['Accept']
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
return
|
|
|
|
if self.path.startswith('/users/') and \
|
|
'/pendingFollowers' in self.path:
|
|
pending_collection_authorized = authorized
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
page_number = 1
|
|
if '?page=' in self.path:
|
|
page_number_str = self.path.split('?page=')[1]
|
|
if ';' in page_number_str:
|
|
page_number_str = page_number_str.split(';')[0]
|
|
if page_number_str.isdigit():
|
|
page_number = int(page_number_str)
|
|
# show pending followers collection for the nickname
|
|
actor = \
|
|
local_actor_url(self.server.http_prefix,
|
|
nickname, self.server.domain_full)
|
|
actor += '/pendingFollowers'
|
|
pending_json = {
|
|
"@context": [
|
|
"https://www.w3.org/ns/activitystreams"
|
|
],
|
|
"id": actor,
|
|
"type": "OrderedCollection",
|
|
"name": nickname + "'s Pending Followers",
|
|
"orderedItems": []
|
|
}
|
|
if has_accept(self, calling_domain) and \
|
|
pending_collection_authorized:
|
|
if self.server.debug:
|
|
print('Preparing pending followers collection')
|
|
|
|
if self.server.debug:
|
|
print('Pending followers collection for account: ' +
|
|
nickname)
|
|
base_dir = self.server.base_dir
|
|
pending_json = \
|
|
pending_followers_timeline_json(actor, base_dir, nickname,
|
|
self.server.domain)
|
|
msg_str = json.dumps(pending_json,
|
|
ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
accept_str = self.headers['Accept']
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
return
|
|
|
|
# wanted items collection for this instance
|
|
# this is only accessible to instance members or to
|
|
# other instances which present an authorization token
|
|
if self.path.startswith('/users/') and '/wanted' in self.path:
|
|
wanted_collection_authorized = authorized
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
page_number = 1
|
|
if '?page=' in self.path:
|
|
page_number_str = self.path.split('?page=')[1]
|
|
if ';' in page_number_str:
|
|
page_number_str = page_number_str.split(';')[0]
|
|
if page_number_str.isdigit():
|
|
page_number = int(page_number_str)
|
|
if not wanted_collection_authorized:
|
|
if self.server.debug:
|
|
print('Wanted collection access is not authorized. ' +
|
|
'Checking Authorization header')
|
|
# Check the authorization token
|
|
if self.headers.get('Origin') and \
|
|
self.headers.get('Authorization'):
|
|
permitted_domains = \
|
|
self.server.shared_items_federated_domains
|
|
shared_item_tokens = \
|
|
self.server.shared_item_federation_tokens
|
|
if authorize_shared_items(permitted_domains,
|
|
self.server.base_dir,
|
|
self.headers['Origin'],
|
|
calling_domain,
|
|
self.headers['Authorization'],
|
|
self.server.debug,
|
|
shared_item_tokens):
|
|
wanted_collection_authorized = True
|
|
elif self.server.debug:
|
|
print('Authorization token refused for ' +
|
|
'wanted collection federation')
|
|
# show wanted collection for federation
|
|
wanted_json = []
|
|
if has_accept(self, calling_domain) and \
|
|
wanted_collection_authorized:
|
|
if self.server.debug:
|
|
print('Preparing wanted collection')
|
|
|
|
domain_full = self.server.domain_full
|
|
http_prefix = self.server.http_prefix
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
if self.server.debug:
|
|
print('Wanted collection for account: ' + nickname)
|
|
base_dir = self.server.base_dir
|
|
wanted_items_per_page = 12
|
|
max_shares_per_account = wanted_items_per_page
|
|
shared_items_federated_domains = \
|
|
self.server.shared_items_federated_domains
|
|
actor = \
|
|
local_actor_url(http_prefix, nickname, domain_full) + \
|
|
'/wanted'
|
|
wanted_json = \
|
|
get_shares_collection(actor, page_number,
|
|
wanted_items_per_page, base_dir,
|
|
self.server.domain, nickname,
|
|
max_shares_per_account,
|
|
shared_items_federated_domains,
|
|
'wanted')
|
|
msg_str = json.dumps(wanted_json,
|
|
ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
accept_str = self.headers['Accept']
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
return
|
|
|
|
# shared items catalog for this instance
|
|
# this is only accessible to instance members or to
|
|
# other instances which present an authorization token
|
|
if self.path.startswith('/catalog') or \
|
|
(self.path.startswith('/users/') and '/catalog' in self.path):
|
|
catalog_authorized = authorized
|
|
if not catalog_authorized:
|
|
if self.server.debug:
|
|
print('Catalog access is not authorized. ' +
|
|
'Checking Authorization header')
|
|
# Check the authorization token
|
|
if self.headers.get('Origin') and \
|
|
self.headers.get('Authorization'):
|
|
permitted_domains = \
|
|
self.server.shared_items_federated_domains
|
|
shared_item_tokens = \
|
|
self.server.shared_item_federation_tokens
|
|
if authorize_shared_items(permitted_domains,
|
|
self.server.base_dir,
|
|
self.headers['Origin'],
|
|
calling_domain,
|
|
self.headers['Authorization'],
|
|
self.server.debug,
|
|
shared_item_tokens):
|
|
catalog_authorized = True
|
|
elif self.server.debug:
|
|
print('Authorization token refused for ' +
|
|
'shared items federation')
|
|
elif self.server.debug:
|
|
print('No Authorization header is available for ' +
|
|
'shared items federation')
|
|
# show shared items catalog for federation
|
|
if has_accept(self, calling_domain) and catalog_authorized:
|
|
catalog_type = 'json'
|
|
headers = self.headers
|
|
debug = self.server.debug
|
|
if self.path.endswith('.csv') or request_csv(headers):
|
|
catalog_type = 'csv'
|
|
elif (self.path.endswith('.json') or
|
|
not request_http(headers, debug)):
|
|
catalog_type = 'json'
|
|
if self.server.debug:
|
|
print('Preparing DFC catalog in format ' + catalog_type)
|
|
|
|
if catalog_type == 'json':
|
|
# catalog as a json
|
|
if not self.path.startswith('/users/'):
|
|
if self.server.debug:
|
|
print('Catalog for the instance')
|
|
catalog_json = \
|
|
shares_catalog_endpoint(self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.path, 'shares')
|
|
else:
|
|
domain_full = self.server.domain_full
|
|
http_prefix = self.server.http_prefix
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
if self.server.debug:
|
|
print('Catalog for account: ' + nickname)
|
|
base_dir = self.server.base_dir
|
|
catalog_json = \
|
|
shares_catalog_account_endpoint(base_dir,
|
|
http_prefix,
|
|
nickname,
|
|
self.server.domain,
|
|
domain_full,
|
|
self.path,
|
|
self.server.debug,
|
|
'shares')
|
|
msg_str = json.dumps(catalog_json,
|
|
ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
accept_str = self.headers['Accept']
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
return
|
|
elif catalog_type == 'csv':
|
|
# catalog as a CSV file for import into a spreadsheet
|
|
msg = \
|
|
shares_catalog_csv_endpoint(self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.path,
|
|
'shares').encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/csv',
|
|
msglen, None, calling_domain, False)
|
|
write2(self, msg)
|
|
return
|
|
http_404(self, 118)
|
|
return
|
|
http_400(self)
|
|
return
|
|
|
|
# wanted items catalog for this instance
|
|
# this is only accessible to instance members or to
|
|
# other instances which present an authorization token
|
|
if self.path.startswith('/wantedItems') or \
|
|
(self.path.startswith('/users/') and '/wantedItems' in self.path):
|
|
catalog_authorized = authorized
|
|
if not catalog_authorized:
|
|
if self.server.debug:
|
|
print('Wanted catalog access is not authorized. ' +
|
|
'Checking Authorization header')
|
|
# Check the authorization token
|
|
if self.headers.get('Origin') and \
|
|
self.headers.get('Authorization'):
|
|
permitted_domains = \
|
|
self.server.shared_items_federated_domains
|
|
shared_item_tokens = \
|
|
self.server.shared_item_federation_tokens
|
|
if authorize_shared_items(permitted_domains,
|
|
self.server.base_dir,
|
|
self.headers['Origin'],
|
|
calling_domain,
|
|
self.headers['Authorization'],
|
|
self.server.debug,
|
|
shared_item_tokens):
|
|
catalog_authorized = True
|
|
elif self.server.debug:
|
|
print('Authorization token refused for ' +
|
|
'wanted items federation')
|
|
elif self.server.debug:
|
|
print('No Authorization header is available for ' +
|
|
'wanted items federation')
|
|
# show wanted items catalog for federation
|
|
if has_accept(self, calling_domain) and catalog_authorized:
|
|
catalog_type = 'json'
|
|
headers = self.headers
|
|
debug = self.server.debug
|
|
if self.path.endswith('.csv') or request_csv(headers):
|
|
catalog_type = 'csv'
|
|
elif (self.path.endswith('.json') or
|
|
not request_http(headers, debug)):
|
|
catalog_type = 'json'
|
|
if self.server.debug:
|
|
print('Preparing DFC wanted catalog in format ' +
|
|
catalog_type)
|
|
|
|
if catalog_type == 'json':
|
|
# catalog as a json
|
|
if not self.path.startswith('/users/'):
|
|
if self.server.debug:
|
|
print('Wanted catalog for the instance')
|
|
catalog_json = \
|
|
shares_catalog_endpoint(self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.path, 'wanted')
|
|
else:
|
|
domain_full = self.server.domain_full
|
|
http_prefix = self.server.http_prefix
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
if self.server.debug:
|
|
print('Wanted catalog for account: ' + nickname)
|
|
base_dir = self.server.base_dir
|
|
catalog_json = \
|
|
shares_catalog_account_endpoint(base_dir,
|
|
http_prefix,
|
|
nickname,
|
|
self.server.domain,
|
|
domain_full,
|
|
self.path,
|
|
self.server.debug,
|
|
'wanted')
|
|
msg_str = json.dumps(catalog_json,
|
|
ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
accept_str = self.headers['Accept']
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
return
|
|
elif catalog_type == 'csv':
|
|
# catalog as a CSV file for import into a spreadsheet
|
|
msg = \
|
|
shares_catalog_csv_endpoint(self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.path,
|
|
'wanted').encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/csv',
|
|
msglen, None, calling_domain, False)
|
|
write2(self, msg)
|
|
return
|
|
http_404(self, 119)
|
|
return
|
|
http_400(self)
|
|
return
|
|
|
|
# minimal mastodon api
|
|
if masto_api(self, self.path, calling_domain, ua_str,
|
|
authorized,
|
|
self.server.http_prefix,
|
|
self.server.base_dir,
|
|
self.authorized_nickname,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
self.server.translate,
|
|
self.server.registration,
|
|
self.server.system_language,
|
|
self.server.project_version,
|
|
self.server.custom_emoji,
|
|
self.server.show_node_info_accounts,
|
|
referer_domain,
|
|
self.server.debug,
|
|
self.server.known_crawlers,
|
|
self.server.sites_unavailable):
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_masto_api[calling_domain]',
|
|
self.server.debug)
|
|
|
|
curr_session = \
|
|
establish_session("GET", curr_session,
|
|
proxy_type, self.server)
|
|
if not curr_session:
|
|
http_404(self, 120)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'session fail',
|
|
self.server.debug)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'create session',
|
|
self.server.debug)
|
|
|
|
# is this a html/ssml/icalendar request?
|
|
html_getreq = False
|
|
csv_getreq = False
|
|
ssml_getreq = False
|
|
icalendar_getreq = False
|
|
if has_accept(self, calling_domain):
|
|
if request_http(self.headers, self.server.debug):
|
|
html_getreq = True
|
|
elif request_csv(self.headers):
|
|
csv_getreq = True
|
|
elif request_ssml(self.headers):
|
|
ssml_getreq = True
|
|
elif request_icalendar(self.headers):
|
|
icalendar_getreq = True
|
|
else:
|
|
if self.headers.get('Connection'):
|
|
# https://developer.mozilla.org/en-US/
|
|
# docs/Web/HTTP/Protocol_upgrade_mechanism
|
|
if self.headers.get('Upgrade'):
|
|
print('HTTP Connection request: ' +
|
|
self.headers['Upgrade'])
|
|
else:
|
|
print('HTTP Connection request: ' +
|
|
self.headers['Connection'])
|
|
http_200(self)
|
|
else:
|
|
print('WARN: No Accept header ' + str(self.headers))
|
|
http_400(self)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'hasAccept',
|
|
self.server.debug)
|
|
|
|
# cached favicon images
|
|
# Note that this comes before the busy flag to avoid conflicts
|
|
if self.path.startswith('/favicons/'):
|
|
if self.server.domain_full in self.path:
|
|
# favicon for this instance
|
|
get_favicon(self, calling_domain, self.server.base_dir,
|
|
self.server.debug, 'favicon.ico')
|
|
return
|
|
show_cached_favicon(self, referer_domain, self.path,
|
|
self.server.base_dir,
|
|
getreq_start_time)
|
|
return
|
|
|
|
# get css
|
|
# Note that this comes before the busy flag to avoid conflicts
|
|
if self.path.endswith('.css'):
|
|
if get_style_sheet(self, self.server.base_dir,
|
|
calling_domain, self.path,
|
|
getreq_start_time):
|
|
return
|
|
|
|
if authorized and '/exports/' in self.path:
|
|
if 'blocks.csv' in self.path:
|
|
get_exported_blocks(self, self.path,
|
|
self.server.base_dir,
|
|
self.server.domain,
|
|
calling_domain)
|
|
else:
|
|
get_exported_theme(self, self.path,
|
|
self.server.base_dir,
|
|
self.server.domain_full)
|
|
return
|
|
|
|
# get fonts
|
|
if '/fonts/' in self.path:
|
|
get_fonts(self, calling_domain, self.path,
|
|
self.server.base_dir, self.server.debug,
|
|
getreq_start_time)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'fonts',
|
|
self.server.debug)
|
|
|
|
if self.path in ('/sharedInbox', '/users/inbox', '/actor/inbox',
|
|
'/users/' + self.server.domain):
|
|
# if shared inbox is not enabled
|
|
if not self.server.enable_shared_inbox:
|
|
http_503(self)
|
|
return
|
|
|
|
self.path = '/inbox'
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'sharedInbox enabled',
|
|
self.server.debug)
|
|
|
|
if self.path == '/categories.xml':
|
|
get_hashtag_categories_feed2(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
proxy_type,
|
|
getreq_start_time,
|
|
self.server.debug,
|
|
curr_session)
|
|
return
|
|
|
|
if self.path == '/newswire.xml':
|
|
_get_newswire_feed(self, calling_domain, self.path,
|
|
proxy_type,
|
|
getreq_start_time,
|
|
self.server.debug,
|
|
curr_session)
|
|
return
|
|
|
|
# RSS 2.0
|
|
if self.path.startswith('/blog/') and \
|
|
self.path.endswith('/rss.xml'):
|
|
if not self.path == '/blog/rss.xml':
|
|
_get_rss2feed(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
proxy_type,
|
|
getreq_start_time,
|
|
self.server.debug,
|
|
curr_session)
|
|
else:
|
|
_get_rss2site(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.port,
|
|
proxy_type,
|
|
self.server.translate,
|
|
getreq_start_time,
|
|
self.server.debug,
|
|
curr_session)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'rss2 done',
|
|
self.server.debug)
|
|
|
|
# RSS 3.0
|
|
if self.path.startswith('/blog/') and \
|
|
self.path.endswith('/rss.txt'):
|
|
_get_rss3feed(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
proxy_type,
|
|
getreq_start_time,
|
|
self.server.debug,
|
|
self.server.system_language,
|
|
curr_session)
|
|
return
|
|
|
|
users_in_path = False
|
|
if '/users/' in self.path:
|
|
users_in_path = True
|
|
|
|
if authorized and not html_getreq and users_in_path:
|
|
if '/following?page=' in self.path:
|
|
_get_following_json(self, self.server.base_dir,
|
|
self.path,
|
|
calling_domain, referer_domain,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
self.server.followingItemsPerPage,
|
|
self.server.debug, 'following')
|
|
return
|
|
if '/followers?page=' in self.path:
|
|
_get_following_json(self, self.server.base_dir,
|
|
self.path,
|
|
calling_domain, referer_domain,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
self.server.followingItemsPerPage,
|
|
self.server.debug, 'followers')
|
|
return
|
|
if '/followrequests?page=' in self.path:
|
|
_get_following_json(self, self.server.base_dir,
|
|
self.path,
|
|
calling_domain, referer_domain,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
self.server.followingItemsPerPage,
|
|
self.server.debug,
|
|
'followrequests')
|
|
return
|
|
|
|
# authorized endpoint used for TTS of posts
|
|
# arriving in your inbox
|
|
if authorized and users_in_path and \
|
|
self.path.endswith('/speaker'):
|
|
if 'application/ssml' not in self.headers['Accept']:
|
|
# json endpoint
|
|
_get_speaker(self, calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.domain)
|
|
else:
|
|
xml_str = \
|
|
get_ssml_box(self.server.base_dir,
|
|
self.path, self.server.domain,
|
|
self.server.system_language,
|
|
self.server.instanceTitle,
|
|
'inbox')
|
|
if xml_str:
|
|
msg = xml_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'application/xrd+xml', msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
return
|
|
|
|
# show a podcast episode
|
|
if authorized and users_in_path and html_getreq and \
|
|
'?podepisode=' in self.path:
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
episode_timestamp = self.path.split('?podepisode=')[1].strip()
|
|
episode_timestamp = episode_timestamp.replace('__', ' ')
|
|
episode_timestamp = episode_timestamp.replace('aa', ':')
|
|
if self.server.newswire.get(episode_timestamp):
|
|
pod_episode = self.server.newswire[episode_timestamp]
|
|
html_str = \
|
|
html_podcast_episode(self.server.translate,
|
|
self.server.base_dir,
|
|
nickname,
|
|
self.server.domain,
|
|
pod_episode,
|
|
self.server.text_mode_banner,
|
|
self.server.session,
|
|
self.server.session_onion,
|
|
self.server.session_i2p,
|
|
self.server.http_prefix,
|
|
self.server.debug)
|
|
if html_str:
|
|
msg = html_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/html', msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
return
|
|
|
|
# redirect to the welcome screen
|
|
if html_getreq and authorized and users_in_path and \
|
|
'/welcome' not in self.path:
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
if '?' in nickname:
|
|
nickname = nickname.split('?')[0]
|
|
if nickname == self.authorized_nickname and \
|
|
self.path != '/users/' + nickname:
|
|
if not is_welcome_screen_complete(self.server.base_dir,
|
|
nickname,
|
|
self.server.domain):
|
|
redirect_headers(self, '/users/' + nickname + '/welcome',
|
|
cookie, calling_domain)
|
|
return
|
|
|
|
if not html_getreq and \
|
|
users_in_path and self.path.endswith('/pinned'):
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
pinned_post_json = \
|
|
get_pinned_post_as_json(self.server.base_dir,
|
|
self.server.http_prefix,
|
|
nickname, self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.system_language)
|
|
message_json = {}
|
|
if pinned_post_json:
|
|
post_id = remove_id_ending(pinned_post_json['id'])
|
|
message_json = \
|
|
outbox_message_create_wrap(self.server.http_prefix,
|
|
nickname,
|
|
self.server.domain,
|
|
self.server.port,
|
|
pinned_post_json)
|
|
message_json['id'] = post_id + '/activity'
|
|
message_json['object']['id'] = post_id
|
|
message_json['object']['url'] = replace_users_with_at(post_id)
|
|
message_json['object']['atomUri'] = post_id
|
|
msg_str = json.dumps(message_json,
|
|
ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
accept_str = self.headers['Accept']
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
return
|
|
|
|
if not html_getreq and \
|
|
users_in_path and self.path.endswith('/collections/featured'):
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
# return the featured posts collection
|
|
_get_featured_collection(self, calling_domain, referer_domain,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
nickname, self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.system_language)
|
|
return
|
|
|
|
if not html_getreq and \
|
|
users_in_path and self.path.endswith('/collections/featuredTags'):
|
|
_get_featured_tags_collection(self, calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.domain)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_get_featured_tags_collection done',
|
|
self.server.debug)
|
|
|
|
# show a performance graph
|
|
if authorized and '/performance?graph=' in self.path:
|
|
graph = self.path.split('?graph=')[1]
|
|
if html_getreq and not graph.endswith('.json'):
|
|
if graph == 'post':
|
|
graph = '_POST'
|
|
elif graph == 'inbox':
|
|
graph = 'INBOX'
|
|
elif graph == 'get':
|
|
graph = '_GET'
|
|
msg = \
|
|
html_watch_points_graph(self.server.base_dir,
|
|
self.server.fitness,
|
|
graph, 16).encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/html', msglen,
|
|
cookie, calling_domain, False)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'graph',
|
|
self.server.debug)
|
|
return
|
|
graph = graph.replace('.json', '')
|
|
if graph == 'post':
|
|
graph = '_POST'
|
|
elif graph == 'inbox':
|
|
graph = 'INBOX'
|
|
elif graph == 'get':
|
|
graph = '_GET'
|
|
watch_points_json = \
|
|
sorted_watch_points(self.server.fitness, graph)
|
|
msg_str = json.dumps(watch_points_json,
|
|
ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
accept_str = self.headers['Accept']
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'graph json',
|
|
self.server.debug)
|
|
return
|
|
|
|
# show the main blog page
|
|
if html_getreq and \
|
|
self.path in ('/blog', '/blog/', '/blogs', '/blogs/'):
|
|
if '/rss.xml' not in self.path:
|
|
curr_session = \
|
|
establish_session("show the main blog page",
|
|
curr_session,
|
|
proxy_type, self.server)
|
|
if not curr_session:
|
|
http_404(self, 121)
|
|
return
|
|
msg = html_blog_view(authorized,
|
|
curr_session,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.translate,
|
|
self.server.domain,
|
|
self.server.port,
|
|
MAX_POSTS_IN_BLOGS_FEED,
|
|
self.server.peertube_instances,
|
|
self.server.system_language,
|
|
self.server.person_cache,
|
|
self.server.debug)
|
|
if msg is not None:
|
|
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, self.server.fitness,
|
|
'_GET', 'blog view',
|
|
self.server.debug)
|
|
return
|
|
http_404(self, 122)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'blog view done',
|
|
self.server.debug)
|
|
|
|
# show a particular page of blog entries
|
|
# for a particular account
|
|
if html_getreq and self.path.startswith('/blog/'):
|
|
if '/rss.xml' not in self.path:
|
|
if _show_blog_page(self, authorized,
|
|
calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie, self.server.translate,
|
|
self.server.debug,
|
|
curr_session):
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_show_blog_page',
|
|
self.server.debug)
|
|
|
|
if html_getreq and users_in_path:
|
|
# show the person options screen with view/follow/block/report
|
|
if '?options=' in self.path:
|
|
show_person_options(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
authorized,
|
|
curr_session)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'person options done',
|
|
self.server.debug)
|
|
# show blog post
|
|
blog_filename, nickname = \
|
|
path_contains_blog_link(self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.path)
|
|
if blog_filename and nickname:
|
|
post_json_object = load_json(blog_filename)
|
|
if is_blog_post(post_json_object):
|
|
msg = html_blog_post(curr_session,
|
|
authorized,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.translate,
|
|
nickname, self.server.domain,
|
|
self.server.domain_full,
|
|
post_json_object,
|
|
self.server.peertube_instances,
|
|
self.server.system_language,
|
|
self.server.person_cache,
|
|
self.server.debug,
|
|
self.server.content_license_url)
|
|
if msg is not None:
|
|
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,
|
|
self.server.fitness,
|
|
'_GET', 'blog post 2',
|
|
self.server.debug)
|
|
return
|
|
http_404(self, 123)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'blog post 2 done',
|
|
self.server.debug)
|
|
|
|
# after selecting a shared item from the left column then show it
|
|
if html_getreq and \
|
|
'?showshare=' in self.path and '/users/' in self.path:
|
|
item_id = self.path.split('?showshare=')[1]
|
|
if '?' in item_id:
|
|
item_id = item_id.split('?')[0]
|
|
category = ''
|
|
if '?category=' in self.path:
|
|
category = self.path.split('?category=')[1]
|
|
if '?' in category:
|
|
category = category.split('?')[0]
|
|
users_path = self.path.split('?showshare=')[0]
|
|
nickname = users_path.replace('/users/', '')
|
|
item_id = urllib.parse.unquote_plus(item_id.strip())
|
|
msg = \
|
|
html_show_share(self.server.base_dir,
|
|
self.server.domain, nickname,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
item_id, self.server.translate,
|
|
self.server.shared_items_federated_domains,
|
|
self.server.default_timeline,
|
|
self.server.theme_name, 'shares', category,
|
|
False)
|
|
if not msg:
|
|
if calling_domain.endswith('.onion') and \
|
|
self.server.onion_domain:
|
|
actor = 'http://' + self.server.onion_domain + users_path
|
|
elif (calling_domain.endswith('.i2p') and
|
|
self.server.i2p_domain):
|
|
actor = 'http://' + self.server.i2p_domain + users_path
|
|
redirect_headers(self, actor + '/tlshares',
|
|
cookie, calling_domain)
|
|
return
|
|
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, self.server.fitness,
|
|
'_GET', 'html_show_share',
|
|
self.server.debug)
|
|
return
|
|
|
|
# after selecting a wanted item from the left column then show it
|
|
if html_getreq and \
|
|
'?showwanted=' in self.path and '/users/' in self.path:
|
|
item_id = self.path.split('?showwanted=')[1]
|
|
if ';' in item_id:
|
|
item_id = item_id.split(';')[0]
|
|
category = self.path.split('?category=')[1]
|
|
if ';' in category:
|
|
category = category.split(';')[0]
|
|
users_path = self.path.split('?showwanted=')[0]
|
|
nickname = users_path.replace('/users/', '')
|
|
item_id = urllib.parse.unquote_plus(item_id.strip())
|
|
msg = \
|
|
html_show_share(self.server.base_dir,
|
|
self.server.domain, nickname,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
item_id, self.server.translate,
|
|
self.server.shared_items_federated_domains,
|
|
self.server.default_timeline,
|
|
self.server.theme_name, 'wanted', category,
|
|
False)
|
|
if not msg:
|
|
if calling_domain.endswith('.onion') and \
|
|
self.server.onion_domain:
|
|
actor = 'http://' + self.server.onion_domain + users_path
|
|
elif (calling_domain.endswith('.i2p') and
|
|
self.server.i2p_domain):
|
|
actor = 'http://' + self.server.i2p_domain + users_path
|
|
redirect_headers(self, actor + '/tlwanted',
|
|
cookie, calling_domain)
|
|
return
|
|
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, self.server.fitness,
|
|
'_GET', 'htmlShowWanted',
|
|
self.server.debug)
|
|
return
|
|
|
|
# remove a shared item
|
|
if html_getreq and '?rmshare=' in self.path:
|
|
item_id = self.path.split('?rmshare=')[1]
|
|
item_id = urllib.parse.unquote_plus(item_id.strip())
|
|
users_path = self.path.split('?rmshare=')[0]
|
|
actor = \
|
|
self.server.http_prefix + '://' + \
|
|
self.server.domain_full + users_path
|
|
msg = html_confirm_remove_shared_item(self.server.translate,
|
|
self.server.base_dir,
|
|
actor, item_id,
|
|
calling_domain, 'shares')
|
|
if not msg:
|
|
if calling_domain.endswith('.onion') and \
|
|
self.server.onion_domain:
|
|
actor = 'http://' + self.server.onion_domain + users_path
|
|
elif (calling_domain.endswith('.i2p') and
|
|
self.server.i2p_domain):
|
|
actor = 'http://' + self.server.i2p_domain + users_path
|
|
redirect_headers(self, actor + '/tlshares',
|
|
cookie, calling_domain)
|
|
return
|
|
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, self.server.fitness,
|
|
'_GET', 'remove shared item',
|
|
self.server.debug)
|
|
return
|
|
|
|
# remove a wanted item
|
|
if html_getreq and '?rmwanted=' in self.path:
|
|
item_id = self.path.split('?rmwanted=')[1]
|
|
item_id = urllib.parse.unquote_plus(item_id.strip())
|
|
users_path = self.path.split('?rmwanted=')[0]
|
|
actor = \
|
|
self.server.http_prefix + '://' + \
|
|
self.server.domain_full + users_path
|
|
msg = html_confirm_remove_shared_item(self.server.translate,
|
|
self.server.base_dir,
|
|
actor, item_id,
|
|
calling_domain, 'wanted')
|
|
if not msg:
|
|
if calling_domain.endswith('.onion') and \
|
|
self.server.onion_domain:
|
|
actor = 'http://' + self.server.onion_domain + users_path
|
|
elif (calling_domain.endswith('.i2p') and
|
|
self.server.i2p_domain):
|
|
actor = 'http://' + self.server.i2p_domain + users_path
|
|
redirect_headers(self, actor + '/tlwanted',
|
|
cookie, calling_domain)
|
|
return
|
|
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, self.server.fitness,
|
|
'_GET', 'remove shared item',
|
|
self.server.debug)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'remove shared item done',
|
|
self.server.debug)
|
|
|
|
if self.path.startswith('/terms'):
|
|
if calling_domain.endswith('.onion') and \
|
|
self.server.onion_domain:
|
|
msg = html_terms_of_service(self.server.base_dir, 'http',
|
|
self.server.onion_domain)
|
|
elif (calling_domain.endswith('.i2p') and
|
|
self.server.i2p_domain):
|
|
msg = html_terms_of_service(self.server.base_dir, 'http',
|
|
self.server.i2p_domain)
|
|
else:
|
|
msg = html_terms_of_service(self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain_full)
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/html', msglen, calling_domain)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'terms of service shown',
|
|
self.server.debug)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'terms of service done',
|
|
self.server.debug)
|
|
|
|
# show a list of who you are following
|
|
if (authorized and users_in_path and
|
|
(self.path.endswith('/followingaccounts') or
|
|
self.path.endswith('/followingaccounts.csv'))):
|
|
nickname = get_nickname_from_actor(self.path)
|
|
if not nickname:
|
|
http_404(self, 124)
|
|
return
|
|
following_filename = \
|
|
acct_dir(self.server.base_dir,
|
|
nickname, self.server.domain) + '/following.txt'
|
|
if not os.path.isfile(following_filename):
|
|
http_404(self, 125)
|
|
return
|
|
if self.path.endswith('/followingaccounts.csv'):
|
|
html_getreq = False
|
|
csv_getreq = True
|
|
if html_getreq:
|
|
msg = html_following_list(self.server.base_dir,
|
|
following_filename)
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/html', msglen, calling_domain)
|
|
write2(self, msg.encode('utf-8'))
|
|
elif csv_getreq:
|
|
msg = csv_following_list(following_filename,
|
|
self.server.base_dir,
|
|
nickname,
|
|
self.server.domain)
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/csv', msglen, calling_domain)
|
|
write2(self, msg.encode('utf-8'))
|
|
else:
|
|
http_404(self, 126)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'following accounts shown',
|
|
self.server.debug)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'following accounts done',
|
|
self.server.debug)
|
|
|
|
# show a list of who are your followers
|
|
if authorized and users_in_path and \
|
|
self.path.endswith('/followersaccounts'):
|
|
nickname = get_nickname_from_actor(self.path)
|
|
if not nickname:
|
|
http_404(self, 127)
|
|
return
|
|
followers_filename = \
|
|
acct_dir(self.server.base_dir,
|
|
nickname, self.server.domain) + '/followers.txt'
|
|
if not os.path.isfile(followers_filename):
|
|
http_404(self, 128)
|
|
return
|
|
if html_getreq:
|
|
msg = html_following_list(self.server.base_dir,
|
|
followers_filename)
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/html', msglen, calling_domain)
|
|
write2(self, msg.encode('utf-8'))
|
|
elif csv_getreq:
|
|
msg = csv_following_list(followers_filename,
|
|
self.server.base_dir,
|
|
nickname,
|
|
self.server.domain)
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/csv', msglen, calling_domain)
|
|
write2(self, msg.encode('utf-8'))
|
|
else:
|
|
http_404(self, 129)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'followers accounts shown',
|
|
self.server.debug)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'followers accounts done',
|
|
self.server.debug)
|
|
|
|
if self.path.endswith('/about'):
|
|
if calling_domain.endswith('.onion'):
|
|
msg = \
|
|
html_about(self.server.base_dir, 'http',
|
|
self.server.onion_domain,
|
|
None, self.server.translate,
|
|
self.server.system_language)
|
|
elif calling_domain.endswith('.i2p'):
|
|
msg = \
|
|
html_about(self.server.base_dir, 'http',
|
|
self.server.i2p_domain,
|
|
None, self.server.translate,
|
|
self.server.system_language)
|
|
else:
|
|
msg = \
|
|
html_about(self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.translate,
|
|
self.server.system_language)
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/html', msglen, calling_domain)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show about screen',
|
|
self.server.debug)
|
|
return
|
|
|
|
if self.path in ('/specification', '/protocol', '/activitypub'):
|
|
if calling_domain.endswith('.onion'):
|
|
msg = \
|
|
html_specification(self.server.base_dir, 'http',
|
|
self.server.onion_domain,
|
|
None, self.server.translate,
|
|
self.server.system_language)
|
|
elif calling_domain.endswith('.i2p'):
|
|
msg = \
|
|
html_specification(self.server.base_dir, 'http',
|
|
self.server.i2p_domain,
|
|
None, self.server.translate,
|
|
self.server.system_language)
|
|
else:
|
|
msg = \
|
|
html_specification(self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.translate,
|
|
self.server.system_language)
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/html', msglen, calling_domain)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show specification screen',
|
|
self.server.debug)
|
|
return
|
|
|
|
if self.path in ('/manual', '/usermanual', '/userguide'):
|
|
if calling_domain.endswith('.onion'):
|
|
msg = \
|
|
html_manual(self.server.base_dir, 'http',
|
|
self.server.onion_domain,
|
|
None, self.server.translate,
|
|
self.server.system_language)
|
|
elif calling_domain.endswith('.i2p'):
|
|
msg = \
|
|
html_manual(self.server.base_dir, 'http',
|
|
self.server.i2p_domain,
|
|
None, self.server.translate,
|
|
self.server.system_language)
|
|
else:
|
|
msg = \
|
|
html_manual(self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.translate,
|
|
self.server.system_language)
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/html', msglen, calling_domain)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show user manual screen',
|
|
self.server.debug)
|
|
return
|
|
|
|
if html_getreq and users_in_path and authorized and \
|
|
self.path.endswith('/accesskeys'):
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
|
|
access_keys = self.server.access_keys
|
|
if self.server.key_shortcuts.get(nickname):
|
|
access_keys = \
|
|
self.server.key_shortcuts[nickname]
|
|
|
|
msg = \
|
|
html_access_keys(self.server.base_dir,
|
|
nickname, self.server.domain,
|
|
self.server.translate,
|
|
access_keys,
|
|
self.server.access_keys,
|
|
self.server.default_timeline,
|
|
self.server.theme_name)
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/html', msglen, calling_domain)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show accesskeys screen',
|
|
self.server.debug)
|
|
return
|
|
|
|
if html_getreq and users_in_path and authorized and \
|
|
self.path.endswith('/themedesigner'):
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
|
|
if not is_artist(self.server.base_dir, nickname):
|
|
http_403(self)
|
|
return
|
|
|
|
msg = \
|
|
html_theme_designer(self.server.base_dir,
|
|
nickname, self.server.domain,
|
|
self.server.translate,
|
|
self.server.default_timeline,
|
|
self.server.theme_name,
|
|
self.server.access_keys)
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/html', msglen, calling_domain)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show theme designer screen',
|
|
self.server.debug)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show about screen done',
|
|
self.server.debug)
|
|
|
|
# the initial welcome screen after first logging in
|
|
if html_getreq and authorized and \
|
|
'/users/' in self.path and self.path.endswith('/welcome'):
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
if not is_welcome_screen_complete(self.server.base_dir,
|
|
nickname,
|
|
self.server.domain):
|
|
msg = \
|
|
html_welcome_screen(self.server.base_dir, nickname,
|
|
self.server.system_language,
|
|
self.server.translate,
|
|
self.server.theme_name)
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/html', msglen, calling_domain)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show welcome screen',
|
|
self.server.debug)
|
|
return
|
|
self.path = self.path.replace('/welcome', '')
|
|
|
|
# the welcome screen which allows you to set an avatar image
|
|
if html_getreq and authorized and \
|
|
'/users/' in self.path and self.path.endswith('/welcome_profile'):
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
if not is_welcome_screen_complete(self.server.base_dir,
|
|
nickname,
|
|
self.server.domain):
|
|
msg = \
|
|
html_welcome_profile(self.server.base_dir, nickname,
|
|
self.server.domain,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.system_language,
|
|
self.server.translate,
|
|
self.server.theme_name)
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/html', msglen, calling_domain)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show welcome profile screen',
|
|
self.server.debug)
|
|
return
|
|
self.path = self.path.replace('/welcome_profile', '')
|
|
|
|
# the final welcome screen
|
|
if html_getreq and authorized and \
|
|
'/users/' in self.path and self.path.endswith('/welcome_final'):
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
if not is_welcome_screen_complete(self.server.base_dir,
|
|
nickname,
|
|
self.server.domain):
|
|
msg = \
|
|
html_welcome_final(self.server.base_dir, nickname,
|
|
self.server.system_language,
|
|
self.server.translate,
|
|
self.server.theme_name)
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/html', msglen, calling_domain)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show welcome final screen',
|
|
self.server.debug)
|
|
return
|
|
self.path = self.path.replace('/welcome_final', '')
|
|
|
|
# if not authorized then show the login screen
|
|
if html_getreq and self.path != '/login' and \
|
|
not is_image_file(self.path) and \
|
|
self.path != '/' and \
|
|
not self.path.startswith('/.well-known/protocol-handler') and \
|
|
self.path != '/users/news/linksmobile' and \
|
|
self.path != '/users/news/newswiremobile':
|
|
if _redirect_to_login_screen(self, calling_domain, self.path,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
authorized, self.server.debug):
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show login screen done',
|
|
self.server.debug)
|
|
|
|
# manifest images used to create a home screen icon
|
|
# when selecting "add to home screen" in browsers
|
|
# which support progressive web apps
|
|
if self.path in ('/logo72.png', '/logo96.png', '/logo128.png',
|
|
'/logo144.png', '/logo150.png', '/logo192.png',
|
|
'/logo256.png', '/logo512.png',
|
|
'/apple-touch-icon.png'):
|
|
media_filename = \
|
|
self.server.base_dir + '/img' + self.path
|
|
if os.path.isfile(media_filename):
|
|
if etag_exists(self, media_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return
|
|
|
|
tries = 0
|
|
media_binary = None
|
|
while tries < 5:
|
|
try:
|
|
with open(media_filename, 'rb') as av_file:
|
|
media_binary = av_file.read()
|
|
break
|
|
except OSError as ex:
|
|
print('EX: manifest logo ' +
|
|
str(tries) + ' ' + str(ex))
|
|
time.sleep(1)
|
|
tries += 1
|
|
if media_binary:
|
|
mime_type = media_file_mime_type(media_filename)
|
|
set_headers_etag(self, media_filename, mime_type,
|
|
media_binary, cookie,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, media_binary)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'manifest logo shown',
|
|
self.server.debug)
|
|
return
|
|
http_404(self, 130)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'manifest logo done',
|
|
self.server.debug)
|
|
|
|
# manifest images used to show example screenshots
|
|
# for use by app stores
|
|
if self.path == '/screenshot1.jpg' or \
|
|
self.path == '/screenshot2.jpg':
|
|
screen_filename = \
|
|
self.server.base_dir + '/img' + self.path
|
|
if os.path.isfile(screen_filename):
|
|
if etag_exists(self, screen_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return
|
|
|
|
tries = 0
|
|
media_binary = None
|
|
while tries < 5:
|
|
try:
|
|
with open(screen_filename, 'rb') as av_file:
|
|
media_binary = av_file.read()
|
|
break
|
|
except OSError as ex:
|
|
print('EX: manifest screenshot ' +
|
|
str(tries) + ' ' + str(ex))
|
|
time.sleep(1)
|
|
tries += 1
|
|
if media_binary:
|
|
mime_type = media_file_mime_type(screen_filename)
|
|
set_headers_etag(self, screen_filename, mime_type,
|
|
media_binary, cookie,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, media_binary)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show screenshot',
|
|
self.server.debug)
|
|
return
|
|
http_404(self, 131)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show screenshot done',
|
|
self.server.debug)
|
|
|
|
# image on login screen or qrcode
|
|
if (is_image_file(self.path) and
|
|
(self.path.startswith('/login.') or
|
|
self.path.startswith('/qrcode.png'))):
|
|
icon_filename = \
|
|
self.server.base_dir + '/accounts' + self.path
|
|
if os.path.isfile(icon_filename):
|
|
if etag_exists(self, icon_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return
|
|
|
|
tries = 0
|
|
media_binary = None
|
|
while tries < 5:
|
|
try:
|
|
with open(icon_filename, 'rb') as av_file:
|
|
media_binary = av_file.read()
|
|
break
|
|
except OSError as ex:
|
|
print('EX: login screen image ' +
|
|
str(tries) + ' ' + str(ex))
|
|
time.sleep(1)
|
|
tries += 1
|
|
if media_binary:
|
|
mime_type_str = media_file_mime_type(icon_filename)
|
|
set_headers_etag(self, icon_filename,
|
|
mime_type_str,
|
|
media_binary, cookie,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, media_binary)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'login screen logo',
|
|
self.server.debug)
|
|
return
|
|
http_404(self, 132)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'login screen logo done',
|
|
self.server.debug)
|
|
|
|
# QR code for account handle
|
|
if users_in_path and \
|
|
self.path.endswith('/qrcode.png'):
|
|
if _show_qrcode(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
self.server.port,
|
|
getreq_start_time):
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'account qrcode done',
|
|
self.server.debug)
|
|
|
|
# search screen banner image
|
|
if users_in_path:
|
|
if self.path.endswith('/search_banner.png'):
|
|
if _search_screen_banner(self, self.path,
|
|
self.server.base_dir,
|
|
self.server.domain,
|
|
getreq_start_time):
|
|
return
|
|
|
|
if self.path.endswith('/left_col_image.png'):
|
|
if _column_image(self, 'left', self.path,
|
|
self.server.base_dir,
|
|
self.server.domain,
|
|
getreq_start_time):
|
|
return
|
|
|
|
if self.path.endswith('/right_col_image.png'):
|
|
if _column_image(self, 'right', self.path,
|
|
self.server.base_dir,
|
|
self.server.domain,
|
|
getreq_start_time):
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'search screen banner done',
|
|
self.server.debug)
|
|
|
|
if self.path.startswith('/defaultprofilebackground'):
|
|
_show_default_profile_background(self, self.server.base_dir,
|
|
self.server.theme_name,
|
|
getreq_start_time)
|
|
return
|
|
|
|
# show a background image on the login or person options page
|
|
if '-background.' in self.path:
|
|
if _show_background_image(self, self.path,
|
|
self.server.base_dir,
|
|
getreq_start_time):
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'background shown done',
|
|
self.server.debug)
|
|
|
|
# emoji images
|
|
if '/emoji/' in self.path:
|
|
_show_emoji(self, self.path, self.server.base_dir,
|
|
getreq_start_time)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show emoji done',
|
|
self.server.debug)
|
|
|
|
# show media
|
|
# Note that this comes before the busy flag to avoid conflicts
|
|
# replace mastoson-style media path
|
|
if '/system/media_attachments/files/' in self.path:
|
|
self.path = self.path.replace('/system/media_attachments/files/',
|
|
'/media/')
|
|
if '/media/' in self.path:
|
|
_show_media(self, self.path, self.server.base_dir,
|
|
getreq_start_time)
|
|
return
|
|
|
|
if '/ontologies/' in self.path or \
|
|
'/data/' in self.path:
|
|
if not has_users_path(self.path):
|
|
_get_ontology(self, calling_domain,
|
|
self.path, self.server.base_dir,
|
|
getreq_start_time)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show media done',
|
|
self.server.debug)
|
|
|
|
# show shared item images
|
|
# Note that this comes before the busy flag to avoid conflicts
|
|
if '/sharefiles/' in self.path:
|
|
if _show_share_image(self, self.path, self.server.base_dir,
|
|
getreq_start_time):
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'share image done',
|
|
self.server.debug)
|
|
|
|
# icon images
|
|
# Note that this comes before the busy flag to avoid conflicts
|
|
if self.path.startswith('/icons/'):
|
|
_show_icon(self, self.path, self.server.base_dir,
|
|
getreq_start_time)
|
|
return
|
|
|
|
# show images within https://instancedomain/activitypub
|
|
if self.path.startswith('/activitypub-tutorial-'):
|
|
if self.path.endswith('.png'):
|
|
_show_specification_image(self, self.path,
|
|
self.server.base_dir,
|
|
getreq_start_time)
|
|
return
|
|
|
|
# show images within https://instancedomain/manual
|
|
if self.path.startswith('/manual-'):
|
|
if is_image_file(self.path):
|
|
_show_manual_image(self, self.path,
|
|
self.server.base_dir,
|
|
getreq_start_time)
|
|
return
|
|
|
|
# help screen images
|
|
# Note that this comes before the busy flag to avoid conflicts
|
|
if self.path.startswith('/helpimages/'):
|
|
_show_help_screen_image(self, self.path,
|
|
self.server.base_dir,
|
|
getreq_start_time)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'help screen image done',
|
|
self.server.debug)
|
|
|
|
# cached avatar images
|
|
# Note that this comes before the busy flag to avoid conflicts
|
|
if self.path.startswith('/avatars/'):
|
|
_show_cached_avatar(self, referer_domain, self.path,
|
|
self.server.base_dir,
|
|
getreq_start_time)
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'cached avatar done',
|
|
self.server.debug)
|
|
|
|
# show avatar or background image
|
|
# Note that this comes before the busy flag to avoid conflicts
|
|
if _show_avatar_or_banner(self, referer_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.domain,
|
|
getreq_start_time):
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'avatar or banner shown done',
|
|
self.server.debug)
|
|
|
|
# This busy state helps to avoid flooding
|
|
# Resources which are expected to be called from a web page
|
|
# should be above this
|
|
curr_time_getreq = int(time.time() * 1000)
|
|
if self.server.getreq_busy:
|
|
if curr_time_getreq - self.server.last_getreq < 500:
|
|
if self.server.debug:
|
|
print('DEBUG: GET Busy')
|
|
self.send_response(429)
|
|
self.end_headers()
|
|
return
|
|
self.server.getreq_busy = True
|
|
self.server.last_getreq = curr_time_getreq
|
|
|
|
# returns after this point should set getreq_busy to False
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'GET busy time',
|
|
self.server.debug)
|
|
|
|
if not permitted_dir(self.path):
|
|
if self.server.debug:
|
|
print('DEBUG: GET Not permitted')
|
|
http_404(self, 133)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# get webfinger endpoint for a person
|
|
if _webfinger(self, calling_domain, referer_domain, cookie):
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'webfinger called',
|
|
self.server.debug)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'permitted directory',
|
|
self.server.debug)
|
|
|
|
# show the login screen
|
|
if (self.path.startswith('/login') or
|
|
(self.path == '/' and
|
|
not authorized and
|
|
not self.server.news_instance)):
|
|
# request basic auth
|
|
msg = html_login(self.server.translate,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.system_language,
|
|
True, ua_str,
|
|
self.server.theme_name).encode('utf-8')
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/html', msglen, calling_domain)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'login shown',
|
|
self.server.debug)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# show the news front page
|
|
if self.path == '/' and \
|
|
not authorized and \
|
|
self.server.news_instance:
|
|
news_url = get_instance_url(calling_domain,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain) + \
|
|
'/users/news'
|
|
logout_redirect(self, news_url, calling_domain)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'news front page shown',
|
|
self.server.debug)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'login shown done',
|
|
self.server.debug)
|
|
|
|
# the newswire screen on mobile
|
|
if html_getreq and self.path.startswith('/users/') and \
|
|
self.path.endswith('/newswiremobile'):
|
|
if (authorized or
|
|
(not authorized and
|
|
self.path.startswith('/users/news/') and
|
|
self.server.news_instance)):
|
|
nickname = get_nickname_from_actor(self.path)
|
|
if not nickname:
|
|
http_404(self, 134)
|
|
self.server.getreq_busy = False
|
|
return
|
|
timeline_path = \
|
|
'/users/' + nickname + '/' + self.server.default_timeline
|
|
show_publish_as_icon = self.server.show_publish_as_icon
|
|
rss_icon_at_top = self.server.rss_icon_at_top
|
|
icons_as_buttons = self.server.icons_as_buttons
|
|
default_timeline = self.server.default_timeline
|
|
access_keys = self.server.access_keys
|
|
if self.server.key_shortcuts.get(nickname):
|
|
access_keys = self.server.key_shortcuts[nickname]
|
|
msg = \
|
|
html_newswire_mobile(self.server.base_dir,
|
|
nickname,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.translate,
|
|
self.server.newswire,
|
|
self.server.positive_voting,
|
|
timeline_path,
|
|
show_publish_as_icon,
|
|
authorized,
|
|
rss_icon_at_top,
|
|
icons_as_buttons,
|
|
default_timeline,
|
|
self.server.theme_name,
|
|
access_keys,
|
|
ua_str).encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/html', msglen,
|
|
cookie, calling_domain, False)
|
|
write2(self, msg)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
if html_getreq and self.path.startswith('/users/') and \
|
|
self.path.endswith('/linksmobile'):
|
|
if (authorized or
|
|
(not authorized and
|
|
self.path.startswith('/users/news/') and
|
|
self.server.news_instance)):
|
|
nickname = get_nickname_from_actor(self.path)
|
|
if not nickname:
|
|
http_404(self, 135)
|
|
self.server.getreq_busy = False
|
|
return
|
|
access_keys = self.server.access_keys
|
|
if self.server.key_shortcuts.get(nickname):
|
|
access_keys = self.server.key_shortcuts[nickname]
|
|
timeline_path = \
|
|
'/users/' + nickname + '/' + self.server.default_timeline
|
|
icons_as_buttons = self.server.icons_as_buttons
|
|
default_timeline = self.server.default_timeline
|
|
shared_items_domains = \
|
|
self.server.shared_items_federated_domains
|
|
msg = \
|
|
html_links_mobile(self.server.base_dir, nickname,
|
|
self.server.domain_full,
|
|
self.server.http_prefix,
|
|
self.server.translate,
|
|
timeline_path,
|
|
authorized,
|
|
self.server.rss_icon_at_top,
|
|
icons_as_buttons,
|
|
default_timeline,
|
|
self.server.theme_name,
|
|
access_keys,
|
|
shared_items_domains).encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/html', msglen, cookie, calling_domain,
|
|
False)
|
|
write2(self, msg)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
if '?remotetag=' in self.path and \
|
|
'/users/' in self.path and authorized:
|
|
actor = self.path.split('?remotetag=')[0]
|
|
nickname = get_nickname_from_actor(actor)
|
|
hashtag_url = self.path.split('?remotetag=')[1]
|
|
if ';' in hashtag_url:
|
|
hashtag_url = hashtag_url.split(';')[0]
|
|
hashtag_url = hashtag_url.replace('--', '/')
|
|
|
|
page_number = 1
|
|
if ';page=' in self.path:
|
|
page_number_str = self.path.split(';page=')[1]
|
|
if ';' in page_number_str:
|
|
page_number_str = page_number_str.split(';')[0]
|
|
if page_number_str.isdigit():
|
|
page_number = int(page_number_str)
|
|
|
|
allow_local_network_access = self.server.allow_local_network_access
|
|
show_published_date_only = self.server.show_published_date_only
|
|
twitter_replacement_domain = self.server.twitter_replacement_domain
|
|
timezone = None
|
|
if self.server.account_timezone.get(nickname):
|
|
timezone = \
|
|
self.server.account_timezone.get(nickname)
|
|
msg = \
|
|
html_hashtag_search_remote(nickname,
|
|
self.server.domain,
|
|
self.server.port,
|
|
self.server.recent_posts_cache,
|
|
self.server.max_recent_posts,
|
|
self.server.translate,
|
|
self.server.base_dir,
|
|
hashtag_url,
|
|
page_number, MAX_POSTS_IN_FEED,
|
|
self.server.session,
|
|
self.server.cached_webfingers,
|
|
self.server.person_cache,
|
|
self.server.http_prefix,
|
|
self.server.project_version,
|
|
self.server.yt_replace_domain,
|
|
twitter_replacement_domain,
|
|
show_published_date_only,
|
|
self.server.peertube_instances,
|
|
allow_local_network_access,
|
|
self.server.theme_name,
|
|
self.server.system_language,
|
|
self.server.max_like_count,
|
|
self.server.signing_priv_key_pem,
|
|
self.server.cw_lists,
|
|
self.server.lists_enabled,
|
|
timezone,
|
|
self.server.bold_reading,
|
|
self.server.dogwhistles,
|
|
self.server.min_images_for_accounts,
|
|
self.server.debug,
|
|
self.server.buy_sites,
|
|
self.server.auto_cw_cache)
|
|
if msg:
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/html', msglen, cookie, calling_domain,
|
|
False)
|
|
write2(self, msg)
|
|
self.server.getreq_busy = False
|
|
return
|
|
else:
|
|
hashtag = urllib.parse.unquote(hashtag_url.split('/')[-1])
|
|
tags_filename = \
|
|
self.server.base_dir + '/tags/' + hashtag + '.txt'
|
|
if os.path.isfile(tags_filename):
|
|
# redirect to the local hashtag screen
|
|
self.server.getreq_busy = False
|
|
ht_url = \
|
|
get_instance_url(calling_domain,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain) + \
|
|
'/users/' + nickname + '/tags/' + hashtag
|
|
redirect_headers(self, ht_url, cookie, calling_domain)
|
|
else:
|
|
# redirect to the upstream hashtag url
|
|
self.server.getreq_busy = False
|
|
redirect_headers(self, hashtag_url, None, calling_domain)
|
|
return
|
|
|
|
# hashtag search
|
|
if self.path.startswith('/tags/') or \
|
|
(authorized and '/tags/' in self.path):
|
|
if self.path.startswith('/tags/rss2/'):
|
|
hashtag_search_rss2(self, calling_domain,
|
|
self.path, cookie,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.port,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time)
|
|
self.server.getreq_busy = False
|
|
return
|
|
if not html_getreq:
|
|
hashtag_search_json2(self, calling_domain, referer_domain,
|
|
self.path, cookie,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.port,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
MAX_POSTS_IN_FEED)
|
|
self.server.getreq_busy = False
|
|
return
|
|
hashtag_search2(self, calling_domain,
|
|
self.path, cookie,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.port,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
curr_session,
|
|
MAX_POSTS_IN_HASHTAG_FEED)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# hashtag map kml
|
|
if self.path.startswith('/tagmaps/') or \
|
|
(authorized and '/tagmaps/' in self.path):
|
|
map_str = \
|
|
map_format_from_tagmaps_path(self.server.base_dir, self.path,
|
|
self.server.map_format,
|
|
self.server.domain)
|
|
if map_str:
|
|
msg = map_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
if self.server.map_format == 'gpx':
|
|
header_type = \
|
|
'application/gpx+xml; charset=utf-8'
|
|
else:
|
|
header_type = \
|
|
'application/vnd.google-earth.kml+xml; charset=utf-8'
|
|
set_headers(self, header_type, msglen,
|
|
None, calling_domain, True)
|
|
write2(self, msg)
|
|
self.server.getreq_busy = False
|
|
return
|
|
http_404(self, 136)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'hashtag search done',
|
|
self.server.debug)
|
|
|
|
# show or hide buttons in the web interface
|
|
if html_getreq and users_in_path and \
|
|
self.path.endswith('/minimal') and \
|
|
authorized:
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
not_min = not is_minimal(self.server.base_dir,
|
|
self.server.domain, nickname)
|
|
set_minimal(self.server.base_dir,
|
|
self.server.domain, nickname, not_min)
|
|
self.path = get_default_path(self.server.media_instance,
|
|
self.server.blogs_instance,
|
|
nickname)
|
|
|
|
# search for a fediverse address, shared item or emoji
|
|
# from the web interface by selecting search icon
|
|
if html_getreq and users_in_path:
|
|
if self.path.endswith('/search') or \
|
|
'/search?' in self.path:
|
|
if '?' in self.path:
|
|
self.path = self.path.split('?')[0]
|
|
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
|
|
access_keys = self.server.access_keys
|
|
if self.server.key_shortcuts.get(nickname):
|
|
access_keys = self.server.key_shortcuts[nickname]
|
|
|
|
# show the search screen
|
|
msg = html_search(self.server.translate,
|
|
self.server.base_dir, self.path,
|
|
self.server.domain,
|
|
self.server.default_timeline,
|
|
self.server.theme_name,
|
|
self.server.text_mode_banner,
|
|
access_keys)
|
|
if msg:
|
|
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, self.server.fitness,
|
|
'_GET', 'search screen shown',
|
|
self.server.debug)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# show a hashtag category from the search screen
|
|
if html_getreq and '/category/' in self.path:
|
|
msg = html_search_hashtag_category(self.server.translate,
|
|
self.server.base_dir, self.path,
|
|
self.server.domain,
|
|
self.server.theme_name)
|
|
if msg:
|
|
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, self.server.fitness,
|
|
'_GET', 'hashtag category screen shown',
|
|
self.server.debug)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'search screen shown done',
|
|
self.server.debug)
|
|
|
|
# Show the html calendar for a user
|
|
if html_getreq and users_in_path:
|
|
if '/calendar' in self.path:
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
|
|
access_keys = self.server.access_keys
|
|
if self.server.key_shortcuts.get(nickname):
|
|
access_keys = self.server.key_shortcuts[nickname]
|
|
|
|
# show the calendar screen
|
|
msg = html_calendar(self.server.person_cache,
|
|
self.server.translate,
|
|
self.server.base_dir, self.path,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.text_mode_banner,
|
|
access_keys,
|
|
False, self.server.system_language,
|
|
self.server.default_timeline,
|
|
self.server.theme_name)
|
|
if msg:
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
if 'ical=true' in self.path:
|
|
set_headers(self, 'text/calendar',
|
|
msglen, cookie, calling_domain,
|
|
False)
|
|
else:
|
|
set_headers(self, 'text/html',
|
|
msglen, cookie, calling_domain,
|
|
False)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'calendar shown',
|
|
self.server.debug)
|
|
else:
|
|
http_404(self, 137)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# Show the icalendar for a user
|
|
if icalendar_getreq and users_in_path:
|
|
if '/calendar' in self.path:
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
|
|
access_keys = self.server.access_keys
|
|
if self.server.key_shortcuts.get(nickname):
|
|
access_keys = self.server.key_shortcuts[nickname]
|
|
|
|
# show the calendar screen
|
|
msg = html_calendar(self.server.person_cache,
|
|
self.server.translate,
|
|
self.server.base_dir, self.path,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.text_mode_banner,
|
|
access_keys,
|
|
True,
|
|
self.server.system_language,
|
|
self.server.default_timeline,
|
|
self.server.theme_name)
|
|
if msg:
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/calendar',
|
|
msglen, cookie, calling_domain,
|
|
False)
|
|
write2(self, msg)
|
|
else:
|
|
http_404(self, 138)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'icalendar shown',
|
|
self.server.debug)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'calendar shown done',
|
|
self.server.debug)
|
|
|
|
# Show confirmation for deleting a calendar event
|
|
if html_getreq and users_in_path:
|
|
if '/eventdelete' in self.path and \
|
|
'?time=' in self.path and \
|
|
'?eventid=' in self.path:
|
|
if _confirm_delete_event(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
cookie,
|
|
self.server.translate,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'calendar delete shown done',
|
|
self.server.debug)
|
|
|
|
# search for emoji by name
|
|
if html_getreq and users_in_path:
|
|
if self.path.endswith('/searchemoji'):
|
|
# show the search screen
|
|
msg = \
|
|
html_search_emoji_text_entry(self.server.translate,
|
|
self.server.base_dir,
|
|
self.path).encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/html', msglen,
|
|
cookie, calling_domain, False)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'emoji search shown',
|
|
self.server.debug)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'emoji search shown done',
|
|
self.server.debug)
|
|
|
|
repeat_private = False
|
|
if html_getreq and '?repeatprivate=' in self.path:
|
|
repeat_private = True
|
|
self.path = self.path.replace('?repeatprivate=', '?repeat=')
|
|
# announce/repeat button was pressed
|
|
if authorized and html_getreq and '?repeat=' in self.path:
|
|
announce_button(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
cookie, proxy_type,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.port,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
repeat_private,
|
|
self.server.debug,
|
|
curr_session,
|
|
self.server.sites_unavailable)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show announce done',
|
|
self.server.debug)
|
|
|
|
if authorized and html_getreq and '?unrepeatprivate=' in self.path:
|
|
self.path = self.path.replace('?unrepeatprivate=', '?unrepeat=')
|
|
|
|
# undo an announce/repeat from the web interface
|
|
if authorized and html_getreq and '?unrepeat=' in self.path:
|
|
announce_button_undo(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
cookie, proxy_type,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
self.server.debug,
|
|
self.server.recent_posts_cache,
|
|
curr_session)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'unannounce done',
|
|
self.server.debug)
|
|
|
|
# send a newswire moderation vote from the web interface
|
|
if authorized and '/newswirevote=' in self.path and \
|
|
self.path.startswith('/users/'):
|
|
_newswire_vote(self, calling_domain, self.path,
|
|
cookie,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
self.server.newswire)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# send a newswire moderation unvote from the web interface
|
|
if authorized and '/newswireunvote=' in self.path and \
|
|
self.path.startswith('/users/'):
|
|
_newswire_unvote(self, calling_domain, self.path,
|
|
cookie,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
self.server.debug,
|
|
self.server.newswire)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# send a follow request approval from the web interface
|
|
if authorized and '/followapprove=' in self.path and \
|
|
self.path.startswith('/users/'):
|
|
follow_approve_button(self, calling_domain, self.path,
|
|
cookie,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.port,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
self.server.debug,
|
|
curr_session)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'follow approve done',
|
|
self.server.debug)
|
|
|
|
# deny a follow request from the web interface
|
|
if authorized and '/followdeny=' in self.path and \
|
|
self.path.startswith('/users/'):
|
|
follow_deny_button(self, calling_domain, self.path,
|
|
cookie,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.port,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
self.server.debug)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'follow deny done',
|
|
self.server.debug)
|
|
|
|
# like from the web interface icon
|
|
if authorized and html_getreq and '?like=' in self.path:
|
|
like_button(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie,
|
|
self.server.debug,
|
|
curr_session)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'like button done',
|
|
self.server.debug)
|
|
|
|
# undo a like from the web interface icon
|
|
if authorized and html_getreq and '?unlike=' in self.path:
|
|
like_button_undo(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie, self.server.debug,
|
|
curr_session)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'unlike button done',
|
|
self.server.debug)
|
|
|
|
# emoji reaction from the web interface icon
|
|
if authorized and html_getreq and \
|
|
'?react=' in self.path and \
|
|
'?actor=' in self.path:
|
|
reaction_button(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie,
|
|
self.server.debug,
|
|
curr_session)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'emoji reaction button done',
|
|
self.server.debug)
|
|
|
|
# undo an emoji reaction from the web interface icon
|
|
if authorized and html_getreq and \
|
|
'?unreact=' in self.path and \
|
|
'?actor=' in self.path:
|
|
reaction_button_undo(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie, self.server.debug,
|
|
curr_session)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'unreaction button done',
|
|
self.server.debug)
|
|
|
|
# bookmark from the web interface icon
|
|
if authorized and html_getreq and '?bookmark=' in self.path:
|
|
bookmark_button(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.port,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie, self.server.debug,
|
|
curr_session)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'bookmark shown done',
|
|
self.server.debug)
|
|
|
|
# emoji recation from the web interface bottom icon
|
|
if authorized and html_getreq and '?selreact=' in self.path:
|
|
_reaction_picker2(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
curr_session)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'bookmark shown done',
|
|
self.server.debug)
|
|
|
|
# undo a bookmark from the web interface icon
|
|
if authorized and html_getreq and '?unbookmark=' in self.path:
|
|
bookmark_button_undo(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.port,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
proxy_type, cookie,
|
|
self.server.debug,
|
|
curr_session)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'unbookmark shown done',
|
|
self.server.debug)
|
|
|
|
# delete button is pressed on a post
|
|
if authorized and html_getreq and '?delete=' in self.path:
|
|
delete_button(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
proxy_type, cookie,
|
|
self.server.debug,
|
|
curr_session)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'delete shown done',
|
|
self.server.debug)
|
|
|
|
# The mute button is pressed
|
|
if authorized and html_getreq and '?mute=' in self.path:
|
|
mute_button(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.port,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
curr_session)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'post muted done',
|
|
self.server.debug)
|
|
|
|
# unmute a post from the web interface icon
|
|
if authorized and html_getreq and '?unmute=' in self.path:
|
|
mute_button_undo(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.port,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
curr_session)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'unmute activated done',
|
|
self.server.debug)
|
|
|
|
# reply from the web interface icon
|
|
in_reply_to_url = None
|
|
reply_to_list = []
|
|
reply_page_number = 1
|
|
reply_category = ''
|
|
share_description = None
|
|
conversation_id = None
|
|
if html_getreq:
|
|
if '?conversationId=' in self.path:
|
|
conversation_id = self.path.split('?conversationId=')[1]
|
|
if '?' in conversation_id:
|
|
conversation_id = conversation_id.split('?')[0]
|
|
# public reply
|
|
if '?replyto=' in self.path:
|
|
in_reply_to_url = self.path.split('?replyto=')[1]
|
|
if '?' in in_reply_to_url:
|
|
mentions_list = in_reply_to_url.split('?')
|
|
for ment in mentions_list:
|
|
if ment.startswith('mention='):
|
|
reply_handle = ment.replace('mention=', '')
|
|
if reply_handle not in reply_to_list:
|
|
reply_to_list.append(reply_handle)
|
|
if ment.startswith('page='):
|
|
reply_page_str = ment.replace('page=', '')
|
|
if len(reply_page_str) > 5:
|
|
reply_page_str = "1"
|
|
if reply_page_str.isdigit():
|
|
reply_page_number = int(reply_page_str)
|
|
in_reply_to_url = mentions_list[0]
|
|
if not self.server.public_replies_unlisted:
|
|
self.path = self.path.split('?replyto=')[0] + '/newpost'
|
|
else:
|
|
self.path = \
|
|
self.path.split('?replyto=')[0] + '/newunlisted'
|
|
if self.server.debug:
|
|
print('DEBUG: replyto path ' + self.path)
|
|
|
|
# unlisted reply
|
|
if '?replyunlisted=' in self.path:
|
|
in_reply_to_url = self.path.split('?replyunlisted=')[1]
|
|
if '?' in in_reply_to_url:
|
|
mentions_list = in_reply_to_url.split('?')
|
|
for ment in mentions_list:
|
|
if ment.startswith('mention='):
|
|
reply_handle = ment.replace('mention=', '')
|
|
if reply_handle not in reply_to_list:
|
|
reply_to_list.append(reply_handle)
|
|
if ment.startswith('page='):
|
|
reply_page_str = ment.replace('page=', '')
|
|
if len(reply_page_str) > 5:
|
|
reply_page_str = "1"
|
|
if reply_page_str.isdigit():
|
|
reply_page_number = int(reply_page_str)
|
|
in_reply_to_url = mentions_list[0]
|
|
self.path = \
|
|
self.path.split('?replyunlisted=')[0] + '/newunlisted'
|
|
if self.server.debug:
|
|
print('DEBUG: replyunlisted path ' + self.path)
|
|
|
|
# reply to followers
|
|
if '?replyfollowers=' in self.path:
|
|
in_reply_to_url = self.path.split('?replyfollowers=')[1]
|
|
if '?' in in_reply_to_url:
|
|
mentions_list = in_reply_to_url.split('?')
|
|
for ment in mentions_list:
|
|
if ment.startswith('mention='):
|
|
reply_handle = ment.replace('mention=', '')
|
|
ment2 = ment.replace('mention=', '')
|
|
if ment2 not in reply_to_list:
|
|
reply_to_list.append(reply_handle)
|
|
if ment.startswith('page='):
|
|
reply_page_str = ment.replace('page=', '')
|
|
if len(reply_page_str) > 5:
|
|
reply_page_str = "1"
|
|
if reply_page_str.isdigit():
|
|
reply_page_number = int(reply_page_str)
|
|
in_reply_to_url = mentions_list[0]
|
|
self.path = self.path.split('?replyfollowers=')[0] + \
|
|
'/newfollowers'
|
|
if self.server.debug:
|
|
print('DEBUG: replyfollowers path ' + self.path)
|
|
|
|
# replying as a direct message,
|
|
# for moderation posts or the dm timeline
|
|
reply_is_chat = False
|
|
if '?replydm=' in self.path or '?replychat=' in self.path:
|
|
reply_type = 'replydm'
|
|
if '?replychat=' in self.path:
|
|
reply_type = 'replychat'
|
|
reply_is_chat = True
|
|
in_reply_to_url = self.path.split('?' + reply_type + '=')[1]
|
|
in_reply_to_url = urllib.parse.unquote_plus(in_reply_to_url)
|
|
if '?' in in_reply_to_url:
|
|
# multiple parameters
|
|
mentions_list = in_reply_to_url.split('?')
|
|
for ment in mentions_list:
|
|
if ment.startswith('mention='):
|
|
reply_handle = ment.replace('mention=', '')
|
|
in_reply_to_url = reply_handle
|
|
if reply_handle not in reply_to_list:
|
|
reply_to_list.append(reply_handle)
|
|
elif ment.startswith('page='):
|
|
reply_page_str = ment.replace('page=', '')
|
|
if len(reply_page_str) > 5:
|
|
reply_page_str = "1"
|
|
if reply_page_str.isdigit():
|
|
reply_page_number = int(reply_page_str)
|
|
elif ment.startswith('category='):
|
|
reply_category = ment.replace('category=', '')
|
|
elif ment.startswith('sharedesc:'):
|
|
# get the title for the shared item
|
|
share_description = \
|
|
ment.replace('sharedesc:', '').strip()
|
|
share_description = \
|
|
share_description.replace('_', ' ')
|
|
in_reply_to_url = mentions_list[0]
|
|
else:
|
|
# single parameter
|
|
if in_reply_to_url.startswith('mention='):
|
|
reply_handle = in_reply_to_url.replace('mention=', '')
|
|
in_reply_to_url = reply_handle
|
|
if reply_handle not in reply_to_list:
|
|
reply_to_list.append(reply_handle)
|
|
elif in_reply_to_url.startswith('sharedesc:'):
|
|
# get the title for the shared item
|
|
share_description = \
|
|
in_reply_to_url.replace('sharedesc:', '').strip()
|
|
share_description = \
|
|
share_description.replace('_', ' ')
|
|
|
|
self.path = \
|
|
self.path.split('?' + reply_type + '=')[0] + '/newdm'
|
|
if self.server.debug:
|
|
print('DEBUG: ' + reply_type + ' path ' + self.path)
|
|
|
|
# Edit a blog post
|
|
if authorized and \
|
|
'/users/' in self.path and \
|
|
'?editblogpost=' in self.path and \
|
|
';actor=' in self.path:
|
|
message_id = self.path.split('?editblogpost=')[1]
|
|
if ';' in message_id:
|
|
message_id = message_id.split(';')[0]
|
|
actor = self.path.split(';actor=')[1]
|
|
if ';' in actor:
|
|
actor = actor.split(';')[0]
|
|
nickname = get_nickname_from_actor(self.path.split('?')[0])
|
|
if not nickname:
|
|
http_404(self, 139)
|
|
self.server.getreq_busy = False
|
|
return
|
|
if nickname == actor:
|
|
post_url = \
|
|
local_actor_url(self.server.http_prefix, nickname,
|
|
self.server.domain_full) + \
|
|
'/statuses/' + message_id
|
|
msg = html_edit_blog(self.server.media_instance,
|
|
self.server.translate,
|
|
self.server.base_dir,
|
|
self.path, reply_page_number,
|
|
nickname, self.server.domain,
|
|
post_url,
|
|
self.server.system_language)
|
|
if msg:
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/html', msglen,
|
|
cookie, calling_domain, False)
|
|
write2(self, msg)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# Edit a post
|
|
edit_post_params = {}
|
|
if authorized and \
|
|
'/users/' in self.path and \
|
|
'?postedit=' in self.path and \
|
|
';scope=' in self.path and \
|
|
';actor=' in self.path:
|
|
post_scope = self.path.split(';scope=')[1]
|
|
if ';' in post_scope:
|
|
post_scope = post_scope.split(';')[0]
|
|
edit_post_params['scope'] = post_scope
|
|
message_id = self.path.split('?postedit=')[1]
|
|
if ';' in message_id:
|
|
message_id = message_id.split(';')[0]
|
|
if ';replyTo=' in self.path:
|
|
reply_to = self.path.split(';replyTo=')[1]
|
|
if ';' in reply_to:
|
|
reply_to = message_id.split(';')[0]
|
|
edit_post_params['replyTo'] = reply_to
|
|
actor = self.path.split(';actor=')[1]
|
|
if ';' in actor:
|
|
actor = actor.split(';')[0]
|
|
edit_post_params['actor'] = actor
|
|
nickname = get_nickname_from_actor(self.path.split('?')[0])
|
|
edit_post_params['nickname'] = nickname
|
|
if not nickname:
|
|
http_404(self, 140)
|
|
self.server.getreq_busy = False
|
|
return
|
|
if nickname != actor:
|
|
http_404(self, 141)
|
|
self.server.getreq_busy = False
|
|
return
|
|
post_url = \
|
|
local_actor_url(self.server.http_prefix, nickname,
|
|
self.server.domain_full) + \
|
|
'/statuses/' + message_id
|
|
edit_post_params['post_url'] = post_url
|
|
# use the new post functions, but using edit_post_params
|
|
new_post_scope = post_scope
|
|
if post_scope == 'public':
|
|
new_post_scope = 'post'
|
|
self.path = '/users/' + nickname + '/new' + new_post_scope
|
|
|
|
# list of known crawlers accessing nodeinfo or masto API
|
|
if _show_known_crawlers(self, calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.known_crawlers):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# edit profile in web interface
|
|
if _edit_profile2(self, calling_domain, self.path,
|
|
self.server.translate,
|
|
self.server.base_dir,
|
|
self.server.domain,
|
|
self.server.port,
|
|
cookie):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# edit links from the left column of the timeline in web interface
|
|
if _edit_links2(self, calling_domain, self.path,
|
|
self.server.translate,
|
|
self.server.base_dir,
|
|
self.server.domain,
|
|
cookie,
|
|
self.server.theme_name):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# edit newswire from the right column of the timeline
|
|
if _edit_newswire2(self, calling_domain, self.path,
|
|
self.server.translate,
|
|
self.server.base_dir,
|
|
self.server.domain, cookie):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# edit news post
|
|
if _edit_news_post2(self, calling_domain, self.path,
|
|
self.server.translate,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
cookie):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
if _show_new_post(self, edit_post_params,
|
|
calling_domain, self.path,
|
|
self.server.media_instance,
|
|
self.server.translate,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
in_reply_to_url, reply_to_list,
|
|
reply_is_chat,
|
|
share_description, reply_page_number,
|
|
reply_category,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
getreq_start_time,
|
|
cookie, no_drop_down, conversation_id,
|
|
curr_session):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'new post done',
|
|
self.server.debug)
|
|
|
|
# get an individual post from the path /@nickname/statusnumber
|
|
if _show_individual_at_post(self, ssml_getreq, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie, self.server.debug,
|
|
curr_session):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# show the likers of a post
|
|
if _show_likers_of_post(self, authorized,
|
|
calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
curr_session):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# show the announcers/repeaters of a post
|
|
if _show_announcers_of_post(self, authorized,
|
|
calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
curr_session):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'individual post done',
|
|
self.server.debug)
|
|
|
|
# get replies to a post /users/nickname/statuses/number/replies
|
|
if self.path.endswith('/replies') or '/replies?page=' in self.path:
|
|
if _show_replies_to_post(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
proxy_type, cookie,
|
|
self.server.debug,
|
|
curr_session):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'post replies done',
|
|
self.server.debug)
|
|
|
|
# roles on profile screen
|
|
if self.path.endswith('/roles') and users_in_path:
|
|
if _show_roles(self, calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie, self.server.debug,
|
|
curr_session):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show roles done',
|
|
self.server.debug)
|
|
|
|
# show skills on the profile page
|
|
if self.path.endswith('/skills') and users_in_path:
|
|
if _show_skills(self, calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie, self.server.debug,
|
|
curr_session):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show skills done',
|
|
self.server.debug)
|
|
|
|
if '?notifypost=' in self.path and users_in_path and authorized:
|
|
if _show_notify_post(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie, self.server.debug,
|
|
curr_session):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# get an individual post from the path
|
|
# /users/nickname/statuses/number
|
|
if '/statuses/' in self.path and users_in_path:
|
|
if _show_individual_post(self, ssml_getreq, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.domain_full,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie, self.server.debug,
|
|
curr_session):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show status done',
|
|
self.server.debug)
|
|
|
|
# get the inbox timeline for a given person
|
|
if self.path.endswith('/inbox') or '/inbox?page=' in self.path:
|
|
if _show_inbox(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
self.server.recent_posts_cache,
|
|
curr_session,
|
|
self.server.default_timeline,
|
|
self.server.max_recent_posts,
|
|
self.server.translate,
|
|
self.server.cached_webfingers,
|
|
self.server.person_cache,
|
|
self.server.allow_deletion,
|
|
self.server.project_version,
|
|
self.server.yt_replace_domain,
|
|
self.server.twitter_replacement_domain,
|
|
ua_str):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show inbox done',
|
|
self.server.debug)
|
|
|
|
# get the direct messages timeline for a given person
|
|
if self.path.endswith('/dm') or '/dm?page=' in self.path:
|
|
if show_dms(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
curr_session, ua_str, MAX_POSTS_IN_FEED):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show dms done',
|
|
self.server.debug)
|
|
|
|
# get the replies timeline for a given person
|
|
if self.path.endswith('/tlreplies') or '/tlreplies?page=' in self.path:
|
|
if show_replies(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
curr_session, ua_str, MAX_POSTS_IN_FEED):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show replies 2 done',
|
|
self.server.debug)
|
|
|
|
# get the media timeline for a given person
|
|
if self.path.endswith('/tlmedia') or '/tlmedia?page=' in self.path:
|
|
if show_media_timeline(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
curr_session, ua_str,
|
|
MAX_POSTS_IN_MEDIA_FEED):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show media 2 done',
|
|
self.server.debug)
|
|
|
|
# get the blogs for a given person
|
|
if self.path.endswith('/tlblogs') or '/tlblogs?page=' in self.path:
|
|
if show_blogs_timeline(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
curr_session, ua_str,
|
|
MAX_POSTS_IN_BLOGS_FEED):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show blogs 2 done',
|
|
self.server.debug)
|
|
|
|
# get the news for a given person
|
|
if self.path.endswith('/tlnews') or '/tlnews?page=' in self.path:
|
|
if show_news_timeline(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
curr_session, ua_str,
|
|
MAX_POSTS_IN_NEWS_FEED):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# get features (local blogs) for a given person
|
|
if self.path.endswith('/tlfeatures') or \
|
|
'/tlfeatures?page=' in self.path:
|
|
if show_features_timeline(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
curr_session, ua_str,
|
|
MAX_POSTS_IN_NEWS_FEED):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show news 2 done',
|
|
self.server.debug)
|
|
|
|
# get the shared items timeline for a given person
|
|
if self.path.endswith('/tlshares') or '/tlshares?page=' in self.path:
|
|
if show_shares_timeline(self, authorized,
|
|
calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
curr_session, ua_str,
|
|
MAX_POSTS_IN_FEED):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# get the wanted items timeline for a given person
|
|
if self.path.endswith('/tlwanted') or '/tlwanted?page=' in self.path:
|
|
if show_wanted_timeline(self, authorized,
|
|
calling_domain, self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
curr_session, ua_str,
|
|
MAX_POSTS_IN_FEED):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show shares 2 done',
|
|
self.server.debug)
|
|
|
|
# block a domain from html_account_info
|
|
if authorized and users_in_path and \
|
|
'/accountinfo?blockdomain=' in self.path and \
|
|
'?handle=' in self.path:
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
if not is_moderator(self.server.base_dir, nickname):
|
|
http_400(self)
|
|
self.server.getreq_busy = False
|
|
return
|
|
block_domain = self.path.split('/accountinfo?blockdomain=')[1]
|
|
search_handle = block_domain.split('?handle=')[1]
|
|
search_handle = urllib.parse.unquote_plus(search_handle)
|
|
block_domain = block_domain.split('?handle=')[0]
|
|
block_domain = urllib.parse.unquote_plus(block_domain.strip())
|
|
if '?' in block_domain:
|
|
block_domain = block_domain.split('?')[0]
|
|
add_global_block(self.server.base_dir, '*', block_domain, None)
|
|
self.server.blocked_cache_last_updated = \
|
|
update_blocked_cache(self.server.base_dir,
|
|
self.server.blocked_cache,
|
|
self.server.blocked_cache_last_updated, 0)
|
|
msg = \
|
|
html_account_info(self.server.translate,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
nickname,
|
|
self.server.domain,
|
|
search_handle,
|
|
self.server.debug,
|
|
self.server.system_language,
|
|
self.server.signing_priv_key_pem,
|
|
None,
|
|
self.server.block_federated)
|
|
if msg:
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/html',
|
|
msglen, calling_domain)
|
|
write2(self, msg)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# unblock a domain from html_account_info
|
|
if authorized and users_in_path and \
|
|
'/accountinfo?unblockdomain=' in self.path and \
|
|
'?handle=' in self.path:
|
|
nickname = self.path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
if not is_moderator(self.server.base_dir, nickname):
|
|
http_400(self)
|
|
self.server.getreq_busy = False
|
|
return
|
|
block_domain = self.path.split('/accountinfo?unblockdomain=')[1]
|
|
search_handle = block_domain.split('?handle=')[1]
|
|
search_handle = urllib.parse.unquote_plus(search_handle)
|
|
block_domain = block_domain.split('?handle=')[0]
|
|
block_domain = urllib.parse.unquote_plus(block_domain.strip())
|
|
remove_global_block(self.server.base_dir, '*', block_domain)
|
|
self.server.blocked_cache_last_updated = \
|
|
update_blocked_cache(self.server.base_dir,
|
|
self.server.blocked_cache,
|
|
self.server.blocked_cache_last_updated, 0)
|
|
msg = \
|
|
html_account_info(self.server.translate,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
nickname,
|
|
self.server.domain,
|
|
search_handle,
|
|
self.server.debug,
|
|
self.server.system_language,
|
|
self.server.signing_priv_key_pem,
|
|
None,
|
|
self.server.block_federated)
|
|
if msg:
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/html',
|
|
msglen, calling_domain)
|
|
write2(self, msg)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
# get the bookmarks timeline for a given person
|
|
if self.path.endswith('/tlbookmarks') or \
|
|
'/tlbookmarks?page=' in self.path or \
|
|
self.path.endswith('/bookmarks') or \
|
|
'/bookmarks?page=' in self.path:
|
|
if show_bookmarks_timeline(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
curr_session, ua_str,
|
|
MAX_POSTS_IN_FEED):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show bookmarks 2 done',
|
|
self.server.debug)
|
|
|
|
# outbox timeline
|
|
if self.path.endswith('/outbox') or \
|
|
'/outbox?page=' in self.path:
|
|
if show_outbox_timeline(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
curr_session, ua_str,
|
|
proxy_type, MAX_POSTS_IN_FEED):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show outbox done',
|
|
self.server.debug)
|
|
|
|
# get the moderation feed for a moderator
|
|
if self.path.endswith('/moderation') or \
|
|
'/moderation?' in self.path:
|
|
if show_mod_timeline(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
cookie, self.server.debug,
|
|
curr_session, ua_str,
|
|
MAX_POSTS_IN_FEED):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show moderation done',
|
|
self.server.debug)
|
|
|
|
if show_shares_feed(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie, self.server.debug, 'shares',
|
|
curr_session, SHARES_PER_PAGE):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show profile 2 done',
|
|
self.server.debug)
|
|
|
|
if show_following_feed(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie, self.server.debug,
|
|
curr_session, FOLLOWS_PER_PAGE):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show profile 3 done',
|
|
self.server.debug)
|
|
|
|
if show_moved_feed(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie, self.server.debug,
|
|
curr_session, FOLLOWS_PER_PAGE):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show moved 4 done',
|
|
self.server.debug)
|
|
|
|
if show_inactive_feed(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie, self.server.debug,
|
|
curr_session,
|
|
self.server.dormant_months,
|
|
self.server.sites_unavailable,
|
|
FOLLOWS_PER_PAGE):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show inactive 5 done',
|
|
self.server.debug)
|
|
|
|
if show_followers_feed(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.port,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie, self.server.debug,
|
|
curr_session, FOLLOWS_PER_PAGE):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show profile 5 done',
|
|
self.server.debug)
|
|
|
|
# look up a person
|
|
if _show_person_profile(self, authorized,
|
|
calling_domain, referer_domain,
|
|
self.path,
|
|
self.server.base_dir,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
getreq_start_time,
|
|
proxy_type,
|
|
cookie, self.server.debug,
|
|
curr_session):
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'show profile posts done',
|
|
self.server.debug)
|
|
|
|
# check that a json file was requested
|
|
if not self.path.endswith('.json'):
|
|
if self.server.debug:
|
|
print('DEBUG: GET Not json: ' + self.path +
|
|
' ' + self.server.base_dir)
|
|
http_404(self, 142)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
if not secure_mode(curr_session,
|
|
proxy_type, False,
|
|
self.server, self.headers,
|
|
self.path):
|
|
if self.server.debug:
|
|
print('WARN: Unauthorized GET')
|
|
http_404(self, 143)
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'authorized fetch',
|
|
self.server.debug)
|
|
|
|
# check that the file exists
|
|
filename = self.server.base_dir + self.path
|
|
if os.path.isfile(filename):
|
|
content = None
|
|
try:
|
|
with open(filename, 'r', encoding='utf-8') as rfile:
|
|
content = rfile.read()
|
|
except OSError:
|
|
print('EX: unable to read file ' + filename)
|
|
if content:
|
|
try:
|
|
content_json = json.loads(content)
|
|
except json.decoder.JSONDecodeError as ex:
|
|
http_400(self)
|
|
print('EX: json decode error ' + str(ex) +
|
|
' from GET content_json ' +
|
|
str(content))
|
|
self.server.getreq_busy = False
|
|
return
|
|
|
|
msg_str = json.dumps(content_json, ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
accept_str = self.headers['Accept']
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'arbitrary json',
|
|
self.server.debug)
|
|
else:
|
|
if self.server.debug:
|
|
print('DEBUG: GET Unknown file')
|
|
http_404(self, 144)
|
|
self.server.getreq_busy = False
|
|
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', 'end benchmarks',
|
|
self.server.debug)
|
|
|
|
|
|
def _permitted_crawler_path(self, path: str) -> bool:
|
|
"""Is the given path permitted to be crawled by a search engine?
|
|
this should only allow through basic information, such as nodeinfo
|
|
"""
|
|
if path == '/' or path == '/about' or path == '/login' or \
|
|
path.startswith('/blog/'):
|
|
return True
|
|
return False
|
|
|
|
|
|
def _get_referer_domain(self, ua_str: str) -> str:
|
|
"""Returns the referer domain
|
|
Which domain is the GET request coming from?
|
|
"""
|
|
referer_domain = None
|
|
if self.headers.get('referer'):
|
|
referer_domain = \
|
|
user_agent_domain(self.headers['referer'], self.server.debug)
|
|
elif self.headers.get('Referer'):
|
|
referer_domain = \
|
|
user_agent_domain(self.headers['Referer'], self.server.debug)
|
|
elif self.headers.get('Signature'):
|
|
if 'keyId="' in self.headers['Signature']:
|
|
referer_domain = self.headers['Signature'].split('keyId="')[1]
|
|
if '/' in referer_domain:
|
|
referer_domain = referer_domain.split('/')[0]
|
|
elif '#' in referer_domain:
|
|
referer_domain = referer_domain.split('#')[0]
|
|
elif '"' in referer_domain:
|
|
referer_domain = referer_domain.split('"')[0]
|
|
elif ua_str:
|
|
referer_domain = user_agent_domain(ua_str, self.server.debug)
|
|
return referer_domain
|
|
|
|
|
|
def _show_vcard(self, base_dir: str, path: str, calling_domain: str,
|
|
referer_domain: str, domain: str) -> bool:
|
|
"""Returns a vcard for the given account
|
|
"""
|
|
if not has_accept(self, calling_domain):
|
|
return False
|
|
if path.endswith('.vcf'):
|
|
path = path.split('.vcf')[0]
|
|
accept_str = 'text/vcard'
|
|
else:
|
|
accept_str = self.headers['Accept']
|
|
if 'text/vcard' not in accept_str and \
|
|
'application/vcard+xml' not in accept_str:
|
|
return False
|
|
if path.startswith('/@'):
|
|
if '/@/' not in path:
|
|
path = path.replace('/@', '/users/', 1)
|
|
if not path.startswith('/users/'):
|
|
http_400(self)
|
|
return True
|
|
nickname = path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
if '?' in nickname:
|
|
nickname = nickname.split('?')[0]
|
|
if self.server.vcard_is_active:
|
|
print('vcard is busy during request from ' + str(referer_domain))
|
|
http_503(self)
|
|
return True
|
|
self.server.vcard_is_active = True
|
|
actor_json = None
|
|
actor_filename = \
|
|
acct_dir(base_dir, nickname, domain) + '.json'
|
|
if os.path.isfile(actor_filename):
|
|
actor_json = load_json(actor_filename)
|
|
if not actor_json:
|
|
print('WARN: vcard actor not found ' + actor_filename)
|
|
http_404(self, 3)
|
|
self.server.vcard_is_active = False
|
|
return True
|
|
if 'application/vcard+xml' in accept_str:
|
|
vcard_str = actor_to_vcard_xml(actor_json, domain)
|
|
header_type = 'application/vcard+xml; charset=utf-8'
|
|
else:
|
|
vcard_str = actor_to_vcard(actor_json, domain)
|
|
header_type = 'text/vcard; charset=utf-8'
|
|
if vcard_str:
|
|
msg = vcard_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, header_type, msglen,
|
|
None, calling_domain, True)
|
|
write2(self, msg)
|
|
print('vcard sent to ' + str(referer_domain))
|
|
self.server.vcard_is_active = False
|
|
return True
|
|
print('WARN: vcard string not returned')
|
|
http_404(self, 4)
|
|
self.server.vcard_is_active = False
|
|
return True
|
|
|
|
|
|
def _security_txt(self, ua_str: str, calling_domain: str,
|
|
referer_domain: str,
|
|
http_prefix: str, calling_site_timeout: int,
|
|
debug: bool) -> bool:
|
|
"""See https://www.rfc-editor.org/rfc/rfc9116
|
|
"""
|
|
if not self.path.startswith('/security.txt'):
|
|
return False
|
|
if referer_domain == self.server.domain_full:
|
|
print('security.txt request from self')
|
|
http_400(self)
|
|
return True
|
|
if self.server.security_txt_is_active:
|
|
if not referer_domain:
|
|
print('security.txt is busy ' +
|
|
'during request without referer domain')
|
|
else:
|
|
print('security.txt is busy during request from ' +
|
|
referer_domain)
|
|
http_503(self)
|
|
return True
|
|
self.server.security_txt_is_active = True
|
|
# is this a real website making the call ?
|
|
if not debug and not self.server.unit_test and referer_domain:
|
|
# Does calling_domain look like a domain?
|
|
if ' ' in referer_domain or \
|
|
';' in referer_domain or \
|
|
'.' not in referer_domain:
|
|
print('security.txt ' +
|
|
'referer domain does not look like a domain ' +
|
|
referer_domain)
|
|
http_400(self)
|
|
self.server.security_txt_is_active = False
|
|
return True
|
|
if not self.server.allow_local_network_access:
|
|
if local_network_host(referer_domain):
|
|
print('security.txt referer domain is from the ' +
|
|
'local network ' + referer_domain)
|
|
http_400(self)
|
|
self.server.security_txt_is_active = False
|
|
return True
|
|
|
|
if not referer_is_active(http_prefix,
|
|
referer_domain, ua_str,
|
|
calling_site_timeout,
|
|
self.server.sites_unavailable):
|
|
print('security.txt referer url is not active ' +
|
|
referer_domain)
|
|
http_400(self)
|
|
self.server.security_txt_is_active = False
|
|
return True
|
|
if self.server.debug:
|
|
print('DEBUG: security.txt ' + self.path)
|
|
|
|
# If we are in broch mode then don't reply
|
|
if not broch_mode_is_active(self.server.base_dir):
|
|
security_txt = \
|
|
'Contact: https://gitlab.com/bashrc2/epicyon/-/issues'
|
|
|
|
msg = security_txt.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/plain; charset=utf-8',
|
|
msglen, None, calling_domain, True)
|
|
write2(self, msg)
|
|
if referer_domain:
|
|
print('security.txt sent to ' + referer_domain)
|
|
else:
|
|
print('security.txt sent to unknown referer')
|
|
self.server.security_txt_is_active = False
|
|
return True
|
|
|
|
|
|
def _show_instance_actor(self, calling_domain: str,
|
|
referer_domain: str, path: str,
|
|
base_dir: str, http_prefix: str,
|
|
domain: str, domain_full: str,
|
|
onion_domain: str, i2p_domain: str,
|
|
getreq_start_time,
|
|
cookie: str, debug: str,
|
|
enable_shared_inbox: bool) -> bool:
|
|
"""Shows the instance actor
|
|
"""
|
|
if debug:
|
|
print('Instance actor requested by ' + calling_domain)
|
|
if request_http(self.headers, debug):
|
|
http_404(self, 88)
|
|
return False
|
|
actor_json = person_lookup(domain, path, base_dir)
|
|
if not actor_json:
|
|
print('ERROR: no instance actor found')
|
|
http_404(self, 89)
|
|
return False
|
|
accept_str = self.headers['Accept']
|
|
actor_domain_url = get_instance_url(calling_domain,
|
|
http_prefix, domain_full,
|
|
onion_domain, i2p_domain)
|
|
actor_url = actor_domain_url + '/users/Actor'
|
|
remove_fields = (
|
|
'icon', 'image', 'tts', 'shares',
|
|
'alsoKnownAs', 'hasOccupation', 'featured',
|
|
'featuredTags', 'discoverable', 'published',
|
|
'devices'
|
|
)
|
|
for rfield in remove_fields:
|
|
if rfield in actor_json:
|
|
del actor_json[rfield]
|
|
actor_json['endpoints'] = {}
|
|
if enable_shared_inbox:
|
|
actor_json['endpoints'] = {
|
|
'sharedInbox': actor_domain_url + '/inbox'
|
|
}
|
|
actor_json['name'] = 'ACTOR'
|
|
actor_json['preferredUsername'] = domain_full
|
|
actor_json['id'] = actor_domain_url + '/actor'
|
|
actor_json['type'] = 'Application'
|
|
actor_json['summary'] = 'Instance Actor'
|
|
actor_json['publicKey']['id'] = actor_domain_url + '/actor#main-key'
|
|
actor_json['publicKey']['owner'] = actor_domain_url + '/actor'
|
|
actor_json['url'] = actor_domain_url + '/actor'
|
|
actor_json['inbox'] = actor_url + '/inbox'
|
|
actor_json['followers'] = actor_url + '/followers'
|
|
actor_json['following'] = actor_url + '/following'
|
|
msg_str = json.dumps(actor_json, ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str, http_prefix,
|
|
domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
if 'application/ld+json' in accept_str:
|
|
set_headers(self, 'application/ld+json', msglen,
|
|
cookie, calling_domain, False)
|
|
elif 'application/jrd+json' in accept_str:
|
|
set_headers(self, 'application/jrd+json', msglen,
|
|
cookie, calling_domain, False)
|
|
else:
|
|
set_headers(self, 'application/activity+json', msglen,
|
|
cookie, calling_domain, False)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET', '_show_instance_actor',
|
|
debug)
|
|
return True
|
|
|
|
|
|
def _browser_config(self, calling_domain: str, referer_domain: str,
|
|
getreq_start_time) -> None:
|
|
"""Used by MS Windows to put an icon on the desktop if you
|
|
link to a website
|
|
"""
|
|
xml_str = \
|
|
'<?xml version="1.0" encoding="utf-8"?>\n' + \
|
|
'<browserconfig>\n' + \
|
|
' <msapplication>\n' + \
|
|
' <tile>\n' + \
|
|
' <square150x150logo src="/logo150.png"/>\n' + \
|
|
' <TileColor>#eeeeee</TileColor>\n' + \
|
|
' </tile>\n' + \
|
|
' </msapplication>\n' + \
|
|
'</browserconfig>'
|
|
|
|
msg_str = json.dumps(xml_str, ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'application/xrd+xml', msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
if self.server.debug:
|
|
print('Sent browserconfig: ' + calling_domain)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_browser_config',
|
|
self.server.debug)
|
|
|
|
|
|
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) -> bool:
|
|
"""get conversation thread from the date link on a post
|
|
"""
|
|
if not path.startswith('/users/'):
|
|
return False
|
|
if '?convthread=' not in path:
|
|
return False
|
|
post_id = path.split('?convthread=')[1].strip()
|
|
post_id = post_id.replace('--', '/')
|
|
if post_id.startswith('/users/'):
|
|
instance_url = get_instance_url(calling_domain,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
post_id = instance_url + post_id
|
|
nickname = path.split('/users/')[1]
|
|
if '?convthread=' in nickname:
|
|
nickname = nickname.split('?convthread=')[0]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
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
|
|
conv_str = \
|
|
html_conversation_view(authorized,
|
|
post_id, self.server.translate,
|
|
base_dir,
|
|
http_prefix,
|
|
nickname,
|
|
domain,
|
|
self.server.project_version,
|
|
self.server.recent_posts_cache,
|
|
self.server.max_recent_posts,
|
|
curr_session,
|
|
self.server.cached_webfingers,
|
|
self.server.person_cache,
|
|
port,
|
|
self.server.yt_replace_domain,
|
|
self.server.twitter_replacement_domain,
|
|
self.server.show_published_date_only,
|
|
self.server.peertube_instances,
|
|
self.server.allow_local_network_access,
|
|
self.server.theme_name,
|
|
self.server.system_language,
|
|
self.server.max_like_count,
|
|
self.server.signing_priv_key_pem,
|
|
self.server.cw_lists,
|
|
self.server.lists_enabled,
|
|
timezone, bold_reading,
|
|
self.server.dogwhistles,
|
|
self.server.access_keys,
|
|
self.server.min_images_for_accounts,
|
|
debug,
|
|
self.server.buy_sites,
|
|
self.server.blocked_cache,
|
|
self.server.block_federated,
|
|
self.server.auto_cw_cache)
|
|
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 '://' + self.server.domain_full + '/' in post_id:
|
|
redirect_headers(self, post_id, cookie, calling_domain)
|
|
else:
|
|
redirect_headers(self, post_id, None, calling_domain)
|
|
self.server.getreq_busy = False
|
|
return True
|
|
|
|
|
|
def _get_newswire_feed(self, calling_domain: str, path: str,
|
|
proxy_type: str, getreq_start_time,
|
|
debug: bool, curr_session) -> None:
|
|
"""Returns the newswire feed
|
|
"""
|
|
curr_session = \
|
|
establish_session("get_newswire_feed",
|
|
curr_session,
|
|
proxy_type,
|
|
self.server)
|
|
if not curr_session:
|
|
http_404(self, 25)
|
|
return
|
|
|
|
msg = get_rs_sfrom_dict(self.server.newswire,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.translate)
|
|
if msg:
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/xml', msglen,
|
|
None, calling_domain, True)
|
|
write2(self, msg)
|
|
if debug:
|
|
print('Sent rss2 newswire feed: ' +
|
|
path + ' ' + calling_domain)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_get_newswire_feed',
|
|
debug)
|
|
return
|
|
if debug:
|
|
print('Failed to get rss2 newswire feed: ' +
|
|
path + ' ' + calling_domain)
|
|
http_404(self, 26)
|
|
|
|
|
|
def _get_rss2feed(self, calling_domain: str, path: str,
|
|
base_dir: str, http_prefix: str,
|
|
domain: str, port: int, proxy_type: str,
|
|
getreq_start_time, debug: bool,
|
|
curr_session) -> None:
|
|
"""Returns an RSS2 feed for the blog
|
|
"""
|
|
nickname = path.split('/blog/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
if not nickname.startswith('rss.'):
|
|
account_dir = acct_dir(self.server.base_dir, nickname, domain)
|
|
if os.path.isdir(account_dir):
|
|
curr_session = \
|
|
establish_session("RSS request",
|
|
curr_session,
|
|
proxy_type,
|
|
self.server)
|
|
if not curr_session:
|
|
return
|
|
|
|
msg = \
|
|
html_blog_page_rss2(base_dir,
|
|
http_prefix,
|
|
self.server.translate,
|
|
nickname,
|
|
domain,
|
|
port,
|
|
MAX_POSTS_IN_RSS_FEED, 1,
|
|
True,
|
|
self.server.system_language)
|
|
if msg is not None:
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/xml', msglen,
|
|
None, calling_domain, True)
|
|
write2(self, msg)
|
|
if debug:
|
|
print('Sent rss2 feed: ' +
|
|
path + ' ' + calling_domain)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_get_rss2feed',
|
|
debug)
|
|
return
|
|
if debug:
|
|
print('Failed to get rss2 feed: ' +
|
|
path + ' ' + calling_domain)
|
|
http_404(self, 22)
|
|
|
|
|
|
def _get_rss2site(self, calling_domain: str, path: str,
|
|
base_dir: str, http_prefix: str,
|
|
domain_full: str, port: int, proxy_type: str,
|
|
translate: {},
|
|
getreq_start_time,
|
|
debug: bool,
|
|
curr_session) -> None:
|
|
"""Returns an RSS2 feed for all blogs on this instance
|
|
"""
|
|
curr_session = \
|
|
establish_session("get_rss2site",
|
|
curr_session,
|
|
proxy_type,
|
|
self.server)
|
|
if not curr_session:
|
|
http_404(self, 23)
|
|
return
|
|
|
|
msg = ''
|
|
for _, dirs, _ in os.walk(base_dir + '/accounts'):
|
|
for acct in dirs:
|
|
if not is_account_dir(acct):
|
|
continue
|
|
nickname = acct.split('@')[0]
|
|
domain = acct.split('@')[1]
|
|
msg += \
|
|
html_blog_page_rss2(base_dir,
|
|
http_prefix,
|
|
self.server.translate,
|
|
nickname,
|
|
domain,
|
|
port,
|
|
MAX_POSTS_IN_RSS_FEED, 1,
|
|
False,
|
|
self.server.system_language)
|
|
break
|
|
if msg:
|
|
msg = rss2header(http_prefix,
|
|
'news', domain_full,
|
|
'Site', translate) + msg + rss2footer()
|
|
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/xml', msglen,
|
|
None, calling_domain, True)
|
|
write2(self, msg)
|
|
if debug:
|
|
print('Sent rss2 feed: ' +
|
|
path + ' ' + calling_domain)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_get_rss2site',
|
|
debug)
|
|
return
|
|
if debug:
|
|
print('Failed to get rss2 feed: ' +
|
|
path + ' ' + calling_domain)
|
|
http_404(self, 24)
|
|
|
|
|
|
def _get_rss3feed(self, calling_domain: str, path: str,
|
|
base_dir: str, http_prefix: str,
|
|
domain: str, port: int, proxy_type: str,
|
|
getreq_start_time,
|
|
debug: bool, system_language: str,
|
|
curr_session) -> None:
|
|
"""Returns an RSS3 feed
|
|
"""
|
|
nickname = path.split('/blog/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
if not nickname.startswith('rss.'):
|
|
account_dir = acct_dir(base_dir, nickname, domain)
|
|
if os.path.isdir(account_dir):
|
|
curr_session = \
|
|
establish_session("get_rss3feed",
|
|
curr_session, proxy_type,
|
|
self.server)
|
|
if not curr_session:
|
|
http_404(self, 29)
|
|
return
|
|
msg = \
|
|
html_blog_page_rss3(base_dir, http_prefix,
|
|
nickname, domain, port,
|
|
MAX_POSTS_IN_RSS_FEED, 1,
|
|
system_language)
|
|
if msg is not None:
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/plain; charset=utf-8',
|
|
msglen, None, calling_domain, True)
|
|
write2(self, msg)
|
|
if self.server.debug:
|
|
print('Sent rss3 feed: ' +
|
|
path + ' ' + calling_domain)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_get_rss3feed', debug)
|
|
return
|
|
if debug:
|
|
print('Failed to get rss3 feed: ' +
|
|
path + ' ' + calling_domain)
|
|
http_404(self, 20)
|
|
|
|
|
|
def _get_following_json(self, base_dir: str, path: str,
|
|
calling_domain: str, referer_domain: str,
|
|
http_prefix: str,
|
|
domain: str, port: int,
|
|
following_items_per_page: int,
|
|
debug: bool, list_name: str = 'following') -> None:
|
|
"""Returns json collection for following.txt
|
|
"""
|
|
following_json = \
|
|
get_following_feed(base_dir, domain, port, path, http_prefix,
|
|
True, following_items_per_page, list_name)
|
|
if not following_json:
|
|
if debug:
|
|
print(list_name + ' json feed not found for ' + path)
|
|
http_404(self, 109)
|
|
return
|
|
msg_str = json.dumps(following_json,
|
|
ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str, http_prefix,
|
|
domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
accept_str = self.headers['Accept']
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
|
|
|
|
def _get_speaker(self, calling_domain: str, referer_domain: str,
|
|
path: str, base_dir: str, domain: str) -> None:
|
|
"""Returns the speaker file used for TTS and
|
|
accessed via c2s
|
|
"""
|
|
nickname = path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
speaker_filename = \
|
|
acct_dir(base_dir, nickname, domain) + '/speaker.json'
|
|
if not os.path.isfile(speaker_filename):
|
|
http_404(self, 18)
|
|
return
|
|
|
|
speaker_json = load_json(speaker_filename)
|
|
msg_str = json.dumps(speaker_json, ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str,
|
|
self.server.http_prefix,
|
|
domain,
|
|
self.server.onion_domain,
|
|
self.server.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)
|
|
|
|
|
|
def _get_featured_collection(self, calling_domain: str,
|
|
referer_domain: str,
|
|
base_dir: str,
|
|
http_prefix: str,
|
|
nickname: str, domain: str,
|
|
domain_full: str,
|
|
system_language: str) -> None:
|
|
"""Returns the featured posts collections in
|
|
actor/collections/featured
|
|
"""
|
|
featured_collection = \
|
|
json_pin_post(base_dir, http_prefix,
|
|
nickname, domain, domain_full, system_language)
|
|
msg_str = json.dumps(featured_collection,
|
|
ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str, http_prefix,
|
|
domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
accept_str = self.headers['Accept']
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
|
|
|
|
def _get_featured_tags_collection(self, calling_domain: str,
|
|
referer_domain: str,
|
|
path: str,
|
|
http_prefix: str,
|
|
domain_full: str,
|
|
domain: str):
|
|
"""Returns the featured tags collections in
|
|
actor/collections/featuredTags
|
|
"""
|
|
post_context = get_individual_post_context()
|
|
featured_tags_collection = {
|
|
'@context': post_context,
|
|
'id': http_prefix + '://' + domain_full + path,
|
|
'orderedItems': [],
|
|
'totalItems': 0,
|
|
'type': 'OrderedCollection'
|
|
}
|
|
msg_str = json.dumps(featured_tags_collection,
|
|
ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str, http_prefix,
|
|
domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
accept_str = self.headers['Accept']
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
|
|
|
|
def _show_blog_page(self, authorized: bool,
|
|
calling_domain: str, path: str,
|
|
base_dir: str, http_prefix: str,
|
|
domain: str, port: int,
|
|
getreq_start_time,
|
|
proxy_type: str, cookie: str,
|
|
translate: {}, debug: str,
|
|
curr_session) -> bool:
|
|
"""Shows a blog page
|
|
"""
|
|
page_number = 1
|
|
nickname = path.split('/blog/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
if '?' in nickname:
|
|
nickname = nickname.split('?')[0]
|
|
if '?page=' in path:
|
|
page_number_str = path.split('?page=')[1]
|
|
if ';' in page_number_str:
|
|
page_number_str = page_number_str.split(';')[0]
|
|
if '?' in page_number_str:
|
|
page_number_str = page_number_str.split('?')[0]
|
|
if '#' in page_number_str:
|
|
page_number_str = page_number_str.split('#')[0]
|
|
if len(page_number_str) > 5:
|
|
page_number_str = "1"
|
|
if page_number_str.isdigit():
|
|
page_number = int(page_number_str)
|
|
if page_number < 1:
|
|
page_number = 1
|
|
elif page_number > 10:
|
|
page_number = 10
|
|
curr_session = \
|
|
establish_session("showBlogPage",
|
|
curr_session, proxy_type,
|
|
self.server)
|
|
if not curr_session:
|
|
http_404(self, 90)
|
|
self.server.getreq_busy = False
|
|
return True
|
|
msg = html_blog_page(authorized,
|
|
curr_session,
|
|
base_dir,
|
|
http_prefix,
|
|
translate,
|
|
nickname,
|
|
domain, port,
|
|
MAX_POSTS_IN_BLOGS_FEED, page_number,
|
|
self.server.peertube_instances,
|
|
self.server.system_language,
|
|
self.server.person_cache,
|
|
debug)
|
|
if msg is not None:
|
|
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,
|
|
self.server.fitness,
|
|
'_GET', '_show_blog_page',
|
|
debug)
|
|
return True
|
|
http_404(self, 91)
|
|
return True
|
|
|
|
|
|
def _redirect_to_login_screen(self, calling_domain: str, path: str,
|
|
http_prefix: str, domain_full: str,
|
|
onion_domain: str, i2p_domain: str,
|
|
getreq_start_time,
|
|
authorized: bool, debug: bool):
|
|
"""Redirects to the login screen if necessary
|
|
"""
|
|
divert_to_login_screen = False
|
|
if '/media/' not in path and \
|
|
'/ontologies/' not in path and \
|
|
'/data/' not in path and \
|
|
'/sharefiles/' not in path and \
|
|
'/statuses/' not in path and \
|
|
'/emoji/' not in path and \
|
|
'/tags/' not in path and \
|
|
'/tagmaps/' not in path and \
|
|
'/avatars/' not in path and \
|
|
'/favicons/' not in path and \
|
|
'/headers/' not in path and \
|
|
'/fonts/' not in path and \
|
|
'/icons/' not in path:
|
|
divert_to_login_screen = True
|
|
if path.startswith('/users/'):
|
|
nick_str = path.split('/users/')[1]
|
|
if '/' not in nick_str and '?' not in nick_str:
|
|
divert_to_login_screen = False
|
|
else:
|
|
if path.endswith('/following') or \
|
|
path.endswith('/followers') or \
|
|
path.endswith('/skills') or \
|
|
path.endswith('/roles') or \
|
|
path.endswith('/wanted') or \
|
|
path.endswith('/shares'):
|
|
divert_to_login_screen = False
|
|
|
|
if divert_to_login_screen and not authorized:
|
|
divert_path = '/login'
|
|
if self.server.news_instance:
|
|
# for news instances if not logged in then show the
|
|
# front page
|
|
divert_path = '/users/news'
|
|
if debug:
|
|
print('DEBUG: divert_to_login_screen=' +
|
|
str(divert_to_login_screen))
|
|
print('DEBUG: authorized=' + str(authorized))
|
|
print('DEBUG: path=' + path)
|
|
redirect_url = \
|
|
get_instance_url(calling_domain,
|
|
http_prefix, domain_full,
|
|
onion_domain, i2p_domain) + \
|
|
divert_path
|
|
redirect_headers(self, redirect_url, None, calling_domain)
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET', '_redirect_to_login_screen',
|
|
debug)
|
|
return True
|
|
return False
|
|
|
|
|
|
def _show_qrcode(self, calling_domain: str, path: str,
|
|
base_dir: str, domain: str,
|
|
onion_domain: str, i2p_domain: str,
|
|
port: int, getreq_start_time) -> bool:
|
|
"""Shows a QR code for an account
|
|
"""
|
|
nickname = get_nickname_from_actor(path)
|
|
if not nickname:
|
|
http_404(self, 93)
|
|
return True
|
|
if onion_domain:
|
|
qrcode_domain = onion_domain
|
|
port = 80
|
|
elif i2p_domain:
|
|
qrcode_domain = i2p_domain
|
|
port = 80
|
|
else:
|
|
qrcode_domain = domain
|
|
save_person_qrcode(base_dir, nickname, domain, qrcode_domain, port)
|
|
qr_filename = \
|
|
acct_dir(base_dir, nickname, domain) + '/qrcode.png'
|
|
if os.path.isfile(qr_filename):
|
|
if etag_exists(self, qr_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return
|
|
|
|
tries = 0
|
|
media_binary = None
|
|
while tries < 5:
|
|
try:
|
|
with open(qr_filename, 'rb') as av_file:
|
|
media_binary = av_file.read()
|
|
break
|
|
except OSError as ex:
|
|
print('EX: _show_qrcode ' + str(tries) + ' ' + str(ex))
|
|
time.sleep(1)
|
|
tries += 1
|
|
if media_binary:
|
|
mime_type = media_file_mime_type(qr_filename)
|
|
set_headers_etag(self, qr_filename, mime_type,
|
|
media_binary, None,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, media_binary)
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET', '_show_qrcode',
|
|
self.server.debug)
|
|
return True
|
|
http_404(self, 94)
|
|
return True
|
|
|
|
|
|
def _search_screen_banner(self, path: str,
|
|
base_dir: str, domain: str,
|
|
getreq_start_time) -> bool:
|
|
"""Shows a banner image on the search screen
|
|
"""
|
|
nickname = get_nickname_from_actor(path)
|
|
if not nickname:
|
|
http_404(self, 95)
|
|
return True
|
|
banner_filename = \
|
|
acct_dir(base_dir, nickname, domain) + '/search_banner.png'
|
|
if not os.path.isfile(banner_filename):
|
|
if os.path.isfile(base_dir + '/theme/default/search_banner.png'):
|
|
copyfile(base_dir + '/theme/default/search_banner.png',
|
|
banner_filename)
|
|
if os.path.isfile(banner_filename):
|
|
if etag_exists(self, banner_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return True
|
|
|
|
tries = 0
|
|
media_binary = None
|
|
while tries < 5:
|
|
try:
|
|
with open(banner_filename, 'rb') as av_file:
|
|
media_binary = av_file.read()
|
|
break
|
|
except OSError as ex:
|
|
print('EX: _search_screen_banner ' +
|
|
str(tries) + ' ' + str(ex))
|
|
time.sleep(1)
|
|
tries += 1
|
|
if media_binary:
|
|
mime_type = media_file_mime_type(banner_filename)
|
|
set_headers_etag(self, banner_filename, mime_type,
|
|
media_binary, None,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, media_binary)
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET', '_search_screen_banner',
|
|
self.server.debug)
|
|
return True
|
|
http_404(self, 96)
|
|
return True
|
|
|
|
|
|
def _column_image(self, side: str, path: str, base_dir: str, domain: str,
|
|
getreq_start_time) -> bool:
|
|
"""Shows an image at the top of the left/right column
|
|
"""
|
|
nickname = get_nickname_from_actor(path)
|
|
if not nickname:
|
|
http_404(self, 97)
|
|
return True
|
|
banner_filename = \
|
|
acct_dir(base_dir, nickname, domain) + '/' + \
|
|
side + '_col_image.png'
|
|
if os.path.isfile(banner_filename):
|
|
if etag_exists(self, banner_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return True
|
|
|
|
tries = 0
|
|
media_binary = None
|
|
while tries < 5:
|
|
try:
|
|
with open(banner_filename, 'rb') as av_file:
|
|
media_binary = av_file.read()
|
|
break
|
|
except OSError as ex:
|
|
print('EX: _column_image ' + str(tries) + ' ' + str(ex))
|
|
time.sleep(1)
|
|
tries += 1
|
|
if media_binary:
|
|
mime_type = media_file_mime_type(banner_filename)
|
|
set_headers_etag(self, banner_filename, mime_type,
|
|
media_binary, None,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, media_binary)
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET', '_column_image ' + side,
|
|
self.server.debug)
|
|
return True
|
|
http_404(self, 98)
|
|
return True
|
|
|
|
|
|
def _show_default_profile_background(self, base_dir: str, theme_name: str,
|
|
getreq_start_time) -> bool:
|
|
"""If a background image is missing after searching for a handle
|
|
then substitute this image
|
|
"""
|
|
image_extensions = get_image_extensions()
|
|
for ext in image_extensions:
|
|
bg_filename = \
|
|
base_dir + '/theme/' + theme_name + '/image.' + ext
|
|
if os.path.isfile(bg_filename):
|
|
if etag_exists(self, bg_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return True
|
|
|
|
tries = 0
|
|
bg_binary = None
|
|
while tries < 5:
|
|
try:
|
|
with open(bg_filename, 'rb') as av_file:
|
|
bg_binary = av_file.read()
|
|
break
|
|
except OSError as ex:
|
|
print('EX: _show_default_profile_background ' +
|
|
str(tries) + ' ' + str(ex))
|
|
time.sleep(1)
|
|
tries += 1
|
|
if bg_binary:
|
|
if ext == 'jpg':
|
|
ext = 'jpeg'
|
|
set_headers_etag(self, bg_filename,
|
|
'image/' + ext,
|
|
bg_binary, None,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, bg_binary)
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET',
|
|
'_show_default_profile_background',
|
|
self.server.debug)
|
|
return True
|
|
break
|
|
|
|
http_404(self, 100)
|
|
return True
|
|
|
|
|
|
def _show_background_image(self, path: str,
|
|
base_dir: str, getreq_start_time) -> bool:
|
|
"""Show a background image
|
|
"""
|
|
image_extensions = get_image_extensions()
|
|
for ext in image_extensions:
|
|
for bg_im in ('follow', 'options', 'login', 'welcome'):
|
|
# follow screen background image
|
|
if path.endswith('/' + bg_im + '-background.' + ext):
|
|
bg_filename = \
|
|
base_dir + '/accounts/' + \
|
|
bg_im + '-background.' + ext
|
|
if os.path.isfile(bg_filename):
|
|
if etag_exists(self, bg_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return True
|
|
|
|
tries = 0
|
|
bg_binary = None
|
|
while tries < 5:
|
|
try:
|
|
with open(bg_filename, 'rb') as av_file:
|
|
bg_binary = av_file.read()
|
|
break
|
|
except OSError as ex:
|
|
print('EX: _show_background_image ' +
|
|
str(tries) + ' ' + str(ex))
|
|
time.sleep(1)
|
|
tries += 1
|
|
if bg_binary:
|
|
if ext == 'jpg':
|
|
ext = 'jpeg'
|
|
set_headers_etag(self, bg_filename,
|
|
'image/' + ext,
|
|
bg_binary, None,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, bg_binary)
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET',
|
|
'_show_background_image',
|
|
self.server.debug)
|
|
return True
|
|
http_404(self, 99)
|
|
return True
|
|
|
|
|
|
def _show_emoji(self, path: str,
|
|
base_dir: str, getreq_start_time) -> None:
|
|
"""Returns an emoji image
|
|
"""
|
|
if is_image_file(path):
|
|
emoji_str = path.split('/emoji/')[1]
|
|
emoji_filename = base_dir + '/emoji/' + emoji_str
|
|
if not os.path.isfile(emoji_filename):
|
|
emoji_filename = base_dir + '/emojicustom/' + emoji_str
|
|
if os.path.isfile(emoji_filename):
|
|
if etag_exists(self, emoji_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return
|
|
|
|
media_image_type = get_image_mime_type(emoji_filename)
|
|
media_binary = None
|
|
try:
|
|
with open(emoji_filename, 'rb') as av_file:
|
|
media_binary = av_file.read()
|
|
except OSError:
|
|
print('EX: unable to read emoji image ' + emoji_filename)
|
|
if media_binary:
|
|
set_headers_etag(self, emoji_filename,
|
|
media_image_type,
|
|
media_binary, None,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, media_binary)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_show_emoji', self.server.debug)
|
|
return
|
|
http_404(self, 36)
|
|
|
|
|
|
def _show_media(self, path: str, base_dir: str,
|
|
getreq_start_time) -> None:
|
|
"""Returns a media file
|
|
"""
|
|
if is_image_file(path) or \
|
|
path_is_video(path) or \
|
|
path_is_transcript(path) or \
|
|
path_is_audio(path):
|
|
media_str = path.split('/media/')[1]
|
|
media_filename = base_dir + '/media/' + media_str
|
|
if os.path.isfile(media_filename):
|
|
if etag_exists(self, media_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return
|
|
|
|
media_file_type = media_file_mime_type(media_filename)
|
|
|
|
media_tm = os.path.getmtime(media_filename)
|
|
last_modified_time = \
|
|
datetime.datetime.fromtimestamp(media_tm,
|
|
datetime.timezone.utc)
|
|
last_modified_time_str = \
|
|
last_modified_time.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
|
|
|
if media_filename.endswith('.vtt'):
|
|
media_transcript = None
|
|
try:
|
|
with open(media_filename, 'r',
|
|
encoding='utf-8') as fp_vtt:
|
|
media_transcript = fp_vtt.read()
|
|
media_file_type = 'text/vtt; charset=utf-8'
|
|
except OSError:
|
|
print('EX: unable to read media binary ' +
|
|
media_filename)
|
|
if media_transcript:
|
|
media_transcript = media_transcript.encode('utf-8')
|
|
set_headers_etag(self, media_filename, media_file_type,
|
|
media_transcript, None,
|
|
None, True,
|
|
last_modified_time_str)
|
|
write2(self, media_transcript)
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET', '_show_media',
|
|
self.server.debug)
|
|
return
|
|
http_404(self, 32)
|
|
return
|
|
|
|
media_binary = None
|
|
try:
|
|
with open(media_filename, 'rb') as av_file:
|
|
media_binary = av_file.read()
|
|
except OSError:
|
|
print('EX: unable to read media binary ' + media_filename)
|
|
if media_binary:
|
|
set_headers_etag(self, media_filename, media_file_type,
|
|
media_binary, None,
|
|
None, True,
|
|
last_modified_time_str)
|
|
write2(self, media_binary)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_show_media', self.server.debug)
|
|
return
|
|
http_404(self, 33)
|
|
|
|
|
|
def _get_ontology(self, calling_domain: str,
|
|
path: str, base_dir: str,
|
|
getreq_start_time) -> None:
|
|
"""Returns an ontology file
|
|
"""
|
|
if '.owl' in path or '.rdf' in path or '.json' in path:
|
|
if '/ontologies/' in path:
|
|
ontology_str = path.split('/ontologies/')[1].replace('#', '')
|
|
else:
|
|
ontology_str = path.split('/data/')[1].replace('#', '')
|
|
ontology_filename = None
|
|
ontology_file_type = 'application/rdf+xml'
|
|
if ontology_str.startswith('DFC_'):
|
|
ontology_filename = base_dir + '/ontology/DFC/' + ontology_str
|
|
else:
|
|
ontology_str = ontology_str.replace('/data/', '')
|
|
ontology_filename = base_dir + '/ontology/' + ontology_str
|
|
if ontology_str.endswith('.json'):
|
|
ontology_file_type = 'application/ld+json'
|
|
if os.path.isfile(ontology_filename):
|
|
ontology_file = None
|
|
try:
|
|
with open(ontology_filename, 'r',
|
|
encoding='utf-8') as fp_ont:
|
|
ontology_file = fp_ont.read()
|
|
except OSError:
|
|
print('EX: unable to read ontology ' + ontology_filename)
|
|
if ontology_file:
|
|
ontology_file = \
|
|
ontology_file.replace('static.datafoodconsortium.org',
|
|
calling_domain)
|
|
if not calling_domain.endswith('.i2p') and \
|
|
not calling_domain.endswith('.onion'):
|
|
ontology_file = \
|
|
ontology_file.replace('http://' +
|
|
calling_domain,
|
|
'https://' +
|
|
calling_domain)
|
|
msg = ontology_file.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, ontology_file_type, msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_get_ontology', self.server.debug)
|
|
return
|
|
http_404(self, 34)
|
|
|
|
|
|
def _show_share_image(self, path: str,
|
|
base_dir: str, getreq_start_time) -> bool:
|
|
"""Show a shared item image
|
|
"""
|
|
if not is_image_file(path):
|
|
http_404(self, 101)
|
|
return True
|
|
|
|
media_str = path.split('/sharefiles/')[1]
|
|
media_filename = base_dir + '/sharefiles/' + media_str
|
|
if not os.path.isfile(media_filename):
|
|
http_404(self, 102)
|
|
return True
|
|
|
|
if etag_exists(self, media_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return True
|
|
|
|
media_file_type = get_image_mime_type(media_filename)
|
|
media_binary = None
|
|
try:
|
|
with open(media_filename, 'rb') as av_file:
|
|
media_binary = av_file.read()
|
|
except OSError:
|
|
print('EX: unable to read binary ' + media_filename)
|
|
if media_binary:
|
|
set_headers_etag(self, media_filename,
|
|
media_file_type,
|
|
media_binary, None,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, media_binary)
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET', '_show_share_image',
|
|
self.server.debug)
|
|
return True
|
|
|
|
|
|
def _show_icon(self, path: str,
|
|
base_dir: str, getreq_start_time) -> None:
|
|
"""Shows an icon
|
|
"""
|
|
if not path.endswith('.png'):
|
|
http_404(self, 37)
|
|
return
|
|
media_str = path.split('/icons/')[1]
|
|
if '/' not in media_str:
|
|
if not self.server.theme_name:
|
|
theme = 'default'
|
|
else:
|
|
theme = self.server.theme_name
|
|
icon_filename = media_str
|
|
else:
|
|
theme = media_str.split('/')[0]
|
|
icon_filename = media_str.split('/')[1]
|
|
media_filename = \
|
|
base_dir + '/theme/' + theme + '/icons/' + icon_filename
|
|
if etag_exists(self, media_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return
|
|
if self.server.iconsCache.get(media_str):
|
|
media_binary = self.server.iconsCache[media_str]
|
|
mime_type_str = media_file_mime_type(media_filename)
|
|
set_headers_etag(self, media_filename,
|
|
mime_type_str,
|
|
media_binary, None,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, media_binary)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_show_icon', self.server.debug)
|
|
return
|
|
if os.path.isfile(media_filename):
|
|
media_binary = None
|
|
try:
|
|
with open(media_filename, 'rb') as av_file:
|
|
media_binary = av_file.read()
|
|
except OSError:
|
|
print('EX: unable to read icon image ' + media_filename)
|
|
if media_binary:
|
|
mime_type = media_file_mime_type(media_filename)
|
|
set_headers_etag(self, media_filename,
|
|
mime_type,
|
|
media_binary, None,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, media_binary)
|
|
self.server.iconsCache[media_str] = media_binary
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_show_icon', self.server.debug)
|
|
return
|
|
http_404(self, 38)
|
|
|
|
|
|
def _show_specification_image(self, path: str,
|
|
base_dir: str, getreq_start_time) -> None:
|
|
"""Shows an image within the ActivityPub specification document
|
|
"""
|
|
image_filename = path.split('/', 1)[1]
|
|
if '/' in image_filename:
|
|
http_404(self, 39)
|
|
return
|
|
media_filename = \
|
|
base_dir + '/specification/' + image_filename
|
|
if etag_exists(self, media_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return
|
|
if self.server.iconsCache.get(media_filename):
|
|
media_binary = self.server.iconsCache[media_filename]
|
|
mime_type_str = media_file_mime_type(media_filename)
|
|
set_headers_etag(self, media_filename,
|
|
mime_type_str,
|
|
media_binary, None,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, media_binary)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_show_specification_image',
|
|
self.server.debug)
|
|
return
|
|
if os.path.isfile(media_filename):
|
|
media_binary = None
|
|
try:
|
|
with open(media_filename, 'rb') as av_file:
|
|
media_binary = av_file.read()
|
|
except OSError:
|
|
print('EX: unable to read specification image ' +
|
|
media_filename)
|
|
if media_binary:
|
|
mime_type = media_file_mime_type(media_filename)
|
|
set_headers_etag(self, media_filename,
|
|
mime_type,
|
|
media_binary, None,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, media_binary)
|
|
self.server.iconsCache[media_filename] = media_binary
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_show_specification_image',
|
|
self.server.debug)
|
|
return
|
|
http_404(self, 40)
|
|
|
|
|
|
def _show_manual_image(self, path: str,
|
|
base_dir: str, getreq_start_time) -> None:
|
|
"""Shows an image within the manual
|
|
"""
|
|
image_filename = path.split('/', 1)[1]
|
|
if '/' in image_filename:
|
|
http_404(self, 41)
|
|
return
|
|
media_filename = \
|
|
base_dir + '/manual/' + image_filename
|
|
if etag_exists(self, media_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return
|
|
if self.server.iconsCache.get(media_filename):
|
|
media_binary = self.server.iconsCache[media_filename]
|
|
mime_type_str = media_file_mime_type(media_filename)
|
|
set_headers_etag(self, media_filename,
|
|
mime_type_str,
|
|
media_binary, None,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, media_binary)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_show_manual_image',
|
|
self.server.debug)
|
|
return
|
|
if os.path.isfile(media_filename):
|
|
media_binary = None
|
|
try:
|
|
with open(media_filename, 'rb') as av_file:
|
|
media_binary = av_file.read()
|
|
except OSError:
|
|
print('EX: unable to read manual image ' +
|
|
media_filename)
|
|
if media_binary:
|
|
mime_type = media_file_mime_type(media_filename)
|
|
set_headers_etag(self, media_filename,
|
|
mime_type,
|
|
media_binary, None,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, media_binary)
|
|
self.server.iconsCache[media_filename] = media_binary
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_show_manual_image',
|
|
self.server.debug)
|
|
return
|
|
http_404(self, 42)
|
|
|
|
|
|
def _show_help_screen_image(self, path: str,
|
|
base_dir: str, getreq_start_time) -> None:
|
|
"""Shows a help screen image
|
|
"""
|
|
if not is_image_file(path):
|
|
return
|
|
media_str = path.split('/helpimages/')[1]
|
|
if '/' not in media_str:
|
|
if not self.server.theme_name:
|
|
theme = 'default'
|
|
else:
|
|
theme = self.server.theme_name
|
|
icon_filename = media_str
|
|
else:
|
|
theme = media_str.split('/')[0]
|
|
icon_filename = media_str.split('/')[1]
|
|
media_filename = \
|
|
base_dir + '/theme/' + theme + '/helpimages/' + icon_filename
|
|
# if there is no theme-specific help image then use the default one
|
|
if not os.path.isfile(media_filename):
|
|
media_filename = \
|
|
base_dir + '/theme/default/helpimages/' + icon_filename
|
|
if etag_exists(self, media_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return
|
|
if os.path.isfile(media_filename):
|
|
media_binary = None
|
|
try:
|
|
with open(media_filename, 'rb') as av_file:
|
|
media_binary = av_file.read()
|
|
except OSError:
|
|
print('EX: unable to read help image ' + media_filename)
|
|
if media_binary:
|
|
mime_type = media_file_mime_type(media_filename)
|
|
set_headers_etag(self, media_filename,
|
|
mime_type,
|
|
media_binary, None,
|
|
self.server.domain_full,
|
|
False, None)
|
|
write2(self, media_binary)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_show_help_screen_image',
|
|
self.server.debug)
|
|
return
|
|
http_404(self, 43)
|
|
|
|
|
|
def _show_cached_avatar(self, referer_domain: str, path: str,
|
|
base_dir: str, getreq_start_time) -> None:
|
|
"""Shows an avatar image obtained from the cache
|
|
"""
|
|
media_filename = base_dir + '/cache' + path
|
|
if os.path.isfile(media_filename):
|
|
if etag_exists(self, media_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return
|
|
media_binary = None
|
|
try:
|
|
with open(media_filename, 'rb') as av_file:
|
|
media_binary = av_file.read()
|
|
except OSError:
|
|
print('EX: unable to read cached avatar ' + media_filename)
|
|
if media_binary:
|
|
mime_type = media_file_mime_type(media_filename)
|
|
set_headers_etag(self, media_filename,
|
|
mime_type,
|
|
media_binary, None,
|
|
referer_domain,
|
|
False, None)
|
|
write2(self, media_binary)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_show_cached_avatar',
|
|
self.server.debug)
|
|
return
|
|
http_404(self, 46)
|
|
|
|
|
|
def _show_avatar_or_banner(self, referer_domain: str, path: str,
|
|
base_dir: str, domain: str,
|
|
getreq_start_time) -> bool:
|
|
"""Shows an avatar or banner or profile background image
|
|
"""
|
|
if '/users/' not in path:
|
|
if '/system/accounts/avatars/' not in path and \
|
|
'/system/accounts/headers/' not in path and \
|
|
'/accounts/avatars/' not in path and \
|
|
'/accounts/headers/' not in path:
|
|
return False
|
|
if not is_image_file(path):
|
|
return False
|
|
if '/system/accounts/avatars/' in path:
|
|
avatar_str = path.split('/system/accounts/avatars/')[1]
|
|
elif '/accounts/avatars/' in path:
|
|
avatar_str = path.split('/accounts/avatars/')[1]
|
|
elif '/system/accounts/headers/' in path:
|
|
avatar_str = path.split('/system/accounts/headers/')[1]
|
|
elif '/accounts/headers/' in path:
|
|
avatar_str = path.split('/accounts/headers/')[1]
|
|
else:
|
|
avatar_str = path.split('/users/')[1]
|
|
if not ('/' in avatar_str and '.temp.' not in path):
|
|
return False
|
|
avatar_nickname = avatar_str.split('/')[0]
|
|
avatar_file = avatar_str.split('/')[1]
|
|
avatar_file_ext = avatar_file.split('.')[-1]
|
|
# remove any numbers, eg. avatar123.png becomes avatar.png
|
|
if avatar_file.startswith('avatar'):
|
|
avatar_file = 'avatar.' + avatar_file_ext
|
|
elif avatar_file.startswith('banner'):
|
|
avatar_file = 'banner.' + avatar_file_ext
|
|
elif avatar_file.startswith('search_banner'):
|
|
avatar_file = 'search_banner.' + avatar_file_ext
|
|
elif avatar_file.startswith('image'):
|
|
avatar_file = 'image.' + avatar_file_ext
|
|
elif avatar_file.startswith('left_col_image'):
|
|
avatar_file = 'left_col_image.' + avatar_file_ext
|
|
elif avatar_file.startswith('right_col_image'):
|
|
avatar_file = 'right_col_image.' + avatar_file_ext
|
|
avatar_filename = \
|
|
acct_dir(base_dir, avatar_nickname, domain) + '/' + avatar_file
|
|
if not os.path.isfile(avatar_filename):
|
|
original_ext = avatar_file_ext
|
|
original_avatar_file = avatar_file
|
|
alt_ext = get_image_extensions()
|
|
alt_found = False
|
|
for alt in alt_ext:
|
|
if alt == original_ext:
|
|
continue
|
|
avatar_file = \
|
|
original_avatar_file.replace('.' + original_ext,
|
|
'.' + alt)
|
|
avatar_filename = \
|
|
acct_dir(base_dir, avatar_nickname, domain) + \
|
|
'/' + avatar_file
|
|
if os.path.isfile(avatar_filename):
|
|
alt_found = True
|
|
break
|
|
if not alt_found:
|
|
return False
|
|
if etag_exists(self, avatar_filename):
|
|
# The file has not changed
|
|
http_304(self)
|
|
return True
|
|
|
|
avatar_tm = os.path.getmtime(avatar_filename)
|
|
last_modified_time = \
|
|
datetime.datetime.fromtimestamp(avatar_tm, datetime.timezone.utc)
|
|
last_modified_time_str = \
|
|
last_modified_time.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
|
|
|
media_image_type = get_image_mime_type(avatar_file)
|
|
media_binary = None
|
|
try:
|
|
with open(avatar_filename, 'rb') as av_file:
|
|
media_binary = av_file.read()
|
|
except OSError:
|
|
print('EX: unable to read avatar ' + avatar_filename)
|
|
if media_binary:
|
|
set_headers_etag(self, avatar_filename, media_image_type,
|
|
media_binary, None,
|
|
referer_domain, True,
|
|
last_modified_time_str)
|
|
write2(self, media_binary)
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET', '_show_avatar_or_banner',
|
|
self.server.debug)
|
|
return True
|
|
|
|
|
|
def _webfinger(self, calling_domain: str, referer_domain: str,
|
|
cookie: str) -> bool:
|
|
if not self.path.startswith('/.well-known'):
|
|
return False
|
|
if self.server.debug:
|
|
print('DEBUG: WEBFINGER well-known')
|
|
|
|
if self.server.debug:
|
|
print('DEBUG: WEBFINGER host-meta')
|
|
if self.path.startswith('/.well-known/host-meta'):
|
|
if calling_domain.endswith('.onion') and \
|
|
self.server.onion_domain:
|
|
wf_result = \
|
|
webfinger_meta('http', self.server.onion_domain)
|
|
elif (calling_domain.endswith('.i2p') and
|
|
self.server.i2p_domain):
|
|
wf_result = \
|
|
webfinger_meta('http', self.server.i2p_domain)
|
|
else:
|
|
wf_result = \
|
|
webfinger_meta(self.server.http_prefix,
|
|
self.server.domain_full)
|
|
if wf_result:
|
|
msg = wf_result.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'application/xrd+xml', msglen,
|
|
None, calling_domain, True)
|
|
write2(self, msg)
|
|
return True
|
|
http_404(self, 6)
|
|
return True
|
|
if self.path.startswith('/api/statusnet') or \
|
|
self.path.startswith('/api/gnusocial') or \
|
|
self.path.startswith('/siteinfo') or \
|
|
self.path.startswith('/poco') or \
|
|
self.path.startswith('/friendi'):
|
|
http_404(self, 7)
|
|
return True
|
|
# protocol handler. See https://fedi-to.github.io/protocol-handler.html
|
|
if self.path.startswith('/.well-known/protocol-handler'):
|
|
if calling_domain.endswith('.onion'):
|
|
protocol_url, _ = \
|
|
wellknown_protocol_handler(self.path, 'http',
|
|
self.server.onion_domain)
|
|
elif calling_domain.endswith('.i2p'):
|
|
protocol_url, _ = \
|
|
wellknown_protocol_handler(self.path,
|
|
'http', self.server.i2p_domain)
|
|
else:
|
|
protocol_url, _ = \
|
|
wellknown_protocol_handler(self.path,
|
|
self.server.http_prefix,
|
|
self.server.domain_full)
|
|
if protocol_url:
|
|
redirect_headers(self, protocol_url, cookie,
|
|
calling_domain, 308)
|
|
else:
|
|
http_404(self, 8)
|
|
return True
|
|
# nodeinfo
|
|
if self.path.startswith('/.well-known/nodeinfo') or \
|
|
self.path.startswith('/.well-known/x-nodeinfo'):
|
|
if calling_domain.endswith('.onion') and \
|
|
self.server.onion_domain:
|
|
wf_result = \
|
|
webfinger_node_info('http', self.server.onion_domain)
|
|
elif (calling_domain.endswith('.i2p') and
|
|
self.server.i2p_domain):
|
|
wf_result = \
|
|
webfinger_node_info('http', self.server.i2p_domain)
|
|
else:
|
|
wf_result = \
|
|
webfinger_node_info(self.server.http_prefix,
|
|
self.server.domain_full)
|
|
if wf_result:
|
|
msg_str = json.dumps(wf_result)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
if has_accept(self, calling_domain):
|
|
accept_str = self.headers.get('Accept')
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen,
|
|
None, calling_domain, True)
|
|
else:
|
|
set_headers(self, 'application/ld+json', msglen,
|
|
None, calling_domain, True)
|
|
write2(self, msg)
|
|
return True
|
|
http_404(self, 9)
|
|
return True
|
|
|
|
if self.server.debug:
|
|
print('DEBUG: WEBFINGER lookup ' + self.path + ' ' +
|
|
str(self.server.base_dir))
|
|
wf_result = \
|
|
webfinger_lookup(self.path, self.server.base_dir,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain,
|
|
self.server.port, self.server.debug)
|
|
if wf_result:
|
|
msg_str = json.dumps(wf_result)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str,
|
|
self.server.http_prefix,
|
|
self.server.domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'application/jrd+json', msglen,
|
|
None, calling_domain, True)
|
|
write2(self, msg)
|
|
else:
|
|
if self.server.debug:
|
|
print('DEBUG: WEBFINGER lookup 404 ' + self.path)
|
|
http_404(self, 10)
|
|
return True
|
|
|
|
|
|
def _confirm_delete_event(self, calling_domain: str, path: str,
|
|
base_dir: str, http_prefix: str, cookie: str,
|
|
translate: {}, domain_full: str,
|
|
onion_domain: str, i2p_domain: str,
|
|
getreq_start_time) -> bool:
|
|
"""Confirm whether to delete a calendar event
|
|
"""
|
|
post_id = path.split('?eventid=')[1]
|
|
if '?' in post_id:
|
|
post_id = post_id.split('?')[0]
|
|
post_time = path.split('?time=')[1]
|
|
if '?' in post_time:
|
|
post_time = post_time.split('?')[0]
|
|
post_year = path.split('?year=')[1]
|
|
if '?' in post_year:
|
|
post_year = post_year.split('?')[0]
|
|
post_month = path.split('?month=')[1]
|
|
if '?' in post_month:
|
|
post_month = post_month.split('?')[0]
|
|
post_day = path.split('?day=')[1]
|
|
if '?' in post_day:
|
|
post_day = post_day.split('?')[0]
|
|
# show the confirmation screen screen
|
|
msg = html_calendar_delete_confirm(translate,
|
|
base_dir, path,
|
|
http_prefix,
|
|
domain_full,
|
|
post_id, post_time,
|
|
post_year, post_month, post_day,
|
|
calling_domain)
|
|
if not msg:
|
|
actor = \
|
|
http_prefix + '://' + \
|
|
domain_full + \
|
|
path.split('/eventdelete')[0]
|
|
if calling_domain.endswith('.onion') and onion_domain:
|
|
actor = \
|
|
'http://' + onion_domain + \
|
|
path.split('/eventdelete')[0]
|
|
elif calling_domain.endswith('.i2p') and i2p_domain:
|
|
actor = \
|
|
'http://' + i2p_domain + \
|
|
path.split('/eventdelete')[0]
|
|
redirect_headers(self, actor + '/calendar',
|
|
cookie, calling_domain)
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET', '_confirm_delete_event',
|
|
self.server.debug)
|
|
return True
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/html', msglen,
|
|
cookie, calling_domain, False)
|
|
write2(self, msg)
|
|
return True
|
|
|
|
|
|
def _newswire_vote(self, calling_domain: str, path: str,
|
|
cookie: str,
|
|
base_dir: str, http_prefix: str,
|
|
domain_full: str,
|
|
onion_domain: str, i2p_domain: str,
|
|
getreq_start_time,
|
|
newswire: {}):
|
|
"""Vote for a newswire item
|
|
"""
|
|
origin_path_str = path.split('/newswirevote=')[0]
|
|
date_str = \
|
|
path.split('/newswirevote=')[1].replace('T', ' ')
|
|
date_str = date_str.replace(' 00:00', '').replace('+00:00', '')
|
|
date_str = urllib.parse.unquote_plus(date_str) + '+00:00'
|
|
nickname = \
|
|
urllib.parse.unquote_plus(origin_path_str.split('/users/')[1])
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
print('Newswire item date: ' + date_str)
|
|
if newswire.get(date_str):
|
|
if is_moderator(base_dir, nickname):
|
|
newswire_item = newswire[date_str]
|
|
print('Voting on newswire item: ' + str(newswire_item))
|
|
votes_index = 2
|
|
filename_index = 3
|
|
if 'vote:' + nickname not in newswire_item[votes_index]:
|
|
newswire_item[votes_index].append('vote:' + nickname)
|
|
filename = newswire_item[filename_index]
|
|
newswire_state_filename = \
|
|
base_dir + '/accounts/.newswirestate.json'
|
|
try:
|
|
save_json(newswire, newswire_state_filename)
|
|
except BaseException as ex:
|
|
print('EX: saving newswire state, ' + str(ex))
|
|
if filename:
|
|
save_json(newswire_item[votes_index],
|
|
filename + '.votes')
|
|
else:
|
|
print('No newswire item with date: ' + date_str + ' ' +
|
|
str(newswire))
|
|
|
|
origin_path_str_absolute = \
|
|
http_prefix + '://' + domain_full + origin_path_str + '/' + \
|
|
self.server.default_timeline
|
|
if calling_domain.endswith('.onion') and onion_domain:
|
|
origin_path_str_absolute = \
|
|
'http://' + onion_domain + origin_path_str
|
|
elif (calling_domain.endswith('.i2p') and i2p_domain):
|
|
origin_path_str_absolute = \
|
|
'http://' + i2p_domain + origin_path_str
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_newswire_vote',
|
|
self.server.debug)
|
|
redirect_headers(self, origin_path_str_absolute,
|
|
cookie, calling_domain)
|
|
|
|
|
|
def _newswire_unvote(self, calling_domain: str, path: str,
|
|
cookie: str, base_dir: str, http_prefix: str,
|
|
domain_full: str,
|
|
onion_domain: str, i2p_domain: str,
|
|
getreq_start_time, debug: bool,
|
|
newswire: {}):
|
|
"""Remove vote for a newswire item
|
|
"""
|
|
origin_path_str = path.split('/newswireunvote=')[0]
|
|
date_str = \
|
|
path.split('/newswireunvote=')[1].replace('T', ' ')
|
|
date_str = date_str.replace(' 00:00', '').replace('+00:00', '')
|
|
date_str = urllib.parse.unquote_plus(date_str) + '+00:00'
|
|
nickname = \
|
|
urllib.parse.unquote_plus(origin_path_str.split('/users/')[1])
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
if newswire.get(date_str):
|
|
if is_moderator(base_dir, nickname):
|
|
votes_index = 2
|
|
filename_index = 3
|
|
newswire_item = newswire[date_str]
|
|
if 'vote:' + nickname in newswire_item[votes_index]:
|
|
newswire_item[votes_index].remove('vote:' + nickname)
|
|
filename = newswire_item[filename_index]
|
|
newswire_state_filename = \
|
|
base_dir + '/accounts/.newswirestate.json'
|
|
try:
|
|
save_json(newswire, newswire_state_filename)
|
|
except BaseException as ex:
|
|
print('EX: saving newswire state, ' + str(ex))
|
|
if filename:
|
|
save_json(newswire_item[votes_index],
|
|
filename + '.votes')
|
|
else:
|
|
print('No newswire item with date: ' + date_str + ' ' +
|
|
str(newswire))
|
|
|
|
origin_path_str_absolute = \
|
|
http_prefix + '://' + domain_full + origin_path_str + '/' + \
|
|
self.server.default_timeline
|
|
if calling_domain.endswith('.onion') and onion_domain:
|
|
origin_path_str_absolute = \
|
|
'http://' + onion_domain + origin_path_str
|
|
elif (calling_domain.endswith('.i2p') and i2p_domain):
|
|
origin_path_str_absolute = \
|
|
'http://' + i2p_domain + origin_path_str
|
|
redirect_headers(self, origin_path_str_absolute,
|
|
cookie, calling_domain)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_newswire_unvote', debug)
|
|
|
|
|
|
def _reaction_picker2(self, calling_domain: str, path: str,
|
|
base_dir: str, http_prefix: str,
|
|
domain: str, port: int,
|
|
getreq_start_time, cookie: str,
|
|
debug: str, curr_session) -> None:
|
|
"""Press the emoji reaction picker icon at the bottom of the post
|
|
"""
|
|
page_number = 1
|
|
reaction_url = path.split('?selreact=')[1]
|
|
if '?' in reaction_url:
|
|
reaction_url = reaction_url.split('?')[0]
|
|
timeline_bookmark = ''
|
|
if '?bm=' in path:
|
|
timeline_bookmark = path.split('?bm=')[1]
|
|
if '?' in timeline_bookmark:
|
|
timeline_bookmark = timeline_bookmark.split('?')[0]
|
|
timeline_bookmark = '#' + timeline_bookmark
|
|
actor = path.split('?selreact=')[0]
|
|
if '?page=' in path:
|
|
page_number_str = path.split('?page=')[1]
|
|
if '?' in page_number_str:
|
|
page_number_str = page_number_str.split('?')[0]
|
|
if '#' in page_number_str:
|
|
page_number_str = page_number_str.split('#')[0]
|
|
if len(page_number_str) > 5:
|
|
page_number_str = "1"
|
|
if page_number_str.isdigit():
|
|
page_number = int(page_number_str)
|
|
timeline_str = 'inbox'
|
|
if '?tl=' in path:
|
|
timeline_str = path.split('?tl=')[1]
|
|
if '?' in timeline_str:
|
|
timeline_str = timeline_str.split('?')[0]
|
|
self.post_to_nickname = get_nickname_from_actor(actor)
|
|
if not self.post_to_nickname:
|
|
print('WARN: unable to find nickname in ' + actor)
|
|
actor_absolute = \
|
|
get_instance_url(calling_domain,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain) + \
|
|
actor
|
|
actor_path_str = \
|
|
actor_absolute + '/' + timeline_str + \
|
|
'?page=' + str(page_number) + timeline_bookmark
|
|
redirect_headers(self, actor_path_str, cookie, calling_domain)
|
|
return
|
|
|
|
post_json_object = None
|
|
reaction_post_filename = \
|
|
locate_post(base_dir,
|
|
self.post_to_nickname, domain, reaction_url)
|
|
if reaction_post_filename:
|
|
post_json_object = load_json(reaction_post_filename)
|
|
if not reaction_post_filename or not post_json_object:
|
|
print('WARN: unable to locate reaction post ' + reaction_url)
|
|
actor_absolute = \
|
|
get_instance_url(calling_domain,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain) + \
|
|
actor
|
|
actor_path_str = \
|
|
actor_absolute + '/' + timeline_str + \
|
|
'?page=' + str(page_number) + timeline_bookmark
|
|
redirect_headers(self, actor_path_str, cookie, calling_domain)
|
|
return
|
|
|
|
timezone = None
|
|
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.recent_posts_cache,
|
|
self.server.max_recent_posts,
|
|
self.server.translate,
|
|
base_dir,
|
|
curr_session,
|
|
self.server.cached_webfingers,
|
|
self.server.person_cache,
|
|
self.post_to_nickname,
|
|
domain, port, post_json_object,
|
|
http_prefix,
|
|
self.server.project_version,
|
|
self.server.yt_replace_domain,
|
|
self.server.twitter_replacement_domain,
|
|
self.server.show_published_date_only,
|
|
self.server.peertube_instances,
|
|
self.server.allow_local_network_access,
|
|
self.server.theme_name,
|
|
self.server.system_language,
|
|
self.server.max_like_count,
|
|
self.server.signing_priv_key_pem,
|
|
self.server.cw_lists,
|
|
self.server.lists_enabled,
|
|
timeline_str, page_number,
|
|
timezone, bold_reading,
|
|
self.server.dogwhistles,
|
|
self.server.min_images_for_accounts,
|
|
self.server.buy_sites,
|
|
self.server.auto_cw_cache)
|
|
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,
|
|
self.server.fitness,
|
|
'_GET', '_reaction_picker',
|
|
debug)
|
|
|
|
|
|
def _show_known_crawlers(self, calling_domain: str, path: str,
|
|
base_dir: str, known_crawlers: {}) -> bool:
|
|
"""Show a list of known web crawlers
|
|
"""
|
|
if '/users/' not in path:
|
|
return False
|
|
if not path.endswith('/crawlers'):
|
|
return False
|
|
nickname = get_nickname_from_actor(path)
|
|
if not nickname:
|
|
return False
|
|
if not is_moderator(base_dir, nickname):
|
|
return False
|
|
crawlers_list = []
|
|
curr_time = int(time.time())
|
|
recent_crawlers = 60 * 60 * 24 * 30
|
|
for ua_str, item in known_crawlers.items():
|
|
if item['lastseen'] - curr_time < recent_crawlers:
|
|
hits_str = str(item['hits']).zfill(8)
|
|
crawlers_list.append(hits_str + ' ' + ua_str)
|
|
crawlers_list.sort(reverse=True)
|
|
msg = ''
|
|
for line_str in crawlers_list:
|
|
msg += line_str + '\n'
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/plain; charset=utf-8', msglen,
|
|
None, calling_domain, True)
|
|
write2(self, msg)
|
|
return True
|
|
|
|
|
|
def _edit_profile2(self, calling_domain: str, path: str,
|
|
translate: {}, base_dir: str,
|
|
domain: str, port: int,
|
|
cookie: str) -> bool:
|
|
"""Show the edit profile screen
|
|
"""
|
|
if '/users/' in path and path.endswith('/editprofile'):
|
|
peertube_instances = self.server.peertube_instances
|
|
nickname = get_nickname_from_actor(path)
|
|
|
|
access_keys = self.server.access_keys
|
|
if '/users/' in path:
|
|
if self.server.key_shortcuts.get(nickname):
|
|
access_keys = self.server.key_shortcuts[nickname]
|
|
|
|
default_reply_interval_hrs = self.server.default_reply_interval_hrs
|
|
msg = html_edit_profile(self.server, translate,
|
|
base_dir, path, domain, port,
|
|
self.server.default_timeline,
|
|
self.server.theme_name,
|
|
peertube_instances,
|
|
self.server.text_mode_banner,
|
|
self.server.user_agents_blocked,
|
|
self.server.crawlers_allowed,
|
|
access_keys,
|
|
default_reply_interval_hrs,
|
|
self.server.cw_lists,
|
|
self.server.lists_enabled,
|
|
self.server.system_language,
|
|
self.server.min_images_for_accounts,
|
|
self.server.max_recent_posts,
|
|
self.server.reverse_sequence,
|
|
self.server.buy_sites,
|
|
self.server.block_military,
|
|
self.server.block_federated_endpoints)
|
|
if msg:
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/html', msglen,
|
|
cookie, calling_domain, False)
|
|
write2(self, msg)
|
|
else:
|
|
http_404(self, 105)
|
|
return True
|
|
return False
|
|
|
|
|
|
def _edit_links2(self, calling_domain: str, path: str,
|
|
translate: {}, base_dir: str,
|
|
domain: str, cookie: str, theme: str) -> bool:
|
|
"""Show the links from the left column
|
|
"""
|
|
if '/users/' in path and path.endswith('/editlinks'):
|
|
nickname = path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
|
|
access_keys = self.server.access_keys
|
|
if self.server.key_shortcuts.get(nickname):
|
|
access_keys = self.server.key_shortcuts[nickname]
|
|
|
|
msg = html_edit_links(translate,
|
|
base_dir,
|
|
path, domain,
|
|
self.server.default_timeline,
|
|
theme, access_keys)
|
|
if msg:
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/html', msglen,
|
|
cookie, calling_domain, False)
|
|
write2(self, msg)
|
|
else:
|
|
http_404(self, 106)
|
|
return True
|
|
return False
|
|
|
|
|
|
def _edit_newswire2(self, calling_domain: str, path: str,
|
|
translate: {}, base_dir: str,
|
|
domain: str, cookie: str) -> bool:
|
|
"""Show the newswire from the right column
|
|
"""
|
|
if '/users/' in path and path.endswith('/editnewswire'):
|
|
nickname = path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
|
|
access_keys = self.server.access_keys
|
|
if self.server.key_shortcuts.get(nickname):
|
|
access_keys = self.server.key_shortcuts[nickname]
|
|
|
|
msg = html_edit_newswire(translate,
|
|
base_dir,
|
|
path, domain,
|
|
self.server.default_timeline,
|
|
self.server.theme_name,
|
|
access_keys,
|
|
self.server.dogwhistles)
|
|
if msg:
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/html', msglen,
|
|
cookie, calling_domain, False)
|
|
write2(self, msg)
|
|
else:
|
|
http_404(self, 107)
|
|
return True
|
|
return False
|
|
|
|
|
|
def _edit_news_post2(self, calling_domain: str, path: str,
|
|
translate: {}, base_dir: str,
|
|
http_prefix: str, domain: str,
|
|
domain_full: str, cookie: str) -> bool:
|
|
"""Show the edit screen for a news post
|
|
"""
|
|
if '/users/' in path and '/editnewspost=' in path:
|
|
post_actor = 'news'
|
|
if '?actor=' in path:
|
|
post_actor = path.split('?actor=')[1]
|
|
if '?' in post_actor:
|
|
post_actor = post_actor.split('?')[0]
|
|
post_id = path.split('/editnewspost=')[1]
|
|
if '?' in post_id:
|
|
post_id = post_id.split('?')[0]
|
|
post_url = \
|
|
local_actor_url(http_prefix, post_actor, domain_full) + \
|
|
'/statuses/' + post_id
|
|
path = path.split('/editnewspost=')[0]
|
|
msg = html_edit_news_post(translate, base_dir,
|
|
path, domain,
|
|
post_url,
|
|
self.server.system_language)
|
|
if msg:
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/html', msglen,
|
|
cookie, calling_domain, False)
|
|
write2(self, msg)
|
|
else:
|
|
http_404(self, 108)
|
|
return True
|
|
return False
|
|
|
|
|
|
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,
|
|
curr_session) -> bool:
|
|
"""Shows the new post screen
|
|
"""
|
|
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 in_reply_to_url:
|
|
reply_interval_hours = self.server.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 self.server.debug:
|
|
print('Reply is within time interval: ' +
|
|
str(reply_interval_hours) + ' hours')
|
|
|
|
access_keys = self.server.access_keys
|
|
if self.server.key_shortcuts.get(nickname):
|
|
access_keys = self.server.key_shortcuts[nickname]
|
|
|
|
custom_submit_text = get_config_param(base_dir, 'customSubmitText')
|
|
|
|
default_post_language = self.server.system_language
|
|
if self.server.default_post_language.get(nickname):
|
|
default_post_language = \
|
|
self.server.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_language = reply_language
|
|
|
|
bold_reading = False
|
|
if self.server.bold_reading.get(nickname):
|
|
bold_reading = True
|
|
|
|
languages_understood = \
|
|
get_understood_languages(base_dir,
|
|
self.server.http_prefix,
|
|
nickname,
|
|
self.server.domain_full,
|
|
self.server.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,
|
|
self.server.default_timeline,
|
|
self.server.newswire,
|
|
self.server.theme_name,
|
|
no_drop_down, access_keys,
|
|
custom_submit_text,
|
|
conversation_id,
|
|
self.server.recent_posts_cache,
|
|
self.server.max_recent_posts,
|
|
curr_session,
|
|
self.server.cached_webfingers,
|
|
self.server.person_cache,
|
|
self.server.port,
|
|
post_json_object,
|
|
self.server.project_version,
|
|
self.server.yt_replace_domain,
|
|
self.server.twitter_replacement_domain,
|
|
self.server.show_published_date_only,
|
|
self.server.peertube_instances,
|
|
self.server.allow_local_network_access,
|
|
self.server.system_language,
|
|
languages_understood,
|
|
self.server.max_like_count,
|
|
self.server.signing_priv_key_pem,
|
|
self.server.cw_lists,
|
|
self.server.lists_enabled,
|
|
self.server.default_timeline,
|
|
reply_is_chat,
|
|
bold_reading,
|
|
self.server.dogwhistles,
|
|
self.server.min_images_for_accounts,
|
|
new_post_month, new_post_year,
|
|
default_post_language,
|
|
self.server.buy_sites,
|
|
default_buy_site,
|
|
self.server.auto_cw_cache)
|
|
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,
|
|
self.server.fitness,
|
|
'_GET', '_show_new_post',
|
|
self.server.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) -> 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:
|
|
pass
|
|
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)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_show_individual_at_post',
|
|
self.server.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) -> 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 self.server.bold_reading.get(nickname):
|
|
bold_reading = True
|
|
|
|
msg = \
|
|
html_likers_of_post(base_dir, nickname, domain, port,
|
|
post_url, self.server.translate,
|
|
http_prefix,
|
|
self.server.theme_name,
|
|
self.server.access_keys,
|
|
self.server.recent_posts_cache,
|
|
self.server.max_recent_posts,
|
|
curr_session,
|
|
self.server.cached_webfingers,
|
|
self.server.person_cache,
|
|
self.server.project_version,
|
|
self.server.yt_replace_domain,
|
|
self.server.twitter_replacement_domain,
|
|
self.server.show_published_date_only,
|
|
self.server.peertube_instances,
|
|
self.server.allow_local_network_access,
|
|
self.server.system_language,
|
|
self.server.max_like_count,
|
|
self.server.signing_priv_key_pem,
|
|
self.server.cw_lists,
|
|
self.server.lists_enabled,
|
|
'inbox', self.server.default_timeline,
|
|
bold_reading,
|
|
self.server.dogwhistles,
|
|
self.server.min_images_for_accounts,
|
|
self.server.buy_sites,
|
|
self.server.auto_cw_cache, 'likes')
|
|
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, self.server.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) -> 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 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,
|
|
post_url, self.server.translate,
|
|
http_prefix,
|
|
self.server.theme_name,
|
|
self.server.access_keys,
|
|
self.server.recent_posts_cache,
|
|
self.server.max_recent_posts,
|
|
curr_session,
|
|
self.server.cached_webfingers,
|
|
self.server.person_cache,
|
|
self.server.project_version,
|
|
self.server.yt_replace_domain,
|
|
self.server.twitter_replacement_domain,
|
|
self.server.show_published_date_only,
|
|
self.server.peertube_instances,
|
|
self.server.allow_local_network_access,
|
|
self.server.system_language,
|
|
self.server.max_like_count,
|
|
self.server.signing_priv_key_pem,
|
|
self.server.cw_lists,
|
|
self.server.lists_enabled,
|
|
'inbox', self.server.default_timeline,
|
|
bold_reading, self.server.dogwhistles,
|
|
self.server.min_images_for_accounts,
|
|
self.server.buy_sites,
|
|
self.server.auto_cw_cache,
|
|
'shares')
|
|
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, self.server.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) -> 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
|
|
context_str = \
|
|
'https://www.w3.org/ns/activitystreams'
|
|
|
|
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': context_str,
|
|
'first': first_str,
|
|
'id': id_str,
|
|
'last': last_str,
|
|
'totalItems': 0,
|
|
'type': 'OrderedCollection'
|
|
}
|
|
|
|
if request_http(self.headers, debug):
|
|
curr_session = \
|
|
establish_session("showRepliesToPost",
|
|
curr_session, proxy_type,
|
|
self.server)
|
|
if not curr_session:
|
|
http_404(self, 61)
|
|
return True
|
|
recent_posts_cache = self.server.recent_posts_cache
|
|
max_recent_posts = self.server.max_recent_posts
|
|
translate = self.server.translate
|
|
cached_webfingers = self.server.cached_webfingers
|
|
person_cache = self.server.person_cache
|
|
project_version = self.server.project_version
|
|
yt_domain = self.server.yt_replace_domain
|
|
twitter_replacement_domain = \
|
|
self.server.twitter_replacement_domain
|
|
peertube_instances = self.server.peertube_instances
|
|
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
|
|
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,
|
|
self.server.show_published_date_only,
|
|
peertube_instances,
|
|
self.server.allow_local_network_access,
|
|
self.server.theme_name,
|
|
self.server.system_language,
|
|
self.server.max_like_count,
|
|
self.server.signing_priv_key_pem,
|
|
self.server.cw_lists,
|
|
self.server.lists_enabled,
|
|
timezone, bold_reading,
|
|
self.server.dogwhistles,
|
|
self.server.min_images_for_accounts,
|
|
self.server.buy_sites,
|
|
self.server.auto_cw_cache)
|
|
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, self.server.fitness,
|
|
'_GET', '_show_replies_to_post',
|
|
debug)
|
|
else:
|
|
if secure_mode(curr_session, proxy_type, False,
|
|
self.server, self.headers, self.path):
|
|
msg_str = json.dumps(replies_json, ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str, http_prefix,
|
|
domain,
|
|
self.server.onion_domain,
|
|
self.server.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, self.server.fitness,
|
|
'_GET', '_show_replies_to_post json',
|
|
debug)
|
|
else:
|
|
http_404(self, 62)
|
|
return True
|
|
else:
|
|
# replies exist. Itterate through the
|
|
# text file containing message ids
|
|
context_str = 'https://www.w3.org/ns/activitystreams'
|
|
|
|
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': context_str,
|
|
'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("showRepliesToPost2",
|
|
curr_session, proxy_type,
|
|
self.server)
|
|
if not curr_session:
|
|
http_404(self, 63)
|
|
return True
|
|
recent_posts_cache = self.server.recent_posts_cache
|
|
max_recent_posts = self.server.max_recent_posts
|
|
translate = self.server.translate
|
|
cached_webfingers = self.server.cached_webfingers
|
|
person_cache = self.server.person_cache
|
|
project_version = self.server.project_version
|
|
yt_domain = self.server.yt_replace_domain
|
|
twitter_replacement_domain = \
|
|
self.server.twitter_replacement_domain
|
|
peertube_instances = self.server.peertube_instances
|
|
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
|
|
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,
|
|
self.server.show_published_date_only,
|
|
peertube_instances,
|
|
self.server.allow_local_network_access,
|
|
self.server.theme_name,
|
|
self.server.system_language,
|
|
self.server.max_like_count,
|
|
self.server.signing_priv_key_pem,
|
|
self.server.cw_lists,
|
|
self.server.lists_enabled,
|
|
timezone, bold_reading,
|
|
self.server.dogwhistles,
|
|
self.server.min_images_for_accounts,
|
|
self.server.buy_sites,
|
|
self.server.auto_cw_cache)
|
|
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, self.server.fitness,
|
|
'_GET', '_show_replies_to_post',
|
|
debug)
|
|
else:
|
|
if secure_mode(curr_session, proxy_type, False,
|
|
self.server, self.headers, self.path):
|
|
msg_str = json.dumps(replies_json, ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str, http_prefix,
|
|
domain,
|
|
self.server.onion_domain,
|
|
self.server.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, self.server.fitness,
|
|
'_GET', '_show_replies_to_post json',
|
|
debug)
|
|
else:
|
|
http_404(self, 64)
|
|
return True
|
|
return False
|
|
|
|
|
|
def _show_roles(self, calling_domain: str, referer_domain: str,
|
|
path: str, base_dir: str, http_prefix: str,
|
|
domain: str, getreq_start_time,
|
|
proxy_type: str, cookie: str, debug: str,
|
|
curr_session) -> bool:
|
|
"""Show roles within profile screen
|
|
"""
|
|
named_status = path.split('/users/')[1]
|
|
if '/' not in named_status:
|
|
return False
|
|
|
|
post_sections = named_status.split('/')
|
|
nickname = post_sections[0]
|
|
actor_filename = acct_dir(base_dir, nickname, domain) + '.json'
|
|
if not os.path.isfile(actor_filename):
|
|
return False
|
|
|
|
actor_json = load_json(actor_filename)
|
|
if not actor_json:
|
|
return False
|
|
|
|
if actor_json.get('hasOccupation'):
|
|
if request_http(self.headers, debug):
|
|
get_person = \
|
|
person_lookup(domain, path.replace('/roles', ''),
|
|
base_dir)
|
|
if get_person:
|
|
default_timeline = \
|
|
self.server.default_timeline
|
|
recent_posts_cache = \
|
|
self.server.recent_posts_cache
|
|
cached_webfingers = \
|
|
self.server.cached_webfingers
|
|
yt_replace_domain = \
|
|
self.server.yt_replace_domain
|
|
twitter_replacement_domain = \
|
|
self.server.twitter_replacement_domain
|
|
icons_as_buttons = \
|
|
self.server.icons_as_buttons
|
|
|
|
access_keys = self.server.access_keys
|
|
if self.server.key_shortcuts.get(nickname):
|
|
access_keys = self.server.key_shortcuts[nickname]
|
|
|
|
roles_list = get_actor_roles_list(actor_json)
|
|
city = \
|
|
get_spoofed_city(self.server.city,
|
|
base_dir, nickname, domain)
|
|
shared_items_federated_domains = \
|
|
self.server.shared_items_federated_domains
|
|
|
|
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
|
|
msg = \
|
|
html_profile(self.server.signing_priv_key_pem,
|
|
self.server.rss_icon_at_top,
|
|
icons_as_buttons,
|
|
default_timeline,
|
|
recent_posts_cache,
|
|
self.server.max_recent_posts,
|
|
self.server.translate,
|
|
self.server.project_version,
|
|
base_dir, http_prefix, True,
|
|
get_person, 'roles',
|
|
curr_session,
|
|
cached_webfingers,
|
|
self.server.person_cache,
|
|
yt_replace_domain,
|
|
twitter_replacement_domain,
|
|
self.server.show_published_date_only,
|
|
self.server.newswire,
|
|
self.server.theme_name,
|
|
self.server.dormant_months,
|
|
self.server.peertube_instances,
|
|
self.server.allow_local_network_access,
|
|
self.server.text_mode_banner,
|
|
self.server.debug,
|
|
access_keys, city,
|
|
self.server.system_language,
|
|
self.server.max_like_count,
|
|
shared_items_federated_domains,
|
|
roles_list,
|
|
None, None, self.server.cw_lists,
|
|
self.server.lists_enabled,
|
|
self.server.content_license_url,
|
|
timezone, bold_reading,
|
|
self.server.buy_sites, None,
|
|
self.server.max_shares_on_profile,
|
|
self.server.sites_unavailable,
|
|
self.server.no_of_books,
|
|
self.server.auto_cw_cache)
|
|
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, self.server.fitness,
|
|
'_GET', '_show_roles', debug)
|
|
else:
|
|
if secure_mode(curr_session, proxy_type, False,
|
|
self.server, self.headers, self.path):
|
|
roles_list = get_actor_roles_list(actor_json)
|
|
msg_str = json.dumps(roles_list, ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str, http_prefix,
|
|
domain,
|
|
self.server.onion_domain,
|
|
self.server.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, self.server.fitness,
|
|
'_GET', '_show_roles json', debug)
|
|
else:
|
|
http_404(self, 65)
|
|
return True
|
|
return False
|
|
|
|
|
|
def _show_skills(self, calling_domain: str, referer_domain: str,
|
|
path: str, base_dir: str, http_prefix: str,
|
|
domain: str, getreq_start_time, proxy_type: str,
|
|
cookie: str, debug: str, curr_session) -> bool:
|
|
"""Show skills on the profile screen
|
|
"""
|
|
named_status = path.split('/users/')[1]
|
|
if '/' in named_status:
|
|
post_sections = named_status.split('/')
|
|
nickname = post_sections[0]
|
|
actor_filename = acct_dir(base_dir, nickname, domain) + '.json'
|
|
if os.path.isfile(actor_filename):
|
|
actor_json = load_json(actor_filename)
|
|
if actor_json:
|
|
if no_of_actor_skills(actor_json) > 0:
|
|
if request_http(self.headers, self.server.debug):
|
|
get_person = \
|
|
person_lookup(domain,
|
|
path.replace('/skills', ''),
|
|
base_dir)
|
|
if get_person:
|
|
default_timeline = \
|
|
self.server.default_timeline
|
|
recent_posts_cache = \
|
|
self.server.recent_posts_cache
|
|
cached_webfingers = \
|
|
self.server.cached_webfingers
|
|
yt_replace_domain = \
|
|
self.server.yt_replace_domain
|
|
twitter_replacement_domain = \
|
|
self.server.twitter_replacement_domain
|
|
show_published_date_only = \
|
|
self.server.show_published_date_only
|
|
icons_as_buttons = \
|
|
self.server.icons_as_buttons
|
|
allow_local_network_access = \
|
|
self.server.allow_local_network_access
|
|
access_keys = self.server.access_keys
|
|
if self.server.key_shortcuts.get(nickname):
|
|
access_keys = \
|
|
self.server.key_shortcuts[nickname]
|
|
actor_skills_list = \
|
|
get_occupation_skills(actor_json)
|
|
skills = \
|
|
get_skills_from_list(actor_skills_list)
|
|
city = get_spoofed_city(self.server.city,
|
|
base_dir,
|
|
nickname, domain)
|
|
shared_items_fed_domains = \
|
|
self.server.shared_items_federated_domains
|
|
signing_priv_key_pem = \
|
|
self.server.signing_priv_key_pem
|
|
content_license_url = \
|
|
self.server.content_license_url
|
|
peertube_instances = \
|
|
self.server.peertube_instances
|
|
timezone = None
|
|
nick = nickname
|
|
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
|
|
max_shares_on_profile = \
|
|
self.server.max_shares_on_profile
|
|
msg = \
|
|
html_profile(signing_priv_key_pem,
|
|
self.server.rss_icon_at_top,
|
|
icons_as_buttons,
|
|
default_timeline,
|
|
recent_posts_cache,
|
|
self.server.max_recent_posts,
|
|
self.server.translate,
|
|
self.server.project_version,
|
|
base_dir, http_prefix, True,
|
|
get_person, 'skills',
|
|
curr_session,
|
|
cached_webfingers,
|
|
self.server.person_cache,
|
|
yt_replace_domain,
|
|
twitter_replacement_domain,
|
|
show_published_date_only,
|
|
self.server.newswire,
|
|
self.server.theme_name,
|
|
self.server.dormant_months,
|
|
peertube_instances,
|
|
allow_local_network_access,
|
|
self.server.text_mode_banner,
|
|
self.server.debug,
|
|
access_keys, city,
|
|
self.server.system_language,
|
|
self.server.max_like_count,
|
|
shared_items_fed_domains,
|
|
skills,
|
|
None, None,
|
|
self.server.cw_lists,
|
|
self.server.lists_enabled,
|
|
content_license_url,
|
|
timezone, bold_reading,
|
|
self.server.buy_sites,
|
|
None,
|
|
max_shares_on_profile,
|
|
self.server.sites_unavailable,
|
|
self.server.no_of_books,
|
|
self.server.auto_cw_cache)
|
|
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,
|
|
self.server.fitness,
|
|
'_GET', '_show_skills',
|
|
self.server.debug)
|
|
else:
|
|
if secure_mode(curr_session,
|
|
proxy_type, False,
|
|
self.server,
|
|
self.headers,
|
|
self.path):
|
|
actor_skills_list = \
|
|
get_occupation_skills(actor_json)
|
|
skills = \
|
|
get_skills_from_list(actor_skills_list)
|
|
msg_str = json.dumps(skills,
|
|
ensure_ascii=False)
|
|
onion_domain = self.server.onion_domain
|
|
i2p_domain = self.server.i2p_domain
|
|
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)
|
|
accept_str = self.headers['Accept']
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen, None,
|
|
calling_domain, False)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET',
|
|
'_show_skills json',
|
|
debug)
|
|
else:
|
|
http_404(self, 66)
|
|
return True
|
|
actor = path.replace('/skills', '')
|
|
actor_absolute = \
|
|
get_instance_url(calling_domain,
|
|
self.server.http_prefix,
|
|
self.server.domain_full,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain) + \
|
|
actor
|
|
redirect_headers(self, actor_absolute, cookie, calling_domain)
|
|
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) -> 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)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_show_notify_post',
|
|
self.server.debug)
|
|
return result
|
|
|
|
|
|
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) -> 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:
|
|
pass
|
|
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)
|
|
fitness_performance(getreq_start_time, self.server.fitness,
|
|
'_GET', '_show_individual_post',
|
|
self.server.debug)
|
|
return result
|
|
|
|
|
|
def _show_inbox(self, authorized: bool,
|
|
calling_domain: str, referer_domain: str,
|
|
path: str,
|
|
base_dir: str, http_prefix: str,
|
|
domain: str, port: int,
|
|
getreq_start_time,
|
|
cookie: str, debug: str,
|
|
recent_posts_cache: {}, curr_session,
|
|
default_timeline: str,
|
|
max_recent_posts: int,
|
|
translate: {},
|
|
cached_webfingers: {},
|
|
person_cache: {},
|
|
allow_deletion: bool,
|
|
project_version: str,
|
|
yt_replace_domain: str,
|
|
twitter_replacement_domain: str,
|
|
ua_str: str) -> bool:
|
|
"""Shows the inbox timeline
|
|
"""
|
|
if '/users/' in path:
|
|
if authorized:
|
|
inbox_feed = \
|
|
person_box_json(recent_posts_cache,
|
|
base_dir,
|
|
domain,
|
|
port,
|
|
path,
|
|
http_prefix,
|
|
MAX_POSTS_IN_FEED, 'inbox',
|
|
authorized,
|
|
0,
|
|
self.server.positive_voting,
|
|
self.server.voting_time_mins)
|
|
if inbox_feed:
|
|
if getreq_start_time:
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET', '_show_inbox',
|
|
self.server.debug)
|
|
if request_http(self.headers, debug):
|
|
nickname = path.replace('/users/', '')
|
|
nickname = nickname.replace('/inbox', '')
|
|
page_number = 1
|
|
if '?page=' in nickname:
|
|
page_number = nickname.split('?page=')[1]
|
|
if ';' in page_number:
|
|
page_number = page_number.split(';')[0]
|
|
nickname = nickname.split('?page=')[0]
|
|
if len(page_number) > 5:
|
|
page_number = "1"
|
|
if page_number.isdigit():
|
|
page_number = int(page_number)
|
|
else:
|
|
page_number = 1
|
|
if 'page=' not in path:
|
|
# if no page was specified then show the first
|
|
inbox_feed = \
|
|
person_box_json(recent_posts_cache,
|
|
base_dir,
|
|
domain,
|
|
port,
|
|
path + '?page=1',
|
|
http_prefix,
|
|
MAX_POSTS_IN_FEED, 'inbox',
|
|
authorized,
|
|
0,
|
|
self.server.positive_voting,
|
|
self.server.voting_time_mins)
|
|
if getreq_start_time:
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET', '_show_inbox2',
|
|
self.server.debug)
|
|
full_width_tl_button_header = \
|
|
self.server.full_width_tl_button_header
|
|
minimal_nick = is_minimal(base_dir, domain, nickname)
|
|
|
|
access_keys = self.server.access_keys
|
|
if self.server.key_shortcuts.get(nickname):
|
|
access_keys = \
|
|
self.server.key_shortcuts[nickname]
|
|
shared_items_federated_domains = \
|
|
self.server.shared_items_federated_domains
|
|
allow_local_network_access = \
|
|
self.server.allow_local_network_access
|
|
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
|
|
reverse_sequence = False
|
|
if nickname in self.server.reverse_sequence:
|
|
reverse_sequence = True
|
|
last_post_id = None
|
|
if ';lastpost=' in path:
|
|
last_post_id = path.split(';lastpost=')[1]
|
|
if ';' in last_post_id:
|
|
last_post_id = last_post_id.split(';')[0]
|
|
msg = \
|
|
html_inbox(default_timeline,
|
|
recent_posts_cache,
|
|
max_recent_posts,
|
|
translate,
|
|
page_number, MAX_POSTS_IN_FEED,
|
|
curr_session,
|
|
base_dir,
|
|
cached_webfingers,
|
|
person_cache,
|
|
nickname,
|
|
domain,
|
|
port,
|
|
inbox_feed,
|
|
allow_deletion,
|
|
http_prefix,
|
|
project_version,
|
|
minimal_nick,
|
|
yt_replace_domain,
|
|
twitter_replacement_domain,
|
|
self.server.show_published_date_only,
|
|
self.server.newswire,
|
|
self.server.positive_voting,
|
|
self.server.show_publish_as_icon,
|
|
full_width_tl_button_header,
|
|
self.server.icons_as_buttons,
|
|
self.server.rss_icon_at_top,
|
|
self.server.publish_button_at_top,
|
|
authorized,
|
|
self.server.theme_name,
|
|
self.server.peertube_instances,
|
|
allow_local_network_access,
|
|
self.server.text_mode_banner,
|
|
access_keys,
|
|
self.server.system_language,
|
|
self.server.max_like_count,
|
|
shared_items_federated_domains,
|
|
self.server.signing_priv_key_pem,
|
|
self.server.cw_lists,
|
|
self.server.lists_enabled,
|
|
timezone, bold_reading,
|
|
self.server.dogwhistles,
|
|
ua_str,
|
|
self.server.min_images_for_accounts,
|
|
reverse_sequence, last_post_id,
|
|
self.server.buy_sites,
|
|
self.server.auto_cw_cache)
|
|
if getreq_start_time:
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET', '_show_inbox3',
|
|
self.server.debug)
|
|
if msg:
|
|
msg_str = msg
|
|
onion_domain = self.server.onion_domain
|
|
i2p_domain = self.server.i2p_domain
|
|
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)
|
|
set_headers(self, 'text/html', msglen,
|
|
cookie, calling_domain, False)
|
|
write2(self, msg)
|
|
|
|
if getreq_start_time:
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET', '_show_inbox4',
|
|
self.server.debug)
|
|
else:
|
|
# don't need authorized fetch here because
|
|
# there is already the authorization check
|
|
onion_domain = self.server.onion_domain
|
|
i2p_domain = self.server.i2p_domain
|
|
msg_str = json.dumps(inbox_feed, 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)
|
|
accept_str = self.headers['Accept']
|
|
protocol_str = \
|
|
get_json_content_from_accept(accept_str)
|
|
set_headers(self, protocol_str, msglen,
|
|
None, calling_domain, False)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET', '_show_inbox5',
|
|
self.server.debug)
|
|
return True
|
|
else:
|
|
if debug:
|
|
nickname = path.replace('/users/', '')
|
|
nickname = nickname.replace('/inbox', '')
|
|
print('DEBUG: ' + nickname +
|
|
' was not authorized to access ' + path)
|
|
if path != '/inbox':
|
|
# not the shared inbox
|
|
if debug:
|
|
print('DEBUG: GET access to inbox is unauthorized')
|
|
self.send_response(405)
|
|
self.end_headers()
|
|
return True
|
|
return False
|
|
|
|
|
|
def _show_person_profile(self, authorized: bool,
|
|
calling_domain: str,
|
|
referer_domain: str, path: str,
|
|
base_dir: str, http_prefix: str,
|
|
domain: str,
|
|
onion_domain: str, i2p_domain: str,
|
|
getreq_start_time,
|
|
proxy_type: str, cookie: str,
|
|
debug: str,
|
|
curr_session) -> bool:
|
|
"""Shows the profile for a person
|
|
"""
|
|
# look up a person
|
|
actor_json = person_lookup(domain, path, base_dir)
|
|
if not actor_json:
|
|
return False
|
|
add_alternate_domains(actor_json, domain, onion_domain, i2p_domain)
|
|
if request_http(self.headers, debug):
|
|
curr_session = \
|
|
establish_session("showPersonProfile",
|
|
curr_session, proxy_type,
|
|
self.server)
|
|
if not curr_session:
|
|
http_404(self, 86)
|
|
return True
|
|
|
|
access_keys = self.server.access_keys
|
|
city = None
|
|
timezone = None
|
|
if '/users/' in path:
|
|
nickname = path.split('/users/')[1]
|
|
if '/' in nickname:
|
|
nickname = nickname.split('/')[0]
|
|
if self.server.key_shortcuts.get(nickname):
|
|
access_keys = \
|
|
self.server.key_shortcuts[nickname]
|
|
|
|
city = get_spoofed_city(self.server.city,
|
|
base_dir, nickname, domain)
|
|
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
|
|
max_shares_on_profile = \
|
|
self.server.max_shares_on_profile
|
|
sites_unavailable = \
|
|
self.server.sites_unavailable
|
|
msg = \
|
|
html_profile(self.server.signing_priv_key_pem,
|
|
self.server.rss_icon_at_top,
|
|
self.server.icons_as_buttons,
|
|
self.server.default_timeline,
|
|
self.server.recent_posts_cache,
|
|
self.server.max_recent_posts,
|
|
self.server.translate,
|
|
self.server.project_version,
|
|
base_dir, http_prefix, authorized,
|
|
actor_json, 'posts', curr_session,
|
|
self.server.cached_webfingers,
|
|
self.server.person_cache,
|
|
self.server.yt_replace_domain,
|
|
self.server.twitter_replacement_domain,
|
|
self.server.show_published_date_only,
|
|
self.server.newswire,
|
|
self.server.theme_name,
|
|
self.server.dormant_months,
|
|
self.server.peertube_instances,
|
|
self.server.allow_local_network_access,
|
|
self.server.text_mode_banner,
|
|
self.server.debug,
|
|
access_keys, city,
|
|
self.server.system_language,
|
|
self.server.max_like_count,
|
|
self.server.shared_items_federated_domains,
|
|
None, None, None,
|
|
self.server.cw_lists,
|
|
self.server.lists_enabled,
|
|
self.server.content_license_url,
|
|
timezone, bold_reading,
|
|
self.server.buy_sites,
|
|
None,
|
|
max_shares_on_profile,
|
|
sites_unavailable,
|
|
self.server.no_of_books,
|
|
self.server.auto_cw_cache).encode('utf-8')
|
|
msglen = len(msg)
|
|
set_headers(self, 'text/html', msglen,
|
|
cookie, calling_domain, False)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET', '_show_person_profile',
|
|
debug)
|
|
if self.server.debug:
|
|
print('DEBUG: html actor sent')
|
|
else:
|
|
if secure_mode(curr_session, proxy_type, False,
|
|
self.server, self.headers, self.path):
|
|
accept_str = self.headers['Accept']
|
|
msg_str = json.dumps(actor_json, ensure_ascii=False)
|
|
msg_str = convert_domains(calling_domain,
|
|
referer_domain,
|
|
msg_str, http_prefix,
|
|
domain,
|
|
self.server.onion_domain,
|
|
self.server.i2p_domain)
|
|
msg = msg_str.encode('utf-8')
|
|
msglen = len(msg)
|
|
if 'application/ld+json' in accept_str:
|
|
set_headers(self, 'application/ld+json', msglen,
|
|
cookie, calling_domain, False)
|
|
elif 'application/jrd+json' in accept_str:
|
|
set_headers(self, 'application/jrd+json', msglen,
|
|
cookie, calling_domain, False)
|
|
else:
|
|
set_headers(self, 'application/activity+json', msglen,
|
|
cookie, calling_domain, False)
|
|
write2(self, msg)
|
|
fitness_performance(getreq_start_time,
|
|
self.server.fitness,
|
|
'_GET', '_show_person_profile json',
|
|
self.server.debug)
|
|
if self.server.debug:
|
|
print('DEBUG: json actor sent')
|
|
else:
|
|
http_404(self, 87)
|
|
return True
|
|
|
|
|
|
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) -> 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
|
|
|
|
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 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.recent_posts_cache,
|
|
self.server.max_recent_posts,
|
|
self.server.translate,
|
|
base_dir,
|
|
curr_session,
|
|
self.server.cached_webfingers,
|
|
self.server.person_cache,
|
|
nickname, domain, port,
|
|
authorized,
|
|
post_json_object,
|
|
http_prefix,
|
|
self.server.project_version,
|
|
liked_by, react_by, react_emoji,
|
|
self.server.yt_replace_domain,
|
|
self.server.twitter_replacement_domain,
|
|
self.server.show_published_date_only,
|
|
self.server.peertube_instances,
|
|
self.server.allow_local_network_access,
|
|
self.server.theme_name,
|
|
self.server.system_language,
|
|
self.server.max_like_count,
|
|
self.server.signing_priv_key_pem,
|
|
self.server.cw_lists,
|
|
self.server.lists_enabled,
|
|
timezone, mitm, bold_reading,
|
|
self.server.dogwhistles,
|
|
self.server.min_images_for_accounts,
|
|
self.server.buy_sites,
|
|
self.server.auto_cw_cache)
|
|
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, self.server.fitness,
|
|
'_GET', '_show_post_from_file',
|
|
debug)
|
|
else:
|
|
if secure_mode(curr_session, proxy_type, False,
|
|
self.server, self.headers, self.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,
|
|
self.server.onion_domain,
|
|
self.server.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, self.server.fitness,
|
|
'_GET', '_show_post_from_file json',
|
|
debug)
|
|
else:
|
|
http_404(self, 73)
|
|
self.server.getreq_busy = False
|
|
return True
|