Merge branch 'main' of gitlab.com:bashrc2/epicyon

main
Bob Mottram 2022-03-14 13:48:10 +00:00
commit c869ccfad8
22 changed files with 477 additions and 205 deletions

View File

@ -76,7 +76,9 @@ def create_reject(base_dir: str, federation_list: [],
def _accept_follow(base_dir: str, domain: str, message_json: {}, def _accept_follow(base_dir: str, domain: str, message_json: {},
federation_list: [], debug: bool) -> None: federation_list: [], debug: bool,
curr_domain: str,
onion_domain: str, i2p_domain: str) -> None:
"""Receiving a follow Accept activity """Receiving a follow Accept activity
""" """
if not has_object_stringType(message_json, debug): if not has_object_stringType(message_json, debug):
@ -144,6 +146,16 @@ def _accept_follow(base_dir: str, domain: str, message_json: {},
followed_actor) followed_actor)
return return
# convert from onion/i2p to clearnet accepted domain
if onion_domain:
if accepted_domain.endswith('.onion') and \
not curr_domain.endswith('.onion'):
accepted_domain = curr_domain
if i2p_domain:
if accepted_domain.endswith('.i2p') and \
not curr_domain.endswith('.i2p'):
accepted_domain = curr_domain
accepted_domain_full = accepted_domain accepted_domain_full = accepted_domain
if accepted_port: if accepted_port:
accepted_domain_full = accepted_domain + ':' + str(accepted_port) accepted_domain_full = accepted_domain + ':' + str(accepted_port)
@ -189,7 +201,9 @@ def receive_accept_reject(session, base_dir: str,
cached_webfingers: {}, cached_webfingers: {},
person_cache: {}, message_json: {}, person_cache: {}, message_json: {},
federation_list: [], federation_list: [],
debug: bool) -> bool: debug: bool,
curr_domain: str,
onion_domain: str, i2p_domain: str) -> bool:
"""Receives an Accept or Reject within the POST section of HTTPServer """Receives an Accept or Reject within the POST section of HTTPServer
""" """
if message_json['type'] != 'Accept' and message_json['type'] != 'Reject': if message_json['type'] != 'Accept' and message_json['type'] != 'Reject':
@ -215,7 +229,8 @@ def receive_accept_reject(session, base_dir: str,
' does not contain a nickname. ' + ' does not contain a nickname. ' +
'Assuming single user instance.') 'Assuming single user instance.')
# receive follow accept # receive follow accept
_accept_follow(base_dir, domain, message_json, federation_list, debug) _accept_follow(base_dir, domain, message_json, federation_list, debug,
curr_domain, onion_domain, i2p_domain)
if debug: if debug:
print('DEBUG: Uh, ' + message_json['type'] + ', I guess') print('DEBUG: Uh, ' + message_json['type'] + ', I guess')
return True return True

View File

@ -141,7 +141,9 @@ def create_announce(session, base_dir: str, federation_list: [],
send_threads: [], postLog: [], send_threads: [], postLog: [],
person_cache: {}, cached_webfingers: {}, person_cache: {}, cached_webfingers: {},
debug: bool, project_version: str, debug: bool, project_version: str,
signing_priv_key_pem: str) -> {}: signing_priv_key_pem: str,
curr_domain: str,
onion_domain: str, i2p_domain: str) -> {}:
"""Creates an announce message """Creates an announce message
Typically to_url will be https://www.w3.org/ns/activitystreams#Public Typically to_url will be https://www.w3.org/ns/activitystreams#Public
and ccUrl might be a specific person favorited or repeated and the and ccUrl might be a specific person favorited or repeated and the
@ -202,7 +204,8 @@ def create_announce(session, base_dir: str, federation_list: [],
send_threads, postLog, cached_webfingers, send_threads, postLog, cached_webfingers,
person_cache, person_cache,
debug, project_version, None, group_account, debug, project_version, None, group_account,
signing_priv_key_pem, 639633) signing_priv_key_pem, 639633,
curr_domain, onion_domain, i2p_domain)
return new_announce return new_announce
@ -213,7 +216,9 @@ def announce_public(session, base_dir: str, federation_list: [],
send_threads: [], postLog: [], send_threads: [], postLog: [],
person_cache: {}, cached_webfingers: {}, person_cache: {}, cached_webfingers: {},
debug: bool, project_version: str, debug: bool, project_version: str,
signing_priv_key_pem: str) -> {}: signing_priv_key_pem: str,
curr_domain: str,
onion_domain: str, i2p_domain: str) -> {}:
"""Makes a public announcement """Makes a public announcement
""" """
from_domain = get_full_domain(domain, port) from_domain = get_full_domain(domain, port)
@ -227,7 +232,8 @@ def announce_public(session, base_dir: str, federation_list: [],
send_threads, postLog, send_threads, postLog,
person_cache, cached_webfingers, person_cache, cached_webfingers,
debug, project_version, debug, project_version,
signing_priv_key_pem) signing_priv_key_pem, curr_domain,
onion_domain, i2p_domain)
def send_announce_via_server(base_dir: str, session, def send_announce_via_server(base_dir: str, session,

View File

@ -1479,7 +1479,9 @@ class PubServer(BaseHTTPRequestHandler):
str(self.server.base_dir)) str(self.server.base_dir))
wf_result = \ wf_result = \
webfinger_lookup(self.path, self.server.base_dir, webfinger_lookup(self.path, self.server.base_dir,
self.server.domain, self.server.onion_domain, self.server.domain,
self.server.onion_domain,
self.server.i2p_domain,
self.server.port, self.server.debug) self.server.port, self.server.debug)
if wf_result: if wf_result:
msg_str = json.dumps(wf_result) msg_str = json.dumps(wf_result)
@ -1605,6 +1607,7 @@ class PubServer(BaseHTTPRequestHandler):
print('Creating outbox thread ' + print('Creating outbox thread ' +
account_outbox_thread_name + '/' + account_outbox_thread_name + '/' +
str(self.server.outbox_thread_index[account_outbox_thread_name])) str(self.server.outbox_thread_index[account_outbox_thread_name]))
print('THREAD: _post_to_outbox')
self.server.outboxThread[account_outbox_thread_name][index] = \ self.server.outboxThread[account_outbox_thread_name][index] = \
thread_with_trace(target=self._post_to_outbox, thread_with_trace(target=self._post_to_outbox,
args=(message_json.copy(), args=(message_json.copy(),
@ -3374,18 +3377,30 @@ class PubServer(BaseHTTPRequestHandler):
curr_domain = domain curr_domain = domain
curr_port = port curr_port = port
curr_http_prefix = http_prefix curr_http_prefix = http_prefix
curr_proxy_type = proxy_type
if onion_domain: if onion_domain:
if following_domain.endswith('.onion'): if not curr_domain.endswith('.onion') and \
following_domain.endswith('.onion'):
curr_session = self.server.session_onion curr_session = self.server.session_onion
curr_domain = onion_domain curr_domain = onion_domain
curr_port = 80 curr_port = 80
following_port = 80
curr_http_prefix = 'http' curr_http_prefix = 'http'
curr_proxy_type = 'tor'
if i2p_domain: if i2p_domain:
if following_domain.endswith('.i2p'): if not curr_domain.endswith('.i2p') and \
following_domain.endswith('.i2p'):
curr_session = self.server.session_i2p curr_session = self.server.session_i2p
curr_domain = i2p_domain curr_domain = i2p_domain
curr_port = 80 curr_port = 80
following_port = 80
curr_http_prefix = 'http' curr_http_prefix = 'http'
curr_proxy_type = 'i2p'
curr_session = \
self._establish_session("follow request",
curr_session,
curr_proxy_type)
send_follow_request(curr_session, send_follow_request(curr_session,
base_dir, follower_nickname, base_dir, follower_nickname,
@ -3401,7 +3416,10 @@ class PubServer(BaseHTTPRequestHandler):
self.server.cached_webfingers, self.server.cached_webfingers,
self.server.person_cache, debug, self.server.person_cache, debug,
self.server.project_version, self.server.project_version,
self.server.signing_priv_key_pem) self.server.signing_priv_key_pem,
self.server.domain,
self.server.onion_domain,
self.server.i2p_domain)
if calling_domain.endswith('.onion') and onion_domain: if calling_domain.endswith('.onion') and onion_domain:
origin_path_str = 'http://' + onion_domain + users_path origin_path_str = 'http://' + onion_domain + users_path
elif (calling_domain.endswith('.i2p') and i2p_domain): elif (calling_domain.endswith('.i2p') and i2p_domain):
@ -8295,7 +8313,10 @@ class PubServer(BaseHTTPRequestHandler):
self.server.cached_webfingers, self.server.cached_webfingers,
debug, debug,
self.server.project_version, self.server.project_version,
self.server.signing_priv_key_pem) self.server.signing_priv_key_pem,
self.server.domain,
self.server.onion_domain,
self.server.i2p_domain)
announce_filename = None announce_filename = None
if announce_json: if announce_json:
# save the announce straight to the outbox # save the announce straight to the outbox
@ -8519,25 +8540,28 @@ class PubServer(BaseHTTPRequestHandler):
handle_nickname + '@' + \ handle_nickname + '@' + \
get_full_domain(handle_domain, handle_port) get_full_domain(handle_domain, handle_port)
if '@' in following_handle: if '@' in following_handle:
if self.server.onion_domain: if self.server.onion_domain:
if following_handle.endswith('.onion'): if following_handle.endswith('.onion'):
curr_session = self.server.session_onion curr_session = self.server.session_onion
proxy_type = 'tor' proxy_type = 'tor'
port = 80
if self.server.i2p_domain: if self.server.i2p_domain:
if following_handle.endswith('.i2p'): if following_handle.endswith('.i2p'):
curr_session = self.server.session_i2p curr_session = self.server.session_i2p
proxy_type = 'i2p' proxy_type = 'i2p'
port = 80
curr_session = \ curr_session = \
self._establish_session("followApproveButton", self._establish_session("follow_approve_button",
curr_session, proxy_type) curr_session, proxy_type)
if not curr_session: if not curr_session:
print('WARN: unable to establish session ' +
'when approving follow request')
self._404() self._404()
return return
signing_priv_key_pem = \ signing_priv_key_pem = \
self.server.signing_priv_key_pem self.server.signing_priv_key_pem
manual_approve_follow_request_thread(curr_session, manual_approve_follow_request_thread(self.server.session,
self.server.session_onion, self.server.session_onion,
self.server.session_i2p, self.server.session_i2p,
self.server.onion_domain, self.server.onion_domain,
@ -8553,7 +8577,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.person_cache, self.server.person_cache,
debug, debug,
self.server.project_version, self.server.project_version,
signing_priv_key_pem) signing_priv_key_pem,
proxy_type)
origin_path_str_absolute = \ origin_path_str_absolute = \
http_prefix + '://' + domain_full + origin_path_str http_prefix + '://' + domain_full + origin_path_str
if calling_domain.endswith('.onion') and onion_domain: if calling_domain.endswith('.onion') and onion_domain:
@ -8701,7 +8726,7 @@ class PubServer(BaseHTTPRequestHandler):
handle_nickname + '@' + \ handle_nickname + '@' + \
get_full_domain(handle_domain, handle_port) get_full_domain(handle_domain, handle_port)
if '@' in following_handle: if '@' in following_handle:
manual_deny_follow_request_thread(curr_session, manual_deny_follow_request_thread(self.server.session,
self.server.session_onion, self.server.session_onion,
self.server.session_i2p, self.server.session_i2p,
self.server.onion_domain, self.server.onion_domain,
@ -20184,7 +20209,7 @@ def run_shares_expire(version_number: str, base_dir: str) -> None:
def run_posts_watchdog(project_version: str, httpd) -> None: def run_posts_watchdog(project_version: str, httpd) -> None:
"""This tries to keep the posts thread running even if it dies """This tries to keep the posts thread running even if it dies
""" """
print('Starting posts queue watchdog') print('THREAD: Starting posts queue watchdog')
posts_queue_original = httpd.thrPostsQueue.clone(run_posts_queue) posts_queue_original = httpd.thrPostsQueue.clone(run_posts_queue)
httpd.thrPostsQueue.start() httpd.thrPostsQueue.start()
while True: while True:
@ -20192,6 +20217,7 @@ def run_posts_watchdog(project_version: str, httpd) -> None:
if httpd.thrPostsQueue.is_alive(): if httpd.thrPostsQueue.is_alive():
continue continue
httpd.thrPostsQueue.kill() httpd.thrPostsQueue.kill()
print('THREAD: restarting posts queue')
httpd.thrPostsQueue = posts_queue_original.clone(run_posts_queue) httpd.thrPostsQueue = posts_queue_original.clone(run_posts_queue)
httpd.thrPostsQueue.start() httpd.thrPostsQueue.start()
print('Restarting posts queue...') print('Restarting posts queue...')
@ -20200,7 +20226,7 @@ def run_posts_watchdog(project_version: str, httpd) -> None:
def run_shares_expire_watchdog(project_version: str, httpd) -> None: def run_shares_expire_watchdog(project_version: str, httpd) -> None:
"""This tries to keep the shares expiry thread running even if it dies """This tries to keep the shares expiry thread running even if it dies
""" """
print('Starting shares expiry watchdog') print('THREAD: Starting shares expiry watchdog')
shares_expire_original = httpd.thrSharesExpire.clone(run_shares_expire) shares_expire_original = httpd.thrSharesExpire.clone(run_shares_expire)
httpd.thrSharesExpire.start() httpd.thrSharesExpire.start()
while True: while True:
@ -20208,6 +20234,7 @@ def run_shares_expire_watchdog(project_version: str, httpd) -> None:
if httpd.thrSharesExpire.is_alive(): if httpd.thrSharesExpire.is_alive():
continue continue
httpd.thrSharesExpire.kill() httpd.thrSharesExpire.kill()
print('THREAD: restarting shares watchdog')
httpd.thrSharesExpire = shares_expire_original.clone(run_shares_expire) httpd.thrSharesExpire = shares_expire_original.clone(run_shares_expire)
httpd.thrSharesExpire.start() httpd.thrSharesExpire.start()
print('Restarting shares expiry...') print('Restarting shares expiry...')
@ -20688,13 +20715,13 @@ def run_daemon(crawlers_allowed: [],
print('Creating shared item files directory') print('Creating shared item files directory')
os.mkdir(base_dir + '/sharefiles') os.mkdir(base_dir + '/sharefiles')
print('Creating fitness thread') print('THREAD: Creating fitness thread')
httpd.thrFitness = \ httpd.thrFitness = \
thread_with_trace(target=fitness_thread, thread_with_trace(target=fitness_thread,
args=(base_dir, httpd.fitness), daemon=True) args=(base_dir, httpd.fitness), daemon=True)
httpd.thrFitness.start() httpd.thrFitness.start()
print('Creating cache expiry thread') print('THREAD: Creating cache expiry thread')
httpd.thrCache = \ httpd.thrCache = \
thread_with_trace(target=expire_cache, thread_with_trace(target=expire_cache,
args=(base_dir, httpd.person_cache, args=(base_dir, httpd.person_cache,
@ -20706,12 +20733,13 @@ def run_daemon(crawlers_allowed: [],
# number of mins after which sending posts or updates will expire # number of mins after which sending posts or updates will expire
httpd.send_threads_timeout_mins = send_threads_timeout_mins httpd.send_threads_timeout_mins = send_threads_timeout_mins
print('Creating posts queue') print('THREAD: Creating posts queue')
httpd.thrPostsQueue = \ httpd.thrPostsQueue = \
thread_with_trace(target=run_posts_queue, thread_with_trace(target=run_posts_queue,
args=(base_dir, httpd.send_threads, debug, args=(base_dir, httpd.send_threads, debug,
httpd.send_threads_timeout_mins), daemon=True) httpd.send_threads_timeout_mins), daemon=True)
if not unit_test: if not unit_test:
print('THREAD: run_posts_watchdog')
httpd.thrPostsWatchdog = \ httpd.thrPostsWatchdog = \
thread_with_trace(target=run_posts_watchdog, thread_with_trace(target=run_posts_watchdog,
args=(project_version, httpd), daemon=True) args=(project_version, httpd), daemon=True)
@ -20719,11 +20747,12 @@ def run_daemon(crawlers_allowed: [],
else: else:
httpd.thrPostsQueue.start() httpd.thrPostsQueue.start()
print('Creating expire thread for shared items') print('THREAD: Creating expire thread for shared items')
httpd.thrSharesExpire = \ httpd.thrSharesExpire = \
thread_with_trace(target=run_shares_expire, thread_with_trace(target=run_shares_expire,
args=(project_version, base_dir), daemon=True) args=(project_version, base_dir), daemon=True)
if not unit_test: if not unit_test:
print('THREAD: run_shares_expire_watchdog')
httpd.thrSharesExpireWatchdog = \ httpd.thrSharesExpireWatchdog = \
thread_with_trace(target=run_shares_expire_watchdog, thread_with_trace(target=run_shares_expire_watchdog,
args=(project_version, httpd), daemon=True) args=(project_version, httpd), daemon=True)
@ -20752,10 +20781,10 @@ def run_daemon(crawlers_allowed: [],
create_initial_last_seen(base_dir, http_prefix) create_initial_last_seen(base_dir, http_prefix)
print('Creating inbox queue') print('THREAD: Creating inbox queue')
httpd.thrInboxQueue = \ httpd.thrInboxQueue = \
thread_with_trace(target=run_inbox_queue, thread_with_trace(target=run_inbox_queue,
args=(httpd.recent_posts_cache, args=(httpd, httpd.recent_posts_cache,
httpd.max_recent_posts, httpd.max_recent_posts,
project_version, project_version,
base_dir, http_prefix, httpd.send_threads, base_dir, http_prefix, httpd.send_threads,
@ -20784,19 +20813,19 @@ def run_daemon(crawlers_allowed: [],
httpd.default_reply_interval_hrs, httpd.default_reply_interval_hrs,
httpd.cw_lists), daemon=True) httpd.cw_lists), daemon=True)
print('Creating scheduled post thread') print('THREAD: Creating scheduled post thread')
httpd.thrPostSchedule = \ httpd.thrPostSchedule = \
thread_with_trace(target=run_post_schedule, thread_with_trace(target=run_post_schedule,
args=(base_dir, httpd, 20), daemon=True) args=(base_dir, httpd, 20), daemon=True)
print('Creating newswire thread') print('THREAD: Creating newswire thread')
httpd.thrNewswireDaemon = \ httpd.thrNewswireDaemon = \
thread_with_trace(target=run_newswire_daemon, thread_with_trace(target=run_newswire_daemon,
args=(base_dir, httpd, args=(base_dir, httpd,
http_prefix, domain, port, http_prefix, domain, port,
httpd.translate), daemon=True) httpd.translate), daemon=True)
print('Creating federated shares thread') print('THREAD: Creating federated shares thread')
httpd.thrFederatedSharesDaemon = \ httpd.thrFederatedSharesDaemon = \
thread_with_trace(target=run_federated_shares_daemon, thread_with_trace(target=run_federated_shares_daemon,
args=(base_dir, httpd, args=(base_dir, httpd,
@ -20818,25 +20847,25 @@ def run_daemon(crawlers_allowed: [],
httpd.signing_priv_key_pem = get_instance_actor_key(base_dir, domain) httpd.signing_priv_key_pem = get_instance_actor_key(base_dir, domain)
if not unit_test: if not unit_test:
print('Creating inbox queue watchdog') print('THREAD: Creating inbox queue watchdog')
httpd.thrWatchdog = \ httpd.thrWatchdog = \
thread_with_trace(target=run_inbox_queue_watchdog, thread_with_trace(target=run_inbox_queue_watchdog,
args=(project_version, httpd), daemon=True) args=(project_version, httpd), daemon=True)
httpd.thrWatchdog.start() httpd.thrWatchdog.start()
print('Creating scheduled post watchdog') print('THREAD: Creating scheduled post watchdog')
httpd.thrWatchdogSchedule = \ httpd.thrWatchdogSchedule = \
thread_with_trace(target=run_post_schedule_watchdog, thread_with_trace(target=run_post_schedule_watchdog,
args=(project_version, httpd), daemon=True) args=(project_version, httpd), daemon=True)
httpd.thrWatchdogSchedule.start() httpd.thrWatchdogSchedule.start()
print('Creating newswire watchdog') print('THREAD: Creating newswire watchdog')
httpd.thrNewswireWatchdog = \ httpd.thrNewswireWatchdog = \
thread_with_trace(target=run_newswire_watchdog, thread_with_trace(target=run_newswire_watchdog,
args=(project_version, httpd), daemon=True) args=(project_version, httpd), daemon=True)
httpd.thrNewswireWatchdog.start() httpd.thrNewswireWatchdog.start()
print('Creating federated shares watchdog') print('THREAD: Creating federated shares watchdog')
httpd.thrFederatedSharesWatchdog = \ httpd.thrFederatedSharesWatchdog = \
thread_with_trace(target=run_federated_shares_watchdog, thread_with_trace(target=run_federated_shares_watchdog,
args=(project_version, httpd), daemon=True) args=(project_version, httpd), daemon=True)

View File

@ -38,7 +38,7 @@ from follow import deny_follow_request_via_server
from follow import get_follow_requests_via_server from follow import get_follow_requests_via_server
from follow import get_following_via_server from follow import get_following_via_server
from follow import get_followers_via_server from follow import get_followers_via_server
from follow import send_follow_requestViaServer from follow import send_follow_request_via_server
from follow import send_unfollow_request_via_server from follow import send_unfollow_request_via_server
from posts import send_block_via_server from posts import send_block_via_server
from posts import send_undo_block_via_server from posts import send_undo_block_via_server
@ -2265,18 +2265,18 @@ def run_desktop_client(base_dir: str, proxy_type: str, http_prefix: str,
_say_command(say_str, say_str, _say_command(say_str, say_str,
screenreader, system_language, espeak) screenreader, system_language, espeak)
session_follow = create_session(proxy_type) session_follow = create_session(proxy_type)
send_follow_requestViaServer(base_dir, send_follow_request_via_server(base_dir,
session_follow, session_follow,
nickname, password, nickname, password,
domain, port, domain, port,
follow_nickname, follow_nickname,
follow_domain, follow_domain,
follow_port, follow_port,
http_prefix, http_prefix,
cached_webfingers, cached_webfingers,
person_cache, person_cache,
debug, __version__, debug, __version__,
signing_priv_key_pem) signing_priv_key_pem)
else: else:
if follow_handle: if follow_handle:
say_str = follow_handle + ' is not valid' say_str = follow_handle + ' is not valid'

View File

@ -56,7 +56,7 @@ from follow import get_following_via_server
from follow import get_followers_via_server from follow import get_followers_via_server
from follow import clear_follows from follow import clear_follows
from follow import add_follower_of_person from follow import add_follower_of_person
from follow import send_follow_requestViaServer from follow import send_follow_request_via_server
from follow import send_unfollow_request_via_server from follow import send_unfollow_request_via_server
from tests import test_shared_items_federation from tests import test_shared_items_federation
from tests import test_group_follow from tests import test_group_follow
@ -1293,7 +1293,7 @@ if args.approve:
send_threads, postLog, send_threads, postLog,
cached_webfingers, person_cache, cached_webfingers, person_cache,
debug, __version__, debug, __version__,
signing_priv_key_pem) signing_priv_key_pem, proxy_type)
sys.exit() sys.exit()
if args.deny: if args.deny:
@ -2067,13 +2067,13 @@ if args.follow:
if args.secure_mode: if args.secure_mode:
signing_priv_key_pem = get_instance_actor_key(base_dir, domain) signing_priv_key_pem = get_instance_actor_key(base_dir, domain)
send_follow_requestViaServer(base_dir, session, send_follow_request_via_server(base_dir, session,
args.nickname, args.password, args.nickname, args.password,
domain, port, domain, port,
follow_nickname, follow_domain, follow_port, follow_nickname, follow_domain, follow_port,
follow_http_prefix, follow_http_prefix,
cached_webfingers, person_cache, cached_webfingers, person_cache,
debug, __version__, signing_priv_key_pem) debug, __version__, signing_priv_key_pem)
for t in range(20): for t in range(20):
time.sleep(1) time.sleep(1)
# TODO some method to know if it worked # TODO some method to know if it worked

View File

@ -108,8 +108,8 @@ def _remove_from_follow_base(base_dir: str,
approve_follows_filename = accounts_dir + '/' + follow_file + '.txt' approve_follows_filename = accounts_dir + '/' + follow_file + '.txt'
if not os.path.isfile(approve_follows_filename): if not os.path.isfile(approve_follows_filename):
if debug: if debug:
print('WARN: Approve follow requests file ' + print('There is no ' + follow_file +
approve_follows_filename + ' not found') ' to remove ' + handle + ' from')
return return
accept_deny_actor = None accept_deny_actor = None
if accept_or_deny_handle not in open(approve_follows_filename).read(): if accept_or_deny_handle not in open(approve_follows_filename).read():
@ -731,7 +731,9 @@ def followed_account_accepts(session, base_dir: str, http_prefix: str,
cached_webfingers: {}, person_cache: {}, cached_webfingers: {}, person_cache: {},
debug: bool, project_version: str, debug: bool, project_version: str,
removeFollowActivity: bool, removeFollowActivity: bool,
signing_priv_key_pem: str): signing_priv_key_pem: str,
curr_domain: str,
onion_domain: str, i2p_domain: str):
"""The person receiving a follow request accepts the new follower """The person receiving a follow request accepts the new follower
and sends back an Accept activity and sends back an Accept activity
""" """
@ -780,10 +782,12 @@ def followed_account_accepts(session, base_dir: str, http_prefix: str,
send_threads, postLog, cached_webfingers, send_threads, postLog, cached_webfingers,
person_cache, debug, project_version, None, person_cache, debug, project_version, None,
group_account, signing_priv_key_pem, group_account, signing_priv_key_pem,
7856837) 7856837, curr_domain, onion_domain, i2p_domain)
def followed_account_rejects(session, base_dir: str, http_prefix: str, def followed_account_rejects(session, session_onion, session_i2p,
onion_domain: str, i2p_domain: str,
base_dir: str, http_prefix: str,
nickname_to_follow: str, domain_to_follow: str, nickname_to_follow: str, domain_to_follow: str,
port: int, port: int,
nickname: str, domain: str, from_port: int, nickname: str, domain: str, from_port: int,
@ -848,7 +852,8 @@ def followed_account_rejects(session, base_dir: str, http_prefix: str,
send_threads, postLog, cached_webfingers, send_threads, postLog, cached_webfingers,
person_cache, debug, project_version, None, person_cache, debug, project_version, None,
group_account, signing_priv_key_pem, group_account, signing_priv_key_pem,
6393063) 6393063,
domain, onion_domain, i2p_domain)
def send_follow_request(session, base_dir: str, def send_follow_request(session, base_dir: str,
@ -861,7 +866,9 @@ def send_follow_request(session, base_dir: str,
client_to_server: bool, federation_list: [], client_to_server: bool, federation_list: [],
send_threads: [], postLog: [], cached_webfingers: {}, send_threads: [], postLog: [], cached_webfingers: {},
person_cache: {}, debug: bool, person_cache: {}, debug: bool,
project_version: str, signing_priv_key_pem: str) -> {}: project_version: str, signing_priv_key_pem: str,
curr_domain: str,
onion_domain: str, i2p_domain: str) -> {}:
"""Gets the json object for sending a follow request """Gets the json object for sending a follow request
""" """
if not signing_priv_key_pem: if not signing_priv_key_pem:
@ -942,24 +949,25 @@ def send_follow_request(session, base_dir: str,
federation_list, federation_list,
send_threads, postLog, cached_webfingers, person_cache, send_threads, postLog, cached_webfingers, person_cache,
debug, project_version, None, group_account, debug, project_version, None, group_account,
signing_priv_key_pem, 8234389) signing_priv_key_pem, 8234389,
curr_domain, onion_domain, i2p_domain)
return new_follow_json return new_follow_json
def send_follow_requestViaServer(base_dir: str, session, def send_follow_request_via_server(base_dir: str, session,
from_nickname: str, password: str, from_nickname: str, password: str,
from_domain: str, from_port: int, from_domain: str, from_port: int,
follow_nickname: str, follow_domain: str, follow_nickname: str, follow_domain: str,
followPort: int, followPort: int,
http_prefix: str, http_prefix: str,
cached_webfingers: {}, person_cache: {}, cached_webfingers: {}, person_cache: {},
debug: bool, project_version: str, debug: bool, project_version: str,
signing_priv_key_pem: str) -> {}: signing_priv_key_pem: str) -> {}:
"""Creates a follow request via c2s """Creates a follow request via c2s
""" """
if not session: if not session:
print('WARN: No session for send_follow_requestViaServer') print('WARN: No session for send_follow_request_via_server')
return 6 return 6
from_domain_full = get_full_domain(from_domain, from_port) from_domain_full = get_full_domain(from_domain, from_port)

165
inbox.py
View File

@ -606,7 +606,8 @@ def save_post_to_inbox_queue(base_dir: str, http_prefix: str,
def _inbox_post_recipients_add(base_dir: str, http_prefix: str, toList: [], def _inbox_post_recipients_add(base_dir: str, http_prefix: str, toList: [],
recipients_dict: {}, recipients_dict: {},
domain_match: str, domain: str, domain_match: str, domain: str,
actor: str, debug: bool) -> bool: actor: str, debug: bool,
onion_domain: str, i2p_domain: str) -> bool:
"""Given a list of post recipients (toList) from 'to' or 'cc' parameters """Given a list of post recipients (toList) from 'to' or 'cc' parameters
populate a recipients_dict with the handle for each populate a recipients_dict with the handle for each
""" """
@ -614,9 +615,18 @@ def _inbox_post_recipients_add(base_dir: str, http_prefix: str, toList: [],
for recipient in toList: for recipient in toList:
if not recipient: if not recipient:
continue continue
# is this a to a local account? # if the recipient is an onion or i2p address then
# is it an account on a clearnet instance?
# If so then change the onion/i2p to the account domain
if onion_domain:
if onion_domain + '/' in recipient:
recipient = recipient.replace(onion_domain, domain)
if i2p_domain:
if i2p_domain + '/' in recipient:
recipient = recipient.replace(i2p_domain, domain)
# is this a to an account on this instance?
if domain_match in recipient: if domain_match in recipient:
# get the handle for the local account # get the handle for the account on this instance
nickname = recipient.split(domain_match)[1] nickname = recipient.split(domain_match)[1]
handle = nickname + '@' + domain handle = nickname + '@' + domain
if os.path.isdir(base_dir + '/accounts/' + handle): if os.path.isdir(base_dir + '/accounts/' + handle):
@ -643,7 +653,8 @@ def _inbox_post_recipients_add(base_dir: str, http_prefix: str, toList: [],
def _inbox_post_recipients(base_dir: str, post_json_object: {}, def _inbox_post_recipients(base_dir: str, post_json_object: {},
http_prefix: str, domain: str, port: int, http_prefix: str, domain: str, port: int,
debug: bool) -> ([], []): debug: bool,
onion_domain: str, i2p_domain: str) -> ([], []):
"""Returns dictionaries containing the recipients of the given post """Returns dictionaries containing the recipients of the given post
The shared dictionary contains followers The shared dictionary contains followers
""" """
@ -678,7 +689,8 @@ def _inbox_post_recipients(base_dir: str, post_json_object: {},
recipients_list, recipients_list,
recipients_dict, recipients_dict,
domain_match, domain_base, domain_match, domain_base,
actor, debug) actor, debug,
onion_domain, i2p_domain)
if includes_followers: if includes_followers:
follower_recipients = True follower_recipients = True
else: else:
@ -695,7 +707,8 @@ def _inbox_post_recipients(base_dir: str, post_json_object: {},
recipients_list, recipients_list,
recipients_dict, recipients_dict,
domain_match, domain_base, domain_match, domain_base,
actor, debug) actor, debug,
onion_domain, i2p_domain)
if includes_followers: if includes_followers:
follower_recipients = True follower_recipients = True
else: else:
@ -720,7 +733,8 @@ def _inbox_post_recipients(base_dir: str, post_json_object: {},
recipients_list, recipients_list,
recipients_dict, recipients_dict,
domain_match, domain_base, domain_match, domain_base,
actor, debug) actor, debug,
onion_domain, i2p_domain)
if includes_followers: if includes_followers:
follower_recipients = True follower_recipients = True
@ -734,7 +748,8 @@ def _inbox_post_recipients(base_dir: str, post_json_object: {},
recipients_list, recipients_list,
recipients_dict, recipients_dict,
domain_match, domain_base, domain_match, domain_base,
actor, debug) actor, debug,
onion_domain, i2p_domain)
if includes_followers: if includes_followers:
follower_recipients = True follower_recipients = True
@ -753,7 +768,8 @@ def _inbox_post_recipients(base_dir: str, post_json_object: {},
def _receive_undo_follow(session, base_dir: str, http_prefix: str, def _receive_undo_follow(session, base_dir: str, http_prefix: str,
port: int, message_json: {}, port: int, message_json: {},
federation_list: [], federation_list: [],
debug: bool) -> bool: debug: bool, domain: str,
onion_domain: str, i2p_domain: str) -> bool:
if not message_json['object'].get('actor'): if not message_json['object'].get('actor'):
if debug: if debug:
print('DEBUG: follow request has no actor within object') print('DEBUG: follow request has no actor within object')
@ -786,6 +802,12 @@ def _receive_undo_follow(session, base_dir: str, http_prefix: str,
return False return False
domain_following, port_following = \ domain_following, port_following = \
get_domain_from_actor(message_json['object']['object']) get_domain_from_actor(message_json['object']['object'])
if onion_domain:
if domain_following.endswith(onion_domain):
domain_following = domain
if i2p_domain:
if domain_following.endswith(i2p_domain):
domain_following = domain
domain_following_full = get_full_domain(domain_following, port_following) domain_following_full = get_full_domain(domain_following, port_following)
group_account = \ group_account = \
@ -810,7 +832,8 @@ def _receive_undo(session, base_dir: str, http_prefix: str,
port: int, send_threads: [], post_log: [], port: int, send_threads: [], post_log: [],
cached_webfingers: {}, person_cache: {}, cached_webfingers: {}, person_cache: {},
message_json: {}, federation_list: [], message_json: {}, federation_list: [],
debug: bool) -> bool: debug: bool, domain: str,
onion_domain: str, i2p_domain: str) -> bool:
"""Receives an undo request within the POST section of HTTPServer """Receives an undo request within the POST section of HTTPServer
""" """
if not message_json['type'].startswith('Undo'): if not message_json['type'].startswith('Undo'):
@ -831,7 +854,8 @@ def _receive_undo(session, base_dir: str, http_prefix: str,
message_json['object']['type'] == 'Join': message_json['object']['type'] == 'Join':
return _receive_undo_follow(session, base_dir, http_prefix, return _receive_undo_follow(session, base_dir, http_prefix,
port, message_json, port, message_json,
federation_list, debug) federation_list, debug,
domain, onion_domain, i2p_domain)
return False return False
@ -1009,7 +1033,7 @@ def _receive_update_activity(recent_posts_cache: {}, session, base_dir: str,
def _receive_like(recent_posts_cache: {}, def _receive_like(recent_posts_cache: {},
session, handle: str, is_group: bool, base_dir: str, session, handle: str, is_group: bool, base_dir: str,
http_prefix: str, domain: str, port: int, http_prefix: str, domain: str, port: int,
onion_domain: str, onion_domain: str, i2p_domain: str,
send_threads: [], post_log: [], cached_webfingers: {}, send_threads: [], post_log: [], cached_webfingers: {},
person_cache: {}, message_json: {}, federation_list: [], person_cache: {}, message_json: {}, federation_list: [],
debug: bool, debug: bool,
@ -2647,7 +2671,7 @@ def _group_handle(base_dir: str, handle: str) -> bool:
return actor_json['type'] == 'Group' return actor_json['type'] == 'Group'
def _send_to_group_members(session, session_onion, session_i2p, def _send_to_group_members(server, session, session_onion, session_i2p,
base_dir: str, handle: str, port: int, base_dir: str, handle: str, port: int,
post_json_object: {}, post_json_object: {},
http_prefix: str, federation_list: [], http_prefix: str, federation_list: [],
@ -2655,6 +2679,7 @@ def _send_to_group_members(session, session_onion, session_i2p,
cached_webfingers: {}, cached_webfingers: {},
person_cache: {}, debug: bool, person_cache: {}, debug: bool,
system_language: str, system_language: str,
curr_domain: str,
onion_domain: str, i2p_domain: str, onion_domain: str, i2p_domain: str,
signing_priv_key_pem: str) -> None: signing_priv_key_pem: str) -> None:
"""When a post arrives for a group send it out to the group members """When a post arrives for a group send it out to the group members
@ -2707,9 +2732,10 @@ def _send_to_group_members(session, session_onion, session_i2p,
http_prefix, post_id, False, False, http_prefix, post_id, False, False,
send_threads, post_log, send_threads, post_log,
person_cache, cached_webfingers, person_cache, cached_webfingers,
debug, __version__, signing_priv_key_pem) debug, __version__, signing_priv_key_pem,
curr_domain, onion_domain, i2p_domain)
send_to_followers_thread(session, session_onion, session_i2p, send_to_followers_thread(server, session, session_onion, session_i2p,
base_dir, nickname, domain, base_dir, nickname, domain,
onion_domain, i2p_domain, port, onion_domain, i2p_domain, port,
http_prefix, federation_list, http_prefix, federation_list,
@ -2845,7 +2871,8 @@ def _bounce_dm(senderPostId: str, session, http_prefix: str,
signing_priv_key_pem: str, signing_priv_key_pem: str,
content_license_url: str, content_license_url: str,
languages_understood: [], languages_understood: [],
bounce_is_chat: bool) -> bool: bounce_is_chat: bool,
curr_domain: str, onion_domain: str, i2p_domain: str) -> bool:
"""Sends a bounce message back to the sending handle """Sends a bounce message back to the sending handle
if a DM has been rejected if a DM has been rejected
""" """
@ -2919,7 +2946,8 @@ def _bounce_dm(senderPostId: str, session, http_prefix: str,
http_prefix, False, False, federation_list, http_prefix, False, False, federation_list,
send_threads, post_log, cached_webfingers, send_threads, post_log, cached_webfingers,
person_cache, debug, __version__, None, group_account, person_cache, debug, __version__, None, group_account,
signing_priv_key_pem, 7238634) signing_priv_key_pem, 7238634,
curr_domain, onion_domain, i2p_domain)
return True return True
@ -2935,7 +2963,8 @@ def _is_valid_dm(base_dir: str, nickname: str, domain: str, port: int,
handle: str, system_language: str, handle: str, system_language: str,
signing_priv_key_pem: str, signing_priv_key_pem: str,
content_license_url: str, content_license_url: str,
languages_understood: []) -> bool: languages_understood: [],
curr_domain: str, onion_domain: str, i2p_domain: str) -> bool:
"""Is the given message a valid DM? """Is the given message a valid DM?
""" """
if nickname == 'inbox': if nickname == 'inbox':
@ -3022,7 +3051,9 @@ def _is_valid_dm(base_dir: str, nickname: str, domain: str, port: int,
signing_priv_key_pem, signing_priv_key_pem,
content_license_url, content_license_url,
languages_understood, languages_understood,
bounce_chat) bounce_chat,
curr_domain,
onion_domain, i2p_domain)
return False return False
# dm index will be updated # dm index will be updated
@ -3032,7 +3063,7 @@ def _is_valid_dm(base_dir: str, nickname: str, domain: str, port: int,
return True return True
def _receive_question_vote(base_dir: str, nickname: str, domain: str, def _receive_question_vote(server, base_dir: str, nickname: str, domain: str,
http_prefix: str, handle: str, debug: bool, http_prefix: str, handle: str, debug: bool,
post_json_object: {}, recent_posts_cache: {}, post_json_object: {}, recent_posts_cache: {},
session, session_onion, session_i2p, session, session_onion, session_i2p,
@ -3112,7 +3143,7 @@ def _receive_question_vote(base_dir: str, nickname: str, domain: str,
question_json['type'] = 'Update' question_json['type'] = 'Update'
shared_items_federated_domains = [] shared_items_federated_domains = []
shared_item_federation_tokens = {} shared_item_federation_tokens = {}
send_to_followers_thread(session, session_onion, session_i2p, send_to_followers_thread(server, session, session_onion, session_i2p,
base_dir, nickname, domain, base_dir, nickname, domain,
onion_domain, i2p_domain, port, onion_domain, i2p_domain, port,
http_prefix, federation_list, http_prefix, federation_list,
@ -3240,7 +3271,8 @@ def _check_for_git_patches(base_dir: str, nickname: str, domain: str,
return 0 return 0
def _inbox_after_initial(recent_posts_cache: {}, max_recent_posts: int, def _inbox_after_initial(server,
recent_posts_cache: {}, max_recent_posts: int,
session, session_onion, session_i2p, session, session_onion, session_i2p,
key_id: str, handle: str, message_json: {}, key_id: str, handle: str, message_json: {},
base_dir: str, http_prefix: str, send_threads: [], base_dir: str, http_prefix: str, send_threads: [],
@ -3268,6 +3300,19 @@ def _inbox_after_initial(recent_posts_cache: {}, max_recent_posts: int,
languages_understood: []) -> bool: languages_understood: []) -> bool:
""" Anything which needs to be done after initial checks have passed """ Anything which needs to be done after initial checks have passed
""" """
# if this is a clearnet instance then replace any onion/i2p
# domains with the account domain
if onion_domain or i2p_domain:
message_str = json.dumps(message_json, ensure_ascii=False)
if onion_domain:
if onion_domain in message_str:
message_str = message_str.replace(onion_domain, domain)
message_json = json.loads(message_str)
if i2p_domain:
if i2p_domain in message_str:
message_str = message_str.replace(i2p_domain, domain)
message_json = json.loads(message_str)
actor = key_id actor = key_id
if '#' in actor: if '#' in actor:
actor = key_id.split('#')[0] actor = key_id.split('#')[0]
@ -3281,7 +3326,7 @@ def _inbox_after_initial(recent_posts_cache: {}, max_recent_posts: int,
session, handle, is_group, session, handle, is_group,
base_dir, http_prefix, base_dir, http_prefix,
domain, port, domain, port,
onion_domain, onion_domain, i2p_domain,
send_threads, post_log, send_threads, post_log,
cached_webfingers, cached_webfingers,
person_cache, person_cache,
@ -3514,7 +3559,7 @@ def _inbox_after_initial(recent_posts_cache: {}, max_recent_posts: int,
populate_replies(base_dir, http_prefix, domain, post_json_object, populate_replies(base_dir, http_prefix, domain, post_json_object,
max_replies, debug) max_replies, debug)
_receive_question_vote(base_dir, nickname, domain, _receive_question_vote(server, base_dir, nickname, domain,
http_prefix, handle, debug, http_prefix, handle, debug,
post_json_object, recent_posts_cache, post_json_object, recent_posts_cache,
session, session_onion, session_i2p, session, session_onion, session_i2p,
@ -3550,7 +3595,9 @@ def _inbox_after_initial(recent_posts_cache: {}, max_recent_posts: int,
handle, system_language, handle, system_language,
signing_priv_key_pem, signing_priv_key_pem,
content_license_url, content_license_url,
languages_understood): languages_understood,
domain,
onion_domain, i2p_domain):
return False return False
# get the actor being replied to # get the actor being replied to
@ -3684,7 +3731,8 @@ def _inbox_after_initial(recent_posts_cache: {}, max_recent_posts: int,
# send the post out to group members # send the post out to group members
if is_group: if is_group:
_send_to_group_members(session, session_onion, session_i2p, _send_to_group_members(server,
session, session_onion, session_i2p,
base_dir, handle, port, base_dir, handle, port,
post_json_object, post_json_object,
http_prefix, federation_list, http_prefix, federation_list,
@ -3692,7 +3740,7 @@ def _inbox_after_initial(recent_posts_cache: {}, max_recent_posts: int,
post_log, cached_webfingers, post_log, cached_webfingers,
person_cache, person_cache,
debug, system_language, debug, system_language,
onion_domain, i2p_domain, domain, onion_domain, i2p_domain,
signing_priv_key_pem) signing_priv_key_pem)
# if the post wasn't saved # if the post wasn't saved
@ -3747,7 +3795,7 @@ def _restore_queue_items(base_dir: str, queue: []) -> None:
def run_inbox_queue_watchdog(project_version: str, httpd) -> None: def run_inbox_queue_watchdog(project_version: str, httpd) -> None:
"""This tries to keep the inbox thread running even if it dies """This tries to keep the inbox thread running even if it dies
""" """
print('Starting inbox queue watchdog') print('THREAD: Starting inbox queue watchdog')
inbox_queue_original = httpd.thrInboxQueue.clone(run_inbox_queue) inbox_queue_original = httpd.thrInboxQueue.clone(run_inbox_queue)
httpd.thrInboxQueue.start() httpd.thrInboxQueue.start()
while True: while True:
@ -3755,6 +3803,7 @@ def run_inbox_queue_watchdog(project_version: str, httpd) -> None:
if not httpd.thrInboxQueue.is_alive() or httpd.restart_inbox_queue: if not httpd.thrInboxQueue.is_alive() or httpd.restart_inbox_queue:
httpd.restart_inbox_queue_in_progress = True httpd.restart_inbox_queue_in_progress = True
httpd.thrInboxQueue.kill() httpd.thrInboxQueue.kill()
print('THREAD: restarting inbox queue watchdog')
httpd.thrInboxQueue = inbox_queue_original.clone(run_inbox_queue) httpd.thrInboxQueue = inbox_queue_original.clone(run_inbox_queue)
httpd.inbox_queue.clear() httpd.inbox_queue.clear()
httpd.thrInboxQueue.start() httpd.thrInboxQueue.start()
@ -3932,7 +3981,8 @@ def _receive_follow_request(session, session_onion, session_i2p,
cached_webfingers: {}, person_cache: {}, cached_webfingers: {}, person_cache: {},
message_json: {}, federation_list: [], message_json: {}, federation_list: [],
debug: bool, project_version: str, debug: bool, project_version: str,
max_followers: int, onion_domain: str, max_followers: int,
this_domain: str, onion_domain: str,
i2p_domain: str, signing_priv_key_pem: str, i2p_domain: str, signing_priv_key_pem: str,
unit_test: bool) -> bool: unit_test: bool) -> bool:
"""Receives a follow request within the POST section of HTTPServer """Receives a follow request within the POST section of HTTPServer
@ -3971,6 +4021,13 @@ def _receive_follow_request(session, session_onion, session_i2p,
'not found within object') 'not found within object')
return False return False
domain_to_follow, temp_port = get_domain_from_actor(message_json['object']) domain_to_follow, temp_port = get_domain_from_actor(message_json['object'])
# switch to the local domain rather than its onion or i2p version
if onion_domain:
if domain_to_follow.endswith(onion_domain):
domain_to_follow = this_domain
if i2p_domain:
if domain_to_follow.endswith(i2p_domain):
domain_to_follow = this_domain
if not domain_permitted(domain_to_follow, federation_list): if not domain_permitted(domain_to_follow, federation_list):
if debug: if debug:
print('DEBUG: follow domain not permitted ' + domain_to_follow) print('DEBUG: follow domain not permitted ' + domain_to_follow)
@ -4002,6 +4059,7 @@ def _receive_follow_request(session, session_onion, session_i2p,
base_dir + '/accounts/' + handle_to_follow) base_dir + '/accounts/' + handle_to_follow)
return True return True
is_already_follower = False
if is_follower_of_person(base_dir, if is_follower_of_person(base_dir,
nickname_to_follow, domain_to_follow_full, nickname_to_follow, domain_to_follow_full,
nickname, domain_full): nickname, domain_full):
@ -4009,7 +4067,7 @@ def _receive_follow_request(session, session_onion, session_i2p,
print('DEBUG: ' + nickname + '@' + domain + print('DEBUG: ' + nickname + '@' + domain +
' is already a follower of ' + ' is already a follower of ' +
nickname_to_follow + '@' + domain_to_follow) nickname_to_follow + '@' + domain_to_follow)
return True is_already_follower = True
approve_handle = nickname + '@' + domain_full approve_handle = nickname + '@' + domain_full
@ -4017,16 +4075,26 @@ def _receive_follow_request(session, session_onion, session_i2p,
curr_http_prefix = http_prefix curr_http_prefix = http_prefix
curr_domain = domain curr_domain = domain
curr_port = from_port curr_port = from_port
if onion_domain and domain_to_follow.endswith('.onion'): if onion_domain and \
not curr_domain.endswith('.onion') and \
domain_to_follow.endswith('.onion'):
curr_session = session_onion curr_session = session_onion
curr_http_prefix = 'http' curr_http_prefix = 'http'
curr_domain = onion_domain curr_domain = onion_domain
curr_port = 80 curr_port = 80
elif i2p_domain and domain_to_follow.endswith('.i2p'): port = 80
if debug:
print('Domain switched from ' + domain + ' to ' + curr_domain)
elif (i2p_domain and
not curr_domain.endswith('.i2p') and
domain_to_follow.endswith('.i2p')):
curr_session = session_i2p curr_session = session_i2p
curr_http_prefix = 'http' curr_http_prefix = 'http'
curr_domain = i2p_domain curr_domain = i2p_domain
curr_port = 80 curr_port = 80
port = 80
if debug:
print('Domain switched from ' + domain + ' to ' + curr_domain)
# is the actor sending the request valid? # is the actor sending the request valid?
if not valid_sending_actor(curr_session, base_dir, if not valid_sending_actor(curr_session, base_dir,
@ -4037,7 +4105,8 @@ def _receive_follow_request(session, session_onion, session_i2p,
return False return False
# what is the followers policy? # what is the followers policy?
if follow_approval_required(base_dir, nickname_to_follow, if not is_already_follower and \
follow_approval_required(base_dir, nickname_to_follow,
domain_to_follow, debug, approve_handle): domain_to_follow, debug, approve_handle):
print('Follow approval is required') print('Follow approval is required')
if domain.endswith('.onion'): if domain.endswith('.onion'):
@ -4089,7 +4158,12 @@ def _receive_follow_request(session, session_onion, session_i2p,
message_json, debug, message_json['actor'], message_json, debug, message_json['actor'],
group_account) group_account)
else: else:
print('Follow request does not require approval ' + approve_handle) if is_already_follower:
print(approve_handle + ' is already a follower. ' +
'Re-sending Accept.')
else:
print('Follow request does not require approval ' +
approve_handle)
# update the followers # update the followers
account_to_be_followed = \ account_to_be_followed = \
acct_dir(base_dir, nickname_to_follow, domain_to_follow) acct_dir(base_dir, nickname_to_follow, domain_to_follow)
@ -4151,6 +4225,9 @@ def _receive_follow_request(session, session_onion, session_i2p,
followers_file.write(approve_handle + '\n') followers_file.write(approve_handle + '\n')
except OSError: except OSError:
print('EX: unable to write ' + followers_filename) print('EX: unable to write ' + followers_filename)
else:
print('ACCEPT: Follow Accept account directory not found: ' +
account_to_be_followed)
print('Beginning follow accept') print('Beginning follow accept')
return followed_account_accepts(curr_session, base_dir, curr_http_prefix, return followed_account_accepts(curr_session, base_dir, curr_http_prefix,
@ -4160,10 +4237,12 @@ def _receive_follow_request(session, session_onion, session_i2p,
message_json, send_threads, post_log, message_json, send_threads, post_log,
cached_webfingers, person_cache, cached_webfingers, person_cache,
debug, project_version, True, debug, project_version, True,
signing_priv_key_pem) signing_priv_key_pem,
this_domain, onion_domain, i2p_domain)
def run_inbox_queue(recent_posts_cache: {}, max_recent_posts: int, def run_inbox_queue(server,
recent_posts_cache: {}, max_recent_posts: int,
project_version: str, project_version: str,
base_dir: str, http_prefix: str, base_dir: str, http_prefix: str,
send_threads: [], post_log: [], send_threads: [], post_log: [],
@ -4509,7 +4588,7 @@ def run_inbox_queue(recent_posts_cache: {}, max_recent_posts: int,
person_cache, person_cache,
queue_json['post'], queue_json['post'],
federation_list, federation_list,
debug): debug, domain, onion_domain, i2p_domain):
print('Queue: Undo accepted from ' + key_id) print('Queue: Undo accepted from ' + key_id)
if os.path.isfile(queue_filename): if os.path.isfile(queue_filename):
try: try:
@ -4531,7 +4610,8 @@ def run_inbox_queue(recent_posts_cache: {}, max_recent_posts: int,
queue_json['post'], queue_json['post'],
federation_list, federation_list,
debug, project_version, debug, project_version,
max_followers, onion_domain, i2p_domain, max_followers, domain,
onion_domain, i2p_domain,
signing_priv_key_pem, unit_test): signing_priv_key_pem, unit_test):
if os.path.isfile(queue_filename): if os.path.isfile(queue_filename):
try: try:
@ -4553,7 +4633,8 @@ def run_inbox_queue(recent_posts_cache: {}, max_recent_posts: int,
send_threads, post_log, send_threads, post_log,
cached_webfingers, person_cache, cached_webfingers, person_cache,
queue_json['post'], queue_json['post'],
federation_list, debug): federation_list, debug,
domain, onion_domain, i2p_domain):
print('Queue: Accept/Reject received from ' + key_id) print('Queue: Accept/Reject received from ' + key_id)
if os.path.isfile(queue_filename): if os.path.isfile(queue_filename):
try: try:
@ -4590,7 +4671,8 @@ def run_inbox_queue(recent_posts_cache: {}, max_recent_posts: int,
# get recipients list # get recipients list
recipients_dict, recipients_dict_followers = \ recipients_dict, recipients_dict_followers = \
_inbox_post_recipients(base_dir, queue_json['post'], _inbox_post_recipients(base_dir, queue_json['post'],
http_prefix, domain, port, debug) http_prefix, domain, port, debug,
onion_domain, i2p_domain)
if len(recipients_dict.items()) == 0 and \ if len(recipients_dict.items()) == 0 and \
len(recipients_dict_followers.items()) == 0: len(recipients_dict_followers.items()) == 0:
if debug: if debug:
@ -4646,7 +4728,8 @@ def run_inbox_queue(recent_posts_cache: {}, max_recent_posts: int,
destination = \ destination = \
queue_json['destination'].replace(inbox_handle, handle) queue_json['destination'].replace(inbox_handle, handle)
languages_understood = [] languages_understood = []
_inbox_after_initial(recent_posts_cache, _inbox_after_initial(server,
recent_posts_cache,
max_recent_posts, max_recent_posts,
session, session_onion, session_i2p, session, session_onion, session_i2p,
key_id, handle, key_id, handle,

13
like.py
View File

@ -77,7 +77,9 @@ def _create_like(recent_posts_cache: {},
send_threads: [], postLog: [], send_threads: [], postLog: [],
person_cache: {}, cached_webfingers: {}, person_cache: {}, cached_webfingers: {},
debug: bool, project_version: str, debug: bool, project_version: str,
signing_priv_key_pem: str) -> {}: signing_priv_key_pem: str,
curr_domain: str,
onion_domain: str, i2p_domain: str) -> {}:
"""Creates a like """Creates a like
actor is the person doing the liking actor is the person doing the liking
'to' might be a specific person (actor) whose post was liked 'to' might be a specific person (actor) whose post was liked
@ -142,7 +144,8 @@ def _create_like(recent_posts_cache: {},
send_threads, postLog, cached_webfingers, send_threads, postLog, cached_webfingers,
person_cache, person_cache,
debug, project_version, None, group_account, debug, project_version, None, group_account,
signing_priv_key_pem, 7367374) signing_priv_key_pem, 7367374,
curr_domain, onion_domain, i2p_domain)
return new_like_json return new_like_json
@ -156,7 +159,8 @@ def like_post(recent_posts_cache: {},
send_threads: [], postLog: [], send_threads: [], postLog: [],
person_cache: {}, cached_webfingers: {}, person_cache: {}, cached_webfingers: {},
debug: bool, project_version: str, debug: bool, project_version: str,
signing_priv_key_pem: str) -> {}: signing_priv_key_pem: str,
curr_domain: str, onion_domain: str, i2p_domain: str) -> {}:
"""Likes a given status post. This is only used by unit tests """Likes a given status post. This is only used by unit tests
""" """
like_domain = get_full_domain(like_domain, like_port) like_domain = get_full_domain(like_domain, like_port)
@ -170,7 +174,8 @@ def like_post(recent_posts_cache: {},
cc_list, http_prefix, object_url, actor_liked, cc_list, http_prefix, object_url, actor_liked,
client_to_server, client_to_server,
send_threads, postLog, person_cache, cached_webfingers, send_threads, postLog, person_cache, cached_webfingers,
debug, project_version, signing_priv_key_pem) debug, project_version, signing_priv_key_pem,
curr_domain, onion_domain, i2p_domain)
def send_like_via_server(base_dir: str, session, def send_like_via_server(base_dir: str, session,

View File

@ -17,6 +17,7 @@ from utils import get_port_from_domain
from utils import get_user_paths from utils import get_user_paths
from utils import acct_dir from utils import acct_dir
from threads import thread_with_trace from threads import thread_with_trace
from session import create_session
def manual_deny_follow_request(session, session_onion, session_i2p, def manual_deny_follow_request(session, session_onion, session_i2p,
@ -88,6 +89,7 @@ def manual_deny_follow_request_thread(session, session_onion, session_i2p,
"""Manually deny a follow request, within a thread so that the """Manually deny a follow request, within a thread so that the
user interface doesn't lag user interface doesn't lag
""" """
print('THREAD: manual_deny_follow_request')
thr = \ thr = \
thread_with_trace(target=manual_deny_follow_request, thread_with_trace(target=manual_deny_follow_request,
args=(session, session_onion, session_i2p, args=(session, session_onion, session_i2p,
@ -135,7 +137,8 @@ def manual_approve_follow_request(session, session_onion, session_i2p,
cached_webfingers: {}, person_cache: {}, cached_webfingers: {}, person_cache: {},
debug: bool, debug: bool,
project_version: str, project_version: str,
signing_priv_key_pem: str) -> None: signing_priv_key_pem: str,
proxy_type: str) -> None:
"""Manually approve a follow request """Manually approve a follow request
""" """
handle = nickname + '@' + domain handle = nickname + '@' + domain
@ -217,18 +220,28 @@ def manual_approve_follow_request(session, session_onion, session_i2p,
curr_port = port curr_port = port
curr_session = session curr_session = session
curr_http_prefix = http_prefix curr_http_prefix = http_prefix
curr_proxy_type = proxy_type
if onion_domain and \ if onion_domain and \
not curr_domain.endswith('.onion') and \
approve_domain.endswith('.onion'): approve_domain.endswith('.onion'):
curr_domain = onion_domain curr_domain = onion_domain
curr_port = 80 curr_port = 80
approve_port = 80
curr_session = session_onion curr_session = session_onion
curr_http_prefix = 'http' curr_http_prefix = 'http'
curr_proxy_type = 'tor'
elif (i2p_domain and elif (i2p_domain and
not curr_domain.endswith('.i2p') and
approve_domain.endswith('.i2p')): approve_domain.endswith('.i2p')):
curr_domain = i2p_domain curr_domain = i2p_domain
curr_port = 80 curr_port = 80
approve_port = 80
curr_session = session_i2p curr_session = session_i2p
curr_http_prefix = 'http' curr_http_prefix = 'http'
curr_proxy_type = 'i2p'
if not curr_session:
curr_session = create_session(curr_proxy_type)
print('Manual follow accept: Sending Accept for ' + print('Manual follow accept: Sending Accept for ' +
handle + ' follow request from ' + handle + ' follow request from ' +
@ -248,7 +261,10 @@ def manual_approve_follow_request(session, session_onion, session_i2p,
person_cache, person_cache,
debug, debug,
project_version, False, project_version, False,
signing_priv_key_pem) signing_priv_key_pem,
domain,
onion_domain,
i2p_domain)
update_approved_followers = True update_approved_followers = True
else: else:
# this isn't the approved follow so it will remain # this isn't the approved follow so it will remain
@ -317,10 +333,12 @@ def manual_approve_follow_request_thread(session, session_onion, session_i2p,
person_cache: {}, person_cache: {},
debug: bool, debug: bool,
project_version: str, project_version: str,
signing_priv_key_pem: str) -> None: signing_priv_key_pem: str,
proxy_type: str) -> None:
"""Manually approve a follow request, in a thread so as not to cause """Manually approve a follow request, in a thread so as not to cause
the UI to lag the UI to lag
""" """
print('THREAD: manual_approve_follow_request')
thr = \ thr = \
thread_with_trace(target=manual_approve_follow_request, thread_with_trace(target=manual_approve_follow_request,
args=(session, session_onion, session_i2p, args=(session, session_onion, session_i2p,
@ -333,6 +351,7 @@ def manual_approve_follow_request_thread(session, session_onion, session_i2p,
cached_webfingers, person_cache, cached_webfingers, person_cache,
debug, debug,
project_version, project_version,
signing_priv_key_pem), daemon=True) signing_priv_key_pem,
proxy_type), daemon=True)
thr.start() thr.start()
send_threads.append(thr) send_threads.append(thr)

View File

@ -882,7 +882,7 @@ def run_newswire_daemon(base_dir: str, httpd,
def run_newswire_watchdog(project_version: str, httpd) -> None: def run_newswire_watchdog(project_version: str, httpd) -> None:
"""This tries to keep the newswire update thread running even if it dies """This tries to keep the newswire update thread running even if it dies
""" """
print('Starting newswire watchdog') print('THREAD: Starting newswire watchdog')
newswire_original = \ newswire_original = \
httpd.thrPostSchedule.clone(run_newswire_daemon) httpd.thrPostSchedule.clone(run_newswire_daemon)
httpd.thrNewswireDaemon.start() httpd.thrNewswireDaemon.start()
@ -891,6 +891,7 @@ def run_newswire_watchdog(project_version: str, httpd) -> None:
if httpd.thrNewswireDaemon.is_alive(): if httpd.thrNewswireDaemon.is_alive():
continue continue
httpd.thrNewswireDaemon.kill() httpd.thrNewswireDaemon.kill()
print('THREAD: restarting newswire watchdog')
httpd.thrNewswireDaemon = \ httpd.thrNewswireDaemon = \
newswire_original.clone(run_newswire_daemon) newswire_original.clone(run_newswire_daemon)
httpd.thrNewswireDaemon.start() httpd.thrNewswireDaemon.start()

View File

@ -509,7 +509,7 @@ def post_message_to_outbox(session, translate: {},
followers_threads.pop(0) followers_threads.pop(0)
# create a thread to send the post to followers # create a thread to send the post to followers
followers_thread = \ followers_thread = \
send_to_followers_thread(server.session, send_to_followers_thread(server, server.session,
server.session_onion, server.session_onion,
server.session_i2p, server.session_i2p,
base_dir, base_dir,
@ -653,7 +653,7 @@ def post_message_to_outbox(session, translate: {},
print('c2s sender: ' + print('c2s sender: ' +
post_to_nickname + '@' + domain + ':' + str(port)) post_to_nickname + '@' + domain + ':' + str(port))
named_addresses_thread = \ named_addresses_thread = \
send_to_named_addresses_thread(server.session, send_to_named_addresses_thread(server, server.session,
server.session_onion, server.session_onion,
server.session_i2p, server.session_i2p,
base_dir, post_to_nickname, base_dir, post_to_nickname,
@ -668,6 +668,7 @@ def post_message_to_outbox(session, translate: {},
version, version,
shared_items_federated_domains, shared_items_federated_domains,
shared_item_federation_tokens, shared_item_federation_tokens,
signing_priv_key_pem) signing_priv_key_pem,
proxy_type)
followers_threads.append(named_addresses_thread) followers_threads.append(named_addresses_thread)
return True return True

View File

@ -1687,17 +1687,13 @@ def valid_sending_actor(session, base_dir: str,
if sending_actor.endswith(domain + '/users/' + nickname): if sending_actor.endswith(domain + '/users/' + nickname):
return True return True
# get their actor # download the actor
actor_json = \ # NOTE: the actor should not be obtained from the local cache,
get_person_from_cache(base_dir, sending_actor, person_cache, True) # because they may have changed fields which are being tested here,
downloaded_actor = False # such as the bio length
if not actor_json: actor_json, _ = get_actor_json(domain, sending_actor,
# download the actor True, False, debug, True,
actor_json, _ = get_actor_json(domain, sending_actor, signing_priv_key_pem, session)
True, False, debug, True,
signing_priv_key_pem, session)
if actor_json:
downloaded_actor = True
if not actor_json: if not actor_json:
# if the actor couldn't be obtained then proceed anyway # if the actor couldn't be obtained then proceed anyway
return True return True
@ -1776,9 +1772,8 @@ def valid_sending_actor(session, base_dir: str,
sending_actor) sending_actor)
return False return False
if downloaded_actor: # if the actor is valid and was downloaded then
# if the actor is valid and was downloaded then # store it in the cache, but don't write it to file
# store it in the cache, but don't write it to file store_person_in_cache(base_dir, sending_actor, actor_json,
store_person_in_cache(base_dir, sending_actor, actor_json, person_cache, False)
person_cache, False)
return True return True

128
posts.py
View File

@ -2494,6 +2494,7 @@ def send_post(signing_priv_key_pem: str, project_version: str,
send_threads[0].kill() send_threads[0].kill()
send_threads.pop(0) send_threads.pop(0)
print('WARN: thread killed') print('WARN: thread killed')
print('THREAD: thread_send_post')
thr = \ thr = \
thread_with_trace(target=thread_send_post, thread_with_trace(target=thread_send_post,
args=(session, args=(session,
@ -2722,7 +2723,8 @@ def send_signed_json(post_json_object: {}, session, base_dir: str,
person_cache: {}, debug: bool, project_version: str, person_cache: {}, debug: bool, project_version: str,
shared_items_token: str, group_account: bool, shared_items_token: str, group_account: bool,
signing_priv_key_pem: str, signing_priv_key_pem: str,
source_id: int) -> int: source_id: int, curr_domain: str,
onion_domain: str, i2p_domain: str) -> int:
"""Sends a signed json object to an inbox/outbox """Sends a signed json object to an inbox/outbox
""" """
if debug: if debug:
@ -2818,12 +2820,19 @@ def send_signed_json(post_json_object: {}, session, base_dir: str,
# shared_inbox is optional # shared_inbox is optional
# get the senders private key # get the senders private key
account_domain = origin_domain
if onion_domain:
if account_domain == onion_domain:
account_domain = curr_domain
if i2p_domain:
if account_domain == i2p_domain:
account_domain = curr_domain
private_key_pem = \ private_key_pem = \
_get_person_key(nickname, domain, base_dir, 'private', debug) _get_person_key(nickname, account_domain, base_dir, 'private', debug)
if len(private_key_pem) == 0: if len(private_key_pem) == 0:
if debug: if debug:
print('DEBUG: Private key not found for ' + print('DEBUG: Private key not found for ' +
nickname + '@' + domain + nickname + '@' + account_domain +
' in ' + base_dir + '/keys/private') ' in ' + base_dir + '/keys/private')
return 6 return 6
@ -2849,6 +2858,20 @@ def send_signed_json(post_json_object: {}, session, base_dir: str,
# subsequent conversions after creating message body digest # subsequent conversions after creating message body digest
post_json_str = json.dumps(post_json_object) post_json_str = json.dumps(post_json_object)
# if the sender domain has changed from clearnet to onion or i2p
# then change the content of the post accordingly
if debug:
print('Checking for changed origin domain: ' +
domain + ' ' + curr_domain)
if domain != curr_domain:
if not curr_domain.endswith('.onion') and \
not curr_domain.endswith('.i2p'):
if debug:
print('Changing post content sender domain from ' +
curr_domain + ' to ' + domain)
post_json_str = \
post_json_str.replace(curr_domain, domain)
# construct the http header, including the message body digest # construct the http header, including the message body digest
signature_header_json = \ signature_header_json = \
create_signed_header(None, private_key_pem, nickname, domain, port, create_signed_header(None, private_key_pem, nickname, domain, port,
@ -2881,6 +2904,7 @@ def send_signed_json(post_json_object: {}, session, base_dir: str,
print('DEBUG: starting thread to send post') print('DEBUG: starting thread to send post')
pprint(post_json_object) pprint(post_json_object)
domain_full = get_full_domain(domain, port) domain_full = get_full_domain(domain, port)
print('THREAD: thread_send_post 2')
thr = \ thr = \
thread_with_trace(target=thread_send_post, thread_with_trace(target=thread_send_post,
args=(session, args=(session,
@ -2981,7 +3005,7 @@ def _is_profile_update(post_json_object: {}) -> bool:
return False return False
def _send_to_named_addresses(session, session_onion, session_i2p, def _send_to_named_addresses(server, session, session_onion, session_i2p,
base_dir: str, base_dir: str,
nickname: str, domain: str, nickname: str, domain: str,
onion_domain: str, i2p_domain: str, port: int, onion_domain: str, i2p_domain: str, port: int,
@ -2992,7 +3016,8 @@ def _send_to_named_addresses(session, session_onion, session_i2p,
project_version: str, project_version: str,
shared_items_federated_domains: [], shared_items_federated_domains: [],
shared_item_federation_tokens: {}, shared_item_federation_tokens: {},
signing_priv_key_pem: str) -> None: signing_priv_key_pem: str,
proxy_type: str) -> None:
"""sends a post to the specific named addresses in to/cc """sends a post to the specific named addresses in to/cc
""" """
if not session: if not session:
@ -3091,11 +3116,6 @@ def _send_to_named_addresses(session, session_onion, session_i2p,
print('Not sending profile update to self. ' + print('Not sending profile update to self. ' +
nickname + '@' + domain_full) nickname + '@' + domain_full)
continue continue
if debug:
domain_full = get_full_domain(domain, port)
to_domain_full = get_full_domain(to_domain, to_port)
print('DEBUG: Post sending s2s: ' + nickname + '@' + domain_full +
' to ' + to_nickname + '@' + to_domain_full)
# if we have an alt onion domain and we are sending to # if we have an alt onion domain and we are sending to
# another onion domain then switch the clearnet # another onion domain then switch the clearnet
@ -3104,20 +3124,38 @@ def _send_to_named_addresses(session, session_onion, session_i2p,
from_domain_full = get_full_domain(domain, port) from_domain_full = get_full_domain(domain, port)
from_http_prefix = http_prefix from_http_prefix = http_prefix
curr_session = session curr_session = session
curr_proxy_type = proxy_type
session_type = 'default'
if onion_domain: if onion_domain:
if to_domain.endswith('.onion'): if not from_domain.endswith('.onion') and \
to_domain.endswith('.onion'):
from_domain = onion_domain from_domain = onion_domain
from_domain_full = onion_domain from_domain_full = onion_domain
from_http_prefix = 'http' from_http_prefix = 'http'
curr_session = session_onion curr_session = session_onion
port = 80
to_port = 80
curr_proxy_type = 'tor'
session_type = 'tor'
if i2p_domain: if i2p_domain:
if to_domain.endswith('.i2p'): if not from_domain.endswith('.i2p') and \
to_domain.endswith('.i2p'):
from_domain = i2p_domain from_domain = i2p_domain
from_domain_full = i2p_domain from_domain_full = i2p_domain
from_http_prefix = 'http' from_http_prefix = 'http'
curr_session = session_i2p curr_session = session_i2p
port = 80
to_port = 80
curr_proxy_type = 'i2p'
session_type = 'i2p'
cc_list = [] cc_list = []
if debug:
to_domain_full = get_full_domain(to_domain, to_port)
print('DEBUG: Post sending s2s: ' +
nickname + '@' + from_domain_full +
' to ' + to_nickname + '@' + to_domain_full)
# if the "to" domain is within the shared items # if the "to" domain is within the shared items
# federation list then send the token for this domain # federation list then send the token for this domain
# so that it can request a catalog # so that it can request a catalog
@ -3129,6 +3167,16 @@ def _send_to_named_addresses(session, session_onion, session_i2p,
group_account = has_group_type(base_dir, address, person_cache) group_account = has_group_type(base_dir, address, person_cache)
if not curr_session:
curr_session = create_session(curr_proxy_type)
if server:
if session_type == 'tor':
server.session_onion = curr_session
elif session_type == 'i2p':
server.session_i2p = curr_session
else:
server.session = curr_session
send_signed_json(post_json_object, curr_session, base_dir, send_signed_json(post_json_object, curr_session, base_dir,
nickname, from_domain, port, nickname, from_domain, port,
to_nickname, to_domain, to_port, to_nickname, to_domain, to_port,
@ -3137,10 +3185,11 @@ def _send_to_named_addresses(session, session_onion, session_i2p,
send_threads, post_log, cached_webfingers, send_threads, post_log, cached_webfingers,
person_cache, debug, project_version, person_cache, debug, project_version,
shared_items_token, group_account, shared_items_token, group_account,
signing_priv_key_pem, 34436782) signing_priv_key_pem, 34436782,
domain, onion_domain, i2p_domain)
def send_to_named_addresses_thread(session, session_onion, session_i2p, def send_to_named_addresses_thread(server, session, session_onion, session_i2p,
base_dir: str, nickname: str, domain: str, base_dir: str, nickname: str, domain: str,
onion_domain: str, onion_domain: str,
i2p_domain: str, port: int, i2p_domain: str, port: int,
@ -3151,12 +3200,14 @@ def send_to_named_addresses_thread(session, session_onion, session_i2p,
project_version: str, project_version: str,
shared_items_federated_domains: [], shared_items_federated_domains: [],
shared_item_federation_tokens: {}, shared_item_federation_tokens: {},
signing_priv_key_pem: str): signing_priv_key_pem: str,
proxy_type: str):
"""Returns a thread used to send a post to named addresses """Returns a thread used to send a post to named addresses
""" """
print('THREAD: _send_to_named_addresses')
send_thread = \ send_thread = \
thread_with_trace(target=_send_to_named_addresses, thread_with_trace(target=_send_to_named_addresses,
args=(session, session_onion, session_i2p, args=(server, session, session_onion, session_i2p,
base_dir, nickname, domain, base_dir, nickname, domain,
onion_domain, i2p_domain, port, onion_domain, i2p_domain, port,
http_prefix, federation_list, http_prefix, federation_list,
@ -3166,7 +3217,8 @@ def send_to_named_addresses_thread(session, session_onion, session_i2p,
project_version, project_version,
shared_items_federated_domains, shared_items_federated_domains,
shared_item_federation_tokens, shared_item_federation_tokens,
signing_priv_key_pem), daemon=True) signing_priv_key_pem,
proxy_type), daemon=True)
try: try:
send_thread.start() send_thread.start()
except SocketError as ex: except SocketError as ex:
@ -3213,7 +3265,7 @@ def _sending_profile_update(post_json_object: {}) -> bool:
return False return False
def send_to_followers(session, session_onion, session_i2p, def send_to_followers(server, session, session_onion, session_i2p,
base_dir: str, nickname: str, domain: str, base_dir: str, nickname: str, domain: str,
onion_domain: str, i2p_domain: str, port: int, onion_domain: str, i2p_domain: str, port: int,
http_prefix: str, federation_list: [], http_prefix: str, federation_list: [],
@ -3246,6 +3298,12 @@ def send_to_followers(session, session_onion, session_i2p,
# this is after the message has arrived at the server # this is after the message has arrived at the server
client_to_server = False client_to_server = False
curr_proxy_type = None
if domain.endswith('.onion'):
curr_proxy_type = 'tor'
elif domain.endswith('.i2p'):
curr_proxy_type = 'i2p'
# for each instance # for each instance
sending_start_time = datetime.datetime.utcnow() sending_start_time = datetime.datetime.utcnow()
print('Sending post to followers begins ' + print('Sending post to followers begins ' +
@ -3289,10 +3347,6 @@ def send_to_followers(session, session_onion, session_i2p,
if follower_domain.endswith('.i2p'): if follower_domain.endswith('.i2p'):
curr_session = session_i2p curr_session = session_i2p
curr_http_prefix = 'http' curr_http_prefix = 'http'
if not curr_session:
print('WARN: session not found when sending to follower ' +
follower_domain_url)
continue
with_shared_inbox = \ with_shared_inbox = \
_has_shared_inbox(curr_session, curr_http_prefix, follower_domain, _has_shared_inbox(curr_session, curr_http_prefix, follower_domain,
@ -3317,14 +3371,33 @@ def send_to_followers(session, session_onion, session_i2p,
# have an alt onion domain then use the alt # have an alt onion domain then use the alt
from_domain = domain from_domain = domain
from_http_prefix = http_prefix from_http_prefix = http_prefix
session_type = 'default'
if onion_domain: if onion_domain:
if to_domain.endswith('.onion'): if to_domain.endswith('.onion'):
from_domain = onion_domain from_domain = onion_domain
from_http_prefix = 'http' from_http_prefix = 'http'
port = 80
to_port = 80
curr_proxy_type = 'tor'
session_type = 'tor'
if i2p_domain: if i2p_domain:
if to_domain.endswith('.i2p'): if to_domain.endswith('.i2p'):
from_domain = i2p_domain from_domain = i2p_domain
from_http_prefix = 'http' from_http_prefix = 'http'
port = 80
to_port = 80
curr_proxy_type = 'i2p'
session_type = 'i2p'
if not curr_session:
curr_session = create_session(curr_proxy_type)
if server:
if session_type == 'tor':
server.session_onion = curr_session
elif session_type == 'i2p':
server.session_i2p = curr_session
else:
server.session = curr_session
if with_shared_inbox: if with_shared_inbox:
to_nickname = follower_handles[index].split('@')[0] to_nickname = follower_handles[index].split('@')[0]
@ -3357,7 +3430,8 @@ def send_to_followers(session, session_onion, session_i2p,
send_threads, post_log, cached_webfingers, send_threads, post_log, cached_webfingers,
person_cache, debug, project_version, person_cache, debug, project_version,
shared_items_token, group_account, shared_items_token, group_account,
signing_priv_key_pem, 639342) signing_priv_key_pem, 639342,
domain, onion_domain, i2p_domain)
else: else:
# send to individual followers without using a shared inbox # send to individual followers without using a shared inbox
for handle in follower_handles: for handle in follower_handles:
@ -3386,7 +3460,8 @@ def send_to_followers(session, session_onion, session_i2p,
send_threads, post_log, cached_webfingers, send_threads, post_log, cached_webfingers,
person_cache, debug, project_version, person_cache, debug, project_version,
shared_items_token, group_account, shared_items_token, group_account,
signing_priv_key_pem, 634219) signing_priv_key_pem, 634219,
domain, onion_domain, i2p_domain)
time.sleep(4) time.sleep(4)
@ -3399,7 +3474,7 @@ def send_to_followers(session, session_onion, session_i2p,
print('Sending post to followers ends ' + str(sending_mins) + ' mins') print('Sending post to followers ends ' + str(sending_mins) + ' mins')
def send_to_followers_thread(session, session_onion, session_i2p, def send_to_followers_thread(server, session, session_onion, session_i2p,
base_dir: str, nickname: str, domain: str, base_dir: str, nickname: str, domain: str,
onion_domain: str, i2p_domain: str, port: int, onion_domain: str, i2p_domain: str, port: int,
http_prefix: str, federation_list: [], http_prefix: str, federation_list: [],
@ -3412,9 +3487,10 @@ def send_to_followers_thread(session, session_onion, session_i2p,
signing_priv_key_pem: str): signing_priv_key_pem: str):
"""Returns a thread used to send a post to followers """Returns a thread used to send a post to followers
""" """
print('THREAD: send_to_followers')
send_thread = \ send_thread = \
thread_with_trace(target=send_to_followers, thread_with_trace(target=send_to_followers,
args=(session, session_onion, session_i2p, args=(server, session, session_onion, session_i2p,
base_dir, nickname, domain, base_dir, nickname, domain,
onion_domain, i2p_domain, port, onion_domain, i2p_domain, port,
http_prefix, federation_list, http_prefix, federation_list,

View File

@ -70,7 +70,9 @@ def _reactionpost(recent_posts_cache: {},
send_threads: [], post_log: [], send_threads: [], post_log: [],
person_cache: {}, cached_webfingers: {}, person_cache: {}, cached_webfingers: {},
debug: bool, project_version: str, debug: bool, project_version: str,
signing_priv_key_pem: str) -> {}: signing_priv_key_pem: str,
curr_domain: str,
onion_domain: str, i2p_domain: str) -> {}:
"""Creates an emoji reaction """Creates an emoji reaction
actor is the person doing the reacting actor is the person doing the reacting
'to' might be a specific person (actor) whose post was reaction 'to' might be a specific person (actor) whose post was reaction
@ -141,7 +143,8 @@ def _reactionpost(recent_posts_cache: {},
send_threads, post_log, cached_webfingers, send_threads, post_log, cached_webfingers,
person_cache, person_cache,
debug, project_version, None, group_account, debug, project_version, None, group_account,
signing_priv_key_pem, 7165392) signing_priv_key_pem, 7165392,
curr_domain, onion_domain, i2p_domain)
return new_reaction_json return new_reaction_json
@ -156,7 +159,8 @@ def reaction_post(recent_posts_cache: {},
send_threads: [], post_log: [], send_threads: [], post_log: [],
person_cache: {}, cached_webfingers: {}, person_cache: {}, cached_webfingers: {},
debug: bool, project_version: str, debug: bool, project_version: str,
signing_priv_key_pem: str) -> {}: signing_priv_key_pem: str,
curr_domain: str, onion_domain: str, i2p_domain: str) -> {}:
"""Adds a reaction to a given status post. This is only used by unit tests """Adds a reaction to a given status post. This is only used by unit tests
""" """
reaction_domain = get_full_domain(reaction_domain, reaction_port) reaction_domain = get_full_domain(reaction_domain, reaction_port)
@ -172,7 +176,8 @@ def reaction_post(recent_posts_cache: {},
actor_reaction, client_to_server, actor_reaction, client_to_server,
send_threads, post_log, person_cache, send_threads, post_log, person_cache,
cached_webfingers, cached_webfingers,
debug, project_version, signing_priv_key_pem) debug, project_version, signing_priv_key_pem,
curr_domain, onion_domain, i2p_domain)
def send_reaction_via_server(base_dir: str, session, def send_reaction_via_server(base_dir: str, session,

View File

@ -193,7 +193,7 @@ def run_post_schedule(base_dir: str, httpd, max_scheduled_posts: int):
def run_post_schedule_watchdog(project_version: str, httpd) -> None: def run_post_schedule_watchdog(project_version: str, httpd) -> None:
"""This tries to keep the scheduled post thread running even if it dies """This tries to keep the scheduled post thread running even if it dies
""" """
print('Starting scheduled post watchdog') print('THREAD: Starting scheduled post watchdog')
post_schedule_original = \ post_schedule_original = \
httpd.thrPostSchedule.clone(run_post_schedule) httpd.thrPostSchedule.clone(run_post_schedule)
httpd.thrPostSchedule.start() httpd.thrPostSchedule.start()
@ -202,6 +202,7 @@ def run_post_schedule_watchdog(project_version: str, httpd) -> None:
if httpd.thrPostSchedule.is_alive(): if httpd.thrPostSchedule.is_alive():
continue continue
httpd.thrPostSchedule.kill() httpd.thrPostSchedule.kill()
print('THREAD: restarting scheduled post watchdog')
httpd.thrPostSchedule = \ httpd.thrPostSchedule = \
post_schedule_original.clone(run_post_schedule) post_schedule_original.clone(run_post_schedule)
httpd.thrPostSchedule.start() httpd.thrPostSchedule.start()

View File

@ -0,0 +1,7 @@
#!/bin/bash
journalctl -u epicyon | grep 'required positional arguments' > .missing_arguments.txt
if [ ! -f .missing_arguments.txt ]; then
echo 'No missing arguments'
else
cat .missing_arguments.txt
fi

7
scripts/threads 100755
View File

@ -0,0 +1,7 @@
#!/bin/bash
journalctl -u epicyon | grep 'THREAD:' > .threads.txt
if [ ! -f .threads.txt ]; then
echo 'No thread events'
else
cat .threads.txt
fi

View File

@ -1610,7 +1610,7 @@ def run_federated_shares_watchdog(project_version: str, httpd) -> None:
"""This tries to keep the federated shares update thread """This tries to keep the federated shares update thread
running even if it dies running even if it dies
""" """
print('Starting federated shares watchdog') print('THREAD: Starting federated shares watchdog')
federated_shares_original = \ federated_shares_original = \
httpd.thrPostSchedule.clone(run_federated_shares_daemon) httpd.thrPostSchedule.clone(run_federated_shares_daemon)
httpd.thrFederatedSharesDaemon.start() httpd.thrFederatedSharesDaemon.start()
@ -1619,6 +1619,7 @@ def run_federated_shares_watchdog(project_version: str, httpd) -> None:
if httpd.thrFederatedSharesDaemon.is_alive(): if httpd.thrFederatedSharesDaemon.is_alive():
continue continue
httpd.thrFederatedSharesDaemon.kill() httpd.thrFederatedSharesDaemon.kill()
print('THREAD: restarting federated shares watchdog')
httpd.thrFederatedSharesDaemon = \ httpd.thrFederatedSharesDaemon = \
federated_shares_original.clone(run_federated_shares_daemon) federated_shares_original.clone(run_federated_shares_daemon)
httpd.thrFederatedSharesDaemon.start() httpd.thrFederatedSharesDaemon.start()

View File

@ -51,7 +51,7 @@ from posts import send_post_via_server
from posts import seconds_between_published from posts import seconds_between_published
from follow import clear_follows from follow import clear_follows
from follow import clear_followers from follow import clear_followers
from follow import send_follow_requestViaServer from follow import send_follow_request_via_server
from follow import send_unfollow_request_via_server from follow import send_unfollow_request_via_server
from siteactive import site_is_active from siteactive import site_is_active
from utils import convert_published_to_local_timezone from utils import convert_published_to_local_timezone
@ -1393,7 +1393,8 @@ def test_post_message_between_servers(base_dir: str) -> None:
'alice', alice_domain, alice_port, [], 'alice', alice_domain, alice_port, [],
status_number, False, bob_send_threads, bob_post_log, status_number, False, bob_send_threads, bob_post_log,
bob_person_cache, bob_cached_webfingers, bob_person_cache, bob_cached_webfingers,
True, __version__, signing_priv_key_pem) True, __version__, signing_priv_key_pem,
bob_domain, None, None)
for _ in range(20): for _ in range(20):
if 'likes' in open(outbox_post_filename).read(): if 'likes' in open(outbox_post_filename).read():
@ -1415,7 +1416,8 @@ def test_post_message_between_servers(base_dir: str) -> None:
status_number, '😀', status_number, '😀',
False, bob_send_threads, bob_post_log, False, bob_send_threads, bob_post_log,
bob_person_cache, bob_cached_webfingers, bob_person_cache, bob_cached_webfingers,
True, __version__, signing_priv_key_pem) True, __version__, signing_priv_key_pem,
bob_domain, None, None)
for i in range(20): for i in range(20):
if 'reactions' in open(outbox_post_filename).read(): if 'reactions' in open(outbox_post_filename).read():
@ -1451,10 +1453,11 @@ def test_post_message_between_servers(base_dir: str) -> None:
object_url, object_url,
False, bob_send_threads, bob_post_log, False, bob_send_threads, bob_post_log,
bob_person_cache, bob_cached_webfingers, bob_person_cache, bob_cached_webfingers,
True, __version__, signing_priv_key_pem) True, __version__, signing_priv_key_pem,
bob_domain, None, None)
announce_message_arrived = False announce_message_arrived = False
outbox_message_arrived = False outbox_message_arrived = False
for i in range(10): for i in range(20):
time.sleep(1) time.sleep(1)
if not os.path.isdir(inbox_path): if not os.path.isdir(inbox_path):
continue continue
@ -1597,7 +1600,8 @@ def test_follow_between_servers(base_dir: str) -> None:
client_to_server, federation_list, client_to_server, federation_list,
alice_send_threads, alice_post_log, alice_send_threads, alice_post_log,
alice_cached_webfingers, alice_person_cache, alice_cached_webfingers, alice_person_cache,
True, __version__, signing_priv_key_pem) True, __version__, signing_priv_key_pem,
alice_domain, None, None)
print('send_result: ' + str(send_result)) print('send_result: ' + str(send_result))
for _ in range(16): for _ in range(16):
@ -1818,7 +1822,8 @@ def test_shared_items_federation(base_dir: str) -> None:
client_to_server, federation_list, client_to_server, federation_list,
alice_send_threads, alice_post_log, alice_send_threads, alice_post_log,
alice_cached_webfingers, alice_person_cache, alice_cached_webfingers, alice_person_cache,
True, __version__, signing_priv_key_pem) True, __version__, signing_priv_key_pem,
alice_domain, None, None)
print('send_result: ' + str(send_result)) print('send_result: ' + str(send_result))
for _ in range(16): for _ in range(16):
@ -2270,7 +2275,8 @@ def test_group_follow(base_dir: str) -> None:
client_to_server, federation_list, client_to_server, federation_list,
alice_send_threads, alice_post_log, alice_send_threads, alice_post_log,
alice_cached_webfingers, alice_person_cache, alice_cached_webfingers, alice_person_cache,
True, __version__, signing_priv_key_pem) True, __version__, signing_priv_key_pem,
alice_domain, None, None)
print('send_result: ' + str(send_result)) print('send_result: ' + str(send_result))
alice_following_filename = \ alice_following_filename = \
@ -2348,7 +2354,8 @@ def test_group_follow(base_dir: str) -> None:
client_to_server, federation_list, client_to_server, federation_list,
bob_send_threads, bob_post_log, bob_send_threads, bob_post_log,
bob_cached_webfingers, bob_person_cache, bob_cached_webfingers, bob_person_cache,
True, __version__, signing_priv_key_pem) True, __version__, signing_priv_key_pem,
bob_domain, None, None)
print('send_result: ' + str(send_result)) print('send_result: ' + str(send_result))
bob_following_filename = \ bob_following_filename = \
@ -3094,13 +3101,13 @@ def test_client_to_server(base_dir: str):
print('\n\nAlice follows Bob') print('\n\nAlice follows Bob')
signing_priv_key_pem = None signing_priv_key_pem = None
send_follow_requestViaServer(alice_dir, session_alice, send_follow_request_via_server(alice_dir, session_alice,
'alice', password, 'alice', password,
alice_domain, alice_port, alice_domain, alice_port,
'bob', bob_domain, bob_port, 'bob', bob_domain, bob_port,
http_prefix, http_prefix,
cached_webfingers, person_cache, cached_webfingers, person_cache,
True, __version__, signing_priv_key_pem) True, __version__, signing_priv_key_pem)
alice_petnames_filename = alice_dir + '/accounts/' + \ alice_petnames_filename = alice_dir + '/accounts/' + \
'alice@' + alice_domain + '/petnames.txt' 'alice@' + alice_domain + '/petnames.txt'
alice_following_filename = \ alice_following_filename = \
@ -3136,13 +3143,13 @@ def test_client_to_server(base_dir: str):
alice_domain, alice_port) alice_domain, alice_port)
print('\n\nEVENT: Bob follows Alice') print('\n\nEVENT: Bob follows Alice')
send_follow_requestViaServer(alice_dir, session_alice, send_follow_request_via_server(alice_dir, session_alice,
'bob', 'bobpass', 'bob', 'bobpass',
bob_domain, bob_port, bob_domain, bob_port,
'alice', alice_domain, alice_port, 'alice', alice_domain, alice_port,
http_prefix, http_prefix,
cached_webfingers, person_cache, cached_webfingers, person_cache,
True, __version__, signing_priv_key_pem) True, __version__, signing_priv_key_pem)
for _ in range(10): for _ in range(10):
if os.path.isfile(alice_dir + '/accounts/alice@' + alice_domain + if os.path.isfile(alice_dir + '/accounts/alice@' + alice_domain +
'/followers.txt'): '/followers.txt'):

View File

@ -861,16 +861,11 @@ def set_theme(base_dir: str, name: str, domain: str,
_remove_theme(base_dir) _remove_theme(base_dir)
# has the theme changed?
themes = get_themes_list(base_dir) themes = get_themes_list(base_dir)
for theme_name in themes: for theme_name in themes:
theme_name_lower = theme_name.lower() theme_name_lower = theme_name.lower()
if name == theme_name_lower: if name == theme_name_lower:
allow_access = allow_local_network_access
try:
globals()['set_theme' + theme_name](base_dir, allow_access)
except BaseException:
print('EX: set_theme unable to set theme ' + theme_name)
if prev_theme_name: if prev_theme_name:
if prev_theme_name.lower() != theme_name_lower: if prev_theme_name.lower() != theme_name_lower:
# change the banner and profile image # change the banner and profile image
@ -878,12 +873,14 @@ def set_theme(base_dir: str, name: str, domain: str,
_set_theme_images(base_dir, name) _set_theme_images(base_dir, name)
_set_theme_fonts(base_dir, name) _set_theme_fonts(base_dir, name)
result = True result = True
break
if not result: if not result:
# default # default
_set_theme_default(base_dir, allow_local_network_access) _set_theme_default(base_dir, allow_local_network_access)
result = True result = True
# read theme settings from a json file in the theme directory
variables_file = base_dir + '/theme/' + name + '/theme.json' variables_file = base_dir + '/theme/' + name + '/theme.json'
if os.path.isfile(variables_file): if os.path.isfile(variables_file):
_read_variables_file(base_dir, name, variables_file, _read_variables_file(base_dir, name, variables_file,

View File

@ -75,6 +75,7 @@ class thread_with_trace(threading.Thread):
def clone(self, func): def clone(self, func):
"""Create a clone """Create a clone
""" """
print('THREAD: clone')
return thread_with_trace(target=func, return thread_with_trace(target=func,
args=self._args, args=self._args,
daemon=True) daemon=True)

View File

@ -245,7 +245,7 @@ def webfinger_meta(http_prefix: str, domain_full: str) -> str:
def webfinger_lookup(path: str, base_dir: str, def webfinger_lookup(path: str, base_dir: str,
domain: str, onion_domain: str, domain: str, onion_domain: str, i2p_domain: str,
port: int, debug: bool) -> {}: port: int, debug: bool) -> {}:
"""Lookup the webfinger endpoint for an account """Lookup the webfinger endpoint for an account
""" """
@ -287,6 +287,11 @@ def webfinger_lookup(path: str, base_dir: str,
if onion_domain in handle: if onion_domain in handle:
handle = handle.replace(onion_domain, domain) handle = handle.replace(onion_domain, domain)
onionify = True onionify = True
i2pify = False
if i2p_domain:
if i2p_domain in handle:
handle = handle.replace(i2p_domain, domain)
i2pify = True
# instance actor # instance actor
if handle.startswith('actor@'): if handle.startswith('actor@'):
handle = handle.replace('actor@', 'inbox@', 1) handle = handle.replace('actor@', 'inbox@', 1)
@ -299,11 +304,14 @@ def webfinger_lookup(path: str, base_dir: str,
if debug: if debug:
print('DEBUG: WEBFINGER filename not found ' + filename) print('DEBUG: WEBFINGER filename not found ' + filename)
return None return None
if not onionify: if not onionify and not i2pify:
wf_json = load_json(filename) wf_json = load_json(filename)
else: elif onionify:
print('Webfinger request for onionified ' + handle) print('Webfinger request for onionified ' + handle)
wf_json = load_json_onionify(filename, domain, onion_domain) wf_json = load_json_onionify(filename, domain, onion_domain)
else:
print('Webfinger request for i2pified ' + handle)
wf_json = load_json_onionify(filename, domain, i2p_domain)
if not wf_json: if not wf_json:
wf_json = {"nickname": "unknown"} wf_json = {"nickname": "unknown"}
return wf_json return wf_json