epicyon/outbox.py

836 lines
35 KiB
Python
Raw Normal View History

2020-04-03 17:15:33 +00:00
__filename__ = "outbox.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
2024-01-21 19:01:20 +00:00
__version__ = "1.5.0"
2020-04-03 17:15:33 +00:00
__maintainer__ = "Bob Mottram"
2021-09-10 16:14:50 +00:00
__email__ = "bob@libreserver.org"
2020-04-03 17:15:33 +00:00
__status__ = "Production"
2021-06-15 15:08:12 +00:00
__module_group__ = "Timeline"
2020-01-13 10:35:17 +00:00
import os
from shutil import copyfile
2021-12-28 21:36:27 +00:00
from auth import create_password
2021-12-29 21:55:09 +00:00
from posts import is_image_media
2021-12-28 19:33:29 +00:00
from posts import outbox_message_create_wrap
2021-12-28 18:13:52 +00:00
from posts import save_post_to_box
2021-12-29 21:55:09 +00:00
from posts import send_to_followers_thread
from posts import send_to_named_addresses_thread
from utils import get_post_attachments
from utils import get_attributed_to
2022-12-26 11:25:51 +00:00
from utils import contains_invalid_actor_url_chars
from utils import get_attachment_property_value
2022-02-25 19:12:40 +00:00
from utils import get_account_timezone
2022-04-09 15:11:22 +00:00
from utils import has_object_string_type
2021-12-26 11:29:40 +00:00
from utils import get_base_content_from_post
2021-12-26 10:57:03 +00:00
from utils import has_object_dict
2021-12-27 20:43:15 +00:00
from utils import get_local_network_addresses
2021-12-26 12:45:03 +00:00
from utils import get_full_domain
2021-12-27 11:20:57 +00:00
from utils import remove_id_ending
2021-12-27 19:05:25 +00:00
from utils import get_domain_from_actor
2021-12-27 21:42:08 +00:00
from utils import dangerous_markup
2021-12-26 12:07:40 +00:00
from utils import is_featured_writer
2021-12-26 15:13:34 +00:00
from utils import load_json
2021-12-26 14:47:21 +00:00
from utils import save_json
2021-12-26 12:02:29 +00:00
from utils import acct_dir
2021-12-26 10:19:59 +00:00
from utils import local_actor_url
2021-12-26 17:15:04 +00:00
from utils import has_actor
2022-12-24 15:33:26 +00:00
from utils import is_quote_toot
2024-01-09 16:59:23 +00:00
from utils import get_actor_from_post
2021-12-28 21:55:38 +00:00
from blocking import is_blocked_domain
2021-12-29 21:55:09 +00:00
from blocking import outbox_block
from blocking import outbox_undo_block
from blocking import outbox_mute
from blocking import outbox_undo_mute
2021-12-28 21:36:27 +00:00
from media import replace_you_tube
from media import replace_twitter
2021-12-29 21:55:09 +00:00
from media import get_media_path
from media import create_media_dirs
2022-08-22 17:45:18 +00:00
from inbox import store_hash_tags
2021-12-29 21:55:09 +00:00
from inbox import inbox_update_index
from announce import outbox_announce
from announce import outbox_undo_announce
from follow import outbox_undo_follow
2021-12-28 20:32:11 +00:00
from follow import follower_approval_active
2021-12-29 21:55:09 +00:00
from skills import outbox_skills
from availability import outbox_availability
from like import outbox_like
from like import outbox_undo_like
from reaction import outbox_reaction
from reaction import outbox_undo_reaction
from bookmarks import outbox_bookmark
from bookmarks import outbox_undo_bookmark
from delete import outbox_delete
from shares import outbox_share_upload
from shares import outbox_undo_share_upload
from webapp_post import individual_post_as_html
2022-05-12 12:21:03 +00:00
from speaker import update_speaker
2024-01-03 19:11:17 +00:00
from reading import store_book_events
2024-01-04 18:53:34 +00:00
from reading import has_edition_tag
2021-12-29 21:55:09 +00:00
2022-06-12 21:31:53 +00:00
def _person_receive_update_outbox(base_dir: str, http_prefix: str,
2021-12-29 21:55:09 +00:00
nickname: str, domain: str, port: int,
message_json: {}, debug: bool) -> None:
2021-03-17 20:18:00 +00:00
""" Receive an actor update from c2s
For example, setting the PGP key from the desktop client
"""
# these attachments are updatable via c2s
2022-01-03 13:18:36 +00:00
updatable_attachments = ('PGP', 'OpenPGP', 'Email')
2021-03-17 20:18:00 +00:00
2021-12-25 23:51:19 +00:00
if not message_json.get('type'):
2021-03-17 20:18:00 +00:00
return
2021-12-25 23:51:19 +00:00
if not isinstance(message_json['type'], str):
2021-07-19 08:59:30 +00:00
if debug:
print('DEBUG: c2s actor update type is not a string')
return
2021-12-25 23:51:19 +00:00
if message_json['type'] != 'Update':
2021-03-17 20:18:00 +00:00
return
2022-04-09 15:11:22 +00:00
if not has_object_string_type(message_json, debug):
2021-03-17 20:18:00 +00:00
return
2021-12-25 23:51:19 +00:00
if not isinstance(message_json['object']['type'], str):
2021-07-19 08:59:30 +00:00
if debug:
print('DEBUG: c2s actor update object type is not a string')
return
2021-12-25 23:51:19 +00:00
if message_json['object']['type'] != 'Person':
2021-03-17 20:18:00 +00:00
if debug:
print('DEBUG: not a c2s actor update')
return
2021-12-25 23:51:19 +00:00
if not message_json.get('to'):
2021-03-17 20:18:00 +00:00
if debug:
print('DEBUG: c2s actor update has no "to" field')
return
2021-12-26 17:15:04 +00:00
if not has_actor(message_json, debug):
2021-03-17 20:18:00 +00:00
return
2021-12-25 23:51:19 +00:00
if not message_json.get('id'):
2021-03-17 20:18:00 +00:00
if debug:
print('DEBUG: c2s actor update has no id field')
return
2021-12-25 23:51:19 +00:00
if not isinstance(message_json['id'], str):
2021-07-19 08:59:30 +00:00
if debug:
print('DEBUG: c2s actor update id is not a string')
return
2021-12-26 12:45:03 +00:00
domain_full = get_full_domain(domain, port)
2021-12-26 10:19:59 +00:00
actor = local_actor_url(http_prefix, nickname, domain_full)
2023-10-16 18:30:54 +00:00
if not isinstance(message_json['to'], list):
if debug:
print('DEBUG: c2s actor update - to field is not a list ' +
str(message_json['to']))
return
2021-12-25 23:51:19 +00:00
if len(message_json['to']) != 1:
2021-03-17 20:18:00 +00:00
if debug:
print('DEBUG: c2s actor update - to does not contain one actor ' +
2021-12-25 23:51:19 +00:00
str(message_json['to']))
2021-03-17 20:18:00 +00:00
return
2021-12-25 23:51:19 +00:00
if message_json['to'][0] != actor:
2021-03-17 20:18:00 +00:00
if debug:
print('DEBUG: c2s actor update - to does not contain actor ' +
2021-12-25 23:51:19 +00:00
str(message_json['to']) + ' ' + actor)
2021-03-17 20:18:00 +00:00
return
2021-12-25 23:51:19 +00:00
if not message_json['id'].startswith(actor + '#updates/'):
2021-03-17 20:18:00 +00:00
if debug:
print('DEBUG: c2s actor update - unexpected id ' +
2021-12-25 23:51:19 +00:00
message_json['id'])
2021-03-17 20:18:00 +00:00
return
2022-01-03 13:18:36 +00:00
updated_actor_json = message_json['object']
2021-03-17 20:18:00 +00:00
# load actor from file
2022-01-03 13:18:36 +00:00
actor_filename = acct_dir(base_dir, nickname, domain) + '.json'
if not os.path.isfile(actor_filename):
print('actor_filename not found: ' + actor_filename)
2021-03-17 20:18:00 +00:00
return
2022-01-03 13:18:36 +00:00
actor_json = load_json(actor_filename)
2021-12-26 10:29:52 +00:00
if not actor_json:
2021-03-17 20:18:00 +00:00
return
2022-01-03 13:18:36 +00:00
actor_changed = False
2021-03-17 20:18:00 +00:00
# update fields within actor
2022-01-03 13:18:36 +00:00
if 'attachment' in updated_actor_json:
for new_property_value in updated_actor_json['attachment']:
2022-05-11 16:10:38 +00:00
name_value = None
if new_property_value.get('name'):
name_value = new_property_value['name']
elif new_property_value.get('schema:name'):
name_value = new_property_value['schema:name']
if not name_value:
2021-03-17 20:18:00 +00:00
continue
2022-05-11 16:10:38 +00:00
if name_value not in updatable_attachments:
2021-03-17 20:18:00 +00:00
continue
2022-01-03 13:18:36 +00:00
if not new_property_value.get('type'):
2021-03-17 20:18:00 +00:00
continue
prop_value_name, _ = \
get_attachment_property_value(new_property_value)
if not prop_value_name:
2021-03-17 20:18:00 +00:00
continue
2022-05-11 17:23:01 +00:00
if not new_property_value['type'].endswith('PropertyValue'):
2021-03-17 20:18:00 +00:00
continue
2021-12-26 10:29:52 +00:00
if 'attachment' not in actor_json:
2021-07-13 21:59:53 +00:00
continue
found = False
2022-01-08 10:58:54 +00:00
for attach_idx, _ in enumerate(actor_json['attachment']):
2022-05-11 17:23:01 +00:00
attach_type = actor_json['attachment'][attach_idx]['type']
if not attach_type.endswith('PropertyValue'):
2021-07-13 21:59:53 +00:00
continue
2022-05-11 16:10:38 +00:00
attach_name = ''
if actor_json['attachment'][attach_idx].get('name'):
attach_name = \
actor_json['attachment'][attach_idx]['name']
elif actor_json['attachment'][attach_idx].get('schema:name'):
attach_name = \
actor_json['attachment'][attach_idx]['schema:name']
if attach_name != name_value:
2021-07-13 21:59:53 +00:00
continue
if actor_json['attachment'][attach_idx][prop_value_name] != \
new_property_value[prop_value_name]:
actor_json['attachment'][attach_idx][prop_value_name] = \
new_property_value[prop_value_name]
2022-01-03 13:18:36 +00:00
actor_changed = True
found = True
break
2021-07-13 21:59:53 +00:00
if not found:
2021-12-26 10:29:52 +00:00
actor_json['attachment'].append({
2022-05-11 16:10:38 +00:00
"name": name_value,
2021-07-13 21:59:53 +00:00
"type": "PropertyValue",
"value": new_property_value[prop_value_name]
2021-07-13 21:59:53 +00:00
})
2022-01-03 13:18:36 +00:00
actor_changed = True
2021-03-17 20:18:00 +00:00
# save actor to file
2022-01-03 13:18:36 +00:00
if actor_changed:
save_json(actor_json, actor_filename)
2021-03-17 20:18:00 +00:00
if debug:
2022-01-03 13:18:36 +00:00
print('actor saved: ' + actor_filename)
2021-03-17 20:18:00 +00:00
if debug:
2021-12-26 10:29:52 +00:00
print('New attachment: ' + str(actor_json['attachment']))
message_json['object'] = actor_json
2021-03-17 20:18:00 +00:00
if debug:
print('DEBUG: actor update via c2s - ' + nickname + '@' + domain)
2022-07-18 13:59:29 +00:00
def _capitalize_hashtag(content: str, message_json: {},
system_language: str, translate: {},
original_tag: str,
capitalized_tag: str) -> None:
"""If a nowplaying hashtag exists then ensure it is capitalized
"""
if translate.get(original_tag) and \
translate.get(capitalized_tag):
2022-07-18 16:18:04 +00:00
original_tag = translate[original_tag].replace(' ', '_')
capitalized_tag = translate[capitalized_tag].replace(' ', '_')
2022-07-18 13:59:29 +00:00
if '#' + original_tag not in content:
return
content = content.replace('#' + original_tag, '#' + capitalized_tag)
2023-01-08 22:23:02 +00:00
if 'contentMap' in message_json['object']:
2022-07-18 13:59:29 +00:00
if message_json['object']['contentMap'].get(system_language):
message_json['object']['contentMap'][system_language] = content
message_json['object']['contentMap'][system_language] = content
2021-12-29 21:55:09 +00:00
def post_message_to_outbox(session, translate: {},
2021-12-31 23:07:23 +00:00
message_json: {}, post_to_nickname: str,
2021-12-29 21:55:09 +00:00
server, base_dir: str, http_prefix: str,
domain: str, domain_full: str,
onion_domain: str, i2p_domain: str, port: int,
recent_posts_cache: {}, followers_threads: [],
federation_list: [], send_threads: [],
2022-01-03 13:18:36 +00:00
post_log: [], cached_webfingers: {},
2021-12-29 21:55:09 +00:00
person_cache: {}, allow_deletion: bool,
proxy_type: str, version: str, debug: bool,
yt_replace_domain: str,
twitter_replacement_domain: str,
show_published_date_only: bool,
allow_local_network_access: bool,
city: str, system_language: str,
shared_items_federated_domains: [],
2022-01-01 15:11:42 +00:00
shared_item_federation_tokens: {},
2021-12-29 21:55:09 +00:00
low_bandwidth: bool,
signing_priv_key_pem: str,
peertube_instances: str, theme: str,
max_like_count: int,
max_recent_posts: int, cw_lists: {},
lists_enabled: str,
2022-07-05 14:40:26 +00:00
content_license_url: str,
dogwhistles: {},
2023-01-13 15:04:48 +00:00
min_images_for_accounts: [],
2023-09-15 21:04:31 +00:00
buy_sites: {},
2024-01-03 19:11:17 +00:00
sites_unavailable: [],
max_recent_books: int,
books_cache: {},
max_cached_readers: int,
2024-02-11 13:18:16 +00:00
auto_cw_cache: {},
block_federated: []) -> bool:
2020-01-13 10:35:17 +00:00
"""post is received by the outbox
Client to server message post
https://www.w3.org/TR/activitypub/#client-to-server-outbox-delivery
"""
2021-12-25 23:51:19 +00:00
if not message_json.get('type'):
2020-01-13 10:35:17 +00:00
if debug:
print('DEBUG: POST to outbox has no "type" parameter')
return False
2021-12-25 23:51:19 +00:00
if not message_json.get('object') and message_json.get('content'):
if message_json['type'] != 'Create':
2020-01-13 10:35:17 +00:00
# https://www.w3.org/TR/activitypub/#object-without-create
if debug:
print('DEBUG: POST to outbox - adding Create wrapper')
2021-12-25 23:51:19 +00:00
message_json = \
2021-12-28 19:33:29 +00:00
outbox_message_create_wrap(http_prefix,
2021-12-31 23:07:23 +00:00
post_to_nickname,
2021-12-28 19:33:29 +00:00
domain, port,
message_json)
2022-03-24 14:40:28 +00:00
bold_reading = False
if server.bold_reading.get(post_to_nickname):
bold_reading = True
# check that the outgoing post doesn't contain any markup
# which can be used to implement exploits
2021-12-26 10:57:03 +00:00
if has_object_dict(message_json):
# if this is a local only post, is it really local?
if 'localOnly' in message_json['object'] and \
2023-01-08 14:42:47 +00:00
message_json['object'].get('to') and \
message_json['object'].get('attributedTo'):
if message_json['object']['localOnly'] is True:
2023-01-08 14:42:47 +00:00
# check that the to addresses are local
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)
2023-01-15 14:33:18 +00:00
if not to_domain:
continue
2023-01-08 14:42:47 +00:00
to_domain_full = get_full_domain(to_domain, to_port)
if domain_full != to_domain_full:
print("REJECT: local only post isn't local " +
str(message_json))
return False
# check that the sender is local
local_actor = \
get_attributed_to(message_json['object']['attributedTo'])
local_domain, local_port = get_domain_from_actor(local_actor)
2023-01-15 14:33:18 +00:00
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
2023-01-03 15:43:52 +00:00
if is_quote_toot(message_json, ''):
2022-12-24 15:33:26 +00:00
print('REJECT: POST quote toot ' + str(message_json))
return False
2022-01-03 13:18:36 +00:00
content_str = get_base_content_from_post(message_json, system_language)
if content_str:
2022-07-18 13:59:29 +00:00
_capitalize_hashtag(content_str, message_json,
system_language, translate,
'nowplaying', 'NowPlaying')
if dangerous_markup(content_str, allow_local_network_access, []):
print('POST to outbox contains dangerous markup: ' +
2021-12-25 23:51:19 +00:00
str(message_json))
return False
2021-12-25 23:51:19 +00:00
if message_json['type'] == 'Create':
if not (message_json.get('id') and
message_json.get('type') and
message_json.get('actor') and
message_json.get('object') and
message_json.get('to')):
if not message_json.get('id'):
2020-01-13 12:45:27 +00:00
if debug:
2020-04-03 17:15:33 +00:00
print('DEBUG: POST to outbox - ' +
'Create does not have the id parameter ' +
2021-12-25 23:51:19 +00:00
str(message_json))
elif not message_json.get('id'):
2020-01-13 12:45:27 +00:00
if debug:
2020-04-03 17:15:33 +00:00
print('DEBUG: POST to outbox - ' +
'Create does not have the type parameter ' +
2021-12-25 23:51:19 +00:00
str(message_json))
elif not message_json.get('id'):
2020-01-13 12:45:27 +00:00
if debug:
2020-04-03 17:15:33 +00:00
print('DEBUG: POST to outbox - ' +
'Create does not have the actor parameter ' +
2021-12-25 23:51:19 +00:00
str(message_json))
elif not message_json.get('id'):
2020-01-13 12:45:27 +00:00
if debug:
2020-04-03 17:15:33 +00:00
print('DEBUG: POST to outbox - ' +
'Create does not have the object parameter ' +
2021-12-25 23:51:19 +00:00
str(message_json))
2020-01-13 12:45:27 +00:00
else:
if debug:
2020-04-03 17:15:33 +00:00
print('DEBUG: POST to outbox - ' +
'Create does not have the "to" parameter ' +
2021-12-25 23:51:19 +00:00
str(message_json))
2020-01-13 10:35:17 +00:00
return False
2021-02-15 10:06:49 +00:00
# actor should be a string
2024-01-09 16:59:23 +00:00
actor_url = get_actor_from_post(message_json)
if not actor_url:
2021-02-15 10:06:49 +00:00
return False
# actor should look like a url
2024-01-09 16:59:23 +00:00
if '://' not in actor_url or \
'.' not in actor_url:
2021-02-15 10:06:49 +00:00
return False
2024-01-09 16:59:23 +00:00
if contains_invalid_actor_url_chars(actor_url):
2022-12-26 11:25:51 +00:00
return False
2021-02-15 10:06:49 +00:00
# sent by an actor on a local network address?
2021-12-25 18:54:50 +00:00
if not allow_local_network_access:
2022-01-03 13:18:36 +00:00
local_network_pattern_list = get_local_network_addresses()
for local_network_pattern in local_network_pattern_list:
2024-01-09 16:59:23 +00:00
if local_network_pattern in actor_url:
2021-02-15 10:06:49 +00:00
return False
2024-01-09 16:59:23 +00:00
test_domain, test_port = get_domain_from_actor(actor_url)
2023-01-15 14:33:18 +00:00
if test_domain:
test_domain = get_full_domain(test_domain, test_port)
2024-02-11 13:42:15 +00:00
if is_blocked_domain(base_dir, test_domain, None, None):
2023-01-15 14:33:18 +00:00
if debug:
2024-01-09 16:59:23 +00:00
print('DEBUG: domain is blocked: ' + actor_url)
2023-01-15 14:33:18 +00:00
return False
2020-01-15 11:06:40 +00:00
# replace youtube, so that google gets less tracking data
2021-12-28 21:36:27 +00:00
replace_you_tube(message_json, yt_replace_domain, system_language)
2021-09-18 17:08:14 +00:00
# replace twitter, so that twitter posts can be shown without
# having a twitter account
2021-12-28 21:36:27 +00:00
replace_twitter(message_json, twitter_replacement_domain,
system_language)
2020-01-13 10:35:17 +00:00
# https://www.w3.org/TR/activitypub/#create-activity-outbox
2024-01-09 16:59:23 +00:00
message_json['object']['attributedTo'] = actor_url
message_attachments = get_post_attachments(message_json['object'])
if message_attachments:
2022-01-03 13:18:36 +00:00
attachment_index = 0
attach = message_attachments[attachment_index]
2020-04-03 17:15:33 +00:00
if attach.get('mediaType'):
2022-01-03 13:18:36 +00:00
file_extension = 'png'
media_type_str = \
2020-04-03 17:15:33 +00:00
attach['mediaType']
2020-11-28 20:52:13 +00:00
extensions = {
"jpeg": "jpg",
2022-02-06 11:04:49 +00:00
"jxl": "jxl",
2020-11-28 20:52:13 +00:00
"gif": "gif",
2021-01-11 22:27:57 +00:00
"svg": "svg",
2020-11-28 20:52:13 +00:00
"webp": "webp",
"avif": "avif",
2022-10-31 17:26:31 +00:00
"heic": "heic",
2020-11-28 20:52:13 +00:00
"audio/mpeg": "mp3",
"ogg": "ogg",
2022-10-31 11:05:11 +00:00
"audio/wav": "wav",
"audio/x-wav": "wav",
"audio/x-pn-wave": "wav",
"audio/vnd.wave": "wav",
2022-04-18 13:44:08 +00:00
"flac": "flac",
2022-04-18 13:21:45 +00:00
"opus": "opus",
2022-10-20 19:37:59 +00:00
"audio/speex": "spx",
"audio/x-speex": "spx",
2020-11-28 20:52:13 +00:00
"mp4": "mp4",
"webm": "webm",
"ogv": "ogv"
}
2022-01-03 13:18:36 +00:00
for match_ext, ext in extensions.items():
if media_type_str.endswith(match_ext):
file_extension = ext
2020-11-28 20:52:13 +00:00
break
2022-01-03 13:18:36 +00:00
media_dir = \
2021-12-25 16:17:53 +00:00
base_dir + '/accounts/' + \
2021-12-31 23:07:23 +00:00
post_to_nickname + '@' + domain
2022-01-03 13:18:36 +00:00
upload_media_filename = media_dir + '/upload.' + file_extension
if not os.path.isfile(upload_media_filename):
2021-12-25 23:51:19 +00:00
del message_json['object']['attachment']
2020-01-13 10:35:17 +00:00
else:
# generate a path for the uploaded image
2022-01-03 13:18:36 +00:00
mpath = get_media_path()
media_path = mpath + '/' + \
create_password(16).lower() + '.' + file_extension
create_media_dirs(base_dir, mpath)
media_filename = base_dir + '/' + media_path
2020-01-13 10:35:17 +00:00
# move the uploaded image to its new path
2022-01-03 13:18:36 +00:00
os.rename(upload_media_filename, media_filename)
# convert dictionary to list if needed
if isinstance(message_json['object']['attachment'], dict):
message_json['object']['attachment'] = \
[message_json['object']['attachment']]
attach_idx = attachment_index
attach = \
message_json['object']['attachment'][attach_idx]
2020-01-13 10:35:17 +00:00
# change the url of the attachment
2020-04-03 17:15:33 +00:00
attach['url'] = \
2022-01-03 13:18:36 +00:00
http_prefix + '://' + domain_full + '/' + media_path
2021-10-12 18:20:40 +00:00
attach['url'] = \
attach['url'].replace('/media/',
'/system/' +
'media_attachments/files/')
2020-01-13 10:35:17 +00:00
2022-01-03 13:18:36 +00:00
permitted_outbox_types = (
2021-11-10 12:16:03 +00:00
'Create', 'Announce', 'Like', 'EmojiReact', 'Follow', 'Undo',
2023-09-23 14:42:04 +00:00
'Update', 'Add', 'Remove', 'Block', 'Delete', 'Skill', 'Ignore',
2024-01-01 10:43:20 +00:00
'Move', 'Edition'
2021-11-10 12:16:03 +00:00
)
2022-01-03 13:18:36 +00:00
if message_json['type'] not in permitted_outbox_types:
2020-01-13 10:35:17 +00:00
if debug:
2021-12-25 23:51:19 +00:00
print('DEBUG: POST to outbox - ' + message_json['type'] +
2020-01-13 10:35:17 +00:00
' is not a permitted activity type')
return False
2021-12-25 23:51:19 +00:00
if message_json.get('id'):
2021-12-27 11:20:57 +00:00
post_id = remove_id_ending(message_json['id'])
2020-01-13 10:35:17 +00:00
if debug:
print('DEBUG: id attribute exists within POST to outbox')
else:
if debug:
print('DEBUG: No id attribute within POST to outbox')
2021-12-26 19:47:06 +00:00
post_id = None
2020-01-13 10:35:17 +00:00
if debug:
2021-12-28 18:13:52 +00:00
print('DEBUG: save_post_to_box')
2022-11-17 19:52:20 +00:00
2022-11-17 20:10:30 +00:00
is_edited_post = False
if message_json['type'] == 'Update' and \
2024-01-09 10:41:19 +00:00
message_json['object']['type'] in ('Note', 'Event'):
2022-11-17 20:10:30 +00:00
is_edited_post = True
message_json['type'] = 'Create'
2022-11-17 20:10:30 +00:00
outbox_name = 'outbox'
2022-11-17 20:10:30 +00:00
store_hash_tags(base_dir, post_to_nickname, domain,
http_prefix, domain_full,
message_json, translate)
2022-11-17 20:10:30 +00:00
# if this is a blog post or an event then save to its own box
if message_json['type'] == 'Create':
if has_object_dict(message_json):
if message_json['object'].get('type'):
if message_json['object']['type'] == 'Article':
outbox_name = 'tlblogs'
saved_filename = \
save_post_to_box(base_dir,
http_prefix,
post_id,
post_to_nickname, domain_full,
message_json, outbox_name)
if not saved_filename:
print('WARN: post not saved to outbox ' + outbox_name)
return False
2024-01-09 16:59:23 +00:00
actor_url = get_actor_from_post(message_json)
2022-11-17 20:10:30 +00:00
update_speaker(base_dir, http_prefix,
post_to_nickname, domain, domain_full,
message_json, person_cache,
2024-01-09 16:59:23 +00:00
translate, actor_url,
2022-11-17 20:10:30 +00:00
theme, system_language,
outbox_name)
2024-01-04 18:53:34 +00:00
if has_edition_tag(message_json):
store_book_events(base_dir,
message_json,
system_language, [],
translate, debug,
max_recent_books,
books_cache,
max_cached_readers)
2024-01-03 19:11:17 +00:00
2022-11-17 20:10:30 +00:00
# save all instance blogs to the news actor
if post_to_nickname != 'news' and outbox_name == 'tlblogs':
if '/' in saved_filename:
if is_featured_writer(base_dir, post_to_nickname, domain):
saved_post_id = saved_filename.split('/')[-1]
blogs_dir = \
base_dir + '/accounts/news@' + domain + '/tlblogs'
if not os.path.isdir(blogs_dir):
os.mkdir(blogs_dir)
copyfile(saved_filename, blogs_dir + '/' + saved_post_id)
inbox_update_index('tlblogs', base_dir,
'news@' + domain,
saved_filename, debug)
# clear the citations file if it exists
citations_filename = \
base_dir + '/accounts/' + \
post_to_nickname + '@' + domain + '/.citations.txt'
if os.path.isfile(citations_filename):
try:
os.remove(citations_filename)
except OSError:
print('EX: post_message_to_outbox unable to delete ' +
citations_filename)
# The following activity types get added to the index files
indexed_activities = (
2024-01-09 10:41:19 +00:00
'Create', 'Question', 'Note', 'Event', 'EncryptedMessage', 'Article',
2022-11-17 20:10:30 +00:00
'Patch', 'Announce', 'ChatMessage'
)
if message_json['type'] in indexed_activities:
indexes = [outbox_name, "inbox"]
self_actor = \
local_actor_url(http_prefix, post_to_nickname, domain_full)
for box_name_index in indexes:
if not box_name_index:
continue
2021-06-22 20:30:27 +00:00
2022-11-17 20:10:30 +00:00
# should this also go to the media timeline?
if box_name_index == 'inbox':
show_vote_posts = True
show_vote_file = \
acct_dir(base_dir, post_to_nickname, domain) + '/.noVotes'
if os.path.isfile(show_vote_file):
show_vote_posts = False
languages_understood = []
2022-11-17 20:10:30 +00:00
if is_image_media(session, base_dir, http_prefix,
post_to_nickname, domain,
message_json,
yt_replace_domain,
twitter_replacement_domain,
allow_local_network_access,
recent_posts_cache, debug,
system_language,
domain_full, person_cache,
signing_priv_key_pem,
bold_reading,
show_vote_posts,
languages_understood):
2022-11-17 20:10:30 +00:00
inbox_update_index('tlmedia', base_dir,
2021-12-31 23:07:23 +00:00
post_to_nickname + '@' + domain,
2022-01-03 13:18:36 +00:00
saved_filename, debug)
2022-11-17 20:10:30 +00:00
if box_name_index == 'inbox' and outbox_name == 'tlblogs':
continue
# avoid duplicates of the message if already going
# back to the inbox of the same account
if self_actor not in message_json['to']:
# show sent post within the inbox,
# as is the typical convention
inbox_update_index(box_name_index, base_dir,
post_to_nickname + '@' + domain,
saved_filename, debug)
# regenerate the html
use_cache_only = False
page_number = 1
show_individual_post_icons = True
manually_approve_followers = \
follower_approval_active(base_dir,
2022-02-25 19:12:40 +00:00
post_to_nickname, domain)
2022-11-17 20:10:30 +00:00
timezone = \
get_account_timezone(base_dir,
post_to_nickname, domain)
mitm = False
if os.path.isfile(saved_filename.replace('.json', '') +
'.mitm'):
mitm = True
minimize_all_images = False
if post_to_nickname in min_images_for_accounts:
minimize_all_images = True
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,
post_to_nickname, domain, port,
message_json, None, True,
allow_deletion,
http_prefix, __version__,
box_name_index,
yt_replace_domain,
twitter_replacement_domain,
show_published_date_only,
peertube_instances,
allow_local_network_access,
theme, system_language,
max_like_count,
box_name_index != 'dm',
show_individual_post_icons,
manually_approve_followers,
False, True, use_cache_only,
cw_lists, lists_enabled,
timezone, mitm,
bold_reading, dogwhistles,
2023-01-13 15:04:48 +00:00
minimize_all_images, None,
buy_sites, auto_cw_cache)
2022-11-17 20:10:30 +00:00
if is_edited_post:
message_json['type'] = 'Update'
2021-12-29 21:55:09 +00:00
if outbox_announce(recent_posts_cache,
base_dir, message_json, debug):
2020-01-13 10:35:17 +00:00
if debug:
2020-04-03 17:15:33 +00:00
print('DEBUG: Updated announcements (shares) collection ' +
'for the post associated with the Announce activity')
2020-01-13 10:35:17 +00:00
if debug:
print('DEBUG: sending c2s post to followers')
# remove inactive threads
2022-01-03 13:18:36 +00:00
inactive_follower_threads = []
for thr in followers_threads:
if not thr.is_alive():
inactive_follower_threads.append(thr)
for thr in inactive_follower_threads:
followers_threads.remove(thr)
2020-01-13 10:35:17 +00:00
if debug:
2021-12-25 22:48:08 +00:00
print('DEBUG: ' + str(len(followers_threads)) +
2020-04-03 17:15:33 +00:00
' followers threads active')
2020-01-20 12:43:34 +00:00
# retain up to 200 threads
2021-12-25 22:48:08 +00:00
if len(followers_threads) > 200:
2020-01-13 10:35:17 +00:00
# kill the thread if it is still alive
2021-12-25 22:48:08 +00:00
if followers_threads[0].is_alive():
followers_threads[0].kill()
2020-01-13 10:35:17 +00:00
# remove it from the list
2021-12-25 22:48:08 +00:00
followers_threads.pop(0)
2020-01-13 10:35:17 +00:00
# create a thread to send the post to followers
2022-01-03 13:18:36 +00:00
followers_thread = \
2022-03-14 13:29:41 +00:00
send_to_followers_thread(server, server.session,
server.session_onion,
server.session_i2p,
2021-12-29 21:55:09 +00:00
base_dir,
2021-12-31 23:07:23 +00:00
post_to_nickname,
2021-12-29 21:55:09 +00:00
domain, onion_domain, i2p_domain,
port, http_prefix,
federation_list,
send_threads,
2022-01-03 13:18:36 +00:00
post_log,
2021-12-29 21:55:09 +00:00
cached_webfingers,
person_cache,
message_json, debug,
version,
shared_items_federated_domains,
2022-01-01 15:11:42 +00:00
shared_item_federation_tokens,
2023-09-15 21:04:31 +00:00
signing_priv_key_pem,
2023-10-25 19:55:40 +00:00
sites_unavailable,
system_language)
2022-01-03 13:18:36 +00:00
followers_threads.append(followers_thread)
2020-02-04 20:11:19 +00:00
2020-01-13 10:35:17 +00:00
if debug:
print('DEBUG: handle any unfollow requests')
2021-12-29 21:55:09 +00:00
outbox_undo_follow(base_dir, message_json, debug)
2020-02-04 20:11:19 +00:00
2020-01-13 10:35:17 +00:00
if debug:
print('DEBUG: handle skills changes requests')
2021-12-31 23:07:23 +00:00
outbox_skills(base_dir, post_to_nickname, message_json, debug)
2020-02-04 20:11:19 +00:00
2020-01-13 10:35:17 +00:00
if debug:
print('DEBUG: handle availability changes requests')
2021-12-31 23:07:23 +00:00
outbox_availability(base_dir, post_to_nickname, message_json, debug)
2020-01-13 10:35:17 +00:00
if debug:
print('DEBUG: handle any like requests')
2021-12-29 21:55:09 +00:00
outbox_like(recent_posts_cache,
base_dir, post_to_nickname, domain,
2021-12-29 21:55:09 +00:00
message_json, debug)
2020-01-13 10:35:17 +00:00
if debug:
print('DEBUG: handle any undo like requests')
2021-12-29 21:55:09 +00:00
outbox_undo_like(recent_posts_cache,
2022-06-14 10:51:40 +00:00
base_dir, post_to_nickname, domain,
2021-12-29 21:55:09 +00:00
message_json, debug)
2021-11-10 12:16:03 +00:00
if debug:
print('DEBUG: handle any emoji reaction requests')
2021-12-29 21:55:09 +00:00
outbox_reaction(recent_posts_cache,
2022-06-12 21:31:53 +00:00
base_dir, post_to_nickname, domain,
2021-12-29 21:55:09 +00:00
message_json, debug)
2021-11-10 12:16:03 +00:00
if debug:
print('DEBUG: handle any undo emoji reaction requests')
2021-12-29 21:55:09 +00:00
outbox_undo_reaction(recent_posts_cache,
2022-06-12 21:31:53 +00:00
base_dir, post_to_nickname, domain,
2021-12-29 21:55:09 +00:00
message_json, debug)
2021-11-10 12:16:03 +00:00
if debug:
print('DEBUG: handle any undo announce requests')
2021-12-29 21:55:09 +00:00
outbox_undo_announce(recent_posts_cache,
2022-06-09 16:05:42 +00:00
base_dir, post_to_nickname, domain,
2021-12-29 21:55:09 +00:00
message_json, debug)
2020-01-13 10:35:17 +00:00
if debug:
print('DEBUG: handle any bookmark requests')
2021-12-29 21:55:09 +00:00
outbox_bookmark(recent_posts_cache,
base_dir, http_prefix,
2021-12-31 23:07:23 +00:00
post_to_nickname, domain, port,
2021-12-29 21:55:09 +00:00
message_json, debug)
2020-01-13 10:35:17 +00:00
if debug:
print('DEBUG: handle any undo bookmark requests')
2021-12-29 21:55:09 +00:00
outbox_undo_bookmark(recent_posts_cache,
base_dir, http_prefix,
2021-12-31 23:07:23 +00:00
post_to_nickname, domain, port,
2021-12-29 21:55:09 +00:00
message_json, debug)
2020-01-13 10:35:17 +00:00
if debug:
2020-03-22 21:16:02 +00:00
print('DEBUG: handle delete requests')
2021-12-29 21:55:09 +00:00
outbox_delete(base_dir, http_prefix,
2021-12-31 23:07:23 +00:00
post_to_nickname, domain,
2021-12-29 21:55:09 +00:00
message_json, debug,
allow_deletion,
recent_posts_cache)
2020-02-04 20:11:19 +00:00
2020-01-13 10:35:17 +00:00
if debug:
print('DEBUG: handle block requests')
2022-06-09 16:13:16 +00:00
outbox_block(base_dir, post_to_nickname, domain,
2021-12-29 21:55:09 +00:00
message_json, debug)
2020-02-04 20:11:19 +00:00
2020-01-13 10:35:17 +00:00
if debug:
print('DEBUG: handle undo block requests')
outbox_undo_block(base_dir, post_to_nickname, domain, message_json, debug)
2020-02-04 20:11:19 +00:00
2021-03-20 21:20:41 +00:00
if debug:
print('DEBUG: handle mute requests')
2021-12-29 21:55:09 +00:00
outbox_mute(base_dir, http_prefix,
2021-12-31 23:07:23 +00:00
post_to_nickname, domain,
2021-12-29 21:55:09 +00:00
port,
message_json, debug,
recent_posts_cache)
2021-03-20 21:20:41 +00:00
if debug:
print('DEBUG: handle undo mute requests')
2021-12-29 21:55:09 +00:00
outbox_undo_mute(base_dir, http_prefix,
2021-12-31 23:07:23 +00:00
post_to_nickname, domain,
2021-12-29 21:55:09 +00:00
port,
message_json, debug,
recent_posts_cache)
2021-03-20 21:20:41 +00:00
2020-01-13 10:35:17 +00:00
if debug:
print('DEBUG: handle share uploads')
2021-12-31 23:07:23 +00:00
outbox_share_upload(base_dir, http_prefix, post_to_nickname, domain,
2021-12-29 21:55:09 +00:00
port, message_json, debug, city,
system_language, translate, low_bandwidth,
2024-02-11 13:18:16 +00:00
content_license_url, block_federated)
2020-02-04 20:11:19 +00:00
2020-01-13 10:35:17 +00:00
if debug:
print('DEBUG: handle undo share uploads')
2022-06-12 22:14:47 +00:00
outbox_undo_share_upload(base_dir, post_to_nickname, domain,
message_json, debug)
2020-02-04 20:11:19 +00:00
2021-03-17 20:18:00 +00:00
if debug:
print('DEBUG: handle actor updates from c2s')
2022-06-12 21:31:53 +00:00
_person_receive_update_outbox(base_dir, http_prefix,
2021-12-31 23:07:23 +00:00
post_to_nickname, domain, port,
2021-12-29 21:55:09 +00:00
message_json, debug)
2021-03-17 20:18:00 +00:00
2020-01-13 10:35:17 +00:00
if debug:
print('DEBUG: sending c2s post to named addresses')
2021-12-25 23:51:19 +00:00
if message_json.get('to'):
2020-04-03 17:15:33 +00:00
print('c2s sender: ' +
2021-12-31 23:07:23 +00:00
post_to_nickname + '@' + domain + ':' + str(port) +
2021-12-25 23:51:19 +00:00
' recipient: ' + str(message_json['to']))
2020-02-04 20:11:19 +00:00
else:
2020-04-03 17:15:33 +00:00
print('c2s sender: ' +
2021-12-31 23:07:23 +00:00
post_to_nickname + '@' + domain + ':' + str(port))
2022-01-03 13:18:36 +00:00
named_addresses_thread = \
2022-03-14 13:29:41 +00:00
send_to_named_addresses_thread(server, server.session,
server.session_onion,
server.session_i2p,
base_dir, post_to_nickname,
2021-12-29 21:55:09 +00:00
domain, onion_domain, i2p_domain, port,
http_prefix,
federation_list,
send_threads,
2022-01-03 13:18:36 +00:00
post_log,
2021-12-29 21:55:09 +00:00
cached_webfingers,
person_cache,
message_json, debug,
version,
shared_items_federated_domains,
2022-01-01 15:11:42 +00:00
shared_item_federation_tokens,
signing_priv_key_pem,
2023-03-17 21:13:43 +00:00
proxy_type,
2023-09-15 21:04:31 +00:00
server.followers_sync_cache,
2023-10-25 19:55:40 +00:00
server.sites_unavailable,
server.system_language)
2022-01-03 13:18:36 +00:00
followers_threads.append(named_addresses_thread)
2020-01-13 10:35:17 +00:00
return True