Handle FeatureRequest

main
bashrc 2026-06-18 13:23:42 +01:00
parent ed795040c7
commit d72734f0cb
4 changed files with 209 additions and 3 deletions

View File

@ -137,6 +137,35 @@ def create_reject(federation_list: [],
http_prefix, object_json, 'Reject')
def create_feature_reject(federation_list: [],
nickname: str, domain: str, port: int,
to_url: str, cc_url: str, http_prefix: str,
object_json: {}) -> {}:
""" Create json for ActivityPub FeatureRequest Reject """
if not object_json.get('id'):
return None
if not url_permitted(to_url, federation_list):
return None
domain = get_full_domain(domain, port)
new_reject = {
"@context": [
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'type': 'Reject',
'actor': local_actor_url(http_prefix, nickname, domain),
'to': [to_url],
'cc': [],
'object': object_json['id']
}
if cc_url:
new_reject['cc'] = [cc_url]
return new_reject
def _reject_quote_request(message_json: {}, domain_full: str,
federation_list: [],
debug: bool,

View File

@ -884,7 +884,7 @@ def followed_account_rejects(session, session_onion, session_i2p,
curr_session = session_i2p
elif is_yggdrasil_address(domain) and session_yggdrasil:
curr_session = session_yggdrasil
extra_headers = {}
extra_headers: dict = {}
domain_full = get_full_domain(domain, from_port)
remove_followers_sync(followers_sync_cache,
nickname_to_follow,

View File

@ -129,6 +129,7 @@ from src.inbox_receive import inbox_update_index
from src.inbox_receive import receive_edit_to_post
from src.inbox_receive import receive_actor_status
from src.inbox_receive import receive_like
from src.inbox_receive import receive_feature_request
from src.inbox_receive import receive_reaction
from src.inbox_receive import receive_zot_reaction
from src.inbox_receive import receive_bookmark
@ -353,7 +354,7 @@ def inbox_message_has_params(message_json: {}) -> bool:
allowed_without_to_param = [
'Like', 'EmojiReact', 'Follow', 'Join', 'Request',
'Accept', 'Capability', 'Undo', 'Move', 'sm:ActorStatus',
'ActorStatus'
'ActorStatus', 'FeatureRequest'
]
if message_json['type'] not in allowed_without_to_param:
return False
@ -384,7 +385,7 @@ def inbox_permitted_message(domain: str, message_json: {},
always_allowed_types = (
'Follow', 'Join', 'Like', 'EmojiReact', 'Delete', 'Announce', 'Move',
'QuoteRequest', 'sm:ActorStatus', 'ActorStatus'
'QuoteRequest', 'sm:ActorStatus', 'ActorStatus', 'FeatureRequest'
)
if message_json['type'] in always_allowed_types:
return True
@ -2031,6 +2032,31 @@ def _inbox_after_initial(server, inbox_start_time,
inbox_start_time = time.time()
return False
if receive_feature_request(session,
session_onion, session_i2p, session_yggdrasil,
handle, base_dir,
http_prefix, domain, port,
onion_domain, i2p_domain,
yggdrasil_domain,
cached_webfingers,
person_cache, message_json,
debug,
signing_priv_key_pem,
system_language,
mitm_servers,
server.blocked_cache,
server.block_federated,
federation_list,
send_threads, post_log,
sites_unavailable):
if debug:
print('DEBUG: FeatureRequest received from ' + actor)
fitness_performance(inbox_start_time, server.fitness,
'INBOX', '_receive_like',
debug)
inbox_start_time = time.time()
return False
if receive_like(recent_posts_cache,
session, handle,
base_dir, http_prefix,

View File

@ -9,11 +9,14 @@ __module_group__ = "Timeline"
import os
import time
from pprint import pprint
from src.flags import has_group_type
from src.flags import is_recent_post
from src.flags import is_quote_toot
from src.status import actor_status_expired
from src.quote import get_quote_toot_url
from src.timeFunctions import get_account_timezone
from src.utils import is_yggdrasil_address
from src.utils import valid_nickname
from src.utils import get_mutuals_of_person
from src.utils import get_actor_from_post_id
@ -94,6 +97,8 @@ from src.data import load_string
from src.data import erase_file
from src.data import is_a_file
from src.data import is_a_dir
from src.acceptreject import create_feature_reject
from src.posts import send_signed_json
def inbox_update_index(boxname: str, base_dir: str, handle: str,
@ -1126,6 +1131,152 @@ def receive_like(recent_posts_cache: {},
return True
def receive_feature_request(session,
session_onion, session_i2p, session_yggdrasil,
handle: str, base_dir: str,
http_prefix: str, domain: str, port: int,
onion_domain: str, i2p_domain: str,
yggdrasil_domain: str,
cached_webfingers: {},
person_cache: {}, message_json: {},
debug: bool,
signing_priv_key_pem: str,
system_language: str,
mitm_servers: [],
blocked_cache: [],
block_federated: [],
federation_list: [],
send_threads: [], post_log: [],
sites_unavailable: []) -> bool:
"""Receives a FeatureRequest activity within the POST section of HTTPServer
https://codeberg.org/fediverse/fep/src/branch/main/fep/7aa9/fep-7aa9.md
"""
if message_json['type'] != 'FeatureRequest':
return False
if not has_object_string(message_json, debug):
return False
if not message_json.get('id'):
return False
if not isinstance(message_json['id'], str):
return False
if not message_json.get('instrument'):
return False
if not isinstance(message_json['instrument'], str):
return False
actor_url = message_json['object']
actor_nickname = get_nickname_from_actor(actor_url)
if not actor_nickname:
if debug:
print('DEBUG: FeatureRequest has no actor nickname ' + actor_url)
return False
if '/' + actor_nickname + '/' in actor_url:
actor_url = \
actor_url.split('/' + actor_nickname + '/')[0] + \
'/' + actor_nickname
actor_domain, actor_port = get_domain_from_actor(actor_url)
if not actor_domain:
if debug:
print('DEBUG: FeatureRequest has no actor domain ' + actor_url)
return False
actor_domain_full = get_full_domain(actor_domain, actor_port)
handle = actor_nickname + '@' + actor_domain_full
handle_dir = acct_handle_dir(base_dir, handle)
if not is_a_dir(handle_dir):
print('DEBUG: unknown recipient of FeatureRequest - ' + handle)
return True
sender_url = message_json['id']
sender_nickname = get_nickname_from_actor(sender_url)
if not sender_nickname:
if debug:
print('DEBUG: FeatureRequest has no sender nickname ' + sender_url)
return False
if '/' + sender_nickname + '/' in sender_url:
sender_url = \
sender_url.split('/' + sender_nickname + '/')[0] + \
'/' + sender_nickname
sender_domain, sender_port = get_domain_from_actor(sender_url)
if not sender_domain:
if debug:
print('DEBUG: FeatureRequest has no sender domain ' + sender_url)
return False
sender_domain_full = get_full_domain(sender_domain, sender_port)
if is_blocked(base_dir, actor_nickname, actor_domain_full,
sender_nickname, sender_domain_full,
blocked_cache, block_federated):
sender_handle = sender_nickname + '@' + sender_domain_full
print('BLOCK: FeatureRequest sender actor is blocked ' +
sender_handle + ' by ' + actor_url)
return False
reject_json = \
create_feature_reject(federation_list,
actor_nickname, actor_domain, actor_port,
sender_url, '', http_prefix, message_json)
if debug:
pprint(reject_json)
print('DEBUG: sending FeatureRequest Reject from ' +
actor_nickname + '@' + actor_domain_full +
' to ' + sender_nickname + '@' + sender_domain_full)
curr_session = session
curr_domain = domain
curr_port = port
curr_http_prefix = http_prefix
if onion_domain and \
not curr_domain.endswith('.onion') and \
sender_domain.endswith('.onion'):
curr_session = session_onion
curr_http_prefix: str = 'http'
curr_domain = onion_domain
curr_port = 80
port = 80
if debug:
print('Domain switched from ' + domain +
' to ' + curr_domain)
elif (i2p_domain and
not curr_domain.endswith('.i2p') and
sender_domain.endswith('.i2p')):
curr_session = session_i2p
curr_http_prefix: str = 'http'
curr_domain = i2p_domain
curr_port = 80
port = 80
if debug:
print('Domain switched from ' + domain +
' to ' + curr_domain)
elif (yggdrasil_domain and
not is_yggdrasil_address(curr_domain) and
is_yggdrasil_address(sender_domain)):
curr_session = session_yggdrasil
curr_http_prefix: str = 'http'
curr_domain = yggdrasil_domain
curr_port = 80
port = 80
if debug:
print('Domain switched from ' + domain +
' to ' + curr_domain)
extra_headers: dict = {}
client_to_server: bool = False
group_account: bool = False
if has_group_type(base_dir, actor_url, person_cache):
group_account = True
send_signed_json(reject_json, curr_session, base_dir,
sender_nickname, sender_domain, sender_port,
actor_nickname, domain, curr_port,
curr_http_prefix, client_to_server,
federation_list,
send_threads, post_log, cached_webfingers,
person_cache, debug, __version__, None,
group_account, signing_priv_key_pem,
326735214, curr_domain,
onion_domain, i2p_domain, yggdrasil_domain,
extra_headers, sites_unavailable,
system_language, mitm_servers)
return True
def receive_actor_status(base_dir: str, person_cache: {}, message_json: {},
debug: bool) -> bool:
"""Receives an sm:ActorStatus activity within the POST section