| 
									
										
										
										
											2024-05-08 12:09:29 +00:00
										 |  |  | """ ActivityPub Announce (aka retweet/boost) """ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 19:11:39 +00:00
										 |  |  | __filename__ = "announce.py" | 
					
						
							|  |  |  | __author__ = "Bob Mottram" | 
					
						
							|  |  |  | __license__ = "AGPL3+" | 
					
						
							| 
									
										
										
										
											2024-12-22 23:37:30 +00:00
										 |  |  | __version__ = "1.6.0" | 
					
						
							| 
									
										
										
										
											2020-04-01 19:11:39 +00:00
										 |  |  | __maintainer__ = "Bob Mottram" | 
					
						
							| 
									
										
										
										
											2021-09-10 16:14:50 +00:00
										 |  |  | __email__ = "bob@libreserver.org" | 
					
						
							| 
									
										
										
										
											2020-04-01 19:11:39 +00:00
										 |  |  | __status__ = "Production" | 
					
						
							| 
									
										
										
										
											2021-06-15 15:08:12 +00:00
										 |  |  | __module_group__ = "ActivityPub" | 
					
						
							| 
									
										
										
										
											2019-07-02 09:25:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-16 14:51:04 +00:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2025-05-28 16:42:31 +00:00
										 |  |  | from pprint import pprint | 
					
						
							| 
									
										
										
										
											2024-09-13 13:58:14 +00:00
										 |  |  | from flags import has_group_type | 
					
						
							|  |  |  | from flags import url_permitted | 
					
						
							| 
									
										
										
										
											2025-05-28 11:38:45 +00:00
										 |  |  | from status import get_status_number | 
					
						
							| 
									
										
										
										
											2025-05-28 16:42:31 +00:00
										 |  |  | from utils import remove_post_from_cache | 
					
						
							|  |  |  | from utils import get_cached_post_filename | 
					
						
							|  |  |  | from utils import load_json | 
					
						
							| 
									
										
										
										
											2024-07-16 14:51:04 +00:00
										 |  |  | from utils import text_in_file | 
					
						
							| 
									
										
										
										
											2024-05-27 12:45:01 +00:00
										 |  |  | from utils import get_user_paths | 
					
						
							| 
									
										
										
										
											2021-12-26 15:54:46 +00:00
										 |  |  | from utils import has_object_string_object | 
					
						
							| 
									
										
										
										
											2022-03-02 13:49:51 +00:00
										 |  |  | from utils import has_object_dict | 
					
						
							| 
									
										
										
										
											2021-12-26 18:17:37 +00:00
										 |  |  | from utils import remove_domain_port | 
					
						
							| 
									
										
										
										
											2021-12-27 11:20:57 +00:00
										 |  |  | from utils import remove_id_ending | 
					
						
							| 
									
										
										
										
											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 17:57:27 +00:00
										 |  |  | from utils import create_outbox_dir | 
					
						
							| 
									
										
										
										
											2021-12-27 22:19:18 +00:00
										 |  |  | from utils import get_nickname_from_actor | 
					
						
							| 
									
										
										
										
											2021-12-27 19:05:25 +00:00
										 |  |  | from utils import get_domain_from_actor | 
					
						
							| 
									
										
										
										
											2021-12-26 20:36:08 +00:00
										 |  |  | from utils import locate_post | 
					
						
							| 
									
										
										
										
											2021-12-26 14:47:21 +00:00
										 |  |  | from utils import save_json | 
					
						
							| 
									
										
										
										
											2021-12-26 10:19:59 +00:00
										 |  |  | from utils import local_actor_url | 
					
						
							| 
									
										
										
										
											2021-12-26 17:21:37 +00:00
										 |  |  | from utils import replace_users_with_at | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | from posts import send_signed_json | 
					
						
							|  |  |  | from posts import get_person_box | 
					
						
							|  |  |  | from session import post_json | 
					
						
							|  |  |  | from webfinger import webfinger_handle | 
					
						
							| 
									
										
										
										
											2021-12-28 21:36:27 +00:00
										 |  |  | from auth import create_basic_auth_header | 
					
						
							| 
									
										
										
										
											2019-07-02 09:25:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 19:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-02 13:49:51 +00:00
										 |  |  | def no_of_announces(post_json_object: {}) -> int: | 
					
						
							|  |  |  |     """Returns the number of announces on a given post
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     obj = post_json_object | 
					
						
							|  |  |  |     if has_object_dict(post_json_object): | 
					
						
							|  |  |  |         obj = post_json_object['object'] | 
					
						
							|  |  |  |     if not obj.get('shares'): | 
					
						
							|  |  |  |         return 0 | 
					
						
							|  |  |  |     if not isinstance(obj['shares'], dict): | 
					
						
							|  |  |  |         return 0 | 
					
						
							|  |  |  |     if not obj['shares'].get('items'): | 
					
						
							| 
									
										
										
										
											2024-12-23 15:39:55 +00:00
										 |  |  |         obj['shares']['items']: list[dict] = [] | 
					
						
							| 
									
										
										
										
											2022-03-02 13:49:51 +00:00
										 |  |  |         obj['shares']['totalItems'] = 0 | 
					
						
							|  |  |  |     return len(obj['shares']['items']) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-13 13:30:57 +00:00
										 |  |  | def is_announce(post_json_object: {}) -> bool: | 
					
						
							|  |  |  |     """Is the given post an announce?
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not post_json_object.get('type'): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if post_json_object['type'] != 'Announce': | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def is_self_announce(post_json_object: {}) -> bool: | 
					
						
							| 
									
										
										
										
											2021-06-22 19:43:03 +00:00
										 |  |  |     """Is the given post a self announce?
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-12-25 22:09:19 +00:00
										 |  |  |     if not post_json_object.get('actor'): | 
					
						
							| 
									
										
										
										
											2021-06-22 19:43:03 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2021-12-25 22:09:19 +00:00
										 |  |  |     if not post_json_object.get('type'): | 
					
						
							| 
									
										
										
										
											2021-06-22 19:43:03 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2021-12-25 22:09:19 +00:00
										 |  |  |     if post_json_object['type'] != 'Announce': | 
					
						
							| 
									
										
										
										
											2021-06-22 19:43:03 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2021-12-25 22:09:19 +00:00
										 |  |  |     if not post_json_object.get('object'): | 
					
						
							| 
									
										
										
										
											2021-06-22 19:43:03 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |     actor_url = get_actor_from_post(post_json_object) | 
					
						
							|  |  |  |     if not isinstance(actor_url, str): | 
					
						
							| 
									
										
										
										
											2021-06-22 19:43:03 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2021-12-25 22:09:19 +00:00
										 |  |  |     if not isinstance(post_json_object['object'], str): | 
					
						
							| 
									
										
										
										
											2021-06-22 19:43:03 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |     return actor_url in post_json_object['object'] | 
					
						
							| 
									
										
										
										
											2021-06-22 19:43:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def outbox_announce(recent_posts_cache: {}, | 
					
						
							|  |  |  |                     base_dir: str, message_json: {}, debug: bool) -> bool: | 
					
						
							| 
									
										
										
										
											2019-08-01 11:43:22 +00:00
										 |  |  |     """ Adds or removes announce entries from the shares collection
 | 
					
						
							|  |  |  |     within a given post | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-12-26 17:15:04 +00:00
										 |  |  |     if not has_actor(message_json, debug): | 
					
						
							| 
									
										
										
										
											2019-08-01 11:43:22 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |     if not isinstance(message_json['actor'], str): | 
					
						
							| 
									
										
										
										
											2021-06-03 08:33:50 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |     if not message_json.get('type'): | 
					
						
							| 
									
										
										
										
											2019-08-01 11:43:22 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |     if not message_json.get('object'): | 
					
						
							| 
									
										
										
										
											2019-08-01 11:43:22 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |     if message_json['type'] == 'Announce': | 
					
						
							|  |  |  |         if not isinstance(message_json['object'], str): | 
					
						
							| 
									
										
										
										
											2019-09-02 09:43:43 +00:00
										 |  |  |             return False | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |         if is_self_announce(message_json): | 
					
						
							| 
									
										
										
										
											2021-06-03 08:33:50 +00:00
										 |  |  |             return False | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |         actor_url = get_actor_from_post(message_json) | 
					
						
							|  |  |  |         nickname = get_nickname_from_actor(actor_url) | 
					
						
							| 
									
										
										
										
											2019-09-02 09:43:43 +00:00
										 |  |  |         if not nickname: | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |             print('WARN: no nickname found in ' + actor_url) | 
					
						
							| 
									
										
										
										
											2019-09-02 09:43:43 +00:00
										 |  |  |             return False | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |         domain, _ = get_domain_from_actor(actor_url) | 
					
						
							| 
									
										
										
										
											2023-01-15 14:33:18 +00:00
										 |  |  |         if not domain: | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |             print('WARN: no domain found in ' + actor_url) | 
					
						
							| 
									
										
										
										
											2023-01-15 14:33:18 +00:00
										 |  |  |             return False | 
					
						
							| 
									
										
										
										
											2021-12-26 23:41:34 +00:00
										 |  |  |         post_filename = locate_post(base_dir, nickname, domain, | 
					
						
							|  |  |  |                                     message_json['object']) | 
					
						
							|  |  |  |         if post_filename: | 
					
						
							|  |  |  |             update_announce_collection(recent_posts_cache, | 
					
						
							|  |  |  |                                        base_dir, post_filename, | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |                                        actor_url, | 
					
						
							| 
									
										
										
										
											2021-12-26 23:41:34 +00:00
										 |  |  |                                        nickname, domain, debug) | 
					
						
							| 
									
										
										
										
											2019-08-01 11:43:22 +00:00
										 |  |  |             return True | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |     elif message_json['type'] == 'Undo': | 
					
						
							| 
									
										
										
										
											2022-04-09 15:11:22 +00:00
										 |  |  |         if not has_object_string_type(message_json, debug): | 
					
						
							| 
									
										
										
										
											2019-08-01 11:43:22 +00:00
										 |  |  |             return False | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |         if message_json['object']['type'] == 'Announce': | 
					
						
							|  |  |  |             if not isinstance(message_json['object']['object'], str): | 
					
						
							| 
									
										
										
										
											2019-09-02 09:43:43 +00:00
										 |  |  |                 return False | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |             actor_url = get_actor_from_post(message_json) | 
					
						
							|  |  |  |             nickname = get_nickname_from_actor(actor_url) | 
					
						
							| 
									
										
										
										
											2019-09-02 09:43:43 +00:00
										 |  |  |             if not nickname: | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |                 print('WARN: no nickname found in ' + actor_url) | 
					
						
							| 
									
										
										
										
											2019-09-02 09:43:43 +00:00
										 |  |  |                 return False | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |             domain, _ = get_domain_from_actor(actor_url) | 
					
						
							| 
									
										
										
										
											2023-01-15 14:33:18 +00:00
										 |  |  |             if not domain: | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |                 print('WARN: no domain found in ' + actor_url) | 
					
						
							| 
									
										
										
										
											2023-01-15 14:33:18 +00:00
										 |  |  |                 return False | 
					
						
							| 
									
										
										
										
											2021-12-26 23:41:34 +00:00
										 |  |  |             post_filename = locate_post(base_dir, nickname, domain, | 
					
						
							|  |  |  |                                         message_json['object']['object']) | 
					
						
							|  |  |  |             if post_filename: | 
					
						
							| 
									
										
										
										
											2021-12-27 10:55:48 +00:00
										 |  |  |                 undo_announce_collection_entry(recent_posts_cache, | 
					
						
							|  |  |  |                                                base_dir, post_filename, | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |                                                actor_url, | 
					
						
							| 
									
										
										
										
											2021-12-27 10:55:48 +00:00
										 |  |  |                                                domain, debug) | 
					
						
							| 
									
										
										
										
											2019-08-01 11:43:22 +00:00
										 |  |  |                 return True | 
					
						
							|  |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 19:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  | def announced_by_person(is_announced: bool, post_actor: str, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                         nickname: str, domain_full: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-08-01 09:31:38 +00:00
										 |  |  |     """Returns True if the given post is announced by the given person
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     if not post_actor: | 
					
						
							| 
									
										
										
										
											2021-05-07 13:26:00 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2024-05-27 12:45:01 +00:00
										 |  |  |     if is_announced: | 
					
						
							|  |  |  |         users_paths = get_user_paths() | 
					
						
							|  |  |  |         for possible_path in users_paths: | 
					
						
							|  |  |  |             if post_actor.endswith(domain_full + possible_path + nickname): | 
					
						
							|  |  |  |                 return True | 
					
						
							| 
									
										
										
										
											2019-08-01 09:31:38 +00:00
										 |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 19:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def create_announce(session, base_dir: str, federation_list: [], | 
					
						
							|  |  |  |                     nickname: str, domain: str, port: int, | 
					
						
							| 
									
										
										
										
											2022-05-30 12:27:41 +00:00
										 |  |  |                     to_url: str, cc_url: str, http_prefix: str, | 
					
						
							|  |  |  |                     object_url: str, save_to_file: bool, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                     client_to_server: bool, | 
					
						
							| 
									
										
										
										
											2022-05-30 12:27:41 +00:00
										 |  |  |                     send_threads: [], post_log: [], | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                     person_cache: {}, cached_webfingers: {}, | 
					
						
							|  |  |  |                     debug: bool, project_version: str, | 
					
						
							| 
									
										
										
										
											2022-03-13 20:16:39 +00:00
										 |  |  |                     signing_priv_key_pem: str, | 
					
						
							|  |  |  |                     curr_domain: str, | 
					
						
							| 
									
										
										
										
											2023-09-15 21:04:31 +00:00
										 |  |  |                     onion_domain: str, i2p_domain: str, | 
					
						
							| 
									
										
										
										
											2023-10-25 19:55:40 +00:00
										 |  |  |                     sites_unavailable: [], | 
					
						
							| 
									
										
										
										
											2024-12-17 13:50:48 +00:00
										 |  |  |                     system_language: str, | 
					
						
							|  |  |  |                     mitm_servers: []) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-02 09:25:29 +00:00
										 |  |  |     """Creates an announce message
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     Typically to_url will be https://www.w3.org/ns/activitystreams#Public | 
					
						
							| 
									
										
										
										
											2022-05-30 12:27:41 +00:00
										 |  |  |     and cc_url might be a specific person favorited or repeated and the | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     followers url object_url is typically the url of the message, | 
					
						
							| 
									
										
										
										
											2019-07-06 17:00:22 +00:00
										 |  |  |     corresponding to url or atomUri in createPostBase | 
					
						
							| 
									
										
										
										
											2019-07-02 09:25:29 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     if not url_permitted(object_url, federation_list): | 
					
						
							| 
									
										
										
										
											2019-07-02 10:43:54 +00:00
										 |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-26 18:17:37 +00:00
										 |  |  |     domain = remove_domain_port(domain) | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     full_domain = get_full_domain(domain, port) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     status_number, published = get_status_number() | 
					
						
							|  |  |  |     new_announce_id = http_prefix + '://' + full_domain + \ | 
					
						
							|  |  |  |         '/users/' + nickname + '/statuses/' + status_number | 
					
						
							|  |  |  |     atom_uri_str = local_actor_url(http_prefix, nickname, full_domain) + \ | 
					
						
							|  |  |  |         '/statuses/' + status_number | 
					
						
							|  |  |  |     new_announce = { | 
					
						
							| 
									
										
										
										
											2024-09-14 16:40:11 +00:00
										 |  |  |         "@context": [ | 
					
						
							|  |  |  |             'https://www.w3.org/ns/activitystreams', | 
					
						
							|  |  |  |             'https://w3id.org/security/v1' | 
					
						
							|  |  |  |         ], | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |         'actor': local_actor_url(http_prefix, nickname, full_domain), | 
					
						
							|  |  |  |         'atomUri': atom_uri_str, | 
					
						
							| 
									
										
										
										
											2019-07-02 09:25:29 +00:00
										 |  |  |         'cc': [], | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |         'id': new_announce_id + '/activity', | 
					
						
							|  |  |  |         'object': object_url, | 
					
						
							| 
									
										
										
										
											2019-07-02 09:25:29 +00:00
										 |  |  |         'published': published, | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |         'to': [to_url], | 
					
						
							| 
									
										
										
										
											2019-07-02 09:25:29 +00:00
										 |  |  |         'type': 'Announce' | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-05-30 12:27:41 +00:00
										 |  |  |     if cc_url: | 
					
						
							| 
									
										
										
										
											2025-04-12 21:08:06 +00:00
										 |  |  |         new_announce['cc'] = [cc_url] | 
					
						
							| 
									
										
										
										
											2022-05-30 12:27:41 +00:00
										 |  |  |     if save_to_file: | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |         outbox_dir = create_outbox_dir(nickname, domain, base_dir) | 
					
						
							|  |  |  |         filename = \ | 
					
						
							|  |  |  |             outbox_dir + '/' + new_announce_id.replace('/', '#') + '.json' | 
					
						
							|  |  |  |         save_json(new_announce, filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     announce_nickname = None | 
					
						
							|  |  |  |     announce_domain = None | 
					
						
							|  |  |  |     announce_port = None | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |     group_account = False | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     if has_users_path(object_url): | 
					
						
							|  |  |  |         announce_nickname = get_nickname_from_actor(object_url) | 
					
						
							| 
									
										
										
										
											2023-01-15 14:33:18 +00:00
										 |  |  |         announce_domain, announce_port = get_domain_from_actor(object_url) | 
					
						
							|  |  |  |         if announce_nickname and announce_domain: | 
					
						
							| 
									
										
										
										
											2022-03-23 23:59:29 +00:00
										 |  |  |             if '/' + str(announce_nickname) + '/' in object_url: | 
					
						
							|  |  |  |                 announce_actor = \ | 
					
						
							|  |  |  |                     object_url.split('/' + announce_nickname + '/')[0] + \ | 
					
						
							|  |  |  |                     '/' + announce_nickname | 
					
						
							|  |  |  |                 if has_group_type(base_dir, announce_actor, person_cache): | 
					
						
							|  |  |  |                     group_account = True | 
					
						
							| 
									
										
										
										
											2019-07-11 17:55:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     if announce_nickname and announce_domain: | 
					
						
							| 
									
										
										
										
											2023-03-17 21:13:43 +00:00
										 |  |  |         extra_headers = {} | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |         send_signed_json(new_announce, session, base_dir, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                          nickname, domain, port, | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |                          announce_nickname, announce_domain, | 
					
						
							| 
									
										
										
										
											2022-05-31 13:34:29 +00:00
										 |  |  |                          announce_port, | 
					
						
							|  |  |  |                          http_prefix, client_to_server, federation_list, | 
					
						
							| 
									
										
										
										
											2022-05-30 12:27:41 +00:00
										 |  |  |                          send_threads, post_log, cached_webfingers, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                          person_cache, | 
					
						
							|  |  |  |                          debug, project_version, None, group_account, | 
					
						
							| 
									
										
										
										
											2022-03-13 20:16:39 +00:00
										 |  |  |                          signing_priv_key_pem, 639633, | 
					
						
							| 
									
										
										
										
											2023-03-17 21:13:43 +00:00
										 |  |  |                          curr_domain, onion_domain, i2p_domain, | 
					
						
							| 
									
										
										
										
											2023-10-25 19:55:40 +00:00
										 |  |  |                          extra_headers, sites_unavailable, | 
					
						
							| 
									
										
										
										
											2024-12-17 13:50:48 +00:00
										 |  |  |                          system_language, mitm_servers) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     return new_announce | 
					
						
							| 
									
										
										
										
											2019-07-02 09:25:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 19:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def announce_public(session, base_dir: str, federation_list: [], | 
					
						
							|  |  |  |                     nickname: str, domain: str, port: int, http_prefix: str, | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |                     object_url: str, client_to_server: bool, | 
					
						
							| 
									
										
										
										
											2022-05-30 12:27:41 +00:00
										 |  |  |                     send_threads: [], post_log: [], | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                     person_cache: {}, cached_webfingers: {}, | 
					
						
							|  |  |  |                     debug: bool, project_version: str, | 
					
						
							| 
									
										
										
										
											2022-03-13 20:16:39 +00:00
										 |  |  |                     signing_priv_key_pem: str, | 
					
						
							|  |  |  |                     curr_domain: str, | 
					
						
							| 
									
										
										
										
											2023-09-15 21:04:31 +00:00
										 |  |  |                     onion_domain: str, i2p_domain: str, | 
					
						
							| 
									
										
										
										
											2023-10-25 19:55:40 +00:00
										 |  |  |                     sites_unavailable: [], | 
					
						
							| 
									
										
										
										
											2024-12-17 13:50:48 +00:00
										 |  |  |                     system_language: str, | 
					
						
							|  |  |  |                     mitm_servers: []) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-02 09:25:29 +00:00
										 |  |  |     """Makes a public announcement
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     from_domain = get_full_domain(domain, port) | 
					
						
							| 
									
										
										
										
											2020-04-01 19:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     to_url = 'https://www.w3.org/ns/activitystreams#Public' | 
					
						
							| 
									
										
										
										
											2022-05-30 12:27:41 +00:00
										 |  |  |     cc_url = local_actor_url(http_prefix, nickname, from_domain) + '/followers' | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |     return create_announce(session, base_dir, federation_list, | 
					
						
							|  |  |  |                            nickname, domain, port, | 
					
						
							| 
									
										
										
										
											2022-05-30 12:27:41 +00:00
										 |  |  |                            to_url, cc_url, http_prefix, | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |                            object_url, True, client_to_server, | 
					
						
							| 
									
										
										
										
											2022-05-30 12:27:41 +00:00
										 |  |  |                            send_threads, post_log, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                            person_cache, cached_webfingers, | 
					
						
							|  |  |  |                            debug, project_version, | 
					
						
							| 
									
										
										
										
											2022-03-13 20:16:39 +00:00
										 |  |  |                            signing_priv_key_pem, curr_domain, | 
					
						
							| 
									
										
										
										
											2023-09-15 21:04:31 +00:00
										 |  |  |                            onion_domain, i2p_domain, | 
					
						
							| 
									
										
										
										
											2023-10-25 19:55:40 +00:00
										 |  |  |                            sites_unavailable, | 
					
						
							| 
									
										
										
										
											2024-12-17 13:50:48 +00:00
										 |  |  |                            system_language, mitm_servers) | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def send_announce_via_server(base_dir: str, session, | 
					
						
							| 
									
										
										
										
											2022-05-26 22:52:32 +00:00
										 |  |  |                              from_nickname: str, password: str, | 
					
						
							| 
									
										
										
										
											2022-05-30 12:27:41 +00:00
										 |  |  |                              from_domain: str, from_port: int, | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |                              http_prefix: str, repeat_object_url: str, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                              cached_webfingers: {}, person_cache: {}, | 
					
						
							|  |  |  |                              debug: bool, project_version: str, | 
					
						
							| 
									
										
										
										
											2023-10-25 19:55:40 +00:00
										 |  |  |                              signing_priv_key_pem: str, | 
					
						
							| 
									
										
										
										
											2024-12-17 13:50:48 +00:00
										 |  |  |                              system_language: str, | 
					
						
							|  |  |  |                              mitm_servers: []) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  |     """Creates an announce message via c2s
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not session: | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |         print('WARN: No session for send_announce_via_server') | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  |         return 6 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-30 12:27:41 +00:00
										 |  |  |     from_domain_full = get_full_domain(from_domain, from_port) | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     to_url = 'https://www.w3.org/ns/activitystreams#Public' | 
					
						
							| 
									
										
										
										
											2022-05-26 22:52:32 +00:00
										 |  |  |     actor_str = local_actor_url(http_prefix, from_nickname, from_domain_full) | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     cc_url = actor_str + '/followers' | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     status_number, published = get_status_number() | 
					
						
							|  |  |  |     new_announce_id = actor_str + '/statuses/' + status_number | 
					
						
							|  |  |  |     new_announce_json = { | 
					
						
							| 
									
										
										
										
											2024-09-14 16:40:11 +00:00
										 |  |  |         "@context": [ | 
					
						
							|  |  |  |             'https://www.w3.org/ns/activitystreams', | 
					
						
							|  |  |  |             'https://w3id.org/security/v1' | 
					
						
							|  |  |  |         ], | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |         'actor': actor_str, | 
					
						
							|  |  |  |         'atomUri': new_announce_id, | 
					
						
							|  |  |  |         'cc': [cc_url], | 
					
						
							|  |  |  |         'id': new_announce_id + '/activity', | 
					
						
							|  |  |  |         'object': repeat_object_url, | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  |         'published': published, | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |         'to': [to_url], | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  |         'type': 'Announce' | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-26 22:52:32 +00:00
										 |  |  |     handle = http_prefix + '://' + from_domain_full + '/@' + from_nickname | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # lookup the inbox for the To handle | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     wf_request = webfinger_handle(session, handle, http_prefix, | 
					
						
							|  |  |  |                                   cached_webfingers, | 
					
						
							|  |  |  |                                   from_domain, project_version, debug, False, | 
					
						
							| 
									
										
										
										
											2024-12-17 13:50:48 +00:00
										 |  |  |                                   signing_priv_key_pem, mitm_servers) | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     if not wf_request: | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-01 19:11:39 +00:00
										 |  |  |             print('DEBUG: announce webfinger failed for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     if not isinstance(wf_request, dict): | 
					
						
							| 
									
										
										
										
											2021-03-18 10:01:01 +00:00
										 |  |  |         print('WARN: announce webfinger for ' + handle + | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |               ' did not return a dict. ' + str(wf_request)) | 
					
						
							| 
									
										
										
										
											2020-06-23 10:41:12 +00:00
										 |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     post_to_box = 'outbox' | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # get the actor inbox for the To handle | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     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, | 
					
						
							| 
									
										
										
										
											2022-05-26 22:52:32 +00:00
										 |  |  |                                   from_nickname, from_domain, | 
					
						
							| 
									
										
										
										
											2023-10-25 19:55:40 +00:00
										 |  |  |                                   post_to_box, 73528, | 
					
						
							| 
									
										
										
										
											2024-12-17 13:50:48 +00:00
										 |  |  |                                   system_language, mitm_servers) | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if not inbox_url: | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |             print('DEBUG: announce no ' + post_to_box + | 
					
						
							| 
									
										
										
										
											2021-03-18 10:01:01 +00:00
										 |  |  |                   ' was found for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  |         return 3 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     if not from_person_id: | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2021-03-18 10:01:01 +00:00
										 |  |  |             print('DEBUG: announce no actor was found for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  |         return 4 | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-26 22:52:32 +00:00
										 |  |  |     auth_header = create_basic_auth_header(from_nickname, password) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 19:11:39 +00:00
										 |  |  |     headers = { | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |         'host': from_domain, | 
					
						
							| 
									
										
										
										
											2020-04-01 19:11:39 +00:00
										 |  |  |         'Content-type': 'application/json', | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |         'Authorization': auth_header | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     post_result = post_json(http_prefix, from_domain_full, | 
					
						
							|  |  |  |                             session, new_announce_json, [], inbox_url, | 
					
						
							|  |  |  |                             headers, 3, True) | 
					
						
							|  |  |  |     if not post_result: | 
					
						
							| 
									
										
										
										
											2021-03-18 10:01:01 +00:00
										 |  |  |         print('WARN: announce not posted') | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: c2s POST announce success') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     return new_announce_json | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def send_undo_announce_via_server(base_dir: str, session, | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |                                   undo_post_json_object: {}, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                                   nickname: str, password: str, | 
					
						
							| 
									
										
										
										
											2022-06-09 15:21:14 +00:00
										 |  |  |                                   domain: str, port: int, http_prefix: str, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                                   cached_webfingers: {}, person_cache: {}, | 
					
						
							|  |  |  |                                   debug: bool, project_version: str, | 
					
						
							| 
									
										
										
										
											2023-10-25 19:55:40 +00:00
										 |  |  |                                   signing_priv_key_pem: str, | 
					
						
							| 
									
										
										
										
											2024-12-17 13:50:48 +00:00
										 |  |  |                                   system_language: str, | 
					
						
							|  |  |  |                                   mitm_servers: []) -> {}: | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  |     """Undo an announce message via c2s
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not session: | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |         print('WARN: No session for send_undo_announce_via_server') | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  |         return 6 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-26 12:45:03 +00:00
										 |  |  |     domain_full = get_full_domain(domain, port) | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-26 10:19:59 +00:00
										 |  |  |     actor = local_actor_url(http_prefix, nickname, domain_full) | 
					
						
							| 
									
										
										
										
											2021-12-26 17:21:37 +00:00
										 |  |  |     handle = replace_users_with_at(actor) | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     status_number, _ = get_status_number() | 
					
						
							|  |  |  |     unannounce_json = { | 
					
						
							| 
									
										
										
										
											2024-09-14 16:40:11 +00:00
										 |  |  |         "@context": [ | 
					
						
							|  |  |  |             'https://www.w3.org/ns/activitystreams', | 
					
						
							|  |  |  |             'https://w3id.org/security/v1' | 
					
						
							|  |  |  |         ], | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |         'id': actor + '/statuses/' + str(status_number) + '/undo', | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  |         'type': 'Undo', | 
					
						
							|  |  |  |         'actor': actor, | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |         'object': undo_post_json_object['object'] | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # lookup the inbox for the To handle | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     wf_request = webfinger_handle(session, handle, http_prefix, | 
					
						
							|  |  |  |                                   cached_webfingers, | 
					
						
							|  |  |  |                                   domain, project_version, debug, False, | 
					
						
							| 
									
										
										
										
											2024-12-17 13:50:48 +00:00
										 |  |  |                                   signing_priv_key_pem, mitm_servers) | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     if not wf_request: | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: undo announce webfinger failed for ' + handle) | 
					
						
							|  |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     if not isinstance(wf_request, dict): | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  |         print('WARN: undo announce webfinger for ' + handle + | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |               ' did not return a dict. ' + str(wf_request)) | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  |         return 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     post_to_box = 'outbox' | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # get the actor inbox for the To handle | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     origin_domain = 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, | 
					
						
							|  |  |  |                                   nickname, domain, | 
					
						
							| 
									
										
										
										
											2023-10-25 19:55:40 +00:00
										 |  |  |                                   post_to_box, 73528, | 
					
						
							| 
									
										
										
										
											2024-12-17 13:50:48 +00:00
										 |  |  |                                   system_language, mitm_servers) | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if not inbox_url: | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |             print('DEBUG: undo announce no ' + post_to_box + | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  |                   ' was found for ' + handle) | 
					
						
							|  |  |  |         return 3 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     if not from_person_id: | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: undo announce no actor was found for ' + handle) | 
					
						
							|  |  |  |         return 4 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     auth_header = create_basic_auth_header(nickname, password) | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     headers = { | 
					
						
							|  |  |  |         'host': domain, | 
					
						
							|  |  |  |         'Content-type': 'application/json', | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |         'Authorization': auth_header | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     post_result = post_json(http_prefix, domain_full, | 
					
						
							|  |  |  |                             session, unannounce_json, [], inbox_url, | 
					
						
							|  |  |  |                             headers, 3, True) | 
					
						
							|  |  |  |     if not post_result: | 
					
						
							| 
									
										
										
										
											2021-03-18 20:56:08 +00:00
										 |  |  |         print('WARN: undo announce not posted') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: c2s POST undo announce success') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     return unannounce_json | 
					
						
							| 
									
										
										
										
											2021-05-08 13:14:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def outbox_undo_announce(recent_posts_cache: {}, | 
					
						
							| 
									
										
										
										
											2022-06-09 16:05:42 +00:00
										 |  |  |                          base_dir: str, nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                          message_json: {}, debug: bool) -> None: | 
					
						
							| 
									
										
										
										
											2021-05-08 13:14:52 +00:00
										 |  |  |     """ When an undo announce is received by the outbox from c2s
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |     if not message_json.get('type'): | 
					
						
							| 
									
										
										
										
											2021-05-08 13:14:52 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |     if not message_json['type'] == 'Undo': | 
					
						
							| 
									
										
										
										
											2021-05-08 13:14:52 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2022-04-09 15:11:22 +00:00
										 |  |  |     if not has_object_string_type(message_json, debug): | 
					
						
							| 
									
										
										
										
											2021-05-08 13:14:52 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2021-12-25 23:51:19 +00:00
										 |  |  |     if not message_json['object']['type'] == 'Announce': | 
					
						
							| 
									
										
										
										
											2021-05-08 13:14:52 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: not a undo announce') | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2021-12-26 15:54:46 +00:00
										 |  |  |     if not has_object_string_object(message_json, debug): | 
					
						
							| 
									
										
										
										
											2021-05-08 13:14:52 +00:00
										 |  |  |         return | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: c2s undo announce request arrived in outbox') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     message_id = remove_id_ending(message_json['object']['object']) | 
					
						
							| 
									
										
										
										
											2021-12-26 18:17:37 +00:00
										 |  |  |     domain = remove_domain_port(domain) | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |     post_filename = locate_post(base_dir, nickname, domain, message_id) | 
					
						
							| 
									
										
										
										
											2021-12-26 23:41:34 +00:00
										 |  |  |     if not post_filename: | 
					
						
							| 
									
										
										
										
											2021-05-08 13:14:52 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: c2s undo announce post not found in inbox or outbox') | 
					
						
							| 
									
										
										
										
											2021-12-29 22:45:26 +00:00
										 |  |  |             print(message_id) | 
					
						
							| 
									
										
										
										
											2021-05-08 13:14:52 +00:00
										 |  |  |         return True | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |     actor_url = get_actor_from_post(message_json) | 
					
						
							| 
									
										
										
										
											2021-12-27 10:55:48 +00:00
										 |  |  |     undo_announce_collection_entry(recent_posts_cache, base_dir, post_filename, | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |                                    actor_url, domain, debug) | 
					
						
							| 
									
										
										
										
											2021-05-08 13:14:52 +00:00
										 |  |  |     if debug: | 
					
						
							| 
									
										
										
										
											2021-12-26 23:41:34 +00:00
										 |  |  |         print('DEBUG: post undo announce via c2s - ' + post_filename) | 
					
						
							| 
									
										
										
										
											2024-07-16 14:51:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def announce_seen(base_dir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                   message_json: {}) -> bool: | 
					
						
							|  |  |  |     """have the given announce been seen?
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not message_json.get('id'): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if not isinstance(message_json['id'], str): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if not message_json.get('object'): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if not isinstance(message_json['object'], str): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2024-07-16 15:44:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # is this your own announce? | 
					
						
							|  |  |  |     announce_id = remove_id_ending(message_json['id']) | 
					
						
							|  |  |  |     if '://' + domain in announce_id and \ | 
					
						
							|  |  |  |        '/users/' + nickname + '/' in announce_id: | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-16 14:51:04 +00:00
										 |  |  |     post_url = remove_id_ending(message_json['object']) | 
					
						
							|  |  |  |     post_filename = locate_post(base_dir, nickname, domain, post_url) | 
					
						
							|  |  |  |     if not post_filename: | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     seen_filename = post_filename + '.seen' | 
					
						
							|  |  |  |     if not os.path.isfile(seen_filename): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2024-07-16 15:44:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-16 14:51:04 +00:00
										 |  |  |     if text_in_file(announce_id, seen_filename): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def mark_announce_as_seen(base_dir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                           message_json: {}) -> None: | 
					
						
							|  |  |  |     """Marks the given announce post as seen
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not message_json.get('id'): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if not isinstance(message_json['id'], str): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if not message_json.get('object'): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if not isinstance(message_json['object'], str): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     post_url = remove_id_ending(message_json['object']) | 
					
						
							|  |  |  |     post_filename = locate_post(base_dir, nickname, domain, post_url) | 
					
						
							|  |  |  |     if not post_filename: | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     seen_filename = post_filename + '.seen' | 
					
						
							|  |  |  |     if os.path.isfile(seen_filename): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     announce_id = remove_id_ending(message_json['id']) | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         with open(seen_filename, 'w+', encoding='utf-8') as fp_seen: | 
					
						
							|  |  |  |             fp_seen.write(announce_id) | 
					
						
							|  |  |  |     except OSError: | 
					
						
							|  |  |  |         print('EX: mark_announce_as_seen unable to write ' + seen_filename) | 
					
						
							| 
									
										
										
										
											2025-05-28 16:42:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def undo_announce_collection_entry(recent_posts_cache: {}, | 
					
						
							|  |  |  |                                    base_dir: str, post_filename: str, | 
					
						
							|  |  |  |                                    actor: str, domain: str, | 
					
						
							|  |  |  |                                    debug: bool) -> None: | 
					
						
							|  |  |  |     """Undoes an announce for a particular actor by removing it from
 | 
					
						
							|  |  |  |     the "shares" collection within a post. Note that the "shares" | 
					
						
							|  |  |  |     collection has no relation to shared items in shares.py. It's | 
					
						
							|  |  |  |     shares of posts, not shares of physical objects. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     post_json_object = load_json(post_filename) | 
					
						
							|  |  |  |     if not post_json_object: | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     # remove any cached version of this announce so that the announce | 
					
						
							|  |  |  |     # icon is changed | 
					
						
							|  |  |  |     nickname = get_nickname_from_actor(actor) | 
					
						
							|  |  |  |     if not nickname: | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     cached_post_filename = \ | 
					
						
							|  |  |  |         get_cached_post_filename(base_dir, nickname, domain, | 
					
						
							|  |  |  |                                  post_json_object) | 
					
						
							|  |  |  |     if cached_post_filename: | 
					
						
							|  |  |  |         if os.path.isfile(cached_post_filename): | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 os.remove(cached_post_filename) | 
					
						
							|  |  |  |             except OSError: | 
					
						
							|  |  |  |                 if debug: | 
					
						
							|  |  |  |                     print('EX: undo_announce_collection_entry ' + | 
					
						
							|  |  |  |                           'unable to delete cached post ' + | 
					
						
							|  |  |  |                           str(cached_post_filename)) | 
					
						
							|  |  |  |     remove_post_from_cache(post_json_object, recent_posts_cache) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not post_json_object.get('type'): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if post_json_object['type'] != 'Create': | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if not has_object_dict(post_json_object): | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             pprint(post_json_object) | 
					
						
							|  |  |  |             print('DEBUG: post has no object') | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if not post_json_object['object'].get('shares'): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if not post_json_object['object']['shares'].get('items'): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     total_items = 0 | 
					
						
							|  |  |  |     if post_json_object['object']['shares'].get('totalItems'): | 
					
						
							|  |  |  |         total_items = post_json_object['object']['shares']['totalItems'] | 
					
						
							|  |  |  |     item_found = False | 
					
						
							|  |  |  |     for announce_item in post_json_object['object']['shares']['items']: | 
					
						
							|  |  |  |         if not announce_item.get('actor'): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if announce_item['actor'] != actor: | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: Announce was removed for ' + actor) | 
					
						
							|  |  |  |         an_it = announce_item | 
					
						
							|  |  |  |         post_json_object['object']['shares']['items'].remove(an_it) | 
					
						
							|  |  |  |         item_found = True | 
					
						
							|  |  |  |         break | 
					
						
							|  |  |  |     if not item_found: | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if total_items == 1: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: shares (announcements) ' + | 
					
						
							|  |  |  |                   'was removed from post') | 
					
						
							|  |  |  |         del post_json_object['object']['shares'] | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         itlen = len(post_json_object['object']['shares']['items']) | 
					
						
							|  |  |  |         post_json_object['object']['shares']['totalItems'] = itlen | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     save_json(post_json_object, post_filename) | 
					
						
							| 
									
										
										
										
											2025-05-28 17:31:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def update_announce_collection(recent_posts_cache: {}, | 
					
						
							|  |  |  |                                base_dir: str, post_filename: str, | 
					
						
							|  |  |  |                                actor: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                                debug: bool) -> None: | 
					
						
							|  |  |  |     """Updates the announcements collection within a post
 | 
					
						
							|  |  |  |     Confusingly this is known as "shares", but isn't the | 
					
						
							|  |  |  |     same as shared items within shares.py | 
					
						
							|  |  |  |     It's shares of posts, not shares of physical objects. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     post_json_object = load_json(post_filename) | 
					
						
							|  |  |  |     if not post_json_object: | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     # remove any cached version of this announce so that the announce | 
					
						
							|  |  |  |     # icon is changed | 
					
						
							|  |  |  |     cached_post_filename = \ | 
					
						
							|  |  |  |         get_cached_post_filename(base_dir, nickname, domain, | 
					
						
							|  |  |  |                                  post_json_object) | 
					
						
							|  |  |  |     if cached_post_filename: | 
					
						
							|  |  |  |         if os.path.isfile(cached_post_filename): | 
					
						
							|  |  |  |             print('update_announce_collection: removing ' + | 
					
						
							|  |  |  |                   cached_post_filename) | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 os.remove(cached_post_filename) | 
					
						
							|  |  |  |             except OSError: | 
					
						
							|  |  |  |                 if debug: | 
					
						
							|  |  |  |                     print('EX: update_announce_collection ' + | 
					
						
							|  |  |  |                           'unable to delete cached post ' + | 
					
						
							|  |  |  |                           str(cached_post_filename)) | 
					
						
							|  |  |  |     remove_post_from_cache(post_json_object, recent_posts_cache) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not has_object_dict(post_json_object): | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             pprint(post_json_object) | 
					
						
							|  |  |  |             print('DEBUG: post ' + post_filename + ' has no object') | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     post_url = remove_id_ending(post_json_object['id']) | 
					
						
							|  |  |  |     collection_id = post_url + '/shares' | 
					
						
							|  |  |  |     if not post_json_object['object'].get('shares'): | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: Adding initial shares (announcements) to ' + | 
					
						
							|  |  |  |                   post_url) | 
					
						
							|  |  |  |         announcements_json = { | 
					
						
							|  |  |  |             "@context": [ | 
					
						
							|  |  |  |                 'https://www.w3.org/ns/activitystreams', | 
					
						
							|  |  |  |                 'https://w3id.org/security/v1' | 
					
						
							|  |  |  |             ], | 
					
						
							|  |  |  |             'id': collection_id, | 
					
						
							|  |  |  |             'sharesOf': post_url, | 
					
						
							|  |  |  |             'type': 'Collection', | 
					
						
							|  |  |  |             "totalItems": 1, | 
					
						
							|  |  |  |             'items': [{ | 
					
						
							|  |  |  |                 'type': 'Announce', | 
					
						
							|  |  |  |                 'actor': actor | 
					
						
							|  |  |  |             }] | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         post_json_object['object']['shares'] = announcements_json | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         if post_json_object['object']['shares'].get('items'): | 
					
						
							|  |  |  |             shares_items = post_json_object['object']['shares']['items'] | 
					
						
							|  |  |  |             for announce_item in shares_items: | 
					
						
							|  |  |  |                 if announce_item.get('actor'): | 
					
						
							|  |  |  |                     if announce_item['actor'] == actor: | 
					
						
							|  |  |  |                         return | 
					
						
							|  |  |  |             new_announce = { | 
					
						
							|  |  |  |                 'type': 'Announce', | 
					
						
							|  |  |  |                 'actor': actor | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             post_json_object['object']['shares']['items'].append(new_announce) | 
					
						
							|  |  |  |             itlen = len(post_json_object['object']['shares']['items']) | 
					
						
							|  |  |  |             post_json_object['object']['shares']['totalItems'] = itlen | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             if debug: | 
					
						
							|  |  |  |                 print('DEBUG: shares (announcements) section of post ' + | 
					
						
							|  |  |  |                       'has no items list') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: saving post with shares (announcements) added') | 
					
						
							|  |  |  |         pprint(post_json_object) | 
					
						
							|  |  |  |     save_json(post_json_object, post_filename) | 
					
						
							| 
									
										
										
										
											2025-05-28 17:40:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def disallow_announce(content: str, attachment: [], capabilities: {}) -> bool: | 
					
						
							|  |  |  |     """Are announces/boosts not allowed for the given post?
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     # pixelfed style capabilities | 
					
						
							|  |  |  |     if capabilities: | 
					
						
							|  |  |  |         if 'announce' in capabilities: | 
					
						
							|  |  |  |             if isinstance(capabilities['announce'], str): | 
					
						
							|  |  |  |                 if not capabilities['announce'].endswith('#Public'): | 
					
						
							|  |  |  |                     # TODO handle non-public announce permissions | 
					
						
							|  |  |  |                     print('CAPABILITIES: announce ' + capabilities['announce']) | 
					
						
							|  |  |  |                     return True | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # capabilities exist but with no announce defined | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # emojis | 
					
						
							|  |  |  |     disallow_strings = ( | 
					
						
							|  |  |  |         ':boost_no:', | 
					
						
							|  |  |  |         ':noboost:', | 
					
						
							|  |  |  |         ':noboosts:', | 
					
						
							|  |  |  |         ':no_boost:', | 
					
						
							|  |  |  |         ':no_boosts:', | 
					
						
							|  |  |  |         ':boosts_no:', | 
					
						
							|  |  |  |         'dont_repeat', | 
					
						
							|  |  |  |         'dont_announce', | 
					
						
							|  |  |  |         'dont_boost', | 
					
						
							|  |  |  |         'do not boost', | 
					
						
							|  |  |  |         "don't boost", | 
					
						
							|  |  |  |         'boost_denied', | 
					
						
							|  |  |  |         'boosts_denied', | 
					
						
							|  |  |  |         'boostdenied', | 
					
						
							|  |  |  |         'boostsdenied' | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     content_lower = content.lower() | 
					
						
							|  |  |  |     for diss in disallow_strings: | 
					
						
							|  |  |  |         if diss in content_lower: | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # check for attached images without descriptions | 
					
						
							|  |  |  |     if isinstance(attachment, list): | 
					
						
							|  |  |  |         for item in attachment: | 
					
						
							|  |  |  |             if not isinstance(item, dict): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if not item.get('mediaType'): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if not item.get('url'): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if not item['mediaType'].startswith('image/'): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if not item.get('name'): | 
					
						
							|  |  |  |                 # no image description | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  |             image_description = item['name'] | 
					
						
							|  |  |  |             if not isinstance(image_description, str): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if len(image_description) < 5: | 
					
						
							|  |  |  |                 # not enough description | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  |     return False |