From e0ea772681616385b43deec99d91f92767eac8af Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 9 Jan 2024 16:59:23 +0000 Subject: [PATCH] Enable reading friendica-style actors --- acceptreject.py | 13 ++-- announce.py | 31 +++++---- availability.py | 6 +- blocking.py | 7 +- bookmarks.py | 7 +- daemon.py | 43 +++++++----- delete.py | 4 +- desktop_client.py | 6 +- follow.py | 18 ++--- inbox.py | 170 +++++++++++++++++++++++++-------------------- like.py | 10 ++- manualapprove.py | 4 +- outbox.py | 21 +++--- person.py | 3 +- posts.py | 29 ++++---- question.py | 12 ++-- reaction.py | 13 ++-- shares.py | 8 ++- skills.py | 6 +- speaker.py | 7 +- utils.py | 17 ++++- webapp_likers.py | 4 +- webapp_post.py | 35 ++++++---- webapp_profile.py | 9 ++- webapp_timeline.py | 8 ++- 25 files changed, 300 insertions(+), 191 deletions(-) diff --git a/acceptreject.py b/acceptreject.py index f447d62ca..e525cfd14 100644 --- a/acceptreject.py +++ b/acceptreject.py @@ -22,6 +22,7 @@ from utils import has_group_type from utils import local_actor_url from utils import has_actor from utils import has_object_string_type +from utils import get_actor_from_post def _create_accept_reject(base_dir: str, federation_list: [], @@ -37,7 +38,8 @@ def _create_accept_reject(base_dir: str, federation_list: [], if not object_json.get('actor'): return None - if not url_permitted(object_json['actor'], federation_list): + actor_url = get_actor_from_post(object_json) + if not url_permitted(actor_url, federation_list): return None domain = get_full_domain(domain, port) @@ -101,7 +103,7 @@ def _accept_follow(base_dir: str, message_json: {}, return if debug: print('DEBUG: follow Accept received ' + str(message_json)) - this_actor = message_json['object']['actor'] + this_actor = get_actor_from_post(message_json['object']) nickname = get_nickname_from_actor(this_actor) if not nickname: print('WARN: no nickname found in ' + this_actor) @@ -205,17 +207,18 @@ def receive_accept_reject(base_dir: str, domain: str, message_json: {}, return False if not has_actor(message_json, debug): return False - if not has_users_path(message_json['actor']): + actor_url = get_actor_from_post(message_json) + if not has_users_path(actor_url): if debug: print('DEBUG: "users" or "profile" missing from actor in ' + message_json['type'] + '. Assuming single user instance.') - domain, _ = get_domain_from_actor(message_json['actor']) + domain, _ = get_domain_from_actor(actor_url) if not domain_permitted(domain, federation_list): if debug: print('DEBUG: ' + message_json['type'] + ' from domain not permitted - ' + domain) return False - nickname = get_nickname_from_actor(message_json['actor']) + nickname = get_nickname_from_actor(actor_url) if not nickname: # single user instance nickname = 'dev' diff --git a/announce.py b/announce.py index 0f2daeba8..64d6be1bc 100644 --- a/announce.py +++ b/announce.py @@ -27,6 +27,7 @@ from utils import local_actor_url from utils import replace_users_with_at from utils import has_actor from utils import has_object_string_type +from utils import get_actor_from_post from posts import send_signed_json from posts import get_person_box from session import post_json @@ -61,11 +62,12 @@ def is_self_announce(post_json_object: {}) -> bool: return False if not post_json_object.get('object'): return False - if not isinstance(post_json_object['actor'], str): + actor_url = get_actor_from_post(post_json_object) + if not isinstance(actor_url, str): return False if not isinstance(post_json_object['object'], str): return False - return post_json_object['actor'] in post_json_object['object'] + return actor_url in post_json_object['object'] def outbox_announce(recent_posts_cache: {}, @@ -86,20 +88,21 @@ def outbox_announce(recent_posts_cache: {}, return False if is_self_announce(message_json): return False - nickname = get_nickname_from_actor(message_json['actor']) + actor_url = get_actor_from_post(message_json) + nickname = get_nickname_from_actor(actor_url) if not nickname: - print('WARN: no nickname found in ' + message_json['actor']) + print('WARN: no nickname found in ' + actor_url) return False - domain, _ = get_domain_from_actor(message_json['actor']) + domain, _ = get_domain_from_actor(actor_url) if not domain: - print('WARN: no domain found in ' + message_json['actor']) + print('WARN: no domain found in ' + actor_url) return False post_filename = locate_post(base_dir, nickname, domain, message_json['object']) if post_filename: update_announce_collection(recent_posts_cache, base_dir, post_filename, - message_json['actor'], + actor_url, nickname, domain, debug) return True elif message_json['type'] == 'Undo': @@ -108,20 +111,21 @@ def outbox_announce(recent_posts_cache: {}, if message_json['object']['type'] == 'Announce': if not isinstance(message_json['object']['object'], str): return False - nickname = get_nickname_from_actor(message_json['actor']) + actor_url = get_actor_from_post(message_json) + nickname = get_nickname_from_actor(actor_url) if not nickname: - print('WARN: no nickname found in ' + message_json['actor']) + print('WARN: no nickname found in ' + actor_url) return False - domain, _ = get_domain_from_actor(message_json['actor']) + domain, _ = get_domain_from_actor(actor_url) if not domain: - print('WARN: no domain found in ' + message_json['actor']) + print('WARN: no domain found in ' + actor_url) return False post_filename = locate_post(base_dir, nickname, domain, message_json['object']['object']) if post_filename: undo_announce_collection_entry(recent_posts_cache, base_dir, post_filename, - message_json['actor'], + actor_url, domain, debug) return True return False @@ -458,7 +462,8 @@ def outbox_undo_announce(recent_posts_cache: {}, print('DEBUG: c2s undo announce post not found in inbox or outbox') print(message_id) return True + actor_url = get_actor_from_post(message_json) undo_announce_collection_entry(recent_posts_cache, base_dir, post_filename, - message_json['actor'], domain, debug) + actor_url, domain, debug) if debug: print('DEBUG: post undo announce via c2s - ' + post_filename) diff --git a/availability.py b/availability.py index 59a507a67..c256c25ad 100644 --- a/availability.py +++ b/availability.py @@ -21,6 +21,7 @@ from utils import save_json from utils import acct_dir from utils import local_actor_url from utils import has_actor +from utils import get_actor_from_post def set_availability(base_dir: str, nickname: str, domain: str, @@ -67,12 +68,13 @@ def outbox_availability(base_dir: str, nickname: str, message_json: {}, if not has_object_string(message_json, debug): return False - actor_nickname = get_nickname_from_actor(message_json['actor']) + actor_url = get_actor_from_post(message_json) + actor_nickname = get_nickname_from_actor(actor_url) if not actor_nickname: return False if actor_nickname != nickname: return False - domain, _ = get_domain_from_actor(message_json['actor']) + domain, _ = get_domain_from_actor(actor_url) if not domain: return False status = message_json['object'].replace('"', '') diff --git a/blocking.py b/blocking.py index 2cfa750aa..d38a36ee4 100644 --- a/blocking.py +++ b/blocking.py @@ -37,6 +37,7 @@ from utils import acct_dir from utils import local_actor_url from utils import has_actor from utils import text_in_file +from utils import get_actor_from_post from conversation import mute_conversation from conversation import unmute_conversation from auth import create_basic_auth_header @@ -1364,7 +1365,8 @@ def outbox_mute(base_dir: str, http_prefix: str, if not has_actor(message_json, debug): return domain_full = get_full_domain(domain, port) - if not message_json['actor'].endswith(domain_full + '/users/' + nickname): + actor_url = get_actor_from_post(message_json) + if not actor_url.endswith(domain_full + '/users/' + nickname): return if not message_json['type'] == 'Ignore': return @@ -1413,7 +1415,8 @@ def outbox_undo_mute(base_dir: str, http_prefix: str, if not has_actor(message_json, debug): return domain_full = get_full_domain(domain, port) - if not message_json['actor'].endswith(domain_full + '/users/' + nickname): + actor_url = get_actor_from_post(message_json) + if not actor_url.endswith(domain_full + '/users/' + nickname): return if not message_json['type'] == 'Undo': return diff --git a/bookmarks.py b/bookmarks.py index f514451e8..0dc766972 100644 --- a/bookmarks.py +++ b/bookmarks.py @@ -32,6 +32,7 @@ from utils import has_object_string_type from utils import text_in_file from utils import remove_eol from utils import remove_html +from utils import get_actor_from_post from posts import get_person_box from session import post_json @@ -614,9 +615,10 @@ def outbox_bookmark(recent_posts_cache: {}, print('DEBUG: c2s like post not found in inbox or outbox') print(message_url) return True + actor_url = get_actor_from_post(message_json) update_bookmarks_collection(recent_posts_cache, base_dir, post_filename, message_url, - message_json['actor'], domain, debug) + actor_url, domain, debug) if debug: print('DEBUG: post bookmarked via c2s - ' + post_filename) @@ -673,8 +675,9 @@ def outbox_undo_bookmark(recent_posts_cache: {}, print('DEBUG: c2s unbookmark post not found in inbox or outbox') print(message_url) return True + actor_url = get_actor_from_post(message_json) update_bookmarks_collection(recent_posts_cache, base_dir, post_filename, message_url, - message_json['actor'], domain, debug) + actor_url, domain, debug) if debug: print('DEBUG: post unbookmarked via c2s - ' + post_filename) diff --git a/daemon.py b/daemon.py index 47d3de038..792d8acc7 100644 --- a/daemon.py +++ b/daemon.py @@ -387,6 +387,7 @@ from utils import refresh_newswire from utils import is_image_file from utils import has_group_type from utils import binary_is_image +from utils import get_actor_from_post from manualapprove import manual_deny_follow_request_thread from manualapprove import manual_approve_follow_request_thread from announce import create_announce @@ -2178,9 +2179,10 @@ class PubServer(BaseHTTPRequestHandler): # actor should be a string if debug: print('INBOX: checking that actor is string') - if not isinstance(message_json['actor'], str): + actor_url = get_actor_from_post(message_json) + if not isinstance(actor_url, str): print('INBOX: ' + - 'actor should be a string ' + str(message_json['actor'])) + 'actor should be a string ' + str(actor_url)) self._400() self.server.postreq_busy = False return 3 @@ -2262,8 +2264,9 @@ class PubServer(BaseHTTPRequestHandler): if message_json['object'].get('content'): content_str = message_json['object']['content'] if not valid_url_lengths(content_str, 2048): + actor_url = get_actor_from_post(message_json) print('INBOX: content contains urls which are too long ' + - message_json['actor']) + actor_url) self._400() self.server.postreq_busy = False return 3 @@ -2274,23 +2277,26 @@ class PubServer(BaseHTTPRequestHandler): message_json['object']['type'] != 'Application' and \ message_json['object']['type'] != 'Group': if len(message_json['object']['summary']) > 1024: + actor_url = get_actor_from_post(message_json) print('INBOX: summary is too long ' + - message_json['actor'] + ' ' + + actor_url + ' ' + message_json['object']['summary']) self._400() self.server.postreq_busy = False return 3 if '://' in message_json['object']['summary']: + actor_url = get_actor_from_post(message_json) print('INBOX: summary should not contain links ' + - message_json['actor'] + ' ' + + actor_url + ' ' + message_json['object']['summary']) self._400() self.server.postreq_busy = False return 3 else: if len(message_json['object']['summary']) > 4096: + actor_url = get_actor_from_post(message_json) print('INBOX: person summary is too long ' + - message_json['actor'] + ' ' + + actor_url + ' ' + message_json['object']['summary']) self._400() self.server.postreq_busy = False @@ -2335,10 +2341,11 @@ class PubServer(BaseHTTPRequestHandler): # actor should look like a url if debug: print('INBOX: checking that actor looks like a url') - if '://' not in message_json['actor'] or \ - '.' not in message_json['actor']: + actor_url = get_actor_from_post(message_json) + if '://' not in actor_url or \ + '.' not in actor_url: print('INBOX: POST actor does not look like a url ' + - message_json['actor']) + actor_url) self._400() self.server.postreq_busy = False return 3 @@ -2348,18 +2355,19 @@ class PubServer(BaseHTTPRequestHandler): print('INBOX: checking for local network access') if not self.server.allow_local_network_access: local_network_pattern_list = get_local_network_addresses() + actor_url = get_actor_from_post(message_json) for local_network_pattern in local_network_pattern_list: - if local_network_pattern in message_json['actor']: + if local_network_pattern in actor_url: print('INBOX: POST actor contains local network address ' + - message_json['actor']) + actor_url) self._400() self.server.postreq_busy = False return 3 - message_domain, _ = \ - get_domain_from_actor(message_json['actor']) + actor_url = get_actor_from_post(message_json) + message_domain, _ = get_domain_from_actor(actor_url) if not message_domain: - print('INBOX: POST from unknown domain ' + message_json['actor']) + print('INBOX: POST from unknown domain ' + actor_url) self._400() self.server.postreq_busy = False return 3 @@ -2379,10 +2387,9 @@ class PubServer(BaseHTTPRequestHandler): self.server.postreq_busy = False return 3 - message_nickname = \ - get_nickname_from_actor(message_json['actor']) + message_nickname = get_nickname_from_actor(actor_url) if not message_nickname: - print('INBOX: POST from unknown nickname ' + message_json['actor']) + print('INBOX: POST from unknown nickname ' + actor_url) self._400() self.server.postreq_busy = False return 3 @@ -2402,7 +2409,7 @@ class PubServer(BaseHTTPRequestHandler): if message_domain: print('INBOX: Queue: ' + 'Inbox queue is full. Incoming post from ' + - message_json['actor']) + actor_url) else: print('INBOX: Queue: Inbox queue is full') self._503() diff --git a/delete.py b/delete.py index 5879de3fc..2cebb30b3 100644 --- a/delete.py +++ b/delete.py @@ -23,6 +23,7 @@ from utils import remove_moderation_post_from_index from utils import local_actor_url from utils import date_utcnow from utils import date_epoch +from utils import get_actor_from_post from session import post_json from webfinger import webfinger_handle from auth import create_basic_auth_header @@ -138,9 +139,10 @@ def outbox_delete(base_dir: str, http_prefix: str, if debug: print('DEBUG: c2s delete request arrived in outbox') delete_prefix = http_prefix + '://' + domain + actor_url = get_actor_from_post(message_json) if (not allow_deletion and (not message_json['object'].startswith(delete_prefix) or - not message_json['actor'].startswith(delete_prefix))): + not actor_url.startswith(delete_prefix))): if debug: print('DEBUG: delete not permitted from other instances') return diff --git a/desktop_client.py b/desktop_client.py index f9eba5b0a..4e0b4237c 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -34,6 +34,7 @@ from utils import get_domain_from_actor from utils import is_pgp_encrypted from utils import local_actor_url from utils import get_reply_to +from utils import get_actor_from_post from session import create_session from speaker import speakable_text from speaker import get_speaker_pitch @@ -801,7 +802,7 @@ def _read_local_box_post(session, nickname: str, domain: str, print('') if post_json_object['type'] == 'Announce': - actor = post_json_object['actor'] + actor = get_actor_from_post(post_json_object) name_str = get_nickname_from_actor(actor) recent_posts_cache = {} allow_local_network_access = False @@ -1142,7 +1143,8 @@ def _desktop_show_box(indent: str, if post_json_object.get('actor') and \ post_json_object.get('object'): if isinstance(post_json_object['object'], str): - author_actor = post_json_object['actor'] + author_actor = \ + get_actor_from_post(post_json_object) name = get_nickname_from_actor(author_actor) + ' ⮌' name = _pad_to_width(name, name_width) ctr_str = str(ctr) diff --git a/follow.py b/follow.py index a86012732..a0f597d5d 100644 --- a/follow.py +++ b/follow.py @@ -33,6 +33,7 @@ from utils import has_group_type from utils import local_actor_url from utils import text_in_file from utils import remove_eol +from utils import get_actor_from_post from acceptreject import create_accept from acceptreject import create_reject from webfinger import webfinger_handle @@ -803,7 +804,8 @@ def followed_account_accepts(session, base_dir: str, http_prefix: str, group_account = False if follow_json: if follow_json.get('actor'): - if has_group_type(base_dir, follow_json['actor'], person_cache): + actor_url = get_actor_from_post(follow_json) + if has_group_type(base_dir, actor_url, person_cache): group_account = True extra_headers = {} @@ -858,7 +860,7 @@ def followed_account_rejects(session, session_onion, session_i2p, follow_activity_filename) return None # actor who made the follow request - person_url = follow_json['actor'] + person_url = get_actor_from_post(follow_json) # create the reject activity reject_json = \ @@ -1474,17 +1476,15 @@ def outbox_undo_follow(base_dir: str, message_json: {}, debug: bool) -> None: if debug: print('DEBUG: undo follow arrived in outbox') - nickname_follower = \ - get_nickname_from_actor(message_json['object']['actor']) + actor_url = get_actor_from_post(message_json['object']) + nickname_follower = get_nickname_from_actor(actor_url) if not nickname_follower: print('WARN: unable to find nickname in ' + - message_json['object']['actor']) + actor_url) return - domain_follower, port_follower = \ - get_domain_from_actor(message_json['object']['actor']) + domain_follower, port_follower = get_domain_from_actor(actor_url) if not domain_follower: - print('WARN: unable to find domain in ' + - message_json['object']['actor']) + print('WARN: unable to find domain in ' + actor_url) return domain_follower_full = get_full_domain(domain_follower, port_follower) diff --git a/inbox.py b/inbox.py index b41ec9400..c205674e3 100644 --- a/inbox.py +++ b/inbox.py @@ -81,6 +81,7 @@ from utils import has_object_string_type from utils import valid_hash_tag from utils import get_attributed_to from utils import get_reply_to +from utils import get_actor_from_post from categories import get_hashtag_categories from categories import set_hashtag_category from httpsig import get_digest_algorithm_from_headers @@ -272,7 +273,7 @@ def _store_last_post_id(base_dir: str, nickname: str, domain: str, actor = actor_str post_id = remove_id_ending(post_json_object['object']['id']) if not actor: - actor = post_json_object['actor'] + actor = get_actor_from_post(post_json_object) post_id = remove_id_ending(post_json_object['id']) if not actor: return @@ -573,15 +574,16 @@ def inbox_message_has_params(message_json: {}) -> bool: return False # actor should be a string - if not isinstance(message_json['actor'], str): + actor_url = get_actor_from_post(message_json) + if not actor_url: print('WARN: actor should be a string, but is actually: ' + - str(message_json['actor'])) + actor_url) pprint(message_json) return False # type should be a string if not isinstance(message_json['type'], str): - print('WARN: type from ' + str(message_json['actor']) + + print('WARN: type from ' + actor_url + ' should be a string, but is actually: ' + str(message_json['type'])) return False @@ -589,7 +591,7 @@ def inbox_message_has_params(message_json: {}) -> bool: # object should be a dict or a string if not has_object_dict(message_json): if not isinstance(message_json['object'], str): - print('WARN: object from ' + str(message_json['actor']) + + print('WARN: object from ' + actor_url + ' should be a dict or string, but is actually: ' + str(message_json['object'])) return False @@ -611,7 +613,7 @@ def inbox_permitted_message(domain: str, message_json: {}, if not has_actor(message_json, False): return False - actor = message_json['actor'] + actor = get_actor_from_post(message_json) # always allow the local domain if domain in actor: return True @@ -703,7 +705,7 @@ def save_post_to_inbox_queue(base_dir: str, http_prefix: str, get_attributed_to(post_json_object['object']['attributedTo']) if not sending_actor: if post_json_object.get('actor'): - sending_actor = post_json_object['actor'] + sending_actor = get_actor_from_post(post_json_object) # check that the sender is valid if sending_actor: @@ -948,7 +950,7 @@ def _inbox_post_recipients(base_dir: str, post_json_object: {}, domain = get_full_domain(domain, port) domain_match = '/' + domain + '/users/' - actor = post_json_object['actor'] + actor = get_actor_from_post(post_json_object) # first get any specific people which the post is addressed to follower_recipients = False @@ -1062,13 +1064,13 @@ def _receive_undo_follow(base_dir: str, message_json: {}, if debug: print('DEBUG: undo follow request has no actor within object') return False - actor = message_json['object']['actor'] + actor = get_actor_from_post(message_json['object']) if not has_users_path(actor): if debug: print('DEBUG: undo follow request "users" or "profile" missing ' + 'from actor within object') return False - if actor != message_json['actor']: + if actor != get_actor_from_post(message_json): if debug: print('DEBUG: undo follow request actors do not match') return False @@ -1146,7 +1148,8 @@ def _receive_undo(base_dir: str, message_json: {}, debug: bool, print('DEBUG: Undo activity received') if not has_actor(message_json, debug): return False - if not has_users_path(message_json['actor']): + actor_url = get_actor_from_post(message_json) + if not has_users_path(actor_url): if debug: print('DEBUG: "users" or "profile" missing from actor') return False @@ -1366,7 +1369,9 @@ def _receive_update_to_question(recent_posts_cache: {}, message_json: {}, if dangerous_question(post_json_object, allow_local_network_access): return False # does the actor match? - if post_json_object['actor'] != message_json['actor']: + actor_url = get_actor_from_post(post_json_object) + actor_url2 = get_actor_from_post(message_json) + if actor_url != actor_url2: return False save_json(message_json, post_filename) # ensure that the cached post is removed if it exists, so @@ -1616,9 +1621,11 @@ def receive_edit_to_post(recent_posts_cache: {}, message_json: {}, if 'content' not in message_json['object']: return False # does the actor match? - if post_json_object['actor'] != message_json['actor']: + actor_url = get_actor_from_post(post_json_object) + actor_url2 = get_actor_from_post(message_json) + if actor_url != actor_url2: print('EDITPOST: actors do not match ' + - post_json_object['actor'] + ' != ' + message_json['actor']) + actor_url + ' != ' + actor_url2) return False # has the content changed? if post_json_object['object']['content'] == \ @@ -1755,13 +1762,14 @@ def _receive_move_activity(session, base_dir: str, str(message_json['target'])) return False previous_actor = None - if message_json['object'] == message_json['actor']: + actor_url = get_actor_from_post(message_json) + if message_json['object'] == actor_url: print('INBOX: Move activity sent by old actor ' + - message_json['actor'] + ' moving to ' + message_json['target']) - previous_actor = message_json['actor'] - elif message_json['target'] == message_json['actor']: + actor_url + ' moving to ' + message_json['target']) + previous_actor = actor_url + elif message_json['target'] == actor_url: print('INBOX: Move activity sent by new actor ' + - message_json['actor'] + ' moving from ' + + actor_url + ' moving from ' + message_json['object']) previous_actor = message_json['object'] if not previous_actor: @@ -1846,7 +1854,8 @@ def _receive_update_activity(recent_posts_cache: {}, session, base_dir: str, return False if not has_object_string_type(message_json, debug): return False - if not has_users_path(message_json['actor']): + actor_url = get_actor_from_post(message_json) + if not has_users_path(actor_url): if debug: print('DEBUG: "users" or "profile" missing from actor in ' + message_json['type']) @@ -1895,9 +1904,10 @@ def _receive_update_activity(recent_posts_cache: {}, session, base_dir: str, message_json['object'].get('id'): if debug: print('Request to update actor: ' + str(message_json)) - update_nickname = get_nickname_from_actor(message_json['actor']) + actor_url = get_actor_from_post(message_json) + update_nickname = get_nickname_from_actor(actor_url) update_domain, update_port = \ - get_domain_from_actor(message_json['actor']) + get_domain_from_actor(actor_url) if update_nickname and update_domain: if _person_receive_update(base_dir, domain, port, @@ -1945,7 +1955,8 @@ def _receive_like(recent_posts_cache: {}, if debug: print('DEBUG: ' + message_json['type'] + ' has no "to" list') return False - if not has_users_path(message_json['actor']): + actor_url = get_actor_from_post(message_json) + if not has_users_path(actor_url): if debug: print('DEBUG: "users" or "profile" missing from actor in ' + message_json['type']) @@ -1972,7 +1983,7 @@ def _receive_like(recent_posts_cache: {}, if debug: print('DEBUG: liked post found in inbox') - like_actor = message_json['actor'] + like_actor = get_actor_from_post(message_json) handle_name = handle.split('@')[0] handle_dom = handle.split('@')[1] if not _already_liked(base_dir, @@ -2081,7 +2092,8 @@ def _receive_undo_like(recent_posts_cache: {}, return False if not has_object_string_object(message_json, debug): return False - if not has_users_path(message_json['actor']): + actor_url = get_actor_from_post(message_json) + if not has_users_path(actor_url): if debug: print('DEBUG: "users" or "profile" missing from actor in ' + message_json['type'] + ' like') @@ -2107,7 +2119,7 @@ def _receive_undo_like(recent_posts_cache: {}, return True if debug: print('DEBUG: liked post found in inbox. Now undoing.') - like_actor = message_json['actor'] + like_actor = get_actor_from_post(message_json) post_liked_id = message_json['object'] undo_likes_collection_entry(recent_posts_cache, base_dir, post_filename, post_liked_id, like_actor, domain, debug, None) @@ -2213,11 +2225,12 @@ def _receive_reaction(recent_posts_cache: {}, if debug: print('DEBUG: ' + message_json['type'] + ' content is not string') return False + actor_url = get_actor_from_post(message_json) if not valid_emoji_content(message_json['content']): print('_receive_reaction: Invalid emoji reaction: "' + - message_json['content'] + '" from ' + message_json['actor']) + message_json['content'] + '" from ' + actor_url) return False - if not has_users_path(message_json['actor']): + if not has_users_path(actor_url): if debug: print('DEBUG: "users" or "profile" missing from actor in ' + message_json['type']) @@ -2254,7 +2267,7 @@ def _receive_reaction(recent_posts_cache: {}, if debug: print('DEBUG: emoji reaction post found in inbox') - reaction_actor = message_json['actor'] + reaction_actor = get_actor_from_post(message_json) handle_name = handle.split('@')[0] handle_dom = handle.split('@')[1] if not _already_reacted(base_dir, @@ -2394,12 +2407,13 @@ def _receive_zot_reaction(recent_posts_cache: {}, print('DEBUG: ' + message_json['object']['type'] + ' inReplyTo is not string') return False + actor_url = get_actor_from_post(message_json) if not valid_emoji_content(message_json['object']['content']): print('_receive_zot_reaction: Invalid emoji reaction: "' + message_json['object']['content'] + '" from ' + - message_json['actor']) + actor_url) return False - if not has_users_path(message_json['actor']): + if not has_users_path(actor_url): if debug: print('DEBUG: "users" or "profile" missing from actor in ' + message_json['object']['type']) @@ -2437,7 +2451,7 @@ def _receive_zot_reaction(recent_posts_cache: {}, if debug: print('DEBUG: zot emoji reaction post found in inbox') - reaction_actor = message_json['actor'] + reaction_actor = get_actor_from_post(message_json) handle_name = handle.split('@')[0] handle_dom = handle.split('@')[1] if not _already_reacted(base_dir, @@ -2560,7 +2574,8 @@ def _receive_undo_reaction(recent_posts_cache: {}, if debug: print('DEBUG: ' + message_json['type'] + ' content is not string') return False - if not has_users_path(message_json['actor']): + actor_url = get_actor_from_post(message_json) + if not has_users_path(actor_url): if debug: print('DEBUG: "users" or "profile" missing from actor in ' + message_json['type'] + ' reaction') @@ -2586,7 +2601,7 @@ def _receive_undo_reaction(recent_posts_cache: {}, return True if debug: print('DEBUG: reaction post found in inbox. Now undoing.') - reaction_actor = message_json['actor'] + reaction_actor = actor_url post_reaction_id = message_json['object'] emoji_content = remove_html(message_json['object']['content']) if not emoji_content: @@ -2704,11 +2719,12 @@ def _receive_bookmark(recent_posts_cache: {}, return False domain_full = get_full_domain(domain, port) nickname = handle.split('@')[0] - if not message_json['actor'].endswith(domain_full + '/users/' + nickname): + actor_url = get_actor_from_post(message_json) + if not actor_url.endswith(domain_full + '/users/' + nickname): if debug: print('DEBUG: inbox bookmark Add unexpected actor') return False - if not message_json['target'].endswith(message_json['actor'] + + if not message_json['target'].endswith(actor_url + '/tlbookmarks'): if debug: print('DEBUG: inbox bookmark Add target invalid ' + @@ -2741,8 +2757,7 @@ def _receive_bookmark(recent_posts_cache: {}, return True update_bookmarks_collection(recent_posts_cache, base_dir, post_filename, - message_url2, - message_json['actor'], domain, debug) + message_url2, actor_url, domain, debug) # regenerate the html bookmarked_post_json = load_json(post_filename, 0, 1) if bookmarked_post_json: @@ -2831,11 +2846,12 @@ def _receive_undo_bookmark(recent_posts_cache: {}, return False domain_full = get_full_domain(domain, port) nickname = handle.split('@')[0] - if not message_json['actor'].endswith(domain_full + '/users/' + nickname): + actor_url = get_actor_from_post(message_json) + if not actor_url.endswith(domain_full + '/users/' + nickname): if debug: print('DEBUG: inbox undo bookmark Remove unexpected actor') return False - if not message_json['target'].endswith(message_json['actor'] + + if not message_json['target'].endswith(actor_url + '/tlbookmarks'): if debug: print('DEBUG: inbox undo bookmark Remove target invalid ' + @@ -2870,7 +2886,7 @@ def _receive_undo_bookmark(recent_posts_cache: {}, undo_bookmarks_collection_entry(recent_posts_cache, base_dir, post_filename, - message_json['actor'], domain, debug) + actor_url, domain, debug) # regenerate the html bookmarked_post_json = load_json(post_filename, 0, 1) if bookmarked_post_json: @@ -2936,9 +2952,10 @@ def _receive_delete(session, handle: str, is_group: bool, base_dir: str, return False domain_full = get_full_domain(domain, port) delete_prefix = http_prefix + '://' + domain_full + '/' + actor_url = get_actor_from_post(message_json) if (not allow_deletion and (not message_json['object'].startswith(delete_prefix) or - not message_json['actor'].startswith(delete_prefix))): + not actor_url.startswith(delete_prefix))): if debug: print('DEBUG: delete not permitted from other instances') return False @@ -2946,7 +2963,7 @@ def _receive_delete(session, handle: str, is_group: bool, base_dir: str, if debug: print('DEBUG: ' + message_json['type'] + ' has no "to" list') return False - if not has_users_path(message_json['actor']): + if not has_users_path(actor_url): if debug: print('DEBUG: ' + '"users" or "profile" missing from actor in ' + @@ -2957,7 +2974,7 @@ def _receive_delete(session, handle: str, is_group: bool, base_dir: str, print('DEBUG: "statuses" missing from object in ' + message_json['type']) return False - if message_json['actor'] not in message_json['object']: + if actor_url not in message_json['object']: if debug: print('DEBUG: actor is not the owner of the post to be deleted') handle_dir = acct_handle_dir(base_dir, handle) @@ -3034,7 +3051,8 @@ def _receive_announce(recent_posts_cache: {}, if debug: print('DEBUG: ' + message_json['type'] + ' has no "to" list') return False - if not has_users_path(message_json['actor']): + actor_url = get_actor_from_post(message_json) + if not has_users_path(actor_url): if debug: print('DEBUG: ' + '"users" or "profile" missing from actor in ' + @@ -3069,11 +3087,11 @@ def _receive_announce(recent_posts_cache: {}, # is the announce actor blocked? nickname = handle.split('@')[0] - actor_nickname = get_nickname_from_actor(message_json['actor']) + actor_nickname = get_nickname_from_actor(actor_url) if not actor_nickname: print('WARN: _receive_announce no actor_nickname') return False - actor_domain, _ = get_domain_from_actor(message_json['actor']) + actor_domain, _ = get_domain_from_actor(actor_url) if not actor_domain: print('WARN: _receive_announce no actor_domain') return False @@ -3117,10 +3135,11 @@ def _receive_announce(recent_posts_cache: {}, print(message_json['object']) return True # add actor to the list of announcers for a post + actor_url = get_actor_from_post(message_json) update_announce_collection(recent_posts_cache, base_dir, post_filename, - message_json['actor'], nickname, domain, debug) + actor_url, nickname, domain, debug) if debug: - print('DEBUG: Downloading announce post ' + message_json['actor'] + + print('DEBUG: Downloading announce post ' + actor_url + ' -> ' + message_json['object']) domain_full = get_full_domain(domain, port) @@ -3215,8 +3234,9 @@ def _receive_announce(recent_posts_cache: {}, str(post_filename)) else: if debug: + actor_url = get_actor_from_post(message_json) print('DEBUG: Announce post downloaded for ' + - message_json['actor'] + ' -> ' + message_json['object']) + actor_url + ' -> ' + message_json['object']) store_hash_tags(base_dir, nickname, domain, http_prefix, domain_full, post_json_object, translate) @@ -3309,7 +3329,8 @@ def _receive_undo_announce(recent_posts_cache: {}, return False if message_json['object']['type'] != 'Announce': return False - if not has_users_path(message_json['actor']): + actor_url = get_actor_from_post(message_json) + if not has_users_path(actor_url): if debug: print('DEBUG: "users" or "profile" missing from actor in ' + message_json['type'] + ' announce') @@ -3339,7 +3360,7 @@ def _receive_undo_announce(recent_posts_cache: {}, "which isn't an announcement") return False undo_announce_collection_entry(recent_posts_cache, base_dir, post_filename, - message_json['actor'], domain, debug) + actor_url, domain, debug) if os.path.isfile(post_filename): try: os.remove(post_filename) @@ -3936,7 +3957,7 @@ def _inbox_update_calendar_from_tag(base_dir: str, handle: str, if not isinstance(post_json_object['object']['tag'], list): return - actor = post_json_object['actor'] + actor = get_actor_from_post(post_json_object) actor_nickname = get_nickname_from_actor(actor) if not actor_nickname: return @@ -3981,7 +4002,7 @@ def _inbox_update_calendar_from_event(base_dir: str, handle: str, if not isinstance(post_json_object['object']['startTime'], str): return - actor = post_json_object['actor'] + actor = get_actor_from_post(post_json_object) actor_nickname = get_nickname_from_actor(actor) if not actor_nickname: return @@ -4210,7 +4231,7 @@ def _is_valid_dm(base_dir: str, nickname: str, domain: str, port: int, # who is sending a DM? if not post_json_object.get('actor'): return False - sending_actor = post_json_object['actor'] + sending_actor = get_actor_from_post(post_json_object) sending_actor_nickname = \ get_nickname_from_actor(sending_actor) if not sending_actor_nickname: @@ -5573,16 +5594,17 @@ def _receive_follow_request(session, session_onion, session_i2p, print('Receiving follow request') if not has_actor(message_json, debug): return True - if not has_users_path(message_json['actor']): + actor_url = get_actor_from_post(message_json) + if not has_users_path(actor_url): if debug: print('DEBUG: ' + 'users/profile/author/accounts/channel missing from actor') return True - domain, temp_port = get_domain_from_actor(message_json['actor']) + domain, temp_port = get_domain_from_actor(actor_url) if not domain: if debug: print('DEBUG: receive follow request actor without domain ' + - message_json['actor']) + actor_url) return True from_port = port domain_full = get_full_domain(domain, temp_port) @@ -5592,7 +5614,7 @@ def _receive_follow_request(session, session_onion, session_i2p, if debug: print('DEBUG: follower from domain not permitted - ' + domain) return True - nickname = get_nickname_from_actor(message_json['actor']) + nickname = get_nickname_from_actor(actor_url) if not nickname: # single user instance nickname = 'dev' @@ -5723,10 +5745,10 @@ def _receive_follow_request(session, session_onion, session_i2p, # Get the actor for the follower and add it to the cache. # Getting their public key has the same result if debug: - print('Obtaining the following actor: ' + message_json['actor']) + print('Obtaining the following actor: ' + actor_url) pubkey_result = \ get_person_pub_key(base_dir, curr_session, - message_json['actor'], + actor_url, person_cache, debug, project_version, curr_http_prefix, this_domain, onion_domain, @@ -5734,14 +5756,14 @@ def _receive_follow_request(session, session_onion, session_i2p, if not pubkey_result: if debug: print('Unable to obtain following actor: ' + - message_json['actor']) + actor_url) elif isinstance(pubkey_result, dict): if debug: print('http error code trying to obtain following actor: ' + - message_json['actor'] + ' ' + str(pubkey_result)) + actor_url + ' ' + str(pubkey_result)) group_account = \ - has_group_type(base_dir, message_json['actor'], person_cache) + has_group_type(base_dir, actor_url, person_cache) if group_account and is_group_account(base_dir, nickname, domain): print('Group cannot follow a group') return True @@ -5750,7 +5772,7 @@ def _receive_follow_request(session, session_onion, session_i2p, return store_follow_request(base_dir, nickname_to_follow, domain_to_follow, port, nickname, domain, from_port, - message_json, debug, message_json['actor'], + message_json, debug, actor_url, group_account) else: if is_already_follower: @@ -5767,17 +5789,17 @@ def _receive_follow_request(session, session_onion, session_i2p, # for actors which don't follow the mastodon # /users/ path convention store the full actor - if '/users/' not in message_json['actor']: - approve_handle = message_json['actor'] + if '/users/' not in actor_url: + approve_handle = actor_url # Get the actor for the follower and add it to the cache. # Getting their public key has the same result if debug: print('Obtaining the following actor: ' + - message_json['actor']) + actor_url) pubkey_result = \ get_person_pub_key(base_dir, curr_session, - message_json['actor'], + actor_url, person_cache, debug, project_version, curr_http_prefix, this_domain, onion_domain, i2p_domain, @@ -5785,11 +5807,11 @@ def _receive_follow_request(session, session_onion, session_i2p, if not pubkey_result: if debug: print('Unable to obtain following actor: ' + - message_json['actor']) + actor_url) elif isinstance(pubkey_result, dict): if debug: print('http error code trying to obtain ' + - 'following actor: ' + message_json['actor'] + + 'following actor: ' + actor_url + ' ' + str(pubkey_result)) print('Updating followers file: ' + @@ -5798,9 +5820,9 @@ def _receive_follow_request(session, session_onion, session_i2p, if not text_in_file(approve_handle, followers_filename): group_account = \ has_group_type(base_dir, - message_json['actor'], person_cache) + actor_url, person_cache) if debug: - print(approve_handle + ' / ' + message_json['actor'] + + print(approve_handle + ' / ' + actor_url + ' is Group: ' + str(group_account)) if group_account and \ is_group_account(base_dir, nickname, domain): @@ -5837,7 +5859,7 @@ def _receive_follow_request(session, session_onion, session_i2p, return followed_account_accepts(curr_session, base_dir, curr_http_prefix, nickname_to_follow, domain_to_follow, port, nickname, curr_domain, curr_port, - message_json['actor'], federation_list, + actor_url, federation_list, message_json, send_threads, post_log, cached_webfingers, person_cache, debug, project_version, True, diff --git a/like.py b/like.py index b7510bbd0..c4db24f5d 100644 --- a/like.py +++ b/like.py @@ -28,6 +28,7 @@ from utils import load_json from utils import save_json from utils import remove_post_from_cache from utils import get_cached_post_filename +from utils import get_actor_from_post from posts import send_signed_json from session import post_json from webfinger import webfinger_handle @@ -134,9 +135,10 @@ def _create_like(recent_posts_cache: {}, print('DEBUG: like object_url: ' + object_url) return None + actor_url = get_actor_from_post(new_like_json) update_likes_collection(recent_posts_cache, base_dir, post_filename, object_url, - new_like_json['actor'], + actor_url, nickname, domain, debug, None) extra_headers = {} send_signed_json(new_like_json, session, base_dir, @@ -388,9 +390,10 @@ def outbox_like(recent_posts_cache: {}, print('DEBUG: c2s like post not found in inbox or outbox') print(message_id) return True + actor_url = get_actor_from_post(message_json) update_likes_collection(recent_posts_cache, base_dir, post_filename, message_id, - message_json['actor'], + actor_url, nickname, domain, debug, None) if debug: print('DEBUG: post liked via c2s - ' + post_filename) @@ -424,8 +427,9 @@ def outbox_undo_like(recent_posts_cache: {}, print('DEBUG: c2s undo like post not found in inbox or outbox') print(message_id) return True + actor_url = get_actor_from_post(message_json) undo_likes_collection_entry(recent_posts_cache, base_dir, post_filename, - message_id, message_json['actor'], + message_id, actor_url, domain, debug, None) if debug: print('DEBUG: post undo liked via c2s - ' + post_filename) diff --git a/manualapprove.py b/manualapprove.py index e3174cbf6..d0b70ecd8 100644 --- a/manualapprove.py +++ b/manualapprove.py @@ -19,6 +19,7 @@ from utils import get_user_paths from utils import acct_dir from utils import text_in_file from utils import remove_eol +from utils import get_actor_from_post from threads import thread_with_trace from threads import begin_thread from session import create_session @@ -276,6 +277,7 @@ def manual_approve_follow_request(session, session_onion, session_i2p, print('Manual follow accept: Sending Accept for ' + handle + ' follow request from ' + approve_nickname + '@' + approve_domain) + actor_url = get_actor_from_post(follow_json) followed_account_accepts(curr_session, base_dir, curr_http_prefix, nickname, @@ -283,7 +285,7 @@ def manual_approve_follow_request(session, session_onion, session_i2p, approve_nickname, approve_domain, approve_port, - follow_json['actor'], + actor_url, federation_list, follow_json, send_threads, post_log, diff --git a/outbox.py b/outbox.py index 777ff8531..73ac21832 100644 --- a/outbox.py +++ b/outbox.py @@ -34,6 +34,7 @@ from utils import acct_dir from utils import local_actor_url from utils import has_actor from utils import is_quote_toot +from utils import get_actor_from_post from blocking import is_blocked_domain from blocking import outbox_block from blocking import outbox_undo_block @@ -355,30 +356,31 @@ def post_message_to_outbox(session, translate: {}, return False # actor should be a string - if not isinstance(message_json['actor'], str): + actor_url = get_actor_from_post(message_json) + if not actor_url: return False # actor should look like a url - if '://' not in message_json['actor'] or \ - '.' not in message_json['actor']: + if '://' not in actor_url or \ + '.' not in actor_url: return False - if contains_invalid_actor_url_chars(message_json['actor']): + if contains_invalid_actor_url_chars(actor_url): return False # sent by an actor on a local network address? if not allow_local_network_access: local_network_pattern_list = get_local_network_addresses() for local_network_pattern in local_network_pattern_list: - if local_network_pattern in message_json['actor']: + if local_network_pattern in actor_url: return False - test_domain, test_port = get_domain_from_actor(message_json['actor']) + test_domain, test_port = get_domain_from_actor(actor_url) 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']) + print('DEBUG: domain is blocked: ' + actor_url) return False # replace youtube, so that google gets less tracking data replace_you_tube(message_json, yt_replace_domain, system_language) @@ -387,7 +389,7 @@ def post_message_to_outbox(session, translate: {}, replace_twitter(message_json, twitter_replacement_domain, system_language) # https://www.w3.org/TR/activitypub/#create-activity-outbox - message_json['object']['attributedTo'] = message_json['actor'] + message_json['object']['attributedTo'] = actor_url if message_json['object'].get('attachment'): attachment_index = 0 attach = message_json['object']['attachment'][attachment_index] @@ -496,10 +498,11 @@ def post_message_to_outbox(session, translate: {}, print('WARN: post not saved to outbox ' + outbox_name) return False + actor_url = get_actor_from_post(message_json) update_speaker(base_dir, http_prefix, post_to_nickname, domain, domain_full, message_json, person_cache, - translate, message_json['actor'], + translate, actor_url, theme, system_language, outbox_name) diff --git a/person.py b/person.py index ffaa1ed15..b620c7cf6 100644 --- a/person.py +++ b/person.py @@ -71,6 +71,7 @@ from utils import local_actor_url from utils import dangerous_svg from utils import text_in_file from utils import contains_statuses +from utils import get_actor_from_post from session import get_json_valid from session import create_session from session import get_json @@ -1928,7 +1929,7 @@ def valid_sending_actor(session, base_dir: str, the sending actor is valid """ # who sent this post? - sending_actor = post_json_object['actor'] + sending_actor = get_actor_from_post(post_json_object) if not isinstance(sending_actor, str): return False diff --git a/posts.py b/posts.py index 89f73fd8d..c46fee091 100644 --- a/posts.py +++ b/posts.py @@ -87,6 +87,7 @@ from utils import dangerous_markup from utils import acct_dir from utils import local_actor_url from utils import get_reply_to +from utils import get_actor_from_post from media import get_music_metadata from media import attach_media from media import replace_you_tube @@ -3218,7 +3219,8 @@ def _add_followers_to_public_post(post_json_object: {}) -> None: return if post_json_object.get('cc'): return - post_json_object['cc'] = post_json_object['actor'] + '/followers' + actor_url = get_actor_from_post(post_json_object) + post_json_object['cc'] = actor_url + '/followers' elif has_object_dict(post_json_object): if not post_json_object['object'].get('to'): return @@ -3232,8 +3234,9 @@ def _add_followers_to_public_post(post_json_object: {}) -> None: return if post_json_object['object'].get('cc'): return + actor_url = get_actor_from_post(post_json_object) post_json_object['object']['cc'] = \ - post_json_object['actor'] + '/followers' + actor_url + '/followers' def send_signed_json(post_json_object: {}, session, base_dir: str, @@ -3507,10 +3510,9 @@ def add_to_field(activity_type: str, post_json_object: {}, if post_json_object['type'] == 'Add' or \ post_json_object['type'] == 'Remove': if post_json_object['object']['type'] == 'Document': - post_json_object['to'] = \ - [post_json_object['actor']] - post_json_object['object']['to'] = \ - [post_json_object['actor']] + actor_url = get_actor_from_post(post_json_object) + post_json_object['to'] = [actor_url] + post_json_object['object']['to'] = [actor_url] to_field_added = True if not to_field_added and \ @@ -5683,7 +5685,8 @@ def download_announce(session, base_dir: str, http_prefix: str, if not isinstance(post_json_object['object'], str): return None # ignore self-boosts - if post_json_object['actor'] in post_json_object['object']: + actor_url = get_actor_from_post(post_json_object) + if actor_url in post_json_object['object']: return None # get the announced post @@ -5716,24 +5719,24 @@ def download_announce(session, base_dir: str, http_prefix: str, as_header = { 'Accept': accept_str } - if '/channel/' in post_json_object['actor'] or \ - '/accounts/' in post_json_object['actor']: + if '/channel/' in actor_url or \ + '/accounts/' in actor_url: accept_str = \ 'application/ld+json; ' + \ 'profile="' + profile_str + '"' as_header = { 'Accept': accept_str } - actor_nickname = get_nickname_from_actor(post_json_object['actor']) + actor_nickname = get_nickname_from_actor(actor_url) if not actor_nickname: print('WARN: download_announce no actor_nickname') return None actor_domain, actor_port = \ - get_domain_from_actor(post_json_object['actor']) + get_domain_from_actor(actor_url) if not actor_domain: print('Announce actor does not contain a ' + 'valid domain or port number: ' + - str(post_json_object['actor'])) + actor_url) return None if is_blocked(base_dir, nickname, domain, actor_nickname, actor_domain): @@ -6581,7 +6584,7 @@ def get_original_post_from_announce_url(announce_url: str, base_dir: str, actor = attrib url = orig_post_id elif orig_post_json['object'].get('actor'): - actor = orig_post_json['actor'] + actor = get_actor_from_post(orig_post_json) url = orig_post_id else: # we don't have the original post diff --git a/question.py b/question.py index 40ffec010..7140ee2f0 100644 --- a/question.py +++ b/question.py @@ -15,6 +15,7 @@ from utils import has_object_dict from utils import text_in_file from utils import dangerous_markup from utils import get_reply_to +from utils import get_actor_from_post def is_vote(base_dir: str, nickname: str, domain: str, @@ -120,23 +121,24 @@ def question_update_votes(base_dir: str, nickname: str, domain: str, # update the voters file voters_file_separator = ';;;' voters_filename = question_post_filename.replace('.json', '.voters') + actor_url = get_actor_from_post(reply_json) if not os.path.isfile(voters_filename): # create a new voters file try: with open(voters_filename, 'w+', encoding='utf-8') as voters_file: - voters_file.write(reply_json['actor'] + + voters_file.write(actor_url + voters_file_separator + reply_vote + '\n') except OSError: print('EX: unable to write voters file ' + voters_filename) else: - if not text_in_file(reply_json['actor'], voters_filename): + if not text_in_file(actor_url, voters_filename): # append to the voters file try: with open(voters_filename, 'a+', encoding='utf-8') as voters_file: - voters_file.write(reply_json['actor'] + + voters_file.write(actor_url + voters_file_separator + reply_vote + '\n') except OSError: @@ -149,9 +151,9 @@ def question_update_votes(base_dir: str, nickname: str, domain: str, newlines = [] save_voters_file = False for vote_line in lines: - if vote_line.startswith(reply_json['actor'] + + if vote_line.startswith(actor_url + voters_file_separator): - new_vote_line = reply_json['actor'] + \ + new_vote_line = actor_url + \ voters_file_separator + reply_vote + '\n' if vote_line == new_vote_line: break diff --git a/reaction.py b/reaction.py index 18d375874..66748a8dd 100644 --- a/reaction.py +++ b/reaction.py @@ -32,6 +32,7 @@ from utils import remove_post_from_cache from utils import get_cached_post_filename from utils import contains_invalid_chars from utils import remove_eol +from utils import get_actor_from_post from posts import send_signed_json from session import post_json from webfinger import webfinger_handle @@ -133,9 +134,10 @@ def _reactionpost(recent_posts_cache: {}, print('DEBUG: reaction object_url: ' + object_url) return None + actor_url = get_actor_from_post(new_reaction_json) update_reaction_collection(recent_posts_cache, base_dir, post_filename, object_url, - new_reaction_json['actor'], + actor_url, nickname, domain, debug, None, emoji_content) @@ -408,9 +410,10 @@ def outbox_reaction(recent_posts_cache: {}, print('DEBUG: c2s reaction post not found in inbox or outbox') print(message_id) return True + actor_url = get_actor_from_post(message_json) update_reaction_collection(recent_posts_cache, base_dir, post_filename, message_id, - message_json['actor'], + actor_url, nickname, domain, debug, None, emoji_content) if debug: print('DEBUG: post reaction via c2s - ' + post_filename) @@ -449,8 +452,9 @@ def outbox_undo_reaction(recent_posts_cache: {}, print('DEBUG: c2s undo reaction post not found in inbox or outbox') print(message_id) return True + actor_url = get_actor_from_post(message_json) undo_reaction_collection_entry(recent_posts_cache, base_dir, post_filename, - message_id, message_json['actor'], + message_id, actor_url, domain, debug, None, emoji_content) if debug: print('DEBUG: post undo reaction via c2s - ' + post_filename) @@ -642,7 +646,8 @@ def html_emoji_reactions(post_json_object: {}, interactive: bool, base_url = actor + '?react=' + react_by else: base_url = actor + '?unreact=' + react_by - base_url += '?actor=' + post_json_object['actor'] + actor_url = get_actor_from_post(post_json_object) + base_url += '?actor=' + actor_url base_url += '?tl=' + box_name base_url += '?page=' + str(page_number) base_url += '?emojreact=' diff --git a/shares.py b/shares.py index 901c359e7..594691ab4 100644 --- a/shares.py +++ b/shares.py @@ -45,6 +45,7 @@ from utils import is_float from utils import get_category_types from utils import get_shares_files_list from utils import local_actor_url +from utils import get_actor_from_post from media import process_meta_data from media import convert_image_to_low_bandwidth from filters import is_filtered_globally @@ -2088,6 +2089,7 @@ def vf_proposal_from_share(shared_item: {}, "http://www.ontology-of-units-of-measure.org/resource/om-2/" share_id = _vf_share_id(shared_item['shareId']) published = date_seconds_to_string(shared_item['published']) + actor_url = get_actor_from_post(shared_item) offer_item = { "@context": [ "https://www.w3.org/ns/activitystreams", @@ -2111,7 +2113,7 @@ def vf_proposal_from_share(shared_item: {}, ], "type": share_type, "id": share_id, - "attributedTo": shared_item['actor'], + "attributedTo": actor_url, "name": shared_item['displayName'], "content": shared_item['summary'], "published": published, @@ -2123,7 +2125,7 @@ def vf_proposal_from_share(shared_item: {}, "hasUnit": "one", "hasNumericalValue": str(shared_item['itemQty']) }, - publishes_direction: shared_item['actor'] + publishes_direction: actor_url }, "attachment": [], "unitBased": False, @@ -2176,7 +2178,7 @@ def vf_proposal_from_share(shared_item: {}, "hasUnit": "one", "hasNumericalValue": str(shared_item['itemPrice']) }, - reciprocal_direction: shared_item['actor'] + reciprocal_direction: actor_url } return offer_item diff --git a/skills.py b/skills.py index da2eeb806..b10cd9fda 100644 --- a/skills.py +++ b/skills.py @@ -22,6 +22,7 @@ from utils import set_occupation_skills_list from utils import acct_dir from utils import local_actor_url from utils import has_actor +from utils import get_actor_from_post def set_skills_from_dict(actor_json: {}, skills_dict: {}) -> []: @@ -157,12 +158,13 @@ def outbox_skills(base_dir: str, nickname: str, message_json: {}, if not has_object_string(message_json, debug): return False - actor_nickname = get_nickname_from_actor(message_json['actor']) + actor_url = get_actor_from_post(message_json) + actor_nickname = get_nickname_from_actor(actor_url) if not actor_nickname: return False if actor_nickname != nickname: return False - domain, _ = get_domain_from_actor(message_json['actor']) + domain, _ = get_domain_from_actor(actor_url) skill = message_json['object'].replace('"', '').split(';')[0].strip() skill_level_percent_str = \ message_json['object'].replace('"', '').split(';')[1].strip() diff --git a/speaker.py b/speaker.py index 83c9525f7..d1e37e3c2 100644 --- a/speaker.py +++ b/speaker.py @@ -27,6 +27,7 @@ from utils import is_pgp_encrypted from utils import has_object_dict from utils import acct_dir from utils import local_actor_url +from utils import get_actor_from_post from content import html_replace_quote_marks SPEAKER_REMOVE_CHARS = ('.\n', '. ', ',', ';', '?', '!') @@ -492,14 +493,16 @@ def _post_to_speaker_json(base_dir: str, http_prefix: str, urllib.parse.unquote_plus(post_json_object_summary) summary = html.unescape(summary) + actor_url = get_actor_from_post(post_json_object) speaker_name = \ - get_display_name(base_dir, post_json_object['actor'], person_cache) + get_display_name(base_dir, actor_url, person_cache) if not speaker_name: return speaker_name = _remove_emoji_from_text(speaker_name) speaker_name = speaker_name.replace('_', ' ') speaker_name = camel_case_split(speaker_name) - gender = get_gender_from_bio(base_dir, post_json_object['actor'], + actor_url = get_actor_from_post(post_json_object) + gender = get_gender_from_bio(base_dir, actor_url, person_cache, translate) if announcing_actor: announced_nickname = get_nickname_from_actor(announcing_actor) diff --git a/utils.py b/utils.py index 0f1841561..897a61d6e 100644 --- a/utils.py +++ b/utils.py @@ -4013,7 +4013,8 @@ def has_actor(post_json_object: {}, debug: bool) -> bool: """Does the given post have an actor? """ if post_json_object.get('actor'): - if '#' in post_json_object['actor']: + actor_url = get_actor_from_post(post_json_object) + if '#' in actor_url or not actor_url: return False return True if debug: @@ -4881,3 +4882,17 @@ def is_valid_date(date_str: str) -> bool: return False date_sect_ctr += 1 return True + + +def get_actor_from_post(post_json_object: {}) -> str: + """Gets the actor url from the given post + """ + if not post_json_object.get('actor'): + return '' + if isinstance(post_json_object['actor'], str): + return post_json_object['actor'] + if isinstance(post_json_object['actor'], dict): + if post_json_object['actor'].get('id'): + if isinstance(post_json_object['actor']['id'], str): + return post_json_object['actor']['id'] + return '' diff --git a/webapp_likers.py b/webapp_likers.py index d7e5d6c5d..8b9c83fa4 100644 --- a/webapp_likers.py +++ b/webapp_likers.py @@ -15,6 +15,7 @@ from utils import get_display_name from utils import get_nickname_from_actor from utils import has_object_dict from utils import load_json +from utils import get_actor_from_post from person import get_person_avatar_url from webapp_utils import html_header_with_external_style from webapp_utils import html_footer @@ -139,7 +140,8 @@ def html_likers_of_post(base_dir: str, nickname: str, for like_item in obj[dict_name]['items']: if not like_item.get('actor'): continue - liker_actor = like_item['actor'] + actor_url = get_actor_from_post(like_item) + liker_actor = actor_url liker_display_name = \ get_display_name(base_dir, liker_actor, person_cache) if liker_display_name: diff --git a/webapp_post.py b/webapp_post.py index aefb12e55..5bb5919ad 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -74,6 +74,7 @@ from utils import is_unlisted_post from utils import language_right_to_left from utils import get_attributed_to from utils import get_reply_to +from utils import get_actor_from_post from content import format_mixed_right_to_left from content import replace_remote_hashtags from content import detect_dogwhistles @@ -615,17 +616,19 @@ def _get_reply_icon_html(base_dir: str, nickname: str, domain: str, if conversation_id: conversation_str = '?conversationId=' + conversation_id if is_public_reply: + actor_url = get_actor_from_post(post_json_object) reply_str += \ ' \n' elif is_unlisted_reply: + actor_url = get_actor_from_post(post_json_object) reply_str += \ ' \n' else: @@ -633,19 +636,21 @@ def _get_reply_icon_html(base_dir: str, nickname: str, domain: str, reply_type = 'replydm' if is_chat_message(post_json_object): reply_type = 'replychat' + actor_url = get_actor_from_post(post_json_object) reply_str += \ ' ' + \ '\n' else: + actor_url = get_actor_from_post(post_json_object) reply_str += \ ' ' + \ '\n' @@ -664,7 +669,7 @@ def _get_edit_icon_html(base_dir: str, nickname: str, domain_full: str, """Returns html for the edit icon/button """ edit_str = '' - actor = post_json_object['actor'] + actor = get_actor_from_post(post_json_object) # This should either be a post which you created, # or it could be generated from the newswire (see # _add_blogs_to_newswire) in which case anyone with @@ -892,10 +897,11 @@ def _get_announce_icon_html(is_announced: bool, announce_link_str = '?' + \ announce_link + '=' + announce_post_id + page_number_param + actor_url = get_actor_from_post(post_json_object) announce_str += \ ' \n' @@ -976,11 +982,12 @@ def _get_like_icon_html(nickname: str, domain_full: str, if first_post_id: first_post_str = '?firstpost=' + first_post_id.replace('#', '/') + actor_url = get_actor_from_post(post_json_object) like_str += \ ' \n' @@ -1037,11 +1044,12 @@ def _get_bookmark_icon_html(base_dir: str, if first_post_id: first_post_str = '?firstpost=' + first_post_id.replace('#', '/') + actor_url = get_actor_from_post(post_json_object) bookmark_str = \ ' \n' @@ -1083,10 +1091,11 @@ def _get_reaction_icon_html(nickname: str, post_json_object: {}, if first_post_id: first_post_str = '?firstpost=' + first_post_id.replace('#', '/') + actor_url = get_actor_from_post(post_json_object) reaction_str = \ ' \n' @@ -2086,7 +2095,7 @@ def individual_post_as_html(signing_priv_key_pem: str, # benchmark post_start_time = time.time() - post_actor = post_json_object['actor'] + post_actor = get_actor_from_post(post_json_object) # ZZZzzz if is_person_snoozed(base_dir, nickname, domain, post_actor): @@ -2309,10 +2318,11 @@ def individual_post_as_html(signing_priv_key_pem: str, if is_recent_post(post_json_object, 3): if post_json_object.get('actor'): if not os.path.isfile(announce_filename + '.tts'): + actor_url = get_actor_from_post(post_json_object) update_speaker(base_dir, http_prefix, nickname, domain, domain_full, post_json_object, person_cache, - translate, post_json_object['actor'], + translate, actor_url, theme_name, system_language, box_name) try: @@ -3303,13 +3313,14 @@ def html_emoji_reaction_picker(recent_posts_cache: {}, max_recent_posts: int, emoji_picks_str = '' base_url = '/users/' + nickname post_id = remove_id_ending(post_json_object['id']) + actor_url = get_actor_from_post(post_json_object) for _, item in reactions_json.items(): emoji_picks_str += '
\n' for emoji_content in item: emoji_content_encoded = urllib.parse.quote_plus(emoji_content) emoji_url = \ base_url + '?react=' + post_id + \ - '?actor=' + post_json_object['actor'] + \ + '?actor=' + actor_url + \ '?tl=' + box_name + \ '?page=' + str(page_number) + \ '?emojreact=' + emoji_content_encoded diff --git a/webapp_profile.py b/webapp_profile.py index a8d7301ee..7618e1b03 100644 --- a/webapp_profile.py +++ b/webapp_profile.py @@ -39,6 +39,7 @@ from utils import get_reply_interval_hours from utils import get_account_timezone from utils import remove_eol from utils import is_valid_date +from utils import get_actor_from_post from languages import get_actor_languages from skills import get_skills from theme import get_themes_list @@ -167,8 +168,9 @@ def _valid_profile_preview_post(post_json_object: {}, return False, None # convert actor back to id if isinstance(post_json_object['actor'], dict): - if post_json_object['actor'].get('id'): - post_json_object['actor'] = post_json_object['actor']['id'] + actor_url = get_actor_from_post(post_json_object) + if actor_url: + post_json_object['actor'] = actor_url if has_object_dict(post_json_object): # convert attributedTo actor back to id if post_json_object['object'].get('attributedTo'): @@ -178,7 +180,8 @@ def _valid_profile_preview_post(post_json_object: {}, post_json_object['object']['attributedTo'] = \ post_json_object['object']['attributedTo']['id'] if not is_announced_feed_item: - if post_json_object['actor'] != person_url and \ + actor_url = get_actor_from_post(post_json_object) + if actor_url != person_url and \ post_json_object['object']['type'] != 'Page': return False, None return True, post_json_object diff --git a/webapp_timeline.py b/webapp_timeline.py index 267b80cf9..f5f0842ce 100644 --- a/webapp_timeline.py +++ b/webapp_timeline.py @@ -20,6 +20,7 @@ from utils import acct_dir from utils import is_float from utils import local_actor_url from utils import remove_eol +from utils import get_actor_from_post from follow import follower_approval_active from person import is_person_snoozed from markdown import markdown_to_html @@ -1188,7 +1189,7 @@ def html_individual_share(domain: str, share_id: str, contact_title_str = translate['Request to stay'] button_style_str = 'contactbutton' - contact_actor = shared_item['actor'] + contact_actor = get_actor_from_post(shared_item) profile_str += \ '

' + \ '