Move c2s functions to a separate module

main
Bob Mottram 2025-05-31 13:35:59 +01:00
parent af7860bf14
commit 8bc9d2b359
5 changed files with 767 additions and 749 deletions

View File

@ -50,11 +50,11 @@ from follow import get_following_via_server
from follow import get_followers_via_server
from follow import send_follow_request_via_server
from follow import send_unfollow_request_via_server
from posts import send_block_via_server
from posts import send_undo_block_via_server
from posts import send_mute_via_server
from posts import send_undo_mute_via_server
from posts import send_post_via_server
from sendC2S import send_post_via_server
from sendC2S import send_block_via_server
from sendC2S import send_undo_block_via_server
from sendC2S import send_mute_via_server
from sendC2S import send_undo_mute_via_server
from posts import c2s_box_json
from posts import download_announce
from announce import send_announce_via_server

View File

@ -28,21 +28,21 @@ from bookmarks import send_bookmark_via_server
from bookmarks import send_undo_bookmark_via_server
from conversation import download_conversation_posts
from keys import get_instance_actor_key
from sendC2S import send_post_via_server
from sendC2S import send_block_via_server
from sendC2S import send_mute_via_server
from sendC2S import send_undo_mute_via_server
from sendC2S import send_undo_block_via_server
from posts import novel_fields
from posts import set_post_expiry_days
from posts import send_mute_via_server
from posts import send_undo_mute_via_server
from posts import c2s_box_json
from posts import download_follow_collection
from posts import get_public_post_domains
from posts import get_public_post_domains_blocked
from posts import send_block_via_server
from posts import send_undo_block_via_server
from posts import create_public_post
from posts import delete_all_posts
from posts import expire_posts
from posts import archive_posts
from posts import send_post_via_server
from posts import get_public_posts_of_person
from posts import get_user_url
from posts import check_domains

931
posts.py
View File

