Handle incoming edited posts

main
Bob Mottram 2022-04-09 16:11:22 +01:00
parent 1d46483996
commit 4be7edd5f5
13 changed files with 226 additions and 49 deletions

View File

@ -20,7 +20,7 @@ from utils import acct_dir
from utils import has_group_type
from utils import local_actor_url
from utils import has_actor
from utils import has_object_stringType
from utils import has_object_string_type
def _create_accept_reject(base_dir: str, federation_list: [],
@ -81,7 +81,7 @@ def _accept_follow(base_dir: str, domain: str, message_json: {},
onion_domain: str, i2p_domain: str) -> None:
"""Receiving a follow Accept activity
"""
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return
if not message_json['object']['type'] == 'Follow':
if not message_json['object']['type'] == 'Join':

View File

@ -26,7 +26,7 @@ from utils import update_announce_collection
from utils import local_actor_url
from utils import replace_users_with_at
from utils import has_actor
from utils import has_object_stringType
from utils import has_object_string_type
from posts import send_signed_json
from posts import get_person_box
from session import post_json
@ -100,7 +100,7 @@ def outbox_announce(recent_posts_cache: {},
nickname, domain, debug)
return True
elif message_json['type'] == 'Undo':
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return False
if message_json['object']['type'] == 'Announce':
if not isinstance(message_json['object']['object'], str):
@ -422,7 +422,7 @@ def outbox_undo_announce(recent_posts_cache: {},
return
if not message_json['type'] == 'Undo':
return
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return
if not message_json['object']['type'] == 'Announce':
if debug:

View File

@ -13,7 +13,7 @@ import time
from datetime import datetime
from utils import has_object_string
from utils import has_object_string_object
from utils import has_object_stringType
from utils import has_object_string_type
from utils import remove_domain_port
from utils import has_object_dict
from utils import is_account_dir
@ -483,7 +483,7 @@ def outbox_undo_block(base_dir: str, http_prefix: str,
print('DEBUG: not an undo block')
return
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return
if not message_json['object']['type'] == 'Block':
if debug:
@ -841,7 +841,7 @@ def outbox_undo_mute(base_dir: str, http_prefix: str,
return
if not message_json['type'] == 'Undo':
return
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return
if message_json['object']['type'] != 'Ignore':
return

View File

@ -27,7 +27,7 @@ from utils import has_object_dict
from utils import acct_dir
from utils import local_actor_url
from utils import has_actor
from utils import has_object_stringType
from utils import has_object_string_type
from posts import get_person_box
from session import post_json
@ -571,7 +571,7 @@ def outbox_bookmark(recent_posts_cache: {},
if debug:
print('DEBUG: no target in bookmark Add')
return
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return
if not isinstance(message_json['target'], str):
if debug:
@ -627,7 +627,7 @@ def outbox_undo_bookmark(recent_posts_cache: {},
if debug:
print('DEBUG: no target in unbookmark Remove')
return
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return
if not isinstance(message_json['target'], str):
if debug:

View File

@ -10,7 +10,7 @@ __module_group__ = "ActivityPub"
from pprint import pprint
import os
from utils import has_object_string_object
from utils import has_object_stringType
from utils import has_object_string_type
from utils import remove_domain_port
from utils import has_users_path
from utils import get_full_domain
@ -1407,7 +1407,7 @@ def outbox_undo_follow(base_dir: str, message_json: {}, debug: bool) -> None:
return
if not message_json['type'] == 'Undo':
return
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return
if not message_json['object']['type'] == 'Follow':
if not message_json['object']['type'] == 'Join':

4
git.py
View File

@ -10,7 +10,7 @@ __module_group__ = "Profile Metadata"
import os
import html
from utils import acct_dir
from utils import has_object_stringType
from utils import has_object_string_type
def _git_format_content(content: str) -> str:
@ -114,7 +114,7 @@ def convert_post_to_patch(base_dir: str, nickname: str, domain: str,
"""Detects whether the given post contains a patch
and if so then converts it to a Patch ActivityPub type
"""
if not has_object_stringType(post_json_object, False):
if not has_object_string_type(post_json_object, False):
return False
if post_json_object['object']['type'] == 'Patch':
return True

203
inbox.py
View File

@ -17,6 +17,7 @@ from languages import understood_post_language
from like import update_likes_collection
from reaction import update_reaction_collection
from reaction import valid_emoji_content
from utils import delete_cached_html
from utils import get_account_timezone
from utils import domain_permitted
from utils import is_group_account
@ -61,7 +62,7 @@ from utils import undo_likes_collection_entry
from utils import undo_reaction_collection_entry
from utils import has_group_type
from utils import local_actor_url
from utils import has_object_stringType
from utils import has_object_string_type
from utils import valid_hash_tag
from categories import get_hashtag_categories
from categories import set_hashtag_category
@ -849,7 +850,7 @@ def _receive_undo(session, base_dir: str, http_prefix: str,
if debug:
print('DEBUG: "users" or "profile" missing from actor')
return False
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return False
if not has_object_string_object(message_json, debug):
return False
@ -979,20 +980,150 @@ def _receive_update_to_question(recent_posts_cache: {}, message_json: {},
remove_post_from_cache(message_json, recent_posts_cache)
def _receive_edit_to_post(recent_posts_cache: {}, message_json: {},
base_dir: str,
nickname: str, domain: str,
max_mentions: int, max_emoji: int,
allow_local_network_access: bool,
debug: bool,
system_language: str, http_prefix: str,
domain_full: str, person_cache: {},
signing_priv_key_pem: str,
max_recent_posts: int, translate: {},
session, cached_webfingers: {}, port: int,
allow_deletion: bool,
yt_replace_domain: str,
twitter_replacement_domain: str,
show_published_date_only: bool,
peertube_instances: [],
theme_name: str, max_like_count: int,
cw_lists: {}) -> bool:
"""A post was edited
"""
if not has_object_dict(message_json):
return False
# message url of the question
if not message_json['object'].get('id'):
return False
if not message_json.get('actor'):
return False
if not has_actor(message_json, False):
return False
if not has_actor(message_json['object'], False):
return False
message_id = remove_id_ending(message_json['object']['id'])
if '#' in message_id:
message_id = message_id.split('#', 1)[0]
# find the post which was edited
post_filename = locate_post(base_dir, nickname, domain, message_id)
if not post_filename:
print('EDITPOST: ' + message_id + ' has already expired')
return False
if not _valid_post_content(base_dir, nickname, domain,
message_json, max_mentions, max_emoji,
allow_local_network_access, debug,
system_language, http_prefix,
domain_full, person_cache):
print('EDITPOST: contains invalid content' + str(message_json))
return False
# load the json for the post
post_json_object = load_json(post_filename, 1)
if not post_json_object:
return False
if not post_json_object.get('actor'):
return False
# does the actor match?
if post_json_object['actor'] != message_json['actor']:
print('EDITPOST: actors do not match ' +
post_json_object['actor'] + ' != ' + message_json['actor'])
return False
# Change Update to Create
message_json['type'] = 'Create'
save_json(message_json, post_filename)
# ensure that the cached post is removed if it exists, so
# that it then will be recreated
cached_post_filename = \
get_cached_post_filename(base_dir, nickname, domain, message_json)
if cached_post_filename:
if os.path.isfile(cached_post_filename):
try:
os.remove(cached_post_filename)
except OSError:
print('EX: _receive_edit_to_post unable to delete ' +
cached_post_filename)
# remove any cached html for the post which was edited
delete_cached_html(base_dir, nickname, domain, post_json_object)
# remove from memory cache
remove_post_from_cache(message_json, recent_posts_cache)
# regenerate html for the post
page_number = 1
show_published_date_only = False
show_individual_post_icons = True
manually_approve_followers = \
follower_approval_active(base_dir, nickname, domain)
not_dm = not is_dm(message_json)
timezone = get_account_timezone(base_dir, nickname, domain)
mitm = False
if os.path.isfile(post_filename.replace('.json', '') + '.mitm'):
mitm = True
bold_reading = False
bold_reading_filename = \
base_dir + '/accounts/' + nickname + '@' + domain + '/.boldReading'
if os.path.isfile(bold_reading_filename):
bold_reading = True
timezone = get_account_timezone(base_dir, nickname, domain)
lists_enabled = get_config_param(base_dir, "listsEnabled")
individual_post_as_html(signing_priv_key_pem, False,
recent_posts_cache, max_recent_posts,
translate, page_number, base_dir,
session, cached_webfingers, person_cache,
nickname, domain, port, message_json,
None, True, allow_deletion,
http_prefix, __version__,
'inbox',
yt_replace_domain,
twitter_replacement_domain,
show_published_date_only,
peertube_instances,
allow_local_network_access,
theme_name, system_language,
max_like_count, not_dm,
show_individual_post_icons,
manually_approve_followers,
False, True, False, cw_lists,
lists_enabled, timezone, mitm,
bold_reading)
return True
def _receive_update_activity(recent_posts_cache: {}, session, base_dir: str,
http_prefix: str, domain: str, port: int,
send_threads: [], post_log: [],
cached_webfingers: {},
person_cache: {}, message_json: {},
federation_list: [],
nickname: str, debug: bool) -> bool:
nickname: str, debug: bool,
max_mentions: int, max_emoji: int,
allow_local_network_access: bool,
system_language: str,
signing_priv_key_pem: str,
max_recent_posts: int, translate: {},
allow_deletion: bool,
yt_replace_domain: str,
twitter_replacement_domain: str,
show_published_date_only: bool,
peertube_instances: [],
theme_name: str, max_like_count: int,
cw_lists: {}) -> bool:
"""Receives an Update activity within the POST section of HTTPServer
"""
if message_json['type'] != 'Update':
return False
if not has_actor(message_json, debug):
return False
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return False
if not has_users_path(message_json['actor']):
if debug:
@ -1006,6 +1137,30 @@ def _receive_update_activity(recent_posts_cache: {}, session, base_dir: str,
if debug:
print('DEBUG: Question update was received')
return True
elif message_json['object']['type'] == 'Note':
if message_json['object'].get('id'):
domain_full = get_full_domain(domain, port)
if _receive_edit_to_post(recent_posts_cache, message_json,
base_dir, nickname, domain,
max_mentions, max_emoji,
allow_local_network_access,
debug, system_language, http_prefix,
domain_full, person_cache,
signing_priv_key_pem,
max_recent_posts, translate,
session, cached_webfingers, port,
allow_deletion,
yt_replace_domain,
twitter_replacement_domain,
show_published_date_only,
peertube_instances,
theme_name, max_like_count,
cw_lists):
print('EDITPOST: received ' + message_json['object']['id'])
return True
else:
print('EDITPOST: rejected ' + str(message_json))
return False
if message_json['object']['type'] == 'Person' or \
message_json['object']['type'] == 'Application' or \
@ -1186,7 +1341,7 @@ def _receive_undo_like(recent_posts_cache: {},
return False
if not has_actor(message_json, debug):
return False
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return False
if message_json['object']['type'] != 'Like':
return False
@ -1458,7 +1613,7 @@ def _receive_undo_reaction(recent_posts_cache: {},
return False
if not has_actor(message_json, debug):
return False
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return False
if message_json['object']['type'] != 'EmojiReact':
return False
@ -1599,7 +1754,7 @@ def _receive_bookmark(recent_posts_cache: {},
if debug:
print('DEBUG: no target in inbox bookmark Add')
return False
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return False
if not isinstance(message_json['target'], str):
if debug:
@ -1716,7 +1871,7 @@ def _receive_undo_bookmark(recent_posts_cache: {},
if debug:
print('DEBUG: no target in inbox undo bookmark Remove')
return False
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return False
if not isinstance(message_json['target'], str):
if debug:
@ -2318,6 +2473,20 @@ def _valid_post_content(base_dir: str, nickname: str, domain: str,
if not valid_post_date(published, 90, debug):
return False
# if the post has been edited then check its edit date
if message_json['object'].get('updated'):
published_update = message_json['object']['updated']
if 'T' not in published_update:
return False
if 'Z' not in published_update:
return False
if '.' in published_update:
# converts 2022-03-30T17:37:58.734Z into 2022-03-30T17:37:58Z
published_update = published_update.split('.')[0] + 'Z'
message_json['object']['updated'] = published_update
if not valid_post_date(published_update, 90, debug):
return False
summary = None
if message_json['object'].get('summary'):
summary = message_json['object']['summary']
@ -3706,10 +3875,6 @@ def _inbox_after_initial(server,
person_cache, post_json_object, debug,
signing_priv_key_pem)
if json_obj.get('updated') and json_obj.get('id'):
updated_post_id = remove_id_ending(json_obj['id'])
print('Receiving edit to post ' + updated_post_id)
# save the post to file
if save_json(post_json_object, destination_filename):
if mitm:
@ -4748,7 +4913,19 @@ def run_inbox_queue(server,
queue_json['post'],
federation_list,
queue_json['postNickname'],
debug):
debug,
max_mentions, max_emoji,
allow_local_network_access,
system_language,
signing_priv_key_pem,
max_recent_posts, translate,
allow_deletion,
yt_replace_domain,
twitter_replacement_domain,
show_published_date_only,
peertube_instances,
theme_name, max_like_count,
cw_lists):
if debug:
print('Queue: Update accepted from ' + key_id)
if os.path.isfile(queue_filename):

View File

@ -11,7 +11,7 @@ import os
from pprint import pprint
from utils import has_object_string
from utils import has_object_string_object
from utils import has_object_stringType
from utils import has_object_string_type
from utils import remove_domain_port
from utils import has_object_dict
from utils import has_users_path
@ -395,7 +395,7 @@ def outbox_undo_like(recent_posts_cache: {},
return
if not message_json['type'] == 'Undo':
return
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return
if not message_json['object']['type'] == 'Like':
if debug:

View File

@ -16,7 +16,7 @@ from posts import save_post_to_box
from posts import send_to_followers_thread
from posts import send_to_named_addresses_thread
from utils import get_account_timezone
from utils import has_object_stringType
from utils import has_object_string_type
from utils import get_base_content_from_post
from utils import has_object_dict
from utils import get_local_network_addresses
@ -76,7 +76,7 @@ def _person_receive_update_outbox(recent_posts_cache: {},
return
if message_json['type'] != 'Update':
return
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return
if not isinstance(message_json['object']['type'], str):
if debug:

View File

@ -35,7 +35,7 @@ from languages import understood_post_language
from utils import get_summary_from_post
from utils import get_user_paths
from utils import invalid_ciphertext
from utils import has_object_stringType
from utils import has_object_string_type
from utils import remove_id_ending
from utils import replace_users_with_at
from utils import has_group_type
@ -2995,7 +2995,7 @@ def _is_profile_update(post_json_object: {}) -> bool:
for actor updates there is no 'to' within the object
"""
if post_json_object.get('type'):
if has_object_stringType(post_json_object, False):
if has_object_string_type(post_json_object, False):
if (post_json_object['type'] == 'Update' and
(post_json_object['object']['type'] == 'Person' or
post_json_object['object']['type'] == 'Application' or
@ -3038,7 +3038,7 @@ def _send_to_named_addresses(server, session, session_onion, session_i2p,
pprint(post_json_object)
print('DEBUG: ' +
'no "to" field when sending to named addresses')
if has_object_stringType(post_json_object, debug):
if has_object_string_type(post_json_object, debug):
if post_json_object['object']['type'] == 'Follow' or \
post_json_object['object']['type'] == 'Join':
post_json_obj2 = post_json_object['object']['object']
@ -3257,7 +3257,7 @@ def _sending_profile_update(post_json_object: {}) -> bool:
"""
if post_json_object['type'] != 'Update':
return False
if not has_object_stringType(post_json_object, False):
if not has_object_string_type(post_json_object, False):
return False
activity_type = post_json_object['object']['type']
if activity_type in ('Person', 'Application', 'Group', 'Service'):

View File

@ -13,7 +13,7 @@ import urllib.parse
from pprint import pprint
from utils import has_object_string
from utils import has_object_string_object
from utils import has_object_stringType
from utils import has_object_string_type
from utils import remove_domain_port
from utils import has_object_dict
from utils import has_users_path
@ -415,7 +415,7 @@ def outbox_undo_reaction(recent_posts_cache: {},
return
if not message_json['type'] == 'Undo':
return
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return
if not message_json['object']['type'] == 'EmojiReact':
if debug:

View File

@ -22,7 +22,7 @@ from posts import get_person_box
from session import post_json
from session import post_image
from session import create_session
from utils import has_object_stringType
from utils import has_object_string_type
from utils import date_string_to_seconds
from utils import date_seconds_to_string
from utils import get_config_param
@ -1040,7 +1040,7 @@ def outbox_share_upload(base_dir: str, http_prefix: str,
return
if not message_json['type'] == 'Add':
return
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return
if not message_json['object']['type'] == 'Offer':
if debug:
@ -1109,7 +1109,7 @@ def outbox_undo_share_upload(base_dir: str, http_prefix: str,
return
if not message_json['type'] == 'Remove':
return
if not has_object_stringType(message_json, debug):
if not has_object_string_type(message_json, debug):
return
if not message_json['object']['type'] == 'Offer':
if debug:

View File

@ -1680,8 +1680,8 @@ def remove_post_from_cache(post_json_object: {},
del recent_posts_cache['html'][post_id]
def _delete_cached_html(base_dir: str, nickname: str, domain: str,
post_json_object: {}):
def delete_cached_html(base_dir: str, nickname: str, domain: str,
post_json_object: {}):
"""Removes cached html file for the given post
"""
cached_post_filename = \
@ -1691,7 +1691,7 @@ def _delete_cached_html(base_dir: str, nickname: str, domain: str,
try:
os.remove(cached_post_filename)
except OSError:
print('EX: _delete_cached_html ' +
print('EX: delete_cached_html ' +
'unable to delete cached post file ' +
str(cached_post_filename))
@ -1842,7 +1842,7 @@ def delete_post(base_dir: str, http_prefix: str,
str(ext_filename))
# remove cached html version of the post
_delete_cached_html(base_dir, nickname, domain, post_json_object)
delete_cached_html(base_dir, nickname, domain, post_json_object)
has_object = False
if post_json_object.get('object'):
@ -2206,7 +2206,7 @@ def is_blog_post(post_json_object: {}) -> bool:
return False
if not has_object_dict(post_json_object):
return False
if not has_object_stringType(post_json_object, False):
if not has_object_string_type(post_json_object, False):
return False
if not post_json_object['object'].get('content'):
return False
@ -3353,12 +3353,12 @@ def has_actor(post_json_object: {}, debug: bool) -> bool:
return False
def has_object_stringType(post_json_object: {}, debug: bool) -> bool:
def has_object_string_type(post_json_object: {}, debug: bool) -> bool:
"""Does the given post have a type field within an object dict?
"""
if not has_object_dict(post_json_object):
if debug:
print('has_object_stringType no object found')
print('has_object_string_type no object found')
return False
if post_json_object['object'].get('type'):
if isinstance(post_json_object['object']['type'], str):
@ -3377,7 +3377,7 @@ def has_object_string_object(post_json_object: {}, debug: bool) -> bool:
"""
if not has_object_dict(post_json_object):
if debug:
print('has_object_stringType no object found')
print('has_object_string_type no object found')
return False
if post_json_object['object'].get('object'):
if isinstance(post_json_object['object']['object'], str):