diff --git a/announce.py b/announce.py index 1bc3c538f..7af0b2951 100644 --- a/announce.py +++ b/announce.py @@ -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] + \ diff --git a/availability.py b/availability.py index fdb913749..b4daddcd8 100644 --- a/availability.py +++ b/availability.py @@ -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) diff --git a/blocking.py b/blocking.py index 39dbd3976..e5f7426db 100644 --- a/blocking.py +++ b/blocking.py @@ -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, diff --git a/daemon.py b/daemon.py index 8994e1d35..b72fa6984 100644 --- a/daemon.py +++ b/daemon.py @@ -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) diff --git a/desktop_client.py b/desktop_client.py index 5c3c7e5b2..b6e1288ad 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -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 + ' 👤 ' + diff --git a/follow.py b/follow.py index db4d59ce2..5145af18e 100644 --- a/follow.py +++ b/follow.py @@ -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 = \ diff --git a/inbox.py b/inbox.py index 66c1f36f0..47a1696d2 100644 --- a/inbox.py +++ b/inbox.py @@ -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']) diff --git a/like.py b/like.py index ee19e461d..859c5247b 100644 --- a/like.py +++ b/like.py @@ -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) diff --git a/outbox.py b/outbox.py index a5b56ed36..1e0e8b5a3 100644 --- a/outbox.py +++ b/outbox.py @@ -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 diff --git a/posts.py b/posts.py index aa4052406..914c521e5 100644 --- a/posts.py +++ b/posts.py @@ -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 diff --git a/reaction.py b/reaction.py index f3f618382..b4d71a433 100644 --- a/reaction.py +++ b/reaction.py @@ -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: diff --git a/relationships.py b/relationships.py index 7ce81e613..d7a99cc73 100644 --- a/relationships.py +++ b/relationships.py @@ -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 diff --git a/utils.py b/utils.py index 2c6096015..638ca9766 100644 --- a/utils.py +++ b/utils.py @@ -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' diff --git a/webapp_calendar.py b/webapp_calendar.py index eebf7bc22..d693dc80d 100644 --- a/webapp_calendar.py +++ b/webapp_calendar.py @@ -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 = \ - ' - ' + \ - '' - else: - event_time = \ - '' + event_time_markup = \ + '' + 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 = \ + ' - ' + \ + '' if event_time and event_description and event_place: calendar_str += \ '
' + translate['Follow'] + ' ' + \ follow_actor_nick + '@' + follow_domain + ' ?
\n' @@ -274,7 +278,7 @@ def html_confirm_unfollow(translate: {}, base_dir: str, '' + translate['Stop following'] + \ ' ' + follow_actor_nick + '@' + follow_domain + ' ?
\n' @@ -321,7 +325,7 @@ def html_confirm_unblock(translate: {}, base_dir: str, '' + translate['Stop blocking'] + ' ' + \ block_actor_nick + '@' + block_domain + ' ?
\n' @@ -368,7 +372,7 @@ def html_confirm_block(translate: {}, base_dir: str, '' + translate['Block'] + ' ' + \ block_actor_nick + '@' + block_domain + ' ?
\n' diff --git a/webapp_moderation.py b/webapp_moderation.py index 3ff6b93f6..292c4feb1 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -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 += '' + alt_domain + '' 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 += \ - '' + alt_domain + '' + if alt_domain: + other_accounts_html += \ + '' + \ + alt_domain + '' other_accounts_html += '\n' if ctr > 0: options_str += other_accounts_html diff --git a/webapp_post.py b/webapp_post.py index 998aa05ac..ec269de67 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -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 += \ " 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 = '' + translate['New account'] + ': ' + \ '@' + \ @@ -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 += \ - '' + alt_domain + '' + if alt_domain: + other_accounts_html += \ + '' + alt_domain + '' 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 += \ - '' + alt_domain + '' + if alt_domain: + other_accounts_html += \ + '' + \ + alt_domain + '' other_accounts_html += '
\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 += '' + translate['New account'] + \ ': @' + new_handle + '
\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 += \ - '' + alt_domain + '' + if alt_domain: + other_accounts_html += \ + '' + alt_domain + '' 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 += \ - '' + alt_domain + '' + if alt_domain: + other_accounts_html += \ + '' + \ + alt_domain + '' other_accounts_html += '\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