@ -26,9 +26,7 @@ from cache import expire_person_cache
from pprint import pprint
from session import create_session
from session import get_json
from session import post_json
from session import post_json_string
from session import post_image
from session import get_json_valid
from webfinger import webfinger_handle
from httpsig import create_signed_header
@ -1775,39 +1773,39 @@ def get_actor_from_in_reply_to(in_reply_to: str) -> str:
return reply_actor
def _create_post_base(base_dir: str,
nickname: str, domain: str, port: int,
to_url: str, cc_url: str, http_prefix: str, content: str,
save_to_file: bool,
client_to_server: bool, comments_enabled: bool,
attach_image_filename: str,
media_type: str, image_description: str,
video_transcript: str, city: str,
is_moderation_report: bool,
is_article: bool,
in_reply_to: str,
in_reply_to_atom_uri: str,
subject: str, schedule_post: bool,
event_date: str, event_time: str,
location: str,
event_uuid: str, category: str,
join_mode: str,
end_date: str, end_time: str,
event_category: str,
maximum_attendee_capacity: int,
replies_moderation_option: str,
anonymous_participation_enabled: bool,
event_status: str, ticket_url: str,
system_language: str,
conversation_id: str, convthread_id: str,
low_bandwidth: bool, content_license_url: str,
media_license_url: str, media_creator: str,
languages_understood: [], translate: {},
buy_url: str, chat_url: str,
auto_cw_cache: {},
searchable_by: [],
session,
automatic_quote_approval: str) -> {}:
def create_post_base(base_dir: str,
nickname: str, domain: str, port: int,
to_url: str, cc_url: str, http_prefix: str, content: str,
save_to_file: bool,
client_to_server: bool, comments_enabled: bool,
attach_image_filename: str,
media_type: str, image_description: str,
video_transcript: str, city: str,
is_moderation_report: bool,
is_article: bool,
in_reply_to: str,
in_reply_to_atom_uri: str,
subject: str, schedule_post: bool,
event_date: str, event_time: str,
location: str,
event_uuid: str, category: str,
join_mode: str,
end_date: str, end_time: str,
event_category: str,
maximum_attendee_capacity: int,
replies_moderation_option: str,
anonymous_participation_enabled: bool,
event_status: str, ticket_url: str,
system_language: str,
conversation_id: str, convthread_id: str,
low_bandwidth: bool, content_license_url: str,
media_license_url: str, media_creator: str,
languages_understood: [], translate: {},
buy_url: str, chat_url: str,
auto_cw_cache: {},
searchable_by: [],
session,
automatic_quote_approval: str) -> {}:
"""Creates a message
"""
content = remove_invalid_chars(content)
@ -2288,28 +2286,28 @@ def create_public_post(base_dir: str,
local_actor = local_actor_url(http_prefix, nickname, domain_full)
automatic_quote_approval = "https://www.w3.org/ns/activitystreams#Public"
return _create_post_base(base_dir, nickname, domain, port,
'https://www.w3.org/ns/activitystreams#Public',
local_actor + '/followers',
http_prefix, content, save_to_file,
client_to_server, comments_enabled,
attach_image_filename, media_type,
image_description, video_transcript, city,
is_moderation_report, is_article,
in_reply_to, in_reply_to_atom_uri, subject,
schedule_post, event_date, event_time, location,
event_uuid, category, join_mode,
end_date, end_time, event_category,
maximum_attendee_capacity,
replies_moderation_option,
anonymous_participation_enabled,
event_status, ticket_url, system_language,
conversation_id, convthread_id, low_bandwidth,
content_license_url,
media_license_url, media_creator,
languages_understood, translate, buy_url,
chat_url, auto_cw_cache, searchable_by,
session, automatic_quote_approval)
return create_post_base(base_dir, nickname, domain, port,
'https://www.w3.org/ns/activitystreams#Public',
local_actor + '/followers',
http_prefix, content, save_to_file,
client_to_server, comments_enabled,
attach_image_filename, media_type,
image_description, video_transcript, city,
is_moderation_report, is_article,
in_reply_to, in_reply_to_atom_uri, subject,
schedule_post, event_date, event_time, location,
event_uuid, category, join_mode,
end_date, end_time, event_category,
maximum_attendee_capacity,
replies_moderation_option,
anonymous_participation_enabled,
event_status, ticket_url, system_language,
conversation_id, convthread_id, low_bandwidth,
content_license_url,
media_license_url, media_creator,
languages_understood, translate, buy_url,
chat_url, auto_cw_cache, searchable_by,
session, automatic_quote_approval)
def create_reading_post(base_dir: str,
@ -2540,28 +2538,28 @@ def create_question_post(base_dir: str,
searchable_by: list[str] = []
automatic_quote_approval = local_actor
message_json = \
_create_post_base(base_dir, nickname, domain, port,
'https://www.w3.org/ns/activitystreams#Public',
local_actor + '/followers',
http_prefix, content, save_to_file,
client_to_server, comments_enabled,
attach_image_filename, media_type,
image_description, video_transcript, city,
is_moderation_report, is_article,
in_reply_to, in_reply_to_atom_uri, subject,
schedule_post, event_date, event_time,
location, event_uuid, category,
join_mode, end_date, end_time, event_category,
maximum_attendee_capacity,
replies_moderation_option,
anonymous_participation_enabled, event_status,
ticket_url, system_language,
conversation_id, convthread_id, low_bandwidth,
content_license_url,
media_license_url, media_creator,
languages_understood, translate, buy_url,
chat_url, auto_cw_cache, searchable_by,
session, automatic_quote_approval)
create_post_base(base_dir, nickname, domain, port,
'https://www.w3.org/ns/activitystreams#Public',
local_actor + '/followers',
http_prefix, content, save_to_file,
client_to_server, comments_enabled,
attach_image_filename, media_type,
image_description, video_transcript, city,
is_moderation_report, is_article,
in_reply_to, in_reply_to_atom_uri, subject,
schedule_post, event_date, event_time,
location, event_uuid, category,
join_mode, end_date, end_time, event_category,
maximum_attendee_capacity,
replies_moderation_option,
anonymous_participation_enabled, event_status,
ticket_url, system_language,
conversation_id, convthread_id, low_bandwidth,
content_license_url,
media_license_url, media_creator,
languages_understood, translate, buy_url,
chat_url, auto_cw_cache, searchable_by,
session, automatic_quote_approval)
message_json['object']['type'] = 'Question'
message_json['object']['oneOf']: list[dict] = []
message_json['object']['votersCount'] = 0
@ -2616,32 +2614,32 @@ def create_unlisted_post(base_dir: str,
ticket_url = None
searchable_by: list[str] = []
automatic_quote_approval = local_actor
return _create_post_base(base_dir, nickname, domain, port,
local_actor + '/followers',
'https://www.w3.org/ns/activitystreams#Public',
http_prefix, content, save_to_file,
client_to_server, comments_enabled,
attach_image_filename, media_type,
image_description, video_transcript, city,
is_moderation_report, is_article,
in_reply_to, in_reply_to_atom_uri, subject,
schedule_post, event_date,
event_time, location,
event_uuid, category, join_mode,
event_date, event_end_time,
event_category,
maximum_attendee_capacity,
replies_moderation_option,
anonymous_participation_enabled,
event_status,
ticket_url, system_language,
conversation_id, convthread_id, low_bandwidth,
content_license_url,
media_license_url, media_creator,
languages_understood, translate,
buy_url, chat_url, auto_cw_cache,
searchable_by, session,
automatic_quote_approval)
return create_post_base(base_dir, nickname, domain, port,
local_actor + '/followers',
'https://www.w3.org/ns/activitystreams#Public',
http_prefix, content, save_to_file,
client_to_server, comments_enabled,
attach_image_filename, media_type,
image_description, video_transcript, city,
is_moderation_report, is_article,
in_reply_to, in_reply_to_atom_uri, subject,
schedule_post, event_date,
event_time, location,
event_uuid, category, join_mode,
event_date, event_end_time,
event_category,
maximum_attendee_capacity,
replies_moderation_option,
anonymous_participation_enabled,
event_status,
ticket_url, system_language,
conversation_id, convthread_id, low_bandwidth,
content_license_url,
media_license_url, media_creator,
languages_understood, translate,
buy_url, chat_url, auto_cw_cache,
searchable_by, session,
automatic_quote_approval)
def create_followers_only_post(base_dir: str,
@ -2679,28 +2677,28 @@ def create_followers_only_post(base_dir: str,
event_status = None
ticket_url = None
automatic_quote_approval = local_actor + '/following'
return _create_post_base(base_dir, nickname, domain, port,
local_actor + '/followers', None,
http_prefix, content, save_to_file,
client_to_server, comments_enabled,
attach_image_filename, media_type,
image_description, video_transcript, city,
is_moderation_report, is_article,
in_reply_to, in_reply_to_atom_uri, subject,
schedule_post, event_date, event_time, location,
event_uuid, category, join_mode,
event_date, event_end_time, event_category,
maximum_attendee_capacity,
replies_moderation_option,
anonymous_participation_enabled,
event_status, ticket_url, system_language,
conversation_id, convthread_id, low_bandwidth,
content_license_url,
media_license_url, media_creator,
languages_understood, translate,
buy_url, chat_url, auto_cw_cache,
searchable_by, session,
automatic_quote_approval)
return create_post_base(base_dir, nickname, domain, port,
local_actor + '/followers', None,
http_prefix, content, save_to_file,
client_to_server, comments_enabled,
attach_image_filename, media_type,
image_description, video_transcript, city,
is_moderation_report, is_article,
in_reply_to, in_reply_to_atom_uri, subject,
schedule_post, event_date, event_time, location,
event_uuid, category, join_mode,
event_date, event_end_time, event_category,
maximum_attendee_capacity,
replies_moderation_option,
anonymous_participation_enabled,
event_status, ticket_url, system_language,
conversation_id, convthread_id, low_bandwidth,
content_license_url,
media_license_url, media_creator,
languages_understood, translate,
buy_url, chat_url, auto_cw_cache,
searchable_by, session,
automatic_quote_approval)
def get_mentioned_people(base_dir: str, http_prefix: str,
@ -2785,27 +2783,27 @@ def create_direct_message_post(base_dir: str,
searchable_by: list[str] = []
automatic_quote_approval = local_actor
message_json = \
_create_post_base(base_dir, nickname, domain, port,
post_to, post_cc,
http_prefix, content, save_to_file,
client_to_server, comments_enabled,
attach_image_filename, media_type,
image_description, video_transcript, city,
is_moderation_report, is_article,
in_reply_to, in_reply_to_atom_uri, subject,
schedule_post, event_date, event_time, location,
event_uuid, category, join_mode,
event_date, event_end_time, event_category,
maximum_attendee_capacity,
replies_moderation_option,
anonymous_participation_enabled,
event_status, ticket_url, system_language,
conversation_id, convthread_id, low_bandwidth,
content_license_url,
media_license_url, media_creator,
languages_understood, translate, buy_url, chat_url,
auto_cw_cache, searchable_by, session,
automatic_quote_approval)
create_post_base(base_dir, nickname, domain, port,
post_to, post_cc,
http_prefix, content, save_to_file,
client_to_server, comments_enabled,
attach_image_filename, media_type,
image_description, video_transcript, city,
is_moderation_report, is_article,
in_reply_to, in_reply_to_atom_uri, subject,
schedule_post, event_date, event_time, location,
event_uuid, category, join_mode,
event_date, event_end_time, event_category,
maximum_attendee_capacity,
replies_moderation_option,
anonymous_participation_enabled,
event_status, ticket_url, system_language,
conversation_id, convthread_id, low_bandwidth,
content_license_url,
media_license_url, media_creator,
languages_understood, translate, buy_url, chat_url,
auto_cw_cache, searchable_by, session,
automatic_quote_approval)
# mentioned recipients go into To rather than Cc
message_json['to'] = message_json['object']['cc']
if not isinstance(message_json['to'], list):
@ -2928,29 +2926,29 @@ def create_report_post(base_dir: str,
to_nickname = to_url.split('/users/')[1]
handle = to_nickname + '@' + domain
post_json_object = \
_create_post_base(base_dir, nickname, domain, port,
to_url, post_cc,
http_prefix, content, save_to_file,
client_to_server, comments_enabled,
attach_image_filename, media_type,
image_description, video_transcript, city,
is_moderation_report, is_article,
in_reply_to, in_reply_to_atom_uri, subject,
schedule_post, event_date, event_time,
location, event_uuid, category,
join_mode, end_date, end_time,
event_category,
maximum_attendee_capacity,
replies_moderation_option,
anonymous_participation_enabled,
event_status, ticket_url, system_language,
conversation_id, convthread_id, low_bandwidth,
content_license_url,
media_license_url, media_creator,
languages_understood, translate,
buy_url, chat_url, auto_cw_cache,
searchable_by, session,
automatic_quote_approval)
create_post_base(base_dir, nickname, domain, port,
to_url, post_cc,
http_prefix, content, save_to_file,
client_to_server, comments_enabled,
attach_image_filename, media_type,
image_description, video_transcript, city,
is_moderation_report, is_article,
in_reply_to, in_reply_to_atom_uri, subject,
schedule_post, event_date, event_time,
location, event_uuid, category,
join_mode, end_date, end_time,
event_category,
maximum_attendee_capacity,
replies_moderation_option,
anonymous_participation_enabled,
event_status, ticket_url, system_language,
conversation_id, convthread_id, low_bandwidth,
content_license_url,
media_license_url, media_creator,
languages_understood, translate,
buy_url, chat_url, auto_cw_cache,
searchable_by, session,
automatic_quote_approval)
if not post_json_object:
continue
@ -3247,30 +3245,30 @@ def send_post(signing_priv_key_pem: str, project_version: str,
local_actor = local_actor_url(http_prefix, nickname, domain_full)
automatic_quote_approval = local_actor
post_json_object = \
_create_post_base(base_dir, nickname, domain, port,
to_person_id, cc_str, http_prefix, content,
save_to_file, client_to_server,
comments_enabled,
attach_image_filename, media_type,
image_description, video_transcript, city,
is_moderation_report, is_article, in_reply_to,
in_reply_to_atom_uri, subject,
schedule_post,
event_date, event_time, location,
event_uuid, category,
join_mode,
end_date, end_time, event_category,
maximum_attendee_capacity,
replies_moderation_option,
anonymous_participation_enabled,
event_status, ticket_url, system_language,
conversation_id, convthread_id, low_bandwidth,
content_license_url,
media_license_url, media_creator,
languages_understood,
translate, buy_url, chat_url,
auto_cw_cache, searchable_by, session,
automatic_quote_approval)
create_post_base(base_dir, nickname, domain, port,
to_person_id, cc_str, http_prefix, content,
save_to_file, client_to_server,
comments_enabled,
attach_image_filename, media_type,
image_description, video_transcript, city,
is_moderation_report, is_article, in_reply_to,
in_reply_to_atom_uri, subject,
schedule_post,
event_date, event_time, location,
event_uuid, category,
join_mode,
end_date, end_time, event_category,
maximum_attendee_capacity,
replies_moderation_option,
anonymous_participation_enabled,
event_status, ticket_url, system_language,
conversation_id, convthread_id, low_bandwidth,
content_license_url,
media_license_url, media_creator,
languages_understood,
translate, buy_url, chat_url,
auto_cw_cache, searchable_by, session,
automatic_quote_approval)
# get the senders private key
private_key_pem = get_person_key(nickname, domain, base_dir,
@ -3370,181 +3368,6 @@ def send_post(signing_priv_key_pem: str, project_version: str,
return 0
def send_post_via_server(signing_priv_key_pem: str, project_version: str,
base_dir: str, session,
from_nickname: str, password: str,
from_domain: str, from_port: int,
to_nickname: str, to_domain: str, to_port: int,
cc_str: str,
http_prefix: str, content: str,
comments_enabled: bool,
attach_image_filename: str, media_type: str,
image_description: str, video_transcript: str,
city: str, cached_webfingers: {}, person_cache: {},
is_article: bool, system_language: str,
languages_understood: [],
low_bandwidth: bool,
content_license_url: str,
media_license_url: str, media_creator: str,
event_date: str, event_time: str, event_end_time: str,
event_category: str,
location: str, translate: {},
buy_url: str, chat_url: str, auto_cw_cache: {},
debug: bool, in_reply_to: str,
in_reply_to_atom_uri: str,
conversation_id: str, convthread_id: str,
subject: str, searchable_by: [],
mitm_servers: []) -> int:
"""Send a post via a proxy (c2s)
"""
if not session:
print('WARN: No session for send_post_via_server')
return 6
from_domain_full = get_full_domain(from_domain, from_port)
handle = http_prefix + '://' + from_domain_full + '/@' + from_nickname
# lookup the inbox for the To handle
wf_request = \
webfinger_handle(session, handle, http_prefix, cached_webfingers,
from_domain_full, project_version, debug, False,
signing_priv_key_pem, mitm_servers)
if not wf_request:
if debug:
print('DEBUG: post webfinger failed for ' + handle)
return 1
if not isinstance(wf_request, dict):
print('WARN: post webfinger for ' + handle +
' did not return a dict. ' + str(wf_request))
return 1
post_to_box = 'outbox'
if is_article:
post_to_box = 'tlblogs'
# get the actor inbox for the To handle
origin_domain = from_domain
(inbox_url, _, _, from_person_id, _, _,
_, _) = get_person_box(signing_priv_key_pem,
origin_domain,
base_dir, session, wf_request,
person_cache,
project_version, http_prefix,
from_nickname,
from_domain_full, post_to_box,
82796, system_language,
mitm_servers)
if not inbox_url:
if debug:
print('DEBUG: post no ' + post_to_box +
' was found for ' + handle)
return 3
if not from_person_id:
if debug:
print('DEBUG: post no actor was found for ' + handle)
return 4
# Get the json for the c2s post, not saving anything to file
# Note that base_dir is set to None
save_to_file = False
client_to_server = True
if to_domain.lower().endswith('public'):
to_person_id = 'https://www.w3.org/ns/activitystreams#Public'
cc_str = \
local_actor_url(http_prefix, from_nickname, from_domain_full) + \
'/followers'
automatic_quote_approval = \
"https://www.w3.org/ns/activitystreams#Public"
else:
if to_domain.lower().endswith('followers') or \
to_domain.lower().endswith('followersonly'):
from_local_actor = \
local_actor_url(http_prefix, from_nickname, from_domain_full)
to_person_id = from_local_actor + '/followers'
automatic_quote_approval = from_local_actor + '/following'
else:
to_domain_full = get_full_domain(to_domain, to_port)
to_person_id = \
local_actor_url(http_prefix, to_nickname, to_domain_full)
automatic_quote_approval = \
local_actor_url(http_prefix,
from_nickname, from_domain_full)
is_moderation_report = False
schedule_post = False
event_uuid = category = join_mode = None
maximum_attendee_capacity = None
replies_moderation_option = None
anonymous_participation_enabled = None
event_status = ticket_url = None
post_json_object = \
_create_post_base(base_dir,
from_nickname, from_domain, from_port,
to_person_id, cc_str, http_prefix, content,
save_to_file, client_to_server,
comments_enabled,
attach_image_filename, media_type,
image_description, video_transcript, city,
is_moderation_report, is_article, in_reply_to,
in_reply_to_atom_uri, subject, schedule_post,
event_date, event_time, location,
event_uuid, category, join_mode,
event_date, event_end_time,
event_category,
maximum_attendee_capacity,
replies_moderation_option,
anonymous_participation_enabled,
event_status, ticket_url, system_language,
conversation_id, convthread_id, low_bandwidth,
content_license_url,
media_license_url, media_creator,
languages_understood,
translate, buy_url, chat_url, auto_cw_cache,
searchable_by, session,
automatic_quote_approval)
auth_header = create_basic_auth_header(from_nickname, password)
if attach_image_filename:
headers = {
'host': from_domain_full,
'Authorization': auth_header
}
post_result = \
post_image(session, attach_image_filename, [],
inbox_url, headers, http_prefix, from_domain_full)
if not post_result:
if debug:
print('DEBUG: post failed to upload image')
# return 9
headers = {
'host': from_domain_full,
'Content-type': 'application/json',
'Authorization': auth_header
}
post_dumps = json.dumps(post_json_object)
post_result, unauthorized, return_code = \
post_json_string(session, post_dumps, [],
inbox_url, headers, debug,
http_prefix, from_domain_full,
5, True)
if not post_result:
if debug:
if unauthorized:
print('DEBUG: POST failed for c2s to ' +
inbox_url + ' unathorized')
else:
print('DEBUG: POST failed for c2s to ' +
inbox_url + ' return code ' + str(return_code))
return 5
if debug:
print('DEBUG: c2s POST success')
return 0
def group_followers_by_domain(base_dir: str, nickname: str, domain: str) -> {}:
"""Returns a dictionary with followers grouped by domain
"""
@ -6710,374 +6533,6 @@ def is_muted_conv(base_dir: str, nickname: str, domain: str, post_id: str,
return False
def send_block_via_server(base_dir: str, session,
from_nickname: str, password: str,
from_domain: str, from_port: int,
http_prefix: str, blocked_url: str,
cached_webfingers: {}, person_cache: {},
debug: bool, project_version: str,
signing_priv_key_pem: str,
system_language: str,
mitm_servers: []) -> {}:
"""Creates a block via c2s
"""
if not session:
print('WARN: No session for send_block_via_server')
return 6
from_domain_full = get_full_domain(from_domain, from_port)
block_actor = local_actor_url(http_prefix, from_nickname, from_domain_full)
to_url = 'https://www.w3.org/ns/activitystreams#Public'
cc_url = block_actor + '/followers'
new_block_json = {
"@context": [
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'type': 'Block',
'actor': block_actor,
'object': blocked_url,
'to': [to_url],
'cc': [cc_url]
}
handle = http_prefix + '://' + from_domain_full + '/@' + from_nickname
# lookup the inbox for the To handle
wf_request = webfinger_handle(session, handle, http_prefix,
cached_webfingers,
from_domain, project_version, debug, False,
signing_priv_key_pem, mitm_servers)
if not wf_request:
if debug:
print('DEBUG: block webfinger failed for ' + handle)
return 1
if not isinstance(wf_request, dict):
print('WARN: block Webfinger for ' + handle +
' did not return a dict. ' + str(wf_request))
return 1
post_to_box = 'outbox'
# get the actor inbox for the To handle
origin_domain = from_domain
(inbox_url, _, _, from_person_id, _, _,
_, _) = get_person_box(signing_priv_key_pem,
origin_domain,
base_dir, session, wf_request,
person_cache,
project_version, http_prefix,
from_nickname,
from_domain, post_to_box, 72652,
system_language, mitm_servers)
if not inbox_url:
if debug:
print('DEBUG: block no ' + post_to_box +
' was found for ' + handle)
return 3
if not from_person_id:
if debug:
print('DEBUG: block no actor was found for ' + handle)
return 4
auth_header = create_basic_auth_header(from_nickname, password)
headers = {
'host': from_domain,
'Content-type': 'application/json',
'Authorization': auth_header
}
post_result = post_json(http_prefix, from_domain_full,
session, new_block_json, [], inbox_url,
headers, 30, True)
if not post_result:
print('WARN: block unable to post')
if debug:
print('DEBUG: c2s POST block success')
return new_block_json
def send_mute_via_server(base_dir: str, session,
from_nickname: str, password: str,
from_domain: str, from_port: int,
http_prefix: str, muted_url: str,
cached_webfingers: {}, person_cache: {},
debug: bool, project_version: str,
signing_priv_key_pem: str,
system_language: str,
mitm_servers: []) -> {}:
"""Creates a mute via c2s
"""
if not session:
print('WARN: No session for send_mute_via_server')
return 6
from_domain_full = get_full_domain(from_domain, from_port)
actor = local_actor_url(http_prefix, from_nickname, from_domain_full)
handle = replace_users_with_at(actor)
new_mute_json = {
"@context": [
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'type': 'Ignore',
'actor': actor,
'to': [actor],
'object': muted_url
}
# lookup the inbox for the To handle
wf_request = webfinger_handle(session, handle, http_prefix,
cached_webfingers,
from_domain, project_version, debug, False,
signing_priv_key_pem, mitm_servers)
if not wf_request:
if debug:
print('DEBUG: mute webfinger failed for ' + handle)
return 1
if not isinstance(wf_request, dict):
print('WARN: mute Webfinger for ' + handle +
' did not return a dict. ' + str(wf_request))
return 1
post_to_box = 'outbox'
# get the actor inbox for the To handle
origin_domain = from_domain
(inbox_url, _, _, from_person_id, _, _,
_, _) = get_person_box(signing_priv_key_pem,
origin_domain,
base_dir, session, wf_request,
person_cache,
project_version, http_prefix,
from_nickname,
from_domain, post_to_box, 72652,
system_language, mitm_servers)
if not inbox_url:
if debug:
print('DEBUG: mute no ' + post_to_box + ' was found for ' + handle)
return 3
if not from_person_id:
if debug:
print('DEBUG: mute no actor was found for ' + handle)
return 4
auth_header = create_basic_auth_header(from_nickname, password)
headers = {
'host': from_domain,
'Content-type': 'application/json',
'Authorization': auth_header
}
post_result = post_json(http_prefix, from_domain_full,
session, new_mute_json, [], inbox_url,
headers, 3, True)
if post_result is None:
print('WARN: mute unable to post')
if debug:
print('DEBUG: c2s POST mute success')
return new_mute_json
def send_undo_mute_via_server(base_dir: str, session,
from_nickname: str, password: str,
from_domain: str, from_port: int,
http_prefix: str, muted_url: str,
cached_webfingers: {}, person_cache: {},
debug: bool, project_version: str,
signing_priv_key_pem: str,
system_language: str,
mitm_servers: []) -> {}:
"""Undoes a mute via c2s
"""
if not session:
print('WARN: No session for send_undo_mute_via_server')
return 6
from_domain_full = get_full_domain(from_domain, from_port)
actor = local_actor_url(http_prefix, from_nickname, from_domain_full)
handle = replace_users_with_at(actor)
undo_mute_json = {
"@context": [
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'type': 'Undo',
'actor': actor,
'to': [actor],
'object': {
'type': 'Ignore',
'actor': actor,
'to': [actor],
'object': muted_url
}
}
# lookup the inbox for the To handle
wf_request = webfinger_handle(session, handle, http_prefix,
cached_webfingers,
from_domain, project_version, debug, False,
signing_priv_key_pem, mitm_servers)
if not wf_request:
if debug:
print('DEBUG: undo mute webfinger failed for ' + handle)
return 1
if not isinstance(wf_request, dict):
print('WARN: undo mute Webfinger for ' + handle +
' did not return a dict. ' + str(wf_request))
return 1
post_to_box = 'outbox'
# get the actor inbox for the To handle
origin_domain = from_domain
(inbox_url, _, _, from_person_id, _, _,
_, _) = get_person_box(signing_priv_key_pem,
origin_domain,
base_dir, session, wf_request,
person_cache,
project_version, http_prefix,
from_nickname,
from_domain, post_to_box, 72652,
system_language, mitm_servers)
if not inbox_url:
if debug:
print('DEBUG: undo mute no ' + post_to_box +
' was found for ' + handle)
return 3
if not from_person_id:
if debug:
print('DEBUG: undo mute no actor was found for ' + handle)
return 4
auth_header = create_basic_auth_header(from_nickname, password)
headers = {
'host': from_domain,
'Content-type': 'application/json',
'Authorization': auth_header
}
post_result = post_json(http_prefix, from_domain_full,
session, undo_mute_json, [], inbox_url,
headers, 3, True)
if post_result is None:
print('WARN: undo mute unable to post')
if debug:
print('DEBUG: c2s POST undo mute success')
return undo_mute_json
def send_undo_block_via_server(base_dir: str, session,
from_nickname: str, password: str,
from_domain: str, from_port: int,
http_prefix: str, blocked_url: str,
cached_webfingers: {}, person_cache: {},
debug: bool, project_version: str,
signing_priv_key_pem: str,
system_language: str,
mitm_servers: []) -> {}:
"""Creates a block via c2s
"""
if not session:
print('WARN: No session for send_block_via_server')
return 6
from_domain_full = get_full_domain(from_domain, from_port)
block_actor = local_actor_url(http_prefix, from_nickname, from_domain_full)
to_url = 'https://www.w3.org/ns/activitystreams#Public'
cc_url = block_actor + '/followers'
new_block_json = {
"@context": [
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'type': 'Undo',
'actor': block_actor,
'object': {
'type': 'Block',
'actor': block_actor,
'object': blocked_url,
'to': [to_url],
'cc': [cc_url]
}
}
handle = http_prefix + '://' + from_domain_full + '/@' + from_nickname
# lookup the inbox for the To handle
wf_request = webfinger_handle(session, handle, http_prefix,
cached_webfingers,
from_domain, project_version, debug, False,
signing_priv_key_pem, mitm_servers)
if not wf_request:
if debug:
print('DEBUG: unblock webfinger failed for ' + handle)
return 1
if not isinstance(wf_request, dict):
print('WARN: unblock webfinger for ' + handle +
' did not return a dict. ' + str(wf_request))
return 1
post_to_box = 'outbox'
# get the actor inbox for the To handle
origin_domain = from_domain
(inbox_url, _, _, from_person_id, _, _,
_, _) = get_person_box(signing_priv_key_pem,
origin_domain,
base_dir, session, wf_request,
person_cache,
project_version, http_prefix,
from_nickname,
from_domain, post_to_box, 53892,
system_language, mitm_servers)
if not inbox_url:
if debug:
print('DEBUG: unblock no ' + post_to_box +
' was found for ' + handle)
return 3
if not from_person_id:
if debug:
print('DEBUG: unblock no actor was found for ' + handle)
return 4
auth_header = create_basic_auth_header(from_nickname, password)
headers = {
'host': from_domain,
'Content-type': 'application/json',
'Authorization': auth_header
}
post_result = post_json(http_prefix, from_domain_full,
session, new_block_json, [], inbox_url,
headers, 30, True)
if not post_result:
print('WARN: unblock unable to post')
if debug:
print('DEBUG: c2s POST unblock success')
return new_block_json
def post_is_muted(base_dir: str, nickname: str, domain: str,
post_json_object: {}, message_id: str) -> bool:
""" Returns true if the given post is muted

563
sendC2S.py 100644
View File

@ -0,0 +1,563 @@
__filename__ = "sendC2S.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "1.6.0"
__maintainer__ = "Bob Mottram"
__email__ = "bob@libreserver.org"
__status__ = "Production"
__module_group__ = "ActivityPub"
import json
from utils import replace_users_with_at
from utils import get_full_domain
from utils import local_actor_url
from webfinger import webfinger_handle
from posts import get_person_box
from posts import create_post_base
from auth import create_basic_auth_header
from session import post_image
from session import post_json_string
from session import post_json
def send_post_via_server(signing_priv_key_pem: str, project_version: str,
base_dir: str, session,
from_nickname: str, password: str,
from_domain: str, from_port: int,
to_nickname: str, to_domain: str, to_port: int,
cc_str: str,
http_prefix: str, content: str,
comments_enabled: bool,
attach_image_filename: str, media_type: str,
image_description: str, video_transcript: str,
city: str, cached_webfingers: {}, person_cache: {},
is_article: bool, system_language: str,
languages_understood: [],
low_bandwidth: bool,
content_license_url: str,
media_license_url: str, media_creator: str,
event_date: str, event_time: str, event_end_time: str,
event_category: str,
location: str, translate: {},
buy_url: str, chat_url: str, auto_cw_cache: {},
debug: bool, in_reply_to: str,
in_reply_to_atom_uri: str,
conversation_id: str, convthread_id: str,
subject: str, searchable_by: [],
mitm_servers: []) -> int:
"""Send a post via a proxy (c2s)
"""
if not session:
print('WARN: No session for send_post_via_server')
return 6
from_domain_full = get_full_domain(from_domain, from_port)
handle = http_prefix + '://' + from_domain_full + '/@' + from_nickname
# lookup the inbox for the To handle
wf_request = \
webfinger_handle(session, handle, http_prefix, cached_webfingers,
from_domain_full, project_version, debug, False,
signing_priv_key_pem, mitm_servers)
if not wf_request:
if debug:
print('DEBUG: post webfinger failed for ' + handle)
return 1
if not isinstance(wf_request, dict):
print('WARN: post webfinger for ' + handle +
' did not return a dict. ' + str(wf_request))
return 1
post_to_box = 'outbox'
if is_article:
post_to_box = 'tlblogs'
# get the actor inbox for the To handle
origin_domain = from_domain
(inbox_url, _, _, from_person_id, _, _,
_, _) = get_person_box(signing_priv_key_pem,
origin_domain,
base_dir, session, wf_request,
person_cache,
project_version, http_prefix,
from_nickname,
from_domain_full, post_to_box,
82796, system_language,
mitm_servers)
if not inbox_url:
if debug:
print('DEBUG: post no ' + post_to_box +
' was found for ' + handle)
return 3
if not from_person_id:
if debug:
print('DEBUG: post no actor was found for ' + handle)
return 4
# Get the json for the c2s post, not saving anything to file
# Note that base_dir is set to None
save_to_file = False
client_to_server = True
if to_domain.lower().endswith('public'):
to_person_id = 'https://www.w3.org/ns/activitystreams#Public'
cc_str = \
local_actor_url(http_prefix, from_nickname, from_domain_full) + \
'/followers'
automatic_quote_approval = \
"https://www.w3.org/ns/activitystreams#Public"
else:
if to_domain.lower().endswith('followers') or \
to_domain.lower().endswith('followersonly'):
from_local_actor = \
local_actor_url(http_prefix, from_nickname, from_domain_full)
to_person_id = from_local_actor + '/followers'
automatic_quote_approval = from_local_actor + '/following'
else:
to_domain_full = get_full_domain(to_domain, to_port)
to_person_id = \
local_actor_url(http_prefix, to_nickname, to_domain_full)
automatic_quote_approval = \
local_actor_url(http_prefix,
from_nickname, from_domain_full)
is_moderation_report = False
schedule_post = False
event_uuid = category = join_mode = None
maximum_attendee_capacity = None
replies_moderation_option = None
anonymous_participation_enabled = None
event_status = ticket_url = None
post_json_object = \
create_post_base(base_dir,
from_nickname, from_domain, from_port,
to_person_id, cc_str, http_prefix, content,
save_to_file, client_to_server,
comments_enabled,
attach_image_filename, media_type,
image_description, video_transcript, city,
is_moderation_report, is_article, in_reply_to,
in_reply_to_atom_uri, subject, schedule_post,
event_date, event_time, location,
event_uuid, category, join_mode,
event_date, event_end_time,
event_category,
maximum_attendee_capacity,
replies_moderation_option,
anonymous_participation_enabled,
event_status, ticket_url, system_language,
conversation_id, convthread_id, low_bandwidth,
content_license_url,
media_license_url, media_creator,
languages_understood,
translate, buy_url, chat_url, auto_cw_cache,
searchable_by, session,
automatic_quote_approval)
auth_header = create_basic_auth_header(from_nickname, password)
if attach_image_filename:
headers = {
'host': from_domain_full,
'Authorization': auth_header
}
post_result = \
post_image(session, attach_image_filename, [],
inbox_url, headers, http_prefix, from_domain_full)
if not post_result:
if debug:
print('DEBUG: post failed to upload image')
# return 9
headers = {
'host': from_domain_full,
'Content-type': 'application/json',
'Authorization': auth_header
}
post_dumps = json.dumps(post_json_object)
post_result, unauthorized, return_code = \
post_json_string(session, post_dumps, [],
inbox_url, headers, debug,
http_prefix, from_domain_full,
5, True)
if not post_result:
if debug:
if unauthorized:
print('DEBUG: POST failed for c2s to ' +
inbox_url + ' unathorized')
else:
print('DEBUG: POST failed for c2s to ' +
inbox_url + ' return code ' + str(return_code))
return 5
if debug:
print('DEBUG: c2s POST success')
return 0
def send_block_via_server(base_dir: str, session,
from_nickname: str, password: str,
from_domain: str, from_port: int,
http_prefix: str, blocked_url: str,
cached_webfingers: {}, person_cache: {},
debug: bool, project_version: str,
signing_priv_key_pem: str,
system_language: str,
mitm_servers: []) -> {}:
"""Creates a block via c2s
"""
if not session:
print('WARN: No session for send_block_via_server')
return 6
from_domain_full = get_full_domain(from_domain, from_port)
block_actor = local_actor_url(http_prefix, from_nickname, from_domain_full)
to_url = 'https://www.w3.org/ns/activitystreams#Public'
cc_url = block_actor + '/followers'
new_block_json = {
"@context": [
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'type': 'Block',
'actor': block_actor,
'object': blocked_url,
'to': [to_url],
'cc': [cc_url]
}
handle = http_prefix + '://' + from_domain_full + '/@' + from_nickname
# lookup the inbox for the To handle
wf_request = webfinger_handle(session, handle, http_prefix,
cached_webfingers,
from_domain, project_version, debug, False,
signing_priv_key_pem, mitm_servers)
if not wf_request:
if debug:
print('DEBUG: block webfinger failed for ' + handle)
return 1
if not isinstance(wf_request, dict):
print('WARN: block Webfinger for ' + handle +
' did not return a dict. ' + str(wf_request))
return 1
post_to_box = 'outbox'
# get the actor inbox for the To handle
origin_domain = from_domain
(inbox_url, _, _, from_person_id, _, _,
_, _) = get_person_box(signing_priv_key_pem,
origin_domain,
base_dir, session, wf_request,
person_cache,
project_version, http_prefix,
from_nickname,
from_domain, post_to_box, 72652,
system_language, mitm_servers)
if not inbox_url:
if debug:
print('DEBUG: block no ' + post_to_box +
' was found for ' + handle)
return 3
if not from_person_id:
if debug:
print('DEBUG: block no actor was found for ' + handle)
return 4
auth_header = create_basic_auth_header(from_nickname, password)
headers = {
'host': from_domain,
'Content-type': 'application/json',
'Authorization': auth_header
}
post_result = post_json(http_prefix, from_domain_full,
session, new_block_json, [], inbox_url,
headers, 30, True)
if not post_result:
print('WARN: block unable to post')
if debug:
print('DEBUG: c2s POST block success')
return new_block_json
def send_mute_via_server(base_dir: str, session,
from_nickname: str, password: str,
from_domain: str, from_port: int,
http_prefix: str, muted_url: str,
cached_webfingers: {}, person_cache: {},
debug: bool, project_version: str,
signing_priv_key_pem: str,
system_language: str,
mitm_servers: []) -> {}:
"""Creates a mute via c2s
"""
if not session:
print('WARN: No session for send_mute_via_server')
return 6
from_domain_full = get_full_domain(from_domain, from_port)
actor = local_actor_url(http_prefix, from_nickname, from_domain_full)
handle = replace_users_with_at(actor)
new_mute_json = {
"@context": [
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'type': 'Ignore',
'actor': actor,
'to': [actor],
'object': muted_url
}
# lookup the inbox for the To handle
wf_request = webfinger_handle(session, handle, http_prefix,
cached_webfingers,
from_domain, project_version, debug, False,
signing_priv_key_pem, mitm_servers)
if not wf_request:
if debug:
print('DEBUG: mute webfinger failed for ' + handle)
return 1
if not isinstance(wf_request, dict):
print('WARN: mute Webfinger for ' + handle +
' did not return a dict. ' + str(wf_request))
return 1
post_to_box = 'outbox'
# get the actor inbox for the To handle
origin_domain = from_domain
(inbox_url, _, _, from_person_id, _, _,
_, _) = get_person_box(signing_priv_key_pem,
origin_domain,
base_dir, session, wf_request,
person_cache,
project_version, http_prefix,
from_nickname,
from_domain, post_to_box, 72652,
system_language, mitm_servers)
if not inbox_url:
if debug:
print('DEBUG: mute no ' + post_to_box + ' was found for ' + handle)
return 3
if not from_person_id:
if debug:
print('DEBUG: mute no actor was found for ' + handle)
return 4
auth_header = create_basic_auth_header(from_nickname, password)
headers = {
'host': from_domain,
'Content-type': 'application/json',
'Authorization': auth_header
}
post_result = post_json(http_prefix, from_domain_full,
session, new_mute_json, [], inbox_url,
headers, 3, True)
if post_result is None:
print('WARN: mute unable to post')
if debug:
print('DEBUG: c2s POST mute success')
return new_mute_json
def send_undo_mute_via_server(base_dir: str, session,
from_nickname: str, password: str,
from_domain: str, from_port: int,
http_prefix: str, muted_url: str,
cached_webfingers: {}, person_cache: {},
debug: bool, project_version: str,
signing_priv_key_pem: str,
system_language: str,
mitm_servers: []) -> {}:
"""Undoes a mute via c2s
"""
if not session:
print('WARN: No session for send_undo_mute_via_server')
return 6
from_domain_full = get_full_domain(from_domain, from_port)
actor = local_actor_url(http_prefix, from_nickname, from_domain_full)
handle = replace_users_with_at(actor)
undo_mute_json = {
"@context": [
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'type': 'Undo',
'actor': actor,
'to': [actor],
'object': {
'type': 'Ignore',
'actor': actor,
'to': [actor],
'object': muted_url
}
}
# lookup the inbox for the To handle
wf_request = webfinger_handle(session, handle, http_prefix,
cached_webfingers,
from_domain, project_version, debug, False,
signing_priv_key_pem, mitm_servers)
if not wf_request:
if debug:
print('DEBUG: undo mute webfinger failed for ' + handle)
return 1
if not isinstance(wf_request, dict):
print('WARN: undo mute Webfinger for ' + handle +
' did not return a dict. ' + str(wf_request))
return 1
post_to_box = 'outbox'
# get the actor inbox for the To handle
origin_domain = from_domain
(inbox_url, _, _, from_person_id, _, _,
_, _) = get_person_box(signing_priv_key_pem,
origin_domain,
base_dir, session, wf_request,
person_cache,
project_version, http_prefix,
from_nickname,
from_domain, post_to_box, 72652,
system_language, mitm_servers)
if not inbox_url:
if debug:
print('DEBUG: undo mute no ' + post_to_box +
' was found for ' + handle)
return 3
if not from_person_id:
if debug:
print('DEBUG: undo mute no actor was found for ' + handle)
return 4
auth_header = create_basic_auth_header(from_nickname, password)
headers = {
'host': from_domain,
'Content-type': 'application/json',
'Authorization': auth_header
}
post_result = post_json(http_prefix, from_domain_full,
session, undo_mute_json, [], inbox_url,
headers, 3, True)
if post_result is None:
print('WARN: undo mute unable to post')
if debug:
print('DEBUG: c2s POST undo mute success')
return undo_mute_json
def send_undo_block_via_server(base_dir: str, session,
from_nickname: str, password: str,
from_domain: str, from_port: int,
http_prefix: str, blocked_url: str,
cached_webfingers: {}, person_cache: {},
debug: bool, project_version: str,
signing_priv_key_pem: str,
system_language: str,
mitm_servers: []) -> {}:
"""Creates a block via c2s
"""
if not session:
print('WARN: No session for send_block_via_server')
return 6
from_domain_full = get_full_domain(from_domain, from_port)
block_actor = local_actor_url(http_prefix, from_nickname, from_domain_full)
to_url = 'https://www.w3.org/ns/activitystreams#Public'
cc_url = block_actor + '/followers'
new_block_json = {
"@context": [
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'type': 'Undo',
'actor': block_actor,
'object': {
'type': 'Block',
'actor': block_actor,
'object': blocked_url,
'to': [to_url],
'cc': [cc_url]
}
}
handle = http_prefix + '://' + from_domain_full + '/@' + from_nickname
# lookup the inbox for the To handle
wf_request = webfinger_handle(session, handle, http_prefix,
cached_webfingers,
from_domain, project_version, debug, False,
signing_priv_key_pem, mitm_servers)
if not wf_request:
if debug:
print('DEBUG: unblock webfinger failed for ' + handle)
return 1
if not isinstance(wf_request, dict):
print('WARN: unblock webfinger for ' + handle +
' did not return a dict. ' + str(wf_request))
return 1
post_to_box = 'outbox'
# get the actor inbox for the To handle
origin_domain = from_domain
(inbox_url, _, _, from_person_id, _, _,
_, _) = get_person_box(signing_priv_key_pem,
origin_domain,
base_dir, session, wf_request,
person_cache,
project_version, http_prefix,
from_nickname,
from_domain, post_to_box, 53892,
system_language, mitm_servers)
if not inbox_url:
if debug:
print('DEBUG: unblock no ' + post_to_box +
' was found for ' + handle)
return 3
if not from_person_id:
if debug:
print('DEBUG: unblock no actor was found for ' + handle)
return 4
auth_header = create_basic_auth_header(from_nickname, password)
headers = {
'host': from_domain,
'Content-type': 'application/json',
'Authorization': auth_header
}
post_result = post_json(http_prefix, from_domain_full,
session, new_block_json, [], inbox_url,
headers, 30, True)
if not post_result:
print('WARN: unblock unable to post')
if debug:
print('DEBUG: c2s POST unblock success')
return new_block_json

View File

@ -39,6 +39,7 @@ from daemon import run_daemon
from session import get_json_valid
from session import create_session
from session import get_json
from sendC2S import send_post_via_server
from posts import json_post_allows_comments
from posts import convert_post_content_to_html
from posts import get_actor_from_in_reply_to
@ -51,7 +52,6 @@ from posts import send_post
from posts import no_of_followers_on_domain
from posts import group_followers_by_domain
from posts import archive_posts_for_person
from posts import send_post_via_server
from posts import seconds_between_published
from follow import clear_follows
from follow import clear_followers