merge-requests/30/head
Bob Mottram 2023-01-17 13:32:03 +00:00
commit a64b0d2bf4
19 changed files with 387 additions and 191 deletions

View File

@ -91,6 +91,9 @@ def outbox_announce(recent_posts_cache: {},
print('WARN: no nickname found in ' + message_json['actor'])
return False
domain, _ = get_domain_from_actor(message_json['actor'])
if not domain:
print('WARN: no domain found in ' + message_json['actor'])
return False
post_filename = locate_post(base_dir, nickname, domain,
message_json['object'])
if post_filename:
@ -110,6 +113,9 @@ def outbox_announce(recent_posts_cache: {},
print('WARN: no nickname found in ' + message_json['actor'])
return False
domain, _ = get_domain_from_actor(message_json['actor'])
if not domain:
print('WARN: no domain found in ' + message_json['actor'])
return False
post_filename = locate_post(base_dir, nickname, domain,
message_json['object']['object'])
if post_filename:
@ -187,8 +193,8 @@ def create_announce(session, base_dir: str, federation_list: [],
group_account = False
if has_users_path(object_url):
announce_nickname = get_nickname_from_actor(object_url)
if announce_nickname:
announce_domain, announce_port = get_domain_from_actor(object_url)
announce_domain, announce_port = get_domain_from_actor(object_url)
if announce_nickname and announce_domain:
if '/' + str(announce_nickname) + '/' in object_url:
announce_actor = \
object_url.split('/' + announce_nickname + '/')[0] + \

View File

@ -73,6 +73,8 @@ def outbox_availability(base_dir: str, nickname: str, message_json: {},
if actor_nickname != nickname:
return False
domain, _ = get_domain_from_actor(message_json['actor'])
if not domain:
return False
status = message_json['object'].replace('"', '')
return set_availability(base_dir, nickname, domain, status)

View File

@ -814,6 +814,9 @@ def outbox_block(base_dir: str, nickname: str, domain: str,
return False
domain_blocked, port_blocked = \
get_domain_from_actor(message_json['object'])
if not domain_blocked:
print('WARN: unable to find domain in ' + message_json['object'])
return False
domain_blocked_full = get_full_domain(domain_blocked, port_blocked)
add_block(base_dir, nickname, domain,
@ -872,6 +875,10 @@ def outbox_undo_block(base_dir: str, nickname: str, domain: str,
return
domain_object = message_json['object']['object']
domain_blocked, port_blocked = get_domain_from_actor(domain_object)
if not domain_blocked:
print('WARN: unable to find domain in ' +
message_json['object']['object'])
return
domain_blocked_full = get_full_domain(domain_blocked, port_blocked)
remove_block(base_dir, nickname, domain,

174
daemon.py
View File

@ -679,29 +679,34 @@ class PubServer(BaseHTTPRequestHandler):
self.server.person_cache)
reply_to_nickname = get_nickname_from_actor(in_reply_to)
reply_to_domain, reply_to_port = get_domain_from_actor(in_reply_to)
reply_to_domain_full = get_full_domain(reply_to_domain, reply_to_port)
mentions_str = '@' + reply_to_nickname + '@' + reply_to_domain_full
message_json = None
if reply_to_nickname and reply_to_domain:
reply_to_domain_full = \
get_full_domain(reply_to_domain, reply_to_port)
mentions_str = '@' + reply_to_nickname + '@' + reply_to_domain_full
message_json = \
create_direct_message_post(self.server.base_dir, nickname,
self.server.domain, self.server.port,
self.server.http_prefix,
mentions_str + ' ' + answer,
False, False,
comments_enabled,
attach_image_filename,
media_type, image_description, city,
in_reply_to, in_reply_to_atom_uri,
subject, self.server.debug,
schedule_post,
event_date, event_time,
event_end_time,
location, self.server.system_language,
conversation_id,
self.server.low_bandwidth,
self.server.content_license_url,
languages_understood, False,
self.server.translate, buy_url)
message_json = \
create_direct_message_post(self.server.base_dir, nickname,
self.server.domain,
self.server.port,
self.server.http_prefix,
mentions_str + ' ' + answer,
False, False,
comments_enabled,
attach_image_filename,
media_type, image_description, city,
in_reply_to, in_reply_to_atom_uri,
subject, self.server.debug,
schedule_post,
event_date, event_time,
event_end_time,
location,
self.server.system_language,
conversation_id,
self.server.low_bandwidth,
self.server.content_license_url,
languages_understood, False,
self.server.translate, buy_url)
if message_json:
# NOTE: content and contentMap are not required, but we will keep
# them in there so that the post does not get filtered out by
@ -2082,6 +2087,8 @@ class PubServer(BaseHTTPRequestHandler):
for to_actor in message_json['object']['to']:
to_domain, to_port = \
get_domain_from_actor(to_actor)
if not to_domain:
continue
to_domain_full = \
get_full_domain(to_domain, to_port)
if self.server.domain_full != to_domain_full:
@ -2095,14 +2102,16 @@ class PubServer(BaseHTTPRequestHandler):
local_actor = message_json['object']['attributedTo']
local_domain, local_port = \
get_domain_from_actor(local_actor)
local_domain_full = \
get_full_domain(local_domain, local_port)
if self.server.domain_full != local_domain_full:
print("REJECT: inbox local only post isn't local " +
str(message_json))
self._400()
self.server.postreq_busy = False
return 3
if local_domain:
local_domain_full = \
get_full_domain(local_domain, local_port)
if self.server.domain_full != local_domain_full:
print("REJECT: " +
"inbox local only post isn't local " +
str(message_json))
self._400()
self.server.postreq_busy = False
return 3
# actor should look like a url
if debug:
@ -2130,6 +2139,11 @@ class PubServer(BaseHTTPRequestHandler):
message_domain, _ = \
get_domain_from_actor(message_json['actor'])
if not message_domain:
print('INBOX: POST from unknown domain ' + message_json['actor'])
self._400()
self.server.postreq_busy = False
return 3
self.server.blocked_cache_last_updated = \
update_blocked_cache(self.server.base_dir,
@ -2609,8 +2623,11 @@ class PubServer(BaseHTTPRequestHandler):
if search_nickname:
search_domain, _ = \
get_domain_from_actor(search_handle)
search_handle = \
search_nickname + '@' + search_domain
if search_domain:
search_handle = \
search_nickname + '@' + search_domain
else:
search_handle = ''
else:
search_handle = ''
if '@' not in search_handle:
@ -2622,8 +2639,12 @@ class PubServer(BaseHTTPRequestHandler):
if search_nickname:
search_domain, _ = \
get_domain_from_actor(search_handle)
search_handle = \
search_nickname + '@' + search_domain
if search_domain:
search_handle = \
search_nickname + '@' + \
search_domain
else:
search_handle = ''
else:
search_handle = ''
if '@' not in search_handle:
@ -2713,8 +2734,9 @@ class PubServer(BaseHTTPRequestHandler):
# https://domain
block_domain, block_port = \
get_domain_from_actor(moderation_domain)
full_block_domain = \
get_full_domain(block_domain, block_port)
if block_domain:
full_block_domain = \
get_full_domain(block_domain, block_port)
if '@' in moderation_domain:
# nick@domain or *@domain
full_block_domain = \
@ -2743,8 +2765,9 @@ class PubServer(BaseHTTPRequestHandler):
# https://domain
block_domain, block_port = \
get_domain_from_actor(moderation_domain)
full_block_domain = \
get_full_domain(block_domain, block_port)
if block_domain:
full_block_domain = \
get_full_domain(block_domain, block_port)
if '@' in moderation_domain:
# nick@domain or *@domain
full_block_domain = moderation_domain.split('@')[1]
@ -3144,6 +3167,16 @@ class PubServer(BaseHTTPRequestHandler):
return
options_domain, options_port = get_domain_from_actor(options_actor)
if not options_domain:
if calling_domain.endswith('.onion') and onion_domain:
origin_path_str = 'http://' + onion_domain + users_path
elif (calling_domain.endswith('.i2p') and i2p_domain):
origin_path_str = 'http://' + i2p_domain + users_path
print('WARN: unable to find domain in ' + options_actor)
self._redirect_headers(origin_path_str, cookie, calling_domain)
self.server.postreq_busy = False
return
options_domain_full = get_full_domain(options_domain, options_port)
if chooser_nickname == options_nickname and \
options_domain == domain and \
@ -3942,13 +3975,13 @@ class PubServer(BaseHTTPRequestHandler):
if '&' in following_actor:
following_actor = following_actor.split('&')[0]
following_nickname = get_nickname_from_actor(following_actor)
if not following_nickname:
following_domain, following_port = \
get_domain_from_actor(following_actor)
if not following_nickname or not following_domain:
self.send_response(400)
self.end_headers()
self.server.postreq_busy = False
return
following_domain, following_port = \
get_domain_from_actor(following_actor)
following_domain_full = \
get_full_domain(following_domain, following_port)
if follower_nickname == following_nickname and \
@ -4051,13 +4084,13 @@ class PubServer(BaseHTTPRequestHandler):
if '&' in following_actor:
following_actor = following_actor.split('&')[0]
following_nickname = get_nickname_from_actor(following_actor)
if not following_nickname:
following_domain, following_port = \
get_domain_from_actor(following_actor)
if not following_nickname or not following_domain:
self.send_response(400)
self.end_headers()
self.server.postreq_busy = False
return
following_domain, following_port = \
get_domain_from_actor(following_actor)
if follower_nickname == following_nickname and \
following_domain == domain and \
following_port == port:
@ -4128,19 +4161,19 @@ class PubServer(BaseHTTPRequestHandler):
if '&' in blocking_actor:
blocking_actor = blocking_actor.split('&')[0]
blocking_nickname = get_nickname_from_actor(blocking_actor)
if not blocking_nickname:
blocking_domain, blocking_port = \
get_domain_from_actor(blocking_actor)
if not blocking_nickname or not blocking_domain:
if calling_domain.endswith('.onion') and onion_domain:
origin_path_str = 'http://' + onion_domain + users_path
elif (calling_domain.endswith('.i2p') and i2p_domain):
origin_path_str = 'http://' + i2p_domain + users_path
print('WARN: unable to find blocked nickname in ' +
print('WARN: unable to find blocked nickname or domain in ' +
blocking_actor)
self._redirect_headers(origin_path_str,
cookie, calling_domain)
self.server.postreq_busy = False
return
blocking_domain, blocking_port = \
get_domain_from_actor(blocking_actor)
blocking_domain_full = \
get_full_domain(blocking_domain, blocking_port)
if follower_nickname == blocking_nickname and \
@ -4218,18 +4251,19 @@ class PubServer(BaseHTTPRequestHandler):
if '&' in blocking_actor:
blocking_actor = blocking_actor.split('&')[0]
blocking_nickname = get_nickname_from_actor(blocking_actor)
if not blocking_nickname:
blocking_domain, blocking_port = \
get_domain_from_actor(blocking_actor)
if not blocking_nickname or not blocking_domain:
if calling_domain.endswith('.onion') and onion_domain:
origin_path_str = 'http://' + onion_domain + users_path
elif (calling_domain.endswith('.i2p') and i2p_domain):
origin_path_str = 'http://' + i2p_domain + users_path
print('WARN: unable to find nickname in ' + blocking_actor)
print('WARN: unable to find nickname or domain in ' +
blocking_actor)
self._redirect_headers(origin_path_str,
cookie, calling_domain)
self.server.postreq_busy = False
return
blocking_domain, blocking_port = \
get_domain_from_actor(blocking_actor)
blocking_domain_full = \
get_full_domain(blocking_domain, blocking_port)
if blocker_nickname == blocking_nickname and \
@ -4310,7 +4344,9 @@ class PubServer(BaseHTTPRequestHandler):
if '&' in blocking_actor:
blocking_actor = blocking_actor.split('&')[0]
blocking_nickname = get_nickname_from_actor(blocking_actor)
if not blocking_nickname:
blocking_domain, blocking_port = \
get_domain_from_actor(blocking_actor)
if not blocking_nickname or not blocking_domain:
if calling_domain.endswith('.onion') and onion_domain:
origin_path_str = 'http://' + onion_domain + users_path
elif (calling_domain.endswith('.i2p') and i2p_domain):
@ -4320,8 +4356,6 @@ class PubServer(BaseHTTPRequestHandler):
cookie, calling_domain)
self.server.postreq_busy = False
return
blocking_domain, blocking_port = \
get_domain_from_actor(blocking_actor)
blocking_domain_full = \
get_full_domain(blocking_domain, blocking_port)
if blocker_nickname == blocking_nickname and \
@ -4692,13 +4726,13 @@ class PubServer(BaseHTTPRequestHandler):
# get the actor
if not has_users_path(search_str):
search_nickname = get_nickname_from_actor(search_str)
if not search_nickname:
search_domain, search_port = \
get_domain_from_actor(search_str)
if not search_nickname or not search_domain:
self.send_response(400)
self.end_headers()
self.server.postreq_busy = False
return
search_domain, search_port = \
get_domain_from_actor(search_str)
search_domain_full = \
get_full_domain(search_domain, search_port)
actor = \
@ -5155,9 +5189,9 @@ class PubServer(BaseHTTPRequestHandler):
if '&' in item_id:
item_id = item_id.split('&')[0]
share_nickname = get_nickname_from_actor(share_actor)
if share_nickname:
share_domain, _ = \
get_domain_from_actor(share_actor)
share_domain, _ = \
get_domain_from_actor(share_actor)
if share_nickname and share_domain:
remove_shared_item(base_dir,
share_nickname, share_domain, item_id,
'shares')
@ -5227,9 +5261,9 @@ class PubServer(BaseHTTPRequestHandler):
if '&' in item_id:
item_id = item_id.split('&')[0]
share_nickname = get_nickname_from_actor(share_actor)
if share_nickname:
share_domain, _ = \
get_domain_from_actor(share_actor)
share_domain, _ = \
get_domain_from_actor(share_actor)
if share_nickname and share_domain:
remove_shared_item(base_dir,
share_nickname, share_domain, item_id,
'wanted')
@ -9730,11 +9764,11 @@ class PubServer(BaseHTTPRequestHandler):
following_handle = path.split('/followapprove=')[1]
if '://' in following_handle:
handle_nickname = get_nickname_from_actor(following_handle)
if not handle_nickname:
self._404()
return
handle_domain, handle_port = \
get_domain_from_actor(following_handle)
if not handle_nickname or not handle_domain:
self._404()
return
following_handle = \
handle_nickname + '@' + \
get_full_domain(handle_domain, handle_port)
@ -9912,11 +9946,11 @@ class PubServer(BaseHTTPRequestHandler):
following_handle = path.split('/followdeny=')[1]
if '://' in following_handle:
handle_nickname = get_nickname_from_actor(following_handle)
if not handle_nickname:
self._404()
return
handle_domain, handle_port = \
get_domain_from_actor(following_handle)
if not handle_nickname or not handle_domain:
self._404()
return
following_handle = \
handle_nickname + '@' + \
get_full_domain(handle_domain, handle_port)

View File

@ -1386,7 +1386,11 @@ def _desktop_show_follow_requests(follow_requests_json: {},
print('')
for item in follow_requests_json['orderedItems']:
handle_nickname = get_nickname_from_actor(item)
if not handle_nickname:
continue
handle_domain, handle_port = get_domain_from_actor(item)
if not handle_domain:
continue
handle_domain_full = \
get_full_domain(handle_domain, handle_port)
print(indent + ' 👤 ' +
@ -1412,7 +1416,11 @@ def _desktop_show_following(following_json: {}, translate: {},
print('')
for item in following_json['orderedItems']:
handle_nickname = get_nickname_from_actor(item)
if not handle_nickname:
continue
handle_domain, handle_port = get_domain_from_actor(item)
if not handle_domain:
continue
handle_domain_full = \
get_full_domain(handle_domain, handle_port)
print(indent + ' 👤 ' +

View File

@ -191,6 +191,9 @@ def is_following_actor(base_dir: str,
print('WARN: unable to find nickname in ' + actor)
return False
following_domain, following_port = get_domain_from_actor(actor)
if not following_domain:
print('WARN: unable to find domain in ' + actor)
return False
following_handle = \
get_full_domain(following_nickname + '@' + following_domain,
following_port)
@ -1437,6 +1440,10 @@ def outbox_undo_follow(base_dir: str, message_json: {}, debug: bool) -> None:
return
domain_follower, port_follower = \
get_domain_from_actor(message_json['object']['actor'])
if not domain_follower:
print('WARN: unable to find domain in ' +
message_json['object']['actor'])
return
domain_follower_full = get_full_domain(domain_follower, port_follower)
nickname_following = \
@ -1447,6 +1454,10 @@ def outbox_undo_follow(base_dir: str, message_json: {}, debug: bool) -> None:
return
domain_following, port_following = \
get_domain_from_actor(message_json['object']['object'])
if not domain_following:
print('WARN: unable to find domain in ' +
message_json['object']['object'])
return
domain_following_full = get_full_domain(domain_following, port_following)
group_account = \

138
inbox.py
View File

@ -674,12 +674,14 @@ def save_post_to_inbox_queue(base_dir: str, http_prefix: str,
post_json_object['object']['inReplyTo']
reply_domain, _ = \
get_domain_from_actor(in_reply_to)
if is_blocked_domain(base_dir, reply_domain, blocked_cache):
if debug:
print('WARN: post contains reply from ' +
str(actor) +
' to a blocked domain: ' + reply_domain)
return None
if reply_domain:
if is_blocked_domain(base_dir, reply_domain,
blocked_cache):
if debug:
print('WARN: post contains reply from ' +
str(actor) +
' to a blocked domain: ' + reply_domain)
return None
reply_nickname = \
get_nickname_from_actor(in_reply_to)
@ -974,6 +976,10 @@ def _receive_undo_follow(base_dir: str, message_json: {},
return False
domain_follower, port_follower = \
get_domain_from_actor(message_json['object']['actor'])
if not domain_follower:
print('WARN: unable to find domain in ' +
message_json['object']['actor'])
return False
domain_follower_full = get_full_domain(domain_follower, port_follower)
nickname_following = \
@ -984,6 +990,10 @@ def _receive_undo_follow(base_dir: str, message_json: {},
return False
domain_following, port_following = \
get_domain_from_actor(message_json['object']['object'])
if not domain_following:
print('WARN: unable to find domain in ' +
message_json['object']['object'])
return False
if onion_domain:
if domain_following.endswith(onion_domain):
domain_following = domain
@ -1149,46 +1159,51 @@ def _person_receive_update(base_dir: str,
print('actor updated for ' + person_json['id'])
if person_json.get('movedTo'):
prev_domain_full = None
prev_domain, prev_port = get_domain_from_actor(person_json['id'])
prev_domain_full = get_full_domain(prev_domain, prev_port)
if prev_domain:
prev_domain_full = get_full_domain(prev_domain, prev_port)
prev_nickname = get_nickname_from_actor(person_json['id'])
new_domain = None
new_domain, new_port = get_domain_from_actor(person_json['movedTo'])
new_domain_full = get_full_domain(new_domain, new_port)
if new_domain:
new_domain_full = get_full_domain(new_domain, new_port)
new_nickname = get_nickname_from_actor(person_json['movedTo'])
new_actor = prev_nickname + '@' + prev_domain_full + ' ' + \
new_nickname + '@' + new_domain_full
refollow_str = ''
refollow_filename = base_dir + '/accounts/actors_moved.txt'
refollow_file_exists = False
if os.path.isfile(refollow_filename):
try:
with open(refollow_filename, 'r',
encoding='utf-8') as fp_refollow:
refollow_str = fp_refollow.read()
refollow_file_exists = True
except OSError:
print('EX: unable to read ' + refollow_filename)
if new_actor not in refollow_str:
refollow_type = 'w+'
if refollow_file_exists:
refollow_type = 'a+'
try:
with open(refollow_filename, refollow_type,
encoding='utf-8') as fp_refollow:
fp_refollow.write(new_actor + '\n')
except OSError:
print('EX: unable to write to ' +
refollow_filename)
prev_avatar_url = \
get_person_avatar_url(base_dir, person_json['id'],
person_cache)
if prev_avatar_url is None:
prev_avatar_url = ''
_notify_moved(base_dir, domain_full,
prev_nickname + '@' + prev_domain_full,
new_nickname + '@' + new_domain_full,
person_json['id'], prev_avatar_url, http_prefix)
if prev_domain_full and new_domain:
new_actor = prev_nickname + '@' + prev_domain_full + ' ' + \
new_nickname + '@' + new_domain_full
refollow_str = ''
refollow_filename = base_dir + '/accounts/actors_moved.txt'
refollow_file_exists = False
if os.path.isfile(refollow_filename):
try:
with open(refollow_filename, 'r',
encoding='utf-8') as fp_refollow:
refollow_str = fp_refollow.read()
refollow_file_exists = True
except OSError:
print('EX: unable to read ' + refollow_filename)
if new_actor not in refollow_str:
refollow_type = 'w+'
if refollow_file_exists:
refollow_type = 'a+'
try:
with open(refollow_filename, refollow_type,
encoding='utf-8') as fp_refollow:
fp_refollow.write(new_actor + '\n')
except OSError:
print('EX: unable to write to ' +
refollow_filename)
prev_avatar_url = \
get_person_avatar_url(base_dir, person_json['id'],
person_cache)
if prev_avatar_url is None:
prev_avatar_url = ''
_notify_moved(base_dir, domain_full,
prev_nickname + '@' + prev_domain_full,
new_nickname + '@' + new_domain_full,
person_json['id'], prev_avatar_url, http_prefix)
# remove avatar if it exists so that it will be refreshed later
# when a timeline is constructed
@ -1476,9 +1491,9 @@ def _receive_update_activity(recent_posts_cache: {}, session, base_dir: str,
if debug:
print('Request to update actor: ' + str(message_json))
update_nickname = get_nickname_from_actor(message_json['actor'])
if update_nickname:
update_domain, update_port = \
get_domain_from_actor(message_json['actor'])
update_domain, update_port = \
get_domain_from_actor(message_json['actor'])
if update_nickname and update_domain:
if _person_receive_update(base_dir,
domain, port,
update_nickname, update_domain,
@ -2648,6 +2663,9 @@ def _receive_announce(recent_posts_cache: {},
print('WARN: _receive_announce no actor_nickname')
return False
actor_domain, _ = get_domain_from_actor(message_json['actor'])
if not actor_domain:
print('WARN: _receive_announce no actor_domain')
return False
if is_blocked(base_dir, nickname, domain, actor_nickname, actor_domain):
print('Receive announce blocked for actor: ' +
actor_nickname + '@' + actor_domain)
@ -2666,6 +2684,9 @@ def _receive_announce(recent_posts_cache: {},
print('WARN: _receive_announce no announced_actor_nickname')
return False
announced_actor_domain, _ = get_domain_from_actor(message_json['object'])
if not announced_actor_domain:
print('WARN: _receive_announce no announced_actor_domain')
return False
if is_blocked(base_dir, nickname, domain,
announced_actor_nickname, announced_actor_domain):
print('Receive announce object blocked for actor: ' +
@ -3588,6 +3609,8 @@ def _inbox_update_calendar(base_dir: str, handle: str,
if not actor_nickname:
return
actor_domain, _ = get_domain_from_actor(actor)
if not actor_domain:
return
handle_nickname = handle.split('@')[0]
handle_domain = handle.split('@')[1]
if not receiving_calendar_events(base_dir,
@ -4086,6 +4109,8 @@ def _low_frequency_post_notification(base_dir: str, http_prefix: str,
if not from_nickname:
return
from_domain, from_port = get_domain_from_actor(attributed_to)
if not from_domain:
return
from_domain_full = get_full_domain(from_domain, from_port)
if notify_when_person_posts(base_dir, nickname, domain,
from_nickname, from_domain_full):
@ -4116,6 +4141,8 @@ def _check_for_git_patches(base_dir: str, nickname: str, domain: str,
if not from_nickname:
return 0
from_domain, from_port = get_domain_from_actor(attributed_to)
if not from_domain:
return 0
from_domain_full = get_full_domain(from_domain, from_port)
if receive_git_patch(base_dir, nickname, domain,
json_obj['type'], json_obj['summary'],
@ -5144,6 +5171,11 @@ def _receive_follow_request(session, session_onion, session_i2p,
'users/profile/author/accounts/channel missing from actor')
return False
domain, temp_port = get_domain_from_actor(message_json['actor'])
if not domain:
if debug:
print('DEBUG: receive follow request actor without domain ' +
message_json['actor'])
return False
from_port = port
domain_full = get_full_domain(domain, temp_port)
if temp_port:
@ -5167,6 +5199,11 @@ def _receive_follow_request(session, session_onion, session_i2p,
'not found within object')
return False
domain_to_follow, temp_port = get_domain_from_actor(message_json['object'])
if not domain_to_follow:
if debug:
print('DEBUG: receive follow request no domain found in object ' +
message_json['object'])
return False
# switch to the local domain rather than its onion or i2p version
if onion_domain:
if domain_to_follow.endswith(onion_domain):
@ -5613,12 +5650,13 @@ def run_inbox_queue(server,
if queue_json.get('actor'):
if isinstance(queue_json['actor'], str):
sender_domain, _ = get_domain_from_actor(queue_json['actor'])
if sender_domain.endswith('.onion') and \
session_onion and proxy_type != 'tor':
curr_session = session_onion
elif (sender_domain.endswith('.i2p') and
session_i2p and proxy_type != 'i2p'):
curr_session = session_i2p
if sender_domain:
if sender_domain.endswith('.onion') and \
session_onion and proxy_type != 'tor':
curr_session = session_onion
elif (sender_domain.endswith('.i2p') and
session_i2p and proxy_type != 'i2p'):
curr_session = session_i2p
if debug and queue_json.get('actor'):
print('Obtaining public key for actor ' + queue_json['actor'])

14
like.py
View File

@ -114,12 +114,14 @@ def _create_like(recent_posts_cache: {},
liked_post_nickname = get_nickname_from_actor(object_url)
liked_post_domain, liked_post_port = \
get_domain_from_actor(object_url)
if '/' + str(liked_post_nickname) + '/' in object_url:
actor_liked = \
object_url.split('/' + liked_post_nickname + '/')[0] + \
'/' + liked_post_nickname
group_account = \
has_group_type(base_dir, actor_liked, person_cache)
if liked_post_nickname and liked_post_domain:
if '/' + str(liked_post_nickname) + '/' in object_url:
actor_liked = \
object_url.split('/' +
liked_post_nickname + '/')[0] + \
'/' + liked_post_nickname
group_account = \
has_group_type(base_dir, actor_liked, person_cache)
if liked_post_nickname:
post_filename = locate_post(base_dir, nickname, domain, object_url)

View File

@ -275,6 +275,8 @@ def post_message_to_outbox(session, translate: {},
if isinstance(message_json['object']['to'], list):
for to_actor in message_json['object']['to']:
to_domain, to_port = get_domain_from_actor(to_actor)
if not to_domain:
continue
to_domain_full = get_full_domain(to_domain, to_port)
if domain_full != to_domain_full:
print("REJECT: local only post isn't local " +
@ -283,11 +285,13 @@ def post_message_to_outbox(session, translate: {},
# check that the sender is local
local_actor = message_json['object']['attributedTo']
local_domain, local_port = get_domain_from_actor(local_actor)
local_domain_full = get_full_domain(local_domain, local_port)
if domain_full != local_domain_full:
print("REJECT: local only post isn't local " +
str(message_json))
return False
if local_domain:
local_domain_full = \
get_full_domain(local_domain, local_port)
if domain_full != local_domain_full:
print("REJECT: local only post isn't local " +
str(message_json))
return False
if is_quote_toot(message_json, ''):
print('REJECT: POST quote toot ' + str(message_json))
@ -357,11 +361,12 @@ def post_message_to_outbox(session, translate: {},
return False
test_domain, test_port = get_domain_from_actor(message_json['actor'])
test_domain = get_full_domain(test_domain, test_port)
if is_blocked_domain(base_dir, test_domain):
if debug:
print('DEBUG: domain is blocked: ' + message_json['actor'])
return False
if test_domain:
test_domain = get_full_domain(test_domain, test_port)
if is_blocked_domain(base_dir, test_domain):
if debug:
print('DEBUG: domain is blocked: ' + message_json['actor'])
return False
# replace youtube, so that google gets less tracking data
replace_you_tube(message_json, yt_replace_domain, system_language)
# replace twitter, so that twitter posts can be shown without

View File

@ -760,8 +760,9 @@ def get_post_domains(session, outbox_url: str, max_posts: int, debug: bool,
if isinstance(item['object']['inReplyTo'], str):
post_domain, _ = \
get_domain_from_actor(item['object']['inReplyTo'])
if post_domain not in post_domains:
post_domains.append(post_domain)
if post_domain:
if post_domain not in post_domains:
post_domains.append(post_domain)
if item['object'].get('tag'):
for tag_item in item['object']['tag']:
@ -772,8 +773,9 @@ def get_post_domains(session, outbox_url: str, max_posts: int, debug: bool,
if tag_item.get('href'):
post_domain, _ = \
get_domain_from_actor(tag_item['href'])
if post_domain not in post_domains:
post_domains.append(post_domain)
if post_domain:
if post_domain not in post_domains:
post_domains.append(post_domain)
return post_domains
@ -818,6 +820,8 @@ def _get_posts_for_blocked_domains(base_dir: str,
if isinstance(item['object']['inReplyTo'], str):
post_domain, _ = \
get_domain_from_actor(item['object']['inReplyTo'])
if not post_domain:
continue
if is_blocked_domain(base_dir, post_domain):
if item['object'].get('url'):
url = item['object']['url']
@ -837,6 +841,8 @@ def _get_posts_for_blocked_domains(base_dir: str,
if tag_type == 'mention' and tag_item.get('href'):
post_domain, _ = \
get_domain_from_actor(tag_item['href'])
if not post_domain:
continue
if is_blocked_domain(base_dir, post_domain):
if item['object'].get('url'):
url = item['object']['url']
@ -1084,6 +1090,11 @@ def _create_post_cw_from_reply(base_dir: str, nickname: str, domain: str,
def _attach_post_license(post_json_object: {},
content_license_url: str) -> None:
"""Attaches a license to each post
Also see:
https://codeberg.org/fediverse/fep/src/branch/main/feps/fep-c118.md
NOTE: at present (Jan 2023) there is no consensus about how to
represent license information on ActivityPub posts, so this might
need to change if such a consensus appears.
"""
post_json_object['attachment'].append({
"type": "PropertyValue",
@ -1285,7 +1296,15 @@ def _create_post_place_and_time(event_date: str, end_date: str,
end_date_str = end_date + 'T' + end_time + \
':00' + strftime("%z", gmtime())
else:
end_date_str = end_date + 'T12:00:00Z'
if not event_time:
end_date_str = end_date + 'T12:00:00Z'
else:
if event_time.endswith('Z'):
end_date_str = end_date + 'T' + event_time
else:
end_date_str = \
end_date + 'T' + event_time + ':00' + \
strftime("%z", gmtime())
# get the starting date and time
event_date_str = None

View File

@ -113,12 +113,14 @@ def _reactionpost(recent_posts_cache: {},
reaction_post_nickname = get_nickname_from_actor(object_url)
reaction_post_domain, reaction_post_port = \
get_domain_from_actor(object_url)
if '/' + str(reaction_post_nickname) + '/' in object_url:
actor_reaction = \
object_url.split('/' + reaction_post_nickname + '/')[0] + \
'/' + reaction_post_nickname
group_account = \
has_group_type(base_dir, actor_reaction, person_cache)
if reaction_post_domain:
if '/' + str(reaction_post_nickname) + '/' in object_url:
actor_reaction = \
object_url.split('/' +
reaction_post_nickname + '/')[0] + \
'/' + reaction_post_nickname
group_account = \
has_group_type(base_dir, actor_reaction, person_cache)
if reaction_post_nickname:
post_filename = locate_post(base_dir, nickname, domain, object_url)
@ -595,6 +597,8 @@ def html_emoji_reactions(post_json_object: {}, interactive: bool,
if not emoji_nickname:
return ''
emoji_domain, _ = get_domain_from_actor(emoji_actor)
if not emoji_domain:
return ''
emoji_handle = emoji_nickname + '@' + emoji_domain
if emoji_actor == actor:
if emoji_content not in reacted_to_by_this_actor:

View File

@ -208,6 +208,8 @@ def update_moved_actors(base_dir: str, debug: bool) -> None:
actor_str = actor_str.replace('.json', '').replace('#', '/')
nickname = get_nickname_from_actor(actor_str)
domain, port = get_domain_from_actor(actor_str)
if not domain:
continue
domain_full = get_full_domain(domain, port)
handle = nickname + '@' + domain_full
actors_dict[handle] = orig_str

View File

@ -4223,6 +4223,15 @@ def license_link_from_name(license: str) -> str:
value = 'https://www.gnu.org/licenses/fdl-1.3.html'
elif 'OPL' in value_upper or 'OPEN PUBLICATION LIC' in value_upper:
value = 'https://opencontent.org/openpub'
elif 'PDDL' in value_upper or 'OPEN DATA COMMONS PUBLIC' in value_upper:
value = 'https://opendatacommons.org/licenses/pddl'
elif 'ODBL' in value_upper or 'OPEN DATA COMMONS OPEN' in value_upper:
value = 'https://opendatacommons.org/licenses/odbl'
elif 'ODC' in value_upper or 'OPEN DATA COMMONS ATTR' in value_upper:
value = 'https://opendatacommons.org/licenses/by'
elif 'OGL' in value_upper or 'OPEN GOVERNMENT LIC' in value_upper:
value = \
'https://www.nationalarchives.gov.uk/doc/open-government-licence'
elif 'PDL' in value_upper or \
'PUBLIC DOCUMENTATION LIC' in value_upper:
value = 'http://www.openoffice.org/licenses/PDL.html'

View File

@ -49,6 +49,8 @@ def html_calendar_delete_confirm(translate: {}, base_dir: str,
return None
actor = local_actor_url(http_prefix, nickname, domain_full)
domain, _ = get_domain_from_actor(actor)
if not domain:
return None
message_id = actor + '/statuses/' + post_id
post_filename = locate_post(base_dir, nickname, domain, message_id)
@ -171,6 +173,7 @@ def _html_calendar_day(person_cache: {}, translate: {},
if day_events:
for event_post in day_events:
event_time = None
event_time_markup = None
event_end_time = None
start_time_str = ''
end_time_str = ''
@ -272,20 +275,27 @@ def _html_calendar_day(person_cache: {}, translate: {},
event_class = 'calendar__day__event__public__rtl'
cal_item_class = 'calItemPublic'
if event_time:
if event_end_time:
event_time = \
'<time datetime="' + start_time_str + '">' + \
event_time + '</time> - ' + \
'<time datetime="' + end_time_str + '">' + \
event_end_time + '</time>'
else:
event_time = \
'<time datetime="' + start_time_str + '">' + \
event_time + '</time>'
event_time_markup = \
'<time datetime="' + start_time_str + '">' + \
event_time + '</time>'
if event_time and event_end_time and \
start_time_str != end_time_str:
event_time_int_str = event_time.replace(':', '')
event_end_time_int_str = event_end_time.replace(':', '')
if event_time_int_str.isdigit() and \
event_end_time_int_str.isdigit():
if int(event_end_time_int_str) > \
int(event_time_int_str):
event_time_markup = \
'<time datetime="' + start_time_str + '">' + \
event_time_markup + '</time> - ' + \
'<time datetime="' + end_time_str + '">' + \
event_end_time + '</time>'
if event_time and event_description and event_place:
calendar_str += \
'<tr class="' + cal_item_class + '">' + \
'<td class="calendar__day__time"><b>' + event_time + \
'<td class="calendar__day__time"><b>' + \
event_time_markup + \
'</b></td><td class="' + event_class + '">' + \
'<span class="place">' + \
event_place + '</span><br>' + event_description + \
@ -293,7 +303,8 @@ def _html_calendar_day(person_cache: {}, translate: {},
elif event_time and event_description and not event_place:
calendar_str += \
'<tr class="' + cal_item_class + '">' + \
'<td class="calendar__day__time"><b>' + event_time + \
'<td class="calendar__day__time"><b>' + \
event_time_markup + \
'</b></td><td class="' + event_class + '">' + \
event_description + '</td>' + delete_button_str + '</tr>\n'
elif not event_time and event_description and not event_place:
@ -312,7 +323,8 @@ def _html_calendar_day(person_cache: {}, translate: {},
elif event_time and not event_description and event_place:
calendar_str += \
'<tr class="' + cal_item_class + '">' + \
'<td class="calendar__day__time"><b>' + event_time + \
'<td class="calendar__day__time"><b>' + \
event_time_markup + \
'</b></td><td class="' + event_class + '">' + \
'<span class="place">' + \
event_place + '</span></td>' + \

View File

@ -51,6 +51,8 @@ def html_confirm_delete(server,
if not nickname:
return None
domain, port = get_domain_from_actor(actor)
if not domain:
return None
domain_full = get_full_domain(domain, port)
post_filename = locate_post(base_dir, nickname, domain, message_id)
@ -135,6 +137,8 @@ def html_confirm_remove_shared_item(translate: {},
if not nickname:
return None
domain, port = get_domain_from_actor(actor)
if not domain:
return None
domain_full = get_full_domain(domain, port)
shares_file = \
acct_dir(base_dir, nickname, domain) + '/' + shares_file_type + '.json'
@ -224,7 +228,7 @@ def html_confirm_follow(translate: {}, base_dir: str,
' <img loading="lazy" decoding="async" ' + \
'src="' + follow_profile_url + '"/></a>\n'
follow_actor_nick = get_nickname_from_actor(follow_actor)
if follow_actor_nick:
if follow_actor_nick and follow_domain:
follow_str += \
' <p class="followText">' + translate['Follow'] + ' ' + \
follow_actor_nick + '@' + follow_domain + ' ?</p>\n'
@ -274,7 +278,7 @@ def html_confirm_unfollow(translate: {}, base_dir: str,
' <img loading="lazy" decoding="async" src="' + \
follow_profile_url + '"/></a>\n'
follow_actor_nick = get_nickname_from_actor(follow_actor)
if follow_actor_nick:
if follow_actor_nick and follow_domain:
follow_str += \
' <p class="followText">' + translate['Stop following'] + \
' ' + follow_actor_nick + '@' + follow_domain + ' ?</p>\n'
@ -321,7 +325,7 @@ def html_confirm_unblock(translate: {}, base_dir: str,
' <img loading="lazy" decoding="async" src="' + \
block_profile_url + '"/></a>\n'
block_actor_nick = get_nickname_from_actor(block_actor)
if block_actor_nick:
if block_actor_nick and block_domain:
block_str += \
' <p class="blockText">' + translate['Stop blocking'] + ' ' + \
block_actor_nick + '@' + block_domain + ' ?</p>\n'
@ -368,7 +372,7 @@ def html_confirm_block(translate: {}, base_dir: str,
' <img loading="lazy" decoding="async" src="' + \
block_profile_url + '"/></a>\n'
block_actor_nick = get_nickname_from_actor(block_actor)
if block_actor_nick:
if block_actor_nick and block_domain:
block_str += \
' <p class="blockText">' + translate['Block'] + ' ' + \
block_actor_nick + '@' + block_domain + ' ?</p>\n'

View File

@ -119,6 +119,8 @@ def html_account_info(translate: {},
if not search_nickname:
return ''
search_domain, search_port = get_domain_from_actor(search_handle)
if not search_domain:
return ''
search_handle = search_nickname + '@' + search_domain
search_actor = \
@ -160,6 +162,8 @@ def html_account_info(translate: {},
if not follower_nickname:
return ''
follower_domain, follower_port = get_domain_from_actor(follower_actor)
if not follower_domain:
return ''
follower_domain_full = get_full_domain(follower_domain, follower_port)
if is_blocked(base_dir, nickname, domain,
follower_nickname, follower_domain_full):
@ -177,6 +181,8 @@ def html_account_info(translate: {},
return ''
following_domain, following_port = \
get_domain_from_actor(following_actor)
if not following_domain:
return ''
following_domain_full = \
get_full_domain(following_domain, following_port)
if is_blocked(base_dir, nickname, domain,
@ -242,6 +248,8 @@ def html_account_info(translate: {},
if not following_nickname:
return ''
following_domain, following_port = get_domain_from_actor(actor)
if not following_domain:
return ''
following_domain_full = \
get_full_domain(following_domain, following_port)
info_form += '<a href="' + actor + '" ' + \
@ -263,6 +271,8 @@ def html_account_info(translate: {},
if not follower_nickname:
return ''
follower_domain, follower_port = get_domain_from_actor(actor)
if not follower_domain:
return ''
follower_domain_full = \
get_full_domain(follower_domain, follower_port)
info_form += '<a href="' + actor + '" ' + \

View File

@ -336,14 +336,18 @@ def html_person_options(default_timeline: str,
other_accounts_html += ' '
ctr += 1
alt_domain, _ = get_domain_from_actor(alt_actor)
if not alt_domain:
continue
other_accounts_html += \
'<a href="' + alt_actor + '">' + alt_domain + '</a>'
elif isinstance(also_known_as, str):
if also_known_as != options_actor:
ctr += 1
alt_domain, _ = get_domain_from_actor(also_known_as)
other_accounts_html += \
'<a href="' + also_known_as + '">' + alt_domain + '</a>'
if alt_domain:
other_accounts_html += \
'<a href="' + also_known_as + '">' + \
alt_domain + '</a>'
other_accounts_html += '</p>\n'
if ctr > 0:
options_str += other_accounts_html

View File

@ -137,8 +137,8 @@ def _html_post_metadata_open_graph(domain: str, post_json_object: {},
if isinstance(obj_json['attributedTo'], str):
attrib = obj_json['attributedTo']
actor_nick = get_nickname_from_actor(attrib)
if actor_nick:
actor_domain, _ = get_domain_from_actor(attrib)
actor_domain, _ = get_domain_from_actor(attrib)
if actor_nick and actor_domain:
actor_handle = actor_nick + '@' + actor_domain
metadata += \
" <meta name=\"DC.creator\" " + \
@ -512,9 +512,10 @@ def _get_reply_icon_html(base_dir: str, nickname: str, domain: str,
return reply_str
block_domain, _ = \
get_domain_from_actor(post_json_object['object']['replyTo'])
if not is_blocked(base_dir, nickname, domain,
block_nickname, block_domain, {}):
reply_to_link = post_json_object['object']['replyTo']
if block_domain:
if not is_blocked(base_dir, nickname, domain,
block_nickname, block_domain, {}):
reply_to_link = post_json_object['object']['replyTo']
if post_json_object['object'].get('attributedTo'):
if isinstance(post_json_object['object']['attributedTo'], str):
@ -1306,7 +1307,7 @@ def _get_post_title_announce_html(base_dir: str,
if len(announce_display_name) < 2 or \
display_name_is_emoji(announce_display_name):
announce_display_name = None
if not announce_display_name:
if not announce_display_name and announce_domain:
announce_display_name = announce_nickname + '@' + announce_domain
_log_post_timing(enable_timing_log, post_start_time, '13.3')
@ -1666,7 +1667,7 @@ def _get_footer_with_icons(show_icons: bool,
footer_str += delete_str + mute_str + edit_str + buy_str
if not is_news_post(post_json_object):
footer_str += ' '
if content_license_url:
if content_license_url and not is_reminder(post_json_object):
footer_str += _get_copyright_footer(content_license_url,
translate)
# show the date
@ -1798,11 +1799,17 @@ def _get_content_license(post_json_object: {}) -> str:
for item in post_json_object['object']['attachment']:
if not item.get('name'):
continue
if not item.get('value'):
name_lower = item['name'].lower()
if 'license' not in name_lower and \
'copyright' not in name_lower and \
'licence' not in name_lower:
continue
if item['name'] != 'license':
if item.get('value'):
value = item['value']
elif item.get('href'):
value = item['href']
else:
continue
value = item['value']
if '://' not in value:
value = license_link_from_name(value)
return value
@ -1986,6 +1993,8 @@ def individual_post_as_html(signing_priv_key_pem: str,
if not post_actor_nickname:
return ''
post_actor_domain, post_actor_port = get_domain_from_actor(post_actor)
if not post_actor_domain:
return ''
post_actor_domain_full = \
get_full_domain(post_actor_domain, post_actor_port)
post_actor_handle = post_actor_nickname + '@' + post_actor_domain_full
@ -2406,7 +2415,7 @@ def individual_post_as_html(signing_priv_key_pem: str,
footer_str = ''
else:
footer_str = '<div class="' + container_class_icons + '">\n'
if content_license_url:
if content_license_url and not is_reminder(post_json_object):
footer_str += _get_copyright_footer(content_license_url,
translate)
conv_link = '/users/' + nickname + '?convthread=' + \
@ -2762,6 +2771,8 @@ def html_individual_post(recent_posts_cache: {}, max_recent_posts: int,
if not by_str_nickname:
return ''
by_str_domain, by_str_port = get_domain_from_actor(by_str)
if not by_str_domain:
return ''
by_str_domain = get_full_domain(by_str_domain, by_str_port)
by_str_handle = by_str_nickname + '@' + by_str_domain
if translate.get(by_text):

View File

@ -480,8 +480,8 @@ def _get_profile_header(base_dir: str, http_prefix: str, nickname: str,
if moved_to:
new_nickname = get_nickname_from_actor(moved_to)
new_domain, new_port = get_domain_from_actor(moved_to)
new_domain_full = get_full_domain(new_domain, new_port)
if new_nickname and new_domain:
new_domain_full = get_full_domain(new_domain, new_port)
html_str += \
' <p>' + translate['New account'] + ': ' + \
'<a href="' + moved_to + '">@' + \
@ -500,15 +500,18 @@ def _get_profile_header(base_dir: str, http_prefix: str, nickname: str,
other_accounts_html += ' '
ctr += 1
alt_domain, _ = get_domain_from_actor(alt_actor)
other_accounts_html += \
'<a href="' + alt_actor + \
'" tabindex="1">' + alt_domain + '</a>'
if alt_domain:
other_accounts_html += \
'<a href="' + alt_actor + \
'" tabindex="1">' + alt_domain + '</a>'
elif isinstance(also_known_as, str):
if also_known_as != actor:
ctr += 1
alt_domain, _ = get_domain_from_actor(also_known_as)
other_accounts_html += \
'<a href="' + also_known_as + '">' + alt_domain + '</a>'
if alt_domain:
other_accounts_html += \
'<a href="' + also_known_as + '">' + \
alt_domain + '</a>'
other_accounts_html += '</p>\n'
if ctr > 0:
html_str += other_accounts_html
@ -586,8 +589,8 @@ def _get_profile_header_after_search(nickname: str, default_timeline: str,
if moved_to:
new_nickname = get_nickname_from_actor(moved_to)
new_domain, new_port = get_domain_from_actor(moved_to)
new_domain_full = get_full_domain(new_domain, new_port)
if new_nickname and new_domain:
new_domain_full = get_full_domain(new_domain, new_port)
new_handle = new_nickname + '@' + new_domain_full
html_str += ' <p>' + translate['New account'] + \
': <a href="' + moved_to + '">@' + new_handle + '</a></p>\n'
@ -604,15 +607,18 @@ def _get_profile_header_after_search(nickname: str, default_timeline: str,
other_accounts_html += ' '
ctr += 1
alt_domain, _ = get_domain_from_actor(alt_actor)
other_accounts_html += \
'<a href="' + alt_actor + \
'" tabindex="1">' + alt_domain + '</a>'
if alt_domain:
other_accounts_html += \
'<a href="' + alt_actor + \
'" tabindex="1">' + alt_domain + '</a>'
elif isinstance(also_known_as, str):
if also_known_as != actor:
ctr += 1
alt_domain, _ = get_domain_from_actor(also_known_as)
other_accounts_html += \
'<a href="' + also_known_as + '">' + alt_domain + '</a>'
if alt_domain:
other_accounts_html += \
'<a href="' + also_known_as + '">' + \
alt_domain + '</a>'
other_accounts_html += '</p>\n'
if ctr > 0:
@ -2819,6 +2825,8 @@ def _individual_follow_as_html(signing_priv_key_pem: str,
if not follow_url_nickname:
return ''
follow_url_domain, follow_url_port = get_domain_from_actor(follow_url)
if not follow_url_domain:
return ''
follow_url_domain_full = \
get_full_domain(follow_url_domain, follow_url_port)
title_str = '@' + follow_url_nickname + '@' + follow_url_domain_full