| 
									
										
										
										
											2024-05-08 10:44:38 +00:00
										 |  |  | """ ActivityPub Accept or Reject json """ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 18:16:29 +00:00
										 |  |  | __filename__ = "acceptreject.py" | 
					
						
							|  |  |  | __author__ = "Bob Mottram" | 
					
						
							|  |  |  | __license__ = "AGPL3+" | 
					
						
							| 
									
										
										
										
											2024-12-22 23:37:30 +00:00
										 |  |  | __version__ = "1.6.0" | 
					
						
							| 
									
										
										
										
											2020-04-01 18:16:29 +00:00
										 |  |  | __maintainer__ = "Bob Mottram" | 
					
						
							| 
									
										
										
										
											2021-09-10 16:14:50 +00:00
										 |  |  | __email__ = "bob@libreserver.org" | 
					
						
							| 
									
										
										
										
											2020-04-01 18:16:29 +00:00
										 |  |  | __status__ = "Production" | 
					
						
							| 
									
										
										
										
											2021-06-15 15:08:12 +00:00
										 |  |  | __module_group__ = "ActivityPub" | 
					
						
							| 
									
										
										
										
											2019-07-02 11:31:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-01 00:04:27 +00:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2025-04-06 20:06:21 +00:00
										 |  |  | import time | 
					
						
							| 
									
										
										
										
											2025-04-06 19:47:30 +00:00
										 |  |  | from posts import send_signed_json | 
					
						
							| 
									
										
										
										
											2024-09-13 13:58:14 +00:00
										 |  |  | from flags import has_group_type | 
					
						
							|  |  |  | from flags import url_permitted | 
					
						
							| 
									
										
										
										
											2025-04-06 19:47:30 +00:00
										 |  |  | from utils import get_status_number | 
					
						
							| 
									
										
										
										
											2025-04-06 12:06:37 +00:00
										 |  |  | from utils import get_attributed_to | 
					
						
							| 
									
										
										
										
											2024-05-27 12:45:01 +00:00
										 |  |  | from utils import get_user_paths | 
					
						
							| 
									
										
										
										
											2022-06-10 13:29:51 +00:00
										 |  |  | from utils import text_in_file | 
					
						
							| 
									
										
										
										
											2021-12-26 15:54:46 +00:00
										 |  |  | from utils import has_object_string_object | 
					
						
							| 
									
										
										
										
											2021-12-26 12:19:00 +00:00
										 |  |  | from utils import has_users_path | 
					
						
							| 
									
										
										
										
											2021-12-26 12:45:03 +00:00
										 |  |  | from utils import get_full_domain | 
					
						
							| 
									
										
										
										
											2021-12-27 19:05:25 +00:00
										 |  |  | from utils import get_domain_from_actor | 
					
						
							| 
									
										
										
										
											2021-12-27 22:19:18 +00:00
										 |  |  | from utils import get_nickname_from_actor | 
					
						
							| 
									
										
										
										
											2021-12-27 18:28:26 +00:00
										 |  |  | from utils import domain_permitted | 
					
						
							| 
									
										
										
										
											2021-12-27 17:08:19 +00:00
										 |  |  | from utils import follow_person | 
					
						
							| 
									
										
										
										
											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-04-09 15:11:22 +00:00
										 |  |  | from utils import has_object_string_type | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  | from utils import get_actor_from_post | 
					
						
							| 
									
										
										
										
											2019-07-02 11:31:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 18:16:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-06 19:47:30 +00:00
										 |  |  | def _create_quote_accept_reject(receiving_actor: str, | 
					
						
							|  |  |  |                                 sending_actor: str, | 
					
						
							|  |  |  |                                 federation_list: [], | 
					
						
							|  |  |  |                                 debug: bool, | 
					
						
							|  |  |  |                                 quote_request_id: str, | 
					
						
							|  |  |  |                                 quote_request_object: str, | 
					
						
							|  |  |  |                                 quote_request_instrument: str, | 
					
						
							|  |  |  |                                 accept_type: str) -> {}: | 
					
						
							|  |  |  |     """Creates an Accept or Reject response to QuoteRequest
 | 
					
						
							| 
									
										
										
										
											2025-04-06 20:11:19 +00:00
										 |  |  |     https://codeberg.org/fediverse/fep/src/branch/main/fep/044f/fep-044f.md | 
					
						
							| 
									
										
										
										
											2025-04-06 19:47:30 +00:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     if not receiving_actor or \ | 
					
						
							|  |  |  |        not sending_actor or \ | 
					
						
							|  |  |  |        not quote_request_id or \ | 
					
						
							|  |  |  |        not quote_request_object or \ | 
					
						
							|  |  |  |        not quote_request_instrument: | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  |     if not url_permitted(sending_actor, federation_list): | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     status_number, _ = get_status_number() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     new_accept = { | 
					
						
							|  |  |  |         "@context": [ | 
					
						
							|  |  |  |             "https://www.w3.org/ns/activitystreams", | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "toot": "http://joinmastodon.org/ns#", | 
					
						
							|  |  |  |                 "Quote": "toot:QuoteRequest" | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |         "type": accept_type, | 
					
						
							|  |  |  |         "to": [sending_actor], | 
					
						
							|  |  |  |         "id": receiving_actor + "/statuses/" + status_number, | 
					
						
							|  |  |  |         "actor": receiving_actor, | 
					
						
							|  |  |  |         "object": { | 
					
						
							|  |  |  |             "type": "QuoteRequest", | 
					
						
							|  |  |  |             "id": quote_request_id, | 
					
						
							|  |  |  |             "actor": sending_actor, | 
					
						
							|  |  |  |             "object": "https://example.com/users/alice/statuses/1", | 
					
						
							|  |  |  |             "instrument": "https://example.org/users/bob/statuses/1" | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('REJECT: QuoteRequest ' + str(new_accept)) | 
					
						
							|  |  |  |     return new_accept | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-08 10:44:38 +00:00
										 |  |  | def _create_accept_reject(federation_list: [], | 
					
						
							| 
									
										
										
										
											2021-12-25 23:45:30 +00:00
										 |  |  |                           nickname: str, domain: str, port: int, | 
					
						
							| 
									
										
										
										
											2022-05-30 12:45:47 +00:00
										 |  |  |                           to_url: str, cc_url: str, http_prefix: str, | 
					
						
							|  |  |  |                           object_json: {}, accept_type: str) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-06 17:00:22 +00:00
										 |  |  |     """Accepts or rejects something (eg. a follow request or offer)
 | 
					
						
							| 
									
										
										
										
											2022-05-30 12:45:47 +00:00
										 |  |  |     Typically to_url will be https://www.w3.org/ns/activitystreams#Public | 
					
						
							|  |  |  |     and cc_url might be a specific person favorited or repeated and | 
					
						
							| 
									
										
										
										
											2019-07-06 17:00:22 +00:00
										 |  |  |     the followers url objectUrl is typically the url of the message, | 
					
						
							|  |  |  |     corresponding to url or atomUri in createPostBase | 
					
						
							| 
									
										
										
										
											2019-07-02 11:31:26 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-05-30 12:45:47 +00:00
										 |  |  |     if not object_json.get('actor'): | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |     actor_url = get_actor_from_post(object_json) | 
					
						
							|  |  |  |     if not url_permitted(actor_url, federation_list): | 
					
						
							| 
									
										
										
										
											2019-07-02 11:31:26 +00:00
										 |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-26 12:45:03 +00:00
										 |  |  |     domain = get_full_domain(domain, port) | 
					
						
							| 
									
										
										
										
											2019-07-02 11:31:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |     new_accept = { | 
					
						
							| 
									
										
										
										
											2024-09-14 16:40:11 +00:00
										 |  |  |         "@context": [ | 
					
						
							|  |  |  |             'https://www.w3.org/ns/activitystreams', | 
					
						
							|  |  |  |             'https://w3id.org/security/v1' | 
					
						
							|  |  |  |         ], | 
					
						
							| 
									
										
										
										
											2022-05-30 12:45:47 +00:00
										 |  |  |         'type': accept_type, | 
					
						
							| 
									
										
										
										
											2021-12-26 10:19:59 +00:00
										 |  |  |         'actor': local_actor_url(http_prefix, nickname, domain), | 
					
						
							| 
									
										
										
										
											2022-05-30 12:45:47 +00:00
										 |  |  |         'to': [to_url], | 
					
						
							| 
									
										
										
										
											2019-07-02 11:31:26 +00:00
										 |  |  |         'cc': [], | 
					
						
							| 
									
										
										
										
											2022-05-30 12:45:47 +00:00
										 |  |  |         'object': object_json | 
					
						
							| 
									
										
										
										
											2019-07-02 11:31:26 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-05-30 12:45:47 +00:00
										 |  |  |     if cc_url: | 
					
						
							| 
									
										
										
										
											2025-04-12 21:08:06 +00:00
										 |  |  |         new_accept['cc'] = [cc_url] | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |     return new_accept | 
					
						
							| 
									
										
										
										
											2019-07-02 11:31:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 18:16:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-08 10:44:38 +00:00
										 |  |  | def create_accept(federation_list: [], | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                   nickname: str, domain: str, port: int, | 
					
						
							| 
									
										
										
										
											2022-05-30 12:45:47 +00:00
										 |  |  |                   to_url: str, cc_url: str, http_prefix: str, | 
					
						
							|  |  |  |                   object_json: {}) -> {}: | 
					
						
							| 
									
										
										
										
											2024-05-08 10:44:38 +00:00
										 |  |  |     """ Create json for ActivityPub Accept """ | 
					
						
							|  |  |  |     return _create_accept_reject(federation_list, | 
					
						
							| 
									
										
										
										
											2021-12-25 23:45:30 +00:00
										 |  |  |                                  nickname, domain, port, | 
					
						
							| 
									
										
										
										
											2022-05-30 12:45:47 +00:00
										 |  |  |                                  to_url, cc_url, http_prefix, | 
					
						
							|  |  |  |                                  object_json, 'Accept') | 
					
						
							| 
									
										
										
										
											2020-04-01 18:16:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-08 10:44:38 +00:00
										 |  |  | def create_reject(federation_list: [], | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                   nickname: str, domain: str, port: int, | 
					
						
							| 
									
										
										
										
											2022-05-30 12:45:47 +00:00
										 |  |  |                   to_url: str, cc_url: str, http_prefix: str, | 
					
						
							|  |  |  |                   object_json: {}) -> {}: | 
					
						
							| 
									
										
										
										
											2024-05-08 10:44:38 +00:00
										 |  |  |     """ Create json for ActivityPub Reject """ | 
					
						
							|  |  |  |     return _create_accept_reject(federation_list, | 
					
						
							| 
									
										
										
										
											2021-12-25 23:45:30 +00:00
										 |  |  |                                  nickname, domain, port, | 
					
						
							| 
									
										
										
										
											2022-05-30 12:45:47 +00:00
										 |  |  |                                  to_url, cc_url, | 
					
						
							|  |  |  |                                  http_prefix, object_json, 'Reject') | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 18:16:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-06 19:47:30 +00:00
										 |  |  | def _reject_quote_request(message_json: {}, domain_full: str, | 
					
						
							|  |  |  |                           federation_list: [], | 
					
						
							|  |  |  |                           debug: bool, | 
					
						
							|  |  |  |                           session, session_onion, session_i2p, | 
					
						
							|  |  |  |                           base_dir: str, | 
					
						
							|  |  |  |                           http_prefix: str, | 
					
						
							|  |  |  |                           send_threads: [], post_log: [], | 
					
						
							|  |  |  |                           cached_webfingers: {}, | 
					
						
							|  |  |  |                           person_cache: {}, project_version: str, | 
					
						
							|  |  |  |                           signing_priv_key_pem: str, | 
					
						
							|  |  |  |                           onion_domain: str, i2p_domain: str, | 
					
						
							|  |  |  |                           extra_headers: {}, | 
					
						
							|  |  |  |                           sites_unavailable: {}, | 
					
						
							|  |  |  |                           system_language: str, | 
					
						
							|  |  |  |                           mitm_servers: []) -> bool: | 
					
						
							| 
									
										
										
										
											2025-04-06 12:06:37 +00:00
										 |  |  |     """ Rejects a QuoteRequest
 | 
					
						
							| 
									
										
										
										
											2025-04-06 20:10:50 +00:00
										 |  |  |     https://codeberg.org/fediverse/fep/src/branch/main/fep/044f/fep-044f.md | 
					
						
							| 
									
										
										
										
											2025-04-06 12:06:37 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2025-04-06 19:47:30 +00:00
										 |  |  |     sending_actor = None | 
					
						
							|  |  |  |     receiving_actor = None | 
					
						
							|  |  |  |     quote_request_id = None | 
					
						
							|  |  |  |     quote_request_object = None | 
					
						
							|  |  |  |     quote_request_instrument = None | 
					
						
							| 
									
										
										
										
											2025-04-06 12:06:37 +00:00
										 |  |  |     if message_json.get('actor'): | 
					
						
							| 
									
										
										
										
											2025-04-06 19:47:30 +00:00
										 |  |  |         sending_actor = message_json['actor'] | 
					
						
							| 
									
										
										
										
											2025-04-06 12:06:37 +00:00
										 |  |  |     elif message_json.get('instrument'): | 
					
						
							|  |  |  |         if isinstance(message_json['instrument'], dict): | 
					
						
							| 
									
										
										
										
											2025-04-06 19:47:30 +00:00
										 |  |  |             instrument_dict = message_json['instrument'] | 
					
						
							|  |  |  |             if instrument_dict.get('attributedTo'): | 
					
						
							|  |  |  |                 sending_actor = \ | 
					
						
							|  |  |  |                     get_attributed_to(instrument_dict['attributedTo']) | 
					
						
							|  |  |  |             if instrument_dict.get('to'): | 
					
						
							|  |  |  |                 if isinstance(instrument_dict['to'], str): | 
					
						
							|  |  |  |                     receiving_actor = instrument_dict['to'] | 
					
						
							|  |  |  |                 elif isinstance(instrument_dict['to'], list): | 
					
						
							|  |  |  |                     for receiver in instrument_dict['to']: | 
					
						
							|  |  |  |                         if '#Public' not in receiver and \ | 
					
						
							|  |  |  |                            '://' + domain_full + '/' in receiver: | 
					
						
							|  |  |  |                             receiving_actor = receiver | 
					
						
							|  |  |  |                             break | 
					
						
							|  |  |  |             if instrument_dict.get('id'): | 
					
						
							|  |  |  |                 quote_request_instrument = instrument_dict['id'] | 
					
						
							|  |  |  |             if instrument_dict.get('object'): | 
					
						
							|  |  |  |                 quote_request_object = instrument_dict['object'] | 
					
						
							|  |  |  |     if message_json.get('id'): | 
					
						
							|  |  |  |         quote_request_id = message_json['id'] | 
					
						
							|  |  |  |     if not sending_actor: | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if receiving_actor: | 
					
						
							|  |  |  |         quote_request_object = receiving_actor | 
					
						
							|  |  |  |     reject_json = \ | 
					
						
							|  |  |  |         _create_quote_accept_reject(receiving_actor, | 
					
						
							|  |  |  |                                     sending_actor, | 
					
						
							|  |  |  |                                     federation_list, | 
					
						
							|  |  |  |                                     debug, | 
					
						
							|  |  |  |                                     quote_request_id, | 
					
						
							|  |  |  |                                     quote_request_object, | 
					
						
							|  |  |  |                                     quote_request_instrument, | 
					
						
							|  |  |  |                                     'Reject') | 
					
						
							|  |  |  |     if reject_json: | 
					
						
							|  |  |  |         print('REJECT: QuoteRequest from ' + sending_actor) | 
					
						
							|  |  |  |         nickname = get_nickname_from_actor(receiving_actor) | 
					
						
							|  |  |  |         domain, from_port = get_domain_from_actor(receiving_actor) | 
					
						
							|  |  |  |         nickname_to_follow = get_nickname_from_actor(sending_actor) | 
					
						
							|  |  |  |         domain_to_follow, port = get_domain_from_actor(sending_actor) | 
					
						
							|  |  |  |         group_account = \ | 
					
						
							|  |  |  |             has_group_type(base_dir, receiving_actor, person_cache) | 
					
						
							|  |  |  |         if nickname and domain and \ | 
					
						
							|  |  |  |            nickname_to_follow and domain_to_follow: | 
					
						
							|  |  |  |             if debug: | 
					
						
							|  |  |  |                 print('REJECT: QuoteRequest sending reject ' + | 
					
						
							|  |  |  |                       str(reject_json)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             curr_session = session | 
					
						
							|  |  |  |             curr_domain = domain | 
					
						
							|  |  |  |             curr_port = from_port | 
					
						
							|  |  |  |             curr_http_prefix = http_prefix | 
					
						
							|  |  |  |             if onion_domain and \ | 
					
						
							|  |  |  |                not curr_domain.endswith('.onion') and \ | 
					
						
							|  |  |  |                domain_to_follow.endswith('.onion'): | 
					
						
							|  |  |  |                 curr_session = session_onion | 
					
						
							|  |  |  |                 curr_http_prefix = '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 | 
					
						
							|  |  |  |                   domain_to_follow.endswith('.i2p')): | 
					
						
							|  |  |  |                 curr_session = session_i2p | 
					
						
							|  |  |  |                 curr_http_prefix = 'http' | 
					
						
							|  |  |  |                 curr_domain = i2p_domain | 
					
						
							|  |  |  |                 curr_port = 80 | 
					
						
							|  |  |  |                 port = 80 | 
					
						
							|  |  |  |                 if debug: | 
					
						
							|  |  |  |                     print('Domain switched from ' + domain + | 
					
						
							|  |  |  |                           ' to ' + curr_domain) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             client_to_server = False | 
					
						
							|  |  |  |             send_signed_json(reject_json, curr_session, base_dir, | 
					
						
							|  |  |  |                              nickname_to_follow, domain_to_follow, port, | 
					
						
							|  |  |  |                              nickname, domain, curr_port, | 
					
						
							|  |  |  |                              curr_http_prefix, client_to_server, | 
					
						
							|  |  |  |                              federation_list, | 
					
						
							|  |  |  |                              send_threads, post_log, cached_webfingers, | 
					
						
							|  |  |  |                              person_cache, debug, project_version, None, | 
					
						
							|  |  |  |                              group_account, signing_priv_key_pem, | 
					
						
							|  |  |  |                              726235284, curr_domain, onion_domain, i2p_domain, | 
					
						
							|  |  |  |                              extra_headers, sites_unavailable, | 
					
						
							|  |  |  |                              system_language, mitm_servers) | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  |     return False | 
					
						
							| 
									
										
										
										
											2025-04-06 12:06:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-09 10:28:03 +00:00
										 |  |  | def _accept_follow(base_dir: str, message_json: {}, | 
					
						
							| 
									
										
										
										
											2022-03-13 23:57:51 +00:00
										 |  |  |                    federation_list: [], debug: bool, | 
					
						
							|  |  |  |                    curr_domain: str, | 
					
						
							|  |  |  |                    onion_domain: str, i2p_domain: str) -> None: | 
					
						
							| 
									
										
										
										
											2024-05-08 10:44:38 +00:00
										 |  |  |     """ Receiving an ActivityPub follow Accept activity
 | 
					
						
							| 
									
										
										
										
											2025-02-28 12:43:22 +00:00
										 |  |  |     Your follow was accepted | 
					
						
							| 
									
										
										
										
											2019-07-20 08:33:18 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-04-09 15:11:22 +00:00
										 |  |  |     if not has_object_string_type(message_json, debug): | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2024-05-08 10:45:51 +00:00
										 |  |  |     if message_json['object']['type'] not in ('Follow', 'Join'): | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2019-11-12 14:18:23 +00:00
										 |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: receiving Follow activity') | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |     if not message_json['object'].get('actor'): | 
					
						
							| 
									
										
										
										
											2019-11-12 14:18:23 +00:00
										 |  |  |         print('DEBUG: no actor in Follow activity') | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  |         return | 
					
						
							|  |  |  |     # no, this isn't a mistake | 
					
						
							| 
									
										
										
										
											2021-12-26 15:54:46 +00:00
										 |  |  |     if not has_object_string_object(message_json, debug): | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |     if not message_json.get('to'): | 
					
						
							| 
									
										
										
										
											2019-07-07 13:53:12 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: No "to" parameter in follow Accept') | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  |     if debug: | 
					
						
							| 
									
										
										
										
											2022-02-28 20:05:47 +00:00
										 |  |  |         print('DEBUG: follow Accept received ' + str(message_json)) | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |     this_actor = get_actor_from_post(message_json['object']) | 
					
						
							| 
									
										
										
										
											2021-12-27 22:19:18 +00:00
										 |  |  |     nickname = get_nickname_from_actor(this_actor) | 
					
						
							| 
									
										
										
										
											2019-09-02 09:43:43 +00:00
										 |  |  |     if not nickname: | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |         print('WARN: no nickname found in ' + this_actor) | 
					
						
							| 
									
										
										
										
											2019-09-02 09:43:43 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     accepted_domain, accepted_port = get_domain_from_actor(this_actor) | 
					
						
							|  |  |  |     if not accepted_domain: | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |             print('DEBUG: domain not found in ' + this_actor) | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  |         return | 
					
						
							|  |  |  |     if not nickname: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |             print('DEBUG: nickname not found in ' + this_actor) | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     if accepted_port: | 
					
						
							|  |  |  |         if '/' + accepted_domain + ':' + str(accepted_port) + \ | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |            '/users/' + nickname not in this_actor: | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  |             if debug: | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |                 print('Port: ' + str(accepted_port)) | 
					
						
							|  |  |  |                 print('Expected: /' + accepted_domain + ':' + | 
					
						
							|  |  |  |                       str(accepted_port) + '/users/' + nickname) | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |                 print('Actual:   ' + this_actor) | 
					
						
							|  |  |  |                 print('DEBUG: unrecognized actor ' + this_actor) | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  |             return | 
					
						
							|  |  |  |     else: | 
					
						
							| 
									
										
										
										
											2024-05-27 12:45:01 +00:00
										 |  |  |         actor_found = False | 
					
						
							|  |  |  |         users_list = get_user_paths() | 
					
						
							|  |  |  |         for users_str in users_list: | 
					
						
							|  |  |  |             if '/' + accepted_domain + users_str + nickname in this_actor: | 
					
						
							|  |  |  |                 actor_found = True | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if not actor_found: | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  |             if debug: | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |                 print('Expected: /' + accepted_domain + '/users/' + nickname) | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |                 print('Actual:   ' + this_actor) | 
					
						
							|  |  |  |                 print('DEBUG: unrecognized actor ' + this_actor) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |             return | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |     followed_actor = message_json['object']['object'] | 
					
						
							| 
									
										
										
										
											2021-12-27 19:05:25 +00:00
										 |  |  |     followed_domain, port = get_domain_from_actor(followed_actor) | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |     if not followed_domain: | 
					
						
							| 
									
										
										
										
											2020-04-01 18:16:29 +00:00
										 |  |  |         print('DEBUG: no domain found within Follow activity object ' + | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |               followed_actor) | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |     followed_domain_full = followed_domain | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  |     if port: | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |         followed_domain_full = followed_domain + ':' + str(port) | 
					
						
							| 
									
										
										
										
											2021-12-27 22:19:18 +00:00
										 |  |  |     followed_nickname = get_nickname_from_actor(followed_actor) | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |     if not followed_nickname: | 
					
						
							| 
									
										
										
										
											2020-04-01 18:16:29 +00:00
										 |  |  |         print('DEBUG: no nickname found within Follow activity object ' + | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |               followed_actor) | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2019-07-07 11:53:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-13 23:57:51 +00:00
										 |  |  |     # convert from onion/i2p to clearnet accepted domain | 
					
						
							|  |  |  |     if onion_domain: | 
					
						
							|  |  |  |         if accepted_domain.endswith('.onion') and \ | 
					
						
							|  |  |  |            not curr_domain.endswith('.onion'): | 
					
						
							|  |  |  |             accepted_domain = curr_domain | 
					
						
							|  |  |  |     if i2p_domain: | 
					
						
							|  |  |  |         if accepted_domain.endswith('.i2p') and \ | 
					
						
							|  |  |  |            not curr_domain.endswith('.i2p'): | 
					
						
							|  |  |  |             accepted_domain = curr_domain | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     accepted_domain_full = accepted_domain | 
					
						
							|  |  |  |     if accepted_port: | 
					
						
							|  |  |  |         accepted_domain_full = accepted_domain + ':' + str(accepted_port) | 
					
						
							| 
									
										
										
										
											2019-07-16 22:57:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-22 10:50:07 +00:00
										 |  |  |     # has this person already been unfollowed? | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |     unfollowed_filename = \ | 
					
						
							| 
									
										
										
										
											2021-12-26 12:02:29 +00:00
										 |  |  |         acct_dir(base_dir, nickname, accepted_domain_full) + '/unfollowed.txt' | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |     if os.path.isfile(unfollowed_filename): | 
					
						
							| 
									
										
										
										
											2022-06-10 13:29:51 +00:00
										 |  |  |         if text_in_file(followed_nickname + '@' + followed_domain_full, | 
					
						
							|  |  |  |                         unfollowed_filename): | 
					
						
							| 
									
										
										
										
											2020-02-22 10:50:07 +00:00
										 |  |  |             if debug: | 
					
						
							| 
									
										
										
										
											2020-04-01 18:16:29 +00:00
										 |  |  |                 print('DEBUG: follow accept arrived for ' + | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |                       nickname + '@' + accepted_domain_full + | 
					
						
							|  |  |  |                       ' from ' + | 
					
						
							|  |  |  |                       followed_nickname + '@' + followed_domain_full + | 
					
						
							| 
									
										
										
										
											2020-02-22 10:50:07 +00:00
										 |  |  |                       ' but they have been unfollowed') | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |             return | 
					
						
							| 
									
										
										
										
											2020-02-22 10:50:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-30 16:06:34 +00:00
										 |  |  |     # does the url path indicate that this is a group actor | 
					
						
							| 
									
										
										
										
											2021-12-26 17:53:07 +00:00
										 |  |  |     group_account = has_group_type(base_dir, followed_actor, None, debug) | 
					
						
							| 
									
										
										
										
											2021-07-31 11:56:28 +00:00
										 |  |  |     if debug: | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |         print('Accepted follow is a group: ' + str(group_account) + | 
					
						
							|  |  |  |               ' ' + followed_actor + ' ' + base_dir) | 
					
						
							| 
									
										
										
										
											2021-07-30 16:06:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-27 17:08:19 +00:00
										 |  |  |     if follow_person(base_dir, | 
					
						
							|  |  |  |                      nickname, accepted_domain_full, | 
					
						
							|  |  |  |                      followed_nickname, followed_domain_full, | 
					
						
							| 
									
										
										
										
											2024-02-19 20:47:23 +00:00
										 |  |  |                      federation_list, debug, group_account, | 
					
						
							|  |  |  |                      'following.txt'): | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |             print('DEBUG: ' + nickname + '@' + accepted_domain_full + | 
					
						
							|  |  |  |                   ' followed ' + | 
					
						
							|  |  |  |                   followed_nickname + '@' + followed_domain_full) | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-01 18:16:29 +00:00
										 |  |  |             print('DEBUG: Unable to create follow - ' + | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |                   nickname + '@' + accepted_domain + ' -> ' + | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |                   followed_nickname + '@' + followed_domain) | 
					
						
							| 
									
										
										
										
											2020-04-01 18:16:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-09 10:28:03 +00:00
										 |  |  | def receive_accept_reject(base_dir: str, domain: str, message_json: {}, | 
					
						
							|  |  |  |                           federation_list: [], debug: bool, curr_domain: str, | 
					
						
							| 
									
										
										
										
											2022-03-13 23:57:51 +00:00
										 |  |  |                           onion_domain: str, i2p_domain: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-07-06 15:17:21 +00:00
										 |  |  |     """Receives an Accept or Reject within the POST section of HTTPServer
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2024-05-08 10:47:04 +00:00
										 |  |  |     if message_json['type'] not in ('Accept', 'Reject'): | 
					
						
							| 
									
										
										
										
											2019-07-06 15:17:21 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2021-12-26 17:15:04 +00:00
										 |  |  |     if not has_actor(message_json, debug): | 
					
						
							| 
									
										
										
										
											2019-07-06 15:17:21 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |     actor_url = get_actor_from_post(message_json) | 
					
						
							|  |  |  |     if not has_users_path(actor_url): | 
					
						
							| 
									
										
										
										
											2019-07-06 15:17:21 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-01 18:16:29 +00:00
										 |  |  |             print('DEBUG: "users" or "profile" missing from actor in ' + | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |                   message_json['type'] + '. Assuming single user instance.') | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |     domain, _ = get_domain_from_actor(actor_url) | 
					
						
							| 
									
										
										
										
											2021-12-27 18:28:26 +00:00
										 |  |  |     if not domain_permitted(domain, federation_list): | 
					
						
							| 
									
										
										
										
											2019-07-06 15:17:21 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |             print('DEBUG: ' + message_json['type'] + | 
					
						
							| 
									
										
										
										
											2020-04-01 18:16:29 +00:00
										 |  |  |                   ' from domain not permitted - ' + domain) | 
					
						
							| 
									
										
										
										
											2019-07-06 15:17:21 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |     nickname = get_nickname_from_actor(actor_url) | 
					
						
							| 
									
										
										
										
											2019-07-06 15:17:21 +00:00
										 |  |  |     if not nickname: | 
					
						
							| 
									
										
										
										
											2019-10-21 12:27:47 +00:00
										 |  |  |         # single user instance | 
					
						
							| 
									
										
										
										
											2020-04-01 18:16:29 +00:00
										 |  |  |         nickname = 'dev' | 
					
						
							| 
									
										
										
										
											2019-07-06 15:17:21 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |             print('DEBUG: ' + message_json['type'] + | 
					
						
							| 
									
										
										
										
											2020-04-01 18:16:29 +00:00
										 |  |  |                   ' does not contain a nickname. ' + | 
					
						
							| 
									
										
										
										
											2020-03-30 19:09:45 +00:00
										 |  |  |                   'Assuming single user instance.') | 
					
						
							| 
									
										
										
										
											2019-07-20 08:33:18 +00:00
										 |  |  |     # receive follow accept | 
					
						
							| 
									
										
										
										
											2022-06-09 10:28:03 +00:00
										 |  |  |     _accept_follow(base_dir, message_json, federation_list, debug, | 
					
						
							| 
									
										
										
										
											2022-03-13 23:57:51 +00:00
										 |  |  |                    curr_domain, onion_domain, i2p_domain) | 
					
						
							| 
									
										
										
										
											2019-07-06 15:17:21 +00:00
										 |  |  |     if debug: | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |         print('DEBUG: Uh, ' + message_json['type'] + ', I guess') | 
					
						
							| 
									
										
										
										
											2019-07-06 15:17:21 +00:00
										 |  |  |     return True | 
					
						
							| 
									
										
										
										
											2025-04-06 12:06:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-06 19:47:30 +00:00
										 |  |  | def receive_quote_request(message_json: {}, federation_list: [], | 
					
						
							|  |  |  |                           debug: bool, | 
					
						
							|  |  |  |                           domain_full: str, | 
					
						
							|  |  |  |                           session, session_onion, session_i2p, | 
					
						
							|  |  |  |                           base_dir: str, | 
					
						
							|  |  |  |                           http_prefix: str, | 
					
						
							|  |  |  |                           send_threads: [], post_log: [], | 
					
						
							|  |  |  |                           cached_webfingers: {}, | 
					
						
							|  |  |  |                           person_cache: {}, project_version: str, | 
					
						
							|  |  |  |                           signing_priv_key_pem: str, | 
					
						
							|  |  |  |                           onion_domain: str, | 
					
						
							|  |  |  |                           i2p_domain: str, | 
					
						
							|  |  |  |                           extra_headers: {}, | 
					
						
							|  |  |  |                           sites_unavailable: {}, | 
					
						
							|  |  |  |                           system_language: str, | 
					
						
							| 
									
										
										
										
											2025-04-06 20:06:21 +00:00
										 |  |  |                           mitm_servers: [], | 
					
						
							|  |  |  |                           last_quote_request) -> bool: | 
					
						
							| 
									
										
										
										
											2025-04-06 12:06:37 +00:00
										 |  |  |     """Receives a QuoteRequest within the POST section of HTTPServer
 | 
					
						
							| 
									
										
										
										
											2025-04-06 20:10:01 +00:00
										 |  |  |     https://codeberg.org/fediverse/fep/src/branch/main/fep/044f/fep-044f.md | 
					
						
							| 
									
										
										
										
											2025-04-06 12:06:37 +00:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     if message_json['type'] != 'QuoteRequest': | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2025-04-06 20:06:21 +00:00
										 |  |  |     curr_time = int(time.time()) | 
					
						
							|  |  |  |     seconds_since_last_quote_request = curr_time - last_quote_request | 
					
						
							|  |  |  |     if seconds_since_last_quote_request < 30: | 
					
						
							|  |  |  |         # don't handle quote requests too often | 
					
						
							|  |  |  |         return True | 
					
						
							| 
									
										
										
										
											2025-04-06 19:47:30 +00:00
										 |  |  |     _reject_quote_request(message_json, domain_full, | 
					
						
							|  |  |  |                           federation_list, debug, | 
					
						
							|  |  |  |                           session, session_onion, session_i2p, base_dir, | 
					
						
							|  |  |  |                           http_prefix, | 
					
						
							|  |  |  |                           send_threads, post_log, | 
					
						
							|  |  |  |                           cached_webfingers, | 
					
						
							|  |  |  |                           person_cache, project_version, | 
					
						
							|  |  |  |                           signing_priv_key_pem, | 
					
						
							|  |  |  |                           onion_domain, | 
					
						
							|  |  |  |                           i2p_domain, | 
					
						
							|  |  |  |                           extra_headers, | 
					
						
							|  |  |  |                           sites_unavailable, | 
					
						
							|  |  |  |                           system_language, | 
					
						
							|  |  |  |                           mitm_servers) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-06 12:06:37 +00:00
										 |  |  |     return True